247 lines
7.5 KiB
Python
247 lines
7.5 KiB
Python
from operator import attrgetter
|
|
|
|
from django.db.models import F, Prefetch
|
|
from django.http import Http404, JsonResponse
|
|
from django.shortcuts import get_object_or_404
|
|
|
|
from dmoj import settings
|
|
from judge.models import (
|
|
Contest,
|
|
ContestParticipation,
|
|
ContestTag,
|
|
Problem,
|
|
Profile,
|
|
Submission,
|
|
)
|
|
|
|
|
|
def sane_time_repr(delta):
|
|
days = delta.days
|
|
hours = delta.seconds / 3600
|
|
minutes = (delta.seconds % 3600) / 60
|
|
return "%02d:%02d:%02d" % (days, hours, minutes)
|
|
|
|
|
|
def api_v1_contest_list(request):
|
|
queryset = Contest.get_visible_contests(request.user).prefetch_related(
|
|
Prefetch("tags", queryset=ContestTag.objects.only("name"), to_attr="tag_list")
|
|
)
|
|
|
|
return JsonResponse(
|
|
{
|
|
c.key: {
|
|
"name": c.name,
|
|
"start_time": c.start_time.isoformat(),
|
|
"end_time": c.end_time.isoformat(),
|
|
"time_limit": c.time_limit and sane_time_repr(c.time_limit),
|
|
"labels": list(map(attrgetter("name"), c.tag_list)),
|
|
}
|
|
for c in queryset
|
|
}
|
|
)
|
|
|
|
|
|
def api_v1_contest_detail(request, contest):
|
|
contest = get_object_or_404(Contest, key=contest)
|
|
|
|
in_contest = contest.is_in_contest(request.user)
|
|
can_see_rankings = contest.can_see_full_scoreboard(request.user)
|
|
problems = list(
|
|
contest.contest_problems.select_related("problem")
|
|
.defer("problem__description")
|
|
.order_by("order")
|
|
)
|
|
participations = (
|
|
contest.users.filter(virtual=0)
|
|
.prefetch_related("user__organizations")
|
|
.annotate(username=F("user__user__username"))
|
|
.order_by("-score", "cumtime")
|
|
if can_see_rankings
|
|
else []
|
|
)
|
|
|
|
can_see_problems = (
|
|
in_contest or contest.ended or contest.is_editable_by(request.user)
|
|
)
|
|
|
|
return JsonResponse(
|
|
{
|
|
"time_limit": contest.time_limit and contest.time_limit.total_seconds(),
|
|
"start_time": contest.start_time.isoformat(),
|
|
"end_time": contest.end_time.isoformat(),
|
|
"tags": list(contest.tags.values_list("name", flat=True)),
|
|
"is_rated": contest.is_rated,
|
|
"rate_all": contest.is_rated and contest.rate_all,
|
|
"has_rating": contest.ratings.exists(),
|
|
"rating_floor": contest.rating_floor,
|
|
"rating_ceiling": contest.rating_ceiling,
|
|
"format": {
|
|
"name": contest.format_name,
|
|
"config": contest.format_config,
|
|
},
|
|
"problems": [
|
|
{
|
|
"points": int(problem.points),
|
|
"partial": problem.partial,
|
|
"name": problem.problem.name,
|
|
"code": problem.problem.code,
|
|
}
|
|
for problem in problems
|
|
]
|
|
if can_see_problems
|
|
else [],
|
|
"rankings": [
|
|
{
|
|
"user": participation.username,
|
|
"points": participation.score,
|
|
"cumtime": participation.cumtime,
|
|
"is_disqualified": participation.is_disqualified,
|
|
"solutions": contest.format.get_problem_breakdown(
|
|
participation, problems
|
|
),
|
|
}
|
|
for participation in participations
|
|
],
|
|
}
|
|
)
|
|
|
|
|
|
def api_v1_problem_list(request):
|
|
queryset = Problem.objects.filter(is_public=True, is_organization_private=False)
|
|
if settings.ENABLE_FTS and "search" in request.GET:
|
|
query = " ".join(request.GET.getlist("search")).strip()
|
|
if query:
|
|
queryset = queryset.search(query)
|
|
queryset = queryset.values_list(
|
|
"code", "points", "partial", "name", "group__full_name"
|
|
)
|
|
|
|
return JsonResponse(
|
|
{
|
|
code: {
|
|
"points": points,
|
|
"partial": partial,
|
|
"name": name,
|
|
"group": group,
|
|
}
|
|
for code, points, partial, name, group in queryset
|
|
}
|
|
)
|
|
|
|
|
|
def api_v1_problem_info(request, problem):
|
|
p = get_object_or_404(Problem, code=problem)
|
|
if not p.is_accessible_by(request.user):
|
|
raise Http404()
|
|
|
|
return JsonResponse(
|
|
{
|
|
"name": p.name,
|
|
"authors": list(p.authors.values_list("user__username", flat=True)),
|
|
"types": list(p.types.values_list("full_name", flat=True)),
|
|
"group": p.group.full_name,
|
|
"time_limit": p.time_limit,
|
|
"memory_limit": p.memory_limit,
|
|
"points": p.points,
|
|
"partial": p.partial,
|
|
"languages": list(p.allowed_languages.values_list("key", flat=True)),
|
|
}
|
|
)
|
|
|
|
|
|
def api_v1_user_list(request):
|
|
queryset = Profile.objects.filter(is_unlisted=False).values_list(
|
|
"user__username", "points", "performance_points", "display_rank"
|
|
)
|
|
return JsonResponse(
|
|
{
|
|
username: {
|
|
"points": points,
|
|
"performance_points": performance_points,
|
|
"rank": rank,
|
|
}
|
|
for username, points, performance_points, rank in queryset
|
|
}
|
|
)
|
|
|
|
|
|
def api_v1_user_info(request, user):
|
|
profile = get_object_or_404(Profile, user__username=user)
|
|
submissions = list(
|
|
Submission.objects.filter(
|
|
case_points=F("case_total"),
|
|
user=profile,
|
|
problem__is_public=True,
|
|
problem__is_organization_private=False,
|
|
)
|
|
.values("problem")
|
|
.distinct()
|
|
.values_list("problem__code", flat=True)
|
|
)
|
|
resp = {
|
|
"points": profile.points,
|
|
"performance_points": profile.performance_points,
|
|
"rank": profile.display_rank,
|
|
"solved_problems": submissions,
|
|
"organizations": list(profile.organizations.values_list("id", flat=True)),
|
|
}
|
|
|
|
last_rating = profile.ratings.last()
|
|
|
|
contest_history = {}
|
|
participations = ContestParticipation.objects.filter(
|
|
user=profile,
|
|
virtual=0,
|
|
contest__is_visible=True,
|
|
contest__is_private=False,
|
|
contest__is_organization_private=False,
|
|
)
|
|
for contest_key, rating, mean, performance in participations.values_list(
|
|
"contest__key",
|
|
"rating__rating",
|
|
"rating__mean",
|
|
"rating__performance",
|
|
):
|
|
contest_history[contest_key] = {
|
|
"rating": rating,
|
|
"raw_rating": mean,
|
|
"performance": performance,
|
|
}
|
|
|
|
resp["contests"] = {
|
|
"current_rating": last_rating.rating if last_rating else None,
|
|
"history": contest_history,
|
|
}
|
|
|
|
return JsonResponse(resp)
|
|
|
|
|
|
def api_v1_user_submissions(request, user):
|
|
profile = get_object_or_404(Profile, user__username=user)
|
|
subs = Submission.objects.filter(
|
|
user=profile, problem__is_public=True, problem__is_organization_private=False
|
|
)
|
|
|
|
return JsonResponse(
|
|
{
|
|
sub["id"]: {
|
|
"problem": sub["problem__code"],
|
|
"time": sub["time"],
|
|
"memory": sub["memory"],
|
|
"points": sub["points"],
|
|
"language": sub["language__key"],
|
|
"status": sub["status"],
|
|
"result": sub["result"],
|
|
}
|
|
for sub in subs.values(
|
|
"id",
|
|
"problem__code",
|
|
"time",
|
|
"memory",
|
|
"points",
|
|
"language__key",
|
|
"status",
|
|
"result",
|
|
)
|
|
}
|
|
)
|