Add final ranking for superuser (ioi16 only)
This commit is contained in:
parent
6635c3ee99
commit
309b6298e2
16 changed files with 424 additions and 336 deletions
|
@ -523,6 +523,11 @@ urlpatterns = [
|
||||||
contests.ContestRanking.as_view(),
|
contests.ContestRanking.as_view(),
|
||||||
name="contest_ranking",
|
name="contest_ranking",
|
||||||
),
|
),
|
||||||
|
url(
|
||||||
|
r"^/final_ranking/$",
|
||||||
|
contests.ContestFinalRanking.as_view(),
|
||||||
|
name="contest_final_ranking",
|
||||||
|
),
|
||||||
url(
|
url(
|
||||||
r"^/ranking/ajax$",
|
r"^/ranking/ajax$",
|
||||||
contests.contest_ranking_ajax,
|
contests.contest_ranking_ajax,
|
||||||
|
|
|
@ -112,7 +112,7 @@ class AtCoderContestFormat(DefaultContestFormat):
|
||||||
participation.format_data = format_data
|
participation.format_data = format_data
|
||||||
participation.save()
|
participation.save()
|
||||||
|
|
||||||
def display_user_problem(self, participation, contest_problem):
|
def display_user_problem(self, participation, contest_problem, show_final=False):
|
||||||
format_data = (participation.format_data or {}).get(str(contest_problem.id))
|
format_data = (participation.format_data or {}).get(str(contest_problem.id))
|
||||||
if format_data:
|
if format_data:
|
||||||
penalty = (
|
penalty = (
|
||||||
|
|
|
@ -48,7 +48,7 @@ class BaseContestFormat(metaclass=ABCMeta):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def display_user_problem(self, participation, contest_problem):
|
def display_user_problem(self, participation, contest_problem, show_final):
|
||||||
"""
|
"""
|
||||||
Returns the HTML fragment to show a user's performance on an individual problem. This is expected to use
|
Returns the HTML fragment to show a user's performance on an individual problem. This is expected to use
|
||||||
information from the format_data field instead of computing it from scratch.
|
information from the format_data field instead of computing it from scratch.
|
||||||
|
@ -60,7 +60,7 @@ class BaseContestFormat(metaclass=ABCMeta):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def display_participation_result(self, participation):
|
def display_participation_result(self, participation, show_final):
|
||||||
"""
|
"""
|
||||||
Returns the HTML fragment to show a user's performance on the whole contest. This is expected to use
|
Returns the HTML fragment to show a user's performance on the whole contest. This is expected to use
|
||||||
information from the format_data field instead of computing it from scratch.
|
information from the format_data field instead of computing it from scratch.
|
||||||
|
|
|
@ -61,7 +61,7 @@ class DefaultContestFormat(BaseContestFormat):
|
||||||
participation.format_data = format_data
|
participation.format_data = format_data
|
||||||
participation.save()
|
participation.save()
|
||||||
|
|
||||||
def display_user_problem(self, participation, contest_problem):
|
def display_user_problem(self, participation, contest_problem, show_final=False):
|
||||||
format_data = (participation.format_data or {}).get(str(contest_problem.id))
|
format_data = (participation.format_data or {}).get(str(contest_problem.id))
|
||||||
if format_data:
|
if format_data:
|
||||||
return format_html(
|
return format_html(
|
||||||
|
@ -94,7 +94,7 @@ class DefaultContestFormat(BaseContestFormat):
|
||||||
else:
|
else:
|
||||||
return mark_safe('<td class="problem-score-col"></td>')
|
return mark_safe('<td class="problem-score-col"></td>')
|
||||||
|
|
||||||
def display_participation_result(self, participation):
|
def display_participation_result(self, participation, show_final=False):
|
||||||
return format_html(
|
return format_html(
|
||||||
'<td class="user-points">{points}<div class="solving-time">{cumtime}</div></td>',
|
'<td class="user-points">{points}<div class="solving-time">{cumtime}</div></td>',
|
||||||
points=floatformat(participation.score, -self.contest.points_precision),
|
points=floatformat(participation.score, -self.contest.points_precision),
|
||||||
|
|
|
@ -122,7 +122,7 @@ class ECOOContestFormat(DefaultContestFormat):
|
||||||
participation.format_data = format_data
|
participation.format_data = format_data
|
||||||
participation.save()
|
participation.save()
|
||||||
|
|
||||||
def display_user_problem(self, participation, contest_problem):
|
def display_user_problem(self, participation, contest_problem, show_final=False):
|
||||||
format_data = (participation.format_data or {}).get(str(contest_problem.id))
|
format_data = (participation.format_data or {}).get(str(contest_problem.id))
|
||||||
if format_data:
|
if format_data:
|
||||||
bonus = (
|
bonus = (
|
||||||
|
@ -162,7 +162,7 @@ class ECOOContestFormat(DefaultContestFormat):
|
||||||
else:
|
else:
|
||||||
return mark_safe("<td></td>")
|
return mark_safe("<td></td>")
|
||||||
|
|
||||||
def display_participation_result(self, participation):
|
def display_participation_result(self, participation, show_final=False):
|
||||||
return format_html(
|
return format_html(
|
||||||
'<td class="user-points">{points}<div class="solving-time">{cumtime}</div></td>',
|
'<td class="user-points">{points}<div class="solving-time">{cumtime}</div></td>',
|
||||||
points=floatformat(participation.score),
|
points=floatformat(participation.score),
|
||||||
|
|
|
@ -114,7 +114,7 @@ class ICPCContestFormat(DefaultContestFormat):
|
||||||
participation.format_data = format_data
|
participation.format_data = format_data
|
||||||
participation.save()
|
participation.save()
|
||||||
|
|
||||||
def display_user_problem(self, participation, contest_problem):
|
def display_user_problem(self, participation, contest_problem, show_final=False):
|
||||||
format_data = (participation.format_data or {}).get(str(contest_problem.id))
|
format_data = (participation.format_data or {}).get(str(contest_problem.id))
|
||||||
if format_data:
|
if format_data:
|
||||||
penalty = (
|
penalty = (
|
||||||
|
|
|
@ -86,7 +86,12 @@ class IOIContestFormat(DefaultContestFormat):
|
||||||
participation.format_data = format_data
|
participation.format_data = format_data
|
||||||
participation.save()
|
participation.save()
|
||||||
|
|
||||||
def display_user_problem(self, participation, contest_problem):
|
def display_user_problem(self, participation, contest_problem, show_final=False):
|
||||||
|
if show_final:
|
||||||
|
format_data = (participation.format_data_final or {}).get(
|
||||||
|
str(contest_problem.id)
|
||||||
|
)
|
||||||
|
else:
|
||||||
format_data = (participation.format_data or {}).get(str(contest_problem.id))
|
format_data = (participation.format_data or {}).get(str(contest_problem.id))
|
||||||
if format_data:
|
if format_data:
|
||||||
return format_html(
|
return format_html(
|
||||||
|
@ -121,11 +126,17 @@ class IOIContestFormat(DefaultContestFormat):
|
||||||
else:
|
else:
|
||||||
return mark_safe('<td class="problem-score-col"></td>')
|
return mark_safe('<td class="problem-score-col"></td>')
|
||||||
|
|
||||||
def display_participation_result(self, participation):
|
def display_participation_result(self, participation, show_final=False):
|
||||||
|
if show_final:
|
||||||
|
score = participation.score_final
|
||||||
|
cumtime = participation.cumtime_final
|
||||||
|
else:
|
||||||
|
score = participation.score
|
||||||
|
cumtime = participation.cumtime
|
||||||
return format_html(
|
return format_html(
|
||||||
'<td class="user-points">{points}<div class="solving-time">{cumtime}</div></td>',
|
'<td class="user-points">{points}<div class="solving-time">{cumtime}</div></td>',
|
||||||
points=floatformat(participation.score, -self.contest.points_precision),
|
points=floatformat(score, -self.contest.points_precision),
|
||||||
cumtime=nice_repr(timedelta(seconds=participation.cumtime), "noday")
|
cumtime=nice_repr(timedelta(seconds=cumtime), "noday")
|
||||||
if self.config["cumtime"]
|
if self.config["cumtime"]
|
||||||
else "",
|
else "",
|
||||||
)
|
)
|
||||||
|
|
|
@ -100,11 +100,10 @@ class NewIOIContestFormat(IOIContestFormat):
|
||||||
return cursor.fetchall()
|
return cursor.fetchall()
|
||||||
|
|
||||||
def update_participation(self, participation):
|
def update_participation(self, participation):
|
||||||
cumtime = 0
|
|
||||||
score = 0
|
|
||||||
format_data = {}
|
|
||||||
frozen_subtasks = self.get_frozen_subtasks()
|
frozen_subtasks = self.get_frozen_subtasks()
|
||||||
|
|
||||||
|
def calculate_format_data(participation, include_frozen):
|
||||||
|
format_data = {}
|
||||||
for (
|
for (
|
||||||
problem_id,
|
problem_id,
|
||||||
problem_points,
|
problem_points,
|
||||||
|
@ -113,7 +112,7 @@ class NewIOIContestFormat(IOIContestFormat):
|
||||||
total_subtask_points,
|
total_subtask_points,
|
||||||
subtask,
|
subtask,
|
||||||
sub_id,
|
sub_id,
|
||||||
) in self.get_results_by_subtask(participation):
|
) in self.get_results_by_subtask(participation, include_frozen):
|
||||||
problem_id = str(problem_id)
|
problem_id = str(problem_id)
|
||||||
time = from_database_time(time)
|
time = from_database_time(time)
|
||||||
if self.config["cumtime"]:
|
if self.config["cumtime"]:
|
||||||
|
@ -122,13 +121,27 @@ class NewIOIContestFormat(IOIContestFormat):
|
||||||
dt = 0
|
dt = 0
|
||||||
|
|
||||||
if format_data.get(problem_id) is None:
|
if format_data.get(problem_id) is None:
|
||||||
format_data[problem_id] = {"points": 0, "time": 0, "total_points": 0}
|
format_data[problem_id] = {
|
||||||
if subtask not in frozen_subtasks.get(problem_id, set()):
|
"points": 0,
|
||||||
|
"time": 0,
|
||||||
|
"total_points": 0,
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
subtask not in frozen_subtasks.get(problem_id, set())
|
||||||
|
or include_frozen
|
||||||
|
):
|
||||||
format_data[problem_id]["points"] += subtask_points
|
format_data[problem_id]["points"] += subtask_points
|
||||||
format_data[problem_id]["total_points"] += total_subtask_points
|
format_data[problem_id]["total_points"] += total_subtask_points
|
||||||
format_data[problem_id]["time"] = max(dt, format_data[problem_id]["time"])
|
format_data[problem_id]["time"] = max(
|
||||||
|
dt, format_data[problem_id]["time"]
|
||||||
|
)
|
||||||
format_data[problem_id]["problem_points"] = problem_points
|
format_data[problem_id]["problem_points"] = problem_points
|
||||||
|
|
||||||
|
return format_data
|
||||||
|
|
||||||
|
def recalculate_results(format_data):
|
||||||
|
cumtime = 0
|
||||||
|
score = 0
|
||||||
for problem_data in format_data.values():
|
for problem_data in format_data.values():
|
||||||
if not problem_data["total_points"]:
|
if not problem_data["total_points"]:
|
||||||
continue
|
continue
|
||||||
|
@ -141,10 +154,19 @@ class NewIOIContestFormat(IOIContestFormat):
|
||||||
if self.config["cumtime"] and problem_data["points"]:
|
if self.config["cumtime"] and problem_data["points"]:
|
||||||
cumtime += penalty
|
cumtime += penalty
|
||||||
score += problem_data["points"]
|
score += problem_data["points"]
|
||||||
|
return score, cumtime
|
||||||
|
|
||||||
|
format_data = calculate_format_data(participation, False)
|
||||||
|
score, cumtime = recalculate_results(format_data)
|
||||||
self.handle_frozen_state(participation, format_data)
|
self.handle_frozen_state(participation, format_data)
|
||||||
participation.cumtime = max(cumtime, 0)
|
participation.cumtime = max(cumtime, 0)
|
||||||
participation.score = round(score, self.contest.points_precision)
|
participation.score = round(score, self.contest.points_precision)
|
||||||
participation.tiebreaker = 0
|
participation.tiebreaker = 0
|
||||||
participation.format_data = format_data
|
participation.format_data = format_data
|
||||||
|
|
||||||
|
format_data_final = calculate_format_data(participation, True)
|
||||||
|
score_final, cumtime_final = recalculate_results(format_data_final)
|
||||||
|
participation.cumtime_final = max(cumtime_final, 0)
|
||||||
|
participation.score_final = round(score_final, self.contest.points_precision)
|
||||||
|
participation.format_data_final = format_data_final
|
||||||
participation.save()
|
participation.save()
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.2.16 on 2022-12-28 18:36
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
import jsonfield.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("judge", "0141_contestproblem_frozen_subtasks"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="contestparticipation",
|
||||||
|
name="format_data_final",
|
||||||
|
field=jsonfield.fields.JSONField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
verbose_name="same as format_data, but including frozen results",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
25
judge/migrations/0143_auto_20221229_0153.py
Normal file
25
judge/migrations/0143_auto_20221229_0153.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Generated by Django 3.2.16 on 2022-12-28 18:53
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("judge", "0142_contestparticipation_format_data_final"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="contestparticipation",
|
||||||
|
name="cumtime_final",
|
||||||
|
field=models.PositiveIntegerField(
|
||||||
|
default=0, verbose_name="final cumulative time"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="contestparticipation",
|
||||||
|
name="score_final",
|
||||||
|
field=models.FloatField(default=0, verbose_name="final score"),
|
||||||
|
),
|
||||||
|
]
|
|
@ -650,6 +650,15 @@ class ContestParticipation(models.Model):
|
||||||
format_data = JSONField(
|
format_data = JSONField(
|
||||||
verbose_name=_("contest format specific data"), null=True, blank=True
|
verbose_name=_("contest format specific data"), null=True, blank=True
|
||||||
)
|
)
|
||||||
|
format_data_final = JSONField(
|
||||||
|
verbose_name=_("same as format_data, but including frozen results"),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
score_final = models.FloatField(verbose_name=_("final score"), default=0)
|
||||||
|
cumtime_final = models.PositiveIntegerField(
|
||||||
|
verbose_name=_("final cumulative time"), default=0
|
||||||
|
)
|
||||||
|
|
||||||
def recompute_results(self):
|
def recompute_results(self):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
|
|
|
@ -877,47 +877,72 @@ ContestRankingProfile = namedtuple(
|
||||||
BestSolutionData = namedtuple("BestSolutionData", "code points time state is_pretested")
|
BestSolutionData = namedtuple("BestSolutionData", "code points time state is_pretested")
|
||||||
|
|
||||||
|
|
||||||
def make_contest_ranking_profile(contest, participation, contest_problems):
|
def make_contest_ranking_profile(
|
||||||
|
contest, participation, contest_problems, show_final=False
|
||||||
|
):
|
||||||
|
if not show_final:
|
||||||
|
points = participation.score
|
||||||
|
cumtime = participation.cumtime
|
||||||
|
else:
|
||||||
|
points = participation.score_final
|
||||||
|
cumtime = participation.cumtime_final
|
||||||
|
|
||||||
user = participation.user
|
user = participation.user
|
||||||
return ContestRankingProfile(
|
return ContestRankingProfile(
|
||||||
id=user.id,
|
id=user.id,
|
||||||
user=user.user,
|
user=user.user,
|
||||||
css_class=user.css_class,
|
css_class=user.css_class,
|
||||||
username=user.username,
|
username=user.username,
|
||||||
points=participation.score,
|
points=points,
|
||||||
cumtime=participation.cumtime,
|
cumtime=cumtime,
|
||||||
tiebreaker=participation.tiebreaker,
|
tiebreaker=participation.tiebreaker,
|
||||||
organization=user.organization,
|
organization=user.organization,
|
||||||
participation_rating=participation.rating.rating
|
participation_rating=participation.rating.rating
|
||||||
if hasattr(participation, "rating")
|
if hasattr(participation, "rating")
|
||||||
else None,
|
else None,
|
||||||
problem_cells=[
|
problem_cells=[
|
||||||
contest.format.display_user_problem(participation, contest_problem)
|
contest.format.display_user_problem(
|
||||||
|
participation, contest_problem, show_final
|
||||||
|
)
|
||||||
for contest_problem in contest_problems
|
for contest_problem in contest_problems
|
||||||
],
|
],
|
||||||
result_cell=contest.format.display_participation_result(participation),
|
result_cell=contest.format.display_participation_result(
|
||||||
|
participation, show_final
|
||||||
|
),
|
||||||
participation=participation,
|
participation=participation,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def base_contest_ranking_list(contest, problems, queryset):
|
def base_contest_ranking_list(contest, problems, queryset, show_final=False):
|
||||||
return [
|
return [
|
||||||
make_contest_ranking_profile(contest, participation, problems)
|
make_contest_ranking_profile(contest, participation, problems, show_final)
|
||||||
for participation in queryset.select_related("user__user", "rating").defer(
|
for participation in queryset.select_related("user__user", "rating").defer(
|
||||||
"user__about", "user__organizations__about"
|
"user__about", "user__organizations__about"
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def contest_ranking_list(contest, problems, queryset=None):
|
def contest_ranking_list(contest, problems, queryset=None, show_final=False):
|
||||||
if not queryset:
|
if not queryset:
|
||||||
queryset = contest.users.filter(virtual=0)
|
queryset = contest.users.filter(virtual=0)
|
||||||
|
|
||||||
|
if not show_final:
|
||||||
return base_contest_ranking_list(
|
return base_contest_ranking_list(
|
||||||
contest,
|
contest,
|
||||||
problems,
|
problems,
|
||||||
queryset.prefetch_related("user__organizations")
|
queryset.prefetch_related("user__organizations")
|
||||||
.extra(select={"round_score": "round(score, 6)"})
|
.extra(select={"round_score": "round(score, 6)"})
|
||||||
.order_by("is_disqualified", "-round_score", "cumtime", "tiebreaker"),
|
.order_by("is_disqualified", "-round_score", "cumtime", "tiebreaker"),
|
||||||
|
show_final,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return base_contest_ranking_list(
|
||||||
|
contest,
|
||||||
|
problems,
|
||||||
|
queryset.prefetch_related("user__organizations")
|
||||||
|
.extra(select={"round_score": "round(score_final, 6)"})
|
||||||
|
.order_by("is_disqualified", "-round_score", "cumtime_final", "tiebreaker"),
|
||||||
|
show_final,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -928,6 +953,7 @@ def get_contest_ranking_list(
|
||||||
ranking_list=contest_ranking_list,
|
ranking_list=contest_ranking_list,
|
||||||
show_current_virtual=False,
|
show_current_virtual=False,
|
||||||
ranker=ranker,
|
ranker=ranker,
|
||||||
|
show_final=False,
|
||||||
):
|
):
|
||||||
problems = list(
|
problems = list(
|
||||||
contest.contest_problems.select_related("problem")
|
contest.contest_problems.select_related("problem")
|
||||||
|
@ -936,7 +962,7 @@ def get_contest_ranking_list(
|
||||||
)
|
)
|
||||||
|
|
||||||
users = ranker(
|
users = ranker(
|
||||||
ranking_list(contest, problems),
|
ranking_list(contest, problems, show_final=show_final),
|
||||||
key=attrgetter("points", "cumtime", "tiebreaker"),
|
key=attrgetter("points", "cumtime", "tiebreaker"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -955,12 +981,17 @@ def get_contest_ranking_list(
|
||||||
|
|
||||||
def contest_ranking_ajax(request, contest, participation=None):
|
def contest_ranking_ajax(request, contest, participation=None):
|
||||||
contest, exists = _find_contest(request, contest)
|
contest, exists = _find_contest(request, contest)
|
||||||
|
show_final = bool(request.GET.get("final", False))
|
||||||
if not exists:
|
if not exists:
|
||||||
return HttpResponseBadRequest("Invalid contest", content_type="text/plain")
|
return HttpResponseBadRequest("Invalid contest", content_type="text/plain")
|
||||||
|
|
||||||
if not contest.can_see_full_scoreboard(request.user):
|
if not contest.can_see_full_scoreboard(request.user):
|
||||||
raise Http404()
|
raise Http404()
|
||||||
|
|
||||||
|
if show_final:
|
||||||
|
if not request.user.is_superuser or contest.format_name != "ioi16":
|
||||||
|
raise Http404()
|
||||||
|
|
||||||
queryset = contest.users.filter(virtual__gte=0)
|
queryset = contest.users.filter(virtual__gte=0)
|
||||||
if request.GET.get("friend") == "true" and request.profile:
|
if request.GET.get("friend") == "true" and request.profile:
|
||||||
friends = list(request.profile.get_friends())
|
friends = list(request.profile.get_friends())
|
||||||
|
@ -973,6 +1004,7 @@ def contest_ranking_ajax(request, contest, participation=None):
|
||||||
contest,
|
contest,
|
||||||
participation,
|
participation,
|
||||||
ranking_list=partial(contest_ranking_list, queryset=queryset),
|
ranking_list=partial(contest_ranking_list, queryset=queryset),
|
||||||
|
show_final=show_final,
|
||||||
)
|
)
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
|
@ -1039,6 +1071,18 @@ class ContestRanking(ContestRankingBase):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class ContestFinalRanking(LoginRequiredMixin, ContestRanking):
|
||||||
|
page_type = "final_ranking"
|
||||||
|
|
||||||
|
def get_ranking_list(self):
|
||||||
|
if not self.request.user.is_superuser:
|
||||||
|
raise Http404()
|
||||||
|
if self.object.format_name != "ioi16":
|
||||||
|
raise Http404()
|
||||||
|
|
||||||
|
return get_contest_ranking_list(self.request, self.object, show_final=True)
|
||||||
|
|
||||||
|
|
||||||
class ContestParticipationList(LoginRequiredMixin, ContestRankingBase):
|
class ContestParticipationList(LoginRequiredMixin, ContestRankingBase):
|
||||||
page_type = "participation"
|
page_type = "participation"
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,6 +24,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if request.user.is_superuser and can_use_resolver %}
|
{% if request.user.is_superuser and can_use_resolver %}
|
||||||
{{ make_tab_item('resolver', 'fa fa-check', url('resolver', contest.key), _('Resolver')) }}
|
{{ make_tab_item('resolver', 'fa fa-check', url('resolver', contest.key), _('Resolver')) }}
|
||||||
|
{{ make_tab_item('final_ranking', 'fa fa-bar-chart', url('contest_final_ranking', contest.key), _('Final rankings')) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if can_edit %}
|
{% if can_edit %}
|
||||||
{% if perms.judge.moss_contest and has_moss_api_key %}
|
{% if perms.judge.moss_contest and has_moss_api_key %}
|
||||||
|
|
|
@ -118,8 +118,12 @@
|
||||||
var friend = $('#show-friends-checkbox').is(':checked');
|
var friend = $('#show-friends-checkbox').is(':checked');
|
||||||
var virtual = $('#show-virtual-checkbox').is(':checked');
|
var virtual = $('#show-virtual-checkbox').is(':checked');
|
||||||
$('#loading-gif').show();
|
$('#loading-gif').show();
|
||||||
|
var url = `{{url('contest_ranking_ajax', contest.key)}}?friend=${friend}&virtual=${virtual}`;
|
||||||
|
{% if page_type == 'final_ranking' %}
|
||||||
|
url += "&final=true";
|
||||||
|
{% endif %}
|
||||||
$.get({
|
$.get({
|
||||||
url: `{{url('contest_ranking_ajax', contest.key)}}?friend=${friend}&virtual=${virtual}`,
|
url: url,
|
||||||
success: function(HTML) {
|
success: function(HTML) {
|
||||||
$('#users-table').html(HTML);
|
$('#users-table').html(HTML);
|
||||||
highlightFirstSolve();
|
highlightFirstSolve();
|
||||||
|
@ -199,7 +203,8 @@
|
||||||
$('#show-virtual-label').hide();
|
$('#show-virtual-label').hide();
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if request.in_contest %}
|
{% if request.in_contest %}
|
||||||
setInterval(update_ranking, 60 * 1000);
|
clearInterval(window.rankingInterval);
|
||||||
|
window.rankingInterval = setInterval(update_ranking, 60 * 1000);
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
});
|
});
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if page_type == 'ranking' %}
|
{% if page_type == 'ranking' or page_type == 'final_ranking' %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$.fn.ignore = function(sel) {
|
$.fn.ignore = function(sel) {
|
||||||
return this.clone().find(sel || '>*').remove().end();
|
return this.clone().find(sel || '>*').remove().end();
|
||||||
|
|
Loading…
Reference in a new issue