mirror of
https://github.com/DMOJ/online-judge.git
synced 2024-11-25 16:32:37 +08:00
Add batch dependencies to site data interface
This commit is contained in:
parent
61318c7e71
commit
435839e6b3
18
judge/migrations/0145_site_data_batch_prerequisites.py
Normal file
18
judge/migrations/0145_site_data_batch_prerequisites.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.21 on 2024-01-06 04:33
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('judge', '0144_submission_index_cleanup'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='problemtestcase',
|
||||
name='batch_dependencies',
|
||||
field=models.TextField(blank=True, help_text='batch dependencies as a comma-separated list of integers', verbose_name='batch dependencies'),
|
||||
),
|
||||
]
|
@ -93,4 +93,6 @@ class ProblemTestCase(models.Model):
|
||||
output_limit = models.IntegerField(verbose_name=_('output limit length'), blank=True, null=True)
|
||||
checker = models.CharField(max_length=10, verbose_name=_('checker'), choices=CHECKERS, blank=True)
|
||||
checker_args = models.TextField(verbose_name=_('checker arguments'), blank=True,
|
||||
help_text=_('Checker arguments as a JSON object.'))
|
||||
help_text=_('checker arguments as a JSON object'))
|
||||
batch_dependencies = models.TextField(verbose_name=_('batch dependencies'), blank=True,
|
||||
help_text=_('batch dependencies as a comma-separated list of integers'))
|
||||
|
@ -57,6 +57,7 @@ class ProblemDataCompiler(object):
|
||||
def make_init(self):
|
||||
cases = []
|
||||
batch = None
|
||||
batch_count = 0
|
||||
|
||||
def end_batch():
|
||||
if not batch['batched']:
|
||||
@ -109,14 +110,31 @@ class ProblemDataCompiler(object):
|
||||
case.save(update_fields=('checker_args', 'is_pretest'))
|
||||
(batch['batched'] if batch else cases).append(data)
|
||||
elif case.type == 'S':
|
||||
batch_count += 1
|
||||
if batch:
|
||||
end_batch()
|
||||
if case.points is None:
|
||||
raise ProblemDataError(_('Batch start case #%d requires points.') % i)
|
||||
dependencies = []
|
||||
if case.batch_dependencies.strip():
|
||||
try:
|
||||
dependencies = list(map(int, case.batch_dependencies.split(',')))
|
||||
except ValueError:
|
||||
raise ProblemDataError(
|
||||
_('Dependencies must be a comma-separated list of integers for batch start case #%d.') % i,
|
||||
)
|
||||
for batch_number in dependencies:
|
||||
if batch_number >= batch_count:
|
||||
raise ProblemDataError(
|
||||
_('Dependencies must depend on previous batches for batch start case #%d.') % i,
|
||||
)
|
||||
elif batch_number < 1:
|
||||
raise ProblemDataError(_('Dependencies must be positive for batch start case #%d.') % i)
|
||||
batch = {
|
||||
'points': case.points,
|
||||
'batched': [],
|
||||
'is_pretest': case.is_pretest,
|
||||
'dependencies': dependencies,
|
||||
}
|
||||
if case.generator_args:
|
||||
batch['generator_args'] = case.generator_args.splitlines()
|
||||
|
@ -75,10 +75,11 @@ class ProblemCaseForm(ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = ProblemTestCase
|
||||
fields = ('order', 'type', 'input_file', 'output_file', 'points',
|
||||
'is_pretest', 'output_limit', 'output_prefix', 'checker', 'checker_args', 'generator_args')
|
||||
fields = ('order', 'type', 'input_file', 'output_file', 'points', 'is_pretest', 'output_limit',
|
||||
'output_prefix', 'checker', 'checker_args', 'generator_args', 'batch_dependencies')
|
||||
widgets = {
|
||||
'generator_args': HiddenInput,
|
||||
'batch_dependencies': HiddenInput,
|
||||
'type': Select(attrs={'style': 'width: 100%'}),
|
||||
'points': NumberInput(attrs={'style': 'width: 4em'}),
|
||||
'output_prefix': NumberInput(attrs={'style': 'width: 4.5em'}),
|
||||
|
@ -125,37 +125,42 @@
|
||||
.find('input[id$=points], input[id$=pretest]').toggle(!disabled);
|
||||
}).change();
|
||||
|
||||
var tooltip_classes = 'tooltipped tooltipped-s';
|
||||
$tr.find('a.edit-generator-args').mouseover(function () {
|
||||
switch ($tr.attr('data-type')) {
|
||||
case 'C':
|
||||
case 'S':
|
||||
var $this = $(this).addClass(tooltip_classes);
|
||||
$this.attr('aria-label', $this.prev().val() || '(none)');
|
||||
}
|
||||
}).mouseout(function () {
|
||||
$(this).removeClass(tooltip_classes).removeAttr('aria-label');
|
||||
}).featherlight($('.generator-args-editor'), {
|
||||
beforeOpen: function () {
|
||||
function addToolTip(linkClass, editorClass) {
|
||||
var tooltip_classes = 'tooltipped tooltipped-s';
|
||||
$tr.find(linkClass).mouseover(function () {
|
||||
switch ($tr.attr('data-type')) {
|
||||
case 'C':
|
||||
case 'S':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
var $this = $(this).addClass(tooltip_classes);
|
||||
$this.attr('aria-label', $this.prev().val() || '(none)');
|
||||
}
|
||||
},
|
||||
afterOpen: function () {
|
||||
var $input = this.$currentTarget.prev();
|
||||
this.$instance.find('.generator-args-editor')
|
||||
}).mouseout(function () {
|
||||
$(this).removeClass(tooltip_classes).removeAttr('aria-label');
|
||||
}).featherlight($(editorClass), {
|
||||
beforeOpen: function () {
|
||||
switch ($tr.attr('data-type')) {
|
||||
case 'C':
|
||||
case 'S':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
afterOpen: function () {
|
||||
var $input = this.$currentTarget.prev();
|
||||
this.$instance.find(editorClass)
|
||||
.find('textarea').val($input.val()).end()
|
||||
.find('.button').click(function () {
|
||||
$input.val($(this).prev().val());
|
||||
$.featherlight.current().close();
|
||||
}).end()
|
||||
$input.val($(this).prev().val());
|
||||
$.featherlight.current().close();
|
||||
}).end()
|
||||
.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addToolTip('a.edit-generator-args', '.generator-args-editor');
|
||||
addToolTip('a.edit-batch-dependencies', '.batch-dependencies-editor');
|
||||
|
||||
checker_precision($tr.find('select[id$=checker]'));
|
||||
}).find('tbody:first').find('tr').each(function () {
|
||||
@ -300,18 +305,18 @@
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.edit-generator-args {
|
||||
.edit-generator-args, .edit-batch-dependencies {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.generator-args-editor textarea {
|
||||
.generator-args-editor textarea, .batch-dependencies-editor textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-bottom: 0.5em;
|
||||
height: 8em;
|
||||
}
|
||||
|
||||
.generator-args-editor .button {
|
||||
.generator-args-editor .button, .batch-dependencies-editor .button {
|
||||
display: block;
|
||||
float: right;
|
||||
}
|
||||
@ -370,6 +375,10 @@
|
||||
<input type="checkbox" data-suffix="generator_args">
|
||||
{{ _('Generator args') }}
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" data-suffix="batch_dependencies">
|
||||
{{ _('Batch dependencies') }}
|
||||
</label>
|
||||
</div>
|
||||
<table id="case-table" class="table">
|
||||
<thead>
|
||||
@ -384,6 +393,7 @@
|
||||
<th class="output-limit">{{ _('Output limit') }}</th>
|
||||
<th class="checker">{{ _('Checker') }}</th>
|
||||
<th class="generator-args">{{ _('Generator args') }}</th>
|
||||
<th class="batch-dependencies">{{ _('Batch Dependencies') }}</th>
|
||||
{% if cases_formset.can_delete %}
|
||||
<th>{{ _('Delete?') }}</th>
|
||||
{% endif %}
|
||||
@ -424,6 +434,12 @@
|
||||
{{ _('Edit') }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="batch-dependencies">{{ form.batch_dependencies.errors }}{{ form.batch_dependencies }}
|
||||
<a href="javascript:void(0)" class="edit-batch-dependencies">
|
||||
<i class="fa fa-pencil"></i>
|
||||
{{ _('Edit') }}
|
||||
</a>
|
||||
</td>
|
||||
{% if cases_formset.can_delete %}
|
||||
<td>{{ form.DELETE }}</td>
|
||||
{% endif %}
|
||||
@ -435,4 +451,5 @@
|
||||
<a id="add-case-row" href="#"><i class="fa fa-plus"></i> {{ _('Add new case') }}</a>
|
||||
</form>
|
||||
<div style="display: none" class="generator-args-editor"><textarea></textarea><a class="button">{{ _('Save') }}</a></div>
|
||||
<div style="display: none" class="batch-dependencies-editor"><textarea></textarea><a class="button">{{ _('Save') }}</a></div>
|
||||
{% endblock %}
|
||||
|
Loading…
Reference in New Issue
Block a user