From ffd47cbfa1baa5eb2556e38253f548495b4189f1 Mon Sep 17 00:00:00 2001 From: Étienne Loks Date: Thu, 16 Nov 2023 15:50:38 +0100 Subject: đŸ—ƒïž GDPR: add related models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/fr/source/administrateur-applicatif.rst | 7 +++- example_project/settings.py | 4 ++ .../migrations/0233_gdprlog_gdprperson.py | 45 +++++++++++++++++++++ ishtar_common/models.py | 47 ++++++++++++++++++++++ 4 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 ishtar_common/migrations/0233_gdprlog_gdprperson.py diff --git a/docs/fr/source/administrateur-applicatif.rst b/docs/fr/source/administrateur-applicatif.rst index 03ef53c39..1f11728ac 100644 --- a/docs/fr/source/administrateur-applicatif.rst +++ b/docs/fr/source/administrateur-applicatif.rst @@ -304,11 +304,14 @@ La journalisation consiste Ă  assurer la traçabilitĂ© des actions opĂ©rĂ©es sur - le type de traitement, - des liens vers les personnes concernĂ©es par le traitement. +Si une personne est supprimĂ©e de la base de donnĂ©es, nom et prĂ©nom de cette personne sont sauvegardĂ©es dans une table intermĂ©diaire le temps que des donnĂ©es de journalisation concernant cette personne existent. Les types de traitements identifiĂ©s sont : - consultation de l'annuaire (listing de personnes), -- consultation de fiche personne, +- export de l'annuaire, +- consultation de la notice personne, +- export de la notice personne, - crĂ©ation de personne (formulaire ou import), - modification de personne (formulaire, import ou fusion), - suppression de fiche personne. @@ -320,7 +323,7 @@ Cette journalisation est activĂ©e par dĂ©faut. Elle peut ĂȘtre dĂ©sactivĂ©e par La durĂ©e de conservation des donnĂ©es de journalisation est fixĂ©e Ă  6 mois (durĂ©e minimale prĂ©conisĂ©e par la CNIL). Cette durĂ©e peut ĂȘtre changĂ©e par l'administrateur serveur (paramĂštre `GDPR_RETENTION_PERIOD` dans le fichier `local_settings.py`) mais il convient de rester dans le cadre lĂ©gal (sauf exception la durĂ©e de conservation ne peut excĂ©der un an). Au-delĂ  de la durĂ©e paramĂ©trĂ©e les donnĂ©es sont supprimĂ©es automatiquement (un script vĂ©rifie quotidiennement la pĂ©remption des donnĂ©es). -Ces donnĂ©es sont accessibles en consultation uniquement via l'interface d'administrateur aux utilisateurs : statut « super utilisateur » ou dans le groupe « Administrateur RGPD » (et disposant du statut Ă©quipe : cf. :ref:`gestion des comptes ` ). +Ces donnĂ©es sont accessibles en consultation uniquement (la suppression et la modification ne sont pas possible) via l'interface d'administrateur aux utilisateurs : statut « super utilisateur » ou dans le groupe « Administrateur RGPD » (et disposant du statut Ă©quipe : cf. :ref:`gestion des comptes ` ). .. note:: Si des utilisateurs disposent d'un statut « super utilisateur » mais ne sont pas administrateur RGPD, il est nĂ©cessaire de leur retirer ce statut pour leur donner le groupe « administrateur technique ». diff --git a/example_project/settings.py b/example_project/settings.py index 8e9077aad..74638e353 100644 --- a/example_project/settings.py +++ b/example_project/settings.py @@ -292,6 +292,10 @@ JOINT = " | " # not managed cautiously the dir contening these scripts is not set by default ISHTAR_SCRIPT_DIR = "" +# GDPR +GDPR_LOGGING = True +GDPR_RETENTION_PERIOD = int(30.5 * 6) + 1 # ~ 6 month of logging + # TODO: clean... ISHTAR_FILE_PREFIX = "" ISHTAR_OPE_PREFIX = "OA" diff --git a/ishtar_common/migrations/0233_gdprlog_gdprperson.py b/ishtar_common/migrations/0233_gdprlog_gdprperson.py new file mode 100644 index 000000000..374134fce --- /dev/null +++ b/ishtar_common/migrations/0233_gdprlog_gdprperson.py @@ -0,0 +1,45 @@ +# Generated by Django 2.2.24 on 2023-11-16 15:48 + +import datetime +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('ishtar_common', '0232_default_mandatory_keys_import_permissions'), + ] + + operations = [ + migrations.CreateModel( + name='GDPRPerson', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('raw_name', models.CharField(default='-', max_length=300, verbose_name='Raw name')), + ('person', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ishtar_common.Person', verbose_name='Person')), + ], + options={ + 'verbose_name': 'GDPR - Person', + 'verbose_name_plural': 'GDPR - Persons', + }, + ), + migrations.CreateModel( + name='GDPRLog', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateTimeField(default=datetime.datetime.now, verbose_name='Date')), + ('ip', models.GenericIPAddressField(verbose_name='IP')), + ('activity', models.CharField(choices=[('DC', 'Directory consultation'), ('DE', 'Directory export'), ('PV', "Viewing a person's notice"), ('PE', "Exporting a person's notice"), ('PC', 'Person creation'), ('PM', 'Person modification'), ('PD', 'Person deletion')], max_length=2, verbose_name='Activity')), + ('persons', models.ManyToManyField(blank=True, to='ishtar_common.GDPRPerson', verbose_name='Persons')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='User')), + ], + options={ + 'verbose_name': 'GDPR - Log', + 'verbose_name_plural': 'GDPR - Logs', + 'ordering': ('date',), + }, + ), + ] diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 696020c58..944cbcf5d 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -3203,6 +3203,53 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem): post_save.connect(cached_label_changed, sender=Person) +GDPR_ACTIVITY = ( + ("DC", _("Directory consultation")), + ("DE", _("Directory export")), + ("PV", _("Viewing a person's notice")), + ("PE", _("Exporting a person's notice")), + ("PC", _("Person creation")), + ("PM", _("Person modification")), + ("PD", _("Person deletion")), +) + + +class GDPRPerson(models.Model): + person = models.ForeignKey(Person, verbose_name=_("Person"), on_delete=models.SET_NULL, + blank=True, null=True) + raw_name = models.CharField(_("Raw name"), max_length=300, default="-") + + class Meta: + verbose_name = _("GDPR - Person") + verbose_name_plural = _("GDPR - Persons") + + def __str__(self): + return self.raw_name + + +class GDPRLog(models.Model): + user = models.ForeignKey(User, verbose_name=_("User"), on_delete=models.PROTECT) + date = models.DateTimeField(verbose_name=_("Date"), default=datetime.datetime.now) + ip = models.GenericIPAddressField(verbose_name=_("IP")) + activity = models.CharField(_("Activity"), max_length=2, choices=GDPR_ACTIVITY) + persons = models.ManyToManyField(GDPRPerson, verbose_name=_("Persons"), blank=True) + + class Meta: + verbose_name = _("GDPR - Log") + verbose_name_plural = _("GDPR - Logs") + ordering = ("date",) + ADMIN_SECTION = _("GDPR") + + @property + def activity_lbl(self): + gdpr_activity_dict = dict(GDPR_ACTIVITY) + if self.activity not in gdpr_activity_dict: + return str(_("Unknown activity :")) + self.activity + return gdpr_activity_dict[self.activity] + + def __str__(self): + return f"{self.user.username} - {self.date} - {self.activity_lbl}" + class ProfileType(GeneralType): groups = models.ManyToManyField(Group, verbose_name=_("Groups"), blank=True) -- cgit v1.2.3