Coverage for src / mesh / models / orm / discussion_models.py: 73%

37 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-10-22 07:20 +0000

1from django.core.exceptions import ValidationError 

2from django.db import models 

3from django.utils.translation import gettext_lazy as _ 

4 

5from mesh.crud.comments import submission_roles 

6from mesh.models.orm.submission_models import Submission 

7from mesh.models.orm.user_models import User 

8 

9 

10class DiscussionType(models.TextChoices): 

11 EDITOR_AUTHOR = "author", _("Éditeurs / Auteurs") 

12 EDITOR_REVIEWER = "reviewer", _("Éditeurs / Relecteurs") 

13 EDITOR_ONLY = "editor", _("Éditeurs") 

14 

15 

16# ROLE_ICON: dict[str, str] = { 

17# DiscussionType.EDITOR_AUTHOR: "fa-solid fa-user-pen", 

18# DiscussionType.EDITOR_REVIEWER: "fa-solid fa-magnifying-glass", 

19# DiscussionType.EDITOR_ONLY: "fa-regular fa-newspaper", 

20# } 

21 

22# Roles that can be added to the same discussion 

23ALLOWED_ROLES: dict[str, set[str]] = { 

24 DiscussionType.EDITOR_AUTHOR: {"author", "editor"}, 

25 DiscussionType.EDITOR_REVIEWER: {"reviewer", "editor"}, 

26 DiscussionType.EDITOR_ONLY: {"editor"}, 

27} 

28 

29 

30class Discussion(models.Model): 

31 submission = models.ForeignKey( 

32 Submission, on_delete=models.CASCADE, related_name="discussions" 

33 ) 

34 type = models.CharField(max_length=32, choices=DiscussionType.choices) 

35 title = models.CharField(max_length=255, blank=True) 

36 members = models.ManyToManyField(User, related_name="discussions", blank=True) 

37 created_at = models.DateTimeField(auto_now_add=True) 

38 

39 class Meta: 

40 ordering = ["created_at"] 

41 

42 def __str__(self) -> str: 

43 return f"{self.get_type_display()} — submission {self.submission_id}" 

44 

45 def validate_members(self) -> None: 

46 """ 

47 Check that all selected users roles on the submission match the discussion roles. 

48 """ 

49 allowed = ALLOWED_ROLES[self.type] 

50 

51 if allowed is None: 

52 raise ValidationError(_("Missing discussion type : %(type)r") % {"type": self.type}) 

53 

54 for member in self.members.all(): 

55 roles = submission_roles(member, submission=self.submission) 

56 if not roles: 

57 raise ValidationError( 

58 _("%(user)s have no role on this submission.") % {"user": member} 

59 ) 

60 # if user role set not included in allowed role's set 

61 if not roles <= allowed: 

62 raise ValidationError( 

63 _("%(user)s has a non matching role for this discussion « %(type)s ».") 

64 % {"user": member, "type": self.get_type_display()} 

65 ) 

66 

67 

68class DiscussionRead(models.Model): 

69 discussion = models.ForeignKey(Discussion, on_delete=models.CASCADE) 

70 user = models.ForeignKey(User, on_delete=models.CASCADE) 

71 date_last_seen = models.DateTimeField(null=True, blank=True, default=None) 

72 

73 class Meta: 

74 unique_together = ("discussion", "user")