From a6d76a64c42f0186b4724ecff9cebe765983bc70 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Thu, 25 Sep 2025 18:41:23 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=94=A8=E6=88=B7=E6=9D=83?= =?UTF-8?q?=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- account/models.py | 3 ++ account/serializers.py | 3 +- account/views/admin.py | 8 ++--- account/views/oj.py | 71 ++++++++++++++++++++++++------------------ contest/views/admin.py | 40 +++++++++++++----------- submission/models.py | 3 +- submission/views/oj.py | 2 +- 7 files changed, 72 insertions(+), 58 deletions(-) diff --git a/account/models.py b/account/models.py index 43bcf15..7a2c8eb 100644 --- a/account/models.py +++ b/account/models.py @@ -51,6 +51,9 @@ class User(AbstractBaseUser): objects = UserManager() + def is_regular_user(self): + return self.admin_type == AdminType.REGULAR_USER + def is_admin(self): return self.admin_type == AdminType.ADMIN diff --git a/account/serializers.py b/account/serializers.py index 7ccaba7..5b2bf7f 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -1,4 +1,5 @@ from django import forms +from httpx import request from utils.api import serializers, UsernameSerializer @@ -131,7 +132,7 @@ class EditUserSerializer(serializers.Serializer): open_api = serializers.BooleanField() two_factor_auth = serializers.BooleanField() is_disabled = serializers.BooleanField() - class_name = serializers.CharField(max_length=32, allow_blank=True, required=False) + class_name = serializers.CharField(required=False, allow_null=True) class EditUserProfileSerializer(serializers.Serializer): real_name = serializers.CharField(max_length=32, allow_null=True, required=False) diff --git a/account/views/admin.py b/account/views/admin.py index f11243a..70407d2 100644 --- a/account/views/admin.py +++ b/account/views/admin.py @@ -106,7 +106,7 @@ class UserAdminAPI(APIView): user.is_disabled = data["is_disabled"] if data["admin_type"] == AdminType.ADMIN: - user.problem_permission = data["problem_permission"] + user.problem_permission = data["problem_permission"] or ProblemPermission.OWN elif data["admin_type"] == AdminType.SUPER_ADMIN: user.problem_permission = ProblemPermission.ALL else: @@ -156,10 +156,10 @@ class UserAdminAPI(APIView): user = User.objects.all().order_by("-create_time") - is_admin = request.GET.get("admin", "0") + type = request.GET.get("type", "") - if is_admin == "1": - user = user.exclude(admin_type=AdminType.REGULAR_USER) + if type: + user = user.filter(admin_type=type) keyword = request.GET.get("keyword", None) if keyword: diff --git a/account/views/oj.py b/account/views/oj.py index e2b0618..6907a73 100644 --- a/account/views/oj.py +++ b/account/views/oj.py @@ -434,8 +434,9 @@ class UserRankAPI(APIView): n = 0 if rule_type not in ContestRuleType.choices(): rule_type = ContestRuleType.ACM + profiles = UserProfile.objects.filter( - user__admin_type=AdminType.REGULAR_USER, + user__admin_type__in=[AdminType.REGULAR_USER, AdminType.ADMIN], user__is_disabled=False, user__username__icontains=username, ).select_related("user") @@ -456,23 +457,19 @@ class UserActivityRankAPI(APIView): if not start: return self.error("start time is required") hidden_names = User.objects.filter( - Q(admin_type=AdminType.SUPER_ADMIN) - | Q(admin_type=AdminType.ADMIN) - | Q(is_disabled=True) + Q(admin_type=AdminType.SUPER_ADMIN) | Q(is_disabled=True) ).values_list("username", flat=True) submissions = Submission.objects.filter( - contest_id__isnull=True, create_time__gte=start, result=JudgeStatus.ACCEPTED - ) - counts = ( + contest_id__isnull=True, + create_time__gte=start, + result=JudgeStatus.ACCEPTED, + ).exclude(username__in=hidden_names) + data = list( submissions.values("username") .annotate(count=Count("problem_id", distinct=True)) - .order_by("-count")[: 10 + len(hidden_names)] + .order_by("-count")[:10] ) - data = [] - for count in counts: - if count["username"] not in hidden_names: - data.append(count) - return self.success(data[:10]) + return self.success(data) class UserProblemRankAPI(APIView): @@ -482,8 +479,12 @@ class UserProblemRankAPI(APIView): if not user.is_authenticated: return self.error("User is not authenticated") - problem = Problem.objects.get(_id=problem_id, contest_id__isnull=True, visible=True) - submissions = Submission.objects.filter(problem=problem, result=JudgeStatus.ACCEPTED) + problem = Problem.objects.get( + _id=problem_id, contest_id__isnull=True, visible=True + ) + submissions = Submission.objects.filter( + problem=problem, result=JudgeStatus.ACCEPTED + ) all_ac_count = submissions.values("user_id").distinct().count() @@ -491,29 +492,37 @@ class UserProblemRankAPI(APIView): class_ac_count = 0 if class_name: - users = User.objects.filter(class_name=user.class_name, is_disabled=False).values_list("id", flat=True) + users = User.objects.filter( + class_name=user.class_name, is_disabled=False + ).values_list("id", flat=True) user_ids = list(users) submissions = submissions.filter(user_id__in=user_ids) class_ac_count = submissions.values("user_id").distinct().count() - + my_submissions = submissions.filter(user_id=user.id) - + if len(my_submissions) == 0: - return self.success({ - "class_name": class_name, - "rank": -1, - "class_ac_count": class_ac_count, - "all_ac_count": all_ac_count - }) + return self.success( + { + "class_name": class_name, + "rank": -1, + "class_ac_count": class_ac_count, + "all_ac_count": all_ac_count, + } + ) my_first_submission = my_submissions.order_by("create_time").first() - rank = submissions.filter(create_time__lte=my_first_submission.create_time).count() - return self.success({ - "class_name": class_name, - "rank": rank, - "class_ac_count": class_ac_count, - "all_ac_count": all_ac_count, - }) + rank = submissions.filter( + create_time__lte=my_first_submission.create_time + ).count() + return self.success( + { + "class_name": class_name, + "rank": rank, + "class_ac_count": class_ac_count, + "all_ac_count": all_ac_count, + } + ) class ProfileProblemDisplayIDRefreshAPI(APIView): diff --git a/contest/views/admin.py b/contest/views/admin.py index 66addb1..b94acda 100644 --- a/contest/views/admin.py +++ b/contest/views/admin.py @@ -6,7 +6,7 @@ from ipaddress import ip_network import dateutil.parser from django.http import FileResponse -from account.decorators import check_contest_permission, ensure_created_by +from account.decorators import super_admin_required from account.models import User from submission.models import Submission, JudgeStatus from utils.api import APIView, validate_serializer @@ -23,6 +23,7 @@ from ..serializers import (ContestAnnouncementSerializer, ContestAdminSerializer class ContestAPI(APIView): @validate_serializer(CreateConetestSeriaizer) + @super_admin_required def post(self, request): data = request.data data["start_time"] = dateutil.parser.parse(data["start_time"]) @@ -41,11 +42,11 @@ class ContestAPI(APIView): return self.success(ContestAdminSerializer(contest).data) @validate_serializer(EditConetestSeriaizer) + @super_admin_required def put(self, request): data = request.data try: contest = Contest.objects.get(id=data.pop("id")) - ensure_created_by(contest, request.user) except Contest.DoesNotExist: return self.error("Contest does not exist") data["start_time"] = dateutil.parser.parse(data["start_time"]) @@ -68,19 +69,17 @@ class ContestAPI(APIView): contest.save() return self.success(ContestAdminSerializer(contest).data) + @super_admin_required def get(self, request): contest_id = request.GET.get("id") if contest_id: try: contest = Contest.objects.get(id=contest_id) - ensure_created_by(contest, request.user) return self.success(ContestAdminSerializer(contest).data) except Contest.DoesNotExist: return self.error("Contest does not exist") contests = Contest.objects.all().order_by("-create_time") - if request.user.is_admin(): - contests = contests.filter(created_by=request.user) keyword = request.GET.get("keyword") if keyword: @@ -90,6 +89,7 @@ class ContestAPI(APIView): class ContestAnnouncementAPI(APIView): @validate_serializer(CreateContestAnnouncementSerializer) + @super_admin_required def post(self, request): """ Create one contest_announcement. @@ -97,7 +97,6 @@ class ContestAnnouncementAPI(APIView): data = request.data try: contest = Contest.objects.get(id=data.pop("contest_id")) - ensure_created_by(contest, request.user) data["contest"] = contest data["created_by"] = request.user except Contest.DoesNotExist: @@ -106,6 +105,7 @@ class ContestAnnouncementAPI(APIView): return self.success(ContestAnnouncementSerializer(announcement).data) @validate_serializer(EditContestAnnouncementSerializer) + @super_admin_required def put(self, request): """ update contest_announcement @@ -113,7 +113,6 @@ class ContestAnnouncementAPI(APIView): data = request.data try: contest_announcement = ContestAnnouncement.objects.get(id=data.pop("id")) - ensure_created_by(contest_announcement, request.user) except ContestAnnouncement.DoesNotExist: return self.error("Contest announcement does not exist") for k, v in data.items(): @@ -121,19 +120,17 @@ class ContestAnnouncementAPI(APIView): contest_announcement.save() return self.success() + @super_admin_required def delete(self, request): """ Delete one contest_announcement. """ contest_announcement_id = request.GET.get("id") if contest_announcement_id: - if request.user.is_admin(): - ContestAnnouncement.objects.filter(id=contest_announcement_id, - contest__created_by=request.user).delete() - else: - ContestAnnouncement.objects.filter(id=contest_announcement_id).delete() + ContestAnnouncement.objects.filter(id=contest_announcement_id).delete() return self.success() + @super_admin_required def get(self, request): """ Get one contest_announcement or contest_announcement list. @@ -142,7 +139,6 @@ class ContestAnnouncementAPI(APIView): if contest_announcement_id: try: contest_announcement = ContestAnnouncement.objects.get(id=contest_announcement_id) - ensure_created_by(contest_announcement, request.user) return self.success(ContestAnnouncementSerializer(contest_announcement).data) except ContestAnnouncement.DoesNotExist: return self.error("Contest announcement does not exist") @@ -151,8 +147,6 @@ class ContestAnnouncementAPI(APIView): if not contest_id: return self.error("Parameter error") contest_announcements = ContestAnnouncement.objects.filter(contest_id=contest_id) - if request.user.is_admin(): - contest_announcements = contest_announcements.filter(created_by=request.user) keyword = request.GET.get("keyword") if keyword: contest_announcements = contest_announcements.filter(title__contains=keyword) @@ -160,9 +154,17 @@ class ContestAnnouncementAPI(APIView): class ACMContestHelper(APIView): - @check_contest_permission(check_type="ranks") + @super_admin_required def get(self, request): - ranks = ACMContestRank.objects.filter(contest=self.contest, accepted_number__gt=0) \ + contest_id = request.GET.get("contest_id") + if not contest_id: + return self.error("Parameter error, contest_id is required") + try: + contest = Contest.objects.get(id=contest_id, visible=True) + except Contest.DoesNotExist: + return self.error("Contest does not exist") + + ranks = ACMContestRank.objects.filter(contest=contest, accepted_number__gt=0) \ .values("id", "user__username", "user__userprofile__real_name", "submission_info") results = [] for rank in ranks: @@ -179,7 +181,7 @@ class ACMContestHelper(APIView): results.sort(key=lambda x: -x["ac_info"]["ac_time"]) return self.success(results) - @check_contest_permission(check_type="ranks") + @super_admin_required @validate_serializer(ACMContesHelperSerializer) def put(self, request): data = request.data @@ -222,13 +224,13 @@ class DownloadContestSubmissions(APIView): user_ac_map[problem_id] = True return path + @super_admin_required def get(self, request): contest_id = request.GET.get("contest_id") if not contest_id: return self.error("Parameter error") try: contest = Contest.objects.get(id=contest_id) - ensure_created_by(contest, request.user) except Contest.DoesNotExist: return self.error("Contest does not exist") diff --git a/submission/models.py b/submission/models.py index c3ae887..7d7a6cb 100644 --- a/submission/models.py +++ b/submission/models.py @@ -43,8 +43,7 @@ class Submission(models.Model): def check_user_permission(self, user, check_share=True): if ( self.user_id == user.id - or user.is_super_admin() - or user.can_mgmt_all_problem() + or not user.is_regular_user() or self.problem.created_by_id == user.id ): return True diff --git a/submission/views/oj.py b/submission/views/oj.py index 9068204..f657322 100644 --- a/submission/views/oj.py +++ b/submission/views/oj.py @@ -176,7 +176,7 @@ class SubmissionListAPI(APIView): if ( not SysOptions.submission_list_show_all - and not request.user.is_super_admin() + and request.user.is_regular_user() ): return self.success({"results": [], "total": 0})