authentic2-cut/src/authentic2_cut/views.py

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()