Move download submissions to manage submissions page

This commit is contained in:
cuom1999 2020-11-25 13:21:53 -06:00
parent aeed1814b3
commit 3ef47518ee
5 changed files with 77 additions and 59 deletions

View file

@ -119,7 +119,6 @@ urlpatterns = [
url(r'^/pdf$', problem.ProblemPdfView.as_view(), name='problem_pdf'), url(r'^/pdf$', problem.ProblemPdfView.as_view(), name='problem_pdf'),
url(r'^/pdf/(?P<language>[a-z-]+)$', problem.ProblemPdfView.as_view(), name='problem_pdf'), url(r'^/pdf/(?P<language>[a-z-]+)$', problem.ProblemPdfView.as_view(), name='problem_pdf'),
url(r'^/clone', problem.ProblemClone.as_view(), name='problem_clone'), url(r'^/clone', problem.ProblemClone.as_view(), name='problem_clone'),
url(r'^/downloadAC$', problem.download_submissions, name='download_submissions'),
url(r'^/submit$', problem.problem_submit, name='problem_submit'), url(r'^/submit$', problem.problem_submit, name='problem_submit'),
url(r'^/resubmit/(?P<submission>\d+)$', problem.problem_submit, name='problem_submit'), url(r'^/resubmit/(?P<submission>\d+)$', problem.problem_submit, name='problem_submit'),
@ -139,8 +138,8 @@ urlpatterns = [
url(r'^/manage/submission', include([ url(r'^/manage/submission', include([
url('^$', problem_manage.ManageProblemSubmissionView.as_view(), name='problem_manage_submissions'), url('^$', problem_manage.ManageProblemSubmissionView.as_view(), name='problem_manage_submissions'),
url('^/rejudge$', problem_manage.RejudgeSubmissionsView.as_view(), name='problem_submissions_rejudge'), url('^/action$', problem_manage.ActionSubmissionsView.as_view(), name='problem_submissions_action'),
url('^/rejudge/preview$', problem_manage.PreviewRejudgeSubmissionsView.as_view(), url('^/action/preview$', problem_manage.PreviewActionSubmissionsView.as_view(),
name='problem_submissions_rejudge_preview'), name='problem_submissions_rejudge_preview'),
url('^/rejudge/success/(?P<task_id>[A-Za-z0-9-]*)$', problem_manage.rejudge_success, url('^/rejudge/success/(?P<task_id>[A-Za-z0-9-]*)$', problem_manage.rejudge_success,
name='problem_submissions_rejudge_success'), name='problem_submissions_rejudge_success'),

View file

@ -4,7 +4,6 @@ import shutil
from datetime import timedelta from datetime import timedelta
from operator import itemgetter from operator import itemgetter
from random import randrange from random import randrange
import zipfile, tempfile
from django.conf import settings from django.conf import settings
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
@ -678,24 +677,3 @@ class ProblemClone(ProblemMixin, PermissionRequiredMixin, TitleMixin, SingleObje
problem.types.set(types) problem.types.set(types)
return HttpResponseRedirect(reverse('admin:judge_problem_change', args=(problem.id,))) return HttpResponseRedirect(reverse('admin:judge_problem_change', args=(problem.id,)))
def download_submissions(request, problem):
if not request.user.is_superuser:
raise Http404
submissions = Submission.objects.filter(problem__code=problem, result='AC')
with tempfile.SpooledTemporaryFile() as tmp:
with zipfile.ZipFile(tmp, 'w', zipfile.ZIP_DEFLATED) as archive:
for submission in submissions:
file_name = str(submission.id) + '.' + str(submission.language.key)
archive.writestr(file_name, submission.source.source)
# Reset file pointer
tmp.seek(0)
# Write file data to response
response = HttpResponse(tmp.read(), content_type='application/x-zip-compressed')
response['Content-Disposition'] = 'attachment; filename="%s"' % (str(problem) + '_submissions.zip')
return response

View file

@ -1,5 +1,7 @@
from operator import itemgetter from operator import itemgetter
import zipfile, tempfile
from celery.result import AsyncResult from celery.result import AsyncResult
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
@ -63,7 +65,7 @@ class ManageProblemSubmissionView(TitleMixin, ManageProblemSubmissionMixin, Deta
return context return context
class BaseRejudgeSubmissionsView(PermissionRequiredMixin, ManageProblemSubmissionActionMixin, BaseDetailView): class BaseActionSubmissionsView(PermissionRequiredMixin, ManageProblemSubmissionActionMixin, BaseDetailView):
permission_required = 'judge.rejudge_submission_lot' permission_required = 'judge.rejudge_submission_lot'
def perform_action(self): def perform_action(self):
@ -88,16 +90,45 @@ class BaseRejudgeSubmissionsView(PermissionRequiredMixin, ManageProblemSubmissio
raise NotImplementedError() raise NotImplementedError()
class RejudgeSubmissionsView(BaseRejudgeSubmissionsView): class ActionSubmissionsView(BaseActionSubmissionsView):
def generate_response(self, id_range, languages, results): def rejudge_response(self, id_range, languages, results):
status = rejudge_problem_filter.delay(self.object.id, id_range, languages, results) status = rejudge_problem_filter.delay(self.object.id, id_range, languages, results)
return redirect_to_task_status( return redirect_to_task_status(
status, message=_('Rejudging selected submissions for %s...') % (self.object.name,), status, message=_('Rejudging selected submissions for %s...') % (self.object.name,),
redirect=reverse('problem_submissions_rejudge_success', args=[self.object.code, status.id]), redirect=reverse('problem_submissions_rejudge_success', args=[self.object.code, status.id]),
) )
def download_response(self, id_range, languages, results):
if not self.request.user.is_superuser:
raise Http404
class PreviewRejudgeSubmissionsView(BaseRejudgeSubmissionsView): queryset = Submission.objects.filter(problem_id=self.object.id)
submissions = apply_submission_filter(queryset, id_range, languages, results)
with tempfile.SpooledTemporaryFile() as tmp:
with zipfile.ZipFile(tmp, 'w', zipfile.ZIP_DEFLATED) as archive:
for submission in submissions:
file_name = str(submission.id) + '_' + str(submission.user) + '.' + str(submission.language.key)
archive.writestr(file_name, submission.source.source)
# Reset file pointer
tmp.seek(0)
# Write file data to response
response = HttpResponse(tmp.read(), content_type='application/x-zip-compressed')
response['Content-Disposition'] = 'attachment; filename="%s"' % (str(self.object.code) + '_submissions.zip')
return response
def generate_response(self, id_range, languages, results):
action = self.request.POST.get('action')
if (action == 'rejudge'):
return self.rejudge_response(id_range, languages, results)
elif (action == 'download'):
return self.download_response(id_range, languages, results)
else:
return Http404()
class PreviewActionSubmissionsView(BaseActionSubmissionsView):
def generate_response(self, id_range, languages, results): def generate_response(self, id_range, languages, results):
queryset = apply_submission_filter(self.object.submission_set.all(), id_range, languages, results) queryset = apply_submission_filter(self.object.submission_set.all(), id_range, languages, results)
return HttpResponse(str(queryset.count())) return HttpResponse(str(queryset.count()))

View file

@ -10,7 +10,7 @@
.pane { .pane {
display: block; display: block;
max-width: 20em; max-width: 25em;
border: 1px #ccc solid; border: 1px #ccc solid;
border-radius: 5px; border-radius: 5px;
padding: 10px; padding: 10px;
@ -70,7 +70,8 @@
var $use_id = $('#by-range-check'); var $use_id = $('#by-range-check');
var $id_start = $('#by-range-start'); var $id_start = $('#by-range-start');
var $id_end = $('#by-range-end'); var $id_end = $('#by-range-end');
$('#rejudge-selected').click(function (e) {
var actionClick = function (e) {
e.preventDefault(); e.preventDefault();
if ($use_id.prop('checked')) { if ($use_id.prop('checked')) {
var start = parseInt($id_start.val()); var start = parseInt($id_start.val());
@ -84,24 +85,35 @@
} }
} }
var $form = $(this).parents('form'); var $form = $('#form-action');
var input = $("<input>")
.attr("type", "hidden")
.attr("name", "action").val(e.data.action);
$form.append(input);
$.post('{{ url('problem_submissions_rejudge_preview', problem.code) }}', $form.serialize(), 'text') $.post('{{ url('problem_submissions_rejudge_preview', problem.code) }}', $form.serialize(), 'text')
.done(function (count) { .done(function (count) {
if (confirm("{{ _('You are about to rejudge {count} submissions. Are you sure you want to do this?') }}" if (confirm("{{ _('You are about to {action} {count} submissions. Are you sure you want to do this?') }}"
.replace('{count}', count))) { .replace('{count}', count)
.replace('{action}', e.data.action))) {
$form.submit(); $form.submit();
} }
}) })
.fail(function () { .fail(function () {
if (confirm("{{ _('You are about to rejudge a few submissions. Are you sure you want to do this?') }}")) { if (confirm("{{ _('You are about to {action} a few submissions. Are you sure you want to do this?') }}".replace('{action}', e.data.action))) {
$form.submit(); $form.submit();
} }
}); });
}); };
$('#rejudge-selected').on('click', {action: 'rejudge'}, actionClick);
$('#download-selected').on('click', {action: 'download'}, actionClick);
$use_id.change(function () { $use_id.change(function () {
$('#by-range-filter').find('input').prop('disabled', !this.checked); $('#by-range-filter').find('input').prop('disabled', !this.checked);
}); });
}); });
</script> </script>
{% endblock %} {% endblock %}
@ -112,8 +124,8 @@
<div class="panes"> <div class="panes">
{% if request.user.has_perm('judge.rejudge_submission_lot') %} {% if request.user.has_perm('judge.rejudge_submission_lot') %}
<div class="pane"> <div class="pane">
<h3>{{ _('Rejudge Submissions') }}</h3> <h3>{{ _('Filter submissions') }}</h3>
<form action="{{ url('problem_submissions_rejudge', problem.code) }}" method="post"> <form action="{{ url('problem_submissions_action', problem.code) }}" method="post" id="form-action">
{% csrf_token %} {% csrf_token %}
<div class="control-group"> <div class="control-group">
<label><input id="by-range-check" type="checkbox" name="use_range" value="on"> <label><input id="by-range-check" type="checkbox" name="use_range" value="on">
@ -146,16 +158,19 @@
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
</form>
</div>
<div class="pane">
<h3> {{ _('Action') }} </h3>
<a id="rejudge-selected" class="unselectable button full" href="#"> <a id="rejudge-selected" class="unselectable button full" href="#">
{{ _('Rejudge selected submissions') }} {{ _('Rejudge selected submissions') }}
</a> </a>
</form> </br>
</div>
{% endif %}
<div class="pane"> <a id="download-selected" class="unselectable button full" href="#">
<h3>{{ _('Rescore Everything') }}</h3> {{ _('Download selected submissions') }}
<p id="rescore-warning">{{ _('This will rescore %(count)d submissions.', count=submission_count) }}</p> </a>
<br>
<form action="{{ url('problem_submissions_rescore_all', problem.code) }}" method="post"> <form action="{{ url('problem_submissions_rescore_all', problem.code) }}" method="post">
{% csrf_token %} {% csrf_token %}
<a id="rescore-all" class="unselectable button full" href="#" <a id="rescore-all" class="unselectable button full" href="#"
@ -164,5 +179,6 @@
</a> </a>
</form> </form>
</div> </div>
{% endif %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -126,12 +126,6 @@
{% endif %} {% endif %}
<div><a href="{{ url('chronological_submissions', problem.code) }}">{{ _('All submissions') }}</a></div> <div><a href="{{ url('chronological_submissions', problem.code) }}">{{ _('All submissions') }}</a></div>
<div><a href="{{ url('ranked_submissions', problem.code) }}">{{ _('Best submissions') }}</a></div> <div><a href="{{ url('ranked_submissions', problem.code) }}">{{ _('Best submissions') }}</a></div>
{% if request.user.is_superuser %}
<div>
<a href="{{ url('download_submissions', problem.code) }}"> {{ _('Download AC submissions') }} </a>
</div>
{% endif %}
{% if editorial and editorial.is_public and {% if editorial and editorial.is_public and
not (request.user.is_authenticated and request.profile.current_contest) %} not (request.user.is_authenticated and request.profile.current_contest) %}
<hr> <hr>