From c5b3fbdd4a1f77ee25066cdf75238c21b9780d35 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sat, 22 Oct 2022 19:24:48 +0800 Subject: [PATCH] refactor(web/list): list v2 --- db/app_uoj233.sql | 1 + web/app/controllers/group_assignment.php | 6 +- web/app/controllers/group_manage.php | 88 ++-- web/app/controllers/groups.php | 168 +++--- web/app/controllers/list.php | 251 +++++++++ web/app/controllers/list_edit.php | 542 ++++++++++++++++++++ web/app/controllers/lists.php | 165 ++++++ web/app/controllers/problem_list.php | 315 ------------ web/app/controllers/problem_list_manage.php | 194 ------- web/app/controllers/problem_lists.php | 165 ------ web/app/controllers/problem_set.php | 4 +- web/app/libs/uoj-html-lib.php | 11 +- web/app/libs/uoj-query-lib.php | 5 +- web/app/route.php | 6 +- web/app/upgrade/9_list_v2/README.md | 1 + web/app/upgrade/9_list_v2/down.sql | 1 + web/app/upgrade/9_list_v2/up.sql | 1 + web/app/views/main-nav.php | 2 +- web/js/uoj.js | 2 +- 19 files changed, 1106 insertions(+), 822 deletions(-) create mode 100644 web/app/controllers/list.php create mode 100644 web/app/controllers/list_edit.php create mode 100644 web/app/controllers/lists.php delete mode 100644 web/app/controllers/problem_list.php delete mode 100644 web/app/controllers/problem_list_manage.php delete mode 100644 web/app/controllers/problem_lists.php create mode 100644 web/app/upgrade/9_list_v2/README.md create mode 100644 web/app/upgrade/9_list_v2/down.sql create mode 100644 web/app/upgrade/9_list_v2/up.sql diff --git a/db/app_uoj233.sql b/db/app_uoj233.sql index 4639640..7c0efe2 100644 --- a/db/app_uoj233.sql +++ b/db/app_uoj233.sql @@ -686,6 +686,7 @@ UNLOCK TABLES; CREATE TABLE `lists` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` text NOT NULL, + `description` text NOT NULL DEFAULT '', `is_hidden` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; diff --git a/web/app/controllers/group_assignment.php b/web/app/controllers/group_assignment.php index 9c336bc..83ca68c 100644 --- a/web/app/controllers/group_assignment.php +++ b/web/app/controllers/group_assignment.php @@ -28,6 +28,10 @@ $group = queryGroup($assignment['group_id']); $list = queryProblemList($assignment['list_id']); + + if (($group['is_hidden'] || $list['is_hidden']) && !isSuperUser($myUser)) { + become403Page(); + } ?> @@ -40,7 +44,7 @@ 作业: diff --git a/web/app/controllers/group_manage.php b/web/app/controllers/group_manage.php index e930114..a19dcaa 100644 --- a/web/app/controllers/group_manage.php +++ b/web/app/controllers/group_manage.php @@ -81,7 +81,7 @@ $update_profile_form->handle = function($vdata) use ($group) { $esc_title = DB::escape($vdata['title']); $is_hidden = $_POST['is_hidden']; - $esc_announcement = $vdata['announcement']; + $esc_announcement = DB::escape($vdata['announcement']); DB::update("UPDATE `groups` SET title = '$esc_title', is_hidden = '$is_hidden', announcement = '$esc_announcement' WHERE id = {$group['id']}"); @@ -198,6 +198,10 @@ function(res) { } EOD); $add_new_assignment_form->runAtServer(); + + $now = new DateTime(); + $hidden_time = new DateTime(); + $hidden_time->sub(new DateInterval('P7D')); } elseif ($cur_tab == 'users') { if (isset($_POST['submit-remove_user']) && $_POST['submit-remove_user'] == 'remove_user') { $username = $_POST['remove_username']; @@ -331,54 +335,56 @@ EOD);
sub(new DateInterval('P7D')); - echoLongTable( - ['*'], - 'groups_assignments', - "group_id = {$group['id']}", - 'order by end_time desc, list_id desc', - << - ID + 题单 ID 标题 状态 结束时间 操作 EOD, - function($row) use ($group, $now, $hidden_time) { - $list = queryProblemList($row['list_id']); - $end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']); + function($row) use ($group, $now, $hidden_time) { + $list = queryProblemList($row['list_id']); + $end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']); - echo ''; - echo '', $list['id'], ''; - echo '', '', HTML::escape($list['title']), '', ''; - if ($end_time < $hidden_time) { - echo '已隐藏'; - } elseif ($end_time < $now) { - echo '已结束'; - } else { - echo '进行中'; - } - echo '', $end_time->format('Y-m-d H:i:s'), ''; - echo ''; - echo '编辑 '; - echo '
' - . '' - . '' - . '' - . '
'; - echo ''; - echo ''; - }, - [ - 'page_len' => 20, - 'div_classes' => ['table-responsive'], - 'table_classes' => ['table', 'align-middle'], - ] - ); + echo ''; + echo '', $list['id'], ''; + echo ''; + echo '', HTML::escape($list['title']), ''; + if ($list['is_hidden']) { + echo ' ', UOJLocale::get('hidden'), ' '; + } + echo ''; + if ($end_time < $hidden_time) { + echo '已隐藏'; + } elseif ($end_time < $now) { + echo '已结束'; + } else { + echo '进行中'; + } + echo '', $end_time->format('Y-m-d H:i:s'), ''; + echo ''; + echo ' 编辑 '; + echo '
' + . '' + . '' + . '' + . '
'; + echo ''; + echo ''; + }, + [ + 'page_len' => 20, + 'div_classes' => ['table-responsive'], + 'table_classes' => ['table', 'align-middle'], + ] + ); ?>
diff --git a/web/app/controllers/groups.php b/web/app/controllers/groups.php index 4ef0333..0a856d9 100644 --- a/web/app/controllers/groups.php +++ b/web/app/controllers/groups.php @@ -1,89 +1,57 @@ handle = function() { - DB::query("insert into `groups` (title, is_hidden) values ('新小组', 1)"); - }; - $new_group_form->submit_button_config['align'] = 'right'; - $new_group_form->submit_button_config['class_str'] = 'btn btn-primary'; - $new_group_form->submit_button_config['text'] = UOJLocale::get('add new group'); - $new_group_form->submit_button_config['smart_confirm'] = ''; - $new_group_form->runAtServer(); - } - - function echoGroup($group) { - global $myUser, $REQUIRE_LIB; - - echo ''; - echo ''; - echo '#', $group['group_id'], ''; - - if (isset($REQUIRE_LIB['bootstrap5'])) { - echo ''; - } else { - echo ''; - } - if ($group['is_hidden']) { - echo ' [隐藏] '; - } - echo '', $group['title'], ''; - echo ''; - - echo "{$group['user_count']}"; - - echo ''; - } - ?> + if (isSuperUser($myUser)) { + $new_group_form = new UOJForm('new_group'); + $new_group_form->handle = function() { + DB::query("insert into `groups` (title, is_hidden) values ('新小组', 1)"); + }; + $new_group_form->submit_button_config['align'] = 'right'; + $new_group_form->submit_button_config['class_str'] = 'btn btn-primary'; + $new_group_form->submit_button_config['text'] = UOJLocale::get('add new group'); + $new_group_form->submit_button_config['smart_confirm'] = ''; + $new_group_form->runAtServer(); + } + ?> -
+ +
+ +
- +

- - -
- - printHTML(); ?> - -
- - - - + +
+ printHTML(); ?>
+
+ + ID {$groups_caption} @@ -91,35 +59,44 @@ EOD; - if (isSuperUser($myUser)) { - $cond = "1"; - } else { - $cond = 'is_hidden = 0'; - } + if (isSuperUser($myUser)) { + $cond = "1"; + } else { + $cond = 'is_hidden = 0'; + } - $from = "`groups` a left join groups_users b on a.id = b.group_id"; + echoLongTable( + ['a.id as group_id', 'a.title as title', 'a.is_hidden as is_hidden', 'count(b.username) as user_count'], + "`groups` a left join groups_users b on a.id = b.group_id", + $cond, + 'group by a.id order by a.id asc', + $header, + function ($group) use ($myUser) { + echo ''; + echo ''; + echo '#', $group['group_id'], ''; + + echo ''; + echo '', $group['title'], ''; + if ($group['is_hidden']) { + echo ' ', UOJLocale::get('hidden'), ' '; + } + echo ''; + + echo "{$group['user_count']}"; + + echo ''; + }, + [ + 'page_len' => 40, + 'div_classes' => ['card', 'my-3'], + 'table_classes' => ['table', 'uoj-table', 'mb-0'], + 'head_pagination' => true, + 'pagination_table' => "`groups`", + ] + ); + ?> - $table_config = array('page_len' => 40, - 'table_classes' => array('table', 'table-bordered', 'table-hover', 'table-striped'), - 'head_pagination' => true, - 'pagination_table' => "`groups`" - ); - - if (isset($REQUIRE_LIB['bootstrap5'])) { - $table_config['div_classes'] = array('card', 'my-3'); - $table_config['table_classes'] = array('table', 'uoj-table', 'mb-0'); - } - - echoLongTable( - array('a.id as group_id', 'a.title as title', 'a.is_hidden as is_hidden', 'count(b.username) as user_count'), - $from, $cond, 'group by a.id order by a.id asc', - $header, - 'echoGroup', - $table_config - ); - ?> - -
@@ -129,6 +106,5 @@ EOD;
- diff --git a/web/app/controllers/list.php b/web/app/controllers/list.php new file mode 100644 index 0000000..f6d3b9a --- /dev/null +++ b/web/app/controllers/list.php @@ -0,0 +1,251 @@ +'; + if ($problem['submission_id']) { + echo ''; + } else { + echo ''; + } + echo '#', $problem['id'], ''; + echo ''; + echo '', $problem['title'], ''; + + if ($problem['uploader'] == $myUser['username']) { + echo ' ', UOJLocale::get('problems::my problem') ,' '; + } + + if ($problem['is_hidden']) { + echo ' ', UOJLocale::get('hidden'), ' '; + } + + if (isset($_COOKIE['show_tags_mode'])) { + foreach (queryProblemTags($problem['id']) as $tag) { + echo ' '; + echo '', HTML::escape($tag), ''; + echo ' '; + } + } + echo ''; + if (isset($_COOKIE['show_submit_mode'])) { + $perc = $problem['submit_num'] > 0 ? round(100 * $problem['ac_num'] / $problem['submit_num']) : 0; + echo <<×{$problem['ac_num']} + ×{$problem['submit_num']} + +
+
{$perc}%
+
+ +EOD; + } + if (isset($_COOKIE['show_difficulty'])) { + $extra_config = getProblemExtraConfig($problem); + if ($extra_config['difficulty'] == 0) { + echo ""; + } else { + echo "{$extra_config['difficulty']}"; + } + } + echo '', getClickZanBlock('P', $problem['id'], $problem['zan'], null, false), ''; + echo ''; + } + } + + $header = ''; + $header .= 'ID'; + $header .= ''.UOJLocale::get('problems::problem').''; + if (isset($_COOKIE['show_submit_mode'])) { + $header .= ''.UOJLocale::get('problems::ac').''; + $header .= ''.UOJLocale::get('problems::submit').''; + $header .= ''.UOJLocale::get('problems::ac ratio').''; + } + if (isset($_COOKIE['show_difficulty'])) { + $header .= ''.UOJLocale::get('problems::difficulty').''; + } + $header .= ''.UOJLocale::get('appraisal').''; + $header .= ''; + + $pag_config = [ + 'page_len' => 40, + 'col_names' => [ + 'best_ac_submissions.submission_id as submission_id', + 'problems.id as id', + 'problems.is_hidden as is_hidden', + 'problems.title as title', + 'problems.submit_num as submit_num', + 'problems.ac_num as ac_num', + 'problems.zan as zan', + 'problems.extra_config as extra_config', + 'problems.uploader as uploader', + ], + 'table_name' => "problems left join best_ac_submissions on best_ac_submissions.submitter = '{$myUser['username']}' and problems.id = best_ac_submissions.problem_id inner join lists_problems lp on lp.list_id = {$list_id} and lp.problem_id = problems.id", + 'cond' => '1', + 'tail' => 'ORDER BY `id` ASC', + ]; + $pag = new Paginator($pag_config); + ?> + + +
+ + +
+ + +
+ +

+ + (ID: #) + + + + + + +

+ + +
+ + + +
+ + +
+ + + +
+
+

题单简介

+ purify(HTML::parsedown()->text($list['description'])) ?> + + + +

暂无简介

+ +
+
+ +
+
+
+
+ + /> + +
+ +
+ + /> + +
+ +
+ + /> + +
+
+
+ + + +pagination() ?> + +
+ + + + + +get() as $idx => $row): ?> + + +isEmpty()): ?> + + + + + +
+ +
+
+ +pagination() ?> + +
+ + + + +
+ + diff --git a/web/app/controllers/list_edit.php b/web/app/controllers/list_edit.php new file mode 100644 index 0000000..3cccc09 --- /dev/null +++ b/web/app/controllers/list_edit.php @@ -0,0 +1,542 @@ + [ + 'name' => '基本信息', + 'url' => "/list/{$list['id']}/edit/profile", + ], + 'problems' => [ + 'name' => '题目管理', + 'url' => "/list/{$list['id']}/edit/problems", + ], + 'assignments' => [ + 'name' => '对应作业', + 'url' => "/list/{$list['id']}/edit/assignments", + ] + ]; + + if (!isset($tabs_info[$cur_tab])) { + become404Page(); + } + + if ($cur_tab == 'profile') { + $list_tags = queryProblemListTags($list_id); + + $update_profile_form = new UOJForm('update_profile'); + $update_profile_form->addVInput('name', 'text', '标题', $list['title'], + function($title, &$vdata) { + if ($title == '') { + return '标题不能为空'; + } + + if (strlen($title) > 100) { + return '标题过长'; + } + + if (HTML::escape($title) === '') { + return '无效编码'; + } + + $vdata['title'] = $title; + + return ''; + }, + null + ); + $update_profile_form->addVCheckboxes('is_hidden', [ + '0' => '公开', + '1' => '隐藏', + ], '可见性', $list['is_hidden']); + $update_profile_form->addVInput('tags', 'text', '标签(多个标签用逗号隔开)', implode(', ', $list_tags), + function($tags_str, &$vdata) { + $tags_str = str_replace(',', ',', $tags_str); + $tags_raw = explode(',', $tags_str); + $tags = []; + + if (count($tags_raw) > 10) { + return '不能存在超过 10 个标签'; + } + + foreach ($tags_raw as $tag) { + $tag = trim($tag); + + if (strlen($tag) == 0) { + continue; + } + + if (strlen($tag) > 30) { + return '标签 “' . HTML::escape($tag) .'” 太长'; + } + + if (in_array($tag, $tags, true)) { + return '标签 “' . HTML::escape($tag) .'” 重复出现'; + } + + $tags[] = $tag; + } + + $vdata['tags'] = $tags; + + return ''; + }, + null); + $update_profile_form->addVTextArea('description', '描述', $list['description'], + function($description, &$vdata) { + if (strlen($description) > 3000) { + return '描述过长'; + } + + $vdata['description'] = $description; + + return ''; + }, null); + $update_profile_form->handle = function($vdata) use ($list, $list_tags) { + $esc_title = DB::escape($vdata['title']); + $is_hidden = $_POST['is_hidden']; + $esc_description = DB::escape($vdata['description']); + + DB::update("UPDATE `lists` SET `title` = '$esc_title', `is_hidden` = '$is_hidden', `description` = '$esc_description' WHERE id = {$list['id']}"); + + if ($vdata['tags'] !== $list_tags) { + DB::delete("DELETE FROM `lists_tags` WHERE `list_id` = {$list['id']}"); + + foreach ($vdata['tags'] as $tag) { + $esc_tag = DB::escape($tag); + + DB::insert("INSERT INTO `lists_tags` (list_id, tag) VALUES ({$list['id']}, '$esc_tag')"); + } + } + + dieWithJsonData(['status' => 'success', 'message' => '修改成功']); + }; + $update_profile_form->setAjaxSubmit(<<submit_button_config['margin_class'] = 'mt-3'; + $update_profile_form->submit_button_config['text'] = '更新'; + $update_profile_form->runAtServer(); + } elseif ($cur_tab == 'problems') { + if (isset($_POST['submit-remove_problem']) && $_POST['submit-remove_problem'] == 'remove_problem') { + crsf_defend(); + + $problem_id = $_POST['problem_id']; + + if (!validateUInt($problem_id)) { + dieWithAlert('题目 ID 不合法'); + } + + if (!queryProblemBrief($problem_id)) { + dieWithAlert('题目不存在'); + } + + if (!queryProblemInList($list['id'], $problem_id)) { + dieWithAlert('题目不在题单中'); + } + + DB::delete("DELETE FROM lists_problems WHERE problem_id = {$problem_id} AND list_id = {$list['id']}"); + + dieWithAlert('移除成功!'); + } + + $n_problems = DB::selectCount("SELECT count(*) FROM `lists_problems` WHERE `list_id` = {$list['id']}"); + + $add_new_problem_form = new UOJForm('add_new_problem'); + $add_new_problem_form->addVInput('problem_id', 'text', '题目 ID', '', + function ($problem_id, &$vdata) use ($list) { + if (!validateUInt($problem_id)) { + return 'ID 不合法'; + } + + if (!queryProblemBrief($problem_id)) { + return '题目不存在'; + } + + if (queryProblemInList($list['id'], $problem_id)) { + return '该题目已经在题单中'; + } + + $vdata['problem_id'] = $problem_id; + + return ''; + }, + null + ); + $add_new_problem_form->submit_button_config['margin_class'] = 'mt-3'; + $add_new_problem_form->submit_button_config['text'] = '添加'; + $add_new_problem_form->handle = function($vdata) use ($list) { + DB::insert("INSERT INTO `lists_problems` (`list_id`, `problem_id`) values ({$list['id']}, {$vdata['problem_id']})"); + + dieWithJsonData(['status' => 'success', 'message' => '已将题目 #' . $vdata['problem_id'] . ' 添加到题单 #' . $list['id'] .' 中']); + }; + $add_new_problem_form->setAjaxSubmit(<<runAtServer(); + } elseif ($cur_tab == 'assignments') { + if (isset($_POST['submit-remove_assignment']) && $_POST['submit-remove_assignment'] == 'remove_assignment') { + crsf_defend(); + + $group_id = $_POST['group_id']; + + if (!validateUInt($group_id)) { + dieWithAlert('小组 ID 不合法。'); + } + + if (!queryGroup($group_id)) { + dieWithAlert('小组不存在。'); + } + + if (!queryAssignmentByGroupListID($group_id, $list['id'])) { + dieWithAlert('该小组并未将本题单布置为作业。'); + } + + DB::delete("DELETE FROM groups_assignments WHERE group_id = {$group_id} AND list_id = {$list['id']}"); + + dieWithAlert('移除成功!'); + } + + $add_new_assignment_form = new UOJForm('add_new_assignment'); + $add_new_assignment_form->addVInput('new_assignment_group_id', 'text', '小组 ID', '', + function ($group_id, &$vdata) use ($list) { + if (!validateUInt($group_id)) { + return '小组 ID 不合法'; + } + + if (!($list = queryGroup($group_id))) { + return '小组不存在'; + } + + if ($list['is_hidden'] != 0) { + return '题单是隐藏的'; + } + + if (queryAssignmentByGroupListID($group_id, $list['id'])) { + return '该题单已经是这个小组的作业'; + } + + $vdata['group_id'] = $group_id; + + return ''; + }, + null + ); + $default_end_time = new DateTime(); + $default_end_time->setTime(22, 30, 0); + $default_end_time->add(new DateInterval("P7D")); + $add_new_assignment_form->addVInput('new_assignment_end_time', 'text', '截止时间', $default_end_time->format('Y-m-d H:i'), + function ($end_time, &$vdata) { + try { + $vdata['end_time'] = new DateTime($end_time); + } catch (Exception $e) { + return '无效时间格式'; + } + + return ''; + }, + null + ); + $add_new_assignment_form->handle = function(&$vdata) use ($list) { + $esc_end_time = DB::escape($vdata['end_time']->format('Y-m-d H:i:s')); + + DB::insert("insert into groups_assignments (group_id, list_id, end_time) values ({$vdata['group_id']}, '{$list['id']}', '{$esc_end_time}')"); + + dieWithJsonData([ + 'status' => 'success', + 'message' => '题单 #' . $list['id'] . ' 已经被添加到小组 #' . $vdata['group_id'] . ' 的作业列表中,结束时间为 ' . $vdata['end_time']->format('Y-m-d H:i:s') . '。' + ]); + }; + $add_new_assignment_form->submit_button_config['margin_class'] = 'mt-3'; + $add_new_assignment_form->submit_button_config['text'] = '添加'; + $add_new_assignment_form->setAjaxSubmit(<<runAtServer(); + + $now = new DateTime(); + $hidden_time = new DateTime(); + $hidden_time->sub(new DateInterval('P7D')); + } + ?> + + + +

+ + (ID: #) + 管理 +

+ +
+ +
+ + + +"> + 返回 + + +
+ + + +
+ +
+
+ +
+
+ printHTML() ?> +
+
+
注意事项
+
    +
  • 隐藏的题单无法被普通用户查看。
  • +
  • 题单描述支持 Markdown 语法。
  • +
+
+
+
+
+ +
+
+ +
+
+
+ + ID + 标题 + 操作 + +EOD, + function ($row) { + echo ''; + + echo '', $row['id'], ''; + echo '', '', $row['title'], ''; + if ($row['is_hidden']) { + echo ' ', UOJLocale::get('hidden'), ' '; + } + echo ''; + echo ''; + echo '
'; + echo ''; + echo ''; + echo ''; + echo '
'; + echo ''; + + echo ''; + }, + [ + 'page_len' => 20, + 'div_classes' => ['table-responsive'], + 'table_classes' => ['table', 'align-middle'], + 'print_after_table' => function() use ($n_problems) { + echo '
共 ', $n_problems,' 道题目
'; + }, + ] + ); + ?> +
+
+ +
+
+ printHTML() ?> +
+
+
注意事项
+
    +
  • 隐藏的题目添加进题单后无法被普通用户查看。
  • +
  • 如当前题单已经被设置为某个小组的作业,则作业也会一并更新。
  • +
+
+
+
+
+
+ +
+
+ +
+
+
+
+ + 小组 ID + 名称 + 状态 + 结束时间 + 操作 + +EOD, + function($row) use ($list, $now, $hidden_time) { + $group = queryGroup($row['group_id']); + $end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']); + + echo ''; + echo '', $group['id'], ''; + echo '', '', HTML::escape($group['title']), '', ''; + if ($end_time < $hidden_time) { + echo '已隐藏'; + } elseif ($end_time < $now) { + echo '已结束'; + } else { + echo '进行中'; + } + echo '', $end_time->format('Y-m-d H:i:s'), ''; + echo ''; + echo ' 排行榜 '; + echo '
' + . '' + . '' + . '' + . '
'; + echo ''; + echo ''; + }, + [ + 'page_len' => 20, + 'div_classes' => ['table-responsive'], + 'table_classes' => ['table', 'align-middle'], + ] + ); + ?> +
+
+ +
+
+ printHTML() ?> +
+
+
注意事项
+
    +
  • 请为学生预留合理的完成作业的时间。
  • +
  • 排行榜将在作业结束后停止更新。
  • +
  • 如需延长结束时间请删除后再次添加,排行数据不会丢失。
  • +
  • 作业结束七天后将会自动在小组主页中隐藏,但仍可直接通过 URL 访问。
  • +
+
+
+
+
+
+
+ +
+ + +
+ + diff --git a/web/app/controllers/lists.php b/web/app/controllers/lists.php new file mode 100644 index 0000000..b04d3ef --- /dev/null +++ b/web/app/controllers/lists.php @@ -0,0 +1,165 @@ +handle = function() { + DB::query("insert into lists (title, is_hidden) values ('未命名题单', 1)"); + }; + $new_list_form->submit_button_config['align'] = 'right'; + $new_list_form->submit_button_config['class_str'] = 'btn btn-primary'; + $new_list_form->submit_button_config['text'] = UOJLocale::get('problems::add new list'); + $new_list_form->submit_button_config['smart_confirm'] = ''; + + $new_list_form->runAtServer(); + } + + function echoList($list) { + global $myUser; + + if (isListVisibleToUser($list, $myUser)) { + echo ''; + if ($list['problem_count'] == $list['accepted'] && $list['problem_count'] > 0) { + echo ''; + } else { + echo ''; + } + echo '#', $list['list_id'], ''; + + echo ''; + echo '', $list['title'], ' '; + + if ($list['is_hidden']) { + echo ' ', UOJLocale::get('hidden'), ' '; + } + + foreach (queryProblemListTags($list['list_id']) as $tag) { + echo '', '', HTML::escape($tag), '', ' '; + } + echo ''; + + echo "{$list['accepted']}"; + echo "{$list['problem_count']}"; + + echo ''; + } + } + ?> + + + +
+ +
+ + +
+ +

+ +

+ + +
+ printHTML(); ?> +
+ + +
+ + + + ID + {$list_caption} + {$ac_caption} + {$total_caption} + +EOD; + + $cond = []; + $search_tag = null; + + if (isset($_GET['tag'])) { + $search_tag = $_GET['tag']; + } + + if ($search_tag) { + $cond[] = "'" . DB::escape($search_tag) . "' in (select tag from lists_tags where lists_tags.list_id = a.id)"; + } + + if ($cond) { + $cond = join($cond, ' and '); + } else { + $cond = '1'; + } + + echoLongTable( + array('a.id as list_id', 'a.title as title', 'a.is_hidden as is_hidden', 'count(b.problem_id) as problem_count', 'count(c.submitter) as accepted'), + "lists a left join lists_problems b on a.id = b.list_id left join best_ac_submissions c on (b.problem_id = c.problem_id and c.submitter = '{$myUser['username']}')", + $cond, + 'group by a.id order by a.id desc', + $header, + function($list) use ($myUser) { + if (isListVisibleToUser($list, $myUser)) { + echo ''; + if ($list['problem_count'] == $list['accepted'] && $list['problem_count'] > 0) { + echo ''; + } else { + echo ''; + } + echo '#', $list['list_id'], ''; + + echo ''; + echo '', $list['title'], ' '; + + if ($list['is_hidden']) { + echo ' ', UOJLocale::get('hidden'), ' '; + } + + foreach (queryProblemListTags($list['list_id']) as $tag) { + echo '', '', HTML::escape($tag), '', ' '; + } + echo ''; + + echo "{$list['accepted']}"; + echo "{$list['problem_count']}"; + + echo ''; + } + }, + [ + 'page_len' => 40, + 'table_classes' => ['table', 'table-bordered', 'table-hover', 'table-striped'], + 'head_pagination' => true, + 'pagination_table' => 'lists', + 'div_classes' => ['card', 'my-3'], + 'table_classes' => ['table', 'uoj-table', 'mb-0'], + ] + ); + ?> +
+ + + + +
+ + diff --git a/web/app/controllers/problem_list.php b/web/app/controllers/problem_list.php deleted file mode 100644 index 7854cee..0000000 --- a/web/app/controllers/problem_list.php +++ /dev/null @@ -1,315 +0,0 @@ -'; - if ($problem['submission_id']) { - echo ''; - } else { - echo ''; - } - echo '#', $problem['id'], ''; - if (isset($REQUIRE_LIB['bootstrap5'])) { - echo ''; - } else { - echo ''; - } - echo '', $problem['title'], ''; - - if ($problem['uploader'] == $myUser['username']) { - echo ' ', UOJLocale::get('problems::my problem') ,' '; - } - - if ($problem['is_hidden']) { - echo ' ', UOJLocale::get('hidden'), ' '; - } - - if (isset($_COOKIE['show_tags_mode'])) { - foreach (queryProblemTags($problem['id']) as $tag) { - if (isset($REQUIRE_LIB['bootstrap5'])) { - echo ' '; - echo ''; - } else { - echo ' '; - echo ''; - } - echo HTML::escape($tag), ''; - echo ' '; - } - } - echo ''; - if (isset($_COOKIE['show_submit_mode'])) { - $perc = $problem['submit_num'] > 0 ? round(100 * $problem['ac_num'] / $problem['submit_num']) : 0; - echo <<×{$problem['ac_num']} - ×{$problem['submit_num']} - -
-
{$perc}%
-
- -EOD; - } - if (isset($_COOKIE['show_difficulty'])) { - $extra_config = getProblemExtraConfig($problem); - if ($extra_config['difficulty'] == 0) { - echo ""; - } else { - echo "{$extra_config['difficulty']}"; - } - } - echo '', getClickZanBlock('P', $problem['id'], $problem['zan'], null, false), ''; - echo ''; - } - } - - $header = ''; - $header .= 'ID'; - $header .= ''.UOJLocale::get('problems::problem').''; - if (isset($_COOKIE['show_submit_mode'])) { - $header .= ''.UOJLocale::get('problems::ac').''; - $header .= ''.UOJLocale::get('problems::submit').''; - $header .= ''.UOJLocale::get('problems::ac ratio').''; - } - if (isset($_COOKIE['show_difficulty'])) { - $header .= ''.UOJLocale::get('problems::difficulty').''; - } - $header .= ''.UOJLocale::get('appraisal').''; - $header .= ''; - - $pag_config = array('page_len' => 40); - $pag_config['col_names'] = array('best_ac_submissions.submission_id as submission_id', 'problems.id as id', 'problems.is_hidden as is_hidden', 'problems.title as title', 'problems.submit_num as submit_num', 'problems.ac_num as ac_num', 'problems.zan as zan', 'problems.extra_config as extra_config', 'problems.uploader as uploader', 'problems.extra_config as extra_config'); - - $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 inner join lists_problems lp on lp.list_id = {$list_id} and lp.problem_id = problems.id"; - - $pag_config['cond'] = '1'; - $pag_config['tail'] = "order by id asc"; - $pag = new Paginator($pag_config); - - $div_classes = isset($REQUIRE_LIB['bootstrap5']) - ? array('card', 'my-3', 'table-responsive') - : array('table-responsive'); - $table_classes = isset($REQUIRE_LIB['bootstrap5']) - ? array('table', 'uoj-table', 'mb-0') - : array('table', 'table-bordered', 'table-hover', 'table-striped'); - ?> - - - -
-
-
- -

- - [隐藏] - - - (ID: #) -

- - - -
- - - -
- - - - - - -
- - -
-
-
- -
- -
- - - -
- -
- - - -
- -
- -
- -
- pagination(); ?> -
- -
- - -
- pagination(); ?> -
- - - -
- - - - -
- - - - - -get() as $idx => $row) { - echoProblem($row); - echo "\n"; - } - ?> - -isEmpty()): ?> - - - - - - -
- -
-
- -pagination(); ?> - - -
- - - -
- - - diff --git a/web/app/controllers/problem_list_manage.php b/web/app/controllers/problem_list_manage.php deleted file mode 100644 index 0b88dca..0000000 --- a/web/app/controllers/problem_list_manage.php +++ /dev/null @@ -1,194 +0,0 @@ -name = 'list'; - $list_editor->blog_url = null; - $list_editor->cur_data = array( - 'title' => $list['title'], - 'tags' => $list_tags, - 'is_hidden' => $list['is_hidden'] - ); - $list_editor->label_text = array_merge($list_editor->label_text, array( - 'view blog' => '保存题单信息', - 'blog visibility' => '题单可见性' - )); - $list_editor->show_editor = false; - - $list_editor->save = function($data) { - global $list_id, $list; - DB::update("update lists set title = '" . DB::escape($data['title']) . "' where id = {$list_id}"); - - if ($data['tags'] !== $list_tags) { - DB::delete("delete from lists_tags where list_id = {$list_id}"); - foreach ($data['tags'] as $tag) { - DB::insert("insert into lists_tags (list_id, tag) values ({$list_id}, '" . DB::escape($tag) . "')"); - } - } - - if ($data['is_hidden'] != $list['is_hidden'] ) { - DB::update("update lists set is_hidden = {$data['is_hidden']} where id = {$list_id}"); - } - }; - - $list_editor->runAtServer(); - - $add_new_problem_form = new UOJForm('add_new_problem'); - $add_new_problem_form->addInput('problem_id', 'text', '题目 ID', '', - function ($x) { - global $myUser, $list_id; - - if (!isSuperUser($myUser)) { - return '只有超级用户可以编辑题单'; - } - - if (!validateUInt($x)) { - return 'ID 不合法'; - } - $problem = queryProblemBrief($x); - if (!$problem) { - return '题目不存在'; - } - - if (queryProblemInList($list_id, $x)) { - return '该题目已经在题单中'; - } - - return ''; - }, - null - ); - $add_new_problem_form->submit_button_config['align'] = 'compressed'; - $add_new_problem_form->submit_button_config['text'] = '添加到题单'; - $add_new_problem_form->handle = function() { - global $list_id, $myUser; - $problem_id = $_POST['problem_id']; - - DB::insert("insert into lists_problems (list_id, problem_id) values ({$list_id}, {$problem_id})"); - }; - $add_new_problem_form->runAtServer(); - - function removeFromProblemListForm($problem_id) { - $res_form = new UOJForm("remove_problem_{$problem_id}"); - $input_name = "problem_id_delete_{$problem_id}"; - $res_form->addHidden($input_name, $problem_id, function($problem_id) { - global $myUser; - if (!isSuperUser($myUser)) { - return '只有超级用户可以编辑题单'; - } - }, null); - $res_form->handle = function() use ($input_name) { - global $list_id; - $problem_id = $_POST[$input_name]; - DB::query("delete from lists_problems where problem_id={$problem_id} and list_id={$list_id}"); - }; - $res_form->submit_button_config['class_str'] = 'btn btn-danger'; - $res_form->submit_button_config['text'] = '删除'; - $res_form->submit_button_config['align'] = 'inline'; - return $res_form; - } - - $removeProblemForms = array(); - $problem_ids = DB::query("select problem_id from lists_problems where list_id = {$list_id}"); - while ($row = DB::fetch($problem_ids)) { - $problem_id = $row['problem_id']; - $removeForm = removeFromProblemListForm($problem_id); - $removeForm->runAtServer(); - $removeProblemForms[$problem_id] = $removeForm; - } - - function echoProblem($problem) { - global $myUser, $removeProblemForms; - - echo ''; - echo ''; - echo '#', $problem['id'], ''; - echo ''; - if ($problem['is_hidden']) { - echo ' [隐藏] '; - } - if ($problem['uploader'] == $myUser['username']) { - echo ' [我的题目] '; - } - echo '', $problem['title'], ''; - echo ''; - echo ''; - $removeProblemForms[$problem['id']]->printHTML(); - echo ''; - echo ''; - } - - $pag_config = array('page_len' => 40); - $pag_config['col_names'] = array('problems.id as id', 'problems.is_hidden as is_hidden', 'problems.title as title', 'problems.uploader as uploader'); - - $pag_config['table_name'] = "problems inner join lists_problems lp on lp.list_id = {$list_id} and lp.problem_id = problems.id"; - - $pag_config['cond'] = '1'; - $pag_config['tail'] = "order by id asc"; - $pag = new Paginator($pag_config); - ?> - - - -

- (#)管理 -

- - - -
- printHTML(); ?> -
- - - - - - - - - - - get() as $idx => $row) { - echoProblem($row); - echo "\n"; - } - ?> - isEmpty()): ?> - - - - - -
ID题目名称操作
- -
-
- printHTML() ?> -
- -pagination(); ?> - - diff --git a/web/app/controllers/problem_lists.php b/web/app/controllers/problem_lists.php deleted file mode 100644 index 68a39f3..0000000 --- a/web/app/controllers/problem_lists.php +++ /dev/null @@ -1,165 +0,0 @@ -handle = function() { - DB::query("insert into lists (title, is_hidden) values ('未命名题单', 1)"); - }; - $new_list_form->submit_button_config['align'] = 'right'; - $new_list_form->submit_button_config['class_str'] = 'btn btn-primary'; - $new_list_form->submit_button_config['text'] = UOJLocale::get('problems::add new list'); - $new_list_form->submit_button_config['smart_confirm'] = ''; - - $new_list_form->runAtServer(); - } - - function echoList($list) { - global $myUser, $REQUIRE_LIB; - - echo ''; - if ($list['problem_count'] == $list['accepted'] && $list['problem_count'] > 0) { - echo ''; - } else { - echo ''; - } - echo '#', $list['list_id'], ''; - - if (isset($REQUIRE_LIB['bootstrap5'])) { - echo ''; - } else { - echo ''; - } - - if ($list['is_hidden']) { - echo ' [隐藏] '; - } - echo '', $list['title'], ' '; - foreach (queryProblemListTags($list['list_id']) as $tag) { - if (isset($REQUIRE_LIB['bootstrap5'])) { - echo ''; - echo ''; - } else { - echo ''; - echo ''; - } - - echo HTML::escape($tag), '', ' '; - } - echo ''; - - echo "{$list['accepted']}"; - echo "{$list['problem_count']}"; - - echo ''; - } - ?> - - - - -
-
-
- -

- -

- - - -
- - printHTML(); ?> - -
- - - -
- - - - ID - {$problem_list_caption} - {$ac_caption} - {$total_caption} - -EOD; - - $cond = array(); - - $search_tag = null; - if (isset($_GET['tag'])) { - $search_tag = $_GET['tag']; - } - if ($search_tag) { - $cond[] = "'" . DB::escape($search_tag) . "' in (select tag from lists_tags where lists_tags.list_id = a.id)"; - } - if (!isSuperUser($myUser)) { - $cond[] = "is_hidden = 0"; - } - - if ($cond) { - $cond = join($cond, ' and '); - } else { - $cond = '1'; - } - - $from = "lists a left join lists_problems b on a.id = b.list_id left join best_ac_submissions c on (b.problem_id = c.problem_id and c.submitter = '{$myUser['username']}')"; - - $table_config = array( - 'page_len' => 40, - 'table_classes' => array('table', 'table-bordered', 'table-hover', 'table-striped'), - 'head_pagination' => true, - 'pagination_table' => 'lists' - ); - - if (isset($REQUIRE_LIB['bootstrap5'])) { - $table_config['div_classes'] = array('card', 'my-3'); - $table_config['table_classes'] = array('table', 'uoj-table', 'mb-0'); - } - - echoLongTable( - array('a.id as list_id', 'a.title as title', 'a.is_hidden as is_hidden', 'count(b.problem_id) as problem_count', 'count(c.submitter) as accepted'), - $from, $cond, 'group by a.id order by a.id desc', - $header, - 'echoList', - $table_config, - ); - ?> - - -
- - - -
- - - diff --git a/web/app/controllers/problem_set.php b/web/app/controllers/problem_set.php index dcb165a..3c32942 100644 --- a/web/app/controllers/problem_set.php +++ b/web/app/controllers/problem_set.php @@ -1,4 +1,5 @@ {$extra_config['difficulty']}"; } } - echo '', getClickZanBlock('P', $problem['id'], $problem['zan'], null, false), ''; + echo '', getClickZanBlock('P', $problem['id'], $problem['zan'], null, false), ''; echo ''; } } diff --git a/web/app/libs/uoj-html-lib.php b/web/app/libs/uoj-html-lib.php index 6e8e85f..70f5ed4 100644 --- a/web/app/libs/uoj-html-lib.php +++ b/web/app/libs/uoj-html-lib.php @@ -207,6 +207,12 @@ function echoLongTable($col_names, $table_name, $cond, $tail, $header_row, $prin } echo '
'; + + if (isset($config['print_before_table'])) { + $fun = $config['print_before_table']; + $fun(); + } + echo ''; echo ''; echo $header_row; @@ -226,12 +232,13 @@ function echoLongTable($col_names, $table_name, $cond, $tail, $header_row, $prin echo ''; echo '
'; - echo '
'; - + if (isset($config['print_after_table'])) { $fun = $config['print_after_table']; $fun(); } + + echo '
'; echo $pag->pagination(); } diff --git a/web/app/libs/uoj-query-lib.php b/web/app/libs/uoj-query-lib.php index 330a348..9256c75 100644 --- a/web/app/libs/uoj-query-lib.php +++ b/web/app/libs/uoj-query-lib.php @@ -97,7 +97,7 @@ function queryProblemListTags($id) { return $tags; } function queryProblemInList($list_id, $problem_id) { - return DB::selectFirst("select * from lists_problems where list_id='$blog_id' and problem_id='$problem_id'", MYSQLI_ASSOC); + return DB::selectFirst("SELECT * FROM lists_problems WHERE list_id = '$list_id' AND problem_id = '$problem_id'", MYSQLI_ASSOC); } function querySolution($problem_id, $blog_id) { @@ -185,6 +185,9 @@ function queryBlogComment($id) { function isProblemVisibleToUser($problem, $user) { return !$problem['is_hidden'] || hasProblemPermission($user, $problem); } +function isListVisibleToUser($list, $user) { + return !$list['is_hidden'] || isSuperUser($user); +} function isContestProblemVisibleToUser($problem, $contest, $user) { if (isProblemVisibleToUser($problem, $user)) { return true; diff --git a/web/app/route.php b/web/app/route.php index d70a422..b140d0c 100644 --- a/web/app/route.php +++ b/web/app/route.php @@ -22,9 +22,9 @@ Route::group([ Route::any('/problem/{id}/manage/managers', '/problem_managers_manage.php'); Route::any('/problem/{id}/manage/data', '/problem_data_manage.php'); - Route::any('/problem_lists', '/problem_lists.php'); - Route::any('/problem_list/{id}', '/problem_list.php'); - Route::any('/problem_list/{id}/manage', '/problem_list_manage.php'); + Route::any('/lists', '/lists.php'); + Route::any('/list/{id}', '/list.php'); + Route::any('/list/{id}/edit(?:/{tab})?', '/list_edit.php'); Route::any('/contests', '/contests.php'); Route::any('/contest/new', '/add_contest.php'); diff --git a/web/app/upgrade/9_list_v2/README.md b/web/app/upgrade/9_list_v2/README.md new file mode 100644 index 0000000..97810b3 --- /dev/null +++ b/web/app/upgrade/9_list_v2/README.md @@ -0,0 +1 @@ +ref: https://github.com/renbaoshuo/S2OJ/pull/9 diff --git a/web/app/upgrade/9_list_v2/down.sql b/web/app/upgrade/9_list_v2/down.sql new file mode 100644 index 0000000..57a528a --- /dev/null +++ b/web/app/upgrade/9_list_v2/down.sql @@ -0,0 +1 @@ +ALTER TABLE `lists` DROP COLUMN `description`; diff --git a/web/app/upgrade/9_list_v2/up.sql b/web/app/upgrade/9_list_v2/up.sql new file mode 100644 index 0000000..9d5679f --- /dev/null +++ b/web/app/upgrade/9_list_v2/up.sql @@ -0,0 +1 @@ +ALTER TABLE `lists` ADD COLUMN `description` TEXT NOT NULL DEFAULT '' AFTER `title`; diff --git a/web/app/views/main-nav.php b/web/app/views/main-nav.php index 6adc9e4..caf1268 100644 --- a/web/app/views/main-nav.php +++ b/web/app/views/main-nav.php @@ -64,7 +64,7 @@ mb-4" role="navigation">