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 @@
作业:= $list['title'] ?>
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();
+ }
+ ?>
-
+
+
+
+
-
+
= UOJLocale::get('groups') ?>
-
-
-
-
- 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']} |
+
+
+ |
+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);
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+ = $list['title'] ?>
+ (ID: #= $list['id'] ?>)
+
+
+
+ = UOJLocale::get('hidden') ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
题单简介
+ purify(HTML::parsedown()->text($list['description'])) ?>
+
+ = $description ?>
+
+
暂无简介
+
+
+
+
+
+
+
+
+= $pag->pagination() ?>
+
+
+
+
+ = $header ?>
+
+
+get() as $idx => $row): ?>
+
+
+isEmpty()): ?>
+
+
+ = UOJLocale::get('none') ?>
+ |
+
+
+
+
+
+
+= $pag->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'));
+ }
+ ?>
+
+
+
+
+ = $list['title'] ?>
+ (ID: #= $list['id'] ?>)
+ 管理
+
+
+
+
+
+
+= HTML::navListGroup($tabs_info, $cur_tab) ?>
+
+
">
+ 返回
+
+
+
+
+
+
+
+
+
+
+
+
+
+ = $update_profile_form->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 '
';
+ },
+ [
+ '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 '
';
+ }
+ }
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+ = UOJLocale::get('problems lists') ?>
+
+
+
+
+ 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']} |
-
-
- |
-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');
- ?>
-
-
-
-
-
-
-
-
-
- [隐藏]
-
- = $list['title'] ?>
- (ID: #= $list['id'] ?>)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- = $pag->pagination(); ?>
-
-
-
-
-
-
- = $pag->pagination(); ?>
-
-
-
-
-
-
-
-
-
-
-
-
- = $header ?>
-
-
-get() as $idx => $row) {
- echoProblem($row);
- echo "\n";
- }
- ?>
-
-isEmpty()): ?>
-
-
- = UOJLocale::get('none') ?>
- |
-
-
-
-
-
-
-
-= $pag->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);
- ?>
-
-
-
-
- = $list['title'] ?>(#= $list['id'] ?>)管理
-
-
-
-
-
- printHTML(); ?>
-
-
-
-
-
- ID |
- 题目名称 |
- 操作 |
-
-
-
- get() as $idx => $row) {
- echoProblem($row);
- echo "\n";
- }
- ?>
- isEmpty()): ?>
-
-
- = UOJLocale::get('none') ?>
- |
-
-
-
-
-
- printHTML() ?>
-
-
-= $pag->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 '
';
- }
- ?>
-
-
-
-
-
-
-
-
-
- = UOJLocale::get('problems lists') ?>
-
-
-
-
-
-
- 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">
-
+
diff --git a/web/js/uoj.js b/web/js/uoj.js
index 1b218b7..86d2860 100644
--- a/web/js/uoj.js
+++ b/web/js/uoj.js
@@ -249,7 +249,7 @@ $.fn.uoj_problem_tag = function() {
}
$.fn.uoj_list_tag = function() {
return this.each(function() {
- $(this).attr('href', uojHome + '/problem_lists?tag=' + encodeURIComponent($(this).text()));
+ $(this).attr('href', uojHome + '/lists?tag=' + encodeURIComponent($(this).text()));
});
}
$.fn.uoj_blog_tag = function() {