From fd779753907707899760dfb84221dea2988990a9 Mon Sep 17 00:00:00 2001 From: cuom1999 Date: Sat, 23 Mar 2024 00:26:53 -0500 Subject: [PATCH] Add contest rate limit submission --- judge/admin/contest.py | 1 + judge/forms.py | 1 + judge/migrations/0184_contest_rate_limit.py | 28 +++ judge/models/contest.py | 9 + judge/views/problem.py | 39 +++- locale/vi/LC_MESSAGES/django.po | 242 +++++++++++--------- resources/widgets.scss | 2 +- templates/organization/contest/edit.html | 3 +- templates/problem/submit.html | 29 ++- 9 files changed, 234 insertions(+), 120 deletions(-) create mode 100644 judge/migrations/0184_contest_rate_limit.py diff --git a/judge/admin/contest.py b/judge/admin/contest.py index df2d412..7af3e90 100644 --- a/judge/admin/contest.py +++ b/judge/admin/contest.py @@ -163,6 +163,7 @@ class ContestAdmin(CompareVersionAdmin): "scoreboard_visibility", "run_pretests_only", "points_precision", + "rate_limit", ) }, ), diff --git a/judge/forms.py b/judge/forms.py index 290e5bb..853e7e1 100644 --- a/judge/forms.py +++ b/judge/forms.py @@ -296,6 +296,7 @@ class EditOrganizationContestForm(ModelForm): "public_scoreboard", "scoreboard_visibility", "points_precision", + "rate_limit", "description", "og_image", "logo_override_image", diff --git a/judge/migrations/0184_contest_rate_limit.py b/judge/migrations/0184_contest_rate_limit.py new file mode 100644 index 0000000..c05174d --- /dev/null +++ b/judge/migrations/0184_contest_rate_limit.py @@ -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", + ), + ), + ] diff --git a/judge/models/contest.py b/judge/models/contest.py index 4a8b087..1a6a58a 100644 --- a/judge/models/contest.py +++ b/judge/models/contest.py @@ -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") diff --git a/judge/views/problem.py b/judge/views/problem.py index d673e5c..3b68b45 100644 --- a/judge/views/problem.py +++ b/judge/views/problem.py @@ -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( - "

You submitted too many submissions.

", status=429 + _("

You have submitted too many submissions.

"), 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( + _("

You have submitted too many submissions.

"), + 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, }, ) diff --git a/locale/vi/LC_MESSAGES/django.po b/locale/vi/LC_MESSAGES/django.po index 146a893..fd65d13 100644 --- a/locale/vi/LC_MESSAGES/django.po +++ b/locale/vi/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: lqdoj2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-03-23 10:54+0700\n" +"POT-Creation-Date: 2024-03-23 12:24+0700\n" "PO-Revision-Date: 2021-07-20 03:44\n" "Last-Translator: Icyene\n" "Language-Team: Vietnamese\n" @@ -23,8 +23,8 @@ msgid "last seen" msgstr "xem lần cuối" #: chat_box/models.py:54 chat_box/models.py:79 chat_box/models.py:95 -#: judge/admin/interface.py:150 judge/models/contest.py:647 -#: judge/models/contest.py:853 judge/models/course.py:129 +#: judge/admin/interface.py:150 judge/models/contest.py:654 +#: judge/models/contest.py:860 judge/models/course.py:129 #: judge/models/profile.py:412 judge/models/profile.py:486 msgid "user" msgstr "người dùng" @@ -130,74 +130,74 @@ msgstr "Bài tập" msgid "Settings" msgstr "Cài đặt" -#: judge/admin/contest.py:170 +#: judge/admin/contest.py:171 msgid "Scheduling" msgstr "" -#: judge/admin/contest.py:174 +#: judge/admin/contest.py:175 msgid "Details" msgstr "Chi tiết" -#: judge/admin/contest.py:186 templates/contest/list.html:263 +#: judge/admin/contest.py:187 templates/contest/list.html:263 #: templates/contest/list.html:304 templates/contest/list.html:349 #: templates/contest/list.html:386 msgid "Format" msgstr "Thể thức" -#: judge/admin/contest.py:190 templates/contest/ranking-table.html:5 +#: judge/admin/contest.py:191 templates/contest/ranking-table.html:5 #: templates/user/user-about.html:15 templates/user/user-about.html:45 msgid "Rating" msgstr "" -#: judge/admin/contest.py:202 +#: judge/admin/contest.py:203 msgid "Access" msgstr "Truy cập" -#: judge/admin/contest.py:212 judge/admin/problem.py:233 +#: judge/admin/contest.py:213 judge/admin/problem.py:233 msgid "Justice" msgstr "Xử phạt" -#: judge/admin/contest.py:332 +#: judge/admin/contest.py:333 #, python-format msgid "%d contest successfully marked as visible." msgid_plural "%d contests successfully marked as visible." msgstr[0] "%d kỳ thi đã được đánh dấu hiển thị." -#: judge/admin/contest.py:339 +#: judge/admin/contest.py:340 msgid "Mark contests as visible" msgstr "Đánh dấu hiển thị các kỳ thi" -#: judge/admin/contest.py:350 +#: judge/admin/contest.py:351 #, python-format msgid "%d contest successfully marked as hidden." msgid_plural "%d contests successfully marked as hidden." msgstr[0] "%d kỳ thi đã được đánh dấu ẩn." -#: judge/admin/contest.py:357 +#: judge/admin/contest.py:358 msgid "Mark contests as hidden" msgstr "Ẩn các kỳ thi" -#: judge/admin/contest.py:378 judge/admin/submission.py:241 +#: judge/admin/contest.py:379 judge/admin/submission.py:241 #, python-format msgid "%d submission was successfully scheduled for rejudging." msgid_plural "%d submissions were successfully scheduled for rejudging." msgstr[0] "%d bài nộp đã được lên lịch thành công để chấm lại." -#: judge/admin/contest.py:486 +#: judge/admin/contest.py:487 #, python-format msgid "%d participation recalculated." msgid_plural "%d participations recalculated." msgstr[0] "%d thí sinh đã được tính điểm lại." -#: judge/admin/contest.py:493 +#: judge/admin/contest.py:494 msgid "Recalculate results" msgstr "Tính toán lại kết quả" -#: judge/admin/contest.py:498 judge/admin/organization.py:99 +#: judge/admin/contest.py:499 judge/admin/organization.py:99 msgid "username" msgstr "tên đăng nhập" -#: judge/admin/contest.py:504 templates/base.html:244 +#: judge/admin/contest.py:505 templates/base.html:244 msgid "virtual" msgstr "ảo" @@ -558,68 +558,68 @@ msgstr "File tải lên không được quá 5MB." msgid "Any judge" msgstr "" -#: judge/forms.py:337 +#: judge/forms.py:338 msgid "Enter usernames separating by space" msgstr "Nhập các tên đăng nhập, cách nhau bởi dấu cách" -#: judge/forms.py:338 judge/views/stats.py:166 templates/stats/site.html:27 +#: judge/forms.py:339 judge/views/stats.py:166 templates/stats/site.html:27 msgid "New users" msgstr "Thành viên mới" -#: judge/forms.py:355 +#: judge/forms.py:356 #, python-brace-format msgid "These usernames don't exist: {usernames}" msgstr "Các tên đăng nhập này không tồn tại: {usernames}" -#: judge/forms.py:415 +#: judge/forms.py:416 msgid "Username/Email" msgstr "Tên đăng nhập / Email" -#: judge/forms.py:417 judge/views/email.py:22 +#: judge/forms.py:418 judge/views/email.py:22 #: templates/registration/registration_form.html:46 #: templates/registration/registration_form.html:60 #: templates/user/edit-profile.html:101 templates/user/import/table_csv.html:5 msgid "Password" msgstr "Mật khẩu" -#: judge/forms.py:443 +#: judge/forms.py:444 msgid "Two Factor Authentication tokens must be 6 decimal digits." msgstr "Two Factor Authentication phải chứa 6 chữ số." -#: judge/forms.py:456 templates/registration/totp_auth.html:32 +#: judge/forms.py:457 templates/registration/totp_auth.html:32 msgid "Invalid Two Factor Authentication token." msgstr "Token Two Factor Authentication không hợp lệ." -#: judge/forms.py:463 judge/models/problem.py:132 +#: judge/forms.py:464 judge/models/problem.py:132 msgid "Problem code must be ^[a-z0-9]+$" msgstr "Mã bài phải có dạng ^[a-z0-9]+$" -#: judge/forms.py:470 +#: judge/forms.py:471 msgid "Problem with code already exists." msgstr "Mã bài đã tồn tại." -#: judge/forms.py:477 judge/models/contest.py:95 +#: judge/forms.py:478 judge/models/contest.py:95 msgid "Contest id must be ^[a-z0-9]+$" msgstr "Mã kỳ thi phải có dạng ^[a-z0-9]+$" -#: judge/forms.py:484 templates/contest/clone.html:47 +#: judge/forms.py:485 templates/contest/clone.html:47 #: templates/problem/search-form.html:39 msgid "Group" msgstr "Nhóm" -#: judge/forms.py:492 +#: judge/forms.py:493 msgid "Contest with key already exists." msgstr "Mã kỳ thi đã tồn tại." -#: judge/forms.py:500 +#: judge/forms.py:501 msgid "Group doesn't exist." msgstr "Nhóm không tồn tại." -#: judge/forms.py:502 +#: judge/forms.py:503 msgid "You don't have permission in this group." msgstr "Bạn không có quyền trong nhóm này." -#: judge/forms.py:552 +#: judge/forms.py:553 msgid "This problem is duplicated." msgstr "Bài này bị lặp" @@ -803,7 +803,7 @@ msgstr "mô tả" msgid "problems" msgstr "bài tập" -#: judge/models/contest.py:129 judge/models/contest.py:652 +#: judge/models/contest.py:129 judge/models/contest.py:659 msgid "start time" msgstr "thời gian bắt đầu" @@ -1029,267 +1029,277 @@ msgstr "Hiển thị điểm" msgid "Number of digits to round points to." msgstr "Số chữ số thập phân trên bảng điểm." -#: judge/models/contest.py:620 +#: judge/models/contest.py:314 +msgid "rate limit" +msgstr "giới hạn bài nộp" + +#: judge/models/contest.py:318 +msgid "" +"Maximum number of submissions per minute. Leave empty if you don't want rate " +"limit." +msgstr "Số bài nộp tối đa mỗi phút. Để trống nếu không muốn giới hạn." + +#: judge/models/contest.py:627 msgid "See private contests" msgstr "" -#: judge/models/contest.py:621 +#: judge/models/contest.py:628 msgid "Edit own contests" msgstr "" -#: judge/models/contest.py:622 +#: judge/models/contest.py:629 msgid "Edit all contests" msgstr "" -#: judge/models/contest.py:623 +#: judge/models/contest.py:630 msgid "Clone contest" msgstr "" -#: judge/models/contest.py:624 templates/contest/moss.html:72 +#: judge/models/contest.py:631 templates/contest/moss.html:72 msgid "MOSS contest" msgstr "" -#: judge/models/contest.py:625 +#: judge/models/contest.py:632 msgid "Rate contests" msgstr "" -#: judge/models/contest.py:626 +#: judge/models/contest.py:633 msgid "Contest access codes" msgstr "" -#: judge/models/contest.py:627 +#: judge/models/contest.py:634 msgid "Create private contests" msgstr "" -#: judge/models/contest.py:628 +#: judge/models/contest.py:635 msgid "Change contest visibility" msgstr "" -#: judge/models/contest.py:629 +#: judge/models/contest.py:636 msgid "Edit contest problem label script" msgstr "Cách hiển thị thứ tự bài tập" -#: judge/models/contest.py:631 judge/models/contest.py:778 -#: judge/models/contest.py:856 judge/models/contest.py:886 +#: judge/models/contest.py:638 judge/models/contest.py:785 +#: judge/models/contest.py:863 judge/models/contest.py:893 #: judge/models/submission.py:116 msgid "contest" msgstr "kỳ thi" -#: judge/models/contest.py:632 +#: judge/models/contest.py:639 msgid "contests" msgstr "kỳ thi" -#: judge/models/contest.py:641 +#: judge/models/contest.py:648 msgid "associated contest" msgstr "" -#: judge/models/contest.py:654 +#: judge/models/contest.py:661 msgid "score" msgstr "điểm" -#: judge/models/contest.py:655 +#: judge/models/contest.py:662 msgid "cumulative time" msgstr "tổng thời gian" -#: judge/models/contest.py:657 +#: judge/models/contest.py:664 msgid "is disqualified" msgstr "đã bị loại" -#: judge/models/contest.py:659 +#: judge/models/contest.py:666 msgid "Whether this participation is disqualified." msgstr "Quyết định thí sinh có bị loại không." -#: judge/models/contest.py:661 +#: judge/models/contest.py:668 msgid "tie-breaking field" msgstr "" -#: judge/models/contest.py:663 +#: judge/models/contest.py:670 msgid "virtual participation id" msgstr "id lần tham gia ảo" -#: judge/models/contest.py:665 +#: judge/models/contest.py:672 msgid "0 means non-virtual, otherwise the n-th virtual participation." msgstr "0 nghĩa là tham gia chính thức, ngược lại là lần tham gia ảo thứ n." -#: judge/models/contest.py:668 +#: judge/models/contest.py:675 msgid "contest format specific data" msgstr "" -#: judge/models/contest.py:671 +#: judge/models/contest.py:678 msgid "same as format_data, but including frozen results" msgstr "" -#: judge/models/contest.py:675 +#: judge/models/contest.py:682 #, fuzzy #| msgid "score" msgid "final score" msgstr "điểm" -#: judge/models/contest.py:677 +#: judge/models/contest.py:684 #, fuzzy #| msgid "cumulative time" msgid "final cumulative time" msgstr "tổng thời gian" -#: judge/models/contest.py:753 +#: judge/models/contest.py:760 #, python-format msgid "%s spectating in %s" msgstr "%s đang theo dõi trong %s" -#: judge/models/contest.py:758 +#: judge/models/contest.py:765 #, python-format msgid "%s in %s, v%d" msgstr "%s trong %s, v%d" -#: judge/models/contest.py:763 +#: judge/models/contest.py:770 #, python-format msgid "%s in %s" msgstr "%s trong %s" -#: judge/models/contest.py:766 +#: judge/models/contest.py:773 msgid "contest participation" msgstr "lần tham gia kỳ thi" -#: judge/models/contest.py:767 +#: judge/models/contest.py:774 msgid "contest participations" msgstr "lần tham gia kỳ thi" -#: judge/models/contest.py:774 judge/models/contest.py:827 -#: judge/models/contest.py:889 judge/models/course.py:165 +#: judge/models/contest.py:781 judge/models/contest.py:834 +#: judge/models/contest.py:896 judge/models/course.py:165 #: judge/models/problem.py:591 judge/models/problem.py:598 #: judge/models/problem.py:619 judge/models/problem.py:650 #: judge/models/problem_data.py:50 msgid "problem" msgstr "bài tập" -#: judge/models/contest.py:782 judge/models/contest.py:839 +#: judge/models/contest.py:789 judge/models/contest.py:846 #: judge/models/course.py:167 judge/models/problem.py:208 msgid "points" msgstr "điểm" -#: judge/models/contest.py:783 +#: judge/models/contest.py:790 msgid "partial" msgstr "thành phần" -#: judge/models/contest.py:784 judge/models/contest.py:841 +#: judge/models/contest.py:791 judge/models/contest.py:848 msgid "is pretested" msgstr "dùng pretest" -#: judge/models/contest.py:785 judge/models/course.py:166 +#: judge/models/contest.py:792 judge/models/course.py:166 #: judge/models/interface.py:47 msgid "order" msgstr "thứ tự" -#: judge/models/contest.py:787 +#: judge/models/contest.py:794 msgid "visible testcases" msgstr "hiển thị test" -#: judge/models/contest.py:792 +#: judge/models/contest.py:799 msgid "Maximum number of submissions for this problem, or 0 for no limit." msgstr "Số lần nộp tối đa, đặt là 0 nếu không có giới hạn." -#: judge/models/contest.py:794 +#: judge/models/contest.py:801 msgid "max submissions" msgstr "số lần nộp tối đa" -#: judge/models/contest.py:797 +#: judge/models/contest.py:804 msgid "Why include a problem you can't submit to?" msgstr "" -#: judge/models/contest.py:801 +#: judge/models/contest.py:808 #, fuzzy #| msgid "Only for format new IOI. Separated by commas, e.g: 2, 3" msgid "Separated by commas, e.g: 2, 3" msgstr "" "Chỉ dùng với format IOI mới. Các sub cách nhau bởi dấu phẩy. Ví dụ: 2, 3" -#: judge/models/contest.py:802 +#: judge/models/contest.py:809 #, fuzzy #| msgid "frozen subtasks" msgid "hidden subtasks" msgstr "Đóng băng subtasks" -#: judge/models/contest.py:814 +#: judge/models/contest.py:821 msgid "contest problem" msgstr "bài trong kỳ thi" -#: judge/models/contest.py:815 +#: judge/models/contest.py:822 msgid "contest problems" msgstr "bài trong kỳ thi" -#: judge/models/contest.py:821 judge/models/submission.py:273 +#: judge/models/contest.py:828 judge/models/submission.py:273 msgid "submission" msgstr "bài nộp" -#: judge/models/contest.py:834 judge/models/contest.py:860 +#: judge/models/contest.py:841 judge/models/contest.py:867 msgid "participation" msgstr "lần tham gia" -#: judge/models/contest.py:842 +#: judge/models/contest.py:849 msgid "Whether this submission was ran only on pretests." msgstr "Quyết định bài nộp chỉ được chạy trên pretest không." -#: judge/models/contest.py:847 +#: judge/models/contest.py:854 msgid "contest submission" msgstr "bài nộp kỳ thi" -#: judge/models/contest.py:848 +#: judge/models/contest.py:855 msgid "contest submissions" msgstr "bài nộp kỳ thi" -#: judge/models/contest.py:864 +#: judge/models/contest.py:871 msgid "rank" msgstr "rank" -#: judge/models/contest.py:865 +#: judge/models/contest.py:872 msgid "rating" msgstr "rating" -#: judge/models/contest.py:866 +#: judge/models/contest.py:873 msgid "raw rating" msgstr "rating thật" -#: judge/models/contest.py:867 +#: judge/models/contest.py:874 msgid "contest performance" msgstr "" -#: judge/models/contest.py:868 +#: judge/models/contest.py:875 msgid "last rated" msgstr "lần cuối được xếp hạng" -#: judge/models/contest.py:872 +#: judge/models/contest.py:879 msgid "contest rating" msgstr "rating kỳ thi" -#: judge/models/contest.py:873 +#: judge/models/contest.py:880 msgid "contest ratings" msgstr "rating kỳ thi" -#: judge/models/contest.py:897 +#: judge/models/contest.py:904 msgid "contest moss result" msgstr "kết quả MOSS kỳ thi" -#: judge/models/contest.py:898 +#: judge/models/contest.py:905 msgid "contest moss results" msgstr "kết quả MOSS kỳ thi" -#: judge/models/contest.py:903 +#: judge/models/contest.py:910 msgid "clarified problem" msgstr "" -#: judge/models/contest.py:905 +#: judge/models/contest.py:912 msgid "clarification body" msgstr "" -#: judge/models/contest.py:907 +#: judge/models/contest.py:914 msgid "clarification timestamp" msgstr "" -#: judge/models/contest.py:926 +#: judge/models/contest.py:933 msgid "contests summary" msgstr "tổng kết kỳ thi" -#: judge/models/contest.py:927 +#: judge/models/contest.py:934 msgid "contests summaries" msgstr "tổng kết kỳ thi" @@ -3260,30 +3270,34 @@ msgstr "Bài tập" msgid "Problem feed" msgstr "Bài tập" -#: judge/views/problem.py:1026 +#: judge/views/problem.py:1021 judge/views/problem.py:1052 +msgid "

You have submitted too many submissions.

" +msgstr "

Bạn nộp quá nhiều bài.

" + +#: judge/views/problem.py:1033 msgid "Banned from submitting" msgstr "Bị cấm nộp bài" -#: judge/views/problem.py:1028 +#: judge/views/problem.py:1035 msgid "" "You have been declared persona non grata for this problem. You are " "permanently barred from submitting this problem." msgstr "Bạn đã bị cấm nộp bài này." -#: judge/views/problem.py:1051 +#: judge/views/problem.py:1070 msgid "Too many submissions" msgstr "Quá nhiều lần nộp" -#: judge/views/problem.py:1053 +#: judge/views/problem.py:1072 msgid "You have exceeded the submission limit for this problem." msgstr "Bạn đã vượt quá số lần nộp cho bài này." -#: judge/views/problem.py:1132 judge/views/problem.py:1137 +#: judge/views/problem.py:1161 judge/views/problem.py:1166 #, python-format msgid "Submit to %(problem)s" msgstr "Nộp bài cho %(problem)s" -#: judge/views/problem.py:1163 +#: judge/views/problem.py:1193 msgid "Clone Problem" msgstr "Nhân bản bài tập" @@ -4413,7 +4427,7 @@ msgid "Add new" msgstr "Thêm mới" #: templates/course/edit_lesson.html:36 -#: templates/organization/contest/edit.html:40 +#: templates/organization/contest/edit.html:41 #: templates/organization/form.html:6 msgid "Please fix below errors" msgstr "Vui lòng sửa các lỗi bên dưới" @@ -4422,7 +4436,7 @@ msgstr "Vui lòng sửa các lỗi bên dưới" #: templates/markdown_editor/markdown_editor.html:122 #: templates/organization/blog/edit.html:36 #: templates/organization/contest/add.html:36 -#: templates/organization/contest/edit.html:86 +#: templates/organization/contest/edit.html:87 #: templates/organization/form.html:23 templates/pagedown.html:31 msgid "Save" msgstr "Lưu" @@ -4598,7 +4612,7 @@ msgstr "Tác giả" msgid "Post time" msgstr "Thời gian đăng" -#: templates/organization/contest/edit.html:60 +#: templates/organization/contest/edit.html:61 msgid "If you run out of rows, click Save" msgstr "Ấn nút lưu lại nếu cần thêm hàng" @@ -5159,11 +5173,15 @@ msgstr "Lọc" msgid "Random" msgstr "Ngẫu nhiên" -#: templates/problem/submit.html:124 +#: templates/problem/submit.html:48 +msgid "Wait" +msgstr "Đợi" + +#: templates/problem/submit.html:148 msgid "Your source code must contain at most 65536 characters." msgstr "Code phải chứa không quá 65536 ký tự." -#: templates/problem/submit.html:171 +#: templates/problem/submit.html:195 #, python-format msgid "" "Warning! Your default language, %(default_language)s, is " @@ -5172,7 +5190,7 @@ msgstr "" "Cẩn thận! Ngôn ngữ ưa thích của bạn, %(default_language)s, " "không được sử dụng trong bài này." -#: templates/problem/submit.html:182 +#: templates/problem/submit.html:206 #, fuzzy, python-format #| msgid "" #| "\n" @@ -5195,15 +5213,15 @@ msgstr[0] "" " Bạn còn %(left)s lần nộp\n" " " -#: templates/problem/submit.html:191 +#: templates/problem/submit.html:215 msgid "You have 0 submissions left" msgstr "Bạn đã hết lần nộp" -#: templates/problem/submit.html:225 +#: templates/problem/submit.html:249 msgid "No judge is available for this problem." msgstr "Không có máy chấm có thể chấm bài này." -#: templates/problem/submit.html:231 +#: templates/problem/submit.html:255 msgid "Submit!" msgstr "Nộp bài!" diff --git a/resources/widgets.scss b/resources/widgets.scss index ce1b7c2..c52c991 100644 --- a/resources/widgets.scss +++ b/resources/widgets.scss @@ -59,7 +59,7 @@ text-align: center; width: auto; - &.disabled { + &.disabled, &[disabled] { background: linear-gradient(to bottom, darkgray 0, gray 100%) repeat-x !important; border-color: grey !important; cursor: not-allowed; diff --git a/templates/organization/contest/edit.html b/templates/organization/contest/edit.html index e0cffd4..95b1a3e 100644 --- a/templates/organization/contest/edit.html +++ b/templates/organization/contest/edit.html @@ -13,7 +13,8 @@ #org-field-wrapper-end_time, #org-field-wrapper-time_limit, #org-field-wrapper-format_name, - #org-field-wrapper-freeze_after { + #org-field-wrapper-freeze_after, + #org-field-wrapper-rate_limit { display: inline-flex; } .problems-problem { diff --git a/templates/problem/submit.html b/templates/problem/submit.html index e9abb17..af3b64b 100644 --- a/templates/problem/submit.html +++ b/templates/problem/submit.html @@ -32,7 +32,31 @@ } {% endif %} } + + {% if request.in_contest and next_valid_submit_time and not (submission_limit and submissions_left <= 0) %} + $(function () { + const $submitButton = $("#submit-button"); + $submitButton.prop('disabled', true); + const nextValidDate = new Date("{{next_valid_submit_time}}"); + + function updateCountdown() { + var now = new Date(); + var timeUntilNextValid = nextValidDate - now; + + if (timeUntilNextValid > 0) { + var seconds = Math.floor(timeUntilNextValid / 1000); + $("#countdown-timer").text("{{_("Wait")}} " + seconds + "s"); + setTimeout(updateCountdown, 1000); + } else { + $("#countdown-timer").text(""); + $submitButton.prop('disabled', false); + } + } + updateCountdown(); + }); + {% endif %} + {% compress js %}