Coverage for src / mesh / models / log_models.py: 95%
40 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-02-20 10:03 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-02-20 10:03 +0000
1from enum import Enum, unique
2from typing import Any, Self
4from django.conf import settings
5from django.db import models
7# from django.http import HttpRequest
8from django.utils.translation import gettext_lazy as _
10from .base_models import BaseChangeTrackingModel
13@unique
14class LogType(Enum):
15 # Message automatically created following user actions.
16 GENERATED = "generated"
17 # Message explicitely entered by an user.
18 MANUAL = "manual"
21LOG_TYPES = [lt.value for lt in LogType]
22LOG_TYPE_CHOICES = [
23 (LogType.GENERATED.value, _("Auto generated")),
24 (LogType.MANUAL.value, _("Manual entry")),
25]
28class ModelLog(BaseChangeTrackingModel):
29 """
30 Base class to create a simple log table attached to an entity.
32 TODO: Always store the message text ? For auto generated messages (ex: new version),
33 store a unique message code which could enable message lookup somewhere else ?
34 """
36 attached_to: None | models.ForeignKey = None
37 # Log content (French)
38 content = models.TextField(blank=True, null=True)
39 # Translated content (English)
40 content_en = models.TextField(blank=True, null=True)
41 # Log message code (little helper that can fasten message browsing) - Optional
42 code = models.CharField(max_length=128, null=True, blank=True)
43 # Log type - Automatically generated or explicite user entry
44 type = models.CharField(
45 verbose_name=_("Message type"),
46 max_length=32,
47 choices=LOG_TYPE_CHOICES,
48 default=LogType.GENERATED.value,
49 )
50 impersonated_by = models.ForeignKey(
51 settings.AUTH_USER_MODEL,
52 on_delete=models.SET_NULL,
53 null=True,
54 editable=False,
55 related_name="+",
56 )
57 significant = models.BooleanField(verbose_name=_("Significant log"), default=False)
59 class Meta:
60 abstract = True
62 @classmethod
63 def add_message(
64 cls,
65 attached_to: models.Model,
66 content: str | None = None,
67 content_en: str | None = None,
68 user=None,
69 # impersonate_data=None,
70 # request: HttpRequest | None = None,
71 type: str = "",
72 code: str = "",
73 significant: bool = False,
74 ) -> Self:
75 """
76 Adds an entry to the model log.
77 Automatically checks if the request is performed with active impersonate mode.
78 """
79 kwargs: dict[str, Any] = {"attached_to": attached_to, "significant": significant}
80 if content:
81 kwargs["content"] = content
82 if content_en:
83 kwargs["content_en"] = content_en
84 if type and type in LOG_TYPES:
85 kwargs["type"] = type
86 if code:
87 kwargs["code"] = code
89 new_message = cls(**kwargs)
91 if user.impersonate_data:
92 new_message.impersonated_by_id = user.impersonate_data.source.pk # type: ignore
94 if user.is_authenticated:
95 new_message._user = user # type: ignore
96 # if request.user.is_authenticated:
97 # new_message._user = request.user # type: ignore
99 new_message.save()
101 return new_message