Add GP Ranking

This commit is contained in:
anhkha2003 2023-10-06 03:09:34 -05:00
parent c02538bc57
commit 5d95b92f66
9 changed files with 223 additions and 1 deletions

View file

@ -3,7 +3,12 @@ from django.contrib.admin.models import LogEntry
from django.contrib.auth.models import User
from judge.admin.comments import CommentAdmin
from judge.admin.contest import ContestAdmin, ContestParticipationAdmin, ContestTagAdmin
from judge.admin.contest import (
ContestAdmin,
ContestParticipationAdmin,
ContestTagAdmin,
ContestsSummaryAdmin,
)
from judge.admin.interface import (
BlogPostAdmin,
LicenseAdmin,
@ -41,6 +46,7 @@ from judge.models import (
Ticket,
VolunteerProblemVote,
Course,
ContestsSummary,
)
@ -69,3 +75,4 @@ admin.site.register(VolunteerProblemVote, VolunteerProblemVoteAdmin)
admin.site.register(Course)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
admin.site.register(ContestsSummary, ContestsSummaryAdmin)

View file

@ -502,3 +502,19 @@ class ContestParticipationAdmin(admin.ModelAdmin):
show_virtual.short_description = _("virtual")
show_virtual.admin_order_field = "virtual"
class ContestsSummaryForm(ModelForm):
class Meta:
widgets = {
"contests": AdminHeavySelect2MultipleWidget(
data_view="contest_select2", attrs={"style": "width: 100%"}
),
}
class ContestsSummaryAdmin(admin.ModelAdmin):
fields = ("key", "contests", "scores")
list_display = ("key",)
search_fields = ("key", "contests__key")
form = ContestsSummaryForm

View file

@ -1,6 +1,7 @@
from inspect import signature
from django.core.cache import cache
from django.db.models.query import QuerySet
from django.core.handlers.wsgi import WSGIRequest
import hashlib
@ -18,10 +19,14 @@ def cache_wrapper(prefix, timeout=None):
return str(arg)[:MAX_NUM_CHAR]
return str(arg)
def filter_args(args_list):
return [x for x in args_list if not isinstance(x, WSGIRequest)]
def get_key(func, *args, **kwargs):
args_list = list(args)
signature_args = list(signature(func).parameters.keys())
args_list += [kwargs.get(k) for k in signature_args[len(args) :]]
args_list = filter_args(args_list)
args_list = [arg_to_str(i) for i in args_list]
key = prefix + ":" + ":".join(args_list)
key = key.replace(" ", "_")

View file

@ -0,0 +1,30 @@
# Generated by Django 3.2.21 on 2023-10-02 03:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("judge", "0169_public_scoreboard"),
]
operations = [
migrations.CreateModel(
name="ContestsSummary",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("scores", models.JSONField(blank=True, null=True)),
("key", models.CharField(max_length=20, unique=True)),
("contests", models.ManyToManyField(to="judge.Contest")),
],
),
]

View file

@ -16,6 +16,7 @@ from judge.models.contest import (
ContestTag,
Rating,
ContestProblemClarification,
ContestsSummary,
)
from judge.models.interface import BlogPost, MiscConfig, NavigationBar, validate_regex
from judge.models.message import PrivateMessage, PrivateMessageThread

View file

@ -33,6 +33,7 @@ __all__ = [
"ContestSubmission",
"Rating",
"ContestProblemClarification",
"ContestsSummary",
]
@ -900,3 +901,24 @@ class ContestProblemClarification(models.Model):
date = models.DateTimeField(
verbose_name=_("clarification timestamp"), auto_now_add=True
)
class ContestsSummary(models.Model):
contests = models.ManyToManyField(
Contest,
)
scores = models.JSONField(
null=True,
blank=True,
)
key = models.CharField(
max_length=20,
unique=True,
)
class Meta:
verbose_name = _("contests summary")
verbose_name_plural = _("contests summaries")
def __str__(self):
return self.key

View file

@ -27,6 +27,8 @@ from django.db.models import (
Value,
When,
)
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.db.models.expressions import CombinedExpression
from django.http import (
Http404,
@ -67,6 +69,7 @@ from judge.models import (
Profile,
Submission,
ContestProblemClarification,
ContestsSummary,
)
from judge.tasks import run_moss
from judge.utils.celery import redirect_to_task_status
@ -1380,3 +1383,65 @@ def update_contest_mode(request):
old_mode = request.session.get("contest_mode", True)
request.session["contest_mode"] = not old_mode
return HttpResponse()
ContestsSummaryData = namedtuple(
"ContestsSummaryData",
"user points point_contests css_class",
)
def contests_summary_view(request, key):
try:
contests_summary = ContestsSummary.objects.get(key=key)
except:
raise Http404()
cache_key = "csv:" + key
context = cache.get(cache_key)
if context:
return render(request, "contest/contests_summary.html", context)
scores_system = contests_summary.scores
contests = contests_summary.contests.all()
total_points = defaultdict(int)
result_per_contest = defaultdict(lambda: [(0, 0)] * len(contests))
user_css_class = {}
for i in range(len(contests)):
contest = contests[i]
users, problems = get_contest_ranking_list(request, contest)
for rank, user in users:
curr_score = 0
if rank - 1 < len(scores_system):
curr_score = scores_system[rank - 1]
total_points[user.user] += curr_score
result_per_contest[user.user][i] = (curr_score, rank)
user_css_class[user.user] = user.css_class
sorted_total_points = [
ContestsSummaryData(
user=user,
points=total_points[user],
point_contests=result_per_contest[user],
css_class=user_css_class[user],
)
for user in total_points
]
sorted_total_points.sort(key=lambda x: x.points, reverse=True)
total_rank = ranker(sorted_total_points)
context = {
"total_rank": list(total_rank),
"title": _("Contests Summary"),
"contests": contests,
}
cache.set(cache_key, context)
return render(request, "contest/contests_summary.html", context)
@receiver([post_save, post_delete], sender=ContestsSummary)
def clear_cache(sender, instance, **kwargs):
cache.delete("csv:" + instance.key)