structure du projet + docker, back: mise en place BD et apps, front: début de dev pour le header et mise en place du thème et css global (override des variables bootstrap)
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
from .gdpr_event import GDPR_Event
|
||||
from .global_variable import GlobalVariable
|
||||
from .trackable_model import TrackableModel
|
||||
|
||||
__all__ = [
|
||||
"GDPR_Event",
|
||||
"GlobalVariable",
|
||||
"TrackableModel",
|
||||
]
|
||||
@@ -0,0 +1,51 @@
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class GDPR_Event(models.Model):
|
||||
"""
|
||||
Model to log GDPR-related events for auditing purposes.
|
||||
"""
|
||||
|
||||
EVENT_TYPES = [
|
||||
("DATA_EXPORT", _("Export de données")),
|
||||
("DATA_ANONYMIZATION", _("Anonymisation de données")),
|
||||
("CONSENT_WITHDRAWAL", _("Consentement retiré")),
|
||||
]
|
||||
|
||||
EVENT_REASON = [
|
||||
("USER_REQUEST", _("Demande utilisateur")),
|
||||
("RETENTION_POLICY", _("Politique de conservation")),
|
||||
]
|
||||
|
||||
event_type = models.CharField(
|
||||
max_length=50, choices=EVENT_TYPES, verbose_name=_("type d'événement")
|
||||
)
|
||||
subject_reference = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("objet concerné"),
|
||||
help_text=_("Objet concerné par l'événement : Class:id"),
|
||||
)
|
||||
fields_touched = models.JSONField(
|
||||
blank=True,
|
||||
verbose_name=_("champs affectés"),
|
||||
help_text=_("Liste des champs affectés par l'événement."),
|
||||
)
|
||||
reason = models.CharField(
|
||||
max_length=50, verbose_name=_("raison"), choices=EVENT_REASON
|
||||
)
|
||||
done_at = models.DateTimeField(auto_now_add=True, verbose_name=_("date et heure"))
|
||||
done_by = models.ForeignKey(
|
||||
"users.User",
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
verbose_name=_("Effectué par"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Événement RGPD")
|
||||
verbose_name_plural = _("Événements RGPD")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.get_event_type_display()} - {self.done_at} - {self.subject_reference}"
|
||||
@@ -0,0 +1,23 @@
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from api.core.models.trackable_model import TrackableModel
|
||||
|
||||
|
||||
class GlobalVariable(TrackableModel):
|
||||
"""
|
||||
Model to store global key-value pairs for application-wide settings.
|
||||
"""
|
||||
|
||||
key = models.CharField(max_length=255, unique=True, verbose_name=_("clé"))
|
||||
description = models.TextField(
|
||||
blank=True, default="", verbose_name=_("description")
|
||||
)
|
||||
value = models.JSONField(verbose_name=_("valeur"), null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Paramètre global")
|
||||
verbose_name_plural = _("Paramètres globaux")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.key}: {self.value}"
|
||||
@@ -0,0 +1,95 @@
|
||||
from django.utils import timezone
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class TrackableModel(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("créé le"))
|
||||
created_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.PROTECT,
|
||||
related_name="+",
|
||||
verbose_name=_("créé par"),
|
||||
)
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("modifié le"))
|
||||
updated_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.PROTECT,
|
||||
related_name="+",
|
||||
verbose_name=_("modifié par"),
|
||||
)
|
||||
obsolete = models.BooleanField(default=False, verbose_name=_("obsolète"))
|
||||
obsolete_at = models.DateTimeField(
|
||||
null=True, blank=True, verbose_name=_("obsolète le")
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def soft_delete(self, cascade_m2m=True):
|
||||
"""
|
||||
Soft delete of trackable models. Objct becomes obsolete and obsolescence date is indicated.
|
||||
"""
|
||||
if cascade_m2m:
|
||||
self._cascade_soft_delete_m2m()
|
||||
|
||||
self.obsolete = True
|
||||
self.obsolete_at = timezone.now()
|
||||
self.save(update_fields=["obsolete", "obsolete_at"])
|
||||
|
||||
def _cascade_soft_delete_m2m(self):
|
||||
"""
|
||||
Propagation of soft delete to M2M fields.
|
||||
"""
|
||||
for field in self._meta.get_fields():
|
||||
if field.many_to_many and not field.auto_created:
|
||||
through_model = field.remote_field.through
|
||||
|
||||
if issubclass(through_model, TrackableModel):
|
||||
field_name = None
|
||||
for through_field in through_model._meta.get_fields():
|
||||
if through_field.related_model == self.__class__:
|
||||
field_name = through_field.name
|
||||
break
|
||||
|
||||
if field_name:
|
||||
filter_kwargs = {field_name: self}
|
||||
for relation in through_model.objects.filter(
|
||||
**filter_kwargs, obsolete=False
|
||||
):
|
||||
relation.soft_delete(cascade_m2m=False)
|
||||
|
||||
def restore(self, cascade_m2m=True):
|
||||
"""
|
||||
Restore an object that was soft deleted.
|
||||
"""
|
||||
if cascade_m2m:
|
||||
self._cascade_restore_m2m()
|
||||
|
||||
self.obsolete = False
|
||||
self.obsolete_at = None
|
||||
self.save(update_fields=["obsolete", "obsolete_at"])
|
||||
|
||||
def _cascade_restore_m2m(self):
|
||||
for field in self._meta.get_fields():
|
||||
if field.many_to_many and not field.auto_created:
|
||||
through_model = field.remote_field.through
|
||||
|
||||
if issubclass(through_model, TrackableModel):
|
||||
field_name = None
|
||||
for through_field in through_model._meta.get_fields():
|
||||
if through_field.related_model == self.__class__:
|
||||
field_name = through_field.name
|
||||
break
|
||||
|
||||
if field_name:
|
||||
filter_kwargs = {field_name: self}
|
||||
for relation in through_model.objects.filter(
|
||||
**filter_kwargs, obsolete=True
|
||||
):
|
||||
relation.restore(cascade_m2m=False)
|
||||
Reference in New Issue
Block a user