11from itertools import groupby
2+ from lib2to3 .pytree import convert
23from typing import Any , Dict , Iterable , List , Optional , Tuple , Type
34
45from django .db import models
89from django .shortcuts import get_object_or_404
910from django .utils .text import format_lazy
1011from django .utils .translation import ugettext_lazy as _ , ngettext
12+ from django .utils import timezone
13+ from django .utils .dateparse import parse_datetime
14+ import datetime
15+
1116
1217from course .models import CourseModule , UserTag
1318from course .viewbase import CourseInstanceMixin , CourseInstanceBaseView
1621from authorization .permissions import ACCESS
1722from exercise .models import BaseExercise
1823from userprofile .models import UserProfile
24+ from exercise .submission_models import Submission
25+
26+ from .forms import DeadlineRuleDeviationForm , MaxSubmissionRuleDeviationForm
1927
2028
2129class ListDeviationsView (CourseInstanceBaseView ):
@@ -48,7 +56,12 @@ def form_valid(self, form: forms.BaseForm) -> HttpResponse:
4856 exercise__in = exercises ,
4957 submitter__in = submitters ,
5058 )
59+ if isinstance (form , DeadlineRuleDeviationForm ) and not form .cleaned_data .get ("without_late_submission_approval" ):
60+ approve_late_submissions (submitters , exercises , form .cleaned_data )
5161
62+ elif isinstance (form , MaxSubmissionRuleDeviationForm ) and not form .cleaned_data .get ("without_unofficial_submission_approval" ):
63+ approve_unofficial_submissions (submitters , exercises , form .cleaned_data )
64+
5265 if existing_deviations :
5366 # Some deviations already existed. Use OverrideDeviationsView to
5467 # confirm which ones the user wants to override. Store the form
@@ -297,3 +310,36 @@ def get_submitters(form_data: Dict[str, Any]) -> models.QuerySet[UserProfile]:
297310 models .Q (id__in = form_data .get ('submitter' , []))
298311 | models .Q (taggings__tag__in = form_data .get ('submitter_tag' , []))
299312 )
313+
314+ def approve_late_submissions (submitters , exercises , form_data ):
315+ minutes = form_data .get ('minutes' )
316+ new_date = form_data .get ('new_date' )
317+ for submitter in submitters :
318+ for exercise in exercises :
319+ submissions = exercise .get_submissions_for_student (submitter , exclude_errors = True )
320+ for submission in submissions :
321+ new_deadline = None
322+ if new_date :
323+ string_date = str (new_date )[:16 ]
324+ new_deadline = timezone .make_aware (
325+ parse_datetime (string_date ),
326+ timezone .get_current_timezone ())
327+ else :
328+ new_deadline = submission .submission_time + datetime .timedelta (minutes = minutes )
329+
330+ if submission .late_penalty_applied is not None and submission .submission_time <= new_deadline :
331+ submission .convert_penalized_submission ()
332+ submission .save ()
333+
334+ def approve_unofficial_submissions (submitters , exercises , form_data ):
335+ extra_submissions = form_data .get ('extra_submissions' )
336+ for submitter in submitters :
337+ for exercise in exercises :
338+ converted_counter = extra_submissions
339+ submissions_unordered = exercise .get_submissions_for_student (submitter , exclude_errors = True )
340+ submissions = [submission for submission in reversed (submissions_unordered )] #reverse the order to get older submission first
341+ for submission in submissions :
342+ if submission .status == Submission .STATUS .UNOFFICIAL and converted_counter > 0 :
343+ submission .convert_penalized_submission ()
344+ submission .save ()
345+ converted_counter -= 1
0 commit comments