Make submit form work
This commit is contained in:
parent
3629369fba
commit
6f25762ffa
2 changed files with 31 additions and 53 deletions
|
@ -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,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue