problem_data_manage.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  1. <?php
  2. requirePHPLib('form');
  3. requirePHPLib('judger');
  4. requirePHPLib('data');
  5. if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) {
  6. become404Page();
  7. }
  8. if (!hasProblemCtrlPermission($myUser, $problem)) {
  9. become403Page();
  10. }
  11. $group = queryUser($problem['ctrl']);
  12. $oj_name = UOJConfig::$data['profile']['oj-name'];
  13. $problem_extra_config = getProblemExtraConfig($problem);
  14. $data_dir = "/var/uoj_data/${problem['id']}";
  15. function echoFileNotFound($file_name) {
  16. echo '<h4>', htmlspecialchars($file_name), '<sub class="text-danger"> ', '文件未找到', '</sub></h4>';
  17. }
  18. function echoFilePre($file_name) {
  19. global $data_dir;
  20. $file_full_name = $data_dir . '/' . $file_name;
  21. $finfo = finfo_open(FILEINFO_MIME);
  22. $mimetype = finfo_file($finfo, $file_full_name);
  23. if ($mimetype === false) {
  24. echoFileNotFound($file_name);
  25. return;
  26. }
  27. finfo_close($finfo);
  28. echo '<h4>', htmlspecialchars($file_name), '<sub> ', $mimetype, '</sub></h4>';
  29. echo "<pre>\n";
  30. $output_limit = 1000;
  31. if (strStartWith($mimetype, 'text/')) {
  32. echo htmlspecialchars(uojFilePreview($file_full_name, $output_limit));
  33. } else {
  34. echo htmlspecialchars(uojFilePreview($file_full_name, $output_limit, 'binary'));
  35. }
  36. echo "\n</pre>";
  37. }
  38. //上传数据
  39. if ($_POST['problem_data_file_submit']=='submit') {
  40. if ($_FILES["problem_data_file"]["error"] > 0) {
  41. $errmsg = "Error: ".$_FILES["problem_data_file"]["error"];
  42. becomeMsgPage('<div>' . $errmsg . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
  43. } else {
  44. $zip_mime_types = array('application/zip', 'application/x-zip', 'application/x-zip-compressed');
  45. 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') {
  46. $up_filename="/tmp/".rand(0,100000000)."data.zip";
  47. move_uploaded_file($_FILES["problem_data_file"]["tmp_name"], $up_filename);
  48. if (queryGroupTotalSize($group) + filesize($up_filename) > queryGroupQuota($group)) {
  49. $errmsg = '组空间配额超限。';
  50. unlink($up_filename);
  51. becomeMsgPage('<div>' . $errmsg . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
  52. }
  53. $zip = new ZipArchive;
  54. if ($zip->open($up_filename) === TRUE) {
  55. $zip->extractTo("/var/uoj_data/upload/{$problem['id']}");
  56. $zip->close();
  57. exec("cd /var/uoj_data/upload/{$problem['id']}; if [ -z \"`find . -maxdepth 1 -type f`\" ]; then for sub_dir in `find -maxdepth 1 -type d ! -name .`; do mv -f \$sub_dir/* . && rm -rf \$sub_dir; done; fi");
  58. echo "<script>alert('上传成功!')</script>";
  59. } else {
  60. $errmsg = "解压失败!";
  61. becomeMsgPage('<div>' . $errmsg . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
  62. }
  63. unlink($up_filename);
  64. } else {
  65. $errmsg = "请上传zip格式!";
  66. becomeMsgPage('<div>' . $errmsg . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
  67. }
  68. }
  69. }
  70. //添加配置文件
  71. if ($_POST['problem_settings_file_submit']=='submit') {
  72. if ($_POST['use_builtin_checker'] and $_POST['n_tests'] and $_POST['input_pre'] and $_POST['input_suf'] and $_POST['output_pre'] and $_POST['output_suf'] and $_POST['time_limit'] and $_POST['memory_limit']) {
  73. $set_filename="/var/uoj_data/upload/{$problem['id']}/problem.conf";
  74. $has_legacy=false;
  75. if (file_exists($set_filename)) {
  76. $has_legacy=true;
  77. unlink($set_filename);
  78. }
  79. $setfile = fopen($set_filename, "w");
  80. fwrite($setfile, "use_builtin_judger on\n");
  81. if ($_POST['use_builtin_checker'] != 'ownchk') {
  82. fwrite($setfile, "use_builtin_checker ".$_POST['use_builtin_checker']."\n");
  83. }
  84. fwrite($setfile, "n_tests ".$_POST['n_tests']."\n");
  85. if ($_POST['n_ex_tests']) {
  86. fwrite($setfile, "n_ex_tests ".$_POST['n_ex_tests']."\n");
  87. } else {
  88. fwrite($setfile, "n_ex_tests 0\n");
  89. }
  90. if ($_POST['n_sample_tests']) {
  91. fwrite($setfile, "n_sample_tests ".$_POST['n_sample_tests']."\n");
  92. } else {
  93. fwrite($setfile, "n_sample_tests 0\n");
  94. }
  95. fwrite($setfile, "input_pre ".$_POST['input_pre']."\n");
  96. fwrite($setfile, "input_suf ".$_POST['input_suf']."\n");
  97. fwrite($setfile, "output_pre ".$_POST['output_pre']."\n");
  98. fwrite($setfile, "output_suf ".$_POST['output_suf']."\n");
  99. fwrite($setfile, "time_limit ".$_POST['time_limit']."\n");
  100. fwrite($setfile, "memory_limit ".$_POST['memory_limit']."\n");
  101. fclose($setfile);
  102. if (!$has_legacy) {
  103. echo "<script>alert('添加成功!')</script>";
  104. } else {
  105. echo "<script>alert('替换成功!')</script>";
  106. }
  107. } else {
  108. $errmsg = "添加配置文件失败,请检查是否所有输入框都已填写!";
  109. becomeMsgPage('<div>' . $errmsg . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
  110. }
  111. }
  112. $info_form = new UOJForm('info');
  113. $http_host = HTML::escape(UOJContext::httpHost());
  114. $download_url = HTML::url("/download.php?type=problem&id={$problem['id']}");
  115. $info_form->appendHTML(<<<EOD
  116. <div class="form-group row">
  117. <!--<label class="col-sm-3 control-label">zip上传数据</label>
  118. <div class="col-sm-9">
  119. <div class="form-control-static">
  120. <row>
  121. <button type="button" style="width:30%" class="btn btn-primary" data-toggle="modal" data-target="#UploadDataModal">上传数据</button>
  122. <button type="submit" style="width:30%" id="button-submit-data" name="submit-data" value="data" class="btn btn-danger">检验配置并同步数据</button>
  123. </row>
  124. </div>
  125. </div>-->
  126. </div>
  127. EOD
  128. );
  129. $info_form->appendHTML(<<<EOD
  130. <div class="form-group row">
  131. <label class="col-sm-3 control-label">problem_{$problem['id']}.zip</label>
  132. <div class="col-sm-9">
  133. <div class="form-control-static">
  134. <a href="$download_url">$download_url</a>
  135. </div>
  136. </div>
  137. </div>
  138. EOD
  139. );
  140. $info_form->appendHTML(<<<EOD
  141. <div class="form-group row">
  142. <label class="col-sm-3 control-label">testlib.h</label>
  143. <div class="col-sm-9">
  144. <div class="form-control-static">
  145. <a href="/download.php?type=testlib.h">下载</a>
  146. </div>
  147. </div>
  148. </div>
  149. EOD
  150. );
  151. $esc_submission_requirement = HTML::escape(json_encode(json_decode($problem['submission_requirement']), JSON_PRETTY_PRINT));
  152. $info_form->appendHTML(<<<EOD
  153. <div class="form-group row">
  154. <label class="col-sm-3 control-label">提交文件配置</label>
  155. <div class="col-sm-9">
  156. <div class="form-control-static"><pre>
  157. $esc_submission_requirement
  158. </pre>
  159. </div>
  160. </div>
  161. </div>
  162. EOD
  163. );
  164. $esc_extra_config = HTML::escape(json_encode(json_decode($problem['extra_config']), JSON_PRETTY_PRINT));
  165. $info_form->appendHTML(<<<EOD
  166. <div class="form-group row">
  167. <label class="col-sm-3 control-label">其它配置</label>
  168. <div class="col-sm-9">
  169. <div class="form-control-static"><pre>
  170. $esc_extra_config
  171. </pre>
  172. </div>
  173. </div>
  174. </div>
  175. EOD
  176. );
  177. if (isSuperUser($myUser)) {
  178. $info_form->addVInput('submission_requirement', 'text', '提交文件配置', $problem['submission_requirement'],
  179. function ($submission_requirement, &$vdata) {
  180. $submission_requirement = json_decode($submission_requirement, true);
  181. if ($submission_requirement === null) {
  182. return '不是合法的JSON';
  183. }
  184. $vdata['submission_requirement'] = json_encode($submission_requirement);
  185. },
  186. null);
  187. $info_form->addVInput('extra_config', 'text', '其它配置', $problem['extra_config'],
  188. function ($extra_config, &$vdata) {
  189. $extra_config = json_decode($extra_config, true);
  190. if ($extra_config === null) {
  191. return '不是合法的JSON';
  192. }
  193. $vdata['extra_config'] = json_encode($extra_config);
  194. },
  195. null);
  196. $info_form->handle = function(&$vdata) {
  197. global $problem;
  198. $esc_submission_requirement = DB::escape($vdata['submission_requirement']);
  199. $esc_extra_config = DB::escape($vdata['extra_config']);
  200. DB::update("update problems set submission_requirement = '$esc_submission_requirement', extra_config = '$esc_extra_config' where id = {$problem['id']}");
  201. };
  202. } else {
  203. $info_form->no_submit = true;
  204. }
  205. class DataDisplayer {
  206. public $problem_conf = array();
  207. public $data_files = array();
  208. public $displayers = array();
  209. public function __construct($problem_conf = null, $data_files = null) {
  210. global $data_dir;
  211. if (isset($problem_conf)) {
  212. foreach ($problem_conf as $key => $val) {
  213. $this->problem_conf[$key] = array('val' => $val);
  214. }
  215. }
  216. if (!isset($data_files)) {
  217. $this->data_files = array_filter(scandir($data_dir), function($x) {
  218. return $x !== '.' && $x !== '..' && $x !== 'problem.conf';
  219. });
  220. natsort($this->data_files);
  221. array_unshift($this->data_files, 'problem.conf');
  222. } else {
  223. $this->data_files = $data_files;
  224. }
  225. $this->setDisplayer('problem.conf', function($self) {
  226. global $info_form;
  227. $info_form->printHTML();
  228. echo '<div class="top-buffer-md"></div>';
  229. echo '<table class="table table-bordered table-hover table-striped table-text-center">';
  230. echo '<thead>';
  231. echo '<tr>';
  232. echo '<th>key</th>';
  233. echo '<th>value</th>';
  234. echo '</tr>';
  235. echo '</thead>';
  236. echo '<tbody>';
  237. foreach ($self->problem_conf as $key => $info) {
  238. if (!isset($info['status'])) {
  239. echo '<tr>';
  240. echo '<td>', htmlspecialchars($key), '</td>';
  241. echo '<td>', htmlspecialchars($info['val']), '</td>';
  242. echo '</tr>';
  243. } elseif ($info['status'] == 'danger') {
  244. echo '<tr class="text-danger">';
  245. echo '<td>', htmlspecialchars($key), '</td>';
  246. echo '<td>', htmlspecialchars($info['val']), ' <span class="glyphicon glyphicon-remove"></span>', '</td>';
  247. echo '</tr>';
  248. }
  249. }
  250. echo '</tbody>';
  251. echo '</table>';
  252. echoFilePre('problem.conf');
  253. });
  254. }
  255. public function setProblemConfRowStatus($key, $status) {
  256. $this->problem_conf[$key]['status'] = $status;
  257. return $this;
  258. }
  259. public function setDisplayer($file_name, $fun) {
  260. $this->displayers[$file_name] = $fun;
  261. return $this;
  262. }
  263. public function addDisplayer($file_name, $fun) {
  264. $this->data_files[] = $file_name;
  265. $this->displayers[$file_name] = $fun;
  266. return $this;
  267. }
  268. public function echoDataFilesList($active_file) {
  269. foreach ($this->data_files as $file_name) {
  270. echo '<li class="nav-item">';
  271. if ($file_name != $active_file) {
  272. echo '<a class="nav-link" href="#">';
  273. } else {
  274. echo '<a class="nav-link active" href="#">';
  275. }
  276. echo htmlspecialchars($file_name), '</a>', '</li>';
  277. }
  278. }
  279. public function displayFile($file_name) {
  280. global $data_dir;
  281. if (isset($this->displayers[$file_name])) {
  282. $fun = $this->displayers[$file_name];
  283. $fun($this);
  284. } elseif (in_array($file_name, $this->data_files)) {
  285. echoFilePre($file_name);
  286. } else {
  287. echoFileNotFound($file_name);
  288. }
  289. }
  290. }
  291. function getDataDisplayer() {
  292. global $data_dir;
  293. global $problem;
  294. $allow_files = array_flip(array_filter(scandir($data_dir), function($x) {
  295. return $x !== '.' && $x !== '..';
  296. }));
  297. $getDisplaySrcFunc = function($name) use ($allow_files) {
  298. return function() use ($name, $allow_files) {
  299. $src_name = $name . '.cpp';
  300. if (isset($allow_files[$src_name])) {
  301. echoFilePre($src_name);
  302. } else {
  303. echoFileNotFound($src_name);
  304. }
  305. if (isset($allow_files[$name])) {
  306. echoFilePre($name);
  307. } else {
  308. echoFileNotFound($name);
  309. }
  310. };
  311. };
  312. $problem_conf = getUOJConf("$data_dir/problem.conf");
  313. if ($problem_conf === -1) {
  314. return (new DataDisplayer())->setDisplayer('problem.conf', function() {
  315. global $info_form;
  316. $info_form->printHTML();
  317. echoFileNotFound('problem.conf');
  318. });
  319. }
  320. if ($problem_conf === -2) {
  321. return (new DataDisplayer())->setDisplayer('problem.conf', function() {
  322. global $info_form;
  323. $info_form->printHTML();
  324. echo '<h4 class="text-danger">problem.conf 格式有误</h4>';
  325. echoFilePre('problem.conf');
  326. });
  327. }
  328. $judger_name = getUOJConfVal($problem_conf, 'use_builtin_judger', null);
  329. if (!isset($problem_conf['use_builtin_judger'])) {
  330. return new DataDisplayer($problem_conf);
  331. }
  332. if ($problem_conf['use_builtin_judger'] == 'on') {
  333. $n_tests = getUOJConfVal($problem_conf, 'n_tests', 10);
  334. if (!validateUInt($n_tests)) {
  335. return (new DataDisplayer($problem_conf))->setProblemConfRowStatus('n_tests', 'danger');
  336. }
  337. $has_extra_tests = !(isset($problem_conf['submit_answer']) && $problem_conf['submit_answer'] == 'on');
  338. $data_disp = new DataDisplayer($problem_conf, array('problem.conf'));
  339. $data_disp->addDisplayer('tests',
  340. function($self) use ($problem_conf, $allow_files, $n_tests, $n_ex_tests) {
  341. for ($num = 1; $num <= $n_tests; $num++) {
  342. $input_file_name = getUOJProblemInputFileName($problem_conf, $num);
  343. $output_file_name = getUOJProblemOutputFileName($problem_conf, $num);
  344. echo '<div class="row">';
  345. echo '<div class="col-md-6">';
  346. if (isset($allow_files[$input_file_name])) {
  347. echoFilePre($input_file_name);
  348. } else {
  349. echoFileNotFound($input_file_name);
  350. }
  351. echo '</div>';
  352. echo '<div class="col-md-6">';
  353. if (isset($allow_files[$output_file_name])) {
  354. echoFilePre($output_file_name);
  355. } else {
  356. echoFileNotFound($output_file_name);
  357. }
  358. echo '</div>';
  359. echo '</div>';
  360. }
  361. }
  362. );
  363. if ($has_extra_tests) {
  364. $n_ex_tests = getUOJConfVal($problem_conf, 'n_ex_tests', 0);
  365. if (!validateUInt($n_ex_tests)) {
  366. return (new DataDisplayer($problem_conf))->setProblemConfRowStatus('n_ex_tests', 'danger');
  367. }
  368. $data_disp->addDisplayer('extra tests',
  369. function($self) use ($problem_conf, $allow_files, $n_tests, $n_ex_tests) {
  370. for ($num = 1; $num <= $n_ex_tests; $num++) {
  371. $input_file_name = getUOJProblemExtraInputFileName($problem_conf, $num);
  372. $output_file_name = getUOJProblemExtraOutputFileName($problem_conf, $num);
  373. echo '<div class="row">';
  374. echo '<div class="col-md-6">';
  375. if (isset($allow_files[$input_file_name])) {
  376. echoFilePre($input_file_name);
  377. } else {
  378. echoFileNotFound($input_file_name);
  379. }
  380. echo '</div>';
  381. echo '<div class="col-md-6">';
  382. if (isset($allow_files[$output_file_name])) {
  383. echoFilePre($output_file_name);
  384. } else {
  385. echoFileNotFound($output_file_name);
  386. }
  387. echo '</div>';
  388. echo '</div>';
  389. }
  390. }
  391. );
  392. }
  393. if (!isset($problem_conf['interaction_mode'])) {
  394. if (isset($problem_conf['use_builtin_checker'])) {
  395. $data_disp->addDisplayer('checker', function($self) {
  396. echo '<h4>use builtin checker : ', $self->problem_conf['use_builtin_checker']['val'], '</h4>';
  397. });
  398. } else {
  399. $data_disp->addDisplayer('checker', $getDisplaySrcFunc('chk'));
  400. }
  401. }
  402. if ($problem['hackable']) {
  403. $data_disp->addDisplayer('standard', $getDisplaySrcFunc('std'));
  404. $data_disp->addDisplayer('validator', $getDisplaySrcFunc('val'));
  405. }
  406. if (isset($problem_conf['interaction_mode'])) {
  407. $data_disp->addDisplayer('interactor', $getDisplaySrcFunc('interactor'));
  408. }
  409. return $data_disp;
  410. } else {
  411. return (new DataDisplayer($problem_conf))->setProblemConfRowStatus('use_builtin_judger', 'danger');
  412. }
  413. }
  414. $data_disp = getDataDisplayer();
  415. if (isset($_GET['display_file'])) {
  416. if (!isset($_GET['file_name'])) {
  417. echoFileNotFound('');
  418. } else {
  419. $data_disp->displayFile($_GET['file_name']);
  420. }
  421. die();
  422. }
  423. $hackable_form = new UOJForm('hackable');
  424. $hackable_form->handle = function() {
  425. global $problem;
  426. $problem['hackable'] = !$problem['hackable'];
  427. //$problem['hackable'] = 0;
  428. $ret = dataSyncProblemData($problem);
  429. if ($ret) {
  430. becomeMsgPage('<div>' . $ret . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
  431. }
  432. $hackable = $problem['hackable'] ? 1 : 0;
  433. DB::query("update problems set hackable = $hackable where id = ${problem['id']}");
  434. };
  435. $hackable_form->submit_button_config['class_str'] = 'btn btn-warning btn-block';
  436. $hackable_form->submit_button_config['text'] = $problem['hackable'] ? '禁止使用hack' : '允许使用hack';
  437. $hackable_form->submit_button_config['smart_confirm'] = '';
  438. $data_form = new UOJForm('data');
  439. $data_form->handle = function() {
  440. global $problem, $myUser;
  441. set_time_limit(60 * 5);
  442. $ret = dataSyncProblemData($problem, $myUser);
  443. if ($ret) {
  444. becomeMsgPage('<div>' . $ret . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
  445. }
  446. };
  447. $data_form->submit_button_config['class_str'] = 'btn btn-danger btn-block';
  448. $data_form->submit_button_config['text'] = '检验配置并同步';
  449. $data_form->submit_button_config['smart_confirm'] = '';
  450. $clear_data_form = new UOJForm('clear_data');
  451. $clear_data_form->handle = function() {
  452. global $problem;
  453. dataClearProblemData($problem);
  454. };
  455. $clear_data_form->submit_button_config['class_str'] = 'btn btn-danger btn-block';
  456. $clear_data_form->submit_button_config['text'] = '清空题目数据';
  457. $clear_data_form->submit_button_config['smart_confirm'] = '';
  458. $rejudge_form = new UOJForm('rejudge');
  459. $rejudge_form->handle = function() {
  460. global $problem;
  461. rejudgeProblem($problem);
  462. };
  463. $rejudge_form->succ_href = "/submissions?problem_id={$problem['id']}";
  464. $rejudge_form->submit_button_config['class_str'] = 'btn btn-danger btn-block';
  465. $rejudge_form->submit_button_config['text'] = '重测该题';
  466. $rejudge_form->submit_button_config['smart_confirm'] = '';
  467. $rejudgege97_form = new UOJForm('rejudgege97');
  468. $rejudgege97_form->handle = function() {
  469. global $problem;
  470. rejudgeProblemGe97($problem);
  471. };
  472. $rejudgege97_form->succ_href = "/submissions?problem_id={$problem['id']}";
  473. $rejudgege97_form->submit_button_config['class_str'] = 'btn btn-danger btn-block';
  474. $rejudgege97_form->submit_button_config['text'] = '重测 >=97 的程序';
  475. $rejudgege97_form->submit_button_config['smart_confirm'] = '';
  476. $view_type_form = new UOJForm('view_type');
  477. $view_type_form->addVSelect('view_content_type',
  478. array('NONE' => '禁止',
  479. 'SELF' => '仅自己',
  480. 'ALL_AFTER_AC' => 'AC后',
  481. 'ALL' => '所有人'
  482. ),
  483. '查看提交文件:',
  484. $problem_extra_config['view_content_type']
  485. );
  486. $view_type_form->addVSelect('view_all_details_type',
  487. array('NONE' => '禁止',
  488. 'SELF' => '仅自己',
  489. 'ALL_AFTER_AC' => 'AC后',
  490. 'ALL' => '所有人'
  491. ),
  492. '查看全部详细信息:',
  493. $problem_extra_config['view_all_details_type']
  494. );
  495. $view_type_form->addVSelect('view_details_type',
  496. array('NONE' => '禁止',
  497. 'SELF' => '仅自己',
  498. 'ALL_AFTER_AC' => 'AC后',
  499. 'ALL' => '所有人'
  500. ),
  501. '查看测试点详细信息:',
  502. $problem_extra_config['view_details_type']
  503. );
  504. $view_type_form->handle = function() {
  505. global $problem, $problem_extra_config;
  506. $config = $problem_extra_config;
  507. $config['view_content_type'] = $_POST['view_content_type'];
  508. $config['view_all_details_type'] = $_POST['view_all_details_type'];
  509. $config['view_details_type'] = $_POST['view_details_type'];
  510. $esc_config = DB::escape(json_encode($config));
  511. DB::query("update problems set extra_config = '$esc_config' where id = '{$problem['id']}'");
  512. };
  513. $view_type_form->submit_button_config['class_str'] = 'btn btn-warning btn-block top-buffer-sm';
  514. if ($problem['hackable']) {
  515. $test_std_form = new UOJForm('test_std');
  516. $test_std_form->handle = function() {
  517. global $myUser, $problem;
  518. $user_std = queryUser('std');
  519. if (!$user_std) {
  520. becomeMsgPage('请建立"std"账号。');
  521. }
  522. $requirement = json_decode($problem['submission_requirement'], true);
  523. $zip_file_name = uojRandAvaiableSubmissionFileName();
  524. $zip_file = new ZipArchive();
  525. if ($zip_file->open(UOJContext::storagePath().$zip_file_name, ZipArchive::CREATE) !== true) {
  526. becomeMsgPage('提交失败');
  527. }
  528. $content = array();
  529. $content['file_name'] = $zip_file_name;
  530. $content['config'] = array();
  531. foreach ($requirement as $req) {
  532. if ($req['type'] == "source code") {
  533. $content['config'][] = array("{$req['name']}_language", "C++17");
  534. }
  535. }
  536. $tot_size = 0;
  537. foreach ($requirement as $req) {
  538. $zip_file->addFile("/var/uoj_data/{$problem['id']}/std.cpp", $req['file_name']);
  539. $tot_size += $zip_file->statName($req['file_name'])['size'];
  540. }
  541. $zip_file->close();
  542. $content['config'][] = array('validate_input_before_test', 'on');
  543. $content['config'][] = array('problem_id', $problem['id']);
  544. $esc_content = DB::escape(json_encode($content));
  545. $esc_language = DB::escape('C++');
  546. $result = array();
  547. $result['status'] = "Waiting";
  548. $result_json = json_encode($result);
  549. $is_hidden = $problem['is_hidden'] ? 1 : 0;
  550. 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)");
  551. };
  552. $test_std_form->succ_href = "/submissions?problem_id={$problem['id']}";
  553. $test_std_form->submit_button_config['class_str'] = 'btn btn-danger btn-block';
  554. $test_std_form->submit_button_config['text'] = '检验数据正确性';
  555. $test_std_form->runAtServer();
  556. }
  557. $hackable_form->runAtServer();
  558. $view_type_form->runAtServer();
  559. $data_form->runAtServer();
  560. $clear_data_form->runAtServer();
  561. $rejudge_form->runAtServer();
  562. $rejudgege97_form->runAtServer();
  563. $info_form->runAtServer();
  564. ?>
  565. <?php
  566. $REQUIRE_LIB['dialog'] = '';
  567. ?>
  568. <?php echoUOJPageHeader(HTML::stripTags($problem['title']) . ' - 数据 - 题目管理') ?>
  569. <h1 class="page-header" align="center">#<?=$problem['id']?> : <?=$problem['title']?> 管理</h1>
  570. <ul class="nav nav-tabs" role="tablist">
  571. <li class="nav-item"><a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/statement" role="tab">编辑</a></li>
  572. <li class="nav-item"><a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/managers" role="tab">管理者</a></li>
  573. <li class="nav-item"><a class="nav-link active" href="/problem/<?= $problem['id'] ?>/manage/data" role="tab">数据</a></li>
  574. <li class="nav-item"><a class="nav-link" href="/problem/<?=$problem['id']?>" role="tab">返回</a></li>
  575. </ul>
  576. <div class="row">
  577. <div class="col-md-10 top-buffer-sm">
  578. <div class="row">
  579. <div class="col-md-3 top-buffer-sm" id="div-file_list">
  580. <ul class="nav nav-pills flex-column">
  581. <?php $data_disp->echoDataFilesList('problem.conf'); ?>
  582. </ul>
  583. </div>
  584. <div class="col-md-9 top-buffer-sm" id="div-file_content">
  585. <?php $data_disp->displayFile('problem.conf'); ?>
  586. </div>
  587. <script type="text/javascript">
  588. curFileName = '';
  589. $('#div-file_list a').click(function(e) {
  590. $('#div-file_content').html('<h3>Loading...</h3>');
  591. $(this).tab('show');
  592. var fileName = $(this).text();
  593. curFileName = fileName;
  594. $.get('/problem/<?= $problem['id'] ?>/manage/data', {
  595. display_file: '',
  596. file_name: fileName
  597. },
  598. function(data) {
  599. if (curFileName != fileName) {
  600. return;
  601. }
  602. $('#div-file_content').html(data);
  603. },
  604. 'html'
  605. );
  606. return false;
  607. });
  608. </script>
  609. </div>
  610. </div>
  611. <div class="col-md-2 top-buffer-sm">
  612. <div class="top-buffer-md">
  613. <?php if ($problem['hackable']): ?>
  614. <span class="glyphicon glyphicon-ok"></span> hack功能已启用
  615. <?php else: ?>
  616. <span class="glyphicon glyphicon-remove"></span> hack功能已禁止
  617. <?php endif ?>
  618. <?php $hackable_form->printHTML() ?>
  619. </div>
  620. <div class="top-buffer-md">
  621. <?php if ($problem['hackable']): ?>
  622. <?php $test_std_form->printHTML() ?>
  623. <?php endif ?>
  624. </div>
  625. <div class="top-buffer-md">
  626. <button id="button-display_view_type" type="button" class="btn btn-primary btn-block" onclick="$('#div-view_type').toggle('fast');">提交记录可视权限</button>
  627. <div class="top-buffer-sm" id="div-view_type" style="display:none; padding-left:5px; padding-right:5px;">
  628. <?php $view_type_form->printHTML(); ?>
  629. </div>
  630. </div>
  631. <div class="top-buffer-md">
  632. <?php $data_form->printHTML(); ?>
  633. </div>
  634. <div class="top-buffer-md">
  635. <?php $clear_data_form->printHTML(); ?>
  636. </div>
  637. <div class="top-buffer-md">
  638. <?php $rejudge_form->printHTML(); ?>
  639. </div>
  640. <div class="top-buffer-md">
  641. <?php $rejudgege97_form->printHTML(); ?>
  642. </div>
  643. <div class="top-buffer-md">
  644. <button type="button" class="btn btn-block btn-primary" data-toggle="modal" data-target="#UploadDataModal">上传数据</button>
  645. </div>
  646. <div class="top-buffer-md">
  647. <button type="button" class="btn btn-block btn-primary" data-toggle="modal" data-target="#ProblemSettingsFileModal">试题配置</button>
  648. </div>
  649. </div>
  650. <div class="modal fade" id="UploadDataModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  651. <div class="modal-dialog">
  652. <div class="modal-content">
  653. <div class="modal-header">
  654. <h4 class="modal-title" id="myModalLabel">上传数据</h4>
  655. <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
  656. </div>
  657. <div class="modal-body">
  658. <form action="" method="post" enctype="multipart/form-data" role="form">
  659. <div class="form-group">
  660. <label for="exampleInputFile">上传zip文件</label>
  661. <input type="file" name="problem_data_file" id="problem_data_file">
  662. <p class="help-block">说明:请将所有数据放置于压缩包根目录内。若压缩包内仅存在文件夹而不存在文件,则会将这些一级子文件夹下的内容移动到根目录下,然后这些一级子文件夹删除;若这些子文件夹内存在同名文件,则会发生随机替换,仅保留一个副本。
  663. <?php
  664. echo "<br>本组剩余空间配额:<b class='text-danger'>"
  665. . printSize(queryGroupQuota($group) - queryGroupTotalSize($group))
  666. ?></b></p>
  667. </div>
  668. <input type="hidden" name="problem_data_file_submit" value="submit">
  669. </div>
  670. <div class="modal-footer">
  671. <button type="submit" class="btn btn-success">上传</button>
  672. </form>
  673. <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
  674. </div>
  675. </div>
  676. </div>
  677. </div>
  678. <div class="modal fade" id="ProblemSettingsFileModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  679. <div class="modal-dialog">
  680. <div class="modal-content">
  681. <div class="modal-header">
  682. <h4 class="modal-title" id="myModalLabel">试题配置</h4>
  683. <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
  684. </div>
  685. <div class="modal-body">
  686. <form class="form-horizontal" action="" method="post" role="form">
  687. <div class="form-group row">
  688. <label for="use_builtin_checker" class="col-sm-5 control-label">比对函数</label>
  689. <div class="col-sm-7">
  690. <select class="form-control" id="use_builtin_checker" name="use_builtin_checker">
  691. <option value="ncmp">单行整数序列</option>
  692. <option value="wcmp">单行字符串序列</option>
  693. <option value="fcmp">多行数据(不忽略行末空格,但忽略文末回车)</option>
  694. <option value="ownchk">自定义校验器</option>
  695. </select>
  696. <!--<input type="hidden" class="form-control" id="use_builtin_checker" name="use_builtin_checker" placeholder="比对函数">-->
  697. </div>
  698. </div>
  699. <div class="form-group row">
  700. <label for="n_tests" class="col-sm-5 control-label">n_tests</label>
  701. <div class="col-sm-7">
  702. <input type="text" class="form-control" id="n_tests" name="n_tests" placeholder="数据点个数">
  703. </div>
  704. </div>
  705. <div class="form-group row">
  706. <label for="n_ex_tests" class="col-sm-5 control-label">n_ex_tests</label>
  707. <div class="col-sm-7">
  708. <input type="text" class="form-control" id="n_ex_tests" name="n_ex_tests" placeholder="额外数据点个数">
  709. </div>
  710. </div>
  711. <div class="form-group row">
  712. <label for="n_sample_tests" class="col-sm-5 control-label">n_sample_tests</label>
  713. <div class="col-sm-7">
  714. <input type="text" class="form-control" id="n_sample_tests" name="n_sample_tests" placeholder="样例测试点个数">
  715. </div>
  716. </div>
  717. <div class="form-group row">
  718. <label for="input_pre" class="col-sm-5 control-label">input_pre</label>
  719. <div class="col-sm-7">
  720. <input type="text" class="form-control" id="input_pre" name="input_pre" placeholder="输入文件名称">
  721. </div>
  722. </div>
  723. <div class="form-group row">
  724. <label for="input_suf" class="col-sm-5 control-label">input_suf</label>
  725. <div class="col-sm-7">
  726. <input type="text" class="form-control" id="input_suf" name="input_suf" placeholder="输入文件后缀">
  727. </div>
  728. </div>
  729. <div class="form-group row">
  730. <label for="output_pre" class="col-sm-5 control-label">output_pre</label>
  731. <div class="col-sm-7">
  732. <input type="text" class="form-control" id="output_pre" name="output_pre" placeholder="输出文件名称">
  733. </div>
  734. </div>
  735. <div class="form-group row">
  736. <label for="output_suf" class="col-sm-5 control-label">output_suf</label>
  737. <div class="col-sm-7">
  738. <input type="text" class="form-control" id="output_suf" name="output_suf" placeholder="输出文件后缀">
  739. </div>
  740. </div>
  741. <div class="form-group row">
  742. <label for="time_limit" class="col-sm-5 control-label">time_limit</label>
  743. <div class="col-sm-7">
  744. <input type="text" class="form-control" id="time_limit" name="time_limit" placeholder="时间限制(不能为小数!)">
  745. </div>
  746. </div>
  747. <div class="form-group row">
  748. <label for="memory_limit" class="col-sm-5 control-label">memory_limit</label>
  749. <div class="col-sm-7">
  750. <input type="text" class="form-control" id="memory_limit" name="memory_limit" placeholder="内存限制">
  751. </div>
  752. </div>
  753. <input type="hidden" name="problem_settings_file_submit" value="submit">
  754. </div>
  755. <div class="modal-footer">
  756. <button type="submit" class="btn btn-success">确定</button>
  757. </form>
  758. <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
  759. </div>
  760. </div>
  761. </div>
  762. </div>
  763. </div>
  764. <?php echoUOJPageFooter() ?>