From b56805227a1136b8573c0cf6c098ba54d33882ac Mon Sep 17 00:00:00 2001 From: borzechof99 <borzechof99@mi.fu-berlin.de> Date: Fri, 25 Jun 2021 19:04:53 +0200 Subject: [PATCH] Implement Sport PUT,PATCH,DELETE, IncompleteSport GET, Criteria GET --- unisportomat/quiz/models.py | 12 ++++ unisportomat/quiz/serializers.py | 81 ++++++++++++++++++---- unisportomat/quiz/views.py | 109 ++++++++++++++++++++++++++++-- unisportomat/unisportomat/urls.py | 2 + 4 files changed, 182 insertions(+), 22 deletions(-) diff --git a/unisportomat/quiz/models.py b/unisportomat/quiz/models.py index 23168aa..fd3c446 100644 --- a/unisportomat/quiz/models.py +++ b/unisportomat/quiz/models.py @@ -125,6 +125,18 @@ class Criterion(models.Model): def __str__(self): return self.name + def get_active_sum(self): + + num_active = 0 + sum = 0 + + for rating_obj in CriterionRating.objects.filter(criterion=self): + if rating_obj.rating != -1: + num_active += 1 + sum += rating_obj.rating + + return num_active, sum + class CallToMove(models.Model): """Defines text and image that are used to show a call to move between questions""" diff --git a/unisportomat/quiz/serializers.py b/unisportomat/quiz/serializers.py index 601fdbb..68d94c4 100644 --- a/unisportomat/quiz/serializers.py +++ b/unisportomat/quiz/serializers.py @@ -81,22 +81,26 @@ class SingleSportSerializer(serializers.BaseSerializer): def to_internal_value(self, request): """ The Data in the Request is taken and written to another Dictionary. - During this process, the Data is Validated on: - - whether Name and URL for Sport exist - - whether the Rating Value and Criterion ID are valid + During this process, the Data is Validated on whether the Rating Value and Criterion ID are valid. + If the Request is PATCHing or PUTting an existing Sport, not every field must be existant. + So, the existance is explicitly checked. """ - data = {"valid_request": True} + sport_dictionary = {} - for field_value in ["name", "url"]: - try: - data[field_value] = request.data[field_value] - except: - data["valid_request"] = False - return data + # If The Sport is Being Patched, Name or URL may not be changed. + # That means that those Fields might not be sent in the Request, + # leading to needing to check whether they exist. + if "name" in request.data.keys(): + sport_dictionary["name"] = request.data["name"] + + if "url" in request.data.keys(): + sport_dictionary["url"] = request.data["url"] - data["criteria"] = [] + # A Number of Criteria may be sent with the Sport + sport_dictionary["criteria"] = [] + # For every Sent Criterion, the ID of the Criterion and the Rating Value is being tested for Validity for criterion in request.data["criteria"]: value = criterion["value"] @@ -104,9 +108,56 @@ class SingleSportSerializer(serializers.BaseSerializer): validate_rating(value) crit = Criterion.objects.get(pk=criterion["id"]) except: - data["valid_request"] = False - return data + return None + + sport_dictionary["criteria"].append((crit, value)) + + return sport_dictionary + + +class IncompleteSportSerializer(serializers.BaseSerializer): + def to_representation(self, incomplete_sports): + + incomplete_sport_list = [] + + for sport in incomplete_sports: + incomplete_sport = { + "id": sport.pk, + "name": sport.name, + "criteria": [], + } + + for crit in sport.criteria_ratings.iterator(): + + if sport.get_rating(crit) != -1: + continue + + incomplete_sport["criteria"].append( + { + "id": crit.pk, + "name": crit.name, + } + ) + + incomplete_sport_list.append(incomplete_sport) + + return incomplete_sport_list + + +class CriteriaSerializer(serializers.BaseSerializer): + def to_representation(self, data): + + criteria_list = [] + + for crit, active_sports, sum_of_weights in data: + + criterion_dict = {} + + criterion_dict["id"] = crit.pk + criterion_dict["name"] = crit.name + criterion_dict["number_of_sports_active"] = active_sports + criterion_dict["sum_of_weights"] = sum_of_weights - data["criteria"].append((crit, value)) + criteria_list.append(criterion_dict) - return data + return criteria_list diff --git a/unisportomat/quiz/views.py b/unisportomat/quiz/views.py index dc02417..f3d56cd 100644 --- a/unisportomat/quiz/views.py +++ b/unisportomat/quiz/views.py @@ -16,6 +16,8 @@ from .serializers import ( CriterionListSerializer, QuestionListSerializer, SingleSportSerializer, + CriteriaSerializer, + IncompleteSportSerializer, ) from .models import Sport, Criterion, Question @@ -86,7 +88,6 @@ class SmallSportListView(viewsets.ViewSet): sports = Sport.objects.all() sports = paginator.paginate_queryset(sports, request) - criteria = Criterion.objects.all() is_filled_tuples = [] for sport in sports: @@ -103,7 +104,7 @@ class SmallSportListView(viewsets.ViewSet): data_dict = SingleSportSerializer().to_internal_value(request) # A Try at Error Catching - if not data_dict["valid_request"]: + if data_dict == None: return HttpResponse(status=400) new_sport = Sport.objects.create_sport() @@ -128,7 +129,9 @@ class SmallSportListView(viewsets.ViewSet): sport = get_object_or_404(Sport, pk=pk) - return Response(SingleSportSerializer(sport).data) + response = SingleSportSerializer(sport) + + return Response(response.data) # PUT for api/admin/sport/<id>/ def update(self, request, pk=None): @@ -136,15 +139,107 @@ class SmallSportListView(viewsets.ViewSet): TODO """ - data_dict = SingleSportSerializer().to_internal_value(request) + # Get Data from Serializer + request_data = SingleSportSerializer().to_internal_value(request) + if request_data == None: + # Something is Broke, so Refuse Changing Data + return HttpResponse(status=400) + + # Get Sport from Data sport = Sport.objects.get(pk=pk) - print(data_dict) + # Apply New Data to Sport + sport.name = request_data["name"] + sport.url = request_data["url"] + + # Overwrite Criterion Ratings + for criterion, value in request_data["criteria"]: + sport.rate(criterion, value) - return Response({"test": "Updating a Single Entry"}) + # Re-Serialize changed Sport and Send it back + response = SingleSportSerializer(sport) + + return Response(response.data) + + # PATCH for api/admin/sport/<id>/ + def partial_update(self, request, pk=None): + + # Get Data from Serializer + request_data = SingleSportSerializer().to_internal_value(request) + + if request_data == None: + # Something is Broke, so Refuse Changing Data + return HttpResponse(status=400) + + # Get Sport from Data + sport = Sport.objects.get(pk=pk) + + # Apply New Data to Sport, if it exists + if "name" in request_data.keys(): + sport.name = request_data["name"] + + if "url" in request_data.keys(): + sport.url = request_data["url"] + + # Overwrite Criterion Ratings + for criterion, value in request_data["criteria"]: + sport.rate(criterion, value) + + # Re-Serialize changed Sport and Send it back + response = SingleSportSerializer(sport) + + return Response(response.data) # DELETE for api/admin/sport/<id>/ def destroy(self, request, pk=None): - return Response({"test": "Removing a Single Entry"}) + sport = get_object_or_404(Sport, pk=pk) + + sport.delete() + + return HttpResponse(status=404) + + +class IncompleteSportView(APIView): + + authentication_classes = [] + + # GET for api/admin/sport/incomplete + def get(self, request): + + incomplete_sport_list = [] + + for sport in Sport.objects.iterator(): + + if not sport.is_filled(): + incomplete_sport_list.append(sport) + + response = IncompleteSportSerializer(incomplete_sport_list) + + return Response(response.data) + + +class CriteriaView(APIView): + + """ + View for the List of Criteria and their Metadata + TODO: More Documentation + """ + + authentication_classes = [] + + # GET for api/admin/criteria + def get(self, request): + + data = [] + + for crit in Criterion.objects.iterator(): + + active_sports, sum_of_weights = crit.get_active_sum() + + data.append((crit, active_sports, sum_of_weights)) + + response = CriteriaSerializer(data) + + return Response(response.data) diff --git a/unisportomat/unisportomat/urls.py b/unisportomat/unisportomat/urls.py index 06f8bb1..6814e5c 100644 --- a/unisportomat/unisportomat/urls.py +++ b/unisportomat/unisportomat/urls.py @@ -27,4 +27,6 @@ router.register(r"small-sport-list", views.SmallSportListView, "small-sport-list urlpatterns = [ path("admin/", admin.site.urls), path("api/admin/", include(router.urls)), + path("api/admin/sport/incomplete/", views.IncompleteSportView.as_view()), + path("api/admin/criteria/", views.CriteriaView.as_view()), ] -- GitLab