diff --git a/contest/serializers.py b/contest/serializers.py index 9e42578..356cdda 100644 --- a/contest/serializers.py +++ b/contest/serializers.py @@ -79,11 +79,11 @@ class ACMContestRankSerializer(serializers.ModelSerializer): fields = "__all__" def __init__(self, *args, **kwargs): - self.is_admin_role = kwargs.pop("is_admin_role", False) + self.is_contest_admin = kwargs.pop("is_contest_admin", False) super().__init__(*args, **kwargs) def get_user(self, obj): - return UsernameSerializer(obj.user, is_admin_role=self.is_admin_role).data + return UsernameSerializer(obj.user, need_real_name=self.is_contest_admin).data class OIContestRankSerializer(serializers.ModelSerializer): @@ -94,8 +94,15 @@ class OIContestRankSerializer(serializers.ModelSerializer): fields = "__all__" def __init__(self, *args, **kwargs): - self.is_admin_role = kwargs.pop("is_admin_role", False) + self.is_contest_admin = kwargs.pop("is_contest_admin", False) super().__init__(*args, **kwargs) def get_user(self, obj): - return UsernameSerializer(obj.user, is_admin_role=self.is_admin_role).data + return UsernameSerializer(obj.user, need_real_name=self.is_contest_admin).data + + +class ACMContesHelperSerializer(serializers.Serializer): + contest_id = serializers.IntegerField() + problem_id = serializers.CharField() + rank_id = serializers.IntegerField() + checked = serializers.BooleanField() diff --git a/contest/urls/admin.py b/contest/urls/admin.py index 5a8bc75..1032952 100644 --- a/contest/urls/admin.py +++ b/contest/urls/admin.py @@ -1,8 +1,9 @@ from django.conf.urls import url -from ..views.admin import ContestAnnouncementAPI, ContestAPI +from ..views.admin import ContestAnnouncementAPI, ContestAPI, ACMContestHelper urlpatterns = [ url(r"^contest/?$", ContestAPI.as_view(), name="contest_admin_api"), - url(r"^contest/announcement/?$", ContestAnnouncementAPI.as_view(), name="contest_announcement_admin_api") + url(r"^contest/announcement/?$", ContestAnnouncementAPI.as_view(), name="contest_announcement_admin_api"), + url(r"^contest/acm_helper/?$", ACMContestHelper.as_view(), name="acm_contest_helper"), ] diff --git a/contest/views/admin.py b/contest/views/admin.py index d5ce347..ebc0c7a 100644 --- a/contest/views/admin.py +++ b/contest/views/admin.py @@ -2,13 +2,15 @@ from ipaddress import ip_network import dateutil.parser from utils.api import APIView, validate_serializer +from utils.cache import cache +from utils.constants import CacheKey -from ..models import Contest, ContestAnnouncement +from account.decorators import check_contest_permission +from ..models import Contest, ContestAnnouncement, ACMContestRank from ..serializers import (ContestAnnouncementSerializer, ContestAdminSerializer, - CreateConetestSeriaizer, - CreateContestAnnouncementSerializer, - EditConetestSeriaizer, - EditContestAnnouncementSerializer) + CreateConetestSeriaizer, CreateContestAnnouncementSerializer, + EditConetestSeriaizer, EditContestAnnouncementSerializer, + ACMContesHelperSerializer) class ContestAPI(APIView): @@ -50,6 +52,9 @@ class ContestAPI(APIView): ip_network(ip_range, strict=False) except ValueError as e: return self.error(f"{ip_range} is not a valid cidr network") + if not contest.real_time_rank and data.get("real_time_rank"): + cache_key = f"{CacheKey.contest_rank_cache}:{contest.id}" + cache.delete(cache_key) for k, v in data.items(): setattr(contest, k, v) @@ -150,3 +155,41 @@ class ContestAnnouncementAPI(APIView): if keyword: contest_announcements = contest_announcements.filter(title__contains=keyword) return self.success(ContestAnnouncementSerializer(contest_announcements, many=True).data) + + +class ACMContestHelper(APIView): + @check_contest_permission(check_type="ranks") + def get(self, request): + ranks = ACMContestRank.objects.filter(contest=self.contest, accepted_number__gt=0) \ + .values("id", "user__username", "user__userprofile__real_name", "submission_info") + results = [] + for rank in ranks: + for problem_id, info in rank["submission_info"].items(): + if info["is_ac"]: + results.append({ + "id": rank["id"], + "username": rank["user__username"], + "real_name": rank["user__userprofile__real_name"], + "problem_id": problem_id, + "ac_info": info, + "checked": info.get("checked", False) + }) + results.sort(key=lambda x: -x["ac_info"]["ac_time"]) + return self.success(results) + + @validate_serializer(ACMContesHelperSerializer) + @check_contest_permission(check_type="ranks") + def put(self, request): + data = request.data + if not request.user.is_contest_admin(self.contest): + return self.error("You are not contest admin") + try: + rank = ACMContestRank.objects.get(pk=data["rank_id"]) + except ACMContestRank.DoesNotExist: + return self.error("Rank id does not exist") + problem_rank_status = rank.submission_info.get(data["problem_id"]) + if not problem_rank_status: + return self.error("Problem id does not exist") + problem_rank_status["checked"] = data["checked"] + rank.save(update_fields=("submission_info",)) + return self.success() diff --git a/deploy/health_check.py b/deploy/health_check.py index a12e615..f5065a2 100644 --- a/deploy/health_check.py +++ b/deploy/health_check.py @@ -2,7 +2,7 @@ import xmlrpclib if __name__ == "__main__": try: - server = xmlrpclib.Server('http://localhost:9005/RPC2') + server = xmlrpclib.Server("http://localhost:9005/RPC2") info = server.supervisor.getAllProcessInfo() error_states = list(filter(lambda x: x["state"] != 20, info)) exit(len(error_states)) diff --git a/oj/dev_settings.py b/oj/dev_settings.py index 5c75a0b..49d3f73 100644 --- a/oj/dev_settings.py +++ b/oj/dev_settings.py @@ -7,7 +7,7 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'HOST': '127.0.0.1', - 'PORT': 5433, + 'PORT': 5432, 'NAME': "onlinejudge", 'USER': "onlinejudge", 'PASSWORD': 'onlinejudge'