From 18d23c771a56757393001065d4b1708cf437bf6c Mon Sep 17 00:00:00 2001 From: anhkha2003 Date: Wed, 2 Oct 2024 20:27:49 -0500 Subject: [PATCH] Fix contest rescore bug --- judge/admin/contest.py | 41 ++++++------------------------------ judge/utils/contest.py | 23 +++++++++++--------- judge/views/course.py | 6 +++++- judge/views/organization.py | 2 +- resources/base.scss | 4 ++++ resources/table.scss | 2 +- resources/users.scss | 1 + templates/course/grades.html | 18 +++++++++------- templates/user/pp-row.html | 3 +-- 9 files changed, 42 insertions(+), 58 deletions(-) diff --git a/judge/admin/contest.py b/judge/admin/contest.py index be07ab3..062d014 100644 --- a/judge/admin/contest.py +++ b/judge/admin/contest.py @@ -32,6 +32,7 @@ from judge.widgets import ( HeavyPreviewAdminPageDownWidget, ) from judge.views.contests import recalculate_contest_summary_result +from judge.utils.contest import maybe_trigger_contest_rescore class AdminHeavySelect2Widget(AdminHeavySelect2Widget): @@ -310,39 +311,14 @@ class ContestAdmin(CompareVersionAdmin): super().save_model(request, obj, form, change) - # We need this flag because `save_related` deals with the inlines, but does not know if we have already rescored - self._rescored = False - if form.changed_data and any( - f in form.changed_data - for f in ( - "start_time", - "end_time", - "time_limit", - "format_config", - "format_name", - "freeze_after", - ) - ): - self._rescore(obj.key) - self._rescored = True - - if form.changed_data and any( - f in form.changed_data - for f in ( - "authors", - "curators", - "testers", - ) - ): - Contest._author_ids.dirty(obj) - Contest._curator_ids.dirty(obj) - Contest._tester_ids.dirty(obj) - def save_related(self, request, form, formsets, change): super().save_related(request, form, formsets, change) # Only rescored if we did not already do so in `save_model` - if not self._rescored and any(formset.has_changed() for formset in formsets): - self._rescore(form.cleaned_data["key"]) + formset_changed = False + if any(formset.has_changed() for formset in formsets): + formset_changed = True + + maybe_trigger_contest_rescore(form, form.instance, formset_changed) def has_change_permission(self, request, obj=None): if not request.user.has_perm("judge.edit_own_contest"): @@ -351,11 +327,6 @@ class ContestAdmin(CompareVersionAdmin): return True return obj.is_editable_by(request.user) - def _rescore(self, contest_key): - from judge.tasks import rescore_contest - - transaction.on_commit(rescore_contest.s(contest_key).delay) - def make_visible(self, request, queryset): if not request.user.has_perm("judge.change_contest_visibility"): queryset = queryset.filter( diff --git a/judge/utils/contest.py b/judge/utils/contest.py index eeb4134..959749e 100644 --- a/judge/utils/contest.py +++ b/judge/utils/contest.py @@ -5,17 +5,20 @@ from judge.models import ( ) -def maybe_trigger_contest_rescore(form, contest): - if any( - f in form.changed_data - for f in ( - "start_time", - "end_time", - "time_limit", - "format_config", - "format_name", - "freeze_after", +def maybe_trigger_contest_rescore(form, contest, force_rescore=False): + if ( + any( + f in form.changed_data + for f in ( + "start_time", + "end_time", + "time_limit", + "format_config", + "format_name", + "freeze_after", + ) ) + or force_rescore ): transaction.on_commit(rescore_contest.s(contest.key).delay) diff --git a/judge/views/course.py b/judge/views/course.py index 17f794e..7514d6f 100644 --- a/judge/views/course.py +++ b/judge/views/course.py @@ -715,7 +715,10 @@ class EditCourseContest(CourseEditableMixin, FormView): def post(self, request, *args, **kwargs): problem_formset = self.get_problem_formset(True) if problem_formset.is_valid(): + self.problem_form_changes = False for problem_form in problem_formset: + if problem_form.has_changed(): + self.problem_form_changes = True if problem_form.cleaned_data.get("DELETE") and problem_form.instance.pk: problem_form.instance.delete() @@ -741,7 +744,8 @@ class EditCourseContest(CourseEditableMixin, FormView): revisions.set_comment(_("Edited from course") + " " + self.course.name) revisions.set_user(self.request.user) - maybe_trigger_contest_rescore(form, self.contest) + if self.problem_form_changes: + maybe_trigger_contest_rescore(form, self.contest, True) form.save() diff --git a/judge/views/organization.py b/judge/views/organization.py index 364b12a..2a5fea1 100644 --- a/judge/views/organization.py +++ b/judge/views/organization.py @@ -1039,7 +1039,7 @@ class EditOrganizationContest( self.object.is_organization_private = True self.object.save() - maybe_trigger_contest_rescore(form, self.object) + maybe_trigger_contest_rescore(form, self.object, True) return res diff --git a/resources/base.scss b/resources/base.scss index a64375a..1b63cc7 100644 --- a/resources/base.scss +++ b/resources/base.scss @@ -843,6 +843,10 @@ noscript #noscript { .nav-fa-icon { display: none; } + + .page-title { + margin-left: 0.5em; + } } @media(min-width: 800px) { diff --git a/resources/table.scss b/resources/table.scss index a077ed4..2d8e635 100644 --- a/resources/table.scss +++ b/resources/table.scss @@ -22,7 +22,7 @@ } } - td:first-child { + th:first-child, td:first-child { border-color: $border_gray; border-width: 1px 1px 0 1px; } diff --git a/resources/users.scss b/resources/users.scss index a619026..d6f41ac 100644 --- a/resources/users.scss +++ b/resources/users.scss @@ -179,6 +179,7 @@ th.header.rank { vertical-align: top; width: 225px; float: right; + margin-top: 1em; .select2-selection__arrow { display: none; diff --git a/templates/course/grades.html b/templates/course/grades.html index 5dba12a..3b19cf9 100644 --- a/templates/course/grades.html +++ b/templates/course/grades.html @@ -47,8 +47,8 @@ var rows = $('#users-table tbody tr').get(); var sortBy = $(this).val(); rows.sort(function(a, b) { - var keyA = $(a).find(sortBy === 'username' ? '.user-name' : 'td:last-child').text().trim(); - var keyB = $(b).find(sortBy === 'username' ? '.user-name' : 'td:last-child').text().trim(); + var keyA = $(a).find(sortBy === 'username' ? '.user-name' : '.total-score').text().trim(); + var keyB = $(b).find(sortBy === 'username' ? '.user-name' : '.total-score').text().trim(); if(sortBy === 'total') { // Convert percentage string to number for comparison @@ -76,11 +76,13 @@ {% block middle_content %}

{{content_title}}

{{_("Sort by")}}: - - +
+ + +
@@ -119,7 +121,7 @@ {{student.first_name}} -
+ {% if grade_total_student %} {{ grade_total_student['percentage'] | floatformat(0) }}% {% else %} diff --git a/templates/user/pp-row.html b/templates/user/pp-row.html index d943068..eb5b13f 100644 --- a/templates/user/pp-row.html +++ b/templates/user/pp-row.html @@ -10,7 +10,6 @@
{{ breakdown.sub_points|floatformat(0) }} / {{ breakdown.sub_total|floatformat(0) }}
{{ breakdown.sub_lang }}
- {{ relative_time(breakdown.sub_date) }}
@@ -19,7 +18,7 @@
{% trans weight=breakdown.weight|floatformat(0) %} - weighted {{ weight }}% + {{ weight }}% {% endtrans %} {% if breakdown.scaled_points < 10 %}