Make submit form work

This commit is contained in:
cuom1999 2020-07-19 16:39:28 -05:00
parent 3629369fba
commit 6f25762ffa
2 changed files with 31 additions and 53 deletions

View file

@ -10,9 +10,9 @@ from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.db import transaction from django.db import transaction
from django.db.models import Count, F, Prefetch, Q, Sum, Case, When, IntegerField from django.db.models import Count, F, Prefetch, Q
from django.db.utils import ProgrammingError from django.db.utils import ProgrammingError
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseRedirect from django.http import Http404, HttpResponse, HttpResponseForbidden, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
from django.template.loader import get_template from django.template.loader import get_template
from django.urls import reverse from django.urls import reverse
@ -49,7 +49,7 @@ def get_contest_problem(problem, profile):
def get_contest_submission_count(problem, profile, virtual): def get_contest_submission_count(problem, profile, virtual):
return profile.current_contest.submissions.exclude(submission__status__in=['IE']) \ return profile.current_contest.submissions.exclude(submission__status__in=['IE']) \
.filter(problem__problem__code=problem, participation__virtual=virtual).count() .filter(problem__problem=problem, participation__virtual=virtual).count()
class ProblemMixin(object): class ProblemMixin(object):
@ -177,7 +177,7 @@ class ProblemDetail(ProblemMixin, SolvedProblemMixin, CommentedDetailView):
context['submission_limit'] = contest_problem.max_submissions context['submission_limit'] = contest_problem.max_submissions
if contest_problem.max_submissions: if contest_problem.max_submissions:
context['submissions_left'] = max(contest_problem.max_submissions - context['submissions_left'] = max(contest_problem.max_submissions -
get_contest_submission_count(self.object.code, user.profile, get_contest_submission_count(self.object, user.profile,
user.profile.current_contest.virtual), 0) user.profile.current_contest.virtual), 0)
context['available_judges'] = Judge.objects.filter(online=True, problems=self.object) context['available_judges'] = Judge.objects.filter(online=True, problems=self.object)
@ -287,11 +287,11 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
context_object_name = 'problems' context_object_name = 'problems'
template_name = 'problem/list.html' template_name = 'problem/list.html'
paginate_by = 50 paginate_by = 50
sql_sort = frozenset(('date', 'points', 'ac_rate', 'user_count', 'code')) sql_sort = frozenset(('points', 'ac_rate', 'user_count', 'code'))
manual_sort = frozenset(('name', 'group', 'solved', 'type')) manual_sort = frozenset(('name', 'group', 'solved', 'type'))
all_sorts = sql_sort | manual_sort all_sorts = sql_sort | manual_sort
default_desc = frozenset(('date', 'points', 'ac_rate', 'user_count')) default_desc = frozenset(('points', 'ac_rate', 'user_count'))
default_sort = '-date' default_sort = 'code'
def get_paginator(self, queryset, per_page, orphans=0, def get_paginator(self, queryset, per_page, orphans=0,
allow_empty_first_page=True, **kwargs): allow_empty_first_page=True, **kwargs):
@ -404,17 +404,9 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(ProblemList, self).get_context_data(**kwargs) context = super(ProblemList, self).get_context_data(**kwargs)
context['hide_solved'] = 0 if self.in_contest else int(self.hide_solved) context['hide_solved'] = 0 if self.in_contest else int(self.hide_solved)
context['show_types'] = 0 if self.in_contest else int(self.show_types) context['show_types'] = 0 if self.in_contest else int(self.show_types)
context['full_text'] = 0 if self.in_contest else int(self.full_text) context['full_text'] = 0 if self.in_contest else int(self.full_text)
context['show_editorial'] = 0 if self.in_contest else int(self.show_editorial)
if (context['show_editorial']):
context['object_list'] = context['object_list'] \
.annotate(has_public_editorial=Sum(Case(When(solution__is_public=True, then=1),
default=0, output_field=IntegerField())))
context['category'] = self.category context['category'] = self.category
context['categories'] = ProblemGroup.objects.all() context['categories'] = ProblemGroup.objects.all()
if self.show_types: if self.show_types:
@ -464,7 +456,6 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
self.hide_solved = self.GET_with_session(request, 'hide_solved') self.hide_solved = self.GET_with_session(request, 'hide_solved')
self.show_types = self.GET_with_session(request, 'show_types') self.show_types = self.GET_with_session(request, 'show_types')
self.full_text = self.GET_with_session(request, 'full_text') self.full_text = self.GET_with_session(request, 'full_text')
self.show_editorial = self.GET_with_session(request, 'show_editorial')
self.search_query = None self.search_query = None
self.category = None self.category = None
@ -494,7 +485,7 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
return generic_message(request, 'FTS syntax error', e.args[1], status=400) return generic_message(request, 'FTS syntax error', e.args[1], status=400)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
to_update = ('hide_solved', 'show_types', 'full_text', 'show_editorial') to_update = ('hide_solved', 'show_types', 'full_text')
for key in to_update: for key in to_update:
if key in request.GET: if key in request.GET:
val = request.GET.get(key) == '1' val = request.GET.get(key) == '1'
@ -531,12 +522,19 @@ user_logger = logging.getLogger('judge.user')
@login_required @login_required
def problem_submit(request, problem=None, submission=None): def problem_submit(request, problem, submission=None):
if submission is not None and not request.user.has_perm('judge.resubmit_other') and \ if submission is not None and not request.user.has_perm('judge.resubmit_other') and \
get_object_or_404(Submission, id=int(submission)).user.user != request.user: get_object_or_404(Submission, id=int(submission)).user.user != request.user:
raise PermissionDenied() raise PermissionDenied()
profile = request.profile profile = request.profile
problem = get_object_or_404(Problem, code=problem)
if not problem.is_accessible_by(request.user):
if request.method == 'POST':
user_logger.info('Naughty user %s wants to submit to %s without permission',
request.user.username, problem.code)
return HttpResponseForbidden('<h1>Do you want me to ban you?</h1>')
raise Http404()
if problem.is_editable_by(request.user): if problem.is_editable_by(request.user):
judge_choices = tuple(Judge.objects.filter(online=True, problems=problem).values_list('name', 'name')) judge_choices = tuple(Judge.objects.filter(online=True, problems=problem).values_list('name', 'name'))
@ -551,15 +549,9 @@ def problem_submit(request, problem=None, submission=None):
Submission.objects.filter(user=profile, was_rejudged=False) Submission.objects.filter(user=profile, was_rejudged=False)
.exclude(status__in=['D', 'IE', 'CE', 'AB']).count() >= settings.DMOJ_SUBMISSION_LIMIT): .exclude(status__in=['D', 'IE', 'CE', 'AB']).count() >= settings.DMOJ_SUBMISSION_LIMIT):
return HttpResponse('<h1>You submitted too many submissions.</h1>', status=429) return HttpResponse('<h1>You submitted too many submissions.</h1>', status=429)
if not form.cleaned_data['problem'].allowed_languages.filter( if not problem.allowed_languages.filter(id=form.cleaned_data['language'].id).exists():
id=form.cleaned_data['language'].id).exists():
raise PermissionDenied() raise PermissionDenied()
if not form.cleaned_data['problem'].is_accessible_by(request.user): if not request.user.is_superuser and problem.banned_users.filter(id=profile.id).exists():
user_logger.info('Naughty user %s wants to submit to %s without permission',
request.user.username, form.cleaned_data['problem'].code)
return HttpResponseForbidden('<h1>Do you want me to ban you?</h1>')
if not request.user.is_superuser and form.cleaned_data['problem'].banned_users.filter(
id=profile.id).exists():
return generic_message(request, _('Banned from submitting'), return generic_message(request, _('Banned from submitting'),
_('You have been declared persona non grata for this problem. ' _('You have been declared persona non grata for this problem. '
'You are permanently barred from submitting this problem.')) 'You are permanently barred from submitting this problem.'))
@ -568,7 +560,7 @@ def problem_submit(request, problem=None, submission=None):
if profile.current_contest is not None: if profile.current_contest is not None:
contest_id = profile.current_contest.contest_id contest_id = profile.current_contest.contest_id
try: try:
contest_problem = form.cleaned_data['problem'].contests.get(contest_id=contest_id) contest_problem = problem.contests.get(contest_id=contest_id)
except ContestProblem.DoesNotExist: except ContestProblem.DoesNotExist:
model = form.save() model = form.save()
else: else:
@ -600,16 +592,8 @@ def problem_submit(request, problem=None, submission=None):
form_data = form.cleaned_data form_data = form.cleaned_data
if submission is not None: if submission is not None:
sub = get_object_or_404(Submission, id=int(submission)) sub = get_object_or_404(Submission, id=int(submission))
if 'problem' not in form_data:
return HttpResponseBadRequest()
else: else:
initial = {'language': profile.language} initial = {'language': profile.language}
if problem is not None:
initial['problem'] = get_object_or_404(Problem, code=problem)
problem_object = initial['problem']
if not problem_object.is_accessible_by(request.user):
raise Http404()
if submission is not None: if submission is not None:
try: try:
sub = get_object_or_404(Submission.objects.select_related('source', 'language'), id=int(submission)) sub = get_object_or_404(Submission.objects.select_related('source', 'language'), id=int(submission))
@ -619,12 +603,10 @@ def problem_submit(request, problem=None, submission=None):
raise Http404() raise Http404()
form = ProblemSubmitForm(judge_choices=judge_choices, initial=initial) form = ProblemSubmitForm(judge_choices=judge_choices, initial=initial)
form_data = initial form_data = initial
if 'problem' in form_data: form.fields['language'].queryset = (
form.fields['language'].queryset = ( problem.usable_languages.order_by('name', 'key')
form_data['problem'].usable_languages.order_by('name', 'key') .prefetch_related(Prefetch('runtimeversion_set', RuntimeVersion.objects.order_by('priority')))
.prefetch_related(Prefetch('runtimeversion_set', RuntimeVersion.objects.order_by('priority'))) )
)
problem_object = form_data['problem']
if 'language' in form_data: if 'language' in form_data:
form.fields['source'].widget.mode = form_data['language'].ace form.fields['source'].widget.mode = form_data['language'].ace
form.fields['source'].widget.theme = profile.ace_theme form.fields['source'].widget.theme = profile.ace_theme
@ -637,7 +619,7 @@ def problem_submit(request, problem=None, submission=None):
submission_limit = submissions_left = None submission_limit = submissions_left = None
if profile.current_contest is not None: if profile.current_contest is not None:
try: try:
submission_limit = problem_object.contests.get(contest=profile.current_contest.contest).max_submissions submission_limit = problem.contests.get(contest=profile.current_contest.contest).max_submissions
except ContestProblem.DoesNotExist: except ContestProblem.DoesNotExist:
pass pass
else: else:
@ -647,19 +629,18 @@ def problem_submit(request, problem=None, submission=None):
return render(request, 'problem/submit.html', { return render(request, 'problem/submit.html', {
'form': form, 'form': form,
'title': _('Submit to %(problem)s') % { 'title': _('Submit to %(problem)s') % {
'problem': problem_object.translated_name(request.LANGUAGE_CODE), 'problem': problem.translated_name(request.LANGUAGE_CODE),
}, },
'content_title': mark_safe(escape(_('Submit to %(problem)s')) % { 'content_title': mark_safe(escape(_('Submit to %(problem)s')) % {
'problem': format_html('<a href="{0}">{1}</a>', 'problem': format_html('<a href="{0}">{1}</a>',
reverse('problem_detail', args=[problem_object.code]), reverse('problem_detail', args=[problem.code]),
problem_object.translated_name(request.LANGUAGE_CODE)), problem.translated_name(request.LANGUAGE_CODE)),
}), }),
'langs': Language.objects.all(), 'langs': Language.objects.all(),
'no_judges': not form.fields['language'].queryset, 'no_judges': not form.fields['language'].queryset,
'submission_limit': submission_limit, 'submission_limit': submission_limit,
'submissions_left': submissions_left, 'submissions_left': submissions_left,
'ACE_URL': settings.ACE_URL, 'ACE_URL': settings.ACE_URL,
'default_lang': default_lang, 'default_lang': default_lang,
}) })

View file

@ -47,7 +47,7 @@
function formatSelection(state) { function formatSelection(state) {
if (!state.id) return state.text; // optgroup if (!state.id) return state.text; // optgroup
var data = makeDisplayData($("option[data-id=" + state.id + "]")); var data = makeDisplayData($("option[data-id=" + state.id + "]"));
return "<b>" + state.text + "</b> (" + data + ")"; return $('<span>').append($('<b>').text(state.text), ' (', data, ')');
} }
// Terrible hack, adapted from https://github.com/select2/select2/issues/4436 // Terrible hack, adapted from https://github.com/select2/select2/issues/4436
@ -71,9 +71,6 @@
$("#id_language").select2({ $("#id_language").select2({
templateResult: format, templateResult: format,
templateSelection: formatSelection, templateSelection: formatSelection,
escapeMarkup: function (m) {
return m;
},
resultsAdapter: customAdapter resultsAdapter: customAdapter
}); });
@ -156,7 +153,7 @@
white-space: nowrap white-space: nowrap
} }
#language-select2 .select2-dropdown--above { #language-select2.select2-dropdown--above {
display: flex; display: flex;
flex-direction: column-reverse; flex-direction: column-reverse;
} }