## 撤回:增删题单题目本来就会重算进度,我诊断错了
上一个 commit 我给 ProblemSetProblemAdminAPI 的 post/delete 加了显式的
sync_all_progress_for_problemset,理由是"增删题目不重算进度"。**那是错的。**
problemset/signals.py 里有 post_save / post_delete 信号接收器,
在 ProblemSetProblem 变化时同步进度**并重算奖章**,且 apps.py 的 ready()
确实导入了 signals。我的显式调用只是让同一件事做两遍。
更该记住的是**为什么当时没发现**:那一版测试只看"进度有没有更新",
而信号和我的调用都会让它更新 —— 分不出是谁干的,所以照样是绿的。
这次的测试改成先撤掉调用再验,并直接断言信号已注册在 post_save/post_delete 上,
这样才真的有区分力。6/6 通过。
同一批修复里的另外 5 条经复核都成立,保留。特别是「移除用户留下孤儿奖章」——
signals.py 里**没有**针对 ProblemSetProgress 的 post_delete,那条必须自己清。
## 删无引用序列化器(-78 行)
全仓 106 个序列化器,11 个无任何引用:
account: FileUploadForm, GenerateUserSerializer, SSOSerializer,
UserChangeEmailSerializer, UserChangePasswordSerializer,
UsernameOrEmailCheckSerializer
contest: CreateContestAnnouncementSerializer, EditContestAnnouncementSerializer
problem: CreateProblemCodeTemplateSerializer
flowchart: FlowchartSubmissionMergedSerializer, FlowchartSubmissionSummarySerializer
前 8 个是上一个 commit 删掉的视图留下的(FileUploadForm 正是
SimditorFileUploadAPIView 用的),后 3 个是原本就死的。
检测器同样做了自检:拿 3 个明确在用的序列化器反测,没有误判。
另外确认这 11 个都没有字符串形式的动态引用。
`ruff check .` 全绿。行尾未被改动(上一轮踩过这个坑,这次脚本里加了断言)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
120 lines
3.9 KiB
Python
120 lines
3.9 KiB
Python
from django import forms
|
|
|
|
from utils.api import UsernameSerializer, serializers
|
|
|
|
from .models import AdminType, ProblemPermission, User, UserProfile
|
|
|
|
|
|
class UserLoginSerializer(serializers.Serializer):
|
|
username = serializers.CharField()
|
|
password = serializers.CharField()
|
|
|
|
|
|
class UserRegisterSerializer(serializers.Serializer):
|
|
username = serializers.CharField(max_length=32)
|
|
password = serializers.CharField(min_length=6)
|
|
email = serializers.EmailField(max_length=64)
|
|
|
|
|
|
class ImportUserSerializer(serializers.Serializer):
|
|
users = serializers.ListField(child=serializers.ListField(child=serializers.CharField(max_length=64)))
|
|
|
|
|
|
class UserAdminSerializer(serializers.ModelSerializer):
|
|
real_name = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = User
|
|
fields = [
|
|
"id",
|
|
"username",
|
|
"email",
|
|
"admin_type",
|
|
"problem_permission",
|
|
"real_name",
|
|
"create_time",
|
|
"last_login",
|
|
"open_api",
|
|
"is_disabled",
|
|
"raw_password",
|
|
"class_name",
|
|
]
|
|
|
|
def get_real_name(self, obj):
|
|
return obj.userprofile.real_name
|
|
|
|
def to_representation(self, instance):
|
|
data = super().to_representation(instance)
|
|
if instance.admin_type != AdminType.REGULAR_USER:
|
|
data.pop("raw_password", None)
|
|
return data
|
|
|
|
|
|
class UserSerializer(serializers.ModelSerializer):
|
|
class Meta:
|
|
model = User
|
|
fields = [
|
|
"id",
|
|
"username",
|
|
"email",
|
|
"admin_type",
|
|
"problem_permission",
|
|
"create_time",
|
|
"last_login",
|
|
"open_api",
|
|
"is_disabled",
|
|
"class_name",
|
|
]
|
|
|
|
|
|
class UserProfileSerializer(serializers.ModelSerializer):
|
|
user = UserSerializer()
|
|
real_name = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = UserProfile
|
|
fields = "__all__"
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.show_real_name = kwargs.pop("show_real_name", False)
|
|
super(UserProfileSerializer, self).__init__(*args, **kwargs)
|
|
|
|
def get_real_name(self, obj):
|
|
return obj.real_name if self.show_real_name else None
|
|
|
|
|
|
class EditUserSerializer(serializers.Serializer):
|
|
id = serializers.IntegerField()
|
|
username = serializers.CharField(max_length=32)
|
|
real_name = serializers.CharField(max_length=32, allow_blank=True, allow_null=True)
|
|
password = serializers.CharField(min_length=6, allow_blank=True, required=False, default=None)
|
|
email = serializers.EmailField(max_length=64)
|
|
admin_type = serializers.ChoiceField(choices=AdminType.choices)
|
|
problem_permission = serializers.ChoiceField(choices=ProblemPermission.choices)
|
|
open_api = serializers.BooleanField()
|
|
is_disabled = serializers.BooleanField()
|
|
class_name = serializers.CharField(required=False, allow_null=True, allow_blank=True)
|
|
|
|
|
|
class EditUserProfileSerializer(serializers.Serializer):
|
|
real_name = serializers.CharField(max_length=32, allow_null=True, required=False)
|
|
avatar = serializers.CharField(max_length=256, allow_blank=True, required=False)
|
|
blog = serializers.URLField(max_length=256, allow_blank=True, required=False)
|
|
mood = serializers.CharField(max_length=256, allow_blank=True, required=False)
|
|
github = serializers.URLField(max_length=256, allow_blank=True, required=False)
|
|
school = serializers.CharField(max_length=64, allow_blank=True, required=False)
|
|
major = serializers.CharField(max_length=64, allow_blank=True, required=False)
|
|
language = serializers.CharField(max_length=32, allow_blank=True, required=False)
|
|
|
|
|
|
class ImageUploadForm(forms.Form):
|
|
image = forms.FileField()
|
|
|
|
|
|
class RankInfoSerializer(serializers.ModelSerializer):
|
|
user = UsernameSerializer()
|
|
|
|
class Meta:
|
|
model = UserProfile
|
|
fields = ["user", "id", "accepted_number", "submission_number", "mood"]
|