From 6857cadcae5dcb3bc00c60feff4caf5fa8dfb026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20Cz=C3=A9m=C3=A1n?= <trabarni@gmail.com> Date: Wed, 4 Apr 2018 09:53:59 +0200 Subject: [PATCH] Fix homework file size validation & created_by field default value --- src/common/serializers.py | 12 +++++ src/common/validators.py | 26 +++++++++++ src/homework/migrations/0001_initial.py | 2 +- .../migrations/0009_merge_20180404_0825.py | 14 ++++++ .../migrations/0010_auto_20180404_0828.py | 30 ++++++++++++ .../migrations/0011_auto_20180404_0853.py | 25 ++++++++++ src/homework/models.py | 46 ++++++++----------- src/homework/serializers.py | 16 ++----- src/homework/views.py | 28 +---------- 9 files changed, 135 insertions(+), 64 deletions(-) create mode 100644 src/common/serializers.py create mode 100644 src/common/validators.py create mode 100644 src/homework/migrations/0009_merge_20180404_0825.py create mode 100644 src/homework/migrations/0010_auto_20180404_0828.py create mode 100644 src/homework/migrations/0011_auto_20180404_0853.py diff --git a/src/common/serializers.py b/src/common/serializers.py new file mode 100644 index 0000000..5e08862 --- /dev/null +++ b/src/common/serializers.py @@ -0,0 +1,12 @@ +from rest_framework import compat + + +class CurrentUserProfileDefault(object): + def set_context(self, serializer_field): + self.user = serializer_field.context['request'].user + + def __call__(self): + return self.user.profile + + def __repr__(self): + return compat.unicode_to_repr('%s()' % self.__class__.__name__) diff --git a/src/common/validators.py b/src/common/validators.py new file mode 100644 index 0000000..343f781 --- /dev/null +++ b/src/common/validators.py @@ -0,0 +1,26 @@ +from django.core import exceptions +from django.utils.deconstruct import deconstructible +from django.utils.translation import ugettext_lazy as _ + + +@deconstructible +class FileSizeValidator(): + size_limit = 5242880 # 5MB - 5242880 + message = _('Too big file. %(size)d') + code = 'invalid' + + def __init__(self, size_limit=None, message=None, code=None): + if size_limit is not None: + self.size_limit = size_limit + if message is not None: + self.message = message + if code is not None: + self.code = code + + def __call__(self, file): + if file.size > self.size_limit: + raise exceptions.ValidationError( + self.message, + code=self.code, + params={'size': file.size} + ) diff --git a/src/homework/migrations/0001_initial.py b/src/homework/migrations/0001_initial.py index 57b9c1f..c06eb42 100644 --- a/src/homework/migrations/0001_initial.py +++ b/src/homework/migrations/0001_initial.py @@ -42,7 +42,7 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(max_length=150)), ('date', models.DateTimeField(auto_now_add=True)), - ('deadline', models.DateTimeField(validators=[homework.models.validate_deadline])), + ('deadline', models.DateTimeField()), ('text', models.TextField()), ('files', models.FileField(blank=True, upload_to='', validators=[django.core.validators.FileExtensionValidator('image/png', 'image/jpeg', 'application/zip')])), ('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), diff --git a/src/homework/migrations/0009_merge_20180404_0825.py b/src/homework/migrations/0009_merge_20180404_0825.py new file mode 100644 index 0000000..f571560 --- /dev/null +++ b/src/homework/migrations/0009_merge_20180404_0825.py @@ -0,0 +1,14 @@ +# Generated by Django 2.0.1 on 2018-04-04 06:25 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('homework', '0008_auto_20180221_1135'), + ('homework', '0007_merge_20180205_2021'), + ] + + operations = [ + ] diff --git a/src/homework/migrations/0010_auto_20180404_0828.py b/src/homework/migrations/0010_auto_20180404_0828.py new file mode 100644 index 0000000..5be35ff --- /dev/null +++ b/src/homework/migrations/0010_auto_20180404_0828.py @@ -0,0 +1,30 @@ +# Generated by Django 2.0.1 on 2018-04-04 06:28 + +import common.validators +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('homework', '0009_merge_20180404_0825'), + ] + + operations = [ + migrations.AlterField( + model_name='solution', + name='files', + field=models.FileField(blank=True, upload_to='', validators=[django.core.validators.FileExtensionValidator('image/png', 'image/jpeg', 'application/zip'), common.validators.FileSizeValidator(size_limit=52428800)]), + ), + migrations.AlterField( + model_name='task', + name='deadline', + field=models.DateTimeField(), + ), + migrations.AlterField( + model_name='task', + name='files', + field=models.FileField(blank=True, upload_to='', validators=[django.core.validators.FileExtensionValidator('image/png', 'image/jpeg', 'application/zip'), common.validators.FileSizeValidator(size_limit=52428800)]), + ), + ] diff --git a/src/homework/migrations/0011_auto_20180404_0853.py b/src/homework/migrations/0011_auto_20180404_0853.py new file mode 100644 index 0000000..0524fa0 --- /dev/null +++ b/src/homework/migrations/0011_auto_20180404_0853.py @@ -0,0 +1,25 @@ +# Generated by Django 2.0.1 on 2018-04-04 06:53 + +import common.validators +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('homework', '0010_auto_20180404_0828'), + ] + + operations = [ + migrations.AlterField( + model_name='solution', + name='files', + field=models.FileField(blank=True, upload_to='', validators=[django.core.validators.FileExtensionValidator(['image/png', 'image/jpeg', 'application/zip']), common.validators.FileSizeValidator(size_limit=52428800)]), + ), + migrations.AlterField( + model_name='task', + name='files', + field=models.FileField(blank=True, upload_to='', validators=[django.core.validators.FileExtensionValidator(['image/png', 'image/jpeg', 'application/zip']), common.validators.FileSizeValidator(size_limit=52428800)]), + ), + ] diff --git a/src/homework/models.py b/src/homework/models.py index 5974d6b..c586fa0 100644 --- a/src/homework/models.py +++ b/src/homework/models.py @@ -1,34 +1,25 @@ from django.db import models -from django.contrib.auth.models import User -from django.core.exceptions import ValidationError -from django.utils.translation import ugettext_lazy as _ -from django.utils import timezone from django.core import validators -from account.models import Profile -# from . import myfields - - -# 5MB - 5242880 -__MAX_UPLOAD_SIZE = 5242880 - -def validate_deadline(deadline): - if deadline <= timezone.now(): - raise ValidationError(_('Date must be greater than now'), code='invalid') +from common.validators import FileSizeValidator +from account.models import Profile class Task(models.Model): title = models.CharField(max_length=150) date = models.DateTimeField(auto_now_add=True, editable=False) - deadline = models.DateTimeField(validators=[validate_deadline]) + deadline = models.DateTimeField() text = models.TextField() created_by = models.ForeignKey(Profile, on_delete=models.DO_NOTHING) files = models.FileField( - validators=[validators.FileExtensionValidator( - 'image/png', - 'image/jpeg', - 'application/zip', - )], + validators=[ + validators.FileExtensionValidator([ + 'image/png', + 'image/jpeg', + 'application/zip', + ]), + FileSizeValidator(size_limit=52428800), # 52428800 - 50MiB + ], blank=True, ) @@ -38,15 +29,18 @@ class Task(models.Model): class Solution(models.Model): task = models.ForeignKey(Task, related_name='task_solution', on_delete=models.CASCADE) - created_by = models.ForeignKey(Profile, related_name='student_solution', on_delete=models.CASCADE) + created_by = models.ForeignKey(Profile, related_name='student_solution', on_delete=models.CASCADE) date = models.DateTimeField(auto_now_add=True, editable=False) ready = models.BooleanField(default=False) accepted = models.BooleanField(default=False) files = models.FileField( - validators=[validators.FileExtensionValidator( - 'image/png', - 'image/jpeg', - 'application/zip', - )], + validators=[ + validators.FileExtensionValidator([ + 'image/png', + 'image/jpeg', + 'zip', + ]), + FileSizeValidator(size_limit=52428800), # 52428800 - 50MiB + ], blank=True, ) diff --git a/src/homework/serializers.py b/src/homework/serializers.py index f3a816e..5b5497f 100644 --- a/src/homework/serializers.py +++ b/src/homework/serializers.py @@ -1,29 +1,23 @@ from rest_framework import serializers + +from common.serializers import CurrentUserProfileDefault from . import models class TaskSerializer(serializers.ModelSerializer): + created_by = serializers.HiddenField(default=CurrentUserProfileDefault()) + class Meta: model = models.Task read_only_fields = ('created_by', 'date') - # extra_kwargs = {'created_by': {'default': serializers.CurrentUserDefault()}} fields = '__all__' class SolutionSerializer(serializers.ModelSerializer): date = serializers.DateTimeField(read_only=True) + created_by = serializers.HiddenField(default=CurrentUserProfileDefault()) class Meta: model = models.Solution read_only_fields = ('created_by', 'date' 'ready') - # extra_kwargs = {'created_by': {'default': serializers.CurrentUserDefault()}} fields = ('task', 'date', 'accepted', 'files', 'created_by') - - # def validate(self, attrs): - # task = attrs['task'] - # date = attrs['date'] keyerror - # - # if task.deadline < date: - # raise serializers.ValidationError("You cannot submit homework after the deadline") - # - # return attrs diff --git a/src/homework/views.py b/src/homework/views.py index c6f1f9b..508a498 100644 --- a/src/homework/views.py +++ b/src/homework/views.py @@ -1,15 +1,9 @@ -from rest_framework import viewsets +from rest_framework import viewsets, status from rest_framework.response import Response -from rest_framework import status -from rest_framework.decorators import list_route -from django.http import Http404 -from django.shortcuts import get_object_or_404 -import datetime -from django.utils import timezone +from common import permissions from . import serializers from . import models -from common import permissions class TasksViewSet(viewsets.ModelViewSet): @@ -22,21 +16,3 @@ class SolutionsViewSet(viewsets.ModelViewSet): serializer_class = serializers.SolutionSerializer queryset = models.Solution.objects.all() permission_classes = (permissions.IsStaffOrReadOnlyForAuthenticated, ) - - def perform_create(self, serializer): - serializer.validated_data['accepted'] = False - task = serializer.validated_data['task'] - now = timezone.now() - if task.deadline < now: - raise Http404("Deadline") - serializer.save() - - # def get_queryset(self): - # user = self.request.user - # if user.has_perm(permissions.IsStaffUser): - # return models.Solution.objects.all() - # - # @list_route(methods=['get']) - # def me(self, request): - # serializer = self.serializer_class(request.user.profile) #request ? - # return Response(serializer.data) \ No newline at end of file -- GitLab