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')})