Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions web/app/controllers/problem_data_configure.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php
requireLib('bootstrap5');
requirePHPLib('form');
requirePHPLib('judger');
requirePHPLib('data');

UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404();
UOJProblem::cur()->userCanManage(Auth::user()) || UOJResponse::page403();

$problem_configure = new UOJProblemConfigure(UOJProblem::cur());
$problem_configure->runAtServer();
$problem_conf_str = '';

foreach ($problem_configure->problem_conf->conf as $key => $val) {
if ($key == 'use_builtin_judger' && $val == 'off') {
continue;
}

if ($key == 'use_builtin_checker' && $val == 'ownchk') {
continue;
}

$problem_conf_str .= "{$key} {$val}\n";
}
?>

<?php echoUOJPageHeader('数据配置 - ' . HTML::stripTags(UOJProblem::cur()->getTitle(['with' => 'id']))) ?>

<h1>
<?= UOJProblem::cur()->getTitle(['with' => 'id']) ?> 数据配置
</h1>

<div class="row mt-3">
<div class="col-12 col-md-4">
<div class="card">
<div class="card-header fw-bold">problem.conf 预览</div>

<div class="card-body p-0" id="problem-conf-preview">
<pre class="bg-light mb-0 p-3"><code><?= $problem_conf_str ?></code></pre>
</div>

<div class="card-footer bg-transparent small text-muted">
此处显示的 <code>problem.conf</code> 为根据右侧填写的配置信息生成的内容预览,并非题目当前实际配置文件。
</div>
</div>
<div class="card mt-3">
<div class="card-header fw-bold">功能说明</div>

<div class="card-body">
<p>此处可以对 <b>传统题</b> 进行快速配置,在填写完成之后点击页面底部的「提交」按钮即可替换现有配置文件并进行数据同步。</p>
<p>目前暂不支持对交互题、提交答案题、通信题进行配置,对于此类题目请手动编写配置文件。</p>
<p>如需要配置子任务依赖,也可以基于此处生成的配置文件进行修改后再手动上传。</p>
<p>关于数据配置的更多帮助,请查阅 <a href="https://s2oj.github.io/#/manage/tutorial/problem_data" target="_blank">帮助文档</a>。</p>
</div>
</div>
</div>
<div class="col-12 col-md-8 mt-3 mt-md-0">
<?php $problem_configure->printHTML() ?>
</div>
</div>

<?php echoUOJPageFooter() ?>
158 changes: 1 addition & 157 deletions web/app/controllers/problem_data_manage.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,58 +90,6 @@ function echoFilePre($file_name) {
}
}

// 添加配置文件
if ($_POST['problem_settings_file_submit'] == 'submit') {
if ($_POST['use_builtin_checker'] and $_POST['n_tests']) {
$set_filename = "/var/uoj_data/upload/{$problem['id']}/problem.conf";
$has_legacy = false;
if (file_exists($set_filename)) {
$has_legacy = true;
unlink($set_filename);
}
$setfile = fopen($set_filename, "w");
fwrite($setfile, "use_builtin_judger on\n");
if ($_POST['use_builtin_checker'] != 'ownchk') {
fwrite($setfile, "use_builtin_checker " . $_POST['use_builtin_checker'] . "\n");
}
fwrite($setfile, "n_tests " . $_POST['n_tests'] . "\n");
if ($_POST['n_ex_tests']) {
fwrite($setfile, "n_ex_tests " . $_POST['n_ex_tests'] . "\n");
} else {
fwrite($setfile, "n_ex_tests 0\n");
}
if ($_POST['n_sample_tests']) {
fwrite($setfile, "n_sample_tests " . $_POST['n_sample_tests'] . "\n");
} else {
fwrite($setfile, "n_sample_tests 0\n");
}
if (isset($_POST['input_pre'])) {
fwrite($setfile, "input_pre " . $_POST['input_pre'] . "\n");
}
if (isset($_POST['input_suf'])) {
fwrite($setfile, "input_suf " . $_POST['input_suf'] . "\n");
}
if (isset($_POST['output_pre'])) {
fwrite($setfile, "output_pre " . $_POST['output_pre'] . "\n");
}
if (isset($_POST['output_suf'])) {
fwrite($setfile, "output_suf " . $_POST['output_suf'] . "\n");
}
fwrite($setfile, "time_limit " . ($_POST['time_limit'] ?: 1) . "\n");
fwrite($setfile, "memory_limit " . ($_POST['memory_limit'] ?: 256) . "\n");
fclose($setfile);
if (!$has_legacy) {
echo "<script>alert('添加成功!请点击「检验配置并同步数据」按钮以应用新配置文件。')</script>";
} else {
echo "<script>alert('替换成功!请点击「检验配置并同步数据」按钮以应用新配置文件。')</script>";
}
} else {
$errmsg = "添加配置文件失败,请检查是否所有必填输入框都已填写!";
becomeMsgPage('<div>' . $errmsg . '</div><a href="/problem/' . $problem['id'] . '/manage/data">返回</a>');
}
}


$info_form = new UOJForm('info');
$attachment_url = UOJProblem::cur()->getAttachmentUri();
$info_form->appendHTML(<<<EOD
Expand Down Expand Up @@ -670,7 +618,7 @@ function(data) {
<button type="button" class="btn d-block w-100 btn-primary" data-bs-toggle="modal" data-bs-target="#UploadDataModal">上传数据</button>
</div>
<div class="mt-2">
<button type="button" class="btn d-block w-100 btn-primary" data-bs-toggle="modal" data-bs-target="#ProblemSettingsFileModal">试题配置</button>
<a role="button" class="btn d-block w-100 btn-primary" href="<?= UOJProblem::cur()->getUri('/manage/data/configure') ?>">数据配置</a>
</div>
</div>
</aside>
Expand Down Expand Up @@ -705,108 +653,4 @@ function(data) {
</div>
</div>

<?php $problem_conf = UOJProblem::cur()->getProblemConf() ?>

<div class="modal fade" id="ProblemSettingsFileModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="myModalLabel">试题配置</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form class="form-horizontal" action="" method="post" role="form">
<div class="modal-body">
<div class="form-group row">
<label for="use_builtin_checker" class="col-sm-5 control-label">比对函数</label>
<div class="col-sm-7">
<?php $checker_value = $problem_conf instanceof UOJProblemConf ? $problem_conf->getVal('use_builtin_checker', 'ownchk') : ""; ?>
<select class="form-select" id="use_builtin_checker" name="use_builtin_checker">
<option value="ncmp" <?= $checker_value == "ncmp" ? 'selected' : '' ?>>ncmp: 整数序列</option>
<option value="wcmp" <?= $checker_value == "wcmp" ? 'selected' : '' ?>>wcmp: 字符串序列</option>
<option value="lcmp" <?= $checker_value == "lcmp" ? 'selected' : '' ?>>lcmp: 多行数据(忽略行内与行末的多余空格,同时忽略文末回车)</option>
<option value="fcmp" <?= $checker_value == "fcmp" ? 'selected' : '' ?>>fcmp: 多行数据(不忽略行末空格,但忽略文末回车)</option>
<option value="rcmp4" <?= $checker_value == "rcmp4" ? 'selected' : '' ?>>rcmp4: 浮点数序列(误差不超过 1e-4)</option>
<option value="rcmp6" <?= $checker_value == "rcmp6" ? 'selected' : '' ?>>rcmp6: 浮点数序列(误差不超过 1e-6)</option>
<option value="rcmp9" <?= $checker_value == "rcmp9" ? 'selected' : '' ?>>rcmp9: 浮点数序列(误差不超过 1e-9)</option>
<option value="yesno" <?= $checker_value == "yesno" ? 'selected' : '' ?>>yesno: Yes、No(不区分大小写)</option>
<option value="uncmp" <?= $checker_value == "uncmp" ? 'selected' : '' ?>>uncmp: 整数集合</option>
<option value="bcmp" <?= $checker_value == "bcmp" ? 'selected' : '' ?>>bcmp: 二进制文件</option>
<option value="ownchk" <?= $checker_value == "ownchk" ? 'selected' : '' ?>>自定义校验器(需上传 chk.cpp)</option>
</select>
</div>
</div>
<div class="form-group row">
<label for="n_tests" class="col-sm-5 control-label">n_tests</label>
<div class="col-sm-7">
<?php $n_tests_value = $problem_conf instanceof UOJProblemConf ? $problem_conf->getVal('n_tests', '') : ""; ?>
<input type="number" class="form-control" id="n_tests" name="n_tests" placeholder="数据点个数(必填)" value="<?= $n_tests_value ?>">
</div>
</div>
<div class="form-group row">
<label for="n_ex_tests" class="col-sm-5 control-label">n_ex_tests</label>
<div class="col-sm-7">
<?php $n_ex_tests_value = $problem_conf instanceof UOJProblemConf ? $problem_conf->getVal('n_ex_tests', 0) : ""; ?>
<input type="number" class="form-control" id="n_ex_tests" name="n_ex_tests" placeholder="额外数据点个数(默认为 0)" value="<?= $n_ex_tests_value ?>">
</div>
</div>
<div class="form-group row">
<label for="n_sample_tests" class="col-sm-5 control-label">n_sample_tests</label>
<div class="col-sm-7">
<?php $n_sample_tests_value = $problem_conf instanceof UOJProblemConf ? $problem_conf->getVal('n_sample_tests', 0) : ""; ?>
<input type="number" class="form-control" id="n_sample_tests" name="n_sample_tests" placeholder="样例测试点个数(默认为 0)" value="<?= $n_sample_tests_value ?>">
</div>
</div>
<div class="form-group row">
<label for="input_pre" class="col-sm-5 control-label">input_pre</label>
<div class="col-sm-7">
<?php $input_pre_value = $problem_conf instanceof UOJProblemConf ? $problem_conf->getVal('input_pre', 'input') : ""; ?>
<input type="text" class="form-control" id="input_pre" name="input_pre" placeholder="输入文件名称(默认为 input)" value="<?= $input_pre_value ?>">
</div>
</div>
<div class="form-group row">
<label for="input_suf" class="col-sm-5 control-label">input_suf</label>
<div class="col-sm-7">
<?php $input_suf_value = $problem_conf instanceof UOJProblemConf ? $problem_conf->getVal('input_suf', 'txt') : ""; ?>
<input type="text" class="form-control" id="input_suf" name="input_suf" placeholder="输入文件后缀(默认为 txt)" value="<?= $input_suf_value ?>">
</div>
</div>
<div class="form-group row">
<label for="output_pre" class="col-sm-5 control-label">output_pre</label>
<div class="col-sm-7">
<?php $output_pre_value = $problem_conf instanceof UOJProblemConf ? $problem_conf->getVal('output_pre', 'output') : ''; ?>
<input type="text" class="form-control" id="output_pre" name="output_pre" placeholder="输出文件名称(默认为 output)" value="<?= $output_pre_value ?>">
</div>
</div>
<div class="form-group row">
<label for="output_suf" class="col-sm-5 control-label">output_suf</label>
<div class="col-sm-7">
<?php $output_suf_value = $problem_conf instanceof UOJProblemConf ? $problem_conf->getVal('output_suf', 'txt') : ""; ?>
<input type="text" class="form-control" id="output_suf" name="output_suf" placeholder="输出文件后缀(默认为 txt)" value="<?= $output_suf_value ?>">
</div>
</div>
<div class="form-group row">
<label for="time_limit" class="col-sm-5 control-label">time_limit</label>
<div class="col-sm-7">
<?php $time_limit_value = $problem_conf instanceof UOJProblemConf ? $problem_conf->getVal('time_limit', 1) : ""; ?>
<input type="text" class="form-control" id="time_limit" name="time_limit" placeholder="时间限制(默认为 1s)" value="<?= $time_limit_value ?>">
</div>
</div>
<div class="form-group row">
<label for="memory_limit" class="col-sm-5 control-label">memory_limit</label>
<div class="col-sm-7">
<?php $memory_limit_value = $problem_conf instanceof UOJProblemConf ? $problem_conf->getVal('memory_limit', 256) : ""; ?>
<input type="number" class="form-control" id="memory_limit" name="memory_limit" placeholder="内存限制(默认为 256 MB)" value="<?= $memory_limit_value ?>">
</div>
</div>
<input type="hidden" name="problem_settings_file_submit" value="submit">
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-success">确定</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
</div>
</form>
</div>
</div>
</div>

<?php echoUOJPageFooter() ?>
8 changes: 7 additions & 1 deletion web/app/libs/uoj-data-lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,9 @@ private function makefile_at_prepare() {

public function _updateProblemConf($new_problem_conf) {
try {
putUOJConf("{$this->data_dir}/problem.conf", $new_problem_conf);
putUOJConf("{$this->upload_dir}/problem.conf", $new_problem_conf);

$this->_sync();
return '';
} catch (Exception $e) {
return $e->getMessage();
Expand Down Expand Up @@ -506,3 +508,7 @@ function dataAddHackPoint($problem, $uploaded_input_file, $uploaded_output_file,

return (new SyncProblemDataHandler($problem, $user))->addHackPoint($uploaded_input_file, $uploaded_output_file, $reason);
}

function dataUpdateProblemConf($problem, $new_problem_conf) {
return (new SyncProblemDataHandler($problem))->updateProblemConf($new_problem_conf);
}
35 changes: 27 additions & 8 deletions web/app/models/UOJForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ public function addInput($name, $config) {
'type' => 'text',
'div_class' => '',
'input_class' => 'form-control',
'input_attrs' => [],
'input_div_class' => null,
'default_value' => '',
'label' => '',
'label_class' => 'form-label',
Expand All @@ -148,20 +150,28 @@ public function addInput($name, $config) {
], $config['label']);
}

if ($config['input_div_class'] !== null) {
$html .= HTML::tag_begin('div', ['class' => $config['input_div_class']]);
}

$html .= HTML::empty_tag('input', [
'class' => $config['input_class'],
'type' => $config['type'],
'name' => $name,
'id' => "input-$name",
'value' => $config['default_value'],
'placeholder' => $config['placeholder'],
]);
] + $config['input_attrs']);
$html .= HTML::tag('div', ['class' => 'invalid-feedback', 'id' => "help-$name"], '');

if ($config['help']) {
$html .= HTML::tag('div', ['class' => $config['help_class']], $config['help']);
}

if ($config['input_div_class'] !== null) {
$html .= HTML::tag_end('div');
}

$html .= HTML::tag_end('div');

$this->add($name, $html, $config['validator_php'], $config['validator_js']);
Expand Down Expand Up @@ -255,6 +265,7 @@ public function addSelect($name, $config) {
$config += [
'div_class' => '',
'select_class' => 'form-select',
'select_div_class' => null,
'options' => [],
'default_value' => '',
'label' => '',
Expand All @@ -275,6 +286,10 @@ public function addSelect($name, $config) {
], $config['label']);
}

if ($config['select_div_class'] !== null) {
$html .= HTML::tag_begin('div', ['class' => $config['select_div_class']]);
}

// Select
$html .= HTML::tag_begin('select', ['id' => "input-$name", 'name' => $name, 'class' => $config['select_class']]);

Expand All @@ -293,6 +308,10 @@ public function addSelect($name, $config) {
$html .= HTML::tag('div', ['class' => $config['help_class']], $config['help']);
}

if ($config['select_div_class'] !== null) {
$html .= HTML::tag_end('div');
}

$html .= HTML::tag_end('div');

$this->add(
Expand Down Expand Up @@ -503,6 +522,13 @@ public function printHTML() {
if (!$this->config['no_submit']) {
echo HTML::tag_begin('div', ['class' => $this->config['submit_container']['class']]);

if ($this->config['back_button']['href'] !== null) {
echo HTML::tag('a', [
'class' => $this->config['back_button']['class'],
'href' => $this->config['back_button']['href']
], '返回');
}

echo HTML::tag('button', [
'type' => 'submit',
'id' => "button-submit-{$this->form_name}",
Expand All @@ -511,13 +537,6 @@ public function printHTML() {
'class' => $this->config['submit_button']['class']
], $this->config['submit_button']['text']);

if ($this->config['back_button']['href'] !== null) {
echo HTML::tag('a', [
'class' => $this->config['back_button']['class'],
'href' => $this->config['back_button']['href']
], '返回');
}

echo HTML::tag_end('div');
}

Expand Down
8 changes: 8 additions & 0 deletions web/app/models/UOJProblem.php
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,10 @@ public function getDataFolderPath() {
return "/var/uoj_data/{$this->info['id']}";
}

public function getUploadFolderPath() {
return "/var/uoj_data/upload/{$this->info['id']}";
}

public function getDataZipPath() {
return "/var/uoj_data/{$this->info['id']}.zip";
}
Expand All @@ -672,6 +676,10 @@ public function getDataFilePath($name = '') {
return "{$this->getDataFolderPath()}/$name";
}

public function getUploadFilePath($name = '') {
return "{$this->getUploadFolderPath()}/$name";
}

public function getResourcesFolderPath() {
return UOJContext::storagePath() . "/problem_resources/" . $this->info['id'];
}
Expand Down
Loading