diff --git a/db/app_uoj233.sql b/db/app_uoj233.sql index aa59101..3ae2d3a 100644 --- a/db/app_uoj233.sql +++ b/db/app_uoj233.sql @@ -366,7 +366,7 @@ UNLOCK TABLES; CREATE TABLE `countdowns` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `title` text NOT NULL, - `endtime` datetime NOT NULL, + `end_time` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -448,6 +448,21 @@ CREATE TABLE `groups` ( ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `groups_assignments` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8mb4 */; +CREATE TABLE `groups_assignments` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `list_id` int(11) NOT NULL, + `group_id` int(11) NOT NULL, + `end_time` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `groups_users` -- @@ -461,22 +476,6 @@ CREATE TABLE `groups_users` ( ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Table structure for table `assignments` --- - -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8mb4 */; -CREATE TABLE `assignments` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `list_id` int(11) NOT NULL, - `group_id` int(11) NOT NULL, - `create_time` datetime NOT NULL, - `deadline` datetime NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; -/*!40101 SET character_set_client = @saved_cs_client */; - -- -- Table structure for table `hacks` -- diff --git a/web/app/controllers/group.php b/web/app/controllers/group.php index b8e5a8a..2988ffb 100644 --- a/web/app/controllers/group.php +++ b/web/app/controllers/group.php @@ -1,4 +1,5 @@ -
+
-
- - + +

[隐藏] @@ -37,57 +37,48 @@ (ID: #)

- -

-

(小组 ID: )

- - - - - - - -
- + - -
+ +
+
+

+ +

+ +
+ purify(HTML::parsedown()->line($group['announcement'])) ?> +
+ +
+ +
+ +
+
+ +

- -
-
-
-
-
-

- -
-
-
-
-
    - class="mb-0" - - > - addtime(now(), '-168:00:00')", + 'order by end_time desc, list_id desc', + << + ID + 标题 + 状态 + 结束时间 + +EOD, + function($row) use ($group, $now) { + $end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']); - echo '
  • '; - echo '', $ass['title'], ' (题单 #', $ass['list_id'], ')'; - - if ($ddl < $now) { - echo ' overdue'; - } elseif ($ddl->getTimestamp() - $now->getTimestamp() < 86400) { // 1d - echo ' soon'; - } elseif ($now->getTimestamp() - $create_time->getTimestamp() < 86400) { // 1d - echo ' new'; - } - - $ddl_str = $ddl->format('Y-m-d H:i'); - echo ' (截止时间: ', $ddl_str, ',查看完成情况)'; - echo '
  • '; - } - - if (count($assignments) == 0) { - echo '

    暂无作业

    '; - } + echo ''; + echo '', $row['list_id'], ''; + echo '', '', HTML::escape($row['title']), '', ''; + if ($end_time < $now) { + echo '已结束'; + } else { + echo '进行中'; + } + echo '', $end_time->format('Y-m-d H:i:s'), ''; + echo ''; + }, + [ + 'echo_full' => true, + 'div_classes' => ['table-responsive'], + 'table_classes' => ['table', 'align-middle', 'mb-0'], + ] + ); ?> -
-

- -
-
-
-
- true, + 50, 'group_id' => $group_id, 'by_accepted' => true, - 'table_classes' => isset($REQUIRE_LIB['bootstrap5']) - ? array('table', 'text-center', 'mb-0') - : array('table', 'table-bordered', 'table-hover', 'table-striped', 'table-text-center') - )) ?> + 'table_classes' => ['table', 'text-center', 'mb-0'], + ]) ?>
- -

- diff --git a/web/app/controllers/group_assignment.php b/web/app/controllers/group_assignment.php index 964489a..38c9c1b 100644 --- a/web/app/controllers/group_assignment.php +++ b/web/app/controllers/group_assignment.php @@ -40,83 +40,128 @@ 作业:

    +
  • 对应题单:#
  • 所属小组:
  • -
  • 开始时间:
  • -
  • 结束时间:
  • +
  • 结束时间:
