Adds related_name for inverse relationship + ViewSet now use the parameter store_id to filter by store_id/tournament
parent
0829a1e246
commit
2d2e17eb70
@ -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 [] |
||||
Loading…
Reference in new issue