Add batch dependencies to site data interface

This commit is contained in:
Keenan Gugeler 2022-03-11 13:50:19 -05:00 committed by Roger Fu
parent 61318c7e71
commit 435839e6b3
5 changed files with 86 additions and 30 deletions

View 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'),
),
]

View File

@ -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'))

View File

@ -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()

View File

@ -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'}),

View File

@ -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 %}