293 lines
11 KiB
Python
293 lines
11 KiB
Python
# authentic2_cut - Authentic2 plugin for CUT
|
|
# Copyright (C) 2017 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from contextlib import closing
|
|
|
|
from authentic2 import hooks
|
|
from authentic2.manager.user_views import UserDetailView, UserEditView
|
|
from authentic2.manager.views import BaseTableView, FilterQuerysetByPermMixin, SimpleSubTableView
|
|
from authentic2.utils.misc import redirect
|
|
from authentic2.views import EditProfile
|
|
from django.contrib import messages
|
|
from django.contrib.auth import get_user_model
|
|
from django.core.exceptions import PermissionDenied
|
|
from django.db.transaction import atomic
|
|
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
|
from django.utils.timezone import now
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.views.generic.base import RedirectView, TemplateView
|
|
|
|
from . import forms, models, tables, utils
|
|
from .custom_settings import CORE_ATTRIBUTES
|
|
|
|
|
|
class EditCoreView(EditProfile):
|
|
template_names = ['authentic2/cut-edit-core.html']
|
|
fields = [
|
|
'first_name',
|
|
'last_name',
|
|
'birthdate',
|
|
'birthplace',
|
|
'birthcountry',
|
|
]
|
|
|
|
@classmethod
|
|
def get_fields(cls, scopes=None):
|
|
fields, labels = super().get_fields(scopes=scopes)
|
|
return [field for field in fields if field in cls.fields], labels
|
|
|
|
def form_valid(self, form):
|
|
response = super().form_valid(form)
|
|
hooks.call_hooks('event', name='cut-edit-core', user=self.request.user, form=form)
|
|
return response
|
|
|
|
|
|
edit_core = EditCoreView.as_view()
|
|
|
|
|
|
class EditCrownView(EditProfile):
|
|
template_names = ['authentic2/cut-edit-crown.html']
|
|
|
|
@classmethod
|
|
def get_fields(cls, scopes=None):
|
|
fields, labels = super().get_fields(scopes=scopes)
|
|
# discard fields accessible from core attributes edit page
|
|
return [field for field in fields if field not in EditCoreView.fields], labels
|
|
|
|
def form_valid(self, form):
|
|
response = super().form_valid(form)
|
|
hooks.call_hooks('event', name='cut-edit-crown', user=self.request.user, form=form)
|
|
return response
|
|
|
|
|
|
edit_crown = EditCrownView.as_view()
|
|
|
|
|
|
class UserEditCoreView(UserEditView):
|
|
template_name = 'authentic2/cut_manager_user_edit_core.html'
|
|
permissions = ['custom_user.cut_validate_user']
|
|
|
|
def get_title(self):
|
|
if self.object.attributes.validated:
|
|
return 'Modifier les attributs cœurs'
|
|
return 'Valider les attributs cœurs'
|
|
|
|
def get_fields(self):
|
|
fields = super().get_fields()
|
|
return [field for field in CORE_ATTRIBUTES if field in fields]
|
|
|
|
def get_form(self, *args, **kwargs):
|
|
form = super().get_form(*args, **kwargs)
|
|
for field in form.fields.values():
|
|
field.required = True
|
|
return form
|
|
|
|
def form_valid(self, form, context='office', partner=''):
|
|
response = super().form_valid(form)
|
|
already_validated = form.instance.attributes.validated
|
|
if form.has_changed() or not already_validated:
|
|
form.instance.attributes.validated = True
|
|
form.instance.attributes.validation_context = context
|
|
form.instance.attributes.validation_date = now().date()
|
|
if not partner and self.request.user.ou:
|
|
partner = self.request.user.ou.slug
|
|
form.instance.attributes.validation_partner = partner
|
|
hooks.call_hooks(
|
|
'event',
|
|
user=self.request.user,
|
|
name='manager-cut-validate',
|
|
instance=form.instance,
|
|
form=form,
|
|
context=context,
|
|
partner=partner,
|
|
)
|
|
if already_validated:
|
|
msg = 'Les données cœur ont été modifiées.'
|
|
else:
|
|
msg = 'Le compte a été validé.'
|
|
messages.info(self.request, msg)
|
|
return response
|
|
|
|
|
|
manager_user_edit_core = UserEditCoreView.as_view()
|
|
|
|
|
|
class ManagerUserDetailView(UserDetailView):
|
|
def get(self, request, *args, **kwargs):
|
|
response = super().get(request, *args, **kwargs)
|
|
# journalise les accès aux fiches une fois par heure et par session
|
|
t = now()
|
|
key = 'user-looked-%s-%s-%s' % (self.object, t.date(), t.time().hour)
|
|
if key not in request.session:
|
|
request.session[key] = True
|
|
hooks.call_hooks(
|
|
'event',
|
|
name='manager-view-user',
|
|
user=request.user,
|
|
instance=self.object,
|
|
request=request,
|
|
**kwargs,
|
|
)
|
|
return response
|
|
|
|
|
|
manager_user_detail = ManagerUserDetailView.as_view()
|
|
|
|
|
|
class CGU(RedirectView):
|
|
permanent = True
|
|
|
|
def get_redirect_url(self, *args, **kwargs):
|
|
host = self.request.get_host()
|
|
return f'https://portail-{host}/mentions-legales/'
|
|
|
|
|
|
cgu = CGU.as_view()
|
|
|
|
|
|
def next_validation(request):
|
|
if not request.user.is_authenticated or not request.user.has_perm_any('custom_user.cut_validate_user'):
|
|
raise PermissionDenied
|
|
with atomic():
|
|
validation_request = models.ValidationRequest.objects.next_request(request.user)
|
|
if not validation_request:
|
|
messages.info(request, 'Il n\'y aucune demande de validation en ce moment.')
|
|
return redirect(request, 'a2-manager-homepage')
|
|
return redirect(request, 'cut-manager-user-validation', kwargs={'pk': validation_request.pk})
|
|
|
|
|
|
class Validation(UserEditCoreView):
|
|
template_name = 'authentic2/cut_manager_user_validation.html'
|
|
permissions = ['custom_user.cut_validate_user']
|
|
|
|
def get_object(self, queryset=None):
|
|
qs = models.ValidationRequest.objects.all()
|
|
self.validation_request = super().get_object(queryset=qs)
|
|
return self.validation_request.user
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
# si la demande en cours a déjà été traitée, on passe à la suivante
|
|
try:
|
|
return super().dispatch(request, *args, **kwargs)
|
|
except Http404:
|
|
return redirect(request, 'cut-manager-user-next-validation')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
ctx = super().get_context_data(**kwargs)
|
|
ctx['validation_request'] = self.validation_request
|
|
ctx['attachments'] = self.validation_request.attachments.all()
|
|
ctx['action'] = 'Valider'
|
|
ctx['validation_form'] = forms.ValidationForm()
|
|
return ctx
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
# POST is disabled on already validated requests
|
|
if self.validation_request.validated:
|
|
return self.get(request, *args, **kwargs)
|
|
|
|
if 'refuse' in request.POST:
|
|
reason = request.POST.get('reason')
|
|
if not reason:
|
|
messages.error(request, 'Vous devez préciser une raison pour le refus.')
|
|
return HttpResponseRedirect('')
|
|
messages.info(request, 'Demande traitée.')
|
|
self.validation_request.reason = reason
|
|
self.validation_request.status = models.ValidationRequest.STATUS_REFUSED
|
|
self.validation_request.validated = now()
|
|
self.validation_request.validated_by = request.user
|
|
self.validation_request.save()
|
|
return self.next_request(request)
|
|
elif 'validate' in request.POST:
|
|
return super().post(request, *args, **kwargs)
|
|
else: # next
|
|
return self.next_request(request)
|
|
|
|
def next_request(self, request):
|
|
# on ne trouve plus de requête de validation après celle-ci
|
|
# recommençons du début
|
|
with atomic():
|
|
validation_request = models.ValidationRequest.objects.next_request(
|
|
request.user, after=self.validation_request
|
|
)
|
|
if not validation_request:
|
|
return redirect(request, 'cut-manager-user-next-validation')
|
|
return redirect(request, 'cut-manager-user-validation', kwargs={'pk': validation_request.pk})
|
|
|
|
def form_valid(self, form):
|
|
partner = ''
|
|
if hasattr(self.validation_request.origin, 'ou') and self.validation_request.origin.ou:
|
|
partner = self.validation_request.origin.ou.slug
|
|
if not partner and self.request.user.ou:
|
|
partner = self.request.user.ou.slug
|
|
super(UserEditView, self).form_valid(form)
|
|
form.instance.attributes.validated = True
|
|
form.instance.attributes.validation_context = 'online'
|
|
form.instance.attributes.validation_date = now().date()
|
|
form.instance.attributes.validation_partner = partner
|
|
hooks.call_hooks(
|
|
'event',
|
|
user=self.request.user,
|
|
name='manager-cut-validate',
|
|
instance=form.instance,
|
|
form=form,
|
|
context='office',
|
|
partner=partner,
|
|
)
|
|
self.validation_request.accept(self.request.user)
|
|
messages.info(self.request, 'Demande traitée.')
|
|
return self.next_request(self.request)
|
|
|
|
|
|
validation = Validation.as_view()
|
|
|
|
|
|
def validation_attachment(request, pk, filename):
|
|
if not request.user.is_authenticated or not request.user.has_perm_any('custom_user.cut_validate_user'):
|
|
raise PermissionDenied
|
|
attachment = models.ValidationRequestAttachment.objects.get(pk=pk)
|
|
attachment.image.open()
|
|
mime_type = utils.mime_type_from_buffer(attachment.image.read(10000))
|
|
attachment.image.open()
|
|
return HttpResponse(attachment.image, content_type=mime_type)
|
|
|
|
|
|
def validation_attachment_thumbnail(request, pk, filename):
|
|
if not request.user.is_authenticated or not request.user.has_perm_any('custom_user.cut_validate_user'):
|
|
raise PermissionDenied
|
|
attachment = models.ValidationRequestAttachment.objects.get(pk=pk)
|
|
thumbnail = attachment.thumbnail
|
|
if not thumbnail:
|
|
raise Http404
|
|
return HttpResponse(thumbnail.read(), content_type='image/jpeg')
|
|
|
|
|
|
class ValidationHomepage(BaseTableView):
|
|
template_name = 'authentic2/cut_manager_user_validations.html'
|
|
model = models.ValidationRequest
|
|
table_class = tables.ValidationTable
|
|
permissions = ['custom_user.cut_validate_user']
|
|
title = _('Validation requests')
|
|
|
|
def get_queryset(self):
|
|
qs = super(FilterQuerysetByPermMixin, self).get_queryset()
|
|
if 'all' not in self.request.GET:
|
|
qs = qs.filter(status=models.ValidationRequest.STATUS_RECEIVED)
|
|
qs = qs.prefetch_related('origin').select_related()
|
|
return qs
|
|
|
|
|
|
validation_homepage = ValidationHomepage.as_view()
|