From 821149ae542bb1fb6dc9f1158558efd4c7602554 Mon Sep 17 00:00:00 2001 From: Adibov Date: Fri, 24 Nov 2023 14:44:36 +0330 Subject: [PATCH] feat: add capacity field to presentation --- .../migrations/0048_presentation_capacity.py | 18 +++++++ backend/backend_api/models.py | 51 ++++++++++++------- backend/backend_api/serializers.py | 18 ++++++- backend/backend_api/views.py | 37 +++++--------- 4 files changed, 81 insertions(+), 43 deletions(-) create mode 100644 backend/backend_api/migrations/0048_presentation_capacity.py diff --git a/backend/backend_api/migrations/0048_presentation_capacity.py b/backend/backend_api/migrations/0048_presentation_capacity.py new file mode 100644 index 0000000..9b2e9f8 --- /dev/null +++ b/backend/backend_api/migrations/0048_presentation_capacity.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.4 on 2023-11-24 11:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('backend_api', '0047_remove_payment_is_done_payment_status'), + ] + + operations = [ + migrations.AddField( + model_name='presentation', + name='capacity', + field=models.PositiveIntegerField(default=50), + ), + ] diff --git a/backend/backend_api/models.py b/backend/backend_api/models.py index 8519973..26c1f11 100644 --- a/backend/backend_api/models.py +++ b/backend/backend_api/models.py @@ -9,15 +9,12 @@ from django.template.loader import render_to_string from django.urls import reverse from django.utils.translation import gettext_lazy as _ -from rest_framework import status -from rest_framework.response import Response from aaiss_backend import settings from aaiss_backend.settings import BASE_URL from backend_api import validators from backend_api.email import MailerThread from utils.random import create_random_string -from utils.renderers import new_detailed_response SMALL_MAX_LENGTH = 255 BIG_MAX_LENGTH = 65535 @@ -70,7 +67,7 @@ class Teacher(models.Model): bio = models.CharField(max_length=BIG_MAX_LENGTH) order = models.SmallIntegerField(default=0) year = models.IntegerField(blank=False, default=2020) - + def __str__(self): return f"Teacher with id {self.id}: {self.name}" @@ -122,15 +119,24 @@ class Workshop(models.Model): start_date = models.DateTimeField() end_date = models.DateTimeField() - def no_of_participants(self): - return len(User.objects.filter(registered_workshops=self).all()) + @property + def no_of_participants(self) -> int: + return len( + WorkshopRegistration.objects.filter(workshop=self, + status=WorkshopRegistration.StatusChoices.PURCHASED)) + + @property + def remaining_capacity(self) -> int: + return max(self.capacity - self.no_of_participants, 0) @property def participants(self): - users = [] - for user in User.objects.filter(registered_workshops=self).all(): - users.append(user) - return users + participants = [] + for participant in WorkshopRegistration.objects.filter(presentation=self, + status= + WorkshopRegistration.StatusChoices.PURCHASED): + participants += participant.user + return participants def __str__(self): name = "" @@ -145,6 +151,7 @@ class Presentation(models.Model): desc = models.CharField(max_length=BIG_MAX_LENGTH) year = models.IntegerField(blank=False, default=2020) cost = models.PositiveIntegerField(default=0) + capacity = models.PositiveIntegerField(default=50) NOT_ASSIGNED = 'NOT_ASSIGNED' ELEMENTARY = 'Elementary' @@ -166,15 +173,24 @@ class Presentation(models.Model): start_date = models.DateTimeField() end_date = models.DateTimeField() - def no_of_participants(self): - return len(User.objects.filter(registered_for_presentations=True).all()) + @property + def no_of_participants(self) -> int: + return len( + PresentationParticipation.objects.filter(presentation=self, + status=PresentationParticipation.StatusChoices.PURCHASED)) + + @property + def remaining_capacity(self) -> int: + return max(self.capacity - self.no_of_participants, 0) @property def participants(self): - users = [] - for user in User.objects.filter(registered_for_presentations=True).all(): - users.append(user) - return users + participants = [] + for participant in PresentationParticipation.objects.filter(presentation=self, + status= + PresentationParticipation.StatusChoices.PURCHASED): + participants += participant.user + return participants def __str__(self): name = "" @@ -344,7 +360,8 @@ def create_payment_for_user(user: User): raise ValueError(f"User {user} is registered for workshop {workshop} but has no registration") for presentation in user.participated_presentations.all(): try: - presentation_participation = presentation.presentationparticipation_set.get(presentation_id=presentation.id) + presentation_participation = presentation.presentationparticipation_set.get( + presentation_id=presentation.id) if presentation_participation.status != PresentationParticipation.StatusChoices.AWAITING_PAYMENT: continue total_cost += presentation.cost diff --git a/backend/backend_api/serializers.py b/backend/backend_api/serializers.py index 3f41622..83732ff 100644 --- a/backend/backend_api/serializers.py +++ b/backend/backend_api/serializers.py @@ -18,8 +18,6 @@ class Meta: FieldOfInterestSerializer = all_serializer_creator(models.FieldOfInterest) TeacherSerializer = all_serializer_creator(models.Teacher) PresenterSerializer = all_serializer_creator(models.Presenter) -WorkshopSerializer = all_serializer_creator(models.Workshop) -PresentationSerializer = all_serializer_creator(models.Presentation) MiscSerializer = all_serializer_creator(models.Misc) CommitteeSerializer = all_serializer_creator(models.Committee) StaffSerializer = all_serializer_creator(models.Staff) @@ -57,6 +55,22 @@ class AllStaffSectionSerializer(serializers.Serializer): people = serializers.ListField(child=serializers.DictField()) +class WorkshopSerializer(serializers.ModelSerializer): + remaining_capacity = serializers.IntegerField() + + class Meta: + model = models.Workshop + fields = '__all__' + + +class PresentationSerializer(serializers.ModelSerializer): + remaining_capacity = serializers.IntegerField() + + class Meta: + model = models.Presentation + fields = '__all__' + + class WorkshopRegistrationSerializer(serializers.ModelSerializer): workshop = serializers.PrimaryKeyRelatedField(queryset=WorkshopSerializer.Meta.model.objects.all()) diff --git a/backend/backend_api/views.py b/backend/backend_api/views.py index b4ef891..06554f0 100644 --- a/backend/backend_api/views.py +++ b/backend/backend_api/views.py @@ -93,53 +93,42 @@ def retrieve(self, request, year=None, pk=None): return Response(response) -class WorkshopViewSet(viewsets.ViewSet): +class WorkshopViewSet(viewsets.GenericViewSet, + mixins.ListModelMixin, + mixins.RetrieveModelMixin): serializer_class = serializers.WorkshopSerializer + queryset = models.Workshop.objects.all() def list(self, request, year=None, **kwargs): if year is None: year = datetime.datetime.now().year queryset = models.Workshop.objects.filter(year=year) - serializer = self.serializer_class(queryset, many=True) - for workshop_data in serializer.data: - workshop = get_object_or_404(queryset, pk=workshop_data['id']) - workshop_data['is_full'] = ( - len(models.User.objects.filter(registered_workshops=workshop).all()) >= workshop.capacity) - return Response(serializer.data) + return super().list(request, queryset=queryset, **kwargs) def retrieve(self, request, year=None, pk=None): if year is None: year = datetime.datetime.now().year queryset = models.Workshop.objects.filter(year=year) - workshop = get_object_or_404(queryset, pk=pk) - serializer = self.serializer_class(workshop) - response = dict(serializer.data) - response['is_full'] = ( - len(models.User.objects.filter(registered_workshops=workshop).all()) >= workshop.capacity) - return Response(response) + return super().retrieve(request, pk=pk, queryset=queryset) -class PresentationViewSet(viewsets.ViewSet): +class PresentationViewSet(viewsets.GenericViewSet, + mixins.ListModelMixin, + mixins.RetrieveModelMixin): serializer_class = serializers.PresentationSerializer + queryset = models.Presentation.objects.all() def list(self, request, year=None, **kwargs): if year is None: year = datetime.datetime.now().year - queryset = models.Presentation.objects.filter(year=year) - serializer = self.serializer_class(queryset, many=True) - total_registered_for_presentation = len(models.User.objects.filter(registered_for_presentations=True).all()) - response = list(serializer.data) - response.append( - {'is_full': total_registered_for_presentation >= int(models.Misc.objects.get(pk='presentation_cap').desc)}) - return Response(response) + queryset = self.queryset.filter(year=year) + return super().list(request, queryset=queryset, **kwargs) def retrieve(self, request, year=None, pk=None): if year is None: year = datetime.datetime.now().year queryset = models.Presentation.objects.filter(year=year) - presentation = get_object_or_404(queryset, pk=pk) - serializer = self.serializer_class(presentation) - return Response(serializer.data) + return super().retrieve(request, pk=pk, queryset=queryset) class MiscViewSet(viewsets.ViewSet):