Skip to content

Commit

Permalink
Fix displaying score diff in different controllers
Browse files Browse the repository at this point in the history
  • Loading branch information
MasloMaslane committed Sep 17, 2024
1 parent fc02649 commit 729ce2d
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 57 deletions.
6 changes: 6 additions & 0 deletions oioioi/acm/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ def _fill_user_result_for_problem(self, result, pi_submissions):
result.status = None
return None

def get_last_scored_submission(self, user, problem_instance, before=None, include_current=False):
"""This function is not implemented for ACM contests because score difference
isn't shown for ACM contests.
"""
raise NotImplementedError

def update_user_result_for_problem(self, result):
submissions = (
Submission.objects.filter(
Expand Down
26 changes: 19 additions & 7 deletions oioioi/contests/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -852,16 +852,28 @@ def score_display(self, instance):

def score_diff_display(self, instance):
contest_controller = instance.problem_instance.contest.controller
pi_controller = instance.problem_instance.controller
if not contest_controller.display_score_change() or instance.kind != 'NORMAL':
return format_html('<span class="text-secondary">-</span>')

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)
try:
previous_submission = pi_controller.get_last_scored_submission(
instance.user,
instance.problem_instance,
before=instance.date,
)
except Submission.DoesNotExist:
previous_submission = None
try:
curr_submission = pi_controller.get_last_scored_submission(
instance.user,
instance.problem_instance,
before=instance.date,
include_current=True,
)
except Submission.DoesNotExist:
curr_submission = None
return contest_controller.render_score_change(previous_submission, curr_submission)

score_diff_display.short_description = _("Score change")
score_diff_display.admin_order_field = 'score'
Expand Down
4 changes: 4 additions & 0 deletions oioioi/contests/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,10 @@ def update_submission_score(self, submission):
problem = submission.problem_instance.problem
problem.controller.update_submission_score(submission)

def get_last_scored_submission(self, user, problem_instance, before=None, include_current=False):
problem = problem_instance.problem
return problem.controller.get_last_scored_submission(user, problem_instance, before, include_current)

def update_user_result_for_problem(self, result):
problem = result.problem_instance.problem
problem.controller.update_user_result_for_problem(result)
Expand Down
64 changes: 63 additions & 1 deletion oioioi/contests/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
ProblemStatement,
)
from oioioi.programs.controllers import ProgrammingContestController
from oioioi.programs.models import ModelProgramSubmission, Test
from oioioi.programs.models import ModelProgramSubmission, Test, ProgramSubmission
from oioioi.programs.tests import SubmitFileMixin
from oioioi.simpleui.views import (
contest_dashboard_redirect as simpleui_contest_dashboard,
Expand Down Expand Up @@ -4200,3 +4200,65 @@ def test_score_badge(self):
self.assertIn('badge-warning', self._get_badge_for_problem(response.content, 'zad2'))
self.assertIn('badge-danger', self._get_badge_for_problem(response.content, 'zad3'))


class TestScoreDiffDisplay(TestCase):
fixtures = [
'test_users',
'test_contest',
'test_full_package',
'test_problem_instance',
]

contest_controller = 'oioioi.contests.controllers.ContestController'

def _change_contest_controller(self, controller_name):
contest = Contest.objects.get()
contest.controller_name = controller_name
contest.save()

def _get_score_diff(self, submission):
contest = Contest.objects.get()
url = reverse('oioioiadmin:contests_submission_changelist', kwargs={'contest_id': contest.id})
response = self.client.get(url)
self.assertEqual(response.status_code, 200)

soup = bs4.BeautifulSoup(response.content, 'html.parser')
submissions_table = soup.find('table', {'id': 'result_list'})
tbody = submissions_table.find('tbody')
for tr in tbody.find_all('tr'):
s_id = tr.find('th', {'class': 'field-id'}).text
if s_id == str(submission.id):
return tr.find('td', {'class': 'field-score_diff_display'}).text

def _create_submission(self, score, expected_diff):
problem_instance = ProblemInstance.objects.get(pk=1)
user = User.objects.get(username='test_admin')
ps = ProgramSubmission.objects.create(
source_file=ContentFile(b'int main() {}', name='main.cpp'),
problem_instance=problem_instance,
user=user,
score=score,
status='OK',
)
ps.save()
self.assertEqual(expected_diff, self._get_score_diff(ps))
return ps

def setUp(self):
self.client.force_login(User.objects.get(username='test_admin'))
self._change_contest_controller(self.contest_controller)
Submission.objects.all().delete()


class TestScoreDiffSimpleContest(TestScoreDiffDisplay):
contest_controller = 'oioioi.programs.controllers.ProgrammingContestController'

def test(self):
self._create_submission(IntegerScore(25), '+25')
s1 = self._create_submission(IntegerScore(50), '+25')
s2 = self._create_submission(IntegerScore(100), '+50')
self._create_submission(IntegerScore(0), '-100')
s1.kind = 'IGNORED'
s1.save()
self.assertEqual(self._get_score_diff(s2), '+75')
self.assertEqual(self._get_score_diff(s1), '-')
55 changes: 38 additions & 17 deletions oioioi/mp/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,23 +122,24 @@ def _get_score_for_submission(self, submission, ssm):
return score * ssm.multiplier
return None

def update_user_result_for_problem(self, result):
"""Submissions sent during the round are scored as normal.
Submissions sent while the round was over but SubmissionScoreMultiplier was active
are scored with given multiplier.
"""
def get_last_scored_submission(self, user, problem_instance, before=None, include_current=False):
submissions = Submission.objects.filter(
problem_instance=result.problem_instance,
user=result.user,
problem_instance=problem_instance,
user=user,
kind='NORMAL',
score__isnull=False,
)
if before:
if include_current:
submissions = submissions.filter(date__lte=before)
else:
submissions = submissions.filter(date__lt=before)

best_submission = None
best_submission_score = None
try:
ssm = SubmissionScoreMultiplier.objects.get(
contest=result.problem_instance.contest
contest=problem_instance.contest
)
except SubmissionScoreMultiplier.DoesNotExist:
ssm = None
Expand All @@ -148,17 +149,37 @@ def update_user_result_for_problem(self, result):
if not best_submission or (score and best_submission_score < score):
best_submission = submission
best_submission_score = score
return best_submission

try:
report = SubmissionReport.objects.get(
submission=best_submission, status='ACTIVE', kind='NORMAL'
)
except SubmissionReport.DoesNotExist:
report = None
def update_user_result_for_problem(self, result):
"""Submissions sent during the round are scored as normal.
Submissions sent while the round was over but SubmissionScoreMultiplier was active
are scored with given multiplier.
"""
best_submission = self.get_last_scored_submission(result.user, result.problem_instance)
if best_submission:
try:
ssm = SubmissionScoreMultiplier.objects.get(
contest=result.problem_instance.contest
)
except SubmissionScoreMultiplier.DoesNotExist:
ssm = None
best_submission_score = self._get_score_for_submission(best_submission, ssm)

try:
report = SubmissionReport.objects.get(
submission=best_submission, status='ACTIVE', kind='NORMAL'
)
except SubmissionReport.DoesNotExist:
report = None

result.score = best_submission_score
result.status = best_submission.status if best_submission else None
result.submission_report = report
result.score = best_submission_score
result.status = best_submission.status if best_submission else None
result.submission_report = report
else:
result.score = None
result.status = None
result.submission_report = None

def can_submit(self, request, problem_instance, check_round_times=True):
"""Contest admin can always submit.
Expand Down
15 changes: 15 additions & 0 deletions oioioi/mp/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from oioioi.base.tests import TestCase, fake_time
from oioioi.contests.models import Contest, UserResultForProblem
from oioioi.contests.tests.tests import TestScoreDiffDisplay
from oioioi.mp.score import FloatScore


Expand Down Expand Up @@ -96,3 +97,17 @@ def test_results_scores(self):
for urfp in UserResultForProblem.objects.all():
res = self._create_result(urfp.user, urfp.problem_instance)
self.assertEqual(res.score, urfp.score)


class TestScoreDiffMPContest(TestScoreDiffDisplay):
contest_controller = 'oioioi.mp.controllers.MPContestController'

def test(self):
self._create_submission(FloatScore(25.5), '+25.5')
s1 = self._create_submission(FloatScore(50), '+24.5')
s2 = self._create_submission(FloatScore(100), '+50.0')
self._create_submission(FloatScore(0), '0')
s1.kind = 'IGNORED'
s1.save()
self.assertEqual(self._get_score_diff(s1), '-')
self.assertEqual(self._get_score_diff(s2), '+74.5')
74 changes: 49 additions & 25 deletions oioioi/oi/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,24 @@ def can_see_stats(self, request):
def should_confirm_submission_receipt(self, request, submission):
return submission.kind == 'NORMAL' and request.user == submission.user

def get_last_scored_submission(self, user, problem_instance, before=None, include_current=False):
submissions = (
Submission.objects.filter(problem_instance=problem_instance)
.filter(user=user)
.filter(score__isnull=False)
.exclude(status='CE')
.filter(kind='NORMAL')
)
if before:
if include_current:
submissions = submissions.filter(date__lte=before)
else:
submissions = submissions.filter(date__lt=before)
return submissions.latest()

def update_user_result_for_problem(self, result):
try:
latest_submission = (
Submission.objects.filter(problem_instance=result.problem_instance)
.filter(user=result.user)
.filter(score__isnull=False)
.exclude(status='CE')
.filter(kind='NORMAL')
.latest()
)
latest_submission = self.get_last_scored_submission(result.user, result.problem_instance)
try:
report = SubmissionReport.objects.get(
submission=latest_submission, status='ACTIVE', kind='NORMAL'
Expand Down Expand Up @@ -241,18 +249,27 @@ class OIFinalOnsiteContestController(OIOnsiteContestController):
def can_see_submission_score(self, request, submission):
return True

def update_user_result_for_problem(self, result):
def get_last_scored_submission(self, user, problem_instance, before=None, include_current=False):
submissions = (
Submission.objects.filter(problem_instance=result.problem_instance)
.filter(user=result.user)
Submission.objects.filter(problem_instance=problem_instance)
.filter(user=user)
.filter(score__isnull=False)
.exclude(status='CE')
.filter(kind='NORMAL')
)

if before:
if include_current:
submissions = submissions.filter(date__lte=before)
else:
submissions = submissions.filter(date__lt=before)
if submissions:
max_submission = submissions.order_by('-score')[0]
return submissions.order_by('-score')[0]
return None

def update_user_result_for_problem(self, result):
max_submission = self.get_last_scored_submission(result.user, result.problem_instance)

if max_submission:
try:
report = SubmissionReport.objects.get(
submission=max_submission, status='ACTIVE', kind='NORMAL'
Expand Down Expand Up @@ -281,23 +298,30 @@ def reveal_score(self, request, submission):
super(BOIOnsiteContestController, self).reveal_score(request, submission)
self.update_user_results(submission.user, submission.problem_instance)

def update_user_result_for_problem(self, result):
try:
submissions = (
Submission.objects.filter(problem_instance=result.problem_instance)
.filter(user=result.user)
def get_last_scored_submission(self, user, problem_instance, before=None, include_current=False):
submissions = (
Submission.objects.filter(problem_instance=problem_instance)
.filter(user=user)
.filter(score__isnull=False)
.exclude(status='CE')
.filter(kind='NORMAL')
)
if before:
if include_current:
submissions = submissions.filter(date__lte=before)
else:
submissions = submissions.filter(date__lt=before)
chosen_submission = submissions.latest()
revealed = submissions.filter(revealed__isnull=False)
if revealed:
max_revealed = revealed.order_by('-score')[0]
if max_revealed.score > chosen_submission.score:
chosen_submission = max_revealed
return chosen_submission

chosen_submission = submissions.latest()

revealed = submissions.filter(revealed__isnull=False)
if revealed:
max_revealed = revealed.order_by('-score')[0]
if max_revealed.score > chosen_submission.score:
chosen_submission = max_revealed
def update_user_result_for_problem(self, result):
try:
chosen_submission = self.get_last_scored_submission(result.user, result.problem_instance)

try:
report = SubmissionReport.objects.get(
Expand Down
30 changes: 30 additions & 0 deletions oioioi/oi/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from oioioi.contests.current_contest import ContestMode
from oioioi.contests.handlers import update_user_results
from oioioi.contests.models import Contest, ProblemInstance, Round
from oioioi.contests.scores import IntegerScore
from oioioi.contests.tests.tests import TestScoreDiffDisplay
from oioioi.evalmgr.tasks import create_environ
from oioioi.oi.management.commands import import_schools
from oioioi.oi.models import OIRegistration, School
Expand Down Expand Up @@ -616,3 +618,31 @@ def test_user_info_page(self):
self.assertContains(response, reg_data[k])
else:
self.assertNotContains(response, reg_data[k], status_code=403)


class TestScoreDiffOIContest(TestScoreDiffDisplay):
contest_controller = 'oioioi.oi.controllers.OIContestController'

def test(self):
self._create_submission(IntegerScore(25), '+25')
s1 = self._create_submission(IntegerScore(50), '+25')
s2 = self._create_submission(IntegerScore(100), '+50')
self._create_submission(IntegerScore(0), '-100')
s1.kind = 'IGNORED'
s1.save()
self.assertEqual(self._get_score_diff(s2), '+75')
self.assertEqual(self._get_score_diff(s1), '-')


class TestScoreDiffOIFinalsContest(TestScoreDiffDisplay):
contest_controller = 'oioioi.oi.controllers.OIFinalOnsiteContestController'

def test(self):
self._create_submission(IntegerScore(25), '+25')
s1 = self._create_submission(IntegerScore(50), '+25')
s2 = self._create_submission(IntegerScore(100), '+50')
self._create_submission(IntegerScore(0), '0')
s1.kind = 'IGNORED'
s1.save()
self.assertEqual(self._get_score_diff(s2), '+75')
self.assertEqual(self._get_score_diff(s1), '-')
Loading

0 comments on commit 729ce2d

Please sign in to comment.