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