Adds related_name for inverse relationship + ViewSet now use the parameter store_id to filter by store_id/tournament

sync
Laurent 1 year ago
parent 0829a1e246
commit 2d2e17eb70
  1. 39
      api/views.py
  2. 46
      tournaments/models/base.py
  3. 6
      tournaments/models/club.py
  4. 2
      tournaments/models/court.py
  5. 8
      tournaments/models/custom_user.py
  6. 2
      tournaments/models/date_interval.py
  7. 10
      tournaments/models/event.py
  8. 2
      tournaments/models/failed_api_call.py
  9. 15
      tournaments/models/group_stage.py
  10. 2
      tournaments/models/log.py
  11. 9
      tournaments/models/match.py
  12. 2
      tournaments/models/model_log.py
  13. 2
      tournaments/models/player_registration.py
  14. 2
      tournaments/models/purchase.py
  15. 11
      tournaments/models/round.py
  16. 17
      tournaments/models/team_registration.py
  17. 2
      tournaments/models/team_score.py
  18. 70
      tournaments/models/tournament.py
  19. 472
      tournaments/models/views.py
  20. 4
      tournaments/views.py

@ -1,5 +1,5 @@
from .serializers import ClubSerializer, CourtSerializer, DateIntervalSerializer, TournamentSerializer, UserSerializer, ChangePasswordSerializer, EventSerializer, RoundSerializer, GroupStageSerializer, MatchSerializer, TeamScoreSerializer, TeamRegistrationSerializer, PlayerRegistrationSerializer, LiveMatchSerializer, PurchaseSerializer, CustomUserSerializer, FailedApiCallSerializer, LogSerializer, DeviceTokenSerializer, DataAccessSerializer from .serializers import ClubSerializer, CourtSerializer, DateIntervalSerializer, TournamentSerializer, UserSerializer, ChangePasswordSerializer, EventSerializer, RoundSerializer, GroupStageSerializer, MatchSerializer, TeamScoreSerializer, TeamRegistrationSerializer, PlayerRegistrationSerializer, LiveMatchSerializer, PurchaseSerializer, CustomUserSerializer, FailedApiCallSerializer, LogSerializer, DeviceTokenSerializer, DataAccessSerializer
from tournaments.models import Club, Tournament, CustomUser, Event, Round, GroupStage, Match, TeamScore, TeamRegistration, PlayerRegistration, Court, DateInterval, Purchase, FailedApiCall, Log, DeviceToken, ModelLog, DataAccess from tournaments.models import Club, Tournament, CustomUser, Event, Round, GroupStage, Match, TeamScore, TeamRegistration, PlayerRegistration, Court, DateInterval, Purchase, FailedApiCall, Log, DeviceToken, ModelLog, DataAccess, BaseModel
from rest_framework import viewsets, permissions from rest_framework import viewsets, permissions
from rest_framework.authtoken.models import Token from rest_framework.authtoken.models import Token
@ -131,7 +131,8 @@ class DataApi(APIView):
except ValueError: except ValueError:
return Response({"error": f"Invalid date format for last_update: {last_update}"}, status=status.HTTP_400_BAD_REQUEST) return Response({"error": f"Invalid date format for last_update: {last_update}"}, status=status.HTTP_400_BAD_REQUEST)
data_access = DataAccess.objects.filter(shared_with=request.user).values_list('model_id', flat=True) data_access_query = Q(shared_with=request.user) | Q(owner=request.user)
data_access = DataAccess.objects.filter(data_access_query).values_list('model_id', flat=True)
log_query = Q(date__gt=last_update) & (Q(user=request.user) | Q(model_id__in=data_access) | Q(parent_model_id__in=data_access)) log_query = Q(date__gt=last_update) & (Q(user=request.user) | Q(model_id__in=data_access) | Q(parent_model_id__in=data_access))
logs = ModelLog.objects.filter(log_query).order_by('date') logs = ModelLog.objects.filter(log_query).order_by('date')
@ -157,6 +158,7 @@ class DataApi(APIView):
updates[log.model_name][log.model_id] = data updates[log.model_name][log.model_id] = data
instance = model.objects.get(id=log.model_id) instance = model.objects.get(id=log.model_id)
self.add_children_recursively(instance, updates) self.add_children_recursively(instance, updates)
self.add_parents_recursively(instance, updates)
elif log.operation == 'REVOKE_ACCESS': elif log.operation == 'REVOKE_ACCESS':
print(f'revoke access {log.model_id} - {log.store_id}') print(f'revoke access {log.model_id} - {log.store_id}')
# data = self.get_data(model, log) # data = self.get_data(model, log)
@ -184,20 +186,27 @@ class DataApi(APIView):
""" """
Recursively add all children of an instance to the updates dictionary. Recursively add all children of an instance to the updates dictionary.
""" """
child_models = instance.get_child_models() child_models = instance.get_children_by_model()
for child_model_name, related_name in child_models.items():
child_model = apps.get_model(app_label='tournaments', model_name=child_model_name)
children = getattr(instance, related_name).all()
for child_model_name, children in child_models.items():
for child in children: for child in children:
if isinstance(child, BaseModel):
serializer_class = build_serializer_class(child_model_name) serializer_class = build_serializer_class(child_model_name)
serializer = serializer_class(child) serializer = serializer_class(child)
updates[child_model_name][child.id] = serializer.data updates[child_model_name][child.id] = serializer.data
# Recursive call for each child
self.add_children_recursively(child, updates) self.add_children_recursively(child, updates)
def add_parents_recursively(self, instance, updates):
parent_models = instance.get_parents_by_model()
for parent_model_name, parent in parent_models.items():
# print(f'parent = {parent_model_name}')
if isinstance(parent, BaseModel):
serializer_class = build_serializer_class(parent_model_name)
serializer = serializer_class(parent)
updates[parent_model_name][parent.id] = serializer.data
self.add_parents_recursively(parent, updates)
def get_data(self, model, log): def get_data(self, model, log):
instance = model.objects.get(id=log.model_id) instance = model.objects.get(id=log.model_id)
serializer_class = build_serializer_class(log.model_name) serializer_class = build_serializer_class(log.model_name)
@ -357,7 +366,7 @@ class RoundViewSet(viewsets.ModelViewSet):
serializer_class = RoundSerializer serializer_class = RoundSerializer
def get_queryset(self): def get_queryset(self):
tournament_id = self.request.query_params.get('tournament') tournament_id = self.request.query_params.get('store_id')
if tournament_id: if tournament_id:
return self.queryset.filter(tournament=tournament_id) return self.queryset.filter(tournament=tournament_id)
if self.request.user: if self.request.user:
@ -369,7 +378,7 @@ class GroupStageViewSet(viewsets.ModelViewSet):
serializer_class = GroupStageSerializer serializer_class = GroupStageSerializer
def get_queryset(self): def get_queryset(self):
tournament_id = self.request.query_params.get('tournament') tournament_id = self.request.query_params.get('store_id')
if tournament_id: if tournament_id:
return self.queryset.filter(tournament=tournament_id) return self.queryset.filter(tournament=tournament_id)
if self.request.user: if self.request.user:
@ -381,7 +390,7 @@ class MatchViewSet(viewsets.ModelViewSet):
serializer_class = MatchSerializer serializer_class = MatchSerializer
def get_queryset(self): def get_queryset(self):
tournament_id = self.request.query_params.get('tournament') tournament_id = self.request.query_params.get('store_id')
if tournament_id: if tournament_id:
return self.queryset.filter(Q(group_stage__tournament=tournament_id) | Q(round__tournament=tournament_id)) return self.queryset.filter(Q(group_stage__tournament=tournament_id) | Q(round__tournament=tournament_id))
if self.request.user: if self.request.user:
@ -393,7 +402,7 @@ class TeamScoreViewSet(viewsets.ModelViewSet):
serializer_class = TeamScoreSerializer serializer_class = TeamScoreSerializer
def get_queryset(self): def get_queryset(self):
tournament_id = self.request.query_params.get('tournament') tournament_id = self.request.query_params.get('store_id')
if tournament_id: if tournament_id:
return self.queryset.filter(team_registration__tournament=tournament_id) return self.queryset.filter(team_registration__tournament=tournament_id)
if self.request.user: if self.request.user:
@ -405,7 +414,7 @@ class TeamRegistrationViewSet(viewsets.ModelViewSet):
serializer_class = TeamRegistrationSerializer serializer_class = TeamRegistrationSerializer
def get_queryset(self): def get_queryset(self):
tournament_id = self.request.query_params.get('tournament') tournament_id = self.request.query_params.get('store_id')
if tournament_id: if tournament_id:
return self.queryset.filter(tournament=tournament_id) return self.queryset.filter(tournament=tournament_id)
if self.request.user: if self.request.user:
@ -417,7 +426,7 @@ class PlayerRegistrationViewSet(viewsets.ModelViewSet):
serializer_class = PlayerRegistrationSerializer serializer_class = PlayerRegistrationSerializer
def get_queryset(self): def get_queryset(self):
tournament_id = self.request.query_params.get('tournament') tournament_id = self.request.query_params.get('store_id')
if tournament_id: if tournament_id:
return self.queryset.filter(team_registration__tournament=tournament_id) return self.queryset.filter(team_registration__tournament=tournament_id)
if self.request.user: if self.request.user:

