apps: ajoute des gestionnaires d'évènement pour les statistiques et le journal (fixes #17571 #16585)
This commit is contained in:
parent
d8410facef
commit
85152539a6
|
@ -21,6 +21,7 @@ import django.apps
|
|||
|
||||
from django.conf import settings
|
||||
from django.db import router, DEFAULT_DB_ALIAS
|
||||
from django.utils.timezone import now
|
||||
|
||||
|
||||
class AppConfig(django.apps.AppConfig):
|
||||
|
@ -292,6 +293,19 @@ class AppConfig(django.apps.AppConfig):
|
|||
serializer.get_phone_number_fc = get_phone_number_fc
|
||||
serializer.fields['phone_number_fc'] = serializers.SerializerMethodField()
|
||||
|
||||
# override serializer.create to set the creation mode
|
||||
old_create = serializer.create
|
||||
|
||||
def new_create(*args, **kwargs):
|
||||
instance = old_create(*args, **kwargs)
|
||||
request = serializer.context['request']
|
||||
if hasattr(request.user, 'oidc_client'):
|
||||
ou = request.user.oidc_client.ou
|
||||
instance.attributes.creation_partner = ou.slug
|
||||
instance.attributes.creation_mode = 'BO'
|
||||
return instance
|
||||
serializer.create = new_create
|
||||
|
||||
# execute after other modifiers
|
||||
a2_hook_api_modify_serializer.order = 999
|
||||
|
||||
|
@ -452,3 +466,123 @@ class AppConfig(django.apps.AppConfig):
|
|||
user_info['address_fc_formatted'] = address
|
||||
user_info['phone_number_fc'] = fc_user_info.get('phone_number')
|
||||
logging.info(u'modified user_info %s', user_info)
|
||||
|
||||
def a2_hook_event(self, name, **kwargs):
|
||||
method_name = 'cut_event_' + name.replace('-', '_')
|
||||
if hasattr(self, method_name):
|
||||
getattr(self, method_name)(**kwargs)
|
||||
|
||||
def log_action(self, actor, message):
|
||||
from . import models
|
||||
models.Journal.objects.create(
|
||||
actor=actor,
|
||||
message=message)
|
||||
|
||||
def log_modification(self, actor, subject, message):
|
||||
from . import models
|
||||
models.Journal.objects.create(
|
||||
actor=actor,
|
||||
subject=subject,
|
||||
message=message)
|
||||
|
||||
@property
|
||||
def redis_client(self):
|
||||
from django.core import cache
|
||||
return cache.cache.client.get_client()
|
||||
|
||||
def stat(self, *args):
|
||||
t = now()
|
||||
key = 'stat__%s%02d__' % (t.date(), t.hour)
|
||||
key += '__'.join(args)
|
||||
self.redis_client.expire(key, 3600 * 24 * 7)
|
||||
self.redis_client.incr(key)
|
||||
|
||||
def cut_event_login(self, user, how, service=None, **kwargs):
|
||||
# log login for current user
|
||||
if how.startswith('password'):
|
||||
msg = u'connexion par mot de passe'
|
||||
method = 'PWD'
|
||||
elif how == 'france-connect':
|
||||
msg = u'connexion par FranceConnect'
|
||||
method = 'FC'
|
||||
else:
|
||||
msg = u'connexion how:%s'
|
||||
method = how.upper()
|
||||
if service:
|
||||
msg += u' pour %s' % service
|
||||
self.log_action(user, msg)
|
||||
self.stat('login', method)
|
||||
|
||||
def cut_event_registration(self, user, view, form, token, service, **kwargs):
|
||||
# log registration for current user
|
||||
creation_mode = 'FO'
|
||||
msg = u'création du compte en ligne'
|
||||
if 'franceconnect' in token:
|
||||
creation_mode = 'FC'
|
||||
msg = u'création du compte via France Connect'
|
||||
user.attributes.creation_mode = creation_mode
|
||||
self.log_action(user, msg)
|
||||
if service:
|
||||
user.attributes.creation_partner = service
|
||||
|
||||
def cut_event_sso_request(self, idp, service, **kwargs):
|
||||
self.stat('sso-request', service.slug)
|
||||
|
||||
def cut_event_sso_success(self, idp, service, user, **kwargs):
|
||||
msg = u'connexion à %s' % service.name
|
||||
self.log_action(user, msg)
|
||||
self.stat('sso-success', service.slug)
|
||||
|
||||
def cut_event_cut_edit_core(self, user, **kwargs):
|
||||
self.log_action(user, u'édition du profil coeur')
|
||||
|
||||
def cut_event_cut_edit_crown(self, user, **kwargs):
|
||||
self.log_action(user, u'édition du profil couronne')
|
||||
|
||||
def cut_event_password_reset_confirm(self, user, **kwargs):
|
||||
self.log_action(user, u'ré-initialisation du mot de passe')
|
||||
|
||||
def cut_event_change_email_confirm(self, user, **kwargs):
|
||||
self.log_action(user, u'changement de l\'adresse de courriel')
|
||||
|
||||
def cut_event_delete_account(self, user, **kwargs):
|
||||
self.log_action(user, u'demande de suppression du compte')
|
||||
|
||||
def cut_event_manager_action(self, user, action, instance, **kwargs):
|
||||
msgs = {
|
||||
'activate': u'ré-activation du compte',
|
||||
'deactivate': u'suspension du compte',
|
||||
'password_reset': u'envoi d\'un courriel de ré-initialisation du mot de passe',
|
||||
'force_password_change': u'force un changement de mot de passe à '
|
||||
u'la prochaine connexion',
|
||||
'delete_password_reset': u'supprime l\'obligation de changement de mot de passe à '
|
||||
u'la prochaine connexion',
|
||||
}
|
||||
if action.name in msgs:
|
||||
self.log_modification(user, instance, msgs[action.name])
|
||||
|
||||
def cut_event_manager_add_user(self, user, instance, **kwargs):
|
||||
self.log_modification(user, instance, u'création d\'un utilisateur')
|
||||
|
||||
def cut_event_manager_edit_user(self, user, instance, **kwargs):
|
||||
if instance.ou and instance.ou.slug != 'usagers':
|
||||
self.log_modification(user, instance, u'modification du profil')
|
||||
|
||||
def cut_event_manager_delete_user(self, user, instance, **kwargs):
|
||||
self.log_action(self, user, u'suppression de l\'utilisateur %s' % instance)
|
||||
|
||||
def cut_event_manager_add_role_member(self, user, role, member, **kwargs):
|
||||
self.log_modification(user, member, u'ajoute le rôle %s' % role)
|
||||
|
||||
def cut_event_manager_remove_role_member(self, user, role, member, **kwargs):
|
||||
self.log_modification(user, member, u'retire le rôle %s' % role)
|
||||
|
||||
def cut_event_manager_cut_validate(self, user, instance, **kwargs):
|
||||
if instance.attributes.validated:
|
||||
msg = u'modification des données cœur'
|
||||
else:
|
||||
msg = u'validation du compte'
|
||||
self.log_modification(user, instance, msg)
|
||||
|
||||
def cut_event_manager_view_user(self, user, instance, **kwargs):
|
||||
self.log_modification(user, instance, u'fiche consultée')
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('authentic2_cut', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='journal',
|
||||
name='subject',
|
||||
field=models.ForeignKey(related_name='subject_journal', verbose_name=b'Sujet', to=settings.AUTH_USER_MODEL, null=True),
|
||||
),
|
||||
]
|
|
@ -14,6 +14,7 @@ class Journal(models.Model):
|
|||
subject = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
verbose_name='Sujet',
|
||||
null=True,
|
||||
related_name='subject_journal')
|
||||
message = models.TextField(
|
||||
verbose_name='Message')
|
||||
|
|
|
@ -24,9 +24,10 @@ from django.views.generic.base import TemplateView
|
|||
from authentic2.views import EditProfile
|
||||
from authentic2.manager.views import SimpleSubTableView
|
||||
from authentic2.manager.user_views import UserEditView, UserDetailView
|
||||
from authentic2 import hooks
|
||||
|
||||
from .custom_settings import CORE_ATTRIBUTES
|
||||
from . import tables, models
|
||||
from . import tables
|
||||
|
||||
|
||||
class EditCoreView(EditProfile):
|
||||
|
@ -45,6 +46,11 @@ class EditCoreView(EditProfile):
|
|||
fields, labels = super(EditCoreView, cls).get_fields()
|
||||
return [field for field in fields if field in cls.fields], labels
|
||||
|
||||
def form_valid(self, form):
|
||||
response = super(EditCoreView, self).form_valid(self)
|
||||
hooks.call_hooks('event', name='cut-edit-core', user=self.request.user, form=form)
|
||||
return response
|
||||
|
||||
edit_core = EditCoreView.as_view()
|
||||
|
||||
|
||||
|
@ -64,6 +70,11 @@ class EditCrownView(EditProfile):
|
|||
fields, labels = super(EditCrownView, cls).get_fields()
|
||||
return [field for field in fields if field not in cls.fields], labels
|
||||
|
||||
def form_valid(self, form):
|
||||
response = super(EditCrownView, self).form_valid(self)
|
||||
hooks.call_hooks('event', name='cut-edit-crown', user=self.request.user, form=form)
|
||||
return response
|
||||
|
||||
edit_crown = EditCrownView.as_view()
|
||||
|
||||
|
||||
|
@ -90,65 +101,22 @@ class UserEditCoreView(UserEditView):
|
|||
|
||||
def form_valid(self, form):
|
||||
response = super(UserEditCoreView, self).form_valid(form)
|
||||
hooks.call_hooks('event', user=self.request.user, name='manager-cut-validate',
|
||||
instance=form.instance, form=form)
|
||||
if not form.instance.attributes.validated:
|
||||
models.Journal.objects.create(
|
||||
actor=self.request.user,
|
||||
subject=self.object,
|
||||
message='validation du compte')
|
||||
form.instance.attributes.validated = True
|
||||
form.instance.attributes.validation_context = 'office'
|
||||
form.instance.attributes.validation_date = now().date()
|
||||
messages.info(self.request, u'Le compte a été validé.')
|
||||
msg = u'Le compte a été validé.'
|
||||
else:
|
||||
models.Journal.objects.create(
|
||||
actor=self.request.user,
|
||||
subject=self.object,
|
||||
message='modification des données cœur')
|
||||
messages.info(self.request, u'Les données cœur ont été modifié.')
|
||||
msg = u'Les données cœur ont été modifié.'
|
||||
messages.info(self.request, msg)
|
||||
return response
|
||||
|
||||
manager_user_edit_core = UserEditCoreView.as_view()
|
||||
|
||||
|
||||
class ManagerUserDetailView(UserDetailView):
|
||||
def action_force_password_change(self, request, *args, **kwargs):
|
||||
models.Journal.objects.create(
|
||||
actor=self.request.user,
|
||||
subject=self.object,
|
||||
message=u'obligation de changement de mot de passe à la prochaine connexion')
|
||||
return super(ManagerUserDetailView, self).action_force_password_change(
|
||||
request, *args, **kwargs)
|
||||
|
||||
def action_activate(self, request, *args, **kwargs):
|
||||
models.Journal.objects.create(
|
||||
actor=self.request.user,
|
||||
subject=self.object,
|
||||
message=u'ré-activation du compte')
|
||||
return super(ManagerUserDetailView, self).action_activate(request, *args, **kwargs)
|
||||
|
||||
def action_deactivate(self, request, *args, **kwargs):
|
||||
models.Journal.objects.create(
|
||||
actor=self.request.user,
|
||||
subject=self.object,
|
||||
message=u'suspension du compte')
|
||||
return super(ManagerUserDetailView, self).action_deactivate(request, *args, **kwargs)
|
||||
|
||||
def action_password_reset(self, request, *args, **kwargs):
|
||||
models.Journal.objects.create(
|
||||
actor=self.request.user,
|
||||
subject=self.object,
|
||||
message=u'demande de réinitialisation du mot de passe')
|
||||
return super(ManagerUserDetailView, self).action_password_reset(request, *args, **kwargs)
|
||||
|
||||
def action_delete_password_change(self, request, *args, **kwargs):
|
||||
models.Journal.objects.create(
|
||||
actor=self.request.user,
|
||||
subject=self.object,
|
||||
message=u'supprime l\'obligation de changement de mot de passe à la prochaine '
|
||||
u'connexion')
|
||||
return super(ManagerUserDetailView, self).action_delete_password_change(
|
||||
request, *args, **kwargs)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
response = super(ManagerUserDetailView, self).get(request, *args, **kwargs)
|
||||
# journalise les accès aux fiches une fois par heure et par session
|
||||
|
@ -156,10 +124,8 @@ class ManagerUserDetailView(UserDetailView):
|
|||
key = 'user-looked-%s-%s-%s' % (self.object, t.date(), t.time().hour)
|
||||
if key not in request.session:
|
||||
request.session[key] = True
|
||||
models.Journal.objects.create(
|
||||
actor=self.request.user,
|
||||
subject=self.object,
|
||||
message=u'fiche consultée')
|
||||
hooks.call_hooks('event', name='manager-view-user', user=request.user,
|
||||
instance=self.object, request=request, **kwargs)
|
||||
return response
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue