class Class(models.Model):
    CLASS_NUMBERS = (
        (8, 8),
        (9, 9),
        (10, 10),
        (11, 11),
        (12, 12),
    )
    CLASS_NUMBER_VALIDATORS = [MinValueValidator(8), MaxValueValidator(12)]

    CLASS_LETTERS = (
        ('A', 'A'),
        ('B', 'B'),
        ('V', 'V'),
        ('G', 'G'),
    )

    number = models.IntegerField(validators=CLASS_NUMBER_VALIDATORS, choices=CLASS_NUMBERS)
    letter = models.CharField(max_length=1, choices=CLASS_LETTERS)

    def __str__(self):
        return '{}{}'.format(self.number, self.letter)

    class Meta:
        ordering = ['number', 'letter']
        verbose_name_plural = 'classes' class IsStudent(permissions.BasePermission):
    message = ROLE_DEFAULT_MESSAGE.format('student')

    def has_permission(self, request, view):
        return Student.objects.filter(user=request.user).exists() class IsTeacher(permissions.BasePermission):
    message = ROLE_DEFAULT_MESSAGE.format('teacher')

    def has_permission(self, request, view):
        return Teacher.objects.filter(user=request.user).exists() class IsTeacherAuthor(permissions.BasePermission):
    message = AUTHOR_DEFAULT_MESSAGE

    def has_object_permission(self, request, view, obj):
        return obj.author == request.user.teacher class HomeworkSerializer(serializers.ModelSerializer):
    details = serializers.CharField(max_length=256, allow_blank=True)

    class Meta:
        model = Homework
        fields = ('id', 'topic', 'subject', 'clazz', 'deadline', 'details', 'author')
        depth = 1

    def create(self, validated_data):
        request = self.context['request']

        author = request.user.teacher
        subject = author.subject
        clazz = self.context['clazz']

        homework = Homework.objects.create(
            subject=subject,
            author=author,
            clazz=clazz,
            **validated_data
        )

        recipient_list = User.objects.filter(student__clazz=clazz)
        for user in recipient_list:
            send_creation_email(user, model=homework)

        return homework class HomeworkReadSerializer(HomeworkSerializer):
    subject = SubjectSerializer(read_only=True)
    clazz = ClassSerializer(read_only=True)
    author = TeacherAuthorSerializer(read_only=True) class SubmissionSerializer(serializers.ModelSerializer):
    content = serializers.CharField(max_length=2048, allow_blank=False)
    solution_url = serializers.URLField(required=False, allow_blank=True)

    class Meta:
        model = Submission
        fields = ('id', 'homework', 'student', 'content', 'solution_url', 'checked')
        depth = 1

    def create(self, validated_data):
        homework = self.context['homework']
        request = self.context['request']

        student = request.user.student

        return Submission.objects.create(homework=homework, student=student, **validated_data) class SubmissionReadSerializer(SubmissionSerializer):
    student = StudentAuthorSerializer(read_only=True) class Homework(models.Model):
    topic = models.CharField(default='Homework', max_length=50)
    subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
    clazz = models.ForeignKey(Class, on_delete=models.CASCADE)
    deadline = models.DateField(auto_now=False)
    details = models.TextField(max_length=256, blank=True)
    author = models.ForeignKey(Teacher, null=True, related_name='homeworks', on_delete=models.CASCADE)

    def __str__(self):
        return '{} ({}) - {}'.format(self.topic, self.subject, self.clazz)

    class Meta:
        ordering = ['deadline', 'clazz', 'subject'] class HasOnlyOneSubmission(permissions.BasePermission):
    message = 'You can submit only one submission.'

    def has_object_permission(self, request, view, obj):
        return not obj.submissions.filter(student=request.user.student).exists() class IsValidStudent(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        return obj.student == request.user.student class IsNotChecked(permissions.BasePermission):
    message = 'Submission is already checked.'

    def has_object_permission(self, request, view, obj):
        return not obj.checked class HomeworksFilterBackend(filters.BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        if IsTeacher().has_permission(request, self):
            return queryset.filter(subject=request.user.teacher.subject)

        return queryset.filter(clazz=request.user.student.clazz) class SubmissionsFilterBackend(filters.BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        if IsStudent().has_permission(request, self):
            return queryset.filter(student=request.user.student)

        return queryset.filter(checked=False)
from datetime import datetime
from rest_framework import viewsets, status
from rest_framework.generics import get_object_or_404
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework_word_filter import FullWordSearchFilter
from students.models import Class
from students.permissions import IsStudent, IsTeacher, IsTeacherAuthor
from .serializers import (
    HomeworkSerializer, HomeworkReadSerializer, SubmissionSerializer, SubmissionReadSerializer
)
from .models import Homework
from .permissions import HasOnlyOneSubmission, IsValidStudent, IsNotChecked
from .filters import HomeworksFilterBackend, SubmissionsFilterBackend






class HomeworksViewSet(viewsets.ModelViewSet):
    permission_classes_by_action = {
        'list': (IsAuthenticated,),
        'retrieve': (IsAuthenticated,),
        'create': (IsAuthenticated, IsTeacher),
        'update': (IsAuthenticated, IsTeacher, IsTeacherAuthor),
        'destroy': (IsAuthenticated, IsTeacher, IsTeacherAuthor)
    }
    queryset = Homework.objects.filter(deadline__gte=datetime.now())
    filter_backends = (HomeworksFilterBackend, FullWordSearchFilter)
    word_fields = ('topic', 'subject__title', 'author__user__username')

    def get_permissions(self):
        return [
            permission()
            for permission
            in self.permission_classes_by_action[self.action]
        ]

    def get_serializer_class(self):
        return HomeworkReadSerializer if self.request.method in ('GET',) else HomeworkSerializer

    def create(self, request, *args, **kwargs):
        clazz_data = request.data.get('clazz', {})
        clazz = get_object_or_404(Class, **clazz_data)
        context = {'request': request, 'clazz': clazz}

        serializer = self.get_serializer_class()(data=request.data, context=context)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)

        headers = self.get_success_headers(serializer.data)

        return Response(serializer.validated_data, status=status.HTTP_201_CREATED, headers=headers)


class SubmissionsViewSet(viewsets.ModelViewSet):
    permission_classes_by_action = {
        'list': (IsAuthenticated,),
        'retrieve': (IsAuthenticated, IsValidStudent),

        'create': (IsAuthenticated, IsStudent, HasOnlyOneSubmission),