From 5e191ef65c82d6fdbbbe0ae2e2e16fcef8b5ac1c Mon Sep 17 00:00:00 2001
From: Paul Marillonnet <pmarillonnet@entrouvert.com>
Date: Wed, 5 Jan 2022 15:59:44 +0100
Subject: [PATCH 2/3] journal: add user profile management events (#58554)

---
 src/authentic2/journal_event_types.py | 57 +++++++++++++++++++++++++++
 tests/test_manager_journal.py         | 44 ++++++++++++++++++++-
 2 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/src/authentic2/journal_event_types.py b/src/authentic2/journal_event_types.py
index f92c4874..166ef6cc 100644
--- a/src/authentic2/journal_event_types.py
+++ b/src/authentic2/journal_event_types.py
@@ -378,3 +378,60 @@ class UserEmailChange(EventTypeDefinition):
         new_email = event.get_data('email')
         old_email = event.get_data('old_email')
         return _('email address changed from "{0}" to "{1}"').format(old_email, new_email)
+
+
+class UserProfileAdd(EventTypeDefinition):
+    name = 'user.profile.add'
+    label = _('user profile creation')
+
+    @classmethod
+    def record(cls, user, profile_type, object_user, api=False):
+        data = {
+            'profile_type': profile_type.name or profile_type.slug,
+            'object_user': object_user.get_full_name(),
+        }
+        super().record(user=user, data=data, api=api)
+
+    @classmethod
+    def get_message(cls, event, context):
+        profile_type = event.get_data('profile_type')
+        object_user = event.get_data('object_user')
+        return _(f'profile of type "{profile_type}" created for user "{object_user}"')
+
+
+class UserProfileUpdate(EventTypeDefinition):
+    name = 'user.profile.update'
+    label = _('user profile update')
+
+    @classmethod
+    def record(cls, user, profile_type, object_user, api=False):
+        data = {
+            'profile_type': profile_type.name or profile_type.slug,
+            'object_user': object_user.get_full_name(),
+        }
+        super().record(user=user, data=data, api=api)
+
+    @classmethod
+    def get_message(cls, event, context):
+        profile_type = event.get_data('profile_type')
+        object_user = event.get_data('object_user')
+        return _(f'profile of type "{profile_type}" updated for user "{object_user}"')
+
+
+class UserProfileDelete(EventTypeDefinition):
+    name = 'user.profile.delete'
+    label = _('user profile deletion')
+
+    @classmethod
+    def record(cls, user, profile_type, object_user, api=False):
+        data = {
+            'profile_type': profile_type.name or profile_type.slug,
+            'object_user': object_user.get_full_name(),
+        }
+        super().record(user=user, data=data, api=api)
+
+    @classmethod
+    def get_message(cls, event, context):
+        profile_type = event.get_data('profile_type')
+        object_user = event.get_data('object_user')
+        return _(f'profile of type "{profile_type}" deleted for user "{object_user}"')
diff --git a/tests/test_manager_journal.py b/tests/test_manager_journal.py
index 805c151b..8c0bac10 100644
--- a/tests/test_manager_journal.py
+++ b/tests/test_manager_journal.py
@@ -24,7 +24,7 @@ from django.utils.timezone import make_aware
 from authentic2.a2_rbac.models import Role
 from authentic2.a2_rbac.utils import get_default_ou
 from authentic2.apps.journal.models import Event, _registry
-from authentic2.custom_user.models import User
+from authentic2.custom_user.models import ProfileType, User
 from authentic2.journal import journal
 from authentic2.models import Service
 
@@ -50,6 +50,7 @@ def events(db, freezer):
     user = User.objects.create(
         username="user", email="user@example.com", ou=ou, uuid="1" * 32, first_name='Johnny', last_name='doe'
     )
+    profile_type = ProfileType.objects.create(name='One Type', slug='one-type')
     agent = User.objects.create(username="agent", email="agent@example.com", ou=ou, uuid="2" * 32)
     role_user = Role.objects.create(name="role1", ou=ou)
     role_agent = Role.objects.create(name="role2", ou=ou)
@@ -270,6 +271,25 @@ def events(db, freezer):
     make("user.service.sso.refusal", user=user, session=session1, service=service)
     make("user.service.sso.denial", user=user, session=session1, service=service)
 
+    make(
+        'user.profile.add',
+        user=agent,
+        profile_type=profile_type,
+        object_user=user,
+    )
+    make(
+        'user.profile.update',
+        user=agent,
+        profile_type=profile_type,
+        object_user=user,
+    )
+    make(
+        'user.profile.delete',
+        user=agent,
+        profile_type=profile_type,
+        object_user=user,
+    )
+
     # verify we created at least one event for each type
     assert set(Event.objects.values_list("type__name", flat=True)) == set(_registry)
 
@@ -598,6 +618,24 @@ def test_global_journal(app, superuser, events):
             'type': 'user.service.sso.denial',
             'user': 'Johnny doe',
         },
+        {
+            'timestamp': 'Jan. 2, 2020, 10 p.m.',
+            'type': 'user.profile.add',
+            'user': 'agent',
+            'message': 'profile of type "One Type" created for user "Johnny doe"',
+        },
+        {
+            'timestamp': 'Jan. 2, 2020, 11 p.m.',
+            'type': 'user.profile.update',
+            'user': 'agent',
+            'message': 'profile of type "One Type" updated for user "Johnny doe"',
+        },
+        {
+            'timestamp': 'Jan. 3, 2020, midnight',
+            'type': 'user.profile.delete',
+            'user': 'agent',
+            'message': 'profile of type "One Type" deleted for user "Johnny doe"',
+        },
     ]
 
     agent_page = response.click('agent', index=1)
@@ -1097,6 +1135,9 @@ def test_search(app, superuser, events):
 
     table_content = [text_content(p) for p in response.pyquery('tbody td.journal-list--message-column')]
     assert table_content == [
+        'profile of type "One Type" deleted for user "Johnny doe"',
+        'profile of type "One Type" updated for user "Johnny doe"',
+        'profile of type "One Type" created for user "Johnny doe"',
         'automatic activation of user "Johnny doe" because the associated LDAP account reappeared',
         'automatic deactivation of user "Johnny doe" because the associated LDAP source has been deleted',
         'automatic deactivation of user "Johnny doe" because the associated LDAP account does not exist'
@@ -1115,7 +1156,6 @@ def test_search(app, superuser, events):
         'password reset request with email "user@example.com"',
         'user deletion',
         'profile edit (first name)',
-        'password change',
     ]
 
     response.form['event_type'].select(text='Role management')
-- 
2.34.1

