""" Serializers creating JSONs for every Model from .models """ import base64 from rest_framework import serializers from .models import Criterion, validate_rating class SmallSportListSerializer(serializers.BaseSerializer): """ Serializes Lists of Sport Objects in a "Simple" Manner, with Criterions being represented in a Bool. """ def to_representation(self, sport_filled_tuples): """ Takes a List of (Sport, bool) tuples to Serialize. The Bool Represents whether the Sport is Filled or not. """ serialized_data = [] for sport, boolean in sport_filled_tuples: serialized_data.append( { "id": sport.pk, "name": sport.name, "url": sport.url, "is_filled": boolean, } ) return serialized_data class SingleSportSerializer(serializers.BaseSerializer): """ Serializes and Deserializes a Single Sport Object """ def to_representation(self, sport): """ Takes a Single Sport Object and Serializes it and all its Criteria """ serialized_data = {} serialized_data["id"] = sport.pk serialized_data["name"] = sport.name serialized_data["url"] = sport.url serialized_data["currently_active"] = sport.currently_active serialized_data["last_used"] = sport.last_used criteria = [] for criterion in sport.criteria_ratings.iterator(): criterion_data = {} criterion_data["id"] = criterion.pk criterion_data["name"] = criterion.name criterion_data["value"] = sport.get_rating(criterion) criteria.append(criterion_data) serialized_data["criteria"] = criteria return serialized_data 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 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. TODO: Different Functions based on PUT or PATCH? """ sport_dictionary = {} # 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"] if "currently_active" in request.data.keys(): sport_dictionary["currently_active"] = request.data["currently_active"] # If the Sport is only now created with a POST-Request, no Criteria can be filled out for it # This is because the Admin Frontend doesn't have a list of Criteria ready if "criteria" in request.data.keys(): # 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"] try: validate_rating(value) crit = Criterion.objects.get(pk=criterion["id"]) except: # pylint: disable=bare-except return None sport_dictionary["criteria"].append((crit, value)) return sport_dictionary class IncompleteSportSerializer(serializers.BaseSerializer): """ Serializes every Sport Object with Incomplete Criteria Ratings. Includes the Name and ID of both the Sport and the Criteria. """ def to_representation(self, incomplete_sports): """ Serializes Every given Sport Object and goes through every Criterium to serialize those that are unrated. """ incomplete_sport_list = [] for sport in incomplete_sports: incomplete_sport = { "id": sport.pk, "name": sport.name, "criteria": [], } for crit in sport.criteria_ratings.iterator(): # Asking this way to save an indentation and for readability. Would also work when asking for = -1 and handling the append then. 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): """ Serializes Every Criterium and Metadata """ def to_representation(self, data): """ Takes Tuples of (Criterium, Int, Int), where the Integers are the Number of Sports in which the Rating is >1 and the cumulated sum of Ratings >1, respectively """ criteria_list = [] for crit, active_sports, sum_of_weights in data: criterion_dict = {} criterion_dict["id"] = crit.pk criterion_dict["question_id"] = crit.question.pk criterion_dict["name"] = crit.name criterion_dict["number_of_sports_active"] = active_sports criterion_dict["sum_of_weights"] = sum_of_weights criteria_list.append(criterion_dict) return criteria_list class SmallQuestionListSerializer(serializers.BaseSerializer): """ Serializer for a List of Questions """ def to_representation(self, questions): """ Takes a List of Question Objects and JSONifies them, including id, Text in both languages, and Criterion name """ question_list = [] for question in questions: question_list.append( { "id": question.pk, "text_de": question.text_de, "text_en": question.text_en, "criterion": question.criterion.name, } ) return question_list class SingleQuestionSerializer(serializers.BaseSerializer): """ Serializer for Single Questions """ def to_representation(self, question): """ Take a Question and JSONify it and its Criterion """ number_of_sports_active, sum_of_weights = question.criterion.get_active_sum() question_dict = { "id": question.pk, "text_de": question.text_de, "text_en": question.text_en, "criterion": question.criterion.name, "number_of_sports_active": number_of_sports_active, "sum_of_weights": sum_of_weights, } return question_dict def to_internal_value(self, data): """ Take a Single Question JSON and Validate its Contents """ validated_data = {} # Test if Values exist if "text_de" in data.keys(): validated_data["text_de"] = data["text_de"] or "" if "text_en" in data.keys(): validated_data["text_en"] = data["text_en"] or "" if "criterion" in data.keys(): validated_data["criterion"] = data["criterion"] or "" return validated_data class QuestionOrderSerializer(serializers.BaseSerializer): """ Serializer for Question Order Lists """ def to_representation(self, question_order_list): """ Take an ordered Set of QuestionOrderEntry Objects and represent them in JSON """ json_list = [] for order_entry in question_order_list: json_list.append( { "id": order_entry.order_id, "type": order_entry.type_of_slot, "question_id": order_entry.question_id, } ) return json_list class SnackTivityListSerializer(serializers.BaseSerializer): """ Serializer to Serialize Snacks and Activities in their Lists """ def to_representation(self, obj_list): """ Takes a Queryset and JSONifies it """ json_list = [] for obj in obj_list: # bug https://code.djangoproject.com/ticket/25528 has_image = obj.image not in [None, ""] json_list.append( { "id": obj.pk, "text_de": obj.text_de, "text_en": obj.text_en or "", "has_image": has_image, } ) return json_list class SingleSnackTivitySerializer(serializers.BaseSerializer): """ Converts a Single SnackTivity Object to JSON and back """ def to_internal_value(self, data): """ Validates Data given in a Request """ validated_data = {} if "text_de" in data.keys(): validated_data["text_de"] = data["text_de"] if "text_en" in data.keys(): validated_data["text_en"] = data["text_en"] if "image" in data.keys(): validated_data["image"] = data["image"] validated_data["image_type"] = data["image_type"] return validated_data def to_representation(self, obj): """ Converts a SnackTivity Model """ # bug https://code.djangoproject.com/ticket/25528 has_image = obj.image not in [None, ""] if has_image: image_base64 = base64.b64encode(obj.image.file.read()) # Maybe rethink this? Dunno if unsafe. image_type = "image/" + obj.image.file.name.split(".")[-1] else: image_base64 = "" image_type = "" data = { "id": obj.pk, "text_de": obj.text_de, "text_en": obj.text_en or "", "has_image": has_image, "image_type": image_type, "image": image_base64, } return data class ArchiveSerializer(serializers.BaseSerializer): """ Serializes Sports in an archive format """ def to_representation(self, sport_list): """ Takes a list of Sport Objects and returns id, name, last_used, url serialized """ json_sport_list = [] for sport in sport_list: json_sport_list.append( { "id": sport.pk, "name": sport.name, "last_used": sport.last_used, "url": sport.url, } ) return json_sport_list class GreetingEndSerializer(serializers.BaseSerializer): """ Serializer for GreetingText and EndText """ def to_representation(self, obj): """ Represents the object with German and English text """ json_obj = { "text_de": obj.text_de, "text_en": obj.text_en, } return json_obj