@ -12,8 +12,50 @@ class BaseModel(models.Model):
"""Override in child models to provide parent reference""" """Override in child models to provide parent reference"""
return None, None return None, None
def get_child_models(self): def get_children_by_model(self):
return {} """
Returns a dictionary where:
- keys are the model names
- values are QuerySets of related objects
"""
children = self._meta.get_fields(include_parents=False, include_hidden=False)
related_objects = {}
for child in children:
if (child.one_to_many or child.one_to_one) and child.auto_created:
model_name = child.related_model.__name__
related_objects[model_name] = getattr(self, child.name).all()
return related_objects
def get_parents_by_model(self):
"""
Returns a dictionary where:
- keys are the model names
- values are the parent model instances
"""
parents = {}
# Get all fields including parent links
fields = self._meta.get_fields(include_parents=True, include_hidden=True)
for field in fields:
# Check if the field is a parent link (OneToOne field that points to a parent model)
if isinstance(field, models.OneToOneRel) and field.parent_link:
model_name = field.related_model.__name__
# Get the parent instance using the related name
parent_instance = getattr(self, field.get_accessor_name())
if parent_instance:
parents[model_name] = parent_instance
# Also check for direct foreign key relationships that might represent parent relationships
elif isinstance(field, models.ForeignKey):
model_name = field.related_model.__name__
parent_instance = getattr(self, field.name)
if parent_instance:
parents[model_name] = parent_instance
return parents
class SideStoreModel(BaseModel): class SideStoreModel(BaseModel):
store_id = models.CharField(max_length=100) store_id = models.CharField(max_length=100)

@ -4,7 +4,7 @@ from . import BaseModel
class Club(BaseModel): class Club(BaseModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
creator = models.ForeignKey('CustomUser', blank=True, null=True, on_delete=models.SET_NULL) # string to avoid circular import creator = models.ForeignKey('CustomUser', blank=True, null=True, on_delete=models.SET_NULL)
name = models.CharField(max_length=50) name = models.CharField(max_length=50)
acronym = models.CharField(max_length=10) acronym = models.CharField(max_length=10)
phone = models.CharField(max_length=15, null=True, blank=True) phone = models.CharField(max_length=15, null=True, blank=True)
@ -24,10 +24,10 @@ class Club(BaseModel):
return self.name return self.name
def events_count(self): def events_count(self):
return len(self.event_set.all()) return len(self.events.all())
def court_name(self, index): def court_name(self, index):
for court in self.court_set.all(): for court in self.courts.all():
if court.index == index and court.name is not None and len(court.name) > 0: if court.index == index and court.name is not None and len(court.name) > 0:
return court.name return court.name

@ -5,7 +5,7 @@ from . import BaseModel, Club
class Court(BaseModel): class Court(BaseModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
index = models.IntegerField(default=0) index = models.IntegerField(default=0)
club = models.ForeignKey(Club, on_delete=models.CASCADE) club = models.ForeignKey(Club, on_delete=models.CASCADE, related_name='courts')
name = models.CharField(max_length=50, null=True, blank=True) name = models.CharField(max_length=50, null=True, blank=True)
exit_allowed = models.BooleanField(default=False) exit_allowed = models.BooleanField(default=False)
indoor = models.BooleanField(default=False) indoor = models.BooleanField(default=False)

@ -11,7 +11,7 @@ class CustomUser(AbstractUser):
last_update = models.DateTimeField(default=now) last_update = models.DateTimeField(default=now)
email = models.EmailField(unique=True) email = models.EmailField(unique=True)
umpire_code = models.CharField(max_length=50, blank=True, null=True) umpire_code = models.CharField(max_length=50, blank=True, null=True)
clubs = models.ManyToManyField(club.Club, blank=True) clubs = models.ManyToManyField(club.Club, blank=True, related_name='creators')
phone = models.CharField(max_length=15, null=True, blank=True) phone = models.CharField(max_length=15, null=True, blank=True)
first_name = models.CharField(max_length=50) first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50)
@ -47,6 +47,10 @@ class CustomUser(AbstractUser):
'summons_use_full_custom_message', 'match_formats_default_duration', 'bracket_match_format_preference', 'summons_use_full_custom_message', 'match_formats_default_duration', 'bracket_match_format_preference',
'group_stage_match_format_preference', 'loser_bracket_match_format_preference', 'device_id'] 'group_stage_match_format_preference', 'loser_bracket_match_format_preference', 'device_id']
def get_parent_reference(self):
"""Override in child models to provide parent reference"""
return None, None
def __str__(self): def __str__(self):
return self.username return self.username
@ -54,7 +58,7 @@ class CustomUser(AbstractUser):
return f"{self.username} : {self.first_name} {self.last_name} | {self.email} | {self.phone}" return f"{self.username} : {self.first_name} {self.last_name} | {self.email} | {self.phone}"
def event_count(self): def event_count(self):
return len(self.event_set.all()) return len(self.events.all())
def full_name(self): def full_name(self):
return f"{self.first_name} {self.last_name}" return f"{self.first_name} {self.last_name}"

