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
« 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
9# Estados de una solicitud que permiten al usuario estar en el chat
10CHAT_MEMBER_REQUEST_STATES = ['accepted', 'validated', 'unvalidated']
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')}"
18# Indica si un usuario puede participar en el chat de un viaje
19def user_is_eligible(travel, user):
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
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()
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()
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)
57 return Users.objects.filter(id__in=member_ids, is_deleted=False)
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 )
69 id_travel = models.OneToOneField(
70 'travels.Travel',
71 on_delete=models.CASCADE,
72 db_column='id_travel',
73 related_name='chat'
74 )
76 class Meta:
77 db_table = 'chat'
79 def __str__(self):
80 return f"Chat {self.id_travel_id}"
82 # Nombre del chat
83 @property
84 def name(self):
85 travel = self.id_travel
86 return f"{travel.origin} - {travel.destination}"
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)
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
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 )
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()
122 class Meta:
123 db_table = 'chat_message'
124 ordering = ['created_at']
125 indexes = [
126 models.Index(fields=['chat', 'created_at'])
127 ]
129 def __str__(self):
130 return f"{self.user_id}: {self.content[:30]}"
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 )
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 )
156 is_muted = models.BooleanField(default=False)
157 archived_at = models.DateTimeField(null=True, blank=True)
158 is_removed = models.BooleanField(default=False)
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 ]
169 def __str__(self):
170 return f"{self.user_id} @ {self.chat_id}"
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