From 24f1a0372e0a6f5b3eff544ae95f632414117a07 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Sun, 21 Sep 2025 19:11:18 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E9=A2=98=E7=9B=AE=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E7=9A=84=E6=8E=92=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0002_userprofile_class_name.py | 18 ++++++++ ..._userprofile_class_name_user_class_name.py | 22 ++++++++++ account/models.py | 1 + account/serializers.py | 5 ++- account/urls/oj.py | 2 + account/views/oj.py | 42 +++++++++++++++++++ oj/dev_settings.py | 12 ++++-- oj/settings.py | 3 +- 8 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 account/migrations/0002_userprofile_class_name.py create mode 100644 account/migrations/0003_remove_userprofile_class_name_user_class_name.py diff --git a/account/migrations/0002_userprofile_class_name.py b/account/migrations/0002_userprofile_class_name.py new file mode 100644 index 0000000..bb56a27 --- /dev/null +++ b/account/migrations/0002_userprofile_class_name.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.3 on 2025-09-19 06:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='userprofile', + name='class_name', + field=models.TextField(null=True), + ), + ] diff --git a/account/migrations/0003_remove_userprofile_class_name_user_class_name.py b/account/migrations/0003_remove_userprofile_class_name_user_class_name.py new file mode 100644 index 0000000..40ab508 --- /dev/null +++ b/account/migrations/0003_remove_userprofile_class_name_user_class_name.py @@ -0,0 +1,22 @@ +# Generated by Django 5.2.3 on 2025-09-19 06:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0002_userprofile_class_name'), + ] + + operations = [ + migrations.RemoveField( + model_name='userprofile', + name='class_name', + ), + migrations.AddField( + model_name='user', + name='class_name', + field=models.TextField(null=True), + ), + ] diff --git a/account/models.py b/account/models.py index 9e765d1..43bcf15 100644 --- a/account/models.py +++ b/account/models.py @@ -25,6 +25,7 @@ class UserManager(models.Manager): class User(AbstractBaseUser): username = models.TextField(unique=True) + class_name = models.TextField(null=True) email = models.TextField(null=True) create_time = models.DateTimeField(auto_now_add=True, null=True) # One of UserType diff --git a/account/serializers.py b/account/serializers.py index 2ba68eb..7ccaba7 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -67,6 +67,7 @@ class UserAdminSerializer(serializers.ModelSerializer): "open_api", "is_disabled", "raw_password", + "class_name", ] def get_real_name(self, obj): @@ -93,6 +94,7 @@ class UserSerializer(serializers.ModelSerializer): "two_factor_auth", "open_api", "is_disabled", + "class_name", ] @@ -129,7 +131,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 EditUserProfileSerializer(serializers.Serializer): real_name = serializers.CharField(max_length=32, allow_null=True, required=False) @@ -141,7 +143,6 @@ class EditUserProfileSerializer(serializers.Serializer): major = serializers.CharField(max_length=64, allow_blank=True, required=False) language = serializers.CharField(max_length=32, allow_blank=True, required=False) - class ApplyResetPasswordSerializer(serializers.Serializer): email = serializers.EmailField() captcha = serializers.CharField() diff --git a/account/urls/oj.py b/account/urls/oj.py index eeb5e4d..61d9db2 100644 --- a/account/urls/oj.py +++ b/account/urls/oj.py @@ -15,6 +15,7 @@ from ..views.oj import ( UserProfileAPI, UserRankAPI, UserActivityRankAPI, + UserProblemRankAPI, CheckTFARequiredAPI, SessionManagementAPI, ProfileProblemDisplayIDRefreshAPI, @@ -45,6 +46,7 @@ urlpatterns = [ ), path("user_rank", UserRankAPI.as_view()), path("user_activity_rank", UserActivityRankAPI.as_view()), + path("user_problem_rank", UserProblemRankAPI.as_view()), path("sessions", SessionManagementAPI.as_view()), path( "open_api_appkey", diff --git a/account/views/oj.py b/account/views/oj.py index 8ba6ffd..d1e79b7 100644 --- a/account/views/oj.py +++ b/account/views/oj.py @@ -1,4 +1,5 @@ import os +import re from datetime import timedelta from importlib import import_module @@ -475,6 +476,47 @@ class UserActivityRankAPI(APIView): return self.success(data[:10]) +class UserProblemRankAPI(APIView): + def get(self, request): + problem_id = request.GET.get("problem_id") + user = request.user + 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) + all_ac_users = submissions.values("user_id").distinct() + all_ac_count = len(all_ac_users) + + class_name = user.class_name or "" + class_ac_count = 0 + + if class_name: + users = User.objects.filter(class_name=user.class_name, is_disabled=False).values_list("id", flat=True) + submissions = submissions.filter(user_id__in=list(users)) + class_ac_users = submissions.values("user_id").distinct() + class_ac_count = len(class_ac_users) + + 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 + }) + + 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, + }) + + class ProfileProblemDisplayIDRefreshAPI(APIView): @login_required def get(self, request): diff --git a/oj/dev_settings.py b/oj/dev_settings.py index 6f94409..8ba9601 100644 --- a/oj/dev_settings.py +++ b/oj/dev_settings.py @@ -6,14 +6,18 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) DATABASES = { "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": os.path.join(BASE_DIR, "db.sqlite3"), + "ENGINE": "django.db.backends.postgresql", + "HOST": "10.13.114.114", + "PORT": "5433", + "NAME": "onlinejudge", + "USER": "onlinejudge", + "PASSWORD": "onlinejudge", } } REDIS_CONF = { - "host": get_env("REDIS_HOST", "127.0.0.1"), - "port": get_env("REDIS_PORT", "6380"), + "host": "10.13.114.114", + "port": 6379, } diff --git a/oj/settings.py b/oj/settings.py index 2381d67..48b120b 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -210,8 +210,7 @@ def redis_config(db): } -if production_env: - CACHES = {"default": redis_config(db=1)} +CACHES = {"default": redis_config(db=1)} SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_CACHE_ALIAS = "default"