From fc02649d85d9e924cff5f5fa48059e91b1b64778 Mon Sep 17 00:00:00 2001 From: Mateusz Masiarz Date: Tue, 17 Sep 2024 12:10:33 +0200 Subject: [PATCH] Display score change in submissions admin --- oioioi/acm/controllers.py | 3 +++ oioioi/contests/admin.py | 18 ++++++++++++++++++ oioioi/contests/controllers.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/oioioi/acm/controllers.py b/oioioi/acm/controllers.py index 851a8b4a5..aed30edd3 100644 --- a/oioioi/acm/controllers.py +++ b/oioioi/acm/controllers.py @@ -201,6 +201,9 @@ def can_see_round(self, request_or_context, round, no_admin=False): def get_default_safe_exec_mode(self): return 'cpu' + def display_score_change(self): + return False + class ACMOpenContestController(ACMContestController): description = _("ACM style contest (open)") diff --git a/oioioi/contests/admin.py b/oioioi/contests/admin.py index 917567b2d..d1ffdd1c6 100644 --- a/oioioi/contests/admin.py +++ b/oioioi/contests/admin.py @@ -712,6 +712,8 @@ def get_list_display(self, request): ] if request.contest: list_display.remove('contest_display') + if request.contest.controller.display_score_change(): + list_display.append('score_diff_display') return list_display def get_list_display_links(self, request, list_display): @@ -848,6 +850,22 @@ def score_display(self, instance): score_display.short_description = _("Score") score_display.admin_order_field = 'score_with_nulls_smallest' + def score_diff_display(self, instance): + contest_controller = instance.problem_instance.contest.controller + if not contest_controller.display_score_change() or instance.kind != 'NORMAL': + return format_html('-') + + previous_submission = Submission.objects.filter( + user=instance.user, + problem_instance=instance.problem_instance, + kind='NORMAL', + date__lt=instance.date, + ).order_by('-date').first() + return contest_controller.render_score_change(previous_submission, instance) + + score_diff_display.short_description = _("Score change") + score_diff_display.admin_order_field = 'score' + def contest_display(self, instance): return instance.problem_instance.contest diff --git a/oioioi/contests/controllers.py b/oioioi/contests/controllers.py index 48c1bc6b3..3764d9cb5 100644 --- a/oioioi/contests/controllers.py +++ b/oioioi/contests/controllers.py @@ -9,6 +9,7 @@ from django.db.models import Subquery from django.template.loader import render_to_string from django.urls import reverse +from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_noop @@ -974,6 +975,36 @@ def _is_partial_score(self, test_report): def show_default_fields(self, problem_instance): return problem_instance.problem.controller.show_default_fields(problem_instance) + def display_score_change(self): + """ + Whether to display score change for a submission in submissions admin. + """ + return True + + def _calculate_score_change(self, before, after): + """ + Calculate score difference between two scores. + """ + if before is None or after is None: + return after + cls = type(before) + return cls(after.value - before.value) + + def render_score_change(self, previous_submission, current_submission): + """ + Calculates and renders score change between two submissions. + """ + prev_score = previous_submission.score if previous_submission else None + curr_score = current_submission.score if current_submission else None + diff = self._calculate_score_change(prev_score, curr_score) + if diff is None: + return format_html('-') + if diff.value == 0: + return format_html('0') + if diff.value > 0: + return format_html('+{}', diff.value) + return format_html('{}', diff.value) + class PastRoundsHiddenContestControllerMixin(object): """ContestController mixin that hides past rounds