add end_time

This commit is contained in:
2026-03-16 23:44:47 +08:00
parent 8a3a7e21cf
commit ab62d7bff8
4 changed files with 60 additions and 1 deletions

View File

@@ -0,0 +1,18 @@
# Generated by Django 6.0 on 2026-03-16 15:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('problemset', '0006_remove_is_displayed_field'),
]
operations = [
migrations.AddField(
model_name='problemset',
name='end_time',
field=models.DateTimeField(blank=True, null=True, verbose_name='截止时间'),
),
]

View File

@@ -26,6 +26,8 @@ class ProblemSet(models.Model):
status = models.TextField( status = models.TextField(
default="draft", verbose_name="状态" default="draft", verbose_name="状态"
) # active, archived, draft ) # active, archived, draft
# 截止时间(到期后自动解除防作弊隐藏)
end_time = models.DateTimeField(null=True, blank=True, verbose_name="截止时间")
class Meta: class Meta:
db_table = "problemset" db_table = "problemset"

View File

@@ -92,6 +92,7 @@ class ProblemSetListSerializer(serializers.ModelSerializer):
"create_time", "create_time",
"difficulty", "difficulty",
"status", "status",
"end_time",
"problems_count", "problems_count",
"user_progress", "user_progress",
"badges", "badges",
@@ -148,6 +149,7 @@ class CreateProblemSetSerializer(serializers.Serializer):
description = serializers.CharField() description = serializers.CharField()
difficulty = serializers.CharField(default="Easy") difficulty = serializers.CharField(default="Easy")
status = serializers.CharField(default="active") status = serializers.CharField(default="active")
end_time = serializers.DateTimeField(required=False)
class EditProblemSetSerializer(serializers.Serializer): class EditProblemSetSerializer(serializers.Serializer):
@@ -159,6 +161,7 @@ class EditProblemSetSerializer(serializers.Serializer):
difficulty = serializers.CharField(required=False) difficulty = serializers.CharField(required=False)
status = serializers.CharField(required=False) status = serializers.CharField(required=False)
visible = serializers.BooleanField(required=False) visible = serializers.BooleanField(required=False)
end_time = serializers.DateTimeField(required=False, allow_null=True)
class ProblemSetProblemSerializer(serializers.ModelSerializer): class ProblemSetProblemSerializer(serializers.ModelSerializer):

View File

@@ -1,6 +1,10 @@
from django.db import models
from django.utils import timezone
from .models import Submission from .models import Submission
from utils.api import serializers from utils.api import serializers
from utils.serializers import LanguageNameChoiceField from utils.serializers import LanguageNameChoiceField
from problemset.models import ProblemSetProgress
class CreateSubmissionSerializer(serializers.Serializer): class CreateSubmissionSerializer(serializers.Serializer):
@@ -50,4 +54,36 @@ class SubmissionListSerializer(serializers.ModelSerializer):
# 没传user或为匿名user # 没传user或为匿名user
if self.user is None or not self.user.is_authenticated: if self.user is None or not self.user.is_authenticated:
return False return False
return obj.check_user_permission(self.user) if not obj.check_user_permission(self.user):
return False
# 题单防作弊:用户加入了包含该题目的 active 题单时,隐藏加入前的提交链接
# 如果该题目已在题单中做出来了,则恢复显示
if obj.user_id == self.user.id and self.user.is_regular_user():
progress = self._get_problemset_progress(obj.problem_id)
if (
progress
and obj.create_time < progress.join_time
and str(obj.problem_id) not in progress.progress_detail
):
return False
return True
def _get_problemset_progress(self, problem_id):
"""查询用户是否加入了包含该题目的 active 题单,带缓存避免 N+1"""
if not hasattr(self, "_problemset_progress_cache"):
self._problemset_progress_cache = {}
if problem_id not in self._problemset_progress_cache:
self._problemset_progress_cache[problem_id] = (
ProblemSetProgress.objects.filter(
user=self.user,
problemset__status="active",
problemset__problemsetproblem__problem_id=problem_id,
)
.filter(
models.Q(problemset__end_time__isnull=True)
| models.Q(problemset__end_time__gt=timezone.now())
)
.only("join_time", "progress_detail")
.first()
)
return self._problemset_progress_cache[problem_id]