Cloned DMOJ

This commit is contained in:
thanhluong 2020-01-21 15:35:58 +09:00
parent f623974b58
commit 49dc9ff10c
513 changed files with 132349 additions and 39 deletions

View file

@ -0,0 +1,16 @@
{% extends "base.html" %}
{% block header %}
<span class="submission-info">
<span class="submission-date">{{ submission.date|date(_("N j, Y, g:i a")) }}
{%- if perms.judge.change_submission and submission.judged_on %}
on {{ submission.judged_on.name }}
{% endif %}
<br>
<span>{{ submission.language }}</span>
{% if perms.judge.change_submission %}
[<a href="{{ url('admin:judge_submission_change', submission.id) }}">{{ _('Admin') }}</a>]
{% endif %}
</span>
</span>
{% endblock %}

View file

@ -0,0 +1,18 @@
<h3 style="color:red;font-weight:bold">
{% if request.user == submission.user.user %}
{% trans trimmed %}
An internal error occurred while grading, and the {{ SITE_NAME }} administrators have been notified.<br>
In the meantime, try resubmitting in a few seconds.
{% endtrans %}
{% else %}
{{ _('An internal error occurred while grading.') }}
{% endif %}
</h3>
{% if submission.error and request.user.is_authenticated %}
{% if request.profile.id in submission.problem.editor_ids or perms.judge.edit_all_problem %}
<hr style="float:left;width:30%"><br>
<h4>{{ _('Error information') }}</h4>
<pre><code>{{ submission.error|highlight('pytb') }}</code></pre>
{% endif %}
{% endif %}

View file

@ -0,0 +1,377 @@
{% extends "common-content.html" %}
{% block js_media %}
<script type="text/javascript">
{% if dynamic_update and last_msg %}
{% if request.in_contest %}
window.current_contest = '{{request.participation.contest.key}}';
{% else %}
window.current_contest = null;
{% endif %}
{% if dynamic_user_id %}
window.dynamic_user_id = {{dynamic_user_id}};
{% else %}
window.dynamic_user_id = null;
{% endif %}
{% if dynamic_problem_id %}
window.dynamic_problem_id = {{dynamic_problem_id}};
{% else %}
window.dynamic_problem_id = null;
{% endif %}
{% if show_problem %}
window.show_problem = 1;
{% else %}
window.show_problem = 0;
{% endif %}
{% endif %}
window.results_json = {{ results_json }};
</script>
{% compress js %}
<script type="text/javascript" src="{{ static('event.js') }}"></script>
{% if request.user.is_authenticated and perms.judge.rejudge_submission %}
<script type="text/javascript">
window.rejudge_submission = function (id, e) {
if ((typeof e !== 'undefined' && e.ctrlKey) ||
confirm('Are you sure you want to rejudge?')) {
$.ajax({
url: '{{ url('submission_rejudge') }}',
type: "POST",
data: {
id: id
}
});
}
};
</script>
{% endif %}
<script src="{{ static('libs/chart.js/Chart.js') }}"></script>
<script type="text/javascript">
$(function () {
var info_float = $('.info-float');
var container = $('#content-right');
if (window.bad_browser) {
container.css('float', 'right');
} else if (!featureTest('position', 'sticky')) {
fix_div(info_float, 55);
$(window).resize(function () {
info_float.width(container.width());
});
info_float.width(container.width());
}
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
function idAndTextMatcher(params, data) {
if ($.trim(params.term) === '')
return data;
var regex = new RegExp(escapeRegExp(params.term), 'i');
return data.text.search(regex) >= 0 || data.id.search(regex) >= 0 ? data : null;
}
$('#status').select2({
multiple: 1,
placeholder: '{{ _('Filter by status...') }}',
matcher: idAndTextMatcher,
}).css({'visibility': 'visible'});
$('#language').select2({
multiple: 1,
placeholder: '{{ _('Filter by language...') }}',
matcher: idAndTextMatcher,
}).css({'visibility': 'visible'});
});
// Draw the statistics graph.
var chart = null;
function stats_graph(raw_data) {
var colors = {{ results_colors_json }};
var ctx = $('#status-graph').find('canvas')[0].getContext('2d');
var font = $('body').css('font-family');
if (chart !== null) {
chart.destroy();
}
chart = new Chart(ctx, {
type: 'pie',
data: {
datasets: [{
data: raw_data.categories.map(function(entry) {
return entry.count;
}),
backgroundColor: raw_data.categories.map(function(entry) {
return colors[entry.code];
}),
}],
labels: raw_data.categories.map(function(entry) {
return entry.name;
}),
},
options: {
animation: false,
scaleFontFamily: font,
tooltips: {
titleFontFamily: font,
bodyFontFamily: font,
},
legend: {
display: false,
},
},
});
$('#total-submission-count').text(raw_data.total);
}
$(function () {
stats_graph(window.results_json);
});
function load_dynamic_update(last_msg) {
var _collect = function (e) {
return e.value;
};
var language_filter = $.map($('select#language option[selected]'), _collect);
var status_filter = $.map($('select#status option[selected]'), _collect);
var table = $('#submissions-table');
var statistics = $("#statistics-table");
var doing_ajax = false;
var first = parseInt(table.find('>div:first-child').attr('id'));
var update_submission = function (message, force) {
if (language_filter.length && 'language' in message &&
language_filter.indexOf(message.language) == -1)
return;
if (status_filter.length && 'status' in message &&
status_filter.indexOf(message.status) == -1)
return;
var id = message.id;
var row = table.find('div#' + id);
if (row.length < 1) {
if (id < first)
return;
first = id;
row = $('<div>', {id: id, 'class': 'submission-row'}).hide().prependTo(table);
if (table.find('>div').length >= {{ paginator.per_page }})
table.find('>div:last-child').hide('slow', function () {
$(this).remove();
});
}
if (force || !doing_ajax) {
if (!force) doing_ajax = true;
$.ajax({
url: '{{ url('submission_single_query') }}',
data: {id: id, show_problem: show_problem}
}).done(function (data) {
var was_shown = row.is(':visible');
row.html(data);
register_time(row.find('.time-with-rel'));
if (!was_shown) {
row.slideDown('slow');
}
if (!force)
setTimeout(function () {
doing_ajax = false;
}, 1000);
}).fail(function () {
console.log('Failed to update submission: ' + id);
if (!force) doing_ajax = false;
});
}
};
var stats_outdated = false;
var last_stat_update = Date.now();
var stats_update_interval = {{ stats_update_interval|default(0) * 1000 }};
function update_stats() {
if (Date.now() - last_stat_update < stats_update_interval)
return;
$.ajax({
url: '?results'
}).done(function (data) {
last_stat_update = Date.now();
stats_graph(data);
}).fail(function () {
console.log('Failed to update statistics table!' + id);
}).always(function () {
stats_outdated = false;
});
}
$(window).on('dmoj:window-visible', function () {
if (stats_outdated)
update_stats();
});
var $body = $(document.body);
var receiver = new EventReceiver(
"{{ EVENT_DAEMON_LOCATION }}", "{{ EVENT_DAEMON_POLL_LOCATION }}",
['submissions'], last_msg, function (message) {
if (current_contest && message.contest != current_contest)
return;
if (dynamic_user_id && message.user != dynamic_user_id ||
dynamic_problem_id && message.problem != dynamic_problem_id)
return;
if (message.type == 'update-submission') {
if (message.state == 'test-case' && $body.hasClass('window-hidden'))
return;
update_submission(message);
} else if (message.type == 'done-submission') {
update_submission(message, true);
if (!statistics.length) return;
if ($('body').hasClass('window-hidden'))
return stats_outdated = true;
update_stats();
}
}
);
receiver.onwsclose = function (event) {
if (event.code == 1001) {
console.log('Navigated away');
return;
}
console.log('You probably should refresh?');
$('.ws-closed').show().find('a').click(function () {
window.location.reload();
});
};
return receiver;
}
</script>
{% endcompress %}
{% if dynamic_update and last_msg %}
<script type="text/javascript">
$(function () {
load_dynamic_update({{last_msg}});
});
</script>
{% endif %}
{% endblock %}
{% block title_ruler %}{% endblock %}
{% block title_row %}
{% include "submission/submission-list-tabs.html" %}
{% endblock %}
{% block media %}
{% if perms.judge.change_submission and perms.judge.rejudge_submission %}
<style>
td.sub-prop, col.sub-prop {
width: 22%
}
col.sub-info, td.sub-info {
width: 78%
}
#status, #language {
visibility: hidden;
}
</style>
{% endif %}
<style>
.total {
text-align: center;
margin-bottom: 0.5em;
}
#status-graph {
padding: 1em 0em;
}
#status-graph canvas {
display: block;
margin: 0 auto;
}
</style>
{% endblock %}
{% block body %}
{% if page_obj.num_pages > 1 %}
<div style="margin-bottom: 6px; margin-top: 11px">
{% include "list-pages.html" %}
</div>
{% endif %}
<div id="common-content">
<div id="content-right" class="submission">
<div class="info-float">
<div class="sidebox">
<h3>{{ _('Filter submissions') }} <i class="fa fa-search"></i></h3>
<div class="sidebox-content">
<form id="filter-form" name="form" action="" method="get">
<div class="filter-form-group">
<label for="status"><i>{{ _('Status') }}</i></label>
<select id="status" name="status" multiple>
{% for id, name in all_statuses %}
<option {% if id in selected_statuses %}selected{% endif %}
value="{{ id }}">{{ name }}</option>
{% endfor %}
</select>
</div>
<div class="filter-form-group">
<label for="language"><i>{{ _('Language') }}</i></label>
<select id="language" name="language" multiple>
{% for code, name in all_languages %}
<option {% if code in selected_languages %}selected{% endif %}
value="{{ code }}">{{ name }}</option>
{% endfor %}
</select>
</div>
<div class="form-submit-group">
<a id="go" onclick="form.submit()" class="button">{{ _('Go') }}</a>
</div>
</form>
</div>
</div>
<div class="sidebox">
<div id="statistics-table">
<h3>{{ _('Statistics') }} <i class="fa fa-pie-chart"></i></h3>
<div class="sidebox-content">
<div id="status-graph">
<canvas width="230" height="170"></canvas>
</div>
<div class="total">
{{ _('Total:') }} <span id="total-submission-count"></span>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="content-left" class="submission">
<div class="ws-closed">
<a href="javascript:void(0)">{{ _('You were disconnected. Refresh to show latest updates.') }}</a>
</div>
<div id="submissions-table">
{% set profile_id = request.profile.id if request.user.is_authenticated else 0 %}
{% for submission in submissions %}
<div class="submission-row" id="{{ submission.id }}">
{% with problem_name=show_problem and submission.problem.i18n_name %}
{% include "submission/row.html" %}
{% endwith %}
</div>
{% endfor %}
</div>
{% if page_obj.num_pages > 1 %}
<div style="margin-top:10px;">{% include "list-pages.html" %}</div>
{% endif %}
</div>
</div>
{% endblock %}
{% block bodyend %}
{# Don't load MathJax from common-content! #}
{% endblock %}

View file

@ -0,0 +1,79 @@
{% set can_view = submission_layout(submission, profile_id, request.user, editable_problem_ids, completed_problem_ids) %}
<div class="sub-result {{ submission.result_class }}">
<div class="score">
{%- if submission.is_graded -%}
{%- if submission.status in ('IE', 'CE', 'AB') -%}
---
{%- else -%}
{{ submission.case_points|floatformat(0) }} / {{ submission.case_total|floatformat(0) }}
{%- endif -%}
{%- else -%}
<i class="fa fa-spinner fa-pulse"></i>
{%- endif -%}
</div>
<div class="state">
<span title="{{ submission.long_status }}" class="status">{{ submission.short_status }}</span> |
<span class="language">{{ submission.language.short_display_name }}</span>
</div>
</div>
<div class="sub-info{% if submission.status == 'G' %} sub-info-grading{% endif %}">
{% if show_problem %}
<div class="name"><a href="{{ url('problem_detail', submission.problem.code) }}">{{ problem_name }}</a></div>
{% endif %}
<div>
{{ link_user(submission.user) }}
<span class="time">{{ relative_time(submission.date) }}</span>
{% if not request.in_contest and submission.contest_object_id %}
<a href="{{ url('contest_view', submission.contest_object.key) }}"
class="submission-contest">
<i title="{{ submission.contest_object.name }}" class="fa fa-dot-circle-o"></i>
</a>
{% endif %}
</div>
</div>
{% if submission.status == 'G' %}
<div class="sub-testcase">
{%- if submission.current_testcase > 0 -%}
{{ _('Case #%(case)s', case=submission.current_testcase) }}
{%- else -%}
...
{%- endif -%}
</div>
{% endif %}
{% if can_view %}
<div class="sub-prop"><div>
<a href="{{ url('submission_status', submission.id) }}">
<i class="fa fa-eye fa-fw"></i><span class="label">{{ _('view') }}</span>
</a>
{% if perms.judge.rejudge_submission %} ·
<a href="#" onclick="rejudge_submission({{ submission.id }}, event);return false">
<i class="fa fa-refresh fa-fw"></i><span class="label">{{ _('rejudge') }}</span>
</a>
{% endif %}
{% if perms.judge.change_submission %} ·
<a href="{{ url('admin:judge_submission_change', submission.id) }}">
<i class="fa fa-cog fa-fw"></i><span class="label">{{ _('admin') }}</span>
</a>
{% endif %}
</div></div>
{% endif %}
<div class="sub-usage">
{% if submission.status in ('QU', 'P', 'G', 'CE', 'IE', 'AB') %}
<div class="time">---</div>
<div class="memory">---</div>
{% else %}
{% if "TLE" != submission.result %}
<div title="{{ submission.time or 0 }}s" class="time">
{{ (submission.time or 0)|floatformat(2) }}s
</div>
{% else %}
<div class="time">---</div>
{% endif %}
{# No one actually like IEC prefixes, Jinja2. #}
<div class="memory">{{ (submission.memory_bytes|filesizeformat(True)).replace('i', '') }}</div>
{% endif %}
</div>

View file

@ -0,0 +1,59 @@
{% extends "submission/info-base.html" %}
{% block media %}
<style>
.line {
position: relative;
}
.highlighter {
position: absolute;
width: 9999px;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
a:active .line .highlighter {
background: rgba(255, 212, 0, 0.48);
}
</style>
{% endblock %}
{% block body %}
<br>
<div><a href="{{ url('submission_status', submission.id) }}">{{ _('View status') }}</a></div>
<div><a href="{{ url('submission_source_raw', submission.id) }}">{{ _('View raw source') }}</a></div>
{% if request.user == submission.user.user or perms.judge.resubmit_other %}
<div><a href="{{ url('problem_submit', submission.problem.code, submission.id) }}">{{ _('Resubmit') }}</a></div>
{% endif %}
{% if perms.judge.rejudge_submission %}
<div>
<form action="{{ url('submission_rejudge') }}" method="post">
{% csrf_token %}
<a href="#" onclick="parentNode.submit()">{{ _('Rejudge') }}</a>
<input type="hidden" name="id" value="{{ submission.id }}">
<input type="hidden" name="path" value="{{ url('submission_status', submission.id) }}">
</form>
</div>
{% endif %}
<br>
<hr class="half-hr">
<br>
<div class="source-wrap">
<table>
<tr>
<td class="source-ln">
<div>
{% for line in raw_source.split('\n') %}
<a href="#line-{{ loop.index }}" name="line-{{ loop.index }}">
<pre class="line">{{ loop.index }}</pre>
</a>
{% endfor %}
</div>
</td>
<td class="source-code">{{ highlighted_source }}</td>
</tr>
</table>
</div>
{% endblock %}

View file

@ -0,0 +1,141 @@
{% if submission.contest_or_none %}
{% set prefix_length = submission.contest_or_none.problem.output_prefix_override %}
{% else %}
{% set prefix_length = None %}
{% endif %}
{% set is_pretest = submission.is_pretested %}
{% if submission.status != 'IE' %}
{% if submission.status == 'QU' %}
<h4>{{ _('We are waiting for a suitable judge to process your submission...') }}</h4>
{% elif submission.status == 'P' %}
<h4>{{ _('Your submission is being processed...') }}</h4>
{% elif submission.status == 'CE' %}
<h3>{{ _('Compilation Error') }}</h3>
<pre>{{ submission.error|ansi2html }}</pre>
{% else %}
{% if submission.error %}
<h3>{{ _('Compilation Warnings') }}</h3>
<pre>{{ submission.error|ansi2html }}</pre>
<hr class="half-hr"><br>
{% endif %}
{% if is_pretest %}
<h3>{{ _('Pretest Execution Results') }}</h3>
{% else %}
<h3>{{ _('Execution Results') }}</h3>
{% endif %}
<br>
{% set test_case_id = counter() %}
{% for batch in batches %}
{% if batch.id %}
<b>{{ _('Batch ') }}#{{ test_case_id() }}</b>
({{ _('%(points)s/%(total)s points', points=batch.points|floatformat(0), total=batch.total|floatformat(0)) }})
<br>
<div class="batch-cases">
{% endif %}
<table>{% for case in batch.cases %}
<tr id="{{ case.id }}" class="case-row toggle closed">
<td>
{%- if case.status != 'AC' and case.output and (prefix_length is none or prefix_length > 0) -%}
<i class="fa fa-chevron-right fa-fw"></i>
{%- endif -%}
{%- if batch.id -%}
<b>{{ _('Case') }} #{{ loop.index }}:</b>
{%- elif is_pretest -%}
<b>{{ _('Pretest') }} #{{ test_case_id() }}:</b>
{%- else -%}
<b>{{ _('Test case') }} #{{ test_case_id() }}:</b>
{%- endif -%}
</td>
<td>
<span title="{{ case.long_status }}" class="case-{{ case.status }}">
{%- if case.status == 'SC' %}&mdash;{% else %}{{ case.status }}{% endif -%}
</span>
{%- if case.feedback %}&nbsp;({{ case.feedback }}){% endif -%}
</td>
<td>
{%- if case.status != 'SC' -%}
{%- if case.status == 'TLE' -%}
[&gt;<span>{{ time_limit|floatformat(3) }}s,</span>
{%- else -%}
[<span title="{{ case.time }}s">{{ case.time|floatformat(3) }}s,</span>
{%- endif -%}
{%- endif -%}
</td>
<td>{% if case.status != 'SC' %}{{ case.memory|kbdetailformat }}]{% endif %}</td>
{% if not batch.id %}
<td>({{ case.points|floatformat(0) }}/{{ case.total|floatformat(0) }})</td>
{% endif %}
</tr>
{% if case.status != 'AC' and case.output and (prefix_length is none or prefix_length > 0) %}
<tr id="{{ case.id }}-output" style="display:none" class="case-feedback toggled">
<td colspan="5">
<div class="case-info">
<strong>{{ _('Your output (clipped)') }}</strong>
{% if prefix_length is none %}
<pre class="case-output">{{ case.output|linebreaksbr }}</pre>
{% else %}
<pre class="case-output">{{ case.output[:prefix_length]|linebreaksbr }}</pre>
{% endif %}
</div>
</td>
{% if case.extended_feedback %}
<td colspan="5" class="case-ext-feedback">
<div class="case-info">
<strong>{{ _('Judge feedback') }}</strong>
<pre class="case-output">{{ case.extended_feedback|linebreaksbr }}</pre>
</div>
</td>
{% endif %}
</tr>
{% endif %}
{% endfor %}
</table>
{% if batch.id %}</div>{% endif %}
<br>
{% endfor %}
{% if submission.is_graded %}
<br>
{% if submission.result != "AB" %}
<b>{{ _('Resources:') }}</b>
{% if submission.result == "TLE" %}
<span>---,</span>
{% else %}
<span title="{{ submission.time }}s">{{ submission.time|floatformat(3) }}s,</span>
{% endif %}
{{ submission.memory|kbdetailformat }}
<br>
{% if is_pretest %}
<b>{{ _('Final pretest score:') }}</b>
{% else %}
<b>{{ _('Final score:') }}</b>
{% endif %}
{{ submission.case_points|floatformat(0) }}/{{ submission.case_total|floatformat(0) }}
{% if request.in_contest and submission.contest_or_none %}
{% with contest=submission.contest_or_none %}
({{ _('%(points)s/%(total)s points', points=contest.points|roundfloat(3),
total=contest.problem.points|floatformat(-1)) }})
{% endwith %}
{% else %}
({{ _('%(points)s/%(total)s points', points=submission.points|roundfloat(3),
total=submission.problem.points|floatformat(-1)) }})
{% endif %}
{% if is_pretest and submission.result == "AC" %}
<br>
<i>{{ _('Passing pretests does not guarantee a full score on system tests.') }}</i>
{% endif %}
{% else %}
<b>{{ _('Submission aborted!') }}</b>
{% endif %}
<br>
{% endif %}
{% endif %}
{% else %}
{% include "submission/internal-error-message.html" %}
{% endif %}

View file

@ -0,0 +1,94 @@
{% extends "submission/info-base.html" %}
{% block js_media %}
<script type="text/javascript" src="{{ static('event.js') }}"></script>
{% if not submission.is_graded and last_msg %}
<script type="text/javascript">$(function () {
var blocked = false, request = false;
var list = $('#test-cases');
function update() {
if (blocked) {
request = true;
return;
}
request = false;
blocked = true;
$.ajax({
url: '{{ url('submission_testcases_query') }}',
data: {id: '{{ submission.id }}'}
}).done(function (data) {
list.empty().html(data).find('.toggle').each(function () {
register_toggle($(this));
});
setTimeout(function () {
blocked = false;
if (request)
update();
}, 500);
}).fail(function (data) {
console.log('Failed to update testcases!');
});
if ($(window).scrollTop() + $(window).height() > $(document).height() - 100)
$("html, body").animate({scrollTop: $(document).height()}, 0);
}
var receiver = new EventReceiver(
"{{ EVENT_DAEMON_LOCATION }}", "{{ EVENT_DAEMON_POLL_LOCATION }}",
['sub_{{ submission.id_secret }}'], {{ last_msg }}, function (message) {
switch (message.type) {
case 'internal-error':
case 'grading-end':
case 'compile-error':
$('#abort-button').remove();
$('#grading-label').remove();
case 'test-case':
case 'grading-begin':
case 'processing':
update();
}
}
)
});
</script>
{% endif %}
{% endblock %}
{% block body %}
<br>
<div><a href="{{ url('submission_source', submission.id) }}">{{ _('View source') }}</a></div>
{% if request.user == submission.user.user or perms.judge.resubmit_other %}
<div><a href="{{ url('problem_submit', submission.problem.code, submission.id) }}">{{ _('Resubmit') }}</a></div>
{% endif %}
{% if perms.judge.rejudge_submission %}
<div>
<form action="{{ url('submission_rejudge') }}" method="post">
{% csrf_token %}
<a href="#" onclick="parentNode.submit()">{{ _('Rejudge') }}</a>
<input type="hidden" name="id" value="{{ submission.id }}">
<input type="hidden" name="path" value="{{ url('submission_status', submission.id) }}">
</form>
</div>
{% endif %}
<br>
<hr class="half-hr">
<br>
<div id="test-cases">{% include "submission/status-testcases.html" %}</div>
{% if not submission.is_graded %}
{% if request.user == submission.user.user or perms.judge.abort_any_submission %}
<div id="abort-button">
<br>
<hr class="half-hr">
<br>
<form action="{{ url('submission_abort', submission.id) }}" method="post">
{% csrf_token %}
<input style="float:left" type="submit" value="{{ _('Abort') }}" class="button">
<br><br>
</form>
</div>
{% endif %}
{% endif %}
{% endblock %}

View file

@ -0,0 +1,17 @@
{% extends "tabs-base.html" %}
{% block tabs %}
{{ make_tab('all_submissions_list', 'fa-list', all_submissions_link, _('All')) }}
{% if my_submissions_link or tab == 'my_submissions_tab' %}
{{ make_tab('my_submissions_tab', 'fa-user', my_submissions_link, _('Mine')) }}
{% endif %}
{% if best_submissions_link %}
{{ make_tab('best_submissions_list', 'fa-bar-chart', best_submissions_link, _('Best')) }}
{% endif %}
{% if tab == 'user_submissions_tab' %}
{{ make_tab('user_submissions_tab', 'fa-user', None, _("%(user)s's", user=tab_username)) }}
{% endif %}
{% if perms.judge.change_submission %}
{{ make_tab('admin', 'fa-edit', url('admin:judge_submission_changelist'), _('Admin')) }}
{% endif %}
{% endblock %}