;window.location = window.location.origin + window.location.pathname + (window.location.search.length ? window.location.search + "&" : "?") + "_=" + (+new Date()) + window.location.hash;'); if (!Auth::check()) { redirectToLogin(); } if (!isSuperUser($myUser)) { become403Page(); } $cur_tab = isset($_GET['tab']) ? $_GET['tab'] : 'index'; $tabs_info = [ 'index' => [ 'name' => '首页管理', 'url' => "/super_manage/index", ], 'users' => [ 'name' => '用户管理', 'url' => "/super_manage/users", ], 'submissions' => [ 'name' => '提交记录', 'url' => "/super_manage/submissions", ], 'custom_test' => [ 'name' => '自定义测试', 'url' => "/super_manage/custom_test", ], 'judger' => [ 'name' => '评测机管理', 'url' => "/super_manage/judger", ], 'image_hosting' => [ 'name' => '图床管理', 'url' => "/super_manage/image_hosting", ], ]; if (!isset($tabs_info[$cur_tab])) { become404Page(); } if ($cur_tab == 'index') { // ========== 公告 ========== if (isset($_POST['submit-delete_announcement']) && $_POST['submit-delete_announcement'] == 'delete_announcement') { crsf_defend(); $blog_id = $_POST['blog_id']; if (!validateUInt($blog_id)) { die('' . SCRIPT_REFRESH_AS_GET); } DB::delete("DELETE FROM important_blogs WHERE blog_id = {$blog_id}"); die('' . SCRIPT_REFRESH_AS_GET); } $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"); $add_announcement_form = new UOJForm('add_announcement'); $add_announcement_form->addInput('blog_id', 'text', '博客 ID', '', function($id, &$vdata) { if (!validateUInt($id)) { return '博客 ID 无效'; } if (!queryBlog($id)) { return '博客不存在'; } $vdata['blog_id'] = $id; return ''; }, null ); $add_announcement_form->addInput('blog_level', 'text', '置顶级别', '0', function ($x, &$vdata) { if (!validateUInt($x)) { return '数字不合法'; } if ($x > 3) { return '该级别不存在'; } $vdata['level'] = $x; return ''; }, null ); $add_announcement_form->handle = function(&$vdata) { $blog_id = $vdata['blog_id']; $blog_level = $vdata['level']; if (DB::selectFirst("select * from important_blogs where blog_id = {$blog_id}")) { DB::update("update important_blogs set level = {$blog_level} where blog_id = {$blog_id}"); } else { DB::insert("insert into important_blogs (blog_id, level) values ({$blog_id}, {$blog_level})"); } }; $add_announcement_form->submit_button_config['align'] = 'compressed'; $add_announcement_form->submit_button_config['text'] = '提交'; $add_announcement_form->succ_href = '/super_manage/index#announcements'; $add_announcement_form->runAtServer(); // ========== 倒计时 ========== if (isset($_POST['submit-delete_countdown']) && $_POST['submit-delete_countdown'] == 'delete_countdown') { crsf_defend(); $countdown_id = $_POST['countdown_id']; if (!validateUInt($countdown_id)) { die('' . SCRIPT_REFRESH_AS_GET); } DB::delete("DELETE FROM countdowns WHERE id = {$countdown_id}"); die('' . SCRIPT_REFRESH_AS_GET); } $countdowns = DB::selectAll("SELECT id, title, endtime FROM countdowns ORDER BY endtime ASC"); $add_countdown_form = new UOJForm('add_countdown'); $add_countdown_form->addInput('countdown_title', 'text', '标题', '', function($title, &$vdata) { if ($title == '') { return '标题不能为空'; } $vdata['title'] = $title; return ''; }, null ); $add_countdown_form->addInput('countdown_endtime', 'text', '结束时间', date("Y-m-d H:i:s"), function($endtime, &$vdata) { try { $vdata['endtime'] = new DateTime($endtime); } catch (Exception $e) { return '无效时间格式'; } return ''; }, null ); $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')); DB::insert("INSERT INTO countdowns (title, endtime) VALUES ('{$esc_title}', '{$esc_endtime}')"); }; $add_countdown_form->submit_button_config['align'] = 'compressed'; $add_countdown_form->submit_button_config['text'] = '添加'; $add_countdown_form->succ_href = '/super_manage/index#countdowns'; $add_countdown_form->runAtServer(); // ========== 常用链接 ========== if (isset($_POST['submit-delete_link']) && $_POST['submit-delete_link'] == 'delete_link') { crsf_defend(); $item_id = $_POST['item_id']; if (!validateUInt($item_id)) { die('' . SCRIPT_REFRESH_AS_GET); } DB::delete("DELETE FROM links WHERE id = {$item_id}"); die('' . SCRIPT_REFRESH_AS_GET); } $links = DB::selectAll("SELECT `id`, `title`, `url`, `level` FROM `friend_links` ORDER BY `level` DESC, `id` ASC"); $add_link_form = new UOJForm('add_link'); $add_link_form->addInput('link_title', 'text', '标题', '', function($title, &$vdata) { if ($title == '') { return '标题不能为空'; } $vdata['title'] = $title; return ''; }, null ); $add_link_form->addInput('link_url', 'text', '链接', '', function($url, &$vdata) { if (!validateURL($url)) { return '链接不合法'; } $vdata['url'] = $url; return ''; }, null ); $add_link_form->addInput('link_level', 'text', '权重', '10', function($level, &$vdata) { if (!validateUInt($level)) { return '数字不合法'; } $vdata['level'] = $level; return ''; }, null ); $add_link_form->handle = function(&$vdata) { $esc_title = DB::escape($vdata['title']); $esc_url = DB::escape($vdata['url']); $level = $vdata['level']; DB::insert("INSERT INTO friend_links (title, url, level) VALUES ('{$esc_title}', '{$esc_url}', {$level})"); }; $add_link_form->submit_button_config['align'] = 'compressed'; $add_link_form->submit_button_config['text'] = '添加'; $add_link_form->succ_href = '/super_manage/index#links'; $add_link_form->runAtServer(); } elseif ($cur_tab == 'users') { $user_list_cond = []; if (isset($_GET['username']) && $_GET['username'] != "") { $user_list_cond[] = "username like '%" . DB::escape($_GET['username']) . "%'"; } if (isset($_GET['usergroup']) && $_GET['usergroup'] != "") { $user_list_cond[] = "usergroup = '" . DB::escape($_GET['usergroup']) . "'"; } if (isset($_GET['usertype']) && $_GET['usertype'] != "") { $user_list_cond[] = "usertype like '%" . DB::escape($_GET['usertype']) . "%'"; } if ($user_list_cond) { $user_list_cond = join($user_list_cond, ' and '); } else { $user_list_cond = '1'; } $register_form = new UOJForm('register'); $register_form->addVInput('new_username', 'text', '用户名', '', function ($username, &$vdata) { if (!validateUsername($username)) { return '用户名不合法'; } if (queryUser($username)) { return '该用户已存在'; } $vdata['username'] = $username; return ''; }, null ); $register_form->addVInput('new_password', 'password', '密码', '', function ($password, &$vdata) { $vdata['password'] = $password; return ''; }, 'validatePassword' ); $register_form->addVInput('new_email', 'text', '电子邮件(选填)', '', function ($email, &$vdata) { if ($email && !validateEmail($email)) { return '邮件地址不合法'; } $vdata['email'] = $email; return ''; }, null ); $register_form->addVInput('new_realname', 'text', '真实姓名(选填)', '', function ($realname, &$vdata) { $vdata['realname'] = $realname; return ''; }, null ); $register_form->addVInput('new_school', 'text', '学校名称(选填)', '', function ($school, &$vdata) { $vdata['school'] = $school; return ''; }, null ); $register_form->handle = function(&$vdata) { $username = $vdata['username']; $realname = DB::escape($vdata['realname']); $school = DB::escape($vdata['school']); $email = DB::escape($vdata['email']); $password = hash_hmac('md5', $vdata['password'], getPasswordClientSalt()); $password = getPasswordToStore($password, $username); $svn_password = uojRandString(10); 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')"); header('Content-Type: application/json'); die(json_encode(['status' => 'success', 'message' => ''])); }; $register_form->setAjaxSubmit(<<runAtServer(); $change_password_form = new UOJForm('change_password'); $change_password_form->addVInput('p_username', 'text', '用户名', '', function ($username, &$vdata) { if (!validateUsername($username)) { return '用户名不合法'; } if (!queryUser($username)) { return '用户不存在'; } $vdata['username'] = $username; return ''; }, null ); $change_password_form->addVInput('p_password', 'password', '密码', '', function ($password, &$vdata) { $vdata['password'] = $password; return ''; }, 'validatePassword' ); $change_password_form->handle = function(&$vdata) { $esc_username = DB::escape($vdata['username']); $password = hash_hmac('md5', $vdata['password'], getPasswordClientSalt()); $esc_password = DB::escape(getPasswordToStore($password, $vdata['username'])); DB::query("update user_info set password = '$esc_password' where username = '$esc_username'"); header('Content-Type: application/json'); die(json_encode(['status' => 'success', 'message' => '用户 ' . $vdata['username'] . ' 的密码已经被成功重置。'])); }; $change_password_form->submit_button_config['margin_class'] = 'mt-3'; $change_password_form->submit_button_config['text'] = '重置'; $change_password_form->setAjaxSubmit(<<runAtServer(); $change_usergroup_form = new UOJForm('change_usergroup'); $change_usergroup_form->addVInput('username', 'text', '用户名', '', function ($username, &$vdata) { if (!validateUsername($username)) { return '用户名不合法'; } if (!queryUser($username)) { return '用户不存在'; } $vdata['username'] = $username; return ''; }, null ); $change_usergroup_form->addVSelect('op_type', [ 'banneduser' => '设为封禁用户', 'normaluser' => '设为普通用户', 'superuser' => '设为超级用户', ], '操作类型', ''); $change_usergroup_form->handle = function($vdata) { $username = $vdata['username']; $usergroup = ''; switch ($_POST['op_type']) { case 'banneduser': DB::update("update user_info set usergroup = 'B', usertype = 'banned' where username = '{$username}'"); $usergroup = '被封禁的用户'; break; case 'normaluser': DB::update("update user_info set usergroup = 'U', usertype = 'student' where username = '{$username}'"); $usergroup = '普通用户'; break; case 'superuser': DB::update("update user_info set usergroup = 'S', usertype = 'student' where username = '{$username}'"); $usergroup = '超级用户'; break; } header('Content-Type: application/json'); die(json_encode(['status' => 'success', 'message' => '用户 ' . $username . ' 现在是 ' . $usergroup . '。'])); }; $change_usergroup_form->setAjaxSubmit(<<runAtServer(); } elseif ($cur_tab == 'submissions') { } elseif ($cur_tab == 'custom_test') { requireLib('hljs'); $submissions_pag = new Paginator([ 'col_names' => ['*'], 'table_name' => 'custom_test_submissions', 'cond' => '1', 'tail' => 'order by id desc', 'page_len' => 10 ]); $custom_test_deleter = new UOJForm('custom_test_deleter'); $custom_test_deleter->addInput('last', 'text', '删除末尾记录', '5', function ($x, &$vdata) { if (!validateUInt($x)) { return '不合法'; } $vdata['last'] = $x; return ''; }, null ); $custom_test_deleter->handle = function(&$vdata) { $all = DB::selectAll("select * from custom_test_submissions order by id asc limit {$vdata['last']}"); foreach ($all as $submission) { $content = json_decode($submission['content'], true); unlink(UOJContext::storagePath().$content['file_name']); } DB::delete("delete from custom_test_submissions order by id asc limit {$vdata['last']}"); }; $custom_test_deleter->submit_button_config['align'] = 'compressed'; $custom_test_deleter->runAtServer(); } elseif ($cur_tab == 'judger') { $judger_adder = new UOJForm('judger_adder'); $judger_adder->addInput('judger_adder_name', 'text', '评测机名称', '', function ($x, &$vdata) { if (!validateUsername($x)) { return '不合法'; } if (DB::selectCount("select count(*) from judger_info where judger_name='$x'")!=0) { return '不合法'; } $vdata['name'] = $x; return ''; }, null ); $judger_adder->handle = function(&$vdata) { $password = uojRandString(32); DB::insert("insert into judger_info (judger_name,password) values('{$vdata['name']}','{$password}')"); }; $judger_adder->submit_button_config['align'] = 'compressed'; $judger_adder->runAtServer(); $judger_deleter = new UOJForm('judger_deleter'); $judger_deleter->addInput('judger_deleter_name', 'text', '评测机名称', '', function ($x, &$vdata) { if (!validateUsername($x)) { return '不合法'; } if (DB::selectCount("select count(*) from judger_info where judger_name='$x'")!=1) { return '不合法'; } $vdata['name'] = $x; return ''; }, null ); $judger_deleter->handle = function(&$vdata) { DB::delete("delete from judger_info where judger_name='{$vdata['name']}'"); }; $judger_deleter->submit_button_config['align'] = 'compressed'; $judger_deleter->runAtServer(); } elseif ($cur_tab == 'image_hosting') { if (isset($_POST['submit-delete_image']) && $_POST['submit-delete_image'] == 'delete_image') { crsf_defend(); $image_id = $_POST['image_id']; if (!validateUInt($image_id)) { die('' . SCRIPT_REFRESH_AS_GET); } if (!($image = DB::selectFirst("SELECT * from users_images where id = $image_id"))) { die('' . SCRIPT_REFRESH_AS_GET); } unlink(UOJContext::storagePath().$result['path']); DB::delete("DELETE FROM users_images WHERE id = $image_id"); die('' . SCRIPT_REFRESH_AS_GET); } $change_user_image_total_size_limit_form = new UOJForm('change_user_image_total_size_limit'); $change_user_image_total_size_limit_form->submit_button_config['align'] = 'compressed'; $change_user_image_total_size_limit_form->addInput('change_user_image_total_size_limit_username', 'text', '用户名', '', function ($x, &$vdata) { if (!validateUsername($x)) { return '用户名不合法'; } if (!queryUser($x)) { return '用户不存在'; } $vdata['username'] = $x; return ''; }, null ); $change_user_image_total_size_limit_form->addInput('change_user_image_total_size_limit_limit', 'text', '存储限制(单位:Byte)', '104857600', function ($x, &$vdata) { if (!validateUInt($x, 10)) { return '限制不合法'; } if (intval($x) > 2147483648) { return '限制不能大于 2 GB'; } $vdata['limit'] = $x; return ''; }, null ); $change_user_image_total_size_limit_form->handle = function(&$vdata) { DB::update("UPDATE user_info SET images_size_limit = {$vdata['limit']} WHERE username = '{$vdata['username']}'"); }; $change_user_image_total_size_limit_form->runAtServer(); } ?>

