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