Skip to content
Snippets Groups Projects
common_serializers.py 3.13 KiB
import logging
from collections import defaultdict

import django.contrib.auth.password_validation as validators
from django.core import exceptions
from django.db.models.manager import Manager
from rest_framework import serializers
from rest_framework.utils import html

from core import models
from core.serializers.group import GroupSerializer

from .generic import DynamicFieldsModelSerializer

log = logging.getLogger(__name__)


class ExamSerializer(DynamicFieldsModelSerializer):

    class Meta:
        model = models.ExamType
        fields = ('pk', 'module_reference', 'total_score',
                  'pass_score', 'pass_only',)


class TestSerializer(DynamicFieldsModelSerializer):

    class Meta:
        model = models.Test
        fields = ('pk', 'name', 'label', 'annotation')


class UserAccountSerializer(DynamicFieldsModelSerializer):
    exercise_groups = GroupSerializer(many=True)

    def validate(self, data):
        password = data.get('password')

        try:
            if password is not None:
                validators.validate_password(password=password,
                                             user=self.instance)
        except exceptions.ValidationError as err:
            raise serializers.ValidationError({'password': list(err.messages)})
        return data

    class Meta:
        model = models.UserAccount
        fields = ('pk', 'username', 'role', 'is_admin', 'password', 'exercise_groups')
        read_only_fields = ('pk', 'username', 'role', 'is_admin', 'exercise_groups')
        extra_kwargs = {'password': {'write_only': True}}


class CommentDictionarySerializer(serializers.ListSerializer):

    def to_internal_value(self, comment_dict):
        """ Converts a line_no -> comment list dictionary back to a list
        of comments. Currently we do not have any information about the
        feedback since it is not available in this scope. Feedback is
        responsible to add it later on update/creation """
        if html.is_html_input(comment_dict):
            comment_dict = html.parse_html_list(comment_dict)

        if not isinstance(comment_dict, dict):
            raise serializers.ValidationError(
                'Comments have to be provided as a dict'
                'with: line -> list of comments'
            )

        ret = []
        errors = []

        for line, comment in comment_dict.items():
            try:
                comment['of_line'] = line
                validated = self.child.run_validation(comment)
            except serializers.ValidationError as err:
                errors.append(err.detail)
            else:
                ret.append(validated)
                errors.append({})

        if any(errors):
            raise serializers.ValidationError(errors)

        return ret

    def to_representation(self, comments):
        """ Provides a dict where all the keys correspond to lines and contain
        a list of comments on that line. """
        if isinstance(comments, Manager):
            comments = comments.all()

        ret = defaultdict(list)
        for comment in comments:
            ret[comment.of_line].append(self.child.to_representation(comment))
        return ret