$tab): ?>
添加/修改公告
printHTML(); ?>
添加倒计时
printHTML(); ?>
用户名 学校 用户类别 权限 注册时间 操作 EOD, function($row) { echo ''; echo '', '', $row['username'], '', ''; echo '', HTML::escape($row['school']), ''; echo ''; switch ($row['usergroup']) { case 'S': echo UOJLocale::get('user::super user'); break; case 'B': echo UOJLocale::get('user::banned user'); break; default: echo UOJLocale::get('user::normal user'); break; } echo ''; echo ''; foreach (explode(',', $row['usertype']) as $idx => $type) { if ($idx) { echo ', '; } echo UOJLocale::get('user::' . str_replace('_', ' ', $type)) ?: HTML::escape($type); } echo ''; echo '', $row['register_time'], ''; echo '', '编辑', ''; echo ''; }, [ 'page_len' => 20, 'div_classes' => ['table-responsive'], 'table_classes' => ['table', 'align-middle'], ], ); ?>
printHTML() ?>
注意事项
  • 用户名推荐格式为年级 + 姓名全拼,如 2022 级的张三同学可以设置为 2022zhangsan。对于外校学生,推荐格式为学校名称缩写 + 姓名拼音首字母,如山大附中的赵锦熙同学可以设置为 sdfzzjx)。
  • 请提醒用户及时修改初始密码,以免账号被盗导致教学资源流出。请勿设置过于简单的初始密码。
  • 我们推荐在创建账号时输入号主的电子邮件地址以便后期发生忘记密码等情况时进行验证。
  • 创建账号后可以在「修改个人信息」页面中的「特权」选项卡为用户分配权限。特别地,如果该用户是外校学生,那么您可能需要将其设置为「仅比赛参加者」以禁止其查看已参与比赛以外的题目。
