Skip to content

Commit

Permalink
feat: add 'Reject Submission' feature
Browse files Browse the repository at this point in the history
Co-Authored-By: Phan Bình Nguyên Lâm <[email protected]>
  • Loading branch information
minh-ton and LLaammTTeerr committed Apr 21, 2024
1 parent 9291abd commit 0fbcc4d
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 0 deletions.
1 change: 1 addition & 0 deletions dmoj/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@
'WA': '#ed4420',
'CE': '#42586d',
'ERR': '#ffa71c',
'RJ': '#3e6291',
}
DMOJ_API_PAGE_SIZE = 1000

Expand Down
1 change: 1 addition & 0 deletions dmoj/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ def paged_list_view(view, name):

path('widgets/', include([
path('rejudge', widgets.rejudge_submission, name='submission_rejudge'),
path('reject', widgets.reject_submission, name='submission_reject'),
path('single_submission', submission.single_submission, name='submission_single_query'),
path('submission_testcases', submission.SubmissionTestCaseQuery.as_view(), name='submission_testcases_query'),
path('status-table', status.status_table, name='status_table'),
Expand Down
3 changes: 3 additions & 0 deletions judge/models/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,9 @@ def is_accessible_by(self, user, skip_contest_problem_check=False):
def is_rejudgeable_by(self, user):
return user.has_perm('judge.rejudge_submission') and self.is_editable_by(user)

def is_rejectable_by(self, user):
return user.has_perm('judge.reject_submission') and self.is_editable_by(user)

def is_subs_manageable_by(self, user):
return user.is_staff and self.is_rejudgeable_by(user)

Expand Down
20 changes: 20 additions & 0 deletions judge/models/submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
('IE', _('Internal Error')),
('SC', _('Short Circuited')),
('AB', _('Aborted')),
('RJ', _('Rejected')),
)

SUBMISSION_STATUS = (
Expand Down Expand Up @@ -68,6 +69,7 @@ class Submission(models.Model):
'G': _('Grading'),
'D': _('Completed'),
'AB': _('Aborted'),
'RJ': _('Rejected'),
}

user = models.ForeignKey(Profile, on_delete=models.CASCADE, db_index=False)
Expand Down Expand Up @@ -126,6 +128,23 @@ def long_status(self):
def is_locked(self):
return self.locked_after is not None and self.locked_after < timezone.now()

def reject(self):
self.points = 0
self.result = 'RJ'
self.case_points = 0
if self.problem.is_public and not self.problem.is_organization_private:
self.user._updating_stats_only = True
self.user.calculate_points()
self.problem._updating_stats_only = True
self.problem.update_stats()
self.save()
queryset = SubmissionTestCase.objects.filter(submission=self)
for tc in queryset:
tc.points = 0
tc.status = 'RJ'
tc.save()
self.update_contest()

def judge(self, *args, rejudge=False, force_judge=False, rejudge_user=None, **kwargs):
if force_judge or not self.is_locked:
if rejudge:
Expand Down Expand Up @@ -229,6 +248,7 @@ class Meta:
permissions = (
('abort_any_submission', _('Abort any submission')),
('rejudge_submission', _('Rejudge the submission')),
('reject_submission', _('Reject the submisison')),
('rejudge_submission_lot', _('Rejudge a lot of submissions')),
('spam_submission', _('Submit without limit')),
('view_all_submission', _('View all submission')),
Expand Down
21 changes: 21 additions & 0 deletions judge/views/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,27 @@ def rejudge_submission(request):
return HttpResponseRedirect(redirect) if redirect else HttpResponse('success', content_type='text/plain')


@login_required
@require_POST
def reject_submission(request):
if 'id' not in request.POST or not request.POST['id'].isdigit():
return HttpResponseBadRequest()

try:
submission = Submission.objects.get(id=request.POST['id'])
except Submission.DoesNotExist:
return HttpResponseBadRequest()

if not submission.problem.is_rejectable_by(request.user):
return HttpResponseForbidden()

submission.reject()

redirect = request.POST.get('path', None)

return HttpResponseRedirect(redirect) if redirect else HttpResponse('success', content_type='text/plain')


def django_uploader(image):
ext = os.path.splitext(image.name)[1]
if ext not in settings.MARTOR_UPLOAD_SAFE_EXTS:
Expand Down
5 changes: 5 additions & 0 deletions resources/submission.scss
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,11 @@ label[for="language"], label[for="status"], label[for="organization"] {
font-weight: bold;
}

.case-RJ {
color : #3E6291;
font-weight: bold;
}

.case-bad {
text-decoration: underline;
}
Expand Down
21 changes: 21 additions & 0 deletions templates/submission/status.html
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,27 @@
</form>
</div>
{% endif %}

{% if perms.judge.reject_submission and can_edit and not submission.is_locked %}
{% compress js %}
<script type="text/javascript">
window.confirm_and_reject = function (form) {
if (confirm("{{ _('Are you sure you want to reject?') }}")) {
form.submit();
}
};
</script>
{% endcompress %}
<div>
<form action="{{ url('submission_reject') }}" method="post">
{% csrf_token %}
<a href="#" onclick="confirm_and_reject(parentNode)">{{ _('Reject') }}</a>
<input type="hidden" name="id" value="{{ submission.id }}">
<input type="hidden" name="path" value = "{{ url('submission_status', submission.id) }}">
</form>
</div>
{% endif %}

{% if can_edit and not submission.language.file_only %}
<div><a href="{{ url('problem_submission_diff', submission.problem.code) }}?username={{ submission.user.user.username }}&highlight={{ submission.id }}">{{ _('Diff this submission') }}</a></div>
{% endif %}
Expand Down

0 comments on commit 0fbcc4d

Please sign in to comment.