@ -4,7 +4,7 @@ from . import BaseModel
class DateInterval(BaseModel): class DateInterval(BaseModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
event = models.ForeignKey('Event', on_delete=models.CASCADE) event = models.ForeignKey('Event', on_delete=models.CASCADE, related_name='date_intervals')
court_index = models.IntegerField() court_index = models.IntegerField()
start_date = models.DateTimeField() start_date = models.DateTimeField()
end_date = models.DateTimeField() end_date = models.DateTimeField()

@ -4,20 +4,14 @@ import uuid
class Event(BaseModel): class Event(BaseModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
club = models.ForeignKey(Club, on_delete=models.SET_NULL, null=True, blank=True) club = models.ForeignKey(Club, on_delete=models.SET_NULL, null=True, blank=True, related_name='events')
creation_date = models.DateTimeField() creation_date = models.DateTimeField()
creator = models.ForeignKey(CustomUser, blank=True, null=True, on_delete=models.SET_NULL) creator = models.ForeignKey(CustomUser, blank=True, null=True, on_delete=models.SET_NULL, related_name='events')
name = models.CharField(max_length=200, null=True, blank=True) name = models.CharField(max_length=200, null=True, blank=True)
federal_tournament_data = models.JSONField(null=True, blank=True) federal_tournament_data = models.JSONField(null=True, blank=True)
tenup_id = models.CharField(max_length=20, null=True, blank=True) tenup_id = models.CharField(max_length=20, null=True, blank=True)
creator_full_name = models.CharField(max_length=200, null=True, blank=True) creator_full_name = models.CharField(max_length=200, null=True, blank=True)
# Data Access
def get_child_models(self):
return {
'Tournament': 'tournament_set',
}
def __str__(self): def __str__(self):
return self.display_name() return self.display_name()

@ -5,7 +5,7 @@ import uuid
class FailedApiCall(BaseModel): class FailedApiCall(BaseModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
date = models.DateTimeField() date = models.DateTimeField()
user = models.ForeignKey(CustomUser, blank=True, null=True, on_delete=models.SET_NULL) user = models.ForeignKey(CustomUser, blank=True, null=True, on_delete=models.SET_NULL, related_name='failed_api_calls')
type = models.CharField(max_length=50) type = models.CharField(max_length=50)
call_id = models.UUIDField() call_id = models.UUIDField()
error = models.TextField() error = models.TextField()

@ -8,7 +8,7 @@ from django.utils import timezone
class GroupStage(SideStoreModel): class GroupStage(SideStoreModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE) tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE, related_name='group_stages')
index = models.IntegerField(default=0) index = models.IntegerField(default=0)
size = models.IntegerField(default=4) size = models.IntegerField(default=4)
format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
@ -19,11 +19,6 @@ class GroupStage(SideStoreModel):
def get_parent_reference(self): def get_parent_reference(self):
return 'Event', self.tournament.event.id return 'Event', self.tournament.event.id
def get_child_models(self):
return {
'Match': 'match_set',
}
def __str__(self): def __str__(self):
return self.display_name() return self.display_name()
# return f"{self.tournament.display_name()} - {self.display_name()}" # return f"{self.tournament.display_name()} - {self.display_name()}"
@ -50,7 +45,7 @@ class GroupStage(SideStoreModel):
gs_teams = {} gs_teams = {}
# init all teams # init all teams
for team_registration in self.teamregistration_set.all(): for team_registration in self.team_registrations.all():
if team_registration in gs_teams: if team_registration in gs_teams:
team = gs_teams[team_registration] team = gs_teams[team_registration]
else: else:
@ -58,7 +53,7 @@ class GroupStage(SideStoreModel):
gs_teams[team_registration] = team gs_teams[team_registration] = team
# compute matches # compute matches
for match in self.match_set.all(): for match in self.matches.all():
lgs.add_match(match) lgs.add_match(match)
team_scores = match.team_scores.all() team_scores = match.team_scores.all()
if len(team_scores) == 2: if len(team_scores) == 2:
@ -99,7 +94,7 @@ class GroupStage(SideStoreModel):
team1.diff += total1 - total2 team1.diff += total1 - total2
team2.diff += total2 - total1 team2.diff += total2 - total1
if len(self.match_set.filter(end_date__isnull=False).all()) > 0: if len(self.matches.filter(end_date__isnull=False).all()) > 0:
teams = sorted(gs_teams.values(), key=lambda team: -(team.wins * 100 + team.diff)) teams = sorted(gs_teams.values(), key=lambda team: -(team.wins * 100 + team.diff))
else: else:
teams = sorted(gs_teams.values(), key=lambda team: team.position) teams = sorted(gs_teams.values(), key=lambda team: team.position)
@ -116,7 +111,7 @@ class GroupStage(SideStoreModel):
return False return False
def has_at_least_one_started_match(self): def has_at_least_one_started_match(self):
for match in self.match_set.all(): for match in self.matches.all():
if match.start_date: if match.start_date:
return True return True
return False return False

@ -5,7 +5,7 @@ import uuid
class Log(BaseModel): class Log(BaseModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
date = models.DateTimeField() date = models.DateTimeField()
user = models.ForeignKey(CustomUser, blank=True, null=True, on_delete=models.SET_NULL) user = models.ForeignKey(CustomUser, blank=True, null=True, on_delete=models.SET_NULL, related_name='logs')
message = models.TextField(blank=True, null=True) message = models.TextField(blank=True, null=True)
def __str__(self): def __str__(self):

@ -9,8 +9,8 @@ from ..utils.extensions import format_seconds
class Match(SideStoreModel): class Match(SideStoreModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
round = models.ForeignKey(Round, null=True, blank=True, on_delete=models.CASCADE) round = models.ForeignKey(Round, null=True, blank=True, on_delete=models.CASCADE, related_name='matches')
group_stage = models.ForeignKey(GroupStage, null=True, blank=True, on_delete=models.CASCADE) group_stage = models.ForeignKey(GroupStage, null=True, blank=True, on_delete=models.CASCADE, related_name='matches')
name = models.CharField(max_length=200, null=True, blank=True) name = models.CharField(max_length=200, null=True, blank=True)
start_date = models.DateTimeField(null=True, blank=True) start_date = models.DateTimeField(null=True, blank=True)
end_date = models.DateTimeField(null=True, blank=True) end_date = models.DateTimeField(null=True, blank=True)
@ -30,11 +30,6 @@ class Match(SideStoreModel):
def get_parent_reference(self): def get_parent_reference(self):
return 'Event', self.tournament().event.id return 'Event', self.tournament().event.id
def get_child_models(self):
return {
'TeamScore': 'team_scores',
}
def __str__(self): def __str__(self):
names = " / ".join(self.player_names()) names = " / ".join(self.player_names())
return f"{self.stage_name()} #{self.index}: {names}" return f"{self.stage_name()} #{self.index}: {names}"

@ -4,7 +4,7 @@ from . import ModelOperation
class ModelLog(models.Model): class ModelLog(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
user = models.ForeignKey('CustomUser', blank=True, null=True, on_delete=models.SET_NULL) user = models.ForeignKey('CustomUser', blank=True, null=True, on_delete=models.SET_NULL, related_name='model_logs')
model_id = models.UUIDField() model_id = models.UUIDField()
operation = models.CharField(choices=ModelOperation.choices, max_length=50) operation = models.CharField(choices=ModelOperation.choices, max_length=50)
date = models.DateTimeField() date = models.DateTimeField()

@ -4,7 +4,7 @@ import uuid
class PlayerRegistration(SideStoreModel): class PlayerRegistration(SideStoreModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
team_registration = models.ForeignKey(TeamRegistration, on_delete=models.CASCADE) team_registration = models.ForeignKey(TeamRegistration, on_delete=models.CASCADE, related_name='player_registrations')
first_name = models.CharField(max_length=50, blank=True) first_name = models.CharField(max_length=50, blank=True)
last_name = models.CharField(max_length=50, blank=True) last_name = models.CharField(max_length=50, blank=True)
licence_id = models.CharField(max_length=20, null=True, blank=True) licence_id = models.CharField(max_length=20, null=True, blank=True)

@ -4,7 +4,7 @@ from . import BaseModel, CustomUser
class Purchase(BaseModel): class Purchase(BaseModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE) user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='purchases')
identifier = models.BigIntegerField() identifier = models.BigIntegerField()
purchase_date = models.DateTimeField() purchase_date = models.DateTimeField()
product_id = models.CharField(max_length=100) product_id = models.CharField(max_length=100)

@ -4,7 +4,7 @@ import uuid
class Round(SideStoreModel): class Round(SideStoreModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE) tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE, related_name='rounds')
index = models.IntegerField(default=0) index = models.IntegerField(default=0)
parent = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE, related_name='children') parent = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE, related_name='children')
format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
@ -14,11 +14,6 @@ class Round(SideStoreModel):
def get_parent_reference(self): def get_parent_reference(self):
return 'Event', self.tournament.event.id return 'Event', self.tournament.event.id
def get_child_models(self):
return {
'Match': 'match_set',
}
def __str__(self): def __str__(self):
if self.parent: if self.parent:
return f"LB: {self.name()}" return f"LB: {self.name()}"
@ -50,7 +45,7 @@ class Round(SideStoreModel):
matches = [] matches = []
for child in self.children.all(): for child in self.children.all():
child_matches = child.match_set.all() child_matches = child.matches.all()
if hide_empty_matches: if hide_empty_matches:
child_matches = [m for m in child_matches if m.should_appear()] child_matches = [m for m in child_matches if m.should_appear()]
else: else:
@ -66,7 +61,7 @@ class Round(SideStoreModel):
return matches return matches
def get_matches_recursive(self, hide_empty_matches): def get_matches_recursive(self, hide_empty_matches):
matches = list(self.match_set.all()) # Retrieve matches associated with the current round matches = list(self.matches.all()) # Retrieve matches associated with the current round
matches = [m for m in matches if m.should_appear()] matches = [m for m in matches if m.should_appear()]
if hide_empty_matches: if hide_empty_matches:
matches = [m for m in matches if m.should_appear()] matches = [m for m in matches if m.should_appear()]

@ -6,8 +6,8 @@ from django.utils import timezone
class TeamRegistration(SideStoreModel): class TeamRegistration(SideStoreModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE) tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE, related_name='team_registrations')
group_stage = models.ForeignKey(GroupStage, null=True, blank=True, on_delete=models.SET_NULL) group_stage = models.ForeignKey(GroupStage, null=True, blank=True, on_delete=models.SET_NULL, related_name='team_registrations')
registration_date = models.DateTimeField(null=True, blank=True) registration_date = models.DateTimeField(null=True, blank=True)
call_date = models.DateTimeField(null=True, blank=True) call_date = models.DateTimeField(null=True, blank=True)
bracket_position = models.IntegerField(null=True, blank=True) bracket_position = models.IntegerField(null=True, blank=True)
@ -34,11 +34,6 @@ class TeamRegistration(SideStoreModel):
def get_parent_reference(self): def get_parent_reference(self):
return 'Event', self.tournament.event.id return 'Event', self.tournament.event.id
def get_child_models(self):
return {
'PlayerRegistration': 'playerregistration_set',
}
def __str__(self): def __str__(self):
if self.name: if self.name:
return self.name return self.name
@ -52,16 +47,16 @@ class TeamRegistration(SideStoreModel):
if self.name: if self.name:
return [self.name] return [self.name]
else: else:
return [pr.name() for pr in self.playerregistration_set.all()] return [pr.name() for pr in self.player_registrations.all()]
def shortened_team_names(self): def shortened_team_names(self):
if self.name: if self.name:
return [self.name] return [self.name]
else: else:
return [pr.shortened_name() for pr in self.playerregistration_set.all()] return [pr.shortened_name() for pr in self.player_registrations.all()]
def player_names(self): def player_names(self):
names = [pr.name() for pr in self.playerregistration_set.all()] names = [pr.name() for pr in self.player_registrations.all()]
str = " - ".join(names) str = " - ".join(names)
if len(str) > 0: if len(str) > 0:
return str return str
@ -94,7 +89,7 @@ class TeamRegistration(SideStoreModel):
return "--" return "--"
def is_valid_for_summon(self): def is_valid_for_summon(self):
return len(self.playerregistration_set.all()) > 0 return len(self.player_registrations.all()) > 0
def initial_weight(self): def initial_weight(self):
if self.locked_weight is None: if self.locked_weight is None:

@ -5,7 +5,7 @@ import uuid
class TeamScore(SideStoreModel): class TeamScore(SideStoreModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
match = models.ForeignKey(Match, on_delete=models.CASCADE, related_name="team_scores") match = models.ForeignKey(Match, on_delete=models.CASCADE, related_name="team_scores")
team_registration = models.ForeignKey(TeamRegistration, on_delete=models.CASCADE, null=True, blank=True) team_registration = models.ForeignKey(TeamRegistration, on_delete=models.CASCADE, null=True, blank=True, related_name="team_scores")
score = models.CharField(max_length=50, null=True, blank=True) score = models.CharField(max_length=50, null=True, blank=True)
walk_out = models.IntegerField(null=True, blank=True) # TODO type of WO: forfeit, injury... walk_out = models.IntegerField(null=True, blank=True) # TODO type of WO: forfeit, injury...
lucky_loser = models.IntegerField(null=True, blank=True) lucky_loser = models.IntegerField(null=True, blank=True)

@ -17,7 +17,7 @@ class TeamSortingType(models.IntegerChoices):
class Tournament(BaseModel): class Tournament(BaseModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
event = models.ForeignKey(Event, blank=True, null=True, on_delete=models.CASCADE) event = models.ForeignKey(Event, blank=True, null=True, on_delete=models.CASCADE, related_name='tournaments')
name = models.CharField(max_length=200, null=True, blank=True) name = models.CharField(max_length=200, null=True, blank=True)
start_date = models.DateTimeField() start_date = models.DateTimeField()
end_date = models.DateTimeField(null=True, blank=True) end_date = models.DateTimeField(null=True, blank=True)
@ -63,16 +63,6 @@ class Tournament(BaseModel):
def get_parent_reference(self): def get_parent_reference(self):
return 'Event', self.event.id return 'Event', self.event.id
def get_child_models(self):
"""
Returns a dictionary of child model names and their related_names.
"""
return {
'Round': 'round_set',
'GroupStage': 'groupstage_set',
'TeamRegistration': 'teamregistration_set'
}
def __str__(self): def __str__(self):
if self.name: if self.name:
return self.name return self.name
@ -206,7 +196,7 @@ class Tournament(BaseModel):
def team_summons(self): def team_summons(self):
summons = [] summons = []
for team_registration in self.teamregistration_set.all(): for team_registration in self.team_registrations.all():
if team_registration.is_valid_for_summon(): if team_registration.is_valid_for_summon():
next_match = team_registration.next_match() next_match = team_registration.next_match()
if next_match and next_match.start_date is not None: if next_match and next_match.start_date is not None:
@ -221,7 +211,7 @@ class Tournament(BaseModel):
def rankings(self): def rankings(self):
rankings = [] rankings = []
for team_registration in self.teamregistration_set.all(): for team_registration in self.team_registrations.all():
if team_registration.walk_out is False and team_registration.final_ranking is not None: if team_registration.walk_out is False and team_registration.final_ranking is not None:
names = team_registration.team_names() names = team_registration.team_names()
ranking = team_registration.final_ranking ranking = team_registration.final_ranking
@ -242,7 +232,7 @@ class Tournament(BaseModel):
complete_teams = [] complete_teams = []
closed_registration_date = self.closed_registration_date closed_registration_date = self.closed_registration_date
for team_registration in self.teamregistration_set.all(): for team_registration in self.team_registrations.all():
is_valid = False is_valid = False
if closed_registration_date is not None and team_registration.registration_date is not None and team_registration.registration_date <= closed_registration_date: if closed_registration_date is not None and team_registration.registration_date is not None and team_registration.registration_date <= closed_registration_date:
is_valid = True is_valid = True
@ -339,10 +329,10 @@ class Tournament(BaseModel):
match_groups = [] match_groups = []
if group_stage_id: if group_stage_id:
group_stage = self.groupstage_set.filter(id=group_stage_id).first() group_stage = self.group_stages.filter(id=group_stage_id).first()
match_groups.append(self.group_stage_match_group(group_stage, broadcasted, hide_empty_matches=False)) match_groups.append(self.group_stage_match_group(group_stage, broadcasted, hide_empty_matches=False))
elif round_id: elif round_id:
round = self.round_set.filter(id=round_id).first() round = self.rounds.filter(id=round_id).first()
if round: if round:
match_groups = self.round_match_groups(round, broadcasted, hide_empty_matches=False) match_groups = self.round_match_groups(round, broadcasted, hide_empty_matches=False)
else: else:
@ -352,11 +342,11 @@ class Tournament(BaseModel):
def all_groups(self, broadcasted): def all_groups(self, broadcasted):
groups = [] groups = []
for round in self.round_set.filter(parent=None).all().order_by('index'): for round in self.rounds.filter(parent=None).all().order_by('index'):
groups.extend(self.round_match_groups(round, broadcasted, hide_empty_matches=True)) groups.extend(self.round_match_groups(round, broadcasted, hide_empty_matches=True))
if self.display_group_stages(): if self.display_group_stages():
for group_stage in self.groupstage_set.all().order_by('index'): for group_stage in self.group_stages.all().order_by('index'):
group = self.group_stage_match_group(group_stage, broadcasted, hide_empty_matches=True) group = self.group_stage_match_group(group_stage, broadcasted, hide_empty_matches=True)
if group: if group:
groups.append(group) groups.append(group)
@ -364,7 +354,7 @@ class Tournament(BaseModel):
return groups return groups
def group_stage_match_group(self, group_stage, broadcasted, hide_empty_matches): def group_stage_match_group(self, group_stage, broadcasted, hide_empty_matches):
matches = group_stage.match_set.all() matches = group_stage.matches.all()
if hide_empty_matches: if hide_empty_matches:
matches = [m for m in matches if m.should_appear()] matches = [m for m in matches if m.should_appear()]
else: else:
@ -378,7 +368,7 @@ class Tournament(BaseModel):
def round_match_groups(self, round, broadcasted, hide_empty_matches): def round_match_groups(self, round, broadcasted, hide_empty_matches):
groups = [] groups = []
matches = round.match_set.order_by('index').all() matches = round.matches.order_by('index').all()
if hide_empty_matches: if hide_empty_matches:
matches = [m for m in matches if m.should_appear()] matches = [m for m in matches if m.should_appear()]
else: else:
@ -407,7 +397,7 @@ class Tournament(BaseModel):
return MatchGroup(name, live_matches) return MatchGroup(name, live_matches)
def live_group_stages(self): def live_group_stages(self):
group_stages = list(self.groupstage_set.all()) group_stages = list(self.group_stages.all())
group_stages.sort(key=lambda gs: gs.index) group_stages.sort(key=lambda gs: gs.index)
return [gs.live_group_stages() for gs in group_stages] return [gs.live_group_stages() for gs in group_stages]
@ -445,7 +435,7 @@ class Tournament(BaseModel):
matches = [] matches = []
group_stages = [] group_stages = []
if len(self.groupstage_set.all()) > 0 and self.no_bracket_match_has_started(): if len(self.group_stages.all()) > 0 and self.no_bracket_match_has_started():
group_stages = self.live_group_stages() group_stages = self.live_group_stages()
matches = self.broadcasted_group_stages_matches() matches = self.broadcasted_group_stages_matches()
first_round = self.first_round() first_round = self.first_round()
@ -473,18 +463,18 @@ class Tournament(BaseModel):
def no_bracket_match_has_started(self): def no_bracket_match_has_started(self):
matches = [] matches = []
for round in self.round_set.all(): for round in self.rounds.all():
for match in round.match_set.all(): for match in round.matches.all():
if match.started(): if match.started():
return False return False
return True return True
def all_matches(self, hide_empty_matches): def all_matches(self, hide_empty_matches):
matches = [] matches = []
for round in self.round_set.all(): for round in self.rounds.all():
matches.extend(round.all_matches(hide_empty_matches)) matches.extend(round.all_matches(hide_empty_matches))
for group_stage in self.groupstage_set.all(): for group_stage in self.group_stages.all():
matches.extend(group_stage.match_set.all()) matches.extend(group_stage.matches.all())
matches = [m for m in matches if m.should_appear()] matches = [m for m in matches if m.should_appear()]
@ -492,12 +482,12 @@ class Tournament(BaseModel):
def group_stage_matches(self): def group_stage_matches(self):
matches = [] matches = []
for group_stage in self.groupstage_set.all(): for group_stage in self.group_stages.all():
matches.extend(group_stage.match_set.all()) matches.extend(group_stage.matches.all())
return matches return matches
def group_stages_running(self): def group_stages_running(self):
if len(self.groupstage_set.all()) > 0: if len(self.group_stages.all()) > 0:
# check le debut des match de Round # check le debut des match de Round
matches = self.group_stage_matches() matches = self.group_stage_matches()
running_group_stage_matches = [m for m in matches if m.end_date is None] running_group_stage_matches = [m for m in matches if m.end_date is None]
@ -519,7 +509,7 @@ class Tournament(BaseModel):
current_round = last_started_match.round.root_round() current_round = last_started_match.round.root_round()
if current_round: if current_round:
return current_round return current_round
main_rounds = list(self.round_set.filter(parent=None).all()) main_rounds = list(self.rounds.filter(parent=None).all())
main_rounds.sort(key=lambda r: r.index) main_rounds.sort(key=lambda r: r.index)
if main_rounds: if main_rounds:
return main_rounds[0] return main_rounds[0]
@ -532,10 +522,10 @@ class Tournament(BaseModel):
return matches[0] return matches[0]
def round_for_index(self, index): def round_for_index(self, index):
return self.round_set.filter(index=index, parent=None).first() return self.rounds.filter(index=index, parent=None).first()
def first_round(self): def first_round(self):
main_rounds = list(self.round_set.filter(parent=None)) main_rounds = list(self.rounds.filter(parent=None))
main_rounds.sort(key=lambda r: r.index, reverse=True) main_rounds.sort(key=lambda r: r.index, reverse=True)
return main_rounds[0] return main_rounds[0]
@ -544,13 +534,13 @@ class Tournament(BaseModel):
group_stages = self.elected_broadcast_group_stages() group_stages = self.elected_broadcast_group_stages()
group_stages.sort(key=lambda gs: (gs.index, gs.start_date is None, gs.start_date)) group_stages.sort(key=lambda gs: (gs.index, gs.start_date is None, gs.start_date))
for group_stage in group_stages: for group_stage in group_stages:
matches.extend(group_stage.match_set.all()) matches.extend(group_stage.matches.all())
matches = [m for m in matches if m.should_appear()] matches = [m for m in matches if m.should_appear()]
matches.sort(key=lambda m: (m.start_date is None, m.end_date is not None, m.start_date, m.index)) matches.sort(key=lambda m: (m.start_date is None, m.end_date is not None, m.start_date, m.index))
return matches return matches
def elected_broadcast_group_stages(self): def elected_broadcast_group_stages(self):
group_stages = list(self.groupstage_set.all()) group_stages = list(self.group_stages.all())
started = [gs for gs in group_stages if gs.starts_soon()] started = [gs for gs in group_stages if gs.starts_soon()]
if len(started) > 0: if len(started) > 0:
return started return started
@ -598,7 +588,7 @@ class Tournament(BaseModel):
def display_group_stages(self): def display_group_stages(self):
if self.end_date is not None: if self.end_date is not None:
return True return True
if len(self.groupstage_set.all()) == 0: if len(self.group_stages.all()) == 0:
return False return False
if self.publish_group_stages: if self.publish_group_stages:
return True return True
@ -610,7 +600,7 @@ class Tournament(BaseModel):
return timezone.now() >= first_group_stage_start_date return timezone.now() >= first_group_stage_start_date
def group_stage_start_date(self): def group_stage_start_date(self):
group_stages = [gs for gs in self.groupstage_set.all() if gs.start_date is not None] group_stages = [gs for gs in self.group_stages.all() if gs.start_date is not None]
if len(group_stages) == 0: if len(group_stages) == 0:
return None return None
@ -640,7 +630,7 @@ class Tournament(BaseModel):
def bracket_matches(self): def bracket_matches(self):
matches = [] matches = []
for round in self.round_set.all(): for round in self.rounds.all():
matches.extend(round.all_matches(False)) matches.extend(round.all_matches(False))
return matches return matches
@ -665,7 +655,7 @@ class Tournament(BaseModel):
return self.federal_level_category == FederalLevelCategory.UNLISTED return self.federal_level_category == FederalLevelCategory.UNLISTED
def is_build_and_not_empty(self): def is_build_and_not_empty(self):
return (len(self.groupstage_set.all()) > 0 or len(self.round_set.all()) > 0) and len(self.teamregistration_set.all()) >= 4 return (len(self.group_stages.all()) > 0 or len(self.rounds.all()) > 0) and len(self.team_registrations.all()) >= 4
def day_duration_formatted(self): def day_duration_formatted(self):
return plural_format("jour", self.day_duration) return plural_format("jour", self.day_duration)
@ -677,7 +667,7 @@ class Tournament(BaseModel):
return False return False
def has_all_group_stages_started(self): def has_all_group_stages_started(self):
for group_stage in self.groupstage_set.all(): for group_stage in self.group_stages.all():
if group_stage.has_at_least_one_started_match() == False: if group_stage.has_at_least_one_started_match() == False:
return False return False
return True return True

@ -1,472 +0,0 @@
from .serializers import ClubSerializer, CourtSerializer, DateIntervalSerializer, TournamentSerializer, UserSerializer, ChangePasswordSerializer, EventSerializer, RoundSerializer, GroupStageSerializer, MatchSerializer, TeamScoreSerializer, TeamRegistrationSerializer, PlayerRegistrationSerializer, LiveMatchSerializer, PurchaseSerializer, CustomUserSerializer, FailedApiCallSerializer, LogSerializer, DeviceTokenSerializer, DataAccessSerializer
from tournaments.models import Club, Tournament, CustomUser, Event, Round, GroupStage, Match, TeamScore, TeamRegistration, PlayerRegistration, Court, DateInterval, Purchase, FailedApiCall, Log, DeviceToken, ModelLog, DataAccess
from rest_framework import viewsets, permissions
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework import status
from rest_framework.generics import UpdateAPIView
from rest_framework.exceptions import MethodNotAllowed
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
from django.contrib.auth import authenticate
from django.db.models import Q
from django.core.exceptions import ObjectDoesNotExist
from django.utils import timezone
from django.apps import apps
from collections import defaultdict
from .permissions import IsClubOwner
from .utils import is_valid_email, build_serializer_class
class DataApi(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, *args, **kwargs):
# unfold content
model_operation = request.data.get('operation')
model_name = request.data.get('model_name')
data = request.data.get('data')
store_id = request.data.get('store_id')
print(f"DataApi post > {model_operation} {model_name}")
serializer_class = build_serializer_class(model_name)
model = apps.get_model(app_label='tournaments', model_name=model_name)
try:
data_id = data.get('id')
instance = model.objects.get(id=data_id)
if model_operation == 'DELETE':
parent_model, parent_id = instance.get_parent_reference()
return self.delete_and_save_log(request, data_id, model_operation, model_name, store_id, parent_id, parent_model)
else: # PUT
serializer = serializer_class(instance, data=data, context={'request': request})
if serializer.is_valid():
if instance.last_update <= serializer.validated_data.get('last_update'):
print('>>> update')
return self.save_and_create_log(request, serializer, model_operation, model_name, store_id)
else:
print('>>> return 203')
return Response(serializer.data, status=status.HTTP_203_NON_AUTHORITATIVE_INFORMATION)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except model.DoesNotExist: # POST
print('>>> insert')
serializer = serializer_class(data=data, context={'request': request})
if serializer.is_valid():
return self.save_and_create_log(request, serializer, model_operation, model_name, store_id)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def save_and_create_log(self, request, serializer, model_operation, model_name, store_id):
instance = serializer.save()
parent_model, parent_id = instance.get_parent_reference()
self.create_and_save_model_log(
user=request.user,
model_operation=model_operation,
model_name=model_name,
model_id=instance.id,
store_id=store_id,
parent_id=parent_id,
parent_model=parent_model
)
return Response(serializer.data, status=status.HTTP_201_CREATED)
def delete_and_save_log(self, request, data_id, model_operation, model_name, store_id, parent_id, parent_model):
model = apps.get_model(app_label='tournaments', model_name=model_name)
print(model)
try:
instance = model.objects.get(id=data_id)
instance.delete()
except model.DoesNotExist:
return Response({"detail": "Not found."}, status=status.HTTP_404_NOT_FOUND)
# we delete all logs linked to the instance because they won't be needed anymore
ModelLog.objects.filter(model_id=data_id).delete()
self.create_and_save_model_log(
user=request.user,
model_operation=model_operation,
model_name=model_name,
model_id=data_id,
store_id=store_id,
parent_id=parent_id,
parent_model=parent_model
)
return Response(status=status.HTTP_204_NO_CONTENT)
def create_and_save_model_log(self, user, model_operation, model_name, model_id, store_id, parent_id, parent_model):
model_log = ModelLog()
model_log.user = user
model_log.operation = model_operation
model_log.date = timezone.localtime(timezone.now())
model_log.model_name = model_name
model_log.model_id = model_id
model_log.store_id = store_id
model_log.parent_model_id = parent_id
model_log.parent_model_name = parent_model
model_log.save()
def get(self, request, *args, **kwargs):
print('/data GET YEAH!')
last_update = request.query_params.get('last_update')
if not last_update:
return Response({"error": "last_update parameter is required"}, status=status.HTTP_400_BAD_REQUEST)
print(last_update)
try:
last_update = timezone.datetime.fromisoformat(last_update)
except ValueError:
return Response({"error": f"Invalid date format for last_update: {last_update}"}, status=status.HTTP_400_BAD_REQUEST)
data_access = DataAccess.objects.filter(shared_with=request.user).values_list('model_id', flat=True)
log_query = Q(date__gt=last_update) & (Q(user=request.user) | Q(model_id__in=data_access))
logs = ModelLog.objects.filter(log_query).order_by('date')
updates = defaultdict(dict)
deletions = defaultdict(list)
for log in logs:
model = apps.get_model(app_label='tournaments', model_name=log.model_name)
if log.operation in ['POST', 'PUT']:
try:
instance = model.objects.get(id=log.model_id)
serializer_class = build_serializer_class(log.model_name)
serializer = serializer_class(instance)
updates[log.model_name][log.model_id] = serializer.data
except model.DoesNotExist:
# If the instance doesn't exist, it might have been deleted after this log was created
pass
elif log.operation == 'DELETE':
deletions[log.model_name].append({'model_id': log.model_id, 'store_id': log.store_id})
# Convert updates dict to list for each model
for model_name in updates:
updates[model_name] = list(updates[model_name].values())
# Convert deletions set to list for each model
for model_name in deletions:
deletions[model_name] = deletions[model_name]
date = logs.last().date.astimezone().isoformat(timespec='seconds') if logs else None
response_data = {
"updates": dict(updates),
"deletions": dict(deletions),
"date": date
}
return Response(response_data, status=status.HTTP_200_OK)
class CustomAuthToken(APIView):
permission_classes = []
def post(self, request, *args, **kwargs):
username = request.data.get('username')
password = request.data.get('password')
device_id = request.data.get('device_id')
user = authenticate(username=username, password=password)
if user is None and is_valid_email(username) == True:
true_username = self.get_username_from_email(username)
user = authenticate(username=true_username, password=password)
if user is not None:
# if user.device_id is None or user.device_id == device_id or user.username == 'apple-test':
# if user.device_id is None or user.device_id == device_id or user.username == 'apple-test':
user.device_id = device_id
user.save()
token, created = Token.objects.get_or_create(user=user)
return Response({'token': token.key})
# else:
# return Response({'error': 'Vous ne pouvez pour l\'instant vous connecter sur plusieurs appareils en même temps. Veuillez vous déconnecter du précédent appareil. Autrement, veuillez contacter le support.'}, status=status.HTTP_403_FORBIDDEN)
else:
return Response({'error': 'L\'utilisateur et le mot de passe de correspondent pas'}, status=status.HTTP_401_UNAUTHORIZED)
def get_username_from_email(self, email):
try:
user = CustomUser.objects.get(email=email)
return user.username
except ObjectDoesNotExist:
return None # or handle the case where the user doesn't exist
class Logout(APIView):
permission_classes = (IsAuthenticated,)
def post(self, request, *args, **kwargs):
# request.user.auth_token.delete()
device_id = request.data.get('device_id')
if request.user.device_id == device_id:
request.user.device_id = None
request.user.save()
return Response(status=status.HTTP_200_OK)
@api_view(['GET'])
def user_by_token(request):
serializer = UserSerializer(request.user)
return Response(serializer.data, status=status.HTTP_200_OK)
class UserViewSet(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = CustomUserSerializer
permission_classes = [] # Users are public whereas the other requests are only for logged users
def get_serializer_class(self):
# Use UserSerializer for other actions (e.g., create, retrieve)
if self.action in ['create', 'retrieve']:
return UserSerializer
return self.serializer_class
class ClubViewSet(viewsets.ModelViewSet):
queryset = Club.objects.all()
serializer_class = ClubSerializer
permission_classes = [IsClubOwner] # Clubs are public whereas the other requests are only for logged users
def perform_create(self, serializer):
serializer.save(creator=self.request.user)
class TournamentViewSet(viewsets.ModelViewSet):
queryset = Tournament.objects.all()
serializer_class = TournamentSerializer
def get_queryset(self):
if self.request.user.is_anonymous:
return []
return self.queryset.filter(
Q(event__creator=self.request.user) |
Q(id__in=DataAccess.objects.filter(
shared_with=self.request.user,
model_name=self.queryset.model.__name__
).values_list('model_id', flat=True))
)
class PurchaseViewSet(viewsets.ModelViewSet):
queryset = Purchase.objects.all()
serializer_class = PurchaseSerializer
def get_queryset(self):
if self.request.user.is_anonymous:
return []
# return self.queryset.filter(user=self.request.user)
return self.queryset.filter(
Q(user=self.request.user) |
Q(id__in=DataAccess.objects.filter(
shared_with=self.request.user,
model_name=self.queryset.model.__name__
).values_list('model_id', flat=True))
)
def put(self, request, pk):
raise MethodNotAllowed('PUT')
def patch(self, request, pk):
raise MethodNotAllowed('PATCH')
def delete(self, request, pk):
raise MethodNotAllowed('DELETE')
# class ExpandedTournamentViewSet(viewsets.ModelViewSet):
# queryset = Tournament.objects.all()
# serializer_class = ExpandedTournamentSerializer
class ChangePasswordView(UpdateAPIView):
serializer_class = ChangePasswordSerializer
def update(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
# if using drf authtoken, create a new token
if hasattr(user, 'auth_token'):
user.auth_token.delete()
token, created = Token.objects.get_or_create(user=user)
# return new token
return Response({'token': token.key}, status=status.HTTP_200_OK)
class EventViewSet(viewsets.ModelViewSet):
queryset = Event.objects.all()
serializer_class = EventSerializer
def get_queryset(self):
if self.request.user.is_anonymous:
return []
# return self.queryset.filter(creator=self.request.user)
return self.queryset.filter(
Q(creator=self.request.user) |
Q(id__in=DataAccess.objects.filter(
shared_with=self.request.user,
model_name=self.queryset.model.__name__
).values_list('model_id', flat=True))
)
class RoundViewSet(viewsets.ModelViewSet):
queryset = Round.objects.all()
serializer_class = RoundSerializer
def get_queryset(self):
tournament_id = self.request.query_params.get('tournament')
if tournament_id:
return self.queryset.filter(tournament=tournament_id)
if self.request.user:
return self.queryset.filter(tournament__event__creator=self.request.user)
return []
class GroupStageViewSet(viewsets.ModelViewSet):
queryset = GroupStage.objects.all()
serializer_class = GroupStageSerializer
def get_queryset(self):
tournament_id = self.request.query_params.get('tournament')
if tournament_id:
return self.queryset.filter(tournament=tournament_id)
if self.request.user:
return self.queryset.filter(tournament__event__creator=self.request.user)
return []
class MatchViewSet(viewsets.ModelViewSet):
queryset = Match.objects.all()
serializer_class = MatchSerializer
def get_queryset(self):
tournament_id = self.request.query_params.get('tournament')
if tournament_id:
return self.queryset.filter(Q(group_stage__tournament=tournament_id) | Q(round__tournament=tournament_id))
if self.request.user:
return self.queryset.filter(Q(group_stage__tournament__event__creator=self.request.user) | Q(round__tournament__event__creator=self.request.user))
return []
class TeamScoreViewSet(viewsets.ModelViewSet):
queryset = TeamScore.objects.all()
serializer_class = TeamScoreSerializer
def get_queryset(self):
tournament_id = self.request.query_params.get('tournament')
if tournament_id:
return self.queryset.filter(team_registration__tournament=tournament_id)
if self.request.user:
return self.queryset.filter(team_registration__tournament__event__creator=self.request.user)
return []
class TeamRegistrationViewSet(viewsets.ModelViewSet):
queryset = TeamRegistration.objects.all()
serializer_class = TeamRegistrationSerializer
def get_queryset(self):
tournament_id = self.request.query_params.get('tournament')
if tournament_id:
return self.queryset.filter(tournament=tournament_id)
if self.request.user:
return self.queryset.filter(tournament__event__creator=self.request.user)
return []
class PlayerRegistrationViewSet(viewsets.ModelViewSet):
queryset = PlayerRegistration.objects.all()
serializer_class = PlayerRegistrationSerializer
def get_queryset(self):
tournament_id = self.request.query_params.get('tournament')
if tournament_id:
return self.queryset.filter(team_registration__tournament=tournament_id)
if self.request.user:
return self.queryset.filter(team_registration__tournament__event__creator=self.request.user)
return []
class CourtViewSet(viewsets.ModelViewSet):
queryset = Court.objects.all()
serializer_class = CourtSerializer
class DateIntervalViewSet(viewsets.ModelViewSet):
queryset = DateInterval.objects.all()
serializer_class = DateIntervalSerializer
def get_queryset(self):
if self.request.user.is_anonymous:
return []
return self.queryset.filter(
Q(event__creator=self.request.user) |
Q(event__id__in=DataAccess.objects.filter(
shared_with=self.request.user,
model_name=self.queryset.model.__name__
).values_list('model_id', flat=True))
)
class FailedApiCallViewSet(viewsets.ModelViewSet):
queryset = FailedApiCall.objects.all()
serializer_class = FailedApiCallSerializer
permission_classes = [] # FailedApiCall are public whereas the other requests are only for logged users
def get_queryset(self):
return []
def perform_create(self, serializer):
if self.request.user.is_anonymous == False:
serializer.save(user=self.request.user)
else:
serializer.save()
class LogViewSet(viewsets.ModelViewSet):
queryset = Log.objects.all()
serializer_class = LogSerializer
permission_classes = [] # Log are public whereas the other requests are only for logged users
def get_queryset(self):
return []
def perform_create(self, serializer):
if self.request.user.is_anonymous == False:
serializer.save(user=self.request.user)
else:
serializer.save()
class DeviceTokenViewSet(viewsets.ModelViewSet):
queryset = DeviceToken.objects.all()
serializer_class = DeviceTokenSerializer
def get_queryset(self):
if self.request.user:
return self.queryset.filter(user=self.request.user)
return []
def create(self, request, *args, **kwargs):
value = request.data.get('value')
if DeviceToken.objects.filter(value=value).exists():
return Response({"detail": "This device token is already registered."}, status=208)
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class DataAccessViewSet(viewsets.ModelViewSet):
queryset = DataAccess.objects.all()
serializer_class = DataAccessSerializer
def get_queryset(self):
if self.request.user:
return self.queryset.filter(owner=self.request.user)
return []

@ -126,8 +126,8 @@ def tournament(request, tournament_id):
group_stage_id = request.GET.get('group_stage') group_stage_id = request.GET.get('group_stage')
match_groups = tournament.match_groups(False, group_stage_id, round_id) match_groups = tournament.match_groups(False, group_stage_id, round_id)
rounds = tournament.round_set.filter(parent=None).order_by('-index') rounds = tournament.rounds.filter(parent=None).order_by('-index')
group_stages = tournament.groupstage_set.order_by('index') group_stages = tournament.group_stages.order_by('index')
print(len(match_groups)) print(len(match_groups))
print(len(rounds)) print(len(rounds))

Loading…
Cancel
Save