printHTML() ?>
注意事项
  • 在为用户重置密码前请核对对方身份以免被骗。
  • 请勿设置过于简单的密码。
  • 请提醒用户在登录后及时修改初始密码。
printHTML() ?>
注意事项
  • 用户被封禁后将不能再次登录系统。
  • 将当前用户移除权限后将无法再次访问本页面。
  • 在修改用户类别前请仔细核对用户名以免产生不必要的麻烦。

测评失败的提交记录

'', 'table_config' => [ 'div_classes' => ['card', 'mb-3', 'table-responsive'], 'table_classes' => ['table', 'uoj-table', 'mb-0', 'text-center'] ] ], $myUser ); ?>
get() as $submission): ?> isEmpty()): ?>
ID 题目 ID 提交者 提交时间 测评时间
# #
pagination() ?>
删除末尾的 n 条记录
printHTML() ?>

评测机列表

评测机名称 密码 IP EOD, function($row) { echo << {$row['judger_name']} {$row['password']} {$row['ip']} EOD; }, [ 'page_len' => 10, 'div_classes' => ['card', 'mb-3', 'table-responsive'], 'table_classes' => ['table', 'uoj-table', 'mb-0'], ] ); ?>
添加评测机
printHTML(); ?>
删除评测机
printHTML(); ?>
上传者 预览 文件大小 上传时间 操作 EOD, function($row) { $user_link = getUserLink($row['uploader']); if ($row['size'] < 1024 * 512) { $size = strval(round($row['size'] * 1.0 / 1024, 1)) . ' KB'; } else { $size = strval(round($row['size'] * 1.0 / 1024 / 1024, 1)) . ' MB'; } $token = crsf_token(); echo << $user_link $size {$row['upload_time']}
EOD; }, [ 'page_len' => 20, 'div_classes' => ['card', 'mb-3', 'table-responsive'], 'table_classes' => ['table', 'uoj-table', 'mb-0'], ] ); ?>
修改用户图床空间上限
printHTML() ?>