Coverage for chats\models.py: 91.4%

66 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-08-30 20:58 +0200

1import uuid 

2from django.db import models 

3from api.base_models import BaseModel 

4from django.template.defaultfilters import date as django_date 

5from travels.models import RequestTravels 

6from users.models import Users 

7from travels.models import RequestTravels 

8 

9# Estados de una solicitud que permiten al usuario estar en el chat 

10CHAT_MEMBER_REQUEST_STATES = ['accepted', 'validated', 'unvalidated'] 

11 

12 

13# Funcion para generar el nombre del chat a partir de los datos del viaje 

14def chat_display_name(travel): 

15 return f"{travel.origin} - {travel.destination} · {django_date(travel.travel_date, 'j F Y')}" 

16 

17 

18# Indica si un usuario puede participar en el chat de un viaje 

19def user_is_eligible(travel, user): 

20 

21 # Si el usuario es el creador del viaje siempre puede participar en el chat 

22 if travel.creation_user_id == user.id: 

23 return True 

24 

25 # Si el usuario tiene una solicitud en uno de los estados que permiten participar en el chat, puede acceder 

26 return RequestTravels.objects.filter( 

27 id_travel=travel, 

28 user=user, 

29 status__code__in=CHAT_MEMBER_REQUEST_STATES, 

30 is_deleted=False, 

31 ).exists() 

32 

33 

34# Indica si un usuario es miembro de un chat de un viaje 

35def user_is_member(travel, user): 

36 # Si no es elegible no puede ser miembro 

37 if not user_is_eligible(travel, user): 

38 return False 

39 # Si tiene un estado de eliminado del chat, tampoco es miembro 

40 return not ChatMembership.objects.filter( 

41 chat__id_travel=travel, 

42 user=user, 

43 is_removed=True, 

44 ).exists() 

45 

46 

47# Devuelve los usuarios que son miembros del chat de un viaje 

48def get_member_users(travel): 

49 member_ids = {travel.creation_user_id} 

50 passenger_ids = RequestTravels.objects.filter( 

51 id_travel=travel, 

52 status__code__in=CHAT_MEMBER_REQUEST_STATES, 

53 is_deleted=False, 

54 ).values_list('user_id', flat=True) 

55 member_ids.update(passenger_ids) 

56 

57 return Users.objects.filter(id__in=member_ids, is_deleted=False) 

58 

59 

60# Modelo del chat de un viaje 

61class Chat(BaseModel): 

62 id = models.UUIDField( 

63 primary_key=True, 

64 default=uuid.uuid4, 

65 editable=False, 

66 db_column='id_chat' 

67 ) 

68 

69 id_travel = models.OneToOneField( 

70 'travels.Travel', 

71 on_delete=models.CASCADE, 

72 db_column='id_travel', 

73 related_name='chat' 

74 ) 

75 

76 class Meta: 

77 db_table = 'chat' 

78 

79 def __str__(self): 

80 return f"Chat {self.id_travel_id}" 

81 

82 # Nombre del chat 

83 @property 

84 def name(self): 

85 travel = self.id_travel 

86 return f"{travel.origin} - {travel.destination}" 

87 

88 # Indica si el usuario indicado puede participar en el chat 

89 def is_member(self, user): 

90 return user_is_member(self.id_travel, user) 

91 

92 # Obtiene el chat asociado a un viaje. 

93 @classmethod 

94 def get_or_create_for_travel(cls, travel): 

95 chat, _ = cls.objects.get_or_create(id_travel=travel) 

96 return chat 

97 

98 

99# Modelo de un mensaje dentro del chat de un viaje 

100class ChatMessage(BaseModel): 

101 id = models.UUIDField( 

102 primary_key=True, 

103 default=uuid.uuid4, 

104 editable=False, 

105 db_column='id_message' 

106 ) 

107 

108 chat = models.ForeignKey( 

109 'chats.Chat', 

110 on_delete=models.CASCADE, 

111 db_column='id_chat', 

112 related_name='messages' 

113 ) 

114 user = models.ForeignKey( 

115 'users.Users', 

116 on_delete=models.CASCADE, 

117 db_column='id_user', 

118 related_name='chat_messages' 

119 ) 

120 content = models.TextField() 

121 

122 class Meta: 

123 db_table = 'chat_message' 

124 ordering = ['created_at'] 

125 indexes = [ 

126 models.Index(fields=['chat', 'created_at']) 

127 ] 

128 

129 def __str__(self): 

130 return f"{self.user_id}: {self.content[:30]}" 

131 

132 

133# Modelo para representar las relaciones que hay entre un usuario y el chat de un viaje 

134# Almacena informacion como si el chat esta muteado para este usaurio, archivado... 

135class ChatMembership(BaseModel): 

136 id = models.UUIDField( 

137 primary_key=True, 

138 default=uuid.uuid4, 

139 editable=False, 

140 db_column='id_membership' 

141 ) 

142 

143 chat = models.ForeignKey( 

144 'chats.Chat', 

145 on_delete=models.CASCADE, 

146 db_column='id_chat', 

147 related_name='memberships' 

148 ) 

149 user = models.ForeignKey( 

150 'users.Users', 

151 on_delete=models.CASCADE, 

152 db_column='id_user', 

153 related_name='chat_memberships' 

154 ) 

155 

156 is_muted = models.BooleanField(default=False) 

157 archived_at = models.DateTimeField(null=True, blank=True) 

158 is_removed = models.BooleanField(default=False) 

159 

160 class Meta: 

161 db_table = 'chat_membership' 

162 constraints = [ 

163 models.UniqueConstraint( 

164 fields=['chat', 'user'], 

165 name='unique_chat_membership_per_user' 

166 ) 

167 ] 

168 

169 def __str__(self): 

170 return f"{self.user_id} @ {self.chat_id}" 

171 

172 

173# Obtiene o crea el estado del chat para un usuario concreto 

174def get_or_create_membership(chat, user): 

175 membership, _ = ChatMembership.objects.get_or_create(chat=chat, user=user) 

176 return membership