""" web_admin serializers file """ # django imports from rest_framework import serializers from django.contrib.auth import get_user_model from base.constants import (ARTICLE_SURVEY_POINTS, MAX_ARTICLE_CARD, MIN_ARTICLE_SURVEY, MAX_ARTICLE_SURVEY, NUMBER, USER_TYPE, ARTICLE_CARD_IMAGE_FOLDER) # local imports from base.messages import ERROR_CODE from guardian.utils import upload_image_to_alibaba from web_admin.models import Article, ArticleCard, SurveyOption, ArticleSurvey, DefaultArticleCardImage from web_admin.utils import pop_id, get_image_url from junior.models import JuniorArticlePoints, JuniorArticle USER = get_user_model() class ArticleCardSerializer(serializers.ModelSerializer): """ Article Card serializer """ id = serializers.IntegerField(required=False) image_name = serializers.CharField(required=False) image_url = serializers.CharField(required=False) class Meta: """ meta class """ model = ArticleCard fields = ('id', 'title', 'description', 'image_name', 'image_url') def create(self, validated_data): validated_data['image_url'] = get_image_url(validated_data) article = Article.objects.all().first() article_card = ArticleCard.objects.create(article=article, **validated_data) return article_card class SurveyOptionSerializer(serializers.ModelSerializer): """ survey option serializer """ id = serializers.IntegerField(required=False) class Meta: """ meta class """ model = SurveyOption fields = ('id', 'option', 'is_answer') class ArticleSurveySerializer(serializers.ModelSerializer): """ article survey serializer """ id = serializers.IntegerField(required=False) options = SurveyOptionSerializer(many=True) class Meta: """ meta class """ model = ArticleSurvey fields = ('id', 'question', 'options') class ArticleSerializer(serializers.ModelSerializer): """ serializer for article API """ article_cards = ArticleCardSerializer(many=True) article_survey = ArticleSurveySerializer(many=True) class Meta: """ meta class """ model = Article fields = ('id', 'title', 'description', 'article_cards', 'article_survey') def validate(self, attrs): """ to validate request data :return: validated attrs """ article_cards = attrs.get('article_cards', None) article_survey = attrs.get('article_survey', None) if article_cards is None or len(article_cards) > int(MAX_ARTICLE_CARD): raise serializers.ValidationError({'details': ERROR_CODE['2039']}) if article_survey is None or len(article_survey) < int(MIN_ARTICLE_SURVEY) or int( MAX_ARTICLE_SURVEY) < len(article_survey): raise serializers.ValidationError({'details': ERROR_CODE['2040']}) return attrs def create(self, validated_data): """ to create article. ID in post data dict is for update api. :return: article object """ article_cards = validated_data.pop('article_cards') article_survey = validated_data.pop('article_survey') article = Article.objects.create(**validated_data) for card in article_cards: card = pop_id(card) card['image_url'] = get_image_url(card) ArticleCard.objects.create(article=article, **card) for survey in article_survey: survey = pop_id(survey) options = survey.pop('options') survey_obj = ArticleSurvey.objects.create(article=article, points=ARTICLE_SURVEY_POINTS, **survey) for option in options: option = pop_id(option) SurveyOption.objects.create(survey=survey_obj, **option) return article def update(self, instance, validated_data): """ to update article and related table :param instance: article object, :return: article object """ article_cards = validated_data.pop('article_cards') article_survey = validated_data.pop('article_survey') instance.title = validated_data.get('title', instance.title) instance.description = validated_data.get('description', instance.description) instance.save() prev_card = list(ArticleCard.objects.filter(article=instance).values_list('id', flat=True)) # Update or create cards for card_data in article_cards: card_id = card_data.get('id', None) if card_id: prev_card.remove(card_id) card = ArticleCard.objects.get(id=card_id, article=instance) card.title = card_data.get('title', card.title) card.description = card_data.get('description', card.description) card.image_url = get_image_url(card_data) card.save() else: card_data = pop_id(card_data) card_data['image_url'] = get_image_url(card_data) ArticleCard.objects.create(article=instance, **card_data) ArticleCard.objects.filter(id__in=prev_card, article=instance).delete() prev_survey = list(ArticleSurvey.objects.filter(article=instance).values_list('id', flat=True)) # Update or create survey sections for survey_data in article_survey: survey_id = survey_data.get('id', None) options_data = survey_data.pop('options') if survey_id: prev_survey.remove(survey_id) survey = ArticleSurvey.objects.get(id=survey_id, article=instance) survey.question = survey_data.get('question', survey.question) survey.save() else: survey_data = pop_id(survey_data) survey = ArticleSurvey.objects.create(article=instance, points=ARTICLE_SURVEY_POINTS, **survey_data) # Update or create survey options for option_data in options_data: option_id = option_data.get('id', None) if option_id: option = SurveyOption.objects.get(id=option_id, survey=survey) option.option = option_data.get('option', option.option) option.is_answer = option_data.get('is_answer', option.is_answer) option.save() else: option_data = pop_id(option_data) SurveyOption.objects.create(survey=survey, **option_data) ArticleSurvey.objects.filter(id__in=prev_survey, article=instance).delete() return instance class DefaultArticleCardImageSerializer(serializers.ModelSerializer): """ Article Card serializer """ image = serializers.FileField(required=False) image_url = serializers.URLField(required=False) class Meta: """ meta class """ model = DefaultArticleCardImage fields = ('image_name', 'image', 'image_url') def validate(self, attrs): """ to validate data :return: validated data """ if 'image' not in attrs and attrs.get('image') is None: raise serializers.ValidationError({'details': ERROR_CODE['2061']}) image = attrs.get('image') if image and image.size == NUMBER['zero']: raise serializers.ValidationError(ERROR_CODE['2035']) return attrs def create(self, validated_data): """ to create and upload image :return: card_image object """ validated_data['image_url'] = get_image_url(validated_data) card_image = DefaultArticleCardImage.objects.create(**validated_data) return card_image class ArticleListSerializer(serializers.ModelSerializer): """ serializer for article API """ article_cards = ArticleCardSerializer(many=True) article_survey = ArticleSurveySerializer(many=True) total_points = serializers.SerializerMethodField('get_total_points') is_completed = serializers.SerializerMethodField('get_is_completed') class Meta: """ meta class """ model = Article fields = ('id', 'title', 'description', 'article_cards', 'article_survey', 'total_points', 'is_completed') def get_total_points(self, obj): """total points of article""" total_question = ArticleSurvey.objects.filter(article=obj).count() return total_question * NUMBER['five'] def get_is_completed(self, obj): """complete all question""" junior_article = JuniorArticle.objects.filter(article=obj).last() if junior_article: return junior_article.is_completed return False class ArticleQuestionSerializer(serializers.ModelSerializer): """ article survey serializer """ id = serializers.IntegerField(required=False) options = SurveyOptionSerializer(many=True) is_attempt = serializers.SerializerMethodField('get_is_attempt') correct_answer = serializers.SerializerMethodField('get_correct_answer') attempted_answer = serializers.SerializerMethodField('get_attempted_answer') def get_is_attempt(self, obj): """attempt question or not""" context_data = self.context.get('user') junior_article_obj = JuniorArticlePoints.objects.filter(junior__auth=context_data, question=obj).last() if junior_article_obj: return junior_article_obj.is_attempt return False def get_correct_answer(self, obj): """attempt question or not""" ans_obj = SurveyOption.objects.filter(survey=obj, is_answer=True).last() if ans_obj: return ans_obj.id return str("None") def get_attempted_answer(self, obj): """attempt question or not""" context_data = self.context.get('user') junior_article_obj = JuniorArticlePoints.objects.filter(junior__auth=context_data, question=obj, is_answer_correct=True).last() if junior_article_obj: return junior_article_obj.submitted_answer.id return None class Meta: """ meta class """ model = ArticleSurvey fields = ('id', 'question', 'options', 'points', 'is_attempt', 'correct_answer', 'attempted_answer') class StartAssessmentSerializer(serializers.ModelSerializer): """ serializer for article API """ article_survey = ArticleQuestionSerializer(many=True) current_page = serializers.SerializerMethodField('get_current_page') def get_current_page(self, obj): """current page""" context_data = self.context.get('user') data = JuniorArticle.objects.filter(junior__auth=context_data, article=obj).last() if data: return data.current_que_page return NUMBER['zero'] class Meta: """ meta class """ model = Article fields = ('article_survey', 'current_page') class ArticleCardlistSerializer(serializers.ModelSerializer): """ Article Card serializer """ id = serializers.IntegerField(required=False) image_name = serializers.CharField(required=False) image_url = serializers.CharField(required=False) current_page = serializers.SerializerMethodField('get_current_page') def get_current_page(self, obj): """current page""" context_data = self.context.get('user') data = JuniorArticle.objects.filter(junior__auth=context_data, article=obj.article).last() if data: return data.current_card_page return NUMBER['zero'] class Meta: """ meta class """ model = ArticleCard fields = ('id', 'title', 'description', 'image_name', 'image_url', 'current_page')