Coverage for sm / models.py: 92%

38 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-24 12:43 +0000

1from django.db import models 

2from django.contrib.auth.models import Group, User 

3from django.db.models.signals import post_save 

4from django.dispatch import receiver 

5from django.utils import timezone 

6from typing import Any 

7import uuid 

8 

9 

10class GroupProfile(models.Model): 

11 group = models.OneToOneField( 

12 Group, on_delete=models.CASCADE, related_name="profile" 

13 ) 

14 owner = models.ForeignKey( 

15 User, 

16 on_delete=models.SET_NULL, 

17 null=True, 

18 blank=True, 

19 related_name="owned_groups", 

20 ) 

21 max_items = models.PositiveIntegerField( 

22 default=200, 

23 help_text="Maximum number of items across all models for this group.", 

24 ) 

25 max_users = models.PositiveIntegerField( 

26 default=2, help_text="Maximum number of users allowed in this group." 

27 ) 

28 

29 def __str__(self) -> str: 

30 return f"Profile for {self.group.name}" 

31 

32 class Meta: 

33 verbose_name = "Group Profile" 

34 verbose_name_plural = "Group Profiles" 

35 

36 

37@receiver(post_save, sender=Group) 

38def create_group_profile( 

39 sender: Any, instance: Group, created: bool, **kwargs: Any 

40) -> None: 

41 if created: 

42 GroupProfile.objects.get_or_create(group=instance) 

43 from .utils_permissions import sync_group_permissions 

44 

45 sync_group_permissions(instance) 

46 

47 

48class Invitation(models.Model): 

49 email = models.EmailField() 

50 group = models.ForeignKey( 

51 Group, on_delete=models.CASCADE, related_name="invitations" 

52 ) 

53 token = models.UUIDField(default=uuid.uuid4, unique=True) 

54 created_at = models.DateTimeField(default=timezone.now) 

55 created_by = models.ForeignKey( 

56 User, on_delete=models.SET_NULL, null=True, related_name="invitations_sent" 

57 ) 

58 accepted_at = models.DateTimeField(null=True, blank=True) 

59 

60 class Meta: 

61 verbose_name = "Invitation" 

62 verbose_name_plural = "Invitations" 

63 unique_together = ["email", "group"] 

64 

65 def __str__(self) -> str: 

66 return f"Invitation for {self.email} to {self.group.name}" 

67 

68 def is_expired(self) -> bool: 

69 return timezone.now() - self.created_at > timezone.timedelta(hours=24)