'; - $header_row .= ''.UOJLocale::get('username').''; - $header_row .= ''.UOJLocale::get('contests::total score').''; - foreach ($problem_ids as $problem_id) { - $header_row .= '' . '#'.$problem_id.'' . ''; + sort($problem_ids); + + foreach ($users as $user) { + $usernames[] = $user['username']; } - $header_row .= ''; + + // standings: rank => [user => [username, realname], scores[], rank] + $standings = []; - $print_row = function($row) use ($problem_ids) { - $username = $row['username']; + foreach ($usernames as $username) { + $user = queryUser($username); + $row = ['total_score' => 0]; - $scores = []; - $sum = 0; - $total_score = count($problem_ids) * 100; - $query = DB::query("SELECT MAX(id), problem_id, MAX(score) FROM submissions WHERE (problem_id, score) IN (SELECT problem_id, MAX(score) FROM submissions WHERE submitter = '{$username}' AND problem_id IN (".implode(',', $problem_ids).") GROUP BY problem_id) AND submitter = '{$username}' GROUP BY problem_id"); - - while ($row = DB::fetch($query)) { - $scores[$row['problem_id']] = [ - 'submission_id' => $row['MAX(id)'], - 'score' => $row['MAX(score)'], - ]; - - $sum += $row['MAX(score)']; - } - - if ($sum == $total_score) { - echo ''; - } else { - echo ''; - } - echo '' . getUserLink($username) . ''; - echo ''; - echo '', $sum, ''; - echo ''; + $row['user'] = [ + 'username' => $user['username'], + 'realname' => $user['realname'], + ]; foreach ($problem_ids as $problem_id) { - if (!isset($scores[$problem_id])) { - echo ''; + $cond = "submitter = '{$user['username']}' AND problem_id = $problem_id"; + $submission = DB::selectFirst("SELECT id, score FROM submissions INNER JOIN (SELECT MAX(score) AS score FROM submissions WHERE $cond) AS max USING (score) WHERE $cond ORDER BY submit_time DESC"); + + if ($submission) { + $row['scores'][] = [ + 'submission_id' => $submission['id'], + 'score' => intval($submission['score']), + ]; + $row['total_score'] += $submission['score']; } else { - if ($scores[$problem_id]['score'] == 100) { - echo ''; - } else { - echo ''; - } - echo ''.$scores[$problem_id]['score'].''; + $row['scores'][] = null; } - echo ''; } - echo ''; - }; - $from = "user_info a inner join groups_users b on (b.group_id = {$group['id']} and a.username = b.username)"; - $col_names = array('a.username as username'); - $cond = "1"; - $tail = "order by a.username asc"; - $config = [ - 'page_len' => 50, - 'div_classes' => ['card', 'my-3', 'table-responsive', 'text-center'], - 'table_classes' => ['table', 'uoj-table', 'mb-0'], - ]; + $standings[] = $row; + } + + usort($standings, function($lhs, $rhs) { + if ($lhs['total_score'] != $rhs['total_score']) { + return $rhs['total_score'] - $lhs['total_score']; + } - echoLongTable($col_names, $from, $cond, $tail, $header_row, $print_row, $config); + return strcmp($lhs['user']['username'], $rhs['user']['username']); + }); ?> +
+ + +
diff --git a/web/app/controllers/group_manage.php b/web/app/controllers/group_manage.php index c38f3b5..ce765b5 100644 --- a/web/app/controllers/group_manage.php +++ b/web/app/controllers/group_manage.php @@ -3,6 +3,7 @@ redirectToLogin(); } + requireLib('bootstrap5'); requirePHPLib('form'); requirePHPLib('judger'); requirePHPLib('data'); @@ -16,258 +17,453 @@ become403Page(); } - $group_editor = new UOJBlogEditor(); - $group_editor->name = 'group'; - $group_editor->blog_url = null; - $group_editor->cur_data = array( - 'title' => $group['title'], - 'tags' => array(), - 'is_hidden' => $group['is_hidden'] - ); - $group_editor->label_text = array_merge($group_editor->label_text, array( - 'view blog' => '保存小组信息', - 'blog visibility' => '小组可见性' - )); - $group_editor->show_editor = false; - $group_editor->show_tags = false; - - $group_editor->save = function($data) { - global $group_id, $group; - DB::update("update `groups` set title = '".DB::escape($data['title'])."' where id = {$group_id}"); - - if ($data['is_hidden'] != $group['is_hidden'] ) { - DB::update("update `groups` set is_hidden = {$data['is_hidden']} where id = {$group_id}"); - } - }; - $group_editor->runAtServer(); - - $add_new_user_form = new UOJForm('add_new_user'); - $add_new_user_form->addInput('new_username', 'text', '用户名', '', - function ($x) { - global $group_id; - - if (!validateUsername($x)) { - return '用户名不合法'; - } - $user = queryUser($x); - if (!$user) { - return '用户不存在'; - } - - if (queryUserInGroup($group_id, $x)) { - return '该用户已经在小组中'; - } - - return ''; - }, - null - ); - $add_new_user_form->submit_button_config['align'] = 'compressed'; - $add_new_user_form->submit_button_config['text'] = '添加到小组'; - $add_new_user_form->handle = function() { - global $group_id, $myUser; - $username = $_POST['new_username']; - - DB::insert("insert into groups_users (group_id, username) values ({$group_id}, '{$username}')"); - }; - $add_new_user_form->runAtServer(); - + if (isset($_GET['tab'])) { + $cur_tab = $_GET['tab']; + } else { + $cur_tab = 'profile'; + } - $delete_user_form = new UOJForm('delete_user'); - $delete_user_form->addInput('del_username', 'text', '用户名', '', - function ($x) { - global $group_id; + $tabs_info = [ + 'profile' => [ + 'name' => '基本信息', + 'url' => "/group/{$group['id']}/manage/profile", + ], + 'assignments' => [ + 'name' => '作业管理', + 'url' => "/group/{$group['id']}/manage/assignments", + ], + 'users' => [ + 'name' => '用户管理', + 'url' => "/group/{$group['id']}/manage/users", + ] + ]; + + if (!isset($tabs_info[$cur_tab])) { + become404Page(); + } - if (!validateUsername($x)) { - return '用户名不合法'; - } - if (!queryUserInGroup($group_id, $x)) { - return '该用户不在小组中'; + if ($cur_tab == 'profile') { + $update_profile_form = new UOJForm('update_profile'); + $update_profile_form->addVInput('name', 'text', '名称', $group['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' => '隐藏', + ], '可见性', $group['is_hidden']); + $update_profile_form->addVTextArea('announcement', '公告', $group['announcement'], + function($announcement, &$vdata) { + if (strlen($announcement) > 3000) { + return '公告过长'; + } + + $vdata['announcement'] = $announcement; + + return ''; + }, null); + $update_profile_form->handle = function($vdata) use ($group) { + $esc_title = DB::escape($vdata['title']); + $is_hidden = $_POST['is_hidden']; + $esc_announcement = $vdata['announcement']; + + DB::update("UPDATE `groups` SET title = '$esc_title', is_hidden = '$is_hidden', announcement = '$esc_announcement' WHERE id = {$group['id']}"); + + 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 == 'assignments') { + if (isset($_POST['submit-remove_assignment']) && $_POST['submit-remove_assignment'] == 'remove_assignment') { + $list_id = $_POST['list_id']; + + if (!validateUInt($list_id)) { + dieWithAlert('题单 ID 不合法。'); } - return ''; - }, - null - ); - $delete_user_form->submit_button_config['align'] = 'compressed'; - $delete_user_form->submit_button_config['text'] = '从小组中删除'; - $delete_user_form->handle = function() { - global $group_id, $myUser; - $username = $_POST['del_username']; - - DB::query("delete from groups_users where username='{$username}' and group_id={$group_id}"); - }; - $delete_user_form->runAtServer(); - - $add_new_assignment_form = new UOJForm('add_new_assignment'); - $add_new_assignment_form->addInput('new_assignment_list_id', 'text', '题单 ID', '', - function ($x) { - global $group_id; - - if (!validateUInt($x)) { - return '题单 ID 不合法'; - } - $list = queryProblemList($x); - if (!$list) { - return '题单不存在'; - } - if ($list['is_hidden'] != 0) { - return '题单是隐藏的'; + if (!queryAssignmentByGroupListID($group['id'], $list_id)) { + dieWithAlert('该题单不在作业中。'); } - if (queryAssignmentByGroupListID($group_id, $x)) { - return '该题单已经在作业中'; + DB::delete("DELETE FROM `groups_assignments` WHERE `list_id` = $list_id AND `group_id` = {$group['id']}"); + + dieWithAlert('移除成功!'); + } + + $add_new_assignment_form = new UOJForm('add_new_assignment'); + $add_new_assignment_form->addVInput('new_assignment_list_id', 'text', '题单 ID', '', + function ($list_id, &$vdata) use ($group) { + if (!validateUInt($list_id)) { + return '题单 ID 不合法'; + } + + if (!($list = queryProblemList($list_id))) { + return '题单不存在'; + } + + if ($list['is_hidden'] != 0) { + return '题单是隐藏的'; + } + + if (queryAssignmentByGroupListID($group['id'], $list_id)) { + return '该题单已经在作业中'; + } + + $vdata['list_id'] = $list_id; + + return ''; + }, + null + ); + $default_end_time = new DateTime(); + $default_end_time->setTime(17, 0, 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 ($group) { + $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 ({$group['id']}, '{$vdata['list_id']}', '{$esc_end_time}')"); + + dieWithJsonData([ + 'status' => 'success', + 'message' => '题单 #' . $vdata['list_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(); + } elseif ($cur_tab == 'users') { + if (isset($_POST['submit-remove_user']) && $_POST['submit-remove_user'] == 'remove_user') { + $username = $_POST['remove_username']; + + if (!validateUsername($username)) { + dieWithAlert('用户名不合法。'); } - return ''; - }, - null - ); - $default_ddl = new DateTime(); - $default_ddl->setTime(17, 0, 0); - $default_ddl->add(new DateInterval("P7D")); - $add_new_assignment_form->addInput('new_assignment_deadline', 'text', '截止时间', $default_ddl->format('Y-m-d H:i'), - function ($x) { - $ddl = DateTime::createFromFormat('Y-m-d H:i', $x); - if (!$ddl) { - return '截止时间格式不正确,请以类似 "2020-10-1 17:00" 的格式输入'; + if (!queryUser($username)) { + dieWithAlert('用户不存在。'); } - return ''; - }, - null - ); - $add_new_assignment_form->submit_button_config['align'] = 'compressed'; - $add_new_assignment_form->submit_button_config['text'] = '添加作业'; - $add_new_assignment_form->handle = function() { - global $group_id, $myUser; - $list_id = $_POST['new_assignment_list_id']; - $ddl = DateTime::createFromFormat('Y-m-d H:i', $_POST['new_assignment_deadline']); - $ddl_str = $ddl->format('Y-m-d H:i:s'); - - DB::insert("insert into assignments (group_id, list_id, create_time, deadline) values ({$group_id}, '{$list_id}', now(), '{$ddl_str}')"); - }; - $add_new_assignment_form->runAtServer(); - - $remove_assignment_form = new UOJForm('remove_assignment'); - $remove_assignment_form->addInput('remove_assignment_list_id', 'text', '题单 ID', '', - function ($x) { - global $group_id; - - if (!validateUInt($x)) { - return '题单 ID 不合法'; - } - if (!queryAssignmentByGroupListID($group_id, $x)) { - return '该题单不在作业中'; + if (!queryUserInGroup($group['id'], $username)) { + dieWithAlert('该用户不在小组中。'); } - return ''; - }, - null - ); + DB::delete("DELETE FROM `groups_users` WHERE `username` = '$username' AND `group_id` = {$group['id']}"); - $remove_assignment_form->submit_button_config['align'] = 'compressed'; - $remove_assignment_form->submit_button_config['text'] = '删除作业'; - $remove_assignment_form->handle = function() { - global $group_id, $myUser; - $list_id = $_POST['remove_assignment_list_id']; + dieWithAlert('移除成功!'); + } - DB::query("delete from assignments where list_id='{$list_id}' and group_id={$group_id}"); - }; - $remove_assignment_form->runAtServer(); + $add_new_user_form = new UOJForm('add_new_user'); + $add_new_user_form->addVInput('new_username', 'text', '用户名', '', + function ($username, &$vdata) { + global $group_id; - $announcement_form = new UOJForm('announcement_form'); - $announcement_form->addVTextArea('announcement_content', '公告', $group['announcement'], - function ($x) { - return ''; - }, - null - ); - $announcement_form->submit_button_config['text'] = '更新公告'; - $announcement_form->handle = function() { - global $group_id, $myUser; + if (!validateUsername($username)) { + return '用户名不合法'; + } - $content = $_POST['announcement_content']; - $esc_content = DB::escape($content); - DB::query("update groups set announcement = '{$esc_content}' where id = {$group_id}"); - }; - $announcement_form->runAtServer(); + if (!queryUser($username)) { + return '用户不存在'; + } + + if (queryUserInGroup($group_id, $username)) { + return '该用户已经在小组中'; + } + + $vdata['username'] = $username; + + return ''; + }, + null + ); + $add_new_user_form->submit_button_config['margin_class'] = 'mt-3'; + $add_new_user_form->submit_button_config['text'] = '添加'; + $add_new_user_form->handle = function(&$vdata) use ($group) { + DB::insert("insert into groups_users (group_id, username) values ({$group['id']}, '{$vdata['username']}')"); + + dieWithJsonData(['status' => 'success', 'message' => '已将用户名为 ' . $vdata['username'] . ' 的用户添加到本小组。']); + }; + $add_new_user_form->setAjaxSubmit(<<runAtServer(); + } ?> + - - -

- (#)管理 +

+ + (ID: #) + 管理

- +
+ +
-
+ -
编辑小组信息
-
- printHTML(); ?> +"> + 返回 + + +
+ + + +
+ +
+
+ +
+
+ printHTML() ?> +
+
+
注意事项
+
    +
  • 隐藏的小组无法被普通用户查看,即使该用户属于本小组。
  • +
  • 公告支持 Markdown 语法,但不支持添加数学公式。
  • +
+
+
+
+
+ +
+
+ +
+
+
+
+ + ID + 标题 + 状态 + 结束时间 + 操作 + +EOD, + function($row) use ($group, $now) { + $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 < $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() ?> +
+
+
注意事项
+
    +
  • 要被添加为作业的题单必须是公开的。
  • +
  • 请为学生预留合理的完成作业的时间。
  • +
  • 排行榜将在结束后停止更新。
  • +
  • 如需延长结束时间请删除后再次添加,排行数据不会丢失。
  • +
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+ + 用户名 + 操作 + + EOD, + function($row) use ($group) { + echo ''; + echo '', getUserLink($row['username']), ''; + echo ''; + echo '
' + . '' + . '' + . '' + . '
'; + echo ''; + echo ''; + }, + [ + 'page_len' => 20, + 'div_classes' => ['table-responsive'], + 'table_classes' => ['table', 'align-middle'], + ] + ); + ?> +
+
+ +
+
+ printHTML() ?> +
+
+
注意事项
+
    +
  • 添加用户前请确认用户名是否正确以免带来不必要的麻烦。
  • +
  • 用户被添加到小组后将自动被加入组内的所有作业排行中。
  • +
+
+
+
+
+
+
+ +
-
编辑小组公告
-printHTML(); ?> - -
添加用户到小组
-printHTML(); ?> - -
从小组中删除用户
-printHTML(); ?> - -
为小组添加作业
-printHTML(); ?> - -
删除小组的作业
-printHTML(); ?> - -
已被自动隐藏的作业
-
    - getTimestamp() - $ddl->getTimestamp() <= 604800) { - continue; - } // 7d - - echo '
  • '; - echo '', $ass['title'], ' (题单 #', $ass['list_id'], ')'; - - if ($ddl < $now) { - echo ' overdue'; - } elseif ($ddl->getTimestamp() - $now->getTimestamp() < 86400) { // 1d - echo ' soon'; - } elseif ($now->getTimestamp() - $create_time->getTimestamp() < 86400) { // 1d - echo ' new'; - } - - $ddl_str = $ddl->format('Y-m-d H:i'); - echo ' (截止时间: ', $ddl_str, ',查看完成情况)'; - echo '
  • '; - } - - if (count($assignments) == 0) { - echo '

    暂无作业

    '; - } - ?> -
- diff --git a/web/app/controllers/image_hosting/index.php b/web/app/controllers/image_hosting/index.php index 2237a86..e69b84f 100644 --- a/web/app/controllers/image_hosting/index.php +++ b/web/app/controllers/image_hosting/index.php @@ -19,7 +19,7 @@ $count = $_result["count(*)"]; function throwError($msg) { - returnJSONData(['status' => 'error', 'message' => $msg]); + dieWithJsonData(['status' => 'error', 'message' => $msg]); } $allowedTypes = [IMAGETYPE_PNG, IMAGETYPE_JPEG]; @@ -66,7 +66,7 @@ $existing_image = DB::selectFirst("SELECT * FROM users_images WHERE `hash` = '$hash'"); if ($existing_image) { - returnJSONData(['status' => 'success', 'path' => $existing_image['path']]); + dieWithJsonData(['status' => 'success', 'path' => $existing_image['path']]); } $image = new Imagick($_FILES["image_upload_file"]["tmp_name"]); @@ -92,7 +92,7 @@ DB::insert("INSERT INTO users_images (`path`, uploader, width, height, upload_time, size, `hash`) VALUES ('$filename', '{$myUser['username']}', $width, $height, now(), {$_FILES["image_upload_file"]["size"]}, '$hash')"); - returnJSONData(['status' => 'success', 'path' => $filename]); + dieWithJsonData(['status' => 'success', 'path' => $filename]); } elseif ($_POST['image_delete_submit'] == 'submit') { crsf_defend(); diff --git a/web/app/controllers/index.php b/web/app/controllers/index.php index a928688..393ff68 100644 --- a/web/app/controllers/index.php +++ b/web/app/controllers/index.php @@ -1,6 +1,6 @@ mb-0"> diff --git a/web/app/controllers/super_manage.php b/web/app/controllers/super_manage.php index 59687b1..c9316db 100644 --- a/web/app/controllers/super_manage.php +++ b/web/app/controllers/super_manage.php @@ -56,12 +56,12 @@ $blog_id = $_POST['blog_id']; if (!validateUInt($blog_id)) { - die('' . SCRIPT_REFRESH_AS_GET); + dieWithAlert('移除失败:博客 ID 无效'); } DB::delete("DELETE FROM important_blogs WHERE blog_id = {$blog_id}"); - die('' . SCRIPT_REFRESH_AS_GET); + dieWithAlert('移除成功!'); } $announcements = DB::selectAll("SELECT blogs.id as id, blogs.title as title, blogs.poster as poster, user_info.realname as realname, blogs.post_time as post_time, important_blogs.level as level, blogs.is_hidden as is_hidden FROM important_blogs INNER JOIN blogs ON important_blogs.blog_id = blogs.id INNER JOIN user_info ON blogs.poster = user_info.username ORDER BY level DESC, important_blogs.blog_id DESC"); @@ -121,15 +121,15 @@ $countdown_id = $_POST['countdown_id']; if (!validateUInt($countdown_id)) { - die('' . SCRIPT_REFRESH_AS_GET); + dieWithAlert('删除失败:倒计时 ID 无效'); } DB::delete("DELETE FROM countdowns WHERE id = {$countdown_id}"); - die('' . SCRIPT_REFRESH_AS_GET); + dieWithAlert('删除成功!'); } - $countdowns = DB::selectAll("SELECT id, title, endtime FROM countdowns ORDER BY endtime ASC"); + $countdowns = DB::selectAll("SELECT id, title, end_time FROM countdowns ORDER BY end_time ASC"); $add_countdown_form = new UOJForm('add_countdown'); $add_countdown_form->addInput('countdown_title', 'text', '标题', '', @@ -144,10 +144,10 @@ }, null ); - $add_countdown_form->addInput('countdown_endtime', 'text', '结束时间', date("Y-m-d H:i:s"), - function($endtime, &$vdata) { + $add_countdown_form->addInput('countdown_end_time', 'text', '结束时间', date("Y-m-d H:i:s"), + function($end_time, &$vdata) { try { - $vdata['endtime'] = new DateTime($endtime); + $vdata['end_time'] = new DateTime($end_time); } catch (Exception $e) { return '无效时间格式'; } @@ -158,9 +158,9 @@ ); $add_countdown_form->handle = function(&$vdata) { $esc_title = DB::escape($vdata['title']); - $esc_endtime = DB::escape($vdata['endtime']->format('Y-m-d H:i:s')); + $esc_end_time = DB::escape($vdata['end_time']->format('Y-m-d H:i:s')); - DB::insert("INSERT INTO countdowns (title, endtime) VALUES ('{$esc_title}', '{$esc_endtime}')"); + DB::insert("INSERT INTO countdowns (title, end_time) VALUES ('{$esc_title}', '{$esc_end_time}')"); }; $add_countdown_form->submit_button_config['align'] = 'compressed'; $add_countdown_form->submit_button_config['text'] = '添加'; @@ -174,12 +174,12 @@ $item_id = $_POST['item_id']; if (!validateUInt($item_id)) { - die('' . SCRIPT_REFRESH_AS_GET); + dieWithAlert('删除失败:ID 无效'); } DB::delete("DELETE FROM links WHERE id = {$item_id}"); - die('' . SCRIPT_REFRESH_AS_GET); + dieWithAlert('删除成功!'); } $links = DB::selectAll("SELECT `id`, `title`, `url`, `level` FROM `friend_links` ORDER BY `level` DESC, `id` ASC"); @@ -315,7 +315,7 @@ DB::query("insert into user_info (username, realname, email, school, password, svn_password, register_time, usergroup) values ('$username', '$realname', '$email', '$school', '$password', '$svn_password', now(), 'U')"); - returnJSONData(['status' => 'success', 'message' => '']); + dieWithJsonData(['status' => 'success', 'message' => '']); }; $register_form->setAjaxSubmit(<< 'success', 'message' => '用户 ' . $vdata['username'] . ' 的密码已经被成功重置。']); + dieWithJsonData(['status' => 'success', 'message' => '用户 ' . $vdata['username'] . ' 的密码已经被成功重置。']); }; $change_password_form->submit_button_config['margin_class'] = 'mt-3'; $change_password_form->submit_button_config['text'] = '重置'; @@ -436,7 +436,7 @@ EOD); break; } - returnJSONData(['status' => 'success', 'message' => '用户 ' . $username . ' 现在是 ' . $usergroup . '。']); + dieWithJsonData(['status' => 'success', 'message' => '用户 ' . $username . ' 现在是 ' . $usergroup . '。']); }; $change_usergroup_form->setAjaxSubmit(<<alert("删除失败:图片 ID 无效");' . SCRIPT_REFRESH_AS_GET); + dieWithAlert('删除失败:图片 ID 无效'); } if (!($image = DB::selectFirst("SELECT * from users_images where id = $image_id"))) { - die('' . SCRIPT_REFRESH_AS_GET); + dieWithAlert('删除失败:图片不存在'); } unlink(UOJContext::storagePath().$result['path']); DB::delete("DELETE FROM users_images WHERE id = $image_id"); - die('' . SCRIPT_REFRESH_AS_GET); + dieWithAlert('删除成功!'); } @@ -710,7 +710,7 @@ EOD); col_tr += ''; col_tr += '' + row['title'] + ''; - col_tr += '' + row['endtime'] + ''; + col_tr += '' + row['end_time'] + ''; col_tr += '' + '
' + '' + diff --git a/web/app/controllers/user_info_edit.php b/web/app/controllers/user_info_edit.php index bd213cc..046b3c6 100644 --- a/web/app/controllers/user_info_edit.php +++ b/web/app/controllers/user_info_edit.php @@ -179,7 +179,7 @@ EOD); DB::update("UPDATE user_info SET email = '$esc_email', qq = '$esc_qq', sex = '$esc_sex', motto = '$esc_motto', codeforces_handle = '$esc_codeforces_handle', github = '$esc_github', website = '$esc_website', avatar_source = '$esc_avatar_source' WHERE username = '{$user['username']}'"); - returnJSONData(['status' => 'success']); + dieWithJsonData(['status' => 'success']); }; $update_profile_form->submit_button_config['margin_class'] = 'mt-3'; $update_profile_form->submit_button_config['text'] = '更新'; @@ -209,21 +209,21 @@ EOD); $new_password = $_POST['new_password']; if (!validatePassword($old_password) || !checkPassword($user, $old_password)) { - returnJSONData(['status' => 'error', 'message' => '旧密码错误']); + dieWithJsonData(['status' => 'error', 'message' => '旧密码错误']); } if (!validatePassword($new_password)) { - returnJSONData(['status' => 'error', 'message' => '新密码不合法']); + dieWithJsonData(['status' => 'error', 'message' => '新密码不合法']); } if ($old_password == $new_password) { - returnJSONData(['status' => 'error', 'message' => '新密码不能与旧密码相同']); + dieWithJsonData(['status' => 'error', 'message' => '新密码不能与旧密码相同']); } $password = getPasswordToStore($new_password, $user['username']); DB::update("UPDATE `user_info` SET `password` = '$password' where `username` = '{$user['username']}'"); - returnJSONData(['status' => 'success', 'message' => '密码修改成功']); + dieWithJsonData(['status' => 'success', 'message' => '密码修改成功']); } } elseif ($cur_tab == 'privilege') { if (isset($_POST['submit-privilege']) && $_POST['submit-privilege'] == 'privilege' && isSuperUser($myUser)) { @@ -254,7 +254,7 @@ EOD); DB::update("UPDATE `user_info` SET `usertype` = '{$user['usertype']}' where `username` = '{$user['username']}'"); - returnJSONData(['status' => 'success', 'message' => '权限修改成功']); + dieWithJsonData(['status' => 'success', 'message' => '权限修改成功']); } } diff --git a/web/app/libs/uoj-form-lib.php b/web/app/libs/uoj-form-lib.php index f91aae2..e2f31d1 100644 --- a/web/app/libs/uoj-form-lib.php +++ b/web/app/libs/uoj-form-lib.php @@ -1,4 +1,6 @@ ;window.location = window.location.origin + window.location.pathname + (window.location.search.length ? window.location.search + "&" : "?") + "_refresh_" + (+new Date()) + "=" + (+new Date()) + window.location.hash;'); + class UOJForm { public $form_name; public $succ_href; @@ -862,8 +864,12 @@ EOD; return $form; } - function returnJSONData($data) { + function dieWithJsonData($data) { header('Content-Type: application/json'); die(json_encode($data)); } + + function dieWithAlert($str) { + die(''.SCRIPT_REFRESH_AS_GET); + } ?> diff --git a/web/app/libs/uoj-query-lib.php b/web/app/libs/uoj-query-lib.php index fb8896f..8bd4c6f 100644 --- a/web/app/libs/uoj-query-lib.php +++ b/web/app/libs/uoj-query-lib.php @@ -130,6 +130,9 @@ function queryContestProblems($id) { function queryGroup($id) { return DB::selectFirst("select * from groups where id = $id", MYSQLI_ASSOC); } +function queryGroupUsers($id) { + return DB::selectAll("SELECT * FROM groups_users WHERE group_id = $id"); +} function queryUserInGroup($group_id, $username) { return DB::selectFirst("select * from groups_users where username='$username' and group_id='$group_id'", MYSQLI_ASSOC); } @@ -143,17 +146,13 @@ function queryGroupCurrentAC($group_id) { return DB::selectAll("select a.problem_id as problem_id, a.submitter as submitter, a.submission_id as submission_id, b.submit_time as submit_time, d.title as problem_title, b.submit_time as submit_time, e.realname as realname from best_ac_submissions a inner join submissions b on (a.submission_id = b.id) inner join groups_users c on (a.submitter = c.username and c.group_id = $group_id) inner join problems d on (a.problem_id = d.id and d.is_hidden = 0) inner join user_info e on (a.submitter = e.username) where b.submit_time > addtime(now(), '-360:00:00') order by b.submit_time desc limit 10", MYSQLI_ASSOC); } function queryGroupAssignments($group_id) { - return DB::selectAll("select a.id as id, a.list_id as list_id, a.create_time as create_time, a.deadline as deadline, b.title from assignments a left join lists b on a.list_id = b.id where a.group_id = $group_id order by a.deadline asc", MYSQLI_ASSOC); + return DB::selectAll("select a.id as id, a.list_id as list_id, a.end_time as end_time, b.title from groups_assignments a left join lists b on a.list_id = b.id where a.group_id = $group_id order by a.end_time asc", MYSQLI_ASSOC); } function queryGroupActiveAssignments($group_id) { - return DB::selectAll("select a.id as id, a.group_id as group_id, a.list_id as list_id, a.create_time as create_time, a.deadline as deadline, b.title from assignments a left join lists b on a.list_id = b.id where a.group_id = $group_id and a.deadline > addtime(now(), '-168:00:00') order by a.deadline asc", MYSQLI_ASSOC); -} - -function queryAssignment($id) { - return DB::selectFirst("select * from assignments where id = $id", MYSQLI_ASSOC); + return DB::selectAll("select a.id as id, a.group_id as group_id, a.list_id as list_id, a.end_time as end_time, b.title from groups_assignments a left join lists b on a.list_id = b.id where a.group_id = $group_id and a.end_time > addtime(now(), '-168:00:00') order by a.end_time asc", MYSQLI_ASSOC); } function queryAssignmentByGroupListID($group_id, $list_id) { - return DB::selectFirst("select * from assignments where list_id='$list_id' and group_id='$group_id'", MYSQLI_ASSOC); + return DB::selectFirst("select * from groups_assignments where list_id='$list_id' and group_id='$group_id'", MYSQLI_ASSOC); } function queryZanVal($id, $type, $user) { diff --git a/web/app/locale/basic/en.php b/web/app/locale/basic/en.php index 4142075..73e28fd 100644 --- a/web/app/locale/basic/en.php +++ b/web/app/locale/basic/en.php @@ -15,6 +15,7 @@ return [ 'problems lists' => 'Problems Lists', 'groups' => 'Groups', 'add new group' => 'Add new group', + 'group announcement' => 'Group Announcement', 'group announcements' => 'Group Announcements', 'users count' => 'Users', 'submissions' => 'Submissions', diff --git a/web/app/locale/basic/zh-cn.php b/web/app/locale/basic/zh-cn.php index bbc1c5d..e18d4ed 100644 --- a/web/app/locale/basic/zh-cn.php +++ b/web/app/locale/basic/zh-cn.php @@ -15,6 +15,7 @@ return [ 'problems lists' => '题单', 'groups' => '小组', 'add new group' => '添加新小组', + 'group announcement' => '小组公告', 'group announcements' => '小组公告', 'users count' => '用户数量', 'submissions' => '提交记录', diff --git a/web/app/route.php b/web/app/route.php index d62588f..d70a422 100644 --- a/web/app/route.php +++ b/web/app/route.php @@ -49,7 +49,7 @@ Route::group([ Route::any('/groups', '/groups.php'); Route::any('/group/{id}', '/group.php'); - Route::any('/group/{id}/manage', '/group_manage.php'); + Route::any('/group/{id}/manage(?:/{tab})?', '/group_manage.php'); Route::any('/group/{id}/assignment/{list_id}', '/group_assignment.php'); Route::any('/blogs', '/blogs.php'); diff --git a/web/app/upgrade/8_group_v2/README.md b/web/app/upgrade/8_group_v2/README.md new file mode 100644 index 0000000..1ba6224 --- /dev/null +++ b/web/app/upgrade/8_group_v2/README.md @@ -0,0 +1 @@ +ref: https://github.com/renbaoshuo/S2OJ/pull/8 diff --git a/web/app/upgrade/8_group_v2/down.sql b/web/app/upgrade/8_group_v2/down.sql new file mode 100644 index 0000000..8008d9d --- /dev/null +++ b/web/app/upgrade/8_group_v2/down.sql @@ -0,0 +1,4 @@ +RENAME TABLE groups_assignments TO assignments; +ALTER TABLE `assignments` ADD COLUMN `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP; +ALTER TABLE `assignments` CHANGE COLUMN `end_time` `deadline` datetime NOT NULL; +ALTER TABLE `countdowns` CHANGE COLUMN `end_time` `endtime` datetime NOT NULL; diff --git a/web/app/upgrade/8_group_v2/up.sql b/web/app/upgrade/8_group_v2/up.sql new file mode 100644 index 0000000..347d0b1 --- /dev/null +++ b/web/app/upgrade/8_group_v2/up.sql @@ -0,0 +1,4 @@ +RENAME TABLE assignments TO groups_assignments; +ALTER TABLE `groups_assignments` DROP COLUMN `create_time`; +ALTER TABLE `groups_assignments` CHANGE COLUMN `deadline` `end_time` datetime NOT NULL; +ALTER TABLE `countdowns` CHANGE COLUMN `endtime` `end_time` datetime NOT NULL; diff --git a/web/app/views/sidebar.php b/web/app/views/sidebar.php index 6139098..f573d29 100644 --- a/web/app/views/sidebar.php +++ b/web/app/views/sidebar.php @@ -11,6 +11,8 @@
  • @@ -18,7 +20,7 @@
    - purify($group_announcement) ?> + purify($parsedown->line($group_announcement)) ?>
    @@ -38,11 +40,13 @@ } usort($assignments, function($a, $b) { - $deadline_a = DateTime::createFromFormat('Y-m-d H:i:s', $a['deadline']); - $deadline_b = DateTime::createFromFormat('Y-m-d H:i:s', $b['deadline']); + $end_time_a = DateTime::createFromFormat('Y-m-d H:i:s', $a['end_time']); + $end_time_b = DateTime::createFromFormat('Y-m-d H:i:s', $b['end_time']); - return $deadline_b->getTimestamp() - $deadline_a->getTimestamp(); + return $end_time_b->getTimestamp() - $end_time_a->getTimestamp(); }); + + $assignments = array_slice($assignments, 0, 5); ?>
    @@ -53,22 +57,19 @@
  • - + overdue - getTimestamp() - $now->getTimestamp() < 86400): ?> + getTimestamp() - $now->getTimestamp() < 86400): ?> soon - getTimestamp() - $create_time->getTimestamp() < 86400): ?> - new
    - 截止时间: format('Y-m-d H:i') ?> + 截止时间: format('Y-m-d H:i') ?>
  • diff --git a/web/css/uoj-bs5.css b/web/css/uoj-bs5.css index 3039ad4..730e76a 100644 --- a/web/css/uoj-bs5.css +++ b/web/css/uoj-bs5.css @@ -51,11 +51,13 @@ label { float: right; } -.uoj-table > tbody > tr:last-child { +.uoj-table > tbody > tr:last-child, +.uoj-table > tbody > tr:last-child > td { border-bottom-color: transparent; } -.uoj-table > thead > tr:first-child { +.uoj-table > thead > tr:first-child, +.uoj-table > thead > tr:first-child > td { border-top-color: transparent; }