problem_set.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. <?php
  2. requirePHPLib('form');
  3. requirePHPLib('judger');
  4. requirePHPLib('data');
  5. if ($_POST['migrate_problem_submit'] == 'submit') {
  6. if ($myUser == null) {
  7. redirectToLogin();
  8. }
  9. $group = queryUser(DB::escape($_POST['target_group']));
  10. $start = $_POST['start_pid'];
  11. $end = $_POST['end_pid'];
  12. if (!validateUInt($start) || !validateUInt($end)) {
  13. $errmsg = 'Error: 不合法起始终止题号';
  14. becomeMsgPage('<div>' . $errmsg . '</div><a href="/problems">返回</a>');
  15. }
  16. if (!$group) {
  17. $errmsg = "Error: 未找到组 " . HTML::escape($_POST['target_group']);
  18. becomeMsgPage('<div>' . $errmsg . '</div><a href="/problems">返回</a>');
  19. }
  20. if (!hasGroupCtrlPermission($myUser, $group)) {
  21. $errmsg = "Error: 你对组 {$group['username']} 没有控制权";
  22. becomeMsgPage('<div>' . $errmsg . '</div><a href="/problems">返回</a>');
  23. }
  24. for ($i = $start; $i <= $end; $i++) {
  25. if (!hasProblemCtrlPermission($myUser, queryProblemBrief($i))) {
  26. $errmsg = "Error: 你对题目 $i 没有控制权";
  27. becomeMsgPage('<div>' . $errmsg . '</div><a href="/problems">返回</a>');
  28. }
  29. }
  30. for ($i = $start; $i <= $end; $i++) {
  31. attachProblemToGroup(queryProblemBrief($i), $group);
  32. DB::update("update problems set ctrl = '{$group['username']}' where id = $i");
  33. }
  34. }
  35. if ($_POST['copy_problem_submit'] == 'submit') {
  36. if ($myUser == null) {
  37. redirectToLogin();
  38. }
  39. $problems = explode(',', $_POST['copy_problem_list'] ?? '');
  40. if (count($problems) > 10) {
  41. $errmsg = "Error: 你不能一次复制超过 10 个题目";
  42. becomeMsgPage('<div>' . $errmsg . '</div><a href="/problems">返回</a>');
  43. }
  44. // Every id must be validated *before* it is used: queryProblemBrief()
  45. // and queryProblemContent() interpolate it into SQL, and
  46. // dataCopyProblemData() interpolates it straight into exec().
  47. foreach ($problems as $pid) {
  48. if (!validateUInt($pid)) {
  49. $errmsg = "Error: 不合法的题目 ID";
  50. becomeMsgPage('<div>' . $errmsg . '</div><a href="/problems">返回</a>');
  51. }
  52. }
  53. foreach ($problems as $pid) {
  54. if (!hasProblemCtrlPermission($myUser, queryProblemBrief($pid))) {
  55. $errmsg = "Error: 你对题目 $pid 没有控制权";
  56. becomeMsgPage('<div>' . $errmsg . '</div><a href="/problems">返回</a>');
  57. }
  58. }
  59. foreach ($problems as $pid) {
  60. $p = queryProblemBrief($pid);
  61. $title = DB::escape($p['title']);
  62. $q = queryProblemContent($pid);
  63. $stat = DB::escape($q['statement']);
  64. $statmd = DB::escape($q['statement_md']);
  65. DB::query("insert into problems (title, is_hidden, submission_requirement, ctrl) values ('$title', {$p['is_hidden']}, '{$p['submission_requirement']}', '{$p['ctrl']}')");
  66. $id = DB::insert_id();
  67. DB::query("insert into problems_contents (id, statement, statement_md) values ($id, '$stat', '$statmd')");
  68. dataCopyProblemData($pid, $id);
  69. attachProblemToGroup(queryProblemBrief($id), queryUser($p['ctrl']));
  70. }
  71. }
  72. function echoProblem($problem) {
  73. global $myUser;
  74. if (isProblemVisibleToUser($problem, $myUser)) {
  75. echo '<tr class="text-center">';
  76. if ($problem['submission_id']) {
  77. echo '<td class="table-success">';
  78. } else {
  79. echo '<td>';
  80. }
  81. echo '#', $problem['id'], '</td>';
  82. echo '<td class="text-left">';
  83. if ($problem['is_hidden']) {
  84. echo ' <span class="text-danger">[隐藏]</span> ';
  85. }
  86. echo '<a href="/problem/', $problem['id'], '">', HTML::escape($problem['title']), '</a>';
  87. echo '<td><a href="/user/profile/', $problem['ctrl'], '">', HTML::escape(queryUser($problem['ctrl'])['email']), ' (', $problem['ctrl'], ')</a></td>';
  88. if (isset($_COOKIE['show_tags_mode'])) {
  89. foreach (queryProblemTags($problem['id']) as $tag) {
  90. echo '<a class="uoj-problem-tag">', '<span class="badge badge-pill badge-secondary">', HTML::escape($tag), '</span>', '</a>';
  91. }
  92. }
  93. echo '</td>';
  94. if (isset($_COOKIE['show_submit_mode'])) {
  95. $perc = $problem['submit_num'] > 0 ? round(100 * $problem['ac_num'] / $problem['submit_num']) : 0;
  96. echo <<<EOD
  97. <td><a href="/submissions?problem_id={$problem['id']}&min_score=100&max_score=100">&times;{$problem['ac_num']}</a></td>
  98. <td><a href="/submissions?problem_id={$problem['id']}">&times;{$problem['submit_num']}</a></td>
  99. <td>
  100. <div class="progress bot-buffer-no">
  101. <div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="$perc" aria-valuemin="0" aria-valuemax="100" style="width: $perc%; min-width: 20px;">{$perc}%</div>
  102. </div>
  103. </td>
  104. EOD;
  105. }
  106. echo '<td class="text-middle">', getClickZanBlock('P', $problem['id'], $problem['zan']), '</td>';
  107. echo '</tr>';
  108. }
  109. }
  110. $cond = array();
  111. $search_tag = null;
  112. $cur_tab = isset($_GET['tab']) ? $_GET['tab'] : 'all';
  113. if ($cur_tab == 'template') {
  114. $search_tag = "模板题";
  115. }
  116. if (isset($_GET['tag'])) {
  117. $search_tag = $_GET['tag'];
  118. }
  119. if ($search_tag) {
  120. $cond[] = "'".DB::escape($search_tag)."' in (select tag from problems_tags where problems_tags.problem_id = problems.id)";
  121. }
  122. if (isset($_GET["search"])) {
  123. $cond[]="title like '%".DB::escape($_GET["search"])."%' or id like '%".DB::escape($_GET["search"])."%'";
  124. }
  125. if (isset($_GET['group'])) {
  126. $groupname = $_GET['group'];
  127. $cur_tab = $groupname;
  128. $group = queryUser($groupname);
  129. if ($group == null) become404Page();
  130. if (!in_array($groupname, queryUserExtgroups($myUser))) become403Page();
  131. $cond[] = "find_in_set(id, (select privs from user_info where username = '$groupname'))";
  132. }
  133. else {
  134. $group = queryUser('group_default');
  135. $groupname = 'group_default';
  136. }
  137. if ($cond) {
  138. $cond = join($cond, ' and ');
  139. } else {
  140. $cond = '1';
  141. }
  142. $print_new_problem_form = false;
  143. $print_mig_problem_form = false;
  144. $print_copy_problem_form = false;
  145. $print_datum_button = false;
  146. /*
  147. if (($cur_tab == 'all' || $cur_tab == 'template') and isSuperUser($myUser)) {
  148. $print_new_problem_form = true;
  149. $new_problem_form = new UOJForm('new_problem');
  150. $new_problem_form->handle = function() {
  151. global $group;
  152. DB::query("insert into problems (title, is_hidden, submission_requirement, ctrl) values ('New Problem', 1, '{}', 'group_default')");
  153. $id = DB::insert_id();
  154. DB::query("insert into problems_contents (id, statement, statement_md) values ($id, '', '')");
  155. dataNewProblem($id);
  156. attachProblemToGroup(queryProblemBrief($id), $group);
  157. };
  158. $new_problem_form->submit_button_config['align'] = 'right';
  159. $new_problem_form->submit_button_config['class_str'] = 'btn btn-primary';
  160. $new_problem_form->submit_button_config['text'] = UOJLocale::get('problems::add new');
  161. $new_problem_form->submit_button_config['smart_confirm'] = '';
  162. $new_problem_form->runAtServer();
  163. }
  164. */
  165. if (isSuperUser($myUser))
  166. $print_datum_button = true;
  167. if ($group != null and hasGroupCtrlPermission($myUser, $group)) {
  168. $print_new_problem_form = true;
  169. $print_copy_problem_form = true;
  170. $new_problem_form = new UOJForm('new_problem');
  171. $new_problem_form->handle = function() {
  172. global $groupname;
  173. global $group;
  174. DB::query("insert into problems (title, is_hidden, submission_requirement, ctrl) values ('New Problem', 1, '{}', '" . $groupname . "')");
  175. $id = DB::insert_id();
  176. DB::query("insert into problems_contents (id, statement, statement_md) values ($id, '', '')");
  177. dataNewProblem($id);
  178. attachProblemToGroup(queryProblemBrief($id), $group);
  179. };
  180. $new_problem_form->submit_button_config['align'] = 'right';
  181. $new_problem_form->submit_button_config['class_str'] = 'btn btn-primary';
  182. $new_problem_form->submit_button_config['text'] = UOJLocale::get('problems::add new');
  183. $new_problem_form->submit_button_config['smart_confirm'] = '';
  184. $new_problem_form->runAtServer();
  185. $print_mig_problem_form = true;
  186. }
  187. $header = '<tr>';
  188. $header .= '<th class="text-center" style="width:5em;">ID</th>';
  189. $header .= '<th>'.UOJLocale::get('problems::problem').'</th>';
  190. $header .= '<th>组</th>';
  191. if (isset($_COOKIE['show_submit_mode'])) {
  192. $header .= '<th class="text-center" style="width:5em;">'.UOJLocale::get('problems::ac').'</th>';
  193. $header .= '<th class="text-center" style="width:5em;">'.UOJLocale::get('problems::submit').'</th>';
  194. $header .= '<th class="text-center" style="width:150px;">'.UOJLocale::get('problems::ac rate').'</th>';
  195. }
  196. $header .= '<th class="text-center" style="width:220px;">'.UOJLocale::get('appraisal').'</th>';
  197. $header .= '</tr>';
  198. $tabs_info = array(
  199. 'all' => array(
  200. 'name' => UOJLocale::get('problems::all problems'),
  201. 'url' => "/problems"
  202. ),
  203. 'template' => array(
  204. 'name' => UOJLocale::get('problems::template problems'),
  205. 'url' => "/problems/template"
  206. )
  207. );
  208. if ($myUser != null)
  209. foreach (queryUserExtgroups($myUser) as $i => $grp)
  210. if ($grp != '')
  211. $tabs_info[$grp] = array(
  212. 'name' => '团队 ' . $grp .' 题目',
  213. 'url' => "/problems/group/" . $grp
  214. );
  215. $pag_config = array('page_len' => 100);
  216. $pag_config['col_names'] = array('*');
  217. $pag_config['table_name'] = "problems left join best_ac_submissions on best_ac_submissions.submitter = '{$myUser['username']}' and problems.id = best_ac_submissions.problem_id";
  218. $pag_config['cond'] = $cond;
  219. $pag_config['tail'] = "order by id asc";
  220. $pag = new Paginator($pag_config);
  221. $div_classes = array('table-responsive', 'shadow');
  222. $table_classes = array('table', 'table-bordered', 'table-hover', 'table-striped');
  223. ?>
  224. <?php echoUOJPageHeader(UOJLocale::get('problems')) ?>
  225. <div class="row my-4">
  226. <div class="col-sm-9">
  227. <?= HTML::tablist($tabs_info, $cur_tab, 'nav-pills') ?>
  228. </div>
  229. <div class="col-sm-3 order-sm-9 checkbox text-right">
  230. <label class="checkbox-inline" for="input-show_tags_mode"><input type="checkbox" id="input-show_tags_mode" <?= isset($_COOKIE['show_tags_mode']) ? 'checked="checked" ': ''?>/> <?= UOJLocale::get('problems::show tags') ?></label>
  231. <label class="checkbox-inline" for="input-show_submit_mode"><input type="checkbox" id="input-show_submit_mode" <?= isset($_COOKIE['show_submit_mode']) ? 'checked="checked" ': ''?>/> <?= UOJLocale::get('problems::show statistics') ?></label>
  232. </div>
  233. </div>
  234. <div class="top-buffer-sm"></div>
  235. <script type="text/javascript">
  236. $('#input-show_tags_mode').click(function() {
  237. if (this.checked) {
  238. $.cookie('show_tags_mode', '', {path: '/problems'});
  239. } else {
  240. $.removeCookie('show_tags_mode', {path: '/problems'});
  241. }
  242. location.reload();
  243. });
  244. $('#input-show_submit_mode').click(function() {
  245. if (this.checked) {
  246. $.cookie('show_submit_mode', '', {path: '/problems'});
  247. } else {
  248. $.removeCookie('show_submit_mode', {path: '/problems'});
  249. }
  250. location.reload();
  251. });
  252. </script>
  253. <?php
  254. echo '<div class="', join($div_classes, ' '), '">';
  255. echo '<table class="', join($table_classes, ' '), '">';
  256. echo '<thead>';
  257. echo $header;
  258. echo '</thead>';
  259. echo '<tbody>';
  260. foreach ($pag->get() as $idx => $row) {
  261. echoProblem($row);
  262. echo "\n";
  263. }
  264. if ($pag->isEmpty()) {
  265. echo '<tr><td class="text-center" colspan="233">'.UOJLocale::get('none').'</td></tr>';
  266. }
  267. echo '</tbody>';
  268. echo '</table>';
  269. echo '</div>';
  270. if ($print_new_problem_form)
  271. $new_problem_form->printHTML();
  272. if ($print_mig_problem_form) {
  273. echo <<<EOF
  274. <div class="text-right">
  275. <button type="button" class="mt-2 btn btn-secondary" data-toggle="modal" data-target="#MigrateProblemModal">迁移题目</button>
  276. </div>
  277. <div class="modal fade" id="MigrateProblemModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  278. <div class="modal-dialog">
  279. <div class="modal-content">
  280. <div class="modal-header">
  281. <h4 class="modal-title" id="myModalLabel">迁移题目</h4>
  282. <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
  283. </div>
  284. <div class="modal-body">
  285. <form class="form-horizontal" action="" method="post" role="form">
  286. <div class="form-group row">
  287. <input type="hidden" name="migrate_problem_submit" value="submit">
  288. <label for="target_group" class="col-sm-5 control-label">目标组</label>
  289. <div class="col-sm-7">
  290. <input type="text" class="form-control" id="target_group" name="target_group" placeholder="group_default">
  291. </div>
  292. <label for="start_pid" class="col-sm-5 control-label">起始题号</label>
  293. <div class="col-sm-7">
  294. <input type="text" class="form-control" id="start_pid" name="start_pid" placeholder="您必须对范围内的">
  295. </div>
  296. <label for="end_pid" class="col-sm-5 control-label">终止题号</label>
  297. <div class="col-sm-7">
  298. <input type="text" class="form-control" id="end_pid" name="end_pid" placeholder="所有题目都有控制权">
  299. </div>
  300. </div>
  301. </div>
  302. <div class="modal-footer">
  303. <button type="submit" class="btn btn-success">确定</button>
  304. </form>
  305. <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
  306. </div>
  307. </div>
  308. </div>
  309. </div>
  310. EOF;
  311. }
  312. if ($print_copy_problem_form) {
  313. echo <<<EOF
  314. <div class="text-right">
  315. <button type="button" class="mt-2 btn btn-secondary" data-toggle="modal" data-target="#CopyProblemModal">复制题目</button>
  316. </div>
  317. <div class="modal fade" id="CopyProblemModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  318. <div class="modal-dialog">
  319. <div class="modal-content">
  320. <div class="modal-header">
  321. <h4 class="modal-title" id="myModalLabel">复制题目</h4>
  322. <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
  323. </div>
  324. <div class="modal-body">
  325. <form class="form-horizontal" action="" method="post" role="form">
  326. <div class="form-group row">
  327. <input type="hidden" name="copy_problem_submit" value="submit">
  328. <label for="copy_problem_list" class="col-sm-5 control-label">题目列表</label>
  329. <div class="col-sm-7">
  330. <input type="text" class="form-control" id="copy_problem_list" name="copy_problem_list" placeholder="逗号分隔,复制后将连续">
  331. </div>
  332. </div>
  333. </div>
  334. <div class="modal-footer">
  335. <button type="submit" class="btn btn-success">确定</button>
  336. </form>
  337. <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
  338. </div>
  339. </div>
  340. </div>
  341. </div>
  342. EOF;
  343. }
  344. if ($print_datum_button) {
  345. echo <<<EOF
  346. <div class="text-right">
  347. <a type="button" class="mt-2 btn btn-secondary" href="/datums">自动生成数据</a>
  348. </div>
  349. EOF;
  350. }
  351. echo "<div class='mt-4'>";
  352. echo $pag->pagination();
  353. echo "</div>";
  354. ?>
  355. <?php echoUOJPageFooter() ?>