Add contest rate limit submission
This commit is contained in:
parent
664dc3ca71
commit
fd77975390
9 changed files with 234 additions and 120 deletions
|
@ -163,6 +163,7 @@ class ContestAdmin(CompareVersionAdmin):
|
|||
"scoreboard_visibility",
|
||||
"run_pretests_only",
|
||||
"points_precision",
|
||||
"rate_limit",
|
||||
)
|
||||
},
|
||||
),
|
||||
|
|
|
@ -296,6 +296,7 @@ class EditOrganizationContestForm(ModelForm):
|
|||
"public_scoreboard",
|
||||
"scoreboard_visibility",
|
||||
"points_precision",
|
||||
"rate_limit",
|
||||
"description",
|
||||
"og_image",
|
||||
"logo_override_image",
|
||||
|
|
28
judge/migrations/0184_contest_rate_limit.py
Normal file
28
judge/migrations/0184_contest_rate_limit.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Generated by Django 3.2.18 on 2024-03-23 04:07
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("judge", "0183_rename_custom_checker_cpp"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="contest",
|
||||
name="rate_limit",
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True,
|
||||
help_text="Maximum number of submissions per minute. Leave empty if you don't want rate limit.",
|
||||
null=True,
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(1),
|
||||
django.core.validators.MaxValueValidator(5),
|
||||
],
|
||||
verbose_name="rate limit",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -310,6 +310,15 @@ class Contest(models.Model, PageVotable, Bookmarkable):
|
|||
validators=[MinValueValidator(0), MaxValueValidator(10)],
|
||||
help_text=_("Number of digits to round points to."),
|
||||
)
|
||||
rate_limit = models.PositiveIntegerField(
|
||||
verbose_name=(_("rate limit")),
|
||||
null=True,
|
||||
blank=True,
|
||||
validators=[MinValueValidator(1), MaxValueValidator(5)],
|
||||
help_text=_(
|
||||
"Maximum number of submissions per minute. Leave empty if you don't want rate limit."
|
||||
),
|
||||
)
|
||||
comments = GenericRelation("Comment")
|
||||
pagevote = GenericRelation("PageVote")
|
||||
bookmark = GenericRelation("BookMark")
|
||||
|
|
|
@ -963,6 +963,15 @@ class RandomProblem(ProblemList):
|
|||
user_logger = logging.getLogger("judge.user")
|
||||
|
||||
|
||||
def last_nth_submitted_date_in_contest(profile, contest, n):
|
||||
submissions = Submission.objects.filter(
|
||||
user=profile, contest_object=contest
|
||||
).order_by("-id")[:n]
|
||||
if submissions.count() >= n:
|
||||
return submissions[n - 1].date
|
||||
return None
|
||||
|
||||
|
||||
@login_required
|
||||
def problem_submit(request, problem, submission=None):
|
||||
if (
|
||||
|
@ -1011,7 +1020,7 @@ def problem_submit(request, problem, submission=None):
|
|||
>= settings.DMOJ_SUBMISSION_LIMIT
|
||||
):
|
||||
return HttpResponse(
|
||||
"<h1>You submitted too many submissions.</h1>", status=429
|
||||
_("<h1>You have submitted too many submissions.</h1>"), status=429
|
||||
)
|
||||
if not problem.allowed_languages.filter(
|
||||
id=form.cleaned_data["language"].id
|
||||
|
@ -1032,7 +1041,22 @@ def problem_submit(request, problem, submission=None):
|
|||
|
||||
with transaction.atomic():
|
||||
if profile.current_contest is not None:
|
||||
contest = profile.current_contest.contest
|
||||
contest_id = profile.current_contest.contest_id
|
||||
rate_limit = contest.rate_limit
|
||||
|
||||
if rate_limit:
|
||||
t = last_nth_submitted_date_in_contest(
|
||||
profile, contest, rate_limit
|
||||
)
|
||||
if t is not None and timezone.now() - t < timezone.timedelta(
|
||||
minutes=1
|
||||
):
|
||||
return HttpResponse(
|
||||
_("<h1>You have submitted too many submissions.</h1>"),
|
||||
status=429,
|
||||
)
|
||||
|
||||
try:
|
||||
contest_problem = problem.contests.get(contest_id=contest_id)
|
||||
except ContestProblem.DoesNotExist:
|
||||
|
@ -1112,11 +1136,11 @@ def problem_submit(request, problem, submission=None):
|
|||
default_lang = request.profile.language
|
||||
|
||||
submission_limit = submissions_left = None
|
||||
next_valid_submit_time = None
|
||||
if profile.current_contest is not None:
|
||||
contest = profile.current_contest.contest
|
||||
try:
|
||||
submission_limit = problem.contests.get(
|
||||
contest=profile.current_contest.contest
|
||||
).max_submissions
|
||||
submission_limit = problem.contests.get(contest=contest).max_submissions
|
||||
except ContestProblem.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
|
@ -1124,6 +1148,12 @@ def problem_submit(request, problem, submission=None):
|
|||
submissions_left = submission_limit - get_contest_submission_count(
|
||||
problem, profile, profile.current_contest.virtual
|
||||
)
|
||||
if contest.rate_limit:
|
||||
t = last_nth_submitted_date_in_contest(profile, contest, contest.rate_limit)
|
||||
if t is not None:
|
||||
next_valid_submit_time = t + timezone.timedelta(minutes=1)
|
||||
next_valid_submit_time = next_valid_submit_time.isoformat()
|
||||
|
||||
return render(
|
||||
request,
|
||||
"problem/submit.html",
|
||||
|
@ -1153,6 +1183,7 @@ def problem_submit(request, problem, submission=None):
|
|||
"output_only": problem.data_files.output_only
|
||||
if hasattr(problem, "data_files")
|
||||
else False,
|
||||
"next_valid_submit_time": next_valid_submit_time,
|
||||
},
|
||||
)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue