mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-12-29 19:31:52 +00:00
965 lines
36 KiB
PHP
965 lines
36 KiB
PHP
<?php
|
||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
||
redirectToLogin();
|
||
}
|
||
|
||
requireLib('bootstrap5');
|
||
requirePHPLib('form');
|
||
requirePHPLib('judger');
|
||
requirePHPLib('data');
|
||
|
||
if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) {
|
||
become404Page();
|
||
}
|
||
if (!hasProblemPermission($myUser, $problem)) {
|
||
become403Page();
|
||
}
|
||
|
||
$oj_name = UOJConfig::$data['profile']['oj-name'];
|
||
$problem_extra_config = getProblemExtraConfig($problem);
|
||
|
||
$data_dir = "/var/uoj_data/${problem['id']}";
|
||
|
||
function echoFileNotFound($file_name) {
|
||
echo '<h5>', htmlspecialchars($file_name), '</h5>';
|
||
echo '<div class="small text-danger"> ', '文件未找到', '</div>';
|
||
}
|
||
function echoFilePre($file_name) {
|
||
global $data_dir;
|
||
$file_full_name = $data_dir . '/' . $file_name;
|
||
|
||
$finfo = finfo_open(FILEINFO_MIME);
|
||
$mimetype = finfo_file($finfo, $file_full_name);
|
||
if ($mimetype === false) {
|
||
echoFileNotFound($file_name);
|
||
return;
|
||
}
|
||
finfo_close($finfo);
|
||
|
||
echo '<h5 class="mb-1">', htmlspecialchars($file_name), '</h5>';
|
||
echo '<div class="text-muted small mb-1 font-monospace">', $mimetype, '</div>';
|
||
echo '<pre class="bg-light rounded uoj-pre">', "\n";
|
||
|
||
$output_limit = 1000;
|
||
if (strStartWith($mimetype, 'text/')) {
|
||
echo htmlspecialchars(uojFilePreview($file_full_name, $output_limit));
|
||
} else {
|
||
echo htmlspecialchars(uojFilePreview($file_full_name, $output_limit, 'binary'));
|
||
}
|
||
echo "\n</pre>";
|
||
}
|
||
|
||
|
||
//上传数据
|
||
if ($_POST['problem_data_file_submit']=='submit') {
|
||
if ($_FILES["problem_data_file"]["error"] > 0) {
|
||
$errmsg = "Error: ".$_FILES["problem_data_file"]["error"];
|
||
becomeMsgPage('<div>' . $errmsg . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
|
||
} else {
|
||
$zip_mime_types = array('application/zip', 'application/x-zip', 'application/x-zip-compressed');
|
||
if (in_array($_FILES["problem_data_file"]["type"], $zip_mime_types) || $_FILES["problem_data_file"]["type"] == 'application/octet-stream' && substr($_FILES["problem_data_file"]["name"], -4) == '.zip') {
|
||
$up_filename="/tmp/".rand(0,100000000)."data.zip";
|
||
move_uploaded_file($_FILES["problem_data_file"]["tmp_name"], $up_filename);
|
||
$zip = new ZipArchive;
|
||
if ($zip->open($up_filename) === TRUE) {
|
||
$zip->extractTo("/var/uoj_data/upload/{$problem['id']}");
|
||
$zip->close();
|
||
exec("cd /var/uoj_data/upload/{$problem['id']}; if [ `find . -maxdepth 1 -type f`File = File ]; then for sub_dir in `find -maxdepth 1 -type d ! -name .`; do mv -f \$sub_dir/* . && rm -rf \$sub_dir; done; fi");
|
||
echo "<script>alert('上传成功!')</script>";
|
||
} else {
|
||
$errmsg = "解压失败!";
|
||
becomeMsgPage('<div>' . $errmsg . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
|
||
}
|
||
unlink($up_filename);
|
||
} else {
|
||
$errmsg = "请上传zip格式!";
|
||
becomeMsgPage('<div>' . $errmsg . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
|
||
}
|
||
}
|
||
}
|
||
|
||
//添加配置文件
|
||
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');
|
||
$http_host = HTML::escape(UOJContext::httpHost());
|
||
$attachment_url = HTML::url("/download.php?type=attachment&id={$problem['id']}");
|
||
$info_form->appendHTML(<<<EOD
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 control-label">problem_{$problem['id']}_attachment.zip</label>
|
||
<div class="col-sm-9">
|
||
<div class="form-control-static">
|
||
<a class="text-decoration-none" href="$attachment_url">$attachment_url</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
EOD
|
||
);
|
||
$download_url = HTML::url("/download.php?type=problem&id={$problem['id']}");
|
||
$info_form->appendHTML(<<<EOD
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 control-label">problem_{$problem['id']}.zip</label>
|
||
<div class="col-sm-9">
|
||
<div class="form-control-static">
|
||
<a class="text-decoration-none" href="$download_url">$download_url</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
EOD
|
||
);
|
||
$info_form->appendHTML(<<<EOD
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 control-label">testlib.h</label>
|
||
<div class="col-sm-9">
|
||
<div class="form-control-static">
|
||
<a class="text-decoration-none" href="/download.php?type=testlib.h">下载</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
EOD
|
||
);
|
||
|
||
$esc_submission_requirement = HTML::escape(json_encode(json_decode($problem['submission_requirement']), JSON_PRETTY_PRINT));
|
||
$info_form->appendHTML(<<<EOD
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 control-label">提交文件配置</label>
|
||
<div class="col-sm-9">
|
||
<div class="form-control-static"><pre class="uoj-pre bg-light rounded">
|
||
$esc_submission_requirement
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
EOD
|
||
);
|
||
$esc_extra_config = HTML::escape(json_encode(json_decode($problem['extra_config']), JSON_PRETTY_PRINT));
|
||
$info_form->appendHTML(<<<EOD
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 control-label">其它配置</label>
|
||
<div class="col-sm-9">
|
||
<div class="form-control-static"><pre class="uoj-pre bg-light rounded">
|
||
$esc_extra_config
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
EOD
|
||
);
|
||
if (isSuperUser($myUser)) {
|
||
$info_form->addVInput('submission_requirement', 'text', '提交文件配置', $problem['submission_requirement'],
|
||
function ($submission_requirement, &$vdata) {
|
||
$submission_requirement = json_decode($submission_requirement, true);
|
||
if ($submission_requirement === null) {
|
||
return '不是合法的JSON';
|
||
}
|
||
$vdata['submission_requirement'] = json_encode($submission_requirement);
|
||
},
|
||
null);
|
||
$info_form->addVInput('extra_config', 'text', '其它配置', $problem['extra_config'],
|
||
function ($extra_config, &$vdata) {
|
||
$extra_config = json_decode($extra_config, true);
|
||
if ($extra_config === null) {
|
||
return '不是合法的JSON';
|
||
}
|
||
$vdata['extra_config'] = json_encode($extra_config);
|
||
},
|
||
null);
|
||
$info_form->handle = function(&$vdata) {
|
||
global $problem;
|
||
$esc_submission_requirement = DB::escape($vdata['submission_requirement']);
|
||
$esc_extra_config = DB::escape($vdata['extra_config']);
|
||
DB::update("update problems set submission_requirement = '$esc_submission_requirement', extra_config = '$esc_extra_config' where id = {$problem['id']}");
|
||
};
|
||
} else {
|
||
$info_form->no_submit = true;
|
||
}
|
||
|
||
class DataDisplayer {
|
||
public $problem_conf = array();
|
||
public $data_files = array();
|
||
public $displayers = array();
|
||
|
||
public function __construct($problem_conf = null, $data_files = null) {
|
||
global $data_dir;
|
||
|
||
if (isset($problem_conf)) {
|
||
foreach ($problem_conf as $key => $val) {
|
||
$this->problem_conf[$key] = array('val' => $val);
|
||
}
|
||
}
|
||
|
||
if (!isset($data_files)) {
|
||
$this->data_files = array_filter(scandir($data_dir), function($x) {
|
||
return $x !== '.' && $x !== '..' && $x !== 'problem.conf';
|
||
});
|
||
natsort($this->data_files);
|
||
array_unshift($this->data_files, 'problem.conf');
|
||
} else {
|
||
$this->data_files = $data_files;
|
||
}
|
||
|
||
$this->setDisplayer('problem.conf', function($self) {
|
||
global $info_form;
|
||
$info_form->printHTML();
|
||
|
||
echo '<hr class="my-3">';
|
||
|
||
echo '<table class="table table-bordered text-center caption-top">';
|
||
echo '<caption>problem.conf</caption>';
|
||
echo '<thead>';
|
||
echo '<tr>';
|
||
echo '<th>key</th>';
|
||
echo '<th>value</th>';
|
||
echo '</tr>';
|
||
echo '</thead>';
|
||
echo '<tbody>';
|
||
foreach ($self->problem_conf as $key => $info) {
|
||
if (!isset($info['status'])) {
|
||
echo '<tr>';
|
||
echo '<td>', htmlspecialchars($key), '</td>';
|
||
echo '<td>', htmlspecialchars($info['val']), '</td>';
|
||
echo '</tr>';
|
||
} elseif ($info['status'] == 'danger') {
|
||
echo '<tr class="text-danger">';
|
||
echo '<td>', htmlspecialchars($key), '</td>';
|
||
echo '<td>', htmlspecialchars($info['val']), ' <span class="bi bi-x-large"></span>', '</td>';
|
||
echo '</tr>';
|
||
}
|
||
}
|
||
echo '</tbody>';
|
||
echo '</table>';
|
||
|
||
echoFilePre('problem.conf');
|
||
});
|
||
}
|
||
|
||
public function setProblemConfRowStatus($key, $status) {
|
||
$this->problem_conf[$key]['status'] = $status;
|
||
return $this;
|
||
}
|
||
|
||
public function setDisplayer($file_name, $fun) {
|
||
$this->displayers[$file_name] = $fun;
|
||
return $this;
|
||
}
|
||
public function addDisplayer($file_name, $fun) {
|
||
$this->data_files[] = $file_name;
|
||
$this->displayers[$file_name] = $fun;
|
||
return $this;
|
||
}
|
||
public function echoDataFilesList($active_file) {
|
||
foreach ($this->data_files as $file_name) {
|
||
echo '<li class="nav-item">';
|
||
if ($file_name != $active_file) {
|
||
echo '<a class="nav-link" href="#">';
|
||
} else {
|
||
echo '<a class="nav-link active" href="#">';
|
||
}
|
||
echo htmlspecialchars($file_name), '</a>', '</li>';
|
||
}
|
||
}
|
||
public function displayFile($file_name) {
|
||
global $data_dir;
|
||
|
||
if (isset($this->displayers[$file_name])) {
|
||
$fun = $this->displayers[$file_name];
|
||
$fun($this);
|
||
} elseif (in_array($file_name, $this->data_files)) {
|
||
echoFilePre($file_name);
|
||
} else {
|
||
echoFileNotFound($file_name);
|
||
}
|
||
}
|
||
}
|
||
|
||
$problem_conf = getUOJConf("$data_dir/problem.conf");
|
||
|
||
function getDataDisplayer() {
|
||
global $data_dir, $problem, $problem_conf;
|
||
|
||
$allow_files = array_flip(array_filter(scandir($data_dir), function($x) {
|
||
return $x !== '.' && $x !== '..';
|
||
}));
|
||
|
||
$getDisplaySrcFunc = function($name) use ($allow_files) {
|
||
return function() use ($name, $allow_files) {
|
||
$src_name = $name . '.cpp';
|
||
if (isset($allow_files[$src_name])) {
|
||
echoFilePre($src_name);
|
||
} else {
|
||
echoFileNotFound($src_name);
|
||
}
|
||
if (isset($allow_files[$name])) {
|
||
echoFilePre($name);
|
||
} else {
|
||
echoFileNotFound($name);
|
||
}
|
||
};
|
||
};
|
||
|
||
if ($problem_conf === -1) {
|
||
return (new DataDisplayer())->setDisplayer('problem.conf', function() {
|
||
global $info_form;
|
||
$info_form->printHTML();
|
||
|
||
echo '<hr class="my-3">';
|
||
|
||
echoFileNotFound('problem.conf');
|
||
});
|
||
}
|
||
if ($problem_conf === -2) {
|
||
return (new DataDisplayer())->setDisplayer('problem.conf', function() {
|
||
global $info_form;
|
||
$info_form->printHTML();
|
||
|
||
echo '<hr class="my-3">';
|
||
|
||
echo '<div class="fw-bold text-danger">problem.conf 文件格式有误</div>';
|
||
echoFilePre('problem.conf');
|
||
});
|
||
}
|
||
|
||
$judger_name = getUOJConfVal($problem_conf, 'use_builtin_judger', null);
|
||
if (!isset($problem_conf['use_builtin_judger'])) {
|
||
return new DataDisplayer($problem_conf);
|
||
}
|
||
if ($problem_conf['use_builtin_judger'] == 'on') {
|
||
$n_tests = getUOJConfVal($problem_conf, 'n_tests', 10);
|
||
if (!validateUInt($n_tests)) {
|
||
return (new DataDisplayer($problem_conf))->setProblemConfRowStatus('n_tests', 'danger');
|
||
}
|
||
|
||
$has_extra_tests = !(isset($problem_conf['submit_answer']) && $problem_conf['submit_answer'] == 'on');
|
||
|
||
$data_disp = new DataDisplayer($problem_conf, array('problem.conf'));
|
||
$data_disp->addDisplayer('tests',
|
||
function($self) use ($problem_conf, $allow_files, $n_tests, $n_ex_tests) {
|
||
for ($num = 1; $num <= $n_tests; $num++) {
|
||
$input_file_name = getUOJProblemInputFileName($problem_conf, $num);
|
||
$output_file_name = getUOJProblemOutputFileName($problem_conf, $num);
|
||
echo '<div class="row">';
|
||
echo '<div class="col-md-6">';
|
||
if (isset($allow_files[$input_file_name])) {
|
||
echoFilePre($input_file_name);
|
||
} else {
|
||
echoFileNotFound($input_file_name);
|
||
}
|
||
echo '</div>';
|
||
echo '<div class="col-md-6">';
|
||
if (isset($allow_files[$output_file_name])) {
|
||
echoFilePre($output_file_name);
|
||
} else {
|
||
echoFileNotFound($output_file_name);
|
||
}
|
||
echo '</div>';
|
||
echo '</div>';
|
||
}
|
||
}
|
||
);
|
||
if ($has_extra_tests) {
|
||
$n_ex_tests = getUOJConfVal($problem_conf, 'n_ex_tests', 0);
|
||
if (!validateUInt($n_ex_tests)) {
|
||
return (new DataDisplayer($problem_conf))->setProblemConfRowStatus('n_ex_tests', 'danger');
|
||
}
|
||
|
||
$data_disp->addDisplayer('extra tests',
|
||
function($self) use ($problem_conf, $allow_files, $n_tests, $n_ex_tests) {
|
||
for ($num = 1; $num <= $n_ex_tests; $num++) {
|
||
$input_file_name = getUOJProblemExtraInputFileName($problem_conf, $num);
|
||
$output_file_name = getUOJProblemExtraOutputFileName($problem_conf, $num);
|
||
echo '<div class="row">';
|
||
echo '<div class="col-md-6">';
|
||
if (isset($allow_files[$input_file_name])) {
|
||
echoFilePre($input_file_name);
|
||
} else {
|
||
echoFileNotFound($input_file_name);
|
||
}
|
||
echo '</div>';
|
||
echo '<div class="col-md-6">';
|
||
if (isset($allow_files[$output_file_name])) {
|
||
echoFilePre($output_file_name);
|
||
} else {
|
||
echoFileNotFound($output_file_name);
|
||
}
|
||
echo '</div>';
|
||
echo '</div>';
|
||
}
|
||
}
|
||
);
|
||
}
|
||
|
||
if (!isset($problem_conf['interaction_mode'])) {
|
||
if (isset($problem_conf['use_builtin_checker'])) {
|
||
$data_disp->addDisplayer('checker', function($self) {
|
||
echo '<h5>use builtin checker : ', $self->problem_conf['use_builtin_checker']['val'], '</h5>';
|
||
});
|
||
} else {
|
||
$data_disp->addDisplayer('checker', $getDisplaySrcFunc('chk'));
|
||
}
|
||
}
|
||
if ($problem['hackable']) {
|
||
$data_disp->addDisplayer('standard', $getDisplaySrcFunc('std'));
|
||
$data_disp->addDisplayer('validator', $getDisplaySrcFunc('val'));
|
||
}
|
||
if (isset($problem_conf['interaction_mode'])) {
|
||
$data_disp->addDisplayer('interactor', $getDisplaySrcFunc('interactor'));
|
||
}
|
||
return $data_disp;
|
||
} else {
|
||
return (new DataDisplayer($problem_conf))->setProblemConfRowStatus('use_builtin_judger', 'danger');
|
||
}
|
||
}
|
||
|
||
$data_disp = getDataDisplayer();
|
||
|
||
if (isset($_GET['display_file'])) {
|
||
if (!isset($_GET['file_name'])) {
|
||
echoFileNotFound('');
|
||
} else {
|
||
$data_disp->displayFile($_GET['file_name']);
|
||
}
|
||
die();
|
||
}
|
||
|
||
$hackable_form = new UOJForm('hackable');
|
||
$hackable_form->handle = function() {
|
||
global $problem;
|
||
$problem['hackable'] = !$problem['hackable'];
|
||
$ret = dataSyncProblemData($problem);
|
||
if ($ret) {
|
||
becomeMsgPage('<div>' . $ret . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
|
||
}
|
||
|
||
$hackable = $problem['hackable'] ? 1 : 0;
|
||
DB::query("update problems set hackable = $hackable where id = ${problem['id']}");
|
||
};
|
||
$hackable_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100';
|
||
$hackable_form->submit_button_config['text'] = $problem['hackable'] ? '禁用 Hack 功能' : '启用 Hack 功能';
|
||
$hackable_form->submit_button_config['smart_confirm'] = '';
|
||
|
||
$data_form = new UOJForm('data');
|
||
$data_form->handle = function() {
|
||
global $problem, $myUser;
|
||
set_time_limit(60 * 5);
|
||
$ret = dataSyncProblemData($problem, $myUser);
|
||
if ($ret) {
|
||
becomeMsgPage('<div>' . $ret . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
|
||
}
|
||
};
|
||
$data_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100';
|
||
$data_form->submit_button_config['text'] = '检验配置并同步数据';
|
||
$data_form->submit_button_config['smart_confirm'] = '';
|
||
|
||
$clear_data_form = new UOJForm('clear_data');
|
||
$clear_data_form->handle = function() {
|
||
global $problem;
|
||
dataClearProblemData($problem);
|
||
};
|
||
$clear_data_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100';
|
||
$clear_data_form->submit_button_config['text'] = '清空题目数据';
|
||
$clear_data_form->submit_button_config['smart_confirm'] = '';
|
||
|
||
$rejudge_form = new UOJForm('rejudge');
|
||
$rejudge_form->handle = function() {
|
||
global $problem;
|
||
rejudgeProblem($problem);
|
||
};
|
||
$rejudge_form->succ_href = "/submissions?problem_id={$problem['id']}";
|
||
$rejudge_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100';
|
||
$rejudge_form->submit_button_config['text'] = '重测该题';
|
||
$rejudge_form->submit_button_config['smart_confirm'] = '';
|
||
|
||
$rejudgege97_form = new UOJForm('rejudgege97');
|
||
$rejudgege97_form->handle = function() {
|
||
global $problem;
|
||
rejudgeProblemGe97($problem);
|
||
};
|
||
$rejudgege97_form->succ_href = "/submissions?problem_id={$problem['id']}";
|
||
$rejudgege97_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100';
|
||
$rejudgege97_form->submit_button_config['text'] = '重测 >=97 的程序';
|
||
$rejudgege97_form->submit_button_config['smart_confirm'] = '';
|
||
|
||
$view_type_form = new UOJForm('view_type');
|
||
$view_type_form->addVSelect('view_content_type',
|
||
array('NONE' => '禁止',
|
||
'ALL_AFTER_AC' => 'AC后',
|
||
'ALL' => '所有人'
|
||
),
|
||
'查看提交文件:',
|
||
$problem_extra_config['view_content_type']
|
||
);
|
||
$view_type_form->addVSelect('view_all_details_type',
|
||
array('NONE' => '禁止',
|
||
'SELF' => '仅自己',
|
||
'ALL_AFTER_AC' => 'AC后',
|
||
'ALL' => '所有人'
|
||
),
|
||
'查看全部详细信息:',
|
||
$problem_extra_config['view_all_details_type']
|
||
);
|
||
$view_type_form->addVSelect('view_details_type',
|
||
array('NONE' => '禁止',
|
||
'SELF' => '仅自己',
|
||
'ALL_AFTER_AC' => 'AC后',
|
||
'ALL' => '所有人'
|
||
),
|
||
'查看测试点详细信息:',
|
||
$problem_extra_config['view_details_type']
|
||
);
|
||
$view_type_form->handle = function() {
|
||
global $problem, $problem_extra_config;
|
||
$config = $problem_extra_config;
|
||
$config['view_content_type'] = $_POST['view_content_type'];
|
||
$config['view_all_details_type'] = $_POST['view_all_details_type'];
|
||
$config['view_details_type'] = $_POST['view_details_type'];
|
||
$esc_config = DB::escape(json_encode($config));
|
||
DB::query("update problems set extra_config = '$esc_config' where id = '{$problem['id']}'");
|
||
};
|
||
$view_type_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100 mt-2';
|
||
|
||
$solution_view_type_form = new UOJForm('solution_view_type');
|
||
$solution_view_type_form->addVSelect('view_solution_type',
|
||
array('NONE' => '禁止',
|
||
'ALL_AFTER_AC' => 'AC后',
|
||
'ALL' => '所有人'
|
||
),
|
||
'查看题解:',
|
||
$problem_extra_config['view_solution_type']
|
||
);
|
||
$solution_view_type_form->addVSelect('submit_solution_type',
|
||
array('NONE' => '禁止',
|
||
'ALL_AFTER_AC' => 'AC后',
|
||
'ALL' => '所有人'
|
||
),
|
||
'提交题解:',
|
||
$problem_extra_config['submit_solution_type']
|
||
);
|
||
$solution_view_type_form->handle = function() {
|
||
global $problem, $problem_extra_config;
|
||
$config = $problem_extra_config;
|
||
$config['view_solution_type'] = $_POST['view_solution_type'];
|
||
$config['submit_solution_type'] = $_POST['submit_solution_type'];
|
||
$esc_config = DB::escape(json_encode($config));
|
||
DB::query("update problems set extra_config = '$esc_config' where id = '{$problem['id']}'");
|
||
};
|
||
$solution_view_type_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100 mt-2';
|
||
|
||
$difficulty_form = new UOJForm('difficulty');
|
||
$difficulty_form->addVInput('difficulty', 'text', '难度系数', $problem_extra_config['difficulty'],
|
||
function($str) {
|
||
if (!is_numeric($str)) {
|
||
return '难度系数必须是一个数字';
|
||
}
|
||
return '';
|
||
},
|
||
null);
|
||
$difficulty_form->handle = function() {
|
||
global $problem, $problem_extra_config;
|
||
$config = $problem_extra_config;
|
||
$config['difficulty'] = $_POST['difficulty'] + 0;
|
||
$esc_config = DB::escape(json_encode($config));
|
||
DB::query("update problems set extra_config = '$esc_config' where id = '{$problem['id']}'");
|
||
};
|
||
$difficulty_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100 mt-2';
|
||
|
||
if ($problem['hackable']) {
|
||
$test_std_form = new UOJForm('test_std');
|
||
$test_std_form->handle = function() {
|
||
global $myUser, $problem;
|
||
|
||
$user_std = queryUser('std');
|
||
if (!$user_std) {
|
||
becomeMsgPage('请建立 std 账号。');
|
||
}
|
||
|
||
$requirement = json_decode($problem['submission_requirement'], true);
|
||
|
||
$zip_file_name = uojRandAvaiableSubmissionFileName();
|
||
$zip_file = new ZipArchive();
|
||
if ($zip_file->open(UOJContext::storagePath().$zip_file_name, ZipArchive::CREATE) !== true) {
|
||
becomeMsgPage('提交失败');
|
||
}
|
||
|
||
$content = array();
|
||
$content['file_name'] = $zip_file_name;
|
||
$content['config'] = array();
|
||
foreach ($requirement as $req) {
|
||
if ($req['type'] == "source code") {
|
||
$content['config'][] = array("{$req['name']}_language", "C++");
|
||
}
|
||
}
|
||
|
||
$tot_size = 0;
|
||
foreach ($requirement as $req) {
|
||
$zip_file->addFile("/var/uoj_data/{$problem['id']}/std.cpp", $req['file_name']);
|
||
$tot_size += $zip_file->statName($req['file_name'])['size'];
|
||
}
|
||
|
||
$zip_file->close();
|
||
|
||
$content['config'][] = array('validate_input_before_test', 'on');
|
||
$content['config'][] = array('problem_id', $problem['id']);
|
||
$esc_content = DB::escape(json_encode($content));
|
||
$esc_language = DB::escape('C++');
|
||
|
||
$result = array();
|
||
$result['status'] = "Waiting";
|
||
$result_json = json_encode($result);
|
||
$is_hidden = $problem['is_hidden'] ? 1 : 0;
|
||
|
||
DB::insert("insert into submissions (problem_id, submit_time, submitter, content, language, tot_size, status, result, is_hidden) values ({$problem['id']}, now(), '{$user_std['username']}', '$esc_content', '$esc_language', $tot_size, '{$result['status']}', '$result_json', $is_hidden)");
|
||
};
|
||
$test_std_form->succ_href = "/submissions?problem_id={$problem['id']}";
|
||
$test_std_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100';
|
||
$test_std_form->submit_button_config['text'] = '检验数据正确性';
|
||
$test_std_form->runAtServer();
|
||
}
|
||
|
||
$hackable_form->runAtServer();
|
||
$view_type_form->runAtServer();
|
||
$solution_view_type_form->runAtServer();
|
||
$difficulty_form->runAtServer();
|
||
$data_form->runAtServer();
|
||
$clear_data_form->runAtServer();
|
||
$rejudge_form->runAtServer();
|
||
$rejudgege97_form->runAtServer();
|
||
$info_form->runAtServer();
|
||
?>
|
||
|
||
<?php echoUOJPageHeader(HTML::stripTags($problem['title']) . ' - 数据 - 题目管理') ?>
|
||
|
||
<div class="row">
|
||
<!-- left col -->
|
||
<div class="col-12 col-lg-9">
|
||
|
||
<h1 class="h2">
|
||
#<?=$problem['id']?>. <?=$problem['title']?> 管理
|
||
</h1>
|
||
|
||
<ul class="nav nav-pills my-3" role="tablist">
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/statement" role="tab">
|
||
题面
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/managers" role="tab">
|
||
管理者
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link active" href="/problem/<?= $problem['id'] ?>/manage/data" role="tab">
|
||
数据
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
|
||
<div class="card">
|
||
<div class="card-header" id="div-file_list">
|
||
<ul class="nav nav-tabs card-header-tabs">
|
||
<?php $data_disp->echoDataFilesList('problem.conf'); ?>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="card-body" id="div-file_content">
|
||
<?php $data_disp->displayFile('problem.conf'); ?>
|
||
</div>
|
||
|
||
<script type="text/javascript">
|
||
curFileName = '';
|
||
$('#div-file_list a').click(function(e) {
|
||
$('#div-file_content').html('<h3>Loading...</h3>');
|
||
$(this).tab('show');
|
||
|
||
var fileName = $(this).text();
|
||
curFileName = fileName;
|
||
$.get('/problem/<?= $problem['id'] ?>/manage/data', {
|
||
display_file: '',
|
||
file_name: fileName
|
||
},
|
||
function(data) {
|
||
if (curFileName != fileName) {
|
||
return;
|
||
}
|
||
$('#div-file_content').html(data);
|
||
},
|
||
'html'
|
||
);
|
||
return false;
|
||
});
|
||
</script>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
<!-- right col -->
|
||
<aside class="col-12 col-lg-3 mt-3 mt-lg-0 d-flex flex-column">
|
||
|
||
<div class="card card-default mt-3 mt-lg-0 mb-2 order-2 order-lg-1">
|
||
<ul class="nav nav-pills nav-fill flex-column" role="tablist">
|
||
<li class="nav-item text-start">
|
||
<a href="/problem/<?= $problem['id'] ?>" class="nav-link" role="tab">
|
||
<i class="bi bi-journal-text"></i>
|
||
<?= UOJLocale::get('problems::statement') ?>
|
||
</a>
|
||
</li>
|
||
<li class="nav-item text-start">
|
||
<a href="/problem/<?= $problem['id'] ?>/solutions" class="nav-link" role="tab">
|
||
<i class="bi bi-journal-bookmark"></i>
|
||
<?= UOJLocale::get('problems::solutions') ?>
|
||
</a>
|
||
</li>
|
||
<li class="nav-item text-start">
|
||
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/statistics">
|
||
<i class="bi bi-graph-up"></i>
|
||
<?= UOJLocale::get('problems::statistics') ?>
|
||
</a>
|
||
</li>
|
||
<li class="nav-item text-start">
|
||
<a class="nav-link active" href="#" role="tab">
|
||
<i class="bi bi-sliders"></i>
|
||
<?= UOJLocale::get('problems::manage') ?>
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
<div class="card-footer bg-transparent">
|
||
评价:<?= getClickZanBlock('P', $problem['id'], $problem['zan']) ?>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="order-1 order-lg-2">
|
||
<div>
|
||
<?php if ($problem['hackable']): ?>
|
||
<i class="bi bi-check-lg text-success"></i> Hack 功能已启用
|
||
<?php else: ?>
|
||
<i class="bi bi-x-lg text-danger"></i> Hack 功能已禁用
|
||
<?php endif ?>
|
||
<?php $hackable_form->printHTML() ?>
|
||
</div>
|
||
<?php if ($problem['hackable']): ?>
|
||
<div class="mt-2">
|
||
<?php $test_std_form->printHTML() ?>
|
||
</div>
|
||
<?php endif ?>
|
||
<div class="mt-2">
|
||
<button id="button-display_view_type" type="button" class="btn btn-primary d-block w-100" onclick="$('#div-view_type').toggle('fast');">提交记录可视权限</button>
|
||
<div class="mt-2" id="div-view_type" style="display:none; padding-left:5px; padding-right:5px;">
|
||
<?php $view_type_form->printHTML(); ?>
|
||
</div>
|
||
</div>
|
||
<div class="mt-2">
|
||
<button id="button-solution_view_type" type="button" class="btn btn-primary d-block w-100" onclick="$('#div-solution_view_type').toggle('fast');">题解可视权限</button>
|
||
<div class="mt-2" id="div-solution_view_type" style="display:none; padding-left:5px; padding-right:5px;">
|
||
<?php $solution_view_type_form->printHTML(); ?>
|
||
</div>
|
||
</div>
|
||
<div class="mt-2">
|
||
<?php $data_form->printHTML(); ?>
|
||
</div>
|
||
<div class="mt-2">
|
||
<?php $clear_data_form->printHTML(); ?>
|
||
</div>
|
||
<div class="mt-2">
|
||
<?php $rejudge_form->printHTML(); ?>
|
||
</div>
|
||
<div class="mt-2">
|
||
<?php $rejudgege97_form->printHTML(); ?>
|
||
</div>
|
||
|
||
<div class="mt-2">
|
||
<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>
|
||
</div>
|
||
|
||
<div class="mt-2">
|
||
<button id="button-difficulty" type="button" class="btn d-block w-100 btn-primary" onclick="$('#div-difficulty').toggle('fast');">难度系数</button>
|
||
<div class="mt-2" id="div-difficulty" style="display:none; padding-left:5px; padding-right:5px;">
|
||
<?php $difficulty_form->printHTML(); ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
|
||
</div>
|
||
|
||
<div class="modal fade" id="UploadDataModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||
<div class="modal-dialog">
|
||
<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>
|
||
<div class="modal-body">
|
||
<form action="" method="post" enctype="multipart/form-data" role="form">
|
||
<div class="form-group">
|
||
<label for="exampleInputFile">上传zip文件</label>
|
||
<input type="file" name="problem_data_file" id="problem_data_file">
|
||
<p class="help-block">说明:请将所有数据放置于压缩包根目录内。若压缩包内仅存在文件夹而不存在文件,则会将这些一级子文件夹下的内容移动到根目录下,然后这些一级子文件夹删除;若这些子文件夹内存在同名文件,则会发生随机替换,仅保留一个副本。</p>
|
||
</div>
|
||
<input type="hidden" name="problem_data_file_submit" value="submit">
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="submit" class="btn btn-success">上传</button>
|
||
</form>
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<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>
|
||
<div class="modal-body">
|
||
<form class="form-horizontal" action="" method="post" role="form">
|
||
<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 = is_array($problem_conf) ? getUOJConfVal($problem_conf, '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 = is_array($problem_conf) ? getUOJConfVal($problem_conf, '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 = is_array($problem_conf) ? getUOJConfVal($problem_conf, '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 = is_array($problem_conf) ? getUOJConfVal($problem_conf, '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 = is_array($problem_conf) ? getUOJConfVal($problem_conf, '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 = is_array($problem_conf) ? getUOJConfVal($problem_conf, '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 = is_array($problem_conf) ? getUOJConfVal($problem_conf, '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 = is_array($problem_conf) ? getUOJConfVal($problem_conf, '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 = is_array($problem_conf) ? getUOJConfVal($problem_conf, 'time_limit', 1) : ""; ?>
|
||
<input type="number" 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 = is_array($problem_conf) ? getUOJConfVal($problem_conf, '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>
|
||
</form>
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<?php echoUOJPageFooter() ?>
|