from celery import shared_task from django.core.cache import cache from django.utils.translation import gettext as _ from judge.models import Problem, Profile, Submission from judge.utils.celery import Progress __all__ = ('apply_submission_filter', 'rejudge_problem_filter', 'rescore_problem') def apply_submission_filter(queryset, id_range, languages, results): if id_range: start, end = id_range queryset = queryset.filter(id__gte=start, id__lte=end) if languages: queryset = queryset.filter(language_id__in=languages) if results: queryset = queryset.filter(result__in=results) queryset = queryset.exclude(status__in=Submission.IN_PROGRESS_GRADING_STATUS) return queryset @shared_task(bind=True) def rejudge_problem_filter(self, problem_id, id_range=None, languages=None, results=None): queryset = Submission.objects.filter(problem_id=problem_id) queryset = apply_submission_filter(queryset, id_range, languages, results) rejudged = 0 with Progress(self, queryset.count()) as p: for submission in queryset.iterator(): submission.judge(rejudge=True, batch_rejudge=True) rejudged += 1 if rejudged % 10 == 0: p.done = rejudged return rejudged @shared_task(bind=True) def rescore_problem(self, problem_id): problem = Problem.objects.get(id=problem_id) submissions = Submission.objects.filter(problem_id=problem_id) with Progress(self, submissions.count(), stage=_('Modifying submissions')) as p: rescored = 0 for submission in submissions.iterator(): submission.points = round(submission.case_points / submission.case_total * problem.points if submission.case_total else 0, 1) if not problem.partial and submission.points < problem.points: submission.points = 0 submission.save(update_fields=['points']) submission.update_contest() rescored += 1 if rescored % 10 == 0: p.done = rescored with Progress(self, submissions.values('user_id').distinct().count(), stage=_('Recalculating user points')) as p: users = 0 profiles = Profile.objects.filter(id__in=submissions.values_list('user_id', flat=True).distinct()) for profile in profiles.iterator(): profile._updating_stats_only = True profile.calculate_points() cache.delete('user_complete:%d' % profile.id) cache.delete('user_attempted:%d' % profile.id) users += 1 if users % 10 == 0: p.done = users return rescored