from django.urls import reverse from django.utils.html import format_html from django.utils.translation import gettext as _ from judge.models import Submission from judge.utils.problems import get_result_data from judge.utils.raw_sql import join_sql_subquery from judge.views.submission import ForceContestMixin, ProblemSubmissions __all__ = ["RankedSubmissions", "ContestRankedSubmission"] class RankedSubmissions(ProblemSubmissions): tab = "best_submissions_list" page_type = "best_submissions_list" dynamic_update = False def get_queryset(self): if self.in_contest: contest_join = """INNER JOIN judge_contestsubmission AS cs ON (sub.id = cs.submission_id) INNER JOIN judge_contestparticipation AS cp ON (cs.participation_id = cp.id)""" points = "cs.points" constraint = "AND cp.contest_id = %s" else: contest_join = "" points = "sub.points" constraint = "" queryset = ( super(RankedSubmissions, self) ._get_queryset() .filter(user__is_unlisted=False) ) join_sql_subquery( queryset, subquery=""" SELECT sub.id AS id FROM ( SELECT sub.user_id AS uid, MAX(sub.points) AS points FROM judge_submission AS sub {contest_join} WHERE sub.problem_id = %s AND {points} > 0 {constraint} GROUP BY sub.user_id ) AS highscore STRAIGHT_JOIN ( SELECT sub.user_id AS uid, sub.points, MIN(sub.time) as time FROM judge_submission AS sub {contest_join} WHERE sub.problem_id = %s AND {points} > 0 {constraint} GROUP BY sub.user_id, {points} ) AS fastest ON (highscore.uid = fastest.uid AND highscore.points = fastest.points) STRAIGHT_JOIN judge_submission AS sub ON (sub.user_id = fastest.uid AND sub.time = fastest.time) {contest_join} WHERE sub.problem_id = %s AND {points} > 0 {constraint} GROUP BY sub.user_id """.format( points=points, contest_join=contest_join, constraint=constraint ), params=[self.problem.id, self.contest.id] * 3 if self.in_contest else [self.problem.id] * 3, alias="best_subs", join_fields=[("id", "id")], related_model=Submission, ) if self.in_contest: return queryset.order_by("-contest__points", "time") else: return queryset.order_by("-points", "time") def get_title(self): return _("Best solutions for %s") % self.problem_name def get_content_title(self): return format_html( _('Best solutions for {0}'), self.problem_name, reverse("problem_detail", args=[self.problem.code]), ) def _get_result_data(self): return get_result_data( super(RankedSubmissions, self)._get_queryset().order_by() ) class ContestRankedSubmission(ForceContestMixin, RankedSubmissions): def get_title(self): if self.problem.is_accessible_by(self.request.user): return _("Best solutions for %(problem)s in %(contest)s") % { "problem": self.problem_name, "contest": self.contest.name, } return _("Best solutions for problem %(number)s in %(contest)s") % { "number": self.get_problem_number(self.problem), "contest": self.contest.name, } def get_content_title(self): if self.problem.is_accessible_by(self.request.user): return format_html( _('Best solutions for {0} in {2}'), self.problem_name, reverse("problem_detail", args=[self.problem.code]), self.contest.name, reverse("contest_view", args=[self.contest.key]), ) return format_html( _('Best solutions for problem {0} in {1}'), self.get_problem_number(self.problem), self.contest.name, reverse("contest_view", args=[self.contest.key]), ) def _get_result_data(self): return get_result_data( Submission.objects.filter( problem_id=self.problem.id, contest__participation__contest_id=self.contest.id, ) )