feat(web): new user permissions (#10)

This commit is contained in:
Baoshuo Ren 2022-11-12 07:10:34 +08:00
parent d7446b9fa9
commit ef3f7b9e7f
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
52 changed files with 1398 additions and 857 deletions

View File

@ -692,6 +692,7 @@ CREATE TABLE `problems_solutions` (
`problem_id` int NOT NULL, `problem_id` int NOT NULL,
`blog_id` int NOT NULL, `blog_id` int NOT NULL,
PRIMARY KEY (`problem_id`, `blog_id`), PRIMARY KEY (`problem_id`, `blog_id`),
UNIQUE KEY `blog_id` (`blog_id`),
KEY `problem_id` (`problem_id`) KEY `problem_id` (`problem_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;

View File

@ -3,7 +3,7 @@ requireLib('bootstrap5');
requirePHPLib('form'); requirePHPLib('form');
Auth::check() || redirectToLogin(); Auth::check() || redirectToLogin();
isSuperUser(Auth::user()) || UOJResponse::page403(); UOJContest::userCanCreateContest(Auth::user()) || UOJResponse::page403();
$time_form = new UOJBs4Form('time'); $time_form = new UOJBs4Form('time');
$time_form->addVInput( $time_form->addVInput(

View File

@ -21,10 +21,12 @@ Auth::check() || redirectToLogin();
<a href="<?= HTML::blog_url(Auth::id(), '/') ?>" class="btn btn-secondary btn-sm"> <a href="<?= HTML::blog_url(Auth::id(), '/') ?>" class="btn btn-secondary btn-sm">
我的博客首页 我的博客首页
</a> </a>
<a href="<?= HTML::blog_url(Auth::id(), '/post/new/write') ?>" class="btn btn-primary btn-sm"> <?php if (UOJUser::checkPermission(Auth::user(), 'blogs.create')) : ?>
<i class="bi bi-pencil"></i> <a href="<?= HTML::blog_url(Auth::id(), '/post/new/write') ?>" class="btn btn-primary btn-sm">
写新博客 <i class="bi bi-pencil"></i>
</a> 写新博客
</a>
<?php endif ?>
</div> </div>
</div> </div>
<?php endif ?> <?php endif ?>
@ -35,16 +37,16 @@ Auth::check() || redirectToLogin();
echoLongTable( echoLongTable(
['id', 'poster', 'title', 'post_time', 'zan', 'is_hidden'], ['id', 'poster', 'title', 'post_time', 'zan', 'is_hidden'],
'blogs', 'blogs',
isSuperUser($myUser) ? "1" : "is_hidden = 0 or poster = '{$myUser['username']}'", '1',
'order by post_time desc', 'order by post_time desc',
<<<EOD <<<EOD
<tr> <tr>
<th>标题</th> <th>标题</th>
<th style="width:200px">发表者</th> <th style="width:200px">发表者</th>
<th style="width:200px">发表日期</th> <th style="width:200px">发表日期</th>
<th style="width:50px" class="text-center">评价</th> <th style="width:50px" class="text-center">评价</th>
</tr> </tr>
EOD, EOD,
function ($info) { function ($info) {
$blog = new UOJBlog($info); $blog = new UOJBlog($info);
@ -64,6 +66,9 @@ EOD,
'page_len' => 10, 'page_len' => 10,
'div_classes' => ['card', 'my-3', 'table-responsive'], 'div_classes' => ['card', 'my-3', 'table-responsive'],
'table_classes' => ['table', 'uoj-table', 'mb-0'], 'table_classes' => ['table', 'uoj-table', 'mb-0'],
'post_filter' => function ($info) {
return (new UOJBlog($info))->userCanView(Auth::user());
},
] ]
); );
?> ?>

View File

@ -53,7 +53,7 @@ if ($is_manager) {
isset($tabs_info[$cur_tab]) || UOJResponse::page404(); isset($tabs_info[$cur_tab]) || UOJResponse::page404();
if (isSuperUser($myUser) || isContestJudger($myUser)) { if (UOJContest::cur()->userCanStartFinalTest(Auth::user())) {
if (CONTEST_PENDING_FINAL_TEST <= $contest['cur_progress']) { if (CONTEST_PENDING_FINAL_TEST <= $contest['cur_progress']) {
$start_test_form = new UOJBs4Form('start_test'); $start_test_form = new UOJBs4Form('start_test');
$start_test_form->handle = function () { $start_test_form->handle = function () {
@ -113,7 +113,7 @@ if ($cur_tab == 'dashboard') {
$post_question = null; $post_question = null;
} }
} elseif ($cur_tab == 'backstage') { } elseif ($cur_tab == 'backstage') {
if (isSuperUser(Auth::user())) { if ($is_manager) {
$post_notice = new UOJBs4Form('post_notice'); $post_notice = new UOJBs4Form('post_notice');
$post_notice->addInput( $post_notice->addInput(
'title', 'title',
@ -158,7 +158,6 @@ if ($cur_tab == 'dashboard') {
$post_notice = null; $post_notice = null;
} }
if ($is_manager) { if ($is_manager) {
$reply_question = new UOJBs4Form('reply_question'); $reply_question = new UOJBs4Form('reply_question');
$reply_question->addHidden( $reply_question->addHidden(
@ -486,10 +485,8 @@ function echoSelfReviews() {
uojIncludeView('contest-reviews', ['contest' => $contest] + UOJContest::cur()->queryResult()); uojIncludeView('contest-reviews', ['contest' => $contest] + UOJContest::cur()->queryResult());
} }
$page_header = HTML::stripTags($contest['name']) . ' - ';
?> ?>
<?php echoUOJPageHeader(HTML::stripTags($contest['name']) . ' - ' . $tabs_info[$cur_tab]['name'] . ' - ' . UOJLocale::get('contests::contest')) ?> <?php echoUOJPageHeader($tabs_info[$cur_tab]['name'] . ' - ' . UOJContest::info('name') . ' - ' . UOJLocale::get('contests::contest')) ?>
<div class="text-center d-md-none mb-3"> <div class="text-center d-md-none mb-3">
<h1><?= $contest['name'] ?></h1> <h1><?= $contest['name'] ?></h1>
@ -600,7 +597,7 @@ $page_header = HTML::stripTags($contest['name']) . ' - ';
</div> </div>
</div> </div>
<div class="card-footer bg-transparent"> <div class="card-footer bg-transparent">
比赛评价:<?= ClickZans::getBlock('C', $contest['id'], $contest['zan']) ?> 比赛评价:<?= UOJContest::cur()->getZanBlock() ?>
</div> </div>
</div> </div>
@ -618,7 +615,7 @@ $page_header = HTML::stripTags($contest['name']) . ' - ';
<a href="/contest/<?= $contest['id'] ?>/registrants" class="btn btn-secondary d-block mt-2"> <a href="/contest/<?= $contest['id'] ?>/registrants" class="btn btn-secondary d-block mt-2">
<?= UOJLocale::get('contests::contest registrants') ?> <?= UOJLocale::get('contests::contest registrants') ?>
</a> </a>
<?php if (isSuperUser($myUser)) : ?> <?php if ($is_manager) : ?>
<a href="/contest/<?= $contest['id'] ?>/manage" class="btn btn-primary d-block mt-2"> <a href="/contest/<?= $contest['id'] ?>/manage" class="btn btn-primary d-block mt-2">
管理 管理
</a> </a>

View File

@ -4,7 +4,7 @@ requirePHPLib('form');
Auth::check() || redirectToLogin(); Auth::check() || redirectToLogin();
UOJContest::init(UOJRequest::get('id')) || UOJResponse::page404(); UOJContest::init(UOJRequest::get('id')) || UOJResponse::page404();
isSuperUser(Auth::user()) || UOJResponse::page403(); UOJContest::cur()->userCanManage(Auth::user()) || UOJResponse::page403();
$contest = UOJContest::info(); $contest = UOJContest::info();
if (isset($_GET['tab'])) { if (isset($_GET['tab'])) {

View File

@ -52,7 +52,7 @@ function echoContest($info) {
echo '<td>', '<a class="text-decoration-none" href="' . HTML::timeanddate_url($contest->info['start_time'], ['duration' => $contest->info['last_min']]) . '">' . $contest->info['start_time_str'] . '</a>', '</td>'; echo '<td>', '<a class="text-decoration-none" href="' . HTML::timeanddate_url($contest->info['start_time'], ['duration' => $contest->info['last_min']]) . '">' . $contest->info['start_time_str'] . '</a>', '</td>';
echo '<td>', UOJLocale::get('hours', $last_hour), '</td>'; echo '<td>', UOJLocale::get('hours', $last_hour), '</td>';
echo '<td>', '<a class="text-decoration-none" href="/contest/' . $contest->info['id'] . '/registrants">', '<i class="bi bi-person-fill"></i>', ' &times;' . $contest->info['player_num'] . '</a>', '</td>'; echo '<td>', '<a class="text-decoration-none" href="/contest/' . $contest->info['id'] . '/registrants">', '<i class="bi bi-person-fill"></i>', ' &times;' . $contest->info['player_num'] . '</a>', '</td>';
echo '<td>', '<div class="text-left">' . ClickZans::getBlock('C', $contest->info['id'], $contest->info['zan']) . '</div>', '</td>'; echo HTML::tag('td', [], $contest->getZanBlock());
echo '</tr>'; echo '</tr>';
} }
?> ?>
@ -64,7 +64,7 @@ function echoContest($info) {
<?= UOJLocale::get('contests') ?> <?= UOJLocale::get('contests') ?>
</h1> </h1>
<?php if (isSuperUser($myUser)) : ?> <?php if (UOJContest::userCanCreateContest(Auth::user())) : ?>
<div class="text-end"> <div class="text-end">
<a href="/contest/new" class="btn btn-primary"><?= UOJLocale::get('contests::add new contest') ?></a> <a href="/contest/new" class="btn btn-primary"><?= UOJLocale::get('contests::add new contest') ?></a>
</div> </div>
@ -92,6 +92,12 @@ $table_config = [
'table_classes' => ['table', 'uoj-table', 'mb-0', 'text-center'], 'table_classes' => ['table', 'uoj-table', 'mb-0', 'text-center'],
]; ];
if (!UOJUser::checkPermission(Auth::user(), 'contests.view')) {
$table_config['post_filter'] = function ($info) {
return (new UOJContest($info))->userCanView(Auth::user());
};
}
echoLongTable( echoLongTable(
['*'], ['*'],
'contests', 'contests',

View File

@ -7,7 +7,7 @@
if (!validateUsername($username)) { if (!validateUsername($username)) {
return '用户名不合法'; return '用户名不合法';
} }
$vdata['user'] = queryUser($username); $vdata['user'] = UOJUser::query($username);
if (!$vdata['user']) { if (!$vdata['user']) {
return '该用户不存在'; return '该用户不存在';
} }

View File

@ -4,11 +4,9 @@ requirePHPLib('form');
requirePHPLib('judger'); requirePHPLib('judger');
requirePHPLib('data'); requirePHPLib('data');
if (!Auth::check()) { Auth::check() || redirectToLogin();
redirectToLogin();
}
if (isSuperUser($myUser)) { if (UOJGroup::userCanCreateGroup(Auth::user())) {
$new_group_form = new UOJBs4Form('new_group'); $new_group_form = new UOJBs4Form('new_group');
$new_group_form->handle = function () { $new_group_form->handle = function () {
DB::query("insert into `groups` (title, is_hidden) values ('新小组', 1)"); DB::query("insert into `groups` (title, is_hidden) values ('新小组', 1)");
@ -33,7 +31,7 @@ if (isSuperUser($myUser)) {
</h1> </h1>
<?php if (isset($new_group_form)) : ?> <?php if (isset($new_group_form)) : ?>
<div class="text-end mb-2"> <div class="text-end">
<?php $new_group_form->printHTML(); ?> <?php $new_group_form->printHTML(); ?>
</div> </div>
<?php endif ?> <?php endif ?>
@ -45,23 +43,17 @@ if (isSuperUser($myUser)) {
$groups_caption = UOJLocale::get('groups'); $groups_caption = UOJLocale::get('groups');
$users_caption = UOJLocale::get('users count'); $users_caption = UOJLocale::get('users count');
$header = <<<EOD $header = <<<EOD
<tr> <tr>
<th class="text-center" style="width:5em;">ID</th> <th class="text-center" style="width:5em;">ID</th>
<th>{$groups_caption}</th> <th>{$groups_caption}</th>
<th class="text-center" style="width:8em;">{$users_caption}</th> <th class="text-center" style="width:8em;">{$users_caption}</th>
</tr> </tr>
EOD; EOD;
if (isSuperUser(Auth::user())) {
$cond = "1";
} else {
$cond = ["is_hidden" => false];
}
echoLongTable( echoLongTable(
['id', 'title', 'is_hidden'], ['*'],
"`groups`", "`groups`",
$cond, '1',
'order by id asc', 'order by id asc',
$header, $header,
function ($group) { function ($group) {
@ -93,6 +85,9 @@ EOD;
'div_classes' => ['card', 'my-3'], 'div_classes' => ['card', 'my-3'],
'table_classes' => ['table', 'uoj-table', 'mb-0'], 'table_classes' => ['table', 'uoj-table', 'mb-0'],
'head_pagination' => true, 'head_pagination' => true,
'post_filter' => function ($info) {
return (new UOJGroup($info))->userCanView(Auth::user());
}
] ]
); );
?> ?>

View File

@ -6,6 +6,7 @@ requirePHPLib('form');
requireLib('bootstrap5'); requireLib('bootstrap5');
Auth::check() || redirectToLogin(); Auth::check() || redirectToLogin();
UOJUser::checkPermission(Auth::user(), 'users.upload_image') || UOJResponse::page403();
$extra = UOJUser::getExtra($user); $extra = UOJUser::getExtra($user);
$limit = $extra['image_hosting']['total_size_limit']; $limit = $extra['image_hosting']['total_size_limit'];
@ -56,18 +57,18 @@ if ($_POST['image_upload_file_submit'] == 'submit') {
throwError('not_a_image'); throwError('not_a_image');
} }
list($width, $height, $type) = $size; list($width, $height, $type) = $size;
$hash = hash_file("sha256", $_FILES['image_upload_file']['tmp_name']) . Auth::id(); $hash = hash_file("sha256", $_FILES['image_upload_file']['tmp_name']) . Auth::id();
$scale = ceil($height / 600.0); $scale = ceil($height / 600.0);
$watermark_text = UOJConfig::$data['profile']['oj-name-short']; $watermark_text = UOJConfig::$data['profile']['oj-name-short'];
if (isSuperUser($myUser) && $_POST['watermark'] == 'no_watermark') { if (isSuperUser(Auth::user()) && $_POST['watermark'] == 'no_watermark') {
$watermark_text = ""; $watermark_text = "";
$hash .= "__no_watermark"; $hash .= "__no_watermark";
} elseif ($_POST['watermark'] == 'site_shortname_and_username') { } elseif ($_POST['watermark'] == 'site_shortname_and_username') {
$watermark_text .= ' @' . Auth::id(); $watermark_text .= ' @' . Auth::id();
$hash .= "__id"; $hash .= "__id";
} }
$existing_image = DB::selectFirst("SELECT * FROM users_images WHERE `hash` = '$hash'"); $existing_image = DB::selectFirst("SELECT * FROM users_images WHERE `hash` = '$hash'");
@ -96,7 +97,19 @@ if ($_POST['image_upload_file_submit'] == 'submit') {
throwError('unknown error'); throwError('unknown error');
} }
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')"); DB::insert([
"insert into users_images",
DB::bracketed_fields(["path", "uploader", "width", "height", "upload_time", "size", "hash"]),
"values", DB::tuple([
$filename,
Auth::id(),
$width,
$height,
DB::now(),
$_FILES["image_upload_file"]["size"],
$hash,
]),
]);
dieWithJsonData(['status' => 'success', 'path' => $filename]); dieWithJsonData(['status' => 'success', 'path' => $filename]);
} elseif ($_POST['image_delete_submit'] == 'submit') { } elseif ($_POST['image_delete_submit'] == 'submit') {

View File

@ -6,17 +6,17 @@ requirePHPLib('judger');
requirePHPLib('data'); requirePHPLib('data');
Auth::check() || redirectToLogin(); Auth::check() || redirectToLogin();
UOJUser::checkPermission(Auth::user(), 'lists.view') || UOJResponse::page403();
if (isSuperUser($myUser)) { if (UOJList::userCanCreateList(Auth::user())) {
$new_list_form = new UOJBs4Form('new_list'); $new_list_form = new UOJBs4Form('new_list');
$new_list_form->handle = function () { $new_list_form->handle = function () {
DB::query("insert into lists (title, is_hidden) values ('未命名题单', 1)"); DB::insert("insert into lists (title, is_hidden) values ('未命名题单', 1)");
}; };
$new_list_form->submit_button_config['align'] = 'right'; $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['class_str'] = 'btn btn-primary';
$new_list_form->submit_button_config['text'] = UOJLocale::get('problems::add new list'); $new_list_form->submit_button_config['text'] = UOJLocale::get('problems::add new list');
$new_list_form->submit_button_config['smart_confirm'] = ''; $new_list_form->submit_button_config['smart_confirm'] = '';
$new_list_form->runAtServer(); $new_list_form->runAtServer();
} }
@ -92,14 +92,14 @@ $pag = new Paginator([
<div class="row"> <div class="row">
<!-- left col --> <!-- left col -->
<div class="col-lg-9"> <div class="col-lg-9">
<!-- title container --> <!-- title container -->
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<h1> <h1>
<?= UOJLocale::get('problems lists') ?> <?= UOJLocale::get('problems lists') ?>
</h1> </h1>
<?php if (isset($new_list_form)) : ?> <?php if (isset($new_list_form)) : ?>
<div class="text-end mb-2"> <div class="text-end">
<?php $new_list_form->printHTML(); ?> <?php $new_list_form->printHTML(); ?>
</div> </div>
<?php endif ?> <?php endif ?>

View File

@ -313,7 +313,7 @@ if (UOJContest::cur()) {
</div> </div>
</div> </div>
<div class="card-footer bg-transparent"> <div class="card-footer bg-transparent">
比赛评价:<?= ClickZans::getBlock('C', UOJContest::info('id'), UOJContest::info('zan')) ?> 比赛评价:<?= UOJContest::cur()->getZanBlock() ?>
</div> </div>
</div> </div>
<?php if (UOJContest::cur()->progress() <= CONTEST_IN_PROGRESS) : ?> <?php if (UOJContest::cur()->progress() <= CONTEST_IN_PROGRESS) : ?>

View File

@ -127,7 +127,7 @@ if ($_POST['problem_settings_file_submit'] == 'submit') {
$info_form = new UOJBs4Form('info'); $info_form = new UOJBs4Form('info');
$http_host = HTML::escape(UOJContext::httpHost()); $http_host = HTML::escape(UOJContext::httpHost());
$attachment_url = HTML::url("/download.php?type=attachment&id={$problem['id']}"); $attachment_url = UOJProblem::cur()->getAttachmentUri();
$info_form->appendHTML( $info_form->appendHTML(
<<<EOD <<<EOD
<div class="form-group row"> <div class="form-group row">
@ -140,7 +140,7 @@ $info_form->appendHTML(
</div> </div>
EOD EOD
); );
$download_url = HTML::url("/download.php?type=problem&id={$problem['id']}"); $download_url = UOJProblem::cur()->getMainDataUri();
$info_form->appendHTML( $info_form->appendHTML(
<<<EOD <<<EOD
<div class="form-group row"> <div class="form-group row">
@ -194,7 +194,7 @@ $esc_extra_config
</div> </div>
EOD EOD
); );
if (isSuperUser($myUser)) { if (isSuperUser(Auth::user())) {
$info_form->addVInput( $info_form->addVInput(
'submission_requirement', 'submission_requirement',
'text', 'text',

View File

@ -31,7 +31,7 @@ $managers_form = newAddDelCmdForm(
$managers_form->runAtServer(); $managers_form->runAtServer();
if (isSuperUser($myUser)) { if (isSuperUser(Auth::user())) {
$update_uploader_form = new UOJBs4Form('update_uploader'); $update_uploader_form = new UOJBs4Form('update_uploader');
$update_uploader_form->addInput( $update_uploader_form->addInput(
'new_uploader_username', 'new_uploader_username',

View File

@ -5,8 +5,9 @@ requirePHPLib('judger');
requirePHPLib('data'); requirePHPLib('data');
Auth::check() || redirectToLogin(); Auth::check() || redirectToLogin();
UOJUser::checkPermission(Auth::user(), 'problems.view') || UOJResponse::page403();
if (isSuperUser($myUser) || isProblemManager($myUser) || isProblemUploader($myUser)) { if (UOJProblem::userCanCreateProblem(Auth::user())) {
$default_statement = <<<'EOD' $default_statement = <<<'EOD'
<!-- 题目中如有图片,请点击页面顶部的「应用」菜单,打开「图床」,上传至 S2OJ 图床中。 --> <!-- 题目中如有图片,请点击页面顶部的「应用」菜单,打开「图床」,上传至 S2OJ 图床中。 -->
@ -240,12 +241,11 @@ $pag = new Paginator([
<!-- title --> <!-- title -->
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<h1> <h1>
<?= UOJLocale::get('problems') ?> <?= UOJLocale::get('problems') ?>
</h1> </h1>
<?php if (isSuperUser($myUser) || isProblemManager($myUser) || isProblemUploader($myUser)) : ?> <?php if (isset($new_problem_form)) : ?>
<div class="text-end"> <div class="text-end">
<?php $new_problem_form->printHTML(); ?> <?php $new_problem_form->printHTML(); ?>
</div> </div>
@ -360,7 +360,7 @@ $pag = new Paginator([
</label> </label>
</div> </div>
<?php endif ?> <?php endif ?>
<?php if (isProblemManager(Auth::user())) : ?> <?php if (UOJProblem::userCanManageSomeProblem(Auth::user())) : ?>
<div class="form-check d-inline-block ms-2"> <div class="form-check d-inline-block ms-2">
<input type="checkbox" name="is_hidden" <?= isset($_GET['is_hidden']) ? 'checked="checked"' : '' ?> class="form-check-input" id="input-is_hidden"> <input type="checkbox" name="is_hidden" <?= isset($_GET['is_hidden']) ? 'checked="checked"' : '' ?> class="form-check-input" id="input-is_hidden">
<label class="form-check-label" for="input-is_hidden"> <label class="form-check-label" for="input-is_hidden">

View File

@ -7,7 +7,7 @@ requirePHPLib('judger');
Auth::check() || redirectToLogin(); Auth::check() || redirectToLogin();
UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404(); UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404();
UOJProblem::cur()->userCanView(Auth::user()) || UOJResponse::page403(); UOJProblem::cur()->userCanView(Auth::user(), ['ensure' => true]);
if (!UOJProblem::cur()->userCanManage(Auth::user())) { if (!UOJProblem::cur()->userCanManage(Auth::user())) {
UOJProblem::cur()->userPermissionCodeCheck(Auth::user(), UOJProblem::cur()->getExtraConfig('view_solution_type')) || UOJResponse::page403(); UOJProblem::cur()->userPermissionCodeCheck(Auth::user(), UOJProblem::cur()->getExtraConfig('view_solution_type')) || UOJResponse::page403();
@ -81,8 +81,8 @@ if (UOJProblem::cur()->userCanManage(Auth::user()) || UOJProblem::cur()->userPer
} }
} }
if (querySolution(UOJProblem::info('id'), $blog_id)) { if ($problem_id = $blog->getSolutionProblemId()) {
return '该题解已提交'; return "该博客已经是题目 #$problem_id 的题解";
} }
return ''; return '';
@ -200,15 +200,12 @@ $pag = new Paginator($pag_config);
</ul> </ul>
</div> </div>
<!-- Pagination -->
<?= $pag->pagination() ?> <?= $pag->pagination() ?>
</div> </div>
<!-- End left col --> <!-- end left col -->
<!-- Right col --> <!-- right col -->
<aside class="col-lg-3 mt-3 mt-lg-0"> <aside class="col-lg-3 mt-3 mt-lg-0">
<div class="card card-default mb-2"> <div class="card card-default mb-2">
<ul class="nav nav-pills nav-fill flex-column" role="tablist"> <ul class="nav nav-pills nav-fill flex-column" role="tablist">
<li class="nav-item text-start"> <li class="nav-item text-start">

View File

@ -4,9 +4,6 @@ requireLib('morris');
Auth::check() || redirectToLogin(); Auth::check() || redirectToLogin();
UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404(); UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404();
$problem = UOJProblem::cur()->info;
if (UOJRequest::get('contest_id')) { if (UOJRequest::get('contest_id')) {
UOJContest::init(UOJRequest::get('contest_id')) || UOJResponse::page404(); UOJContest::init(UOJRequest::get('contest_id')) || UOJResponse::page404();
UOJProblem::upgradeToContestProblem() || UOJResponse::page404(); UOJProblem::upgradeToContestProblem() || UOJResponse::page404();
@ -183,7 +180,7 @@ $submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']
hoverCallback: function(index, options, content, row) { hoverCallback: function(index, options, content, row) {
var scr = row.score; var scr = row.score;
return '<div class="morris-hover-row-label">' + 'score: ' + scr + '</div>' + return '<div class="morris-hover-row-label">' + 'score: ' + scr + '</div>' +
'<div class="morris-hover-point">' + '<a href="/submissions?problem_id=' + <?= $problem['id'] ?> + '&amp;min_score=' + scr + '&amp;max_score=' + scr + '">' + 'number: ' + row.count + '</a>' + '</div>'; '<div class="morris-hover-point">' + '<a href="/submissions?problem_id=' + <?= UOJProblem::info('id') ?> + '&amp;min_score=' + scr + '&amp;max_score=' + scr + '">' + 'number: ' + row.count + '</a>' + '</div>';
}, },
resize: true resize: true
}); });
@ -212,7 +209,7 @@ $submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']
hoverCallback: function(index, options, content, row) { hoverCallback: function(index, options, content, row) {
var scr = row.score / 100; var scr = row.score / 100;
return '<div class="morris-hover-row-label">' + 'score: &le;' + scr + '</div>' + return '<div class="morris-hover-row-label">' + 'score: &le;' + scr + '</div>' +
'<div class="morris-hover-point">' + '<a href="/submissions?problem_id=' + <?= $problem['id'] ?> + '&amp;max_score=' + scr + '">' + 'number: ' + row.count + '</a>' + '</div>'; '<div class="morris-hover-point">' + '<a href="/submissions?problem_id=' + <?= UOJProblem::info('id') ?> + '&amp;max_score=' + scr + '">' + 'number: ' + row.count + '</a>' + '</div>';
}, },
resize: true resize: true
}); });
@ -241,7 +238,7 @@ $submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']
hoverCallback: function(index, options, content, row) { hoverCallback: function(index, options, content, row) {
var scr = row.score / 100; var scr = row.score / 100;
return '<div class="morris-hover-row-label">' + 'score: &ge;' + scr + '</div>' + return '<div class="morris-hover-row-label">' + 'score: &ge;' + scr + '</div>' +
'<div class="morris-hover-point">' + '<a href="/submissions?problem_id=' + <?= $problem['id'] ?> + '&amp;min_score=' + scr + '">' + 'number: ' + row.count + '</a>' + '</div>'; '<div class="morris-hover-point">' + '<a href="/submissions?problem_id=' + <?= UOJProblem::info('id') ?> + '&amp;min_score=' + scr + '">' + 'number: ' + row.count + '</a>' + '</div>';
}, },
resize: true resize: true
}); });
@ -252,20 +249,17 @@ $submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']
<!-- end left col --> <!-- end left col -->
</div> </div>
<!-- Right col --> <!-- right col -->
<aside class="col-lg-3 mt-3 mt-lg-0"> <aside class="col-lg-3 mt-3 mt-lg-0">
<?php if (UOJContest::cur()) : ?>
<?php if ($contest) : ?>
<!-- Contest card --> <!-- Contest card -->
<div class="card card-default mb-2"> <div class="card card-default mb-2">
<div class="card-body"> <div class="card-body">
<h3 class="h4 card-title text-center"> <h3 class="h4 card-title text-center">
<a class="text-decoration-none text-body" href="/contest/<?= $contest['id'] ?>"> <?= UOJContest::cur()->getLink(['class' => 'text-body']) ?>
<?= $contest['name'] ?>
</a>
</h3> </h3>
<div class="card-text text-center text-muted"> <div class="card-text text-center text-muted">
<?php if ($contest['cur_progress'] <= CONTEST_IN_PROGRESS) : ?> <?php if (UOJContest::cur()->progress() <= CONTEST_IN_PROGRESS) : ?>
<span id="contest-countdown"></span> <span id="contest-countdown"></span>
<?php else : ?> <?php else : ?>
<?= UOJLocale::get('contests::contest ended') ?> <?= UOJLocale::get('contests::contest ended') ?>
@ -273,12 +267,12 @@ $submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']
</div> </div>
</div> </div>
<div class="card-footer bg-transparent"> <div class="card-footer bg-transparent">
比赛评价:<?= ClickZans::getBlock('C', $contest['id'], $contest['zan']) ?> 比赛评价:<?= UOJContest::cur()->getZanBlock() ?>
</div> </div>
</div> </div>
<?php if ($contest['cur_progress'] <= CONTEST_IN_PROGRESS) : ?> <?php if (UOJContest::cur()->progress() <= CONTEST_IN_PROGRESS) : ?>
<script type="text/javascript"> <script type="text/javascript">
$('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJTime::$time_now->getTimestamp() ?>, function() {}, '1.75rem', false); $('#contest-countdown').countdown(<?= UOJContest::info('end_time')->getTimestamp() - UOJTime::$time_now->getTimestamp() ?>, function() {}, '1.75rem', false);
</script> </script>
<?php endif ?> <?php endif ?>
<?php endif ?> <?php endif ?>
@ -286,14 +280,14 @@ $submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']
<div class="card card-default mb-2"> <div class="card card-default mb-2">
<ul class="nav nav-pills nav-fill flex-column" role="tablist"> <ul class="nav nav-pills nav-fill flex-column" role="tablist">
<li class="nav-item text-start"> <li class="nav-item text-start">
<a class="nav-link" role="tab" <?php if ($contest) : ?> href="/contest/<?= $contest['id'] ?>/problem/<?= $problem['id'] ?>" <?php else : ?> href="/problem/<?= $problem['id'] ?>" <?php endif ?>> <a class="nav-link" role="tab" <?php if (UOJContest::cur()) : ?> href="/contest/<?= UOJContest::info('id') ?>/problem/<?= UOJProblem::info('id') ?>" <?php else : ?> href="/problem/<?= UOJProblem::info('id') ?>" <?php endif ?>>
<i class="bi bi-journal-text"></i> <i class="bi bi-journal-text"></i>
<?= UOJLocale::get('problems::statement') ?> <?= UOJLocale::get('problems::statement') ?>
</a> </a>
</li> </li>
<?php if (!$contest || $contest['cur_progress'] >= CONTEST_FINISHED) : ?> <?php if (!UOJContest::cur() || UOJContest::cur()->progress() >= CONTEST_FINISHED) : ?>
<li class="nav-item text-start"> <li class="nav-item text-start">
<a href="/problem/<?= $problem['id'] ?>/solutions" class="nav-link" role="tab"> <a href="/problem/<?= UOJProblem::info('id') ?>/solutions" class="nav-link" role="tab">
<i class="bi bi-journal-bookmark"></i> <i class="bi bi-journal-bookmark"></i>
<?= UOJLocale::get('problems::solutions') ?> <?= UOJLocale::get('problems::solutions') ?>
</a> </a>
@ -305,9 +299,9 @@ $submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']
<?= UOJLocale::get('problems::statistics') ?> <?= UOJLocale::get('problems::statistics') ?>
</a> </a>
</li> </li>
<?php if (hasProblemPermission($myUser, $problem)) : ?> <?php if (UOJProblem::cur()->userCanManage(Auth::user())) : ?>
<li class="nav-item text-start"> <li class="nav-item text-start">
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/statement" role="tab"> <a class="nav-link" href="/problem/<?= UOJProblem::info('id') ?>/manage/statement" role="tab">
<i class="bi bi-sliders"></i> <i class="bi bi-sliders"></i>
<?= UOJLocale::get('problems::manage') ?> <?= UOJLocale::get('problems::manage') ?>
</a> </a>

View File

@ -2,6 +2,7 @@
requireLib('bootstrap5'); requireLib('bootstrap5');
Auth::check() || redirectToLogin(); Auth::check() || redirectToLogin();
UOJUser::checkPermission(Auth::user(), 'users.view') || UOJResponse::page403();
$config = [ $config = [
'page_len' => 50, 'page_len' => 50,
@ -34,7 +35,6 @@ if (isset($_GET['type']) && $_GET['type'] == 'accepted') {
<?php uojIncludeView('sidebar') ?> <?php uojIncludeView('sidebar') ?>
</aside> </aside>
<!-- end right col --> <!-- end right col -->
</div> </div>
<?php echoUOJPageFooter() ?> <?php echoUOJPageFooter() ?>

View File

@ -40,7 +40,7 @@ if (isset($_POST['register'])) {
die(); die();
} elseif (isset($_POST['check_username'])) { } elseif (isset($_POST['check_username'])) {
$username = $_POST['username']; $username = $_POST['username'];
if (validateUsername($username) && !queryUser($username)) { if (validateUsername($username) && !UOJUser::query($username)) {
die('{"ok": true}'); die('{"ok": true}');
} else { } else {
die('{"ok": false}'); die('{"ok": false}');

View File

@ -15,7 +15,7 @@
} }
$newPW = $_POST['newPW']; $newPW = $_POST['newPW'];
$user = queryUser($username); $user = UOJUser::query($username);
if ($user == null) { if ($user == null) {
return '不明错误'; return '不明错误';
} }

View File

@ -3,6 +3,8 @@ requireLib('bootstrap5');
requireLib('calendar_heatmap'); requireLib('calendar_heatmap');
Auth::check() || redirectToLogin(); Auth::check() || redirectToLogin();
UOJUserBlog::userIsOwner(Auth::user()) || UOJUser::checkPermission(Auth::user(), 'blogs.view') || UOJResponse::page403();
Auth::id() == $user['username'] || UOJUser::checkPermission(Auth::user(), 'users.view') || UOJResponse::page403();
?> ?>
<?php echoUOJPageHeader('关于我') ?> <?php echoUOJPageHeader('关于我') ?>

View File

@ -5,6 +5,7 @@ requireLib('hljs');
requirePHPLib('form'); requirePHPLib('form');
Auth::check() || redirectToLogin(); Auth::check() || redirectToLogin();
UOJUserBlog::userIsOwner(Auth::user()) || UOJUser::checkPermission(Auth::user(), 'blogs.view') || UOJResponse::page403();
$blogs_conds = [ $blogs_conds = [
"poster" => UOJUserBlog::id(), "poster" => UOJUserBlog::id(),
@ -144,7 +145,7 @@ $all_tags = DB::selectAll([
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<?php if (UOJUserBlog::userCanManage(Auth::user())) : ?> <?php if (UOJUserBlog::userCanManage(Auth::user()) && UOJUser::checkPermission(Auth::user(), 'blogs.create')) : ?>
<div class="btn-group d-flex"> <div class="btn-group d-flex">
<a href="<?= HTML::blog_url(UOJUserBlog::id(), '/post/new/write') ?>" class="btn btn-primary"> <a href="<?= HTML::blog_url(UOJUserBlog::id(), '/post/new/write') ?>" class="btn btn-primary">
<i class="bi bi-pencil-square"></i> <i class="bi bi-pencil-square"></i>

View File

@ -4,6 +4,7 @@ requireLib('mathjax');
requireLib('hljs'); requireLib('hljs');
requirePHPLib('form'); requirePHPLib('form');
Auth::check() || redirectToLogin();
UOJBlog::init(UOJRequest::get('id')) || UOJResponse::page404(); UOJBlog::init(UOJRequest::get('id')) || UOJResponse::page404();
UOJBlog::cur()->belongsToUserBlog() || UOJResponse::page404(); UOJBlog::cur()->belongsToUserBlog() || UOJResponse::page404();
UOJBlog::cur()->userCanView(Auth::user()) || UOJResponse::page403(); UOJBlog::cur()->userCanView(Auth::user()) || UOJResponse::page403();
@ -18,21 +19,6 @@ function getCommentContentToDisplay($comment) {
} }
} }
if (!Auth::check()) {
redirectToLogin();
}
$solutions = DB::selectAll("select * from problems_solutions where blog_id = {$blog['id']}");
if ($solutions) {
foreach ($solutions as $solution) {
$problem = queryProblemBrief($solution['problem_id']);
if (!hasProblemPermission($myUser, $problem) && isRegisteredRunningContestProblem($myUser, $problem)) {
become403Page();
}
}
}
$comment_form = new UOJBs4Form('comment'); $comment_form = new UOJBs4Form('comment');
$comment_form->addVTextArea( $comment_form->addVTextArea(
'comment', 'comment',

View File

@ -2,12 +2,9 @@
requireLib('bootstrap5'); requireLib('bootstrap5');
requirePHPLib('form'); requirePHPLib('form');
Auth::check() || redirectToLogin();
UOJUserBlog::userCanManage(Auth::user()) || UOJResponse::page403(); UOJUserBlog::userCanManage(Auth::user()) || UOJResponse::page403();
if (!Auth::check()) {
redirectToLogin();
}
if (isset($_GET['id'])) { if (isset($_GET['id'])) {
UOJBlog::init(UOJRequest::get('id')) || UOJResponse::page404(); UOJBlog::init(UOJRequest::get('id')) || UOJResponse::page404();
UOJBlog::cur()->belongsToUserBlog() || UOJResponse::page404(); UOJBlog::cur()->belongsToUserBlog() || UOJResponse::page404();
@ -15,6 +12,9 @@ if (isset($_GET['id'])) {
$blog = UOJBlog::info(); $blog = UOJBlog::info();
$blog['content'] = UOJBlog::cur()->queryContent()['content']; $blog['content'] = UOJBlog::cur()->queryContent()['content'];
$blog['content_md'] = UOJBlog::cur()->queryContent()['content_md']; $blog['content_md'] = UOJBlog::cur()->queryContent()['content_md'];
} else {
UOJUser::checkPermission(Auth::user(), 'blogs.create') || UOJResponse::page403();
isSuperUser(Auth::user()) || UOJUserBlog::userIsOwner(Auth::user()) || UOJResponse::page403();
} }
$blog_editor = new UOJBlogEditor(); $blog_editor = new UOJBlogEditor();

View File

@ -4,6 +4,7 @@ requireLib('hljs');
requireLib('mathjax'); requireLib('mathjax');
Auth::check() || redirectToLogin(); Auth::check() || redirectToLogin();
UOJUserBlog::userIsOwner(Auth::user()) || UOJUser::checkPermission(Auth::user(), 'blogs.view') || UOJResponse::page403();
$blogs_pag = new Paginator([ $blogs_pag = new Paginator([
'col_names' => ['*'], 'col_names' => ['*'],
@ -33,7 +34,7 @@ $all_tags = DB::selectAll("select distinct tag from blogs_tags where blog_id in
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
<img class="media-object img-thumbnail center-block" alt="<?= UOJUserBlog::id() ?> Avatar" src="<?= HTML::avatar_addr(UOJUserBlog::user(), 512) ?>" /> <img class="media-object img-thumbnail center-block" alt="<?= UOJUserBlog::id() ?> Avatar" src="<?= HTML::avatar_addr(UOJUserBlog::user(), 512) ?>" />
<?php if (UOJUserBlog::userCanManage(Auth::user())) : ?> <?php if (UOJUserBlog::userCanManage(Auth::user()) && UOJUser::checkPermission(Auth::user(), 'blogs.create')) : ?>
<div class="btn-group d-flex mt-3"> <div class="btn-group d-flex mt-3">
<a href="<?= HTML::blog_url(UOJUserBlog::id(), '/post/new/write') ?>" class="btn btn-primary"> <a href="<?= HTML::blog_url(UOJUserBlog::id(), '/post/new/write') ?>" class="btn btn-primary">
<i class="bi bi-pencil-square"></i> <i class="bi bi-pencil-square"></i>

View File

@ -4,6 +4,7 @@ requireLib('mathjax');
requirePHPLib('form'); requirePHPLib('form');
Auth::check() || redirectToLogin(); Auth::check() || redirectToLogin();
UOJUserBlog::userIsOwner(Auth::user()) || UOJUser::checkPermission(Auth::user(), 'blogs.view') || UOJResponse::page403();
?> ?>
<?php echoUOJPageHeader(UOJLocale::get('contests::contest self reviews')) ?> <?php echoUOJPageHeader(UOJLocale::get('contests::contest self reviews')) ?>

View File

@ -6,7 +6,7 @@ UOJBlog::init(UOJRequest::get('id')) || UOJResponse::page404();
UOJBlog::cur()->belongsToUserBlog() || UOJResponse::page404(); UOJBlog::cur()->belongsToUserBlog() || UOJResponse::page404();
UOJBlog::cur()->userCanView(Auth::user()) || UOJResponse::page403(); UOJBlog::cur()->userCanView(Auth::user()) || UOJResponse::page403();
UOJBlog::cur()->isTypeS() || UOJResponse::page404(); UOJBlog::cur()->isTypeS() || UOJResponse::page404();
UOJUserBlog::userIsOwner(Auth::user()) || UOJUser::checkPermission(Auth::user(), 'blogs.view') || UOJResponse::page403();
$page_config = UOJContext::pageConfig(); $page_config = UOJContext::pageConfig();
$page_config += [ $page_config += [

View File

@ -12,6 +12,9 @@ if (isset($_GET['id'])) {
$blog = UOJBlog::info(); $blog = UOJBlog::info();
$blog['content'] = UOJBlog::cur()->queryContent()['content']; $blog['content'] = UOJBlog::cur()->queryContent()['content'];
$blog['content_md'] = UOJBlog::cur()->queryContent()['content_md']; $blog['content_md'] = UOJBlog::cur()->queryContent()['content_md'];
} else {
UOJUser::checkPermission(Auth::user(), 'blogs.create') || UOJResponse::page403();
isSuperUser(Auth::user()) || UOJUserBlog::userIsOwner(Auth::user()) || UOJResponse::page403();
} }
$blog_editor = new UOJBlogEditor(); $blog_editor = new UOJBlogEditor();

View File

@ -9,7 +9,7 @@ if (!Auth::check()) {
redirectToLogin(); redirectToLogin();
} }
if (!isSuperUser($myUser)) { if (!isSuperUser(Auth::user())) {
become403Page(); become403Page();
} }
@ -346,7 +346,7 @@ if ($cur_tab == 'index') {
return '用户名不合法'; return '用户名不合法';
} }
if (queryUser($username)) { if (UOJUser::query($username)) {
return '该用户已存在'; return '该用户已存在';
} }
@ -453,7 +453,7 @@ EOD);
return '用户名不合法'; return '用户名不合法';
} }
if (!queryUser($username)) { if (!UOJUser::query($username)) {
return '用户不存在'; return '用户不存在';
} }
@ -524,7 +524,7 @@ EOD);
return '用户名不合法'; return '用户名不合法';
} }
if (!queryUser($username)) { if (!UOJUser::query($username)) {
return '用户不存在'; return '用户不存在';
} }
@ -580,6 +580,206 @@ EOD);
} }
EOD); EOD);
$change_usergroup_form->runAtServer(); $change_usergroup_form->runAtServer();
$users_default_permissions = UOJContext::getMeta('users_default_permissions');
$update_users_default_permissions_form = new UOJForm('update_users_default_permissions');
$update_users_default_permissions_form->appendHTML(HTML::tag('h3', ['class' => 'h5'], '题目'));
$update_users_default_permissions_form->addCheckbox('problems__view', [
'checked' => $users_default_permissions['problems']['view'],
'label' => '查看题目',
'role' => 'switch',
'help' => '',
]);
$update_users_default_permissions_form->addCheckbox('problems__download_testdata', [
'checked' => $users_default_permissions['problems']['download_testdata'],
'label' => '下载测试数据',
'role' => 'switch',
'help' => '请谨慎开启此权限,以防数据泄露。',
]);
$update_users_default_permissions_form->addCheckbox('problems__create', [
'checked' => $users_default_permissions['problems']['create'],
'label' => '新建题目',
'role' => 'switch',
'help' => '',
'disabled' => true,
]);
$update_users_default_permissions_form->addCheckbox('problems__manage', [
'checked' => $users_default_permissions['problems']['manage'],
'label' => '管理题目',
'role' => 'switch',
'help' => '',
'disabled' => true,
]);
$update_users_default_permissions_form->appendHTML(HTML::tag('h3', ['class' => 'h5 mt-3'], '比赛'));
$update_users_default_permissions_form->addCheckbox('contests__view', [
'checked' => $users_default_permissions['contests']['view'],
'label' => '查看比赛',
'role' => 'switch',
'help' => '若用户不具有此权限,则只显示已报名过的比赛列表及详情。',
]);
$update_users_default_permissions_form->addCheckbox('contests__register', [
'checked' => $users_default_permissions['contests']['register'],
'label' => '报名比赛',
'role' => 'switch',
'help' => '',
]);
$update_users_default_permissions_form->addCheckbox('contests__create', [
'checked' => $users_default_permissions['contests']['create'],
'label' => '新建比赛',
'role' => 'switch',
'help' => '',
'disabled' => true,
]);
$update_users_default_permissions_form->addCheckbox('contests__start_final_test', [
'checked' => $users_default_permissions['contests']['start_final_test'],
'label' => '开始比赛最终测试',
'role' => 'switch',
'help' => '',
'disabled' => true,
]);
$update_users_default_permissions_form->addCheckbox('contests__manage', [
'checked' => $users_default_permissions['contests']['manage'],
'label' => '管理比赛',
'role' => 'switch',
'help' => '',
'disabled' => true,
]);
$update_users_default_permissions_form->appendHTML(HTML::tag('h3', ['class' => 'h5 mt-3'], '题单'));
$update_users_default_permissions_form->addCheckbox('lists__view', [
'checked' => $users_default_permissions['lists']['view'],
'label' => '查看题单',
'role' => 'switch',
'help' => '',
]);
$update_users_default_permissions_form->addCheckbox('lists__create', [
'checked' => $users_default_permissions['lists']['create'],
'label' => '新建题单',
'role' => 'switch',
'help' => '',
'disabled' => true,
]);
$update_users_default_permissions_form->addCheckbox('lists__manage', [
'checked' => $users_default_permissions['lists']['manage'],
'label' => '管理题单',
'role' => 'switch',
'help' => '',
'disabled' => true,
]);
$update_users_default_permissions_form->appendHTML(HTML::tag('h3', ['class' => 'h5 mt-3'], '小组'));
$update_users_default_permissions_form->addCheckbox('groups__view', [
'checked' => $users_default_permissions['groups']['view'],
'label' => '查看小组',
'role' => 'switch',
'help' => '',
]);
$update_users_default_permissions_form->addCheckbox('groups__create', [
'checked' => $users_default_permissions['groups']['create'],
'label' => '新建小组',
'role' => 'switch',
'help' => '',
'disabled' => true,
]);
$update_users_default_permissions_form->addCheckbox('groups__manage', [
'checked' => $users_default_permissions['groups']['manage'],
'label' => '管理小组',
'role' => 'switch',
'help' => '',
'disabled' => true,
]);
$update_users_default_permissions_form->appendHTML(HTML::tag('h3', ['class' => 'h5 mt-3'], '博客'));
$update_users_default_permissions_form->addCheckbox('blogs__view', [
'checked' => $users_default_permissions['blogs']['view'],
'label' => '查看博客',
'role' => 'switch',
'help' => '',
]);
$update_users_default_permissions_form->addCheckbox('blogs__create', [
'checked' => $users_default_permissions['blogs']['create'],
'label' => '新建博客',
'role' => 'switch',
'help' => '',
]);
$update_users_default_permissions_form->addCheckbox('blogs__manage', [
'checked' => $users_default_permissions['blogs']['manage'],
'label' => '管理博客',
'role' => 'switch',
'help' => '',
'disabled' => true,
]);
$update_users_default_permissions_form->appendHTML(HTML::tag('h3', ['class' => 'h5 mt-3'], '用户'));
$update_users_default_permissions_form->addCheckbox('users__view', [
'checked' => $users_default_permissions['users']['view'],
'label' => '查看用户',
'role' => 'switch',
'help' => '若用户不具有此权限,则不能查看他人的个人资料。',
]);
$update_users_default_permissions_form->addCheckbox('users__upload_image', [
'checked' => $users_default_permissions['users']['upload_image'],
'label' => '上传图片',
'role' => 'switch',
'help' => '若用户不具有此权限,则不能使用图床功能。',
]);
$update_users_default_permissions_form->setAjaxSubmit(<<<EOD
function(res) {
if (res.status === 'success') {
$('#result-alert-update_users_default_permission')
.html('修改成功!' + (res.message || ''))
.addClass('alert-success')
.removeClass('alert-danger')
.show();
} else {
$('#result-alert-update_users_default_permission')
.html('修改失败。' + (res.message || ''))
.removeClass('alert-success')
.addClass('alert-danger')
.show();
}
$(window).scrollTop(0);
}
EOD);
$update_users_default_permissions_form->config['confirm']['text'] = '你确定要修改所有用户的默认权限吗?';
$update_users_default_permissions_form->handle = function () {
$new_permissions = [
'problems' => [
'view' => isset($_POST['problems__view']),
'download_testdata' => isset($_POST['problems__download_testdata']),
'create' => false, // isset($_POST['problems__create']),
'manage' => false, // isset($_POST['problems__manage']),
],
'contests' => [
'view' => isset($_POST['contests__view']),
'register' => isset($_POST['contests__register']),
'create' => false, // isset($_POST['contests__create']),
'start_final_test' => false, // isset($_POST['contests__start_final_test']),
'manage' => false, // isset($_POST['contests__manage']),
],
'lists' => [
'view' => isset($_POST['lists__view']),
'create' => false, // isset($_POST['lists__create']),
'manage' => false, // isset($_POST['lists__manage']),
],
'groups' => [
'view' => isset($_POST['groups__view']),
'create' => false, // isset($_POST['groups__create']),
'manage' => false, // isset($_POST['groups__manage']),
],
'blogs' => [
'view' => isset($_POST['blogs__view']),
'create' => isset($_POST['blogs__create']),
'manage' => false, // isset($_POST['blogs__manage']),
],
'users' => [
'view' => isset($_POST['users__view']),
'upload_image' => isset($_POST['users__upload_image']),
],
];
UOJContext::setMeta('users_default_permissions', $new_permissions);
dieWithJsonData(['status' => 'success', 'message' => '']);
};
$update_users_default_permissions_form->runAtServer();
} elseif ($cur_tab == 'submissions') { } elseif ($cur_tab == 'submissions') {
} elseif ($cur_tab == 'custom_test') { } elseif ($cur_tab == 'custom_test') {
requireLib('hljs'); requireLib('hljs');
@ -698,7 +898,7 @@ EOD);
return '用户名不合法'; return '用户名不合法';
} }
if (!queryUser($x)) { if (!UOJUser::query($x)) {
return '用户不存在'; return '用户不存在';
} }
@ -960,6 +1160,9 @@ EOD);
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="#user-group" data-bs-toggle="tab" data-bs-target="#user-group">用户类别</a> <a class="nav-link" href="#user-group" data-bs-toggle="tab" data-bs-target="#user-group">用户类别</a>
</li> </li>
<li class="nav-item">
<a class="nav-link" href="#users-default-permissions" data-bs-toggle="tab" data-bs-target="#users-default-permissions">默认权限</a>
</li>
</ul> </ul>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -1111,6 +1314,24 @@ EOD,
</div> </div>
</div> </div>
</div> </div>
<div class="tab-pane" id="users-default-permissions">
<div id="result-alert-update_users_default_permission" class="alert" role="alert" style="display: none"></div>
<div class="row row-cols-1 row-cols-md-2">
<div class="col">
<?php $update_users_default_permissions_form->printHTML() ?>
</div>
<div class="col mt-3 mt-md-0">
<h5>注意事项</h5>
<ul class="mb-0">
<li>此处修改的是 <b>所有用户</b> 的默认权限。</li>
<li>如果某用户的 A 权限启闭状态与为该用户修改 A 权限时的默认权限状态不同,则在此处修改用户默认权限后该用户的 A 权限状态不会受到影响。</li>
<li>对于每一个权限分类,若用户不具有新建项目权限,则只能对现有内容进行管理。</li>
<li>如需为单个用户设置增加/移除特定权限,请前往对应用户的个人资料编辑页面,点击「特权」选项卡修改。</li>
<li>出于安全考虑,部分权限不能被设置为默认权限。</li>
</ul>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,13 +1,11 @@
<?php <?php
requireLib('bootstrap5'); requireLib('bootstrap5');
requireLib('calendar_heatmap'); requireLib('calendar_heatmap');
if (!Auth::check()) { Auth::check() || redirectToLogin();
redirectToLogin(); ($user = UOJUser::query($_GET['username'])) || UOJResponse::page404();
} Auth::id() == $user['username'] || UOJUser::checkPermission(Auth::user(), 'users.view') || UOJResponse::page403();
?>
($user = UOJUser::query($_GET['username'])) || UOJResponse::page404();
?>
<?php echoUOJPageHeader($user['username'] . ' - ' . UOJLocale::get('user profile')) ?> <?php echoUOJPageHeader($user['username'] . ' - ' . UOJLocale::get('user profile')) ?>

View File

@ -293,32 +293,363 @@ EOD);
dieWithJsonData(['status' => 'success', 'message' => '密码修改成功']); dieWithJsonData(['status' => 'success', 'message' => '密码修改成功']);
} }
} elseif ($cur_tab == 'privilege') { } elseif ($cur_tab == 'privilege') {
if (isset($_POST['submit-privilege']) && $_POST['submit-privilege'] == 'privilege' && isSuperUser(Auth::user())) { $users_default_permissions = UOJContext::getMeta('users_default_permissions');
$user['usertype'] = 'student'; $type_text = UOJLocale::get('user::normal user');
if ($user['usergroup'] == 'S') {
if ($_POST['user_type'] == 'teacher') { $type_text = UOJLocale::get('user::super user');
addUserType($user, 'teacher'); } elseif ($user['usergroup'] == 'T') {
removeUserType($user, 'student'); $type_text = UOJLocale::get('user::tmp user');
} else { } elseif ($user['usergroup'] == 'B') {
addUserType($user, 'student'); $type_text = UOJLocale::get('user::banned user');
}
if ($_POST['problem_uploader'] == 'yes') {
addUserType($user, 'problem_uploader');
}
if ($_POST['problem_manager'] == 'yes') {
addUserType($user, 'problem_manager');
}
if ($_POST['contest_judger'] == 'yes') {
addUserType($user, 'contest_judger');
}
DB::update("UPDATE `user_info` SET `usertype` = '{$user['usertype']}' where `username` = '{$user['username']}'");
dieWithJsonData(['status' => 'success', 'message' => '权限修改成功']);
} }
$disabled = !isSuperUser(Auth::user());
$update_user_permissions_form = new UOJForm('update_user_permissions');
if ($disabled) {
$update_user_permissions_form->config['no_submit'] = true;
}
$update_user_permissions_form->appendHTML(HTML::tag('span', [], UOJLocale::get('user::user group')));
$update_user_permissions_form->appendHTML(HTML::tag('span', ['class' => 'd-inline-block ms-3'], $type_text));
$update_user_permissions_form->appendHTML(HTML::tag('h3', ['class' => 'h5 mt-3'], '题目'));
$update_user_permissions_form->addCheckbox('problems__view', [
'checked' => $extra['permissions']['problems']['view'],
'label' => '查看题目',
'role' => 'switch',
'help' => '',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('problems__download_testdata', [
'checked' => $extra['permissions']['problems']['download_testdata'],
'label' => '下载测试数据',
'role' => 'switch',
'help' => '请谨慎开启此权限,以防数据泄露。',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('problems__create', [
'checked' => $extra['permissions']['problems']['create'],
'label' => '新建题目',
'role' => 'switch',
'help' => '',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('problems__manage', [
'checked' => $extra['permissions']['problems']['manage'],
'label' => '管理题目',
'role' => 'switch',
'help' => '若用户不具有「新建题目」权限,则只能对现有题目进行管理。',
'disabled' => $disabled,
]);
$update_user_permissions_form->appendHTML(HTML::tag('h3', ['class' => 'h5 mt-3'], '比赛'));
$update_user_permissions_form->addCheckbox('contests__view', [
'checked' => $extra['permissions']['contests']['view'],
'label' => '查看比赛',
'role' => 'switch',
'help' => '若用户不具有此权限,则只显示已报名过的比赛列表及详情。',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('contests__register', [
'checked' => $extra['permissions']['contests']['register'],
'label' => '报名比赛',
'role' => 'switch',
'help' => '',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('contests__create', [
'checked' => $extra['permissions']['contests']['create'],
'label' => '新建比赛',
'role' => 'switch',
'help' => '',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('contests__start_final_test', [
'checked' => $extra['permissions']['contests']['start_final_test'],
'label' => '开始比赛最终测试',
'role' => 'switch',
'help' => '拥有此权限的用户可以代为开始比赛最终测试。',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('contests__manage', [
'checked' => $extra['permissions']['contests']['manage'],
'label' => '管理比赛',
'role' => 'switch',
'help' => '若用户不具有「新建比赛」权限,则只能对现有比赛进行管理。',
'disabled' => $disabled,
]);
$update_user_permissions_form->appendHTML(HTML::tag('h3', ['class' => 'h5 mt-3'], '题单'));
$update_user_permissions_form->addCheckbox('lists__view', [
'checked' => $extra['permissions']['lists']['view'],
'label' => '查看题单',
'role' => 'switch',
'help' => '',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('lists__create', [
'checked' => $extra['permissions']['lists']['create'],
'label' => '新建题单',
'role' => 'switch',
'help' => '',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('lists__manage', [
'checked' => $extra['permissions']['lists']['manage'],
'label' => '管理题单',
'role' => 'switch',
'help' => '若用户不具有「新建题单」权限,则只能对现有题单进行管理。',
'disabled' => $disabled,
]);
$update_user_permissions_form->appendHTML(HTML::tag('h3', ['class' => 'h5 mt-3'], '小组'));
$update_user_permissions_form->addCheckbox('groups__view', [
'checked' => $extra['permissions']['groups']['view'],
'label' => '查看小组',
'role' => 'switch',
'help' => '',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('groups__create', [
'checked' => $extra['permissions']['groups']['create'],
'label' => '新建小组',
'role' => 'switch',
'help' => '',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('groups__manage', [
'checked' => $extra['permissions']['groups']['manage'],
'label' => '管理小组',
'role' => 'switch',
'help' => '若用户不具有「新建小组」权限,则只能对现有小组进行管理。',
'disabled' => $disabled,
]);
$update_user_permissions_form->appendHTML(HTML::tag('h3', ['class' => 'h5 mt-3'], '博客'));
$update_user_permissions_form->addCheckbox('blogs__view', [
'checked' => $extra['permissions']['blogs']['view'],
'label' => '查看博客',
'role' => 'switch',
'help' => '',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('blogs__create', [
'checked' => $extra['permissions']['blogs']['create'],
'label' => '新建博客',
'role' => 'switch',
'help' => '',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('blogs__manage', [
'checked' => $extra['permissions']['blogs']['manage'],
'label' => '管理博客',
'role' => 'switch',
'help' => '若用户不具有「新建博客」权限,则只能对现有博客进行管理。',
'disabled' => $disabled,
]);
$update_user_permissions_form->appendHTML(HTML::tag('h3', ['class' => 'h5 mt-3'], '用户'));
$update_user_permissions_form->addCheckbox('users__view', [
'checked' => $extra['permissions']['users']['view'],
'label' => '查看用户',
'role' => 'switch',
'help' => '若用户不具有此权限,则不能查看他人的个人资料。',
'disabled' => $disabled,
]);
$update_user_permissions_form->addCheckbox('users__upload_image', [
'checked' => $extra['permissions']['users']['upload_image'],
'label' => '上传图片',
'role' => 'switch',
'help' => '若用户不具有此权限,则不能使用图床功能。',
'disabled' => $disabled,
]);
$update_user_permissions_form->setAjaxSubmit(<<<EOD
function(res) {
if (res.status === 'success') {
$('#result-alert')
.html('修改成功!' + (res.message || ''))
.addClass('alert-success')
.removeClass('alert-danger')
.show();
} else {
$('#result-alert')
.html('修改失败。' + (res.message || ''))
.removeClass('alert-success')
.addClass('alert-danger')
.show();
}
$(window).scrollTop(0);
}
EOD);
$update_user_permissions_form->handle = function () use ($user, $extra, $users_default_permissions) {
$new_permissions = [
'_placeholder' => '',
'problems' => [
'_placeholder' => '',
// 'view' => isset($_POST['problems__view']),
// 'download_testdata' => isset($_POST['problems__download_testdata']),
// 'create' => isset($_POST['problems__create']),
// 'manage' => isset($_POST['problems__manage']),
],
'contests' => [
'_placeholder' => '',
// 'view' => isset($_POST['contests__view']),
// 'register' => isset($_POST['contests__register']),
// 'create' => isset($_POST['contests__create']),
// 'start_final_test' => isset($_POST['contests__start_final_test']),
// 'manage' => isset($_POST['contests__manage']),
],
'lists' => [
'_placeholder' => '',
// 'view' => isset($_POST['lists__view']),
// 'create' => isset($_POST['lists__create']),
// 'manage' => isset($_POST['lists__manage']),
],
'groups' => [
'_placeholder' => '',
// 'view' => isset($_POST['groups__view']),
// 'create' => isset($_POST['groups__create']),
// 'manage' => isset($_POST['groups__manage']),
],
'blogs' => [
'_placeholder' => '',
// 'view' => isset($_POST['blogs__view']),
// 'create' => isset($_POST['blogs__create']),
// 'manage' => isset($_POST['blogs__manage']),
],
'users' => [
'_placeholder' => '',
]
];
if (isset($_POST['problems__view']) && !$users_default_permissions['problems']['view']) {
$new_permissions['problems']['view'] = true;
} elseif (!isset($_POST['problems__view']) && $users_default_permissions['problems']['view']) {
$new_permissions['problems']['view'] = false;
}
if (isset($_POST['problems__download_testdata']) && !$users_default_permissions['problems']['download_testdata']) {
$new_permissions['problems']['download_testdata'] = true;
} elseif (!isset($_POST['problems__download_testdata']) && $users_default_permissions['problems']['download_testdata']) {
$new_permissions['problems']['download_testdata'] = false;
}
if (isset($_POST['problems__create']) && !$users_default_permissions['problems']['create']) {
$new_permissions['problems']['create'] = true;
} elseif (!isset($_POST['problems__create']) && $users_default_permissions['problems']['create']) {
$new_permissions['problems']['create'] = false;
}
if (isset($_POST['problems__manage']) && !$users_default_permissions['problems']['manage']) {
$new_permissions['problems']['manage'] = true;
} elseif (!isset($_POST['problems__manage']) && $users_default_permissions['problems']['manage']) {
$new_permissions['problems']['manage'] = false;
}
if (isset($_POST['contests__view']) && !$users_default_permissions['contests']['view']) {
$new_permissions['contests']['view'] = true;
} elseif (!isset($_POST['contests__view']) && $users_default_permissions['contests']['view']) {
$new_permissions['contests']['view'] = false;
}
if (isset($_POST['contests__register']) && !$users_default_permissions['contests']['register']) {
$new_permissions['contests']['register'] = true;
} elseif (!isset($_POST['contests__register']) && $users_default_permissions['contests']['register']) {
$new_permissions['contests']['register'] = false;
}
if (isset($_POST['contests__create']) && !$users_default_permissions['contests']['create']) {
$new_permissions['contests']['create'] = true;
} elseif (!isset($_POST['contests__create']) && $users_default_permissions['contests']['create']) {
$new_permissions['contests']['create'] = false;
}
if (isset($_POST['contests__start_final_test']) && !$users_default_permissions['contests']['start_final_test']) {
$new_permissions['contests']['start_final_test'] = true;
} elseif (!isset($_POST['contests__start_final_test']) && $users_default_permissions['contests']['start_final_test']) {
$new_permissions['contests']['start_final_test'] = false;
}
if (isset($_POST['contests__manage']) && !$users_default_permissions['contests']['manage']) {
$new_permissions['contests']['manage'] = true;
} elseif (!isset($_POST['contests__manage']) && $users_default_permissions['contests']['manage']) {
$new_permissions['contests']['manage'] = false;
}
if (isset($_POST['lists__view']) && !$users_default_permissions['lists']['view']) {
$new_permissions['lists']['view'] = true;
} elseif (!isset($_POST['lists__view']) && $users_default_permissions['lists']['view']) {
$new_permissions['lists']['view'] = false;
}
if (isset($_POST['lists__create']) && !$users_default_permissions['lists']['create']) {
$new_permissions['lists']['create'] = true;
} elseif (!isset($_POST['lists__create']) && $users_default_permissions['lists']['create']) {
$new_permissions['lists']['create'] = false;
}
if (isset($_POST['lists__manage']) && !$users_default_permissions['lists']['manage']) {
$new_permissions['lists']['manage'] = true;
} elseif (!isset($_POST['lists__manage']) && $users_default_permissions['lists']['manage']) {
$new_permissions['lists']['manage'] = false;
}
if (isset($_POST['groups__view']) && !$users_default_permissions['groups']['view']) {
$new_permissions['groups']['view'] = true;
} elseif (!isset($_POST['groups__view']) && $users_default_permissions['groups']['view']) {
$new_permissions['groups']['view'] = false;
}
if (isset($_POST['groups__create']) && !$users_default_permissions['groups']['create']) {
$new_permissions['groups']['create'] = true;
} elseif (!isset($_POST['groups__create']) && $users_default_permissions['groups']['create']) {
$new_permissions['groups']['create'] = false;
}
if (isset($_POST['groups__manage']) && !$users_default_permissions['groups']['manage']) {
$new_permissions['groups']['manage'] = true;
} elseif (!isset($_POST['groups__manage']) && $users_default_permissions['groups']['manage']) {
$new_permissions['groups']['manage'] = false;
}
if (isset($_POST['blogs__view']) && !$users_default_permissions['blogs']['view']) {
$new_permissions['blogs']['view'] = true;
} elseif (!isset($_POST['blogs__view']) && $users_default_permissions['blogs']['view']) {
$new_permissions['blogs']['view'] = false;
}
if (isset($_POST['blogs__create']) && !$users_default_permissions['blogs']['create']) {
$new_permissions['blogs']['create'] = true;
} elseif (!isset($_POST['blogs__create']) && $users_default_permissions['blogs']['create']) {
$new_permissions['blogs']['create'] = false;
}
if (isset($_POST['blogs__manage']) && !$users_default_permissions['blogs']['manage']) {
$new_permissions['blogs']['manage'] = true;
} elseif (!isset($_POST['blogs__manage']) && $users_default_permissions['blogs']['manage']) {
$new_permissions['blogs']['manage'] = false;
}
if (isset($_POST['users__view']) && !$users_default_permissions['users']['view']) {
$new_permissions['users']['view'] = true;
} elseif (!isset($_POST['users__view']) && $users_default_permissions['users']['view']) {
$new_permissions['users']['view'] = false;
}
if (isset($_POST['users__upload_image']) && !$users_default_permissions['users']['upload_image']) {
$new_permissions['users']['upload_image'] = true;
} elseif (!isset($_POST['users__upload_image']) && $users_default_permissions['users']['upload_image']) {
$new_permissions['users']['upload_image'] = false;
}
$extra['permissions'] = $new_permissions;
DB::update([
"update user_info",
"set", [
"extra" => json_encode($extra),
],
"where", [
"username" => $user['username'],
],
]);
dieWithJsonData(['status' => 'success', 'message' => '']);
};
$update_user_permissions_form->runAtServer();
} }
$pageTitle = $user['username'] == Auth::id() $pageTitle = $user['username'] == Auth::id()
@ -386,7 +717,7 @@ $pageTitle = $user['username'] == Auth::id()
<input type="password" class="form-control" id="input-confirm_password" placeholder="<?= UOJLocale::get('re-enter your new password') ?>" maxlength="20"> <input type="password" class="form-control" id="input-confirm_password" placeholder="<?= UOJLocale::get('re-enter your new password') ?>" maxlength="20">
<div id="help-confirm_password" class="invalid-feedback"></div> <div id="help-confirm_password" class="invalid-feedback"></div>
</div> </div>
<?php if (isSuperUser(Auth::user()) && $user['username'] != $myUser['username']) : ?> <?php if (isSuperUser(Auth::user()) && $user['username'] != Auth::id()) : ?>
<div class="alert alert-warning mb-0" role="alert"> <div class="alert alert-warning mb-0" role="alert">
如需重置其他用户的密码,请前往 <a href="/super_manage/users" class="alert-link">系统管理</a> 页面操作。 如需重置其他用户的密码,请前往 <a href="/super_manage/users" class="alert-link">系统管理</a> 页面操作。
</div> </div>
@ -451,105 +782,7 @@ $pageTitle = $user['username'] == Auth::id()
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<div id="result-alert" class="alert" role="alert" style="display: none"></div> <div id="result-alert" class="alert" role="alert" style="display: none"></div>
<form id="form-privilege" method="post"> <?php $update_user_permissions_form->printHTML() ?>
<?php if (isSuperUser(Auth::user())) : ?>
<fieldset>
<?php else : ?>
<fieldset disabled>
<?php endif ?>
<div class="mb-3">
<span>
<?= UOJLocale::get('user::user group') ?>
</span>
<span class="d-inline-block ms-3">
<?php if ($user['usergroup'] == 'S') : ?>
<?= UOJLocale::get('user::super user') ?>
<?php elseif ($user['usergroup'] == 'B') : ?>
<?= UOJLocale::get('user::banned user') ?>
<?php else : ?>
<?= UOJLocale::get('user::normal user') ?>
<?php endif ?>
</span>
</div>
<div class="input-group mb-3">
<label for="input-user_type" class="form-label">
<?= UOJLocale::get('user::user type') ?>
</label>
<div class="form-check ms-3">
<input class="form-check-input" type="radio" name="user_type" value="student" id="input-user_type" <?= hasUserType($user, 'student') && !hasUserType($user, 'teacher') ? 'checked' : '' ?>>
<label class="form-check-label" for="input-user_type">
<?= UOJLocale::get('user::student') ?>
</label>
</div>
<div class="form-check ms-2">
<input class="form-check-input" type="radio" name="user_type" value="teacher" id="input-user_type_2" <?= hasUserType($user, 'teacher') ? 'checked' : '' ?>>
<label class="form-check-label" for="input-user_type_2">
<?= UOJLocale::get('user::teacher') ?>
</label>
</div>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="problem_uploader" id="input-problem_uploader" <?= hasUserType($user, 'problem_uploader') ? 'checked' : '' ?>>
<label class="form-check-label" for="input-problem_uploader">
<?= UOJLocale::get('user::problem uploader') ?>
</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="problem_manager" id="input-problem_manager" <?= hasUserType($user, 'problem_manager') ? 'checked' : '' ?>>
<label class="form-check-label" for="input-problem_manager">
<?= UOJLocale::get('user::problem manager') ?>
</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="contest_judger" id="input-contest_judger" <?= hasUserType($user, 'contest_judger') ? 'checked' : '' ?>>
<label class="form-check-label" for="input-contest_judger">
<?= UOJLocale::get('user::contest judger') ?>
</label>
</div>
</fieldset>
<?php if (isSuperUser(Auth::user())) : ?>
<div class="text-center">
<button type="submit" id="button-submit-privilege" name="submit-privilege" value="privilege" class="mt-3 btn btn-secondary">更新</button>
</div>
<?php endif ?>
</form>
<script>
$('#form-privilege').submit(function(e) {
$('#result-alert').hide();
$.post('', {
user_type: $('input[name=user_type]:checked').val(),
problem_uploader: $('input[name=problem_uploader]').prop('checked') ? 'yes' : 'no',
problem_manager: $('input[name=problem_manager]').prop('checked') ? 'yes' : 'no',
contest_judger: $('input[name=contest_judger]').prop('checked') ? 'yes' : 'no',
'submit-privilege': 'privilege',
}, function(res) {
if (res && res.status === 'success') {
$('#result-alert')
.html('权限修改成功!')
.addClass('alert-success')
.removeClass('alert-danger')
.show();
$(window).scrollTop(0);
} else {
$('#result-alert')
.html('权限修改失败。' + (res.message || ''))
.removeClass('alert-success')
.addClass('alert-danger')
.show();
$(window).scrollTop(0);
}
});
return false;
});
</script>
</div> </div>
</div> </div>
<?php endif ?> <?php endif ?>

View File

@ -1,83 +1,80 @@
<?php <?php
if (!Auth::check()) { if (!Auth::check()) {
redirectToLogin(); redirectToLogin();
}
function handleMsgPost() {
if (!isset($_POST['receiver'])) {
return 'fail';
}
if (!isset($_POST['message'])) {
return 'fail';
}
if (0 > strlen($_POST['message']) || strlen($_POST['message']) > 65535) {
return 'fail';
}
$receiver = $_POST['receiver'];
$esc_message = DB::escape($_POST['message']);
$sender = Auth::id();
if (!validateUsername($receiver) || !UOJUser::query($receiver)) {
return 'fail';
} }
function handleMsgPost() { DB::query("insert into user_msg (sender, receiver, message, send_time) values ('$sender', '$receiver', '$esc_message', now())");
global $myUser; return "ok";
if (!isset($_POST['receiver'])) { }
return 'fail';
}
if (!isset($_POST['message'])) {
return 'fail';
}
if (0 > strlen($_POST['message']) || strlen($_POST['message']) > 65535) {
return 'fail';
}
$receiver = $_POST['receiver'];
$esc_message = DB::escape($_POST['message']);
$sender = $myUser['username'];
if (!validateUsername($receiver) || !queryUser($receiver)) { function getConversations() {
return 'fail'; $username = Auth::id();
} $result = DB::query("select * from user_msg where sender = '$username' or receiver = '$username' order by send_time DESC");
$ret = array();
DB::query("insert into user_msg (sender, receiver, message, send_time) values ('$sender', '$receiver', '$esc_message', now())"); while ($msg = DB::fetch($result)) {
return "ok"; if ($msg['sender'] !== $username) {
} if (isset($ret[$msg['sender']])) {
$ret[$msg['sender']][1] |= ($msg['read_time'] == null);
function getConversations() { continue;
global $myUser;
$username = $myUser['username'];
$result = DB::query( "select * from user_msg where sender = '$username' or receiver = '$username' order by send_time DESC" );
$ret = array();
while ($msg = DB::fetch($result)) {
if ($msg['sender'] !== $username) {
if (isset($ret[$msg['sender']])) {
$ret[$msg['sender']][1] |= ($msg['read_time'] == null);
continue;
}
$ret[$msg['sender']] = array($msg['send_time'], ($msg['read_time'] == null));
} else {
if (isset($ret[$msg['receiver']])) {
continue;
}
$ret[$msg['receiver']] = array($msg['send_time'], 0);
} }
$ret[$msg['sender']] = array($msg['send_time'], ($msg['read_time'] == null));
} else {
if (isset($ret[$msg['receiver']])) {
continue;
}
$ret[$msg['receiver']] = array($msg['send_time'], 0);
} }
$res = []; }
foreach ($ret as $name => $con) { $res = [];
$res[] = [$con[0], $con[1], $name]; foreach ($ret as $name => $con) {
} $res[] = [$con[0], $con[1], $name];
usort($res, function($a, $b) { }
return -strcmp($a[0], $b[0]); usort($res, function ($a, $b) {
}); return -strcmp($a[0], $b[0]);
return json_encode($res); });
return json_encode($res);
}
function getHistory() {
$username = Auth::id();
if (!isset($_GET['conversationName']) || !validateUsername($_GET['conversationName'])) {
return '[]';
}
if (!isset($_GET['pageNumber']) || !validateUInt($_GET['pageNumber'])) {
return '[]';
} }
function getHistory() { $conversationName = $_GET['conversationName'];
global $myUser; $pageNumber = ($_GET['pageNumber'] - 1) * 10;
$username = $myUser['username']; DB::query("update user_msg set read_time = now() where sender = '$conversationName' and receiver = '$username' and read_time is null");
if (!isset($_GET['conversationName']) || !validateUsername($_GET['conversationName'])) {
return '[]';
}
if (!isset($_GET['pageNumber']) || !validateUInt($_GET['pageNumber'])) {
return '[]';
}
$conversationName = $_GET['conversationName']; $result = DB::query("select * from user_msg where (sender = '$username' and receiver = '$conversationName') or (sender = '$conversationName' and receiver = '$username') order by send_time DESC limit $pageNumber, 11");
$pageNumber = ($_GET['pageNumber'] - 1) * 10; $ret = array();
DB::query("update user_msg set read_time = now() where sender = '$conversationName' and receiver = '$username' and read_time is null"); while ($msg = DB::fetch($result)) {
$ret[] = array($msg['message'], $msg['send_time'], $msg['read_time'], $msg['id'], ($msg['sender'] == $username));
$result = DB::query("select * from user_msg where (sender = '$username' and receiver = '$conversationName') or (sender = '$conversationName' and receiver = '$username') order by send_time DESC limit $pageNumber, 11");
$ret = array();
while ($msg = DB::fetch($result)) {
$ret[] = array($msg['message'], $msg['send_time'], $msg['read_time'], $msg['id'], ($msg['sender'] == $username));
}
return json_encode($ret);
} }
return json_encode($ret);
}
/* /*
function deleteMsg($msgId) { function deleteMsg($msgId) {
return 1; return 1;
$str = <<<EOD $str = <<<EOD
@ -98,21 +95,20 @@
} }
*/ */
if (isset($_POST['user_msg'])) { if (isset($_POST['user_msg'])) {
die(handleMsgPost()); die(handleMsgPost());
} elseif (isset($_GET['getConversations'])) { } elseif (isset($_GET['getConversations'])) {
die(getConversations()); die(getConversations());
} elseif (isset($_GET['getHistory'])) { } elseif (isset($_GET['getHistory'])) {
die(getHistory()); die(getHistory());
} }
?> ?>
<?php echoUOJPageHeader('私信') ?> <?php echoUOJPageHeader('私信') ?>
<h1 class="page-header">私信</h1> <h1 class="page-header">私信</h1>
<div id="conversations"> <div id="conversations"></div>
</div>
<div id="history" style="display:none"> <div id="history" style="display:none">
<div class="card border-primary"> <div class="card border-primary">
@ -147,103 +143,110 @@
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function() { $(document).ready(function() {
$.ajaxSetup({async:false}); $.ajaxSetup({
refreshConversations(); async: false
<?php if (isset($_GET['enter'])): ?> });
enterConversation(<?= json_encode($_GET['enter']) ?>); refreshConversations();
<?php endif ?> <?php if (isset($_GET['enter'])) : ?>
}); enterConversation(<?= json_encode($_GET['enter']) ?>);
<?php endif ?>
});
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
function addButton(conversationName, send_time, type) { function addButton(conversationName, send_time, type) {
$("#conversations").append( $("#conversations").append(
'<div class="row top-buffer-sm">' + '<div class="row top-buffer-sm">' +
'<div class="col-sm-3">' + '<div class="col-sm-3">' +
'<button type="button" class="btn btn-' + ( type ? 'warning' : 'primary' ) + ' btn-block" ' + '<button type="button" class="btn btn-' + (type ? 'warning' : 'primary') + ' btn-block" ' +
'onclick="enterConversation(\'' + conversationName + '\')">' + 'onclick="enterConversation(\'' + conversationName + '\')">' +
conversationName + conversationName +
'</button>' + '</button>' +
'</div>' + '</div>' +
'<div class="col-sm-9" style="line-height:34px">' + '<div class="col-sm-9" style="line-height:34px">' +
'最后发送时间:' + send_time + '最后发送时间:' + send_time +
'</div>' + '</div>' +
'</div>'
);
}
function addBubble(content, send_time, read_time, msgId, conversation, page, type) {
$("#history-list").append(
'<div style=' + (!type ? "margin-left:0%;margin-right:20%;" : "margin-left:20%;margin-right:0%;") + '>' +
'<div class="card border-info mb-4">' +
'<div class="card-body" style="background:#17a2b8; word-break: break-all">' +
'<div style="white-space:pre-wrap">' +
htmlspecialchars(content) +
'</div>' +
'</div>' +
'<div>' +
'<div class="row">' +
'<div class="col-sm-6">' +
'发送时间:' + send_time +
'</div>' +
'<div class="col-sm-6 text-right">' +
'查看时间:' + (read_time == null ? '<strong>未查看</strong>' : read_time) +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' '</div>'
); );
} }
function submitMessagePost(conversationName) { function addBubble(content, send_time, read_time, msgId, conversation, page, type) {
if ($('#input-message').val().length == 0 || $('#input-message').val().length >= 65536) { $("#history-list").append(
$('#help-message').text('私信长度必须在1~65535之间。'); '<div style=' + (!type ? "margin-left:0%;margin-right:20%;" : "margin-left:20%;margin-right:0%;") + '>' +
$('#form-group-message').addClass('has-error'); '<div class="card border-info mb-4">' +
return; '<div class="card-body" style="background:#17a2b8; word-break: break-all">' +
'<div style="white-space:pre-wrap">' +
htmlspecialchars(content) +
'</div>' +
'</div>' +
'<div>' +
'<div class="row">' +
'<div class="col-sm-6">' +
'发送时间:' + send_time +
'</div>' +
'<div class="col-sm-6 text-right">' +
'查看时间:' + (read_time == null ? '<strong>未查看</strong>' : read_time) +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>'
);
}
function submitMessagePost(conversationName) {
if ($('#input-message').val().length == 0 || $('#input-message').val().length >= 65536) {
$('#help-message').text('私信长度必须在1~65535之间。');
$('#form-group-message').addClass('has-error');
return;
} }
$('#help-message').text(''); $('#help-message').text('');
$('#form-group-message').removeClass('has-error'); $('#form-group-message').removeClass('has-error');
$.post('', { $.post('', {
user_msg : 1, user_msg: 1,
receiver : conversationName, receiver: conversationName,
message : $('#input-message').val() message: $('#input-message').val()
}, function(msg) { }, function(msg) {
$('#input-message').val(""); $('#input-message').val("");
}); });
} }
function refreshHistory(conversation, page) { function refreshHistory(conversation, page) {
$("#history-list").empty(); $("#history-list").empty();
var ret = false; var ret = false;
$('#conversation-name').text(conversation); $('#conversation-name').text(conversation);
$('#pageShow').text("" + page.toString() + ""); $('#pageShow').text("" + page.toString() + "");
$.get('', { $.get('', {
getHistory : '', getHistory: '',
conversationName : conversation, conversationName: conversation,
pageNumber : page pageNumber: page
}, function(msg) { }, function(msg) {
var result = JSON.parse(msg); var result = JSON.parse(msg);
var cnt = 0, flag = 0, F = 0; var cnt = 0,
if (result.length == 11) flag = 1, F = 1; flag = 0,
result.reverse(); F = 0;
for (msg in result) { if (result.length == 11) flag = 1, F = 1;
if (flag) {flag = 0; continue;} result.reverse();
var message = result[msg]; for (msg in result) {
addBubble(message[0], message[1], message[2], message[3], conversation, page, message[4]); if (flag) {
if ((++cnt) + 1 == result.length && F) break; flag = 0;
continue;
} }
if (result.length == 11) ret = true; var message = result[msg];
addBubble(message[0], message[1], message[2], message[3], conversation, page, message[4]);
if ((++cnt) + 1 == result.length && F) break;
}
if (result.length == 11) ret = true;
}); });
return ret; return ret;
} }
function refreshConversations() { function refreshConversations() {
$("#conversations").empty(); $("#conversations").empty();
$.get('', { $.get('', {
getConversations : "" getConversations: ""
}, function(msg) { }, function(msg) {
var result = JSON.parse(msg); var result = JSON.parse(msg);
for (i in result) { for (i in result) {
@ -258,49 +261,47 @@ function refreshConversations() {
addButton(conversation[2], conversation[0], conversation[1]); addButton(conversation[2], conversation[0], conversation[1]);
} }
} }
} });
); }
}
function enterConversation(conversationName) {
var slideTime = 300;
var page = 1;
$("#conversations").hide(slideTime);
var changeAble = refreshHistory(conversationName, page);
$("#history").slideDown(slideTime);
$('#form-message').unbind("submit").submit(function() {
submitMessagePost(conversationName);
page = 1;
changeAble = refreshHistory(conversationName, page);
refreshConversations();
return false;
});
$('#goBack').unbind("click").click(function() {
refreshConversations();
$("#history").slideUp(slideTime);
$("#conversations").show(slideTime);
return;
});
$('#pageLeft').unbind("click").click(function() {
if (changeAble) page++;
changeAble = refreshHistory(conversationName, page);
return false;
});
$('#pageLeft2').unbind("click").click(function() {
if (changeAble) page++;
changeAble = refreshHistory(conversationName, page);
});
$('#pageRight').unbind("click").click(function() {
if (page > 1) page--;
changeAble = refreshHistory(conversationName, page);
return false;
});
$('#pageRight2').unbind("click").click(function() {
if (page > 1) page--;
changeAble = refreshHistory(conversationName, page);
});
}
function enterConversation(conversationName) {
var slideTime = 300;
var page = 1;
$("#conversations").hide(slideTime);
var changeAble = refreshHistory(conversationName, page);
$("#history").slideDown(slideTime);
$('#form-message').unbind("submit").submit(function() {
submitMessagePost(conversationName);
page = 1;
changeAble = refreshHistory(conversationName, page);
refreshConversations();
return false;
});
$('#goBack').unbind("click").click(function() {
refreshConversations();
$("#history").slideUp(slideTime);
$("#conversations").show(slideTime);
return;
});
$('#pageLeft').unbind("click").click(function() {
if (changeAble) page++;
changeAble = refreshHistory(conversationName, page);
return false;
});
$('#pageLeft2').unbind("click").click(function() {
if (changeAble) page++;
changeAble = refreshHistory(conversationName, page);
});
$('#pageRight').unbind("click").click(function() {
if (page > 1) page--;
changeAble = refreshHistory(conversationName, page);
return false;
});
$('#pageRight2').unbind("click").click(function() {
if (page > 1) page--;
changeAble = refreshHistory(conversationName, page);
});
}
</script> </script>
<?php echoUOJPageFooter() ?> <?php echoUOJPageFooter() ?>

View File

@ -55,7 +55,7 @@ $system_msgs = [];
foreach ($pag->get() as $idx => $msg) { foreach ($pag->get() as $idx => $msg) {
$system_msgs[$idx] = $msg; $system_msgs[$idx] = $msg;
if (isSuperUser($myUser)) { if (isSuperUser(Auth::user())) {
$delete_form = newDeleteSystemMsgForm($msg['id']); $delete_form = newDeleteSystemMsgForm($msg['id']);
$delete_form->runAtServer(); $delete_form->runAtServer();
$system_msgs[$idx]['delete_form'] = $delete_form; $system_msgs[$idx]['delete_form'] = $delete_form;

View File

@ -6,7 +6,7 @@ function uojHandleAtSign($str, $uri) {
if ($matches[1] === '@') { if ($matches[1] === '@') {
return '@'; return '@';
} else { } else {
$user = queryUser($matches[1]); $user = UOJUser::query($matches[1]);
if ($user == null) { if ($user == null) {
return $matches[0]; return $matches[0];
} else { } else {
@ -99,7 +99,7 @@ function become403Page($message = '访问被拒绝,您可能需要适当的权
} }
function getUserLink($username) { function getUserLink($username) {
if (validateUsername($username) && ($user = queryUser($username)) && $user['usergroup'] != 'B') { if (validateUsername($username) && ($user = UOJUser::query($username)) && $user['usergroup'] != 'B') {
$realname = $user['realname']; $realname = $user['realname'];
if ($realname == "") { if ($realname == "") {
@ -115,7 +115,7 @@ function getUserLink($username) {
function getUserName($username, $realname = null) { function getUserName($username, $realname = null) {
if ($realname == null) { if ($realname == null) {
if (validateUsername($username) && ($user = queryUser($username))) { if (validateUsername($username) && ($user = UOJUser::query($username))) {
$realname = $user['realname']; $realname = $user['realname'];
} }
} }
@ -154,14 +154,6 @@ function getContestProblemLink($problem, $contest_id, $problem_title = '!title_o
return $result; return $result;
} }
function getBlogLink($id) {
$result = '';
if (validateUInt($id) && $blog = queryBlog($id)) {
$result = '<a class="text-decoration-none" href="/blogs/' . $id . '">' . $blog['title'] . '</a>';
}
return $result;
}
function getLongTablePageRawUri($page) { function getLongTablePageRawUri($page) {
$path = strtok(UOJContext::requestURI(), '?'); $path = strtok(UOJContext::requestURI(), '?');
@ -916,49 +908,13 @@ function echoHackDetails($hack_details, $name) {
echoJudgementDetails($hack_details, new HackDetailsStyler(), $name); echoJudgementDetails($hack_details, new HackDetailsStyler(), $name);
} }
function echoHack($hack, $config, $user) { function echoHack($hack, $config, $viewer) {
$problem = queryProblemBrief($hack['problem_id']); $uhack = new UOJHack($hack);
echo '<tr>'; $uhack->setProblem();
if (!isset($config['id_hidden'])) { $uhack->setSubmission();
echo '<td><a href="/hack/', $hack['id'], '">#', $hack['id'], '</a></td>'; $uhack->echoStatusTableRow($config, $viewer);
}
if (!isset($config['submission_hidden'])) {
echo '<td><a href="/submission/', $hack['submission_id'], '">#', $hack['submission_id'], '</a></td>';
}
if (!isset($config['problem_hidden'])) {
if ($hack['contest_id']) {
echo '<td>', getContestProblemLink($problem, $hack['contest_id'], '!id_and_title'), '</td>';
} else {
echo '<td>', getProblemLink($problem, '!id_and_title'), '</td>';
}
}
if (!isset($config['hacker_hidden'])) {
echo '<td>', getUserLink($hack['hacker']), '</td>';
}
if (!isset($config['owner_hidden'])) {
echo '<td>', getUserLink($hack['owner']), '</td>';
}
if (!isset($config['result_hidden'])) {
if ($hack['judge_time'] == null) {
echo '<td><a href="/hack/', $hack['id'], '">Waiting</a></td>';
} elseif ($hack['success'] == null) {
echo '<td><a href="/hack/', $hack['id'], '">Judging</a></td>';
} elseif ($hack['success']) {
echo '<td><a href="/hack/', $hack['id'], '" class="uoj-status" data-success="1"><strong>Success!</strong></a></td>';
} else {
echo '<td><a href="/hack/', $hack['id'], '" class="uoj-status" data-success="0"><strong>Failed.</strong></a></td>';
}
} else {
echo '<td>Hidden</td>';
}
if (!isset($config['submit_time_hidden'])) {
echo '<td>', $hack['submit_time'], '</td>';
}
if (!isset($config['judge_time_hidden'])) {
echo '<td>', $hack['judge_time'], '</td>';
}
echo '</tr>';
} }
function echoHackListOnlyOne($hack, $config, $user) { function echoHackListOnlyOne($hack, $config, $user) {
echo '<div class="card mb-3 table-responsive">'; echo '<div class="card mb-3 table-responsive">';
echo '<table class="table text-center uoj-table mb-0">'; echo '<table class="table text-center uoj-table mb-0">';

View File

@ -1,85 +1,9 @@
<?php <?php
function hasProblemPermission($user, $problem) {
if ($user == null) {
return false;
}
if (isSuperUser($user) || isProblemManager($user)) {
return true;
}
if ($problem['uploader'] == $user['username']) {
return true;
}
return DB::selectFirst("select * from problems_permissions where username = '{$user['username']}' and problem_id = {$problem['id']}") != null;
}
function hasContestPermission($user, $contest) {
if ($user == null) {
return false;
}
if (isSuperUser($user)) {
return true;
}
return DB::selectFirst("select * from contests_permissions where username = '{$user['username']}' and contest_id = {$contest['id']}") != null;
}
function hasRegistered($user, $contest) {
return DB::selectFirst("select * from contests_registrants where username = '${user['username']}' and contest_id = ${contest['id']}") != null;
}
function queryUser($username) {
if (!validateUsername($username)) {
return null;
}
return DB::selectFirst("select * from user_info where username='$username'", MYSQLI_ASSOC);
}
function queryProblemBrief($id) { function queryProblemBrief($id) {
return DB::selectFirst("select * from problems where id = $id", MYSQLI_ASSOC); return DB::selectFirst("select * from problems where id = $id", MYSQLI_ASSOC);
} }
function querySolution($problem_id, $blog_id) {
return DB::selectFirst("select * from problems_solutions where blog_id='$blog_id' and problem_id='$problem_id'", MYSQLI_ASSOC);
}
function queryContestProblemRank($contest, $problem) {
if (!DB::selectFirst("select * from contests_problems where contest_id = {$contest['id']} and problem_id = {$problem['id']}")) {
return null;
}
$contest_problems = DB::selectAll("select problem_id from contests_problems where contest_id = {$contest['id']} order by level, problem_id");
return array_search(array('problem_id' => $problem['id']), $contest_problems) + 1;
}
function queryContest($id) {
return DB::selectFirst("select * from contests where id = $id", MYSQLI_ASSOC);
}
function queryBlog($id) { function queryBlog($id) {
return DB::selectFirst("select * from blogs where id='$id'", MYSQLI_ASSOC); return DB::selectFirst("select * from blogs where id='$id'", MYSQLI_ASSOC);
} }
function queryBlogComment($id) {
return DB::selectFirst("select * from blogs_comments where id='$id'", MYSQLI_ASSOC);
}
function isProblemVisibleToUser($problem, $user) {
return !$problem['is_hidden'] || hasProblemPermission($user, $problem);
}
function isListVisibleToUser($list, $user) {
return !$list['is_hidden'] || isSuperUser($user);
}
function isRegisteredRunningContestProblem($user, $problem) {
$result = DB::query("select contest_id from contests_problems where problem_id = {$problem['id']}");
while (list($contest_id) = DB::fetch($result, MYSQLI_NUM)) {
$contest = queryContest($contest_id);
genMoreContestInfo($contest);
if (
$contest['cur_progress'] == CONTEST_IN_PROGRESS
&& hasRegistered($user, $contest)
&& !hasContestPermission($user, $contest)
&& queryContestProblemRank($contest, $problem)
) {
return true;
}
}
return false;
}

View File

@ -4,6 +4,7 @@ return [
'super user' => 'Super User', 'super user' => 'Super User',
'normal user' => 'Normal User', 'normal user' => 'Normal User',
'banned user' => 'Banned User', 'banned user' => 'Banned User',
'tmp user' => 'Temporary User',
'real name' => 'Real name', 'real name' => 'Real name',
'belongs to these groups' => 'Belongs to these groups:', 'belongs to these groups' => 'Belongs to these groups:',
'avatar source' => 'Avatar source', 'avatar source' => 'Avatar source',

View File

@ -4,6 +4,7 @@ return [
'super user' => '超级用户', 'super user' => '超级用户',
'normal user' => '普通用户', 'normal user' => '普通用户',
'banned user' => '封禁用户', 'banned user' => '封禁用户',
'tmp user' => '临时用户',
'real name' => '真实姓名', 'real name' => '真实姓名',
'belongs to these groups' => '属于这些小组:', 'belongs to these groups' => '属于这些小组:',
'avatar source' => '头像来源', 'avatar source' => '头像来源',

View File

@ -46,6 +46,7 @@ class HTML {
public static function attr($attr) { public static function attr($attr) {
$html = ''; $html = '';
foreach ($attr as $key => $val) { foreach ($attr as $key => $val) {
if ($val === null) continue;
$html .= ' ' . $key . '="'; $html .= ' ' . $key . '="';
$html .= HTML::escape(is_array($val) ? implode(' ', $val) : $val); $html .= HTML::escape(is_array($val) ? implode(' ', $val) : $val);
$html .= '"'; $html .= '"';

View File

@ -10,7 +10,7 @@ class UOJBlog {
} }
$info = DB::selectFirst([ $info = DB::selectFirst([
"select id, title, post_time, active_time, poster, zan, is_hidden, type from blogs", "select id, title, post_time, active_time, poster, zan, is_hidden, type from blogs",
"where", ['id' => $id] "where", ['id' => $id]
]); ]);
if (!$info) { if (!$info) {
return null; return null;
@ -30,7 +30,25 @@ class UOJBlog {
} }
public function userCanView(array $user = null) { public function userCanView(array $user = null) {
return !$this->info['is_hidden'] || $this->userCanManage($user); if ($this->userCanManage($user)) {
return true;
}
if ($this->info['poster'] != $user['username'] && !UOJUser::checkPermission($user, 'blogs.view')) {
return false;
}
if ($problem_id = $this->getSolutionProblemId()) {
$contests = UOJContest::queryContestsHasProblem($problem_id);
foreach ($contests as $contest) {
if ($contest->userHasRegistered($user) && $contest->progress() <= CONTEST_IN_PROGRESS) {
return false;
}
}
}
return !$this->info['is_hidden'];
} }
public function userCanManage(array $user = null) { public function userCanManage(array $user = null) {
@ -70,7 +88,7 @@ class UOJBlog {
$link .= "{$level_str} "; $link .= "{$level_str} ";
} }
} }
$link .= '<a href="'. $this->getBlogUri() .'">'.$this->getTitle($cfg).'</a>'; $link .= '<a href="' . $this->getBlogUri() . '">' . $this->getTitle($cfg) . '</a>';
if (!empty($cfg['show_new_tag'])) { if (!empty($cfg['show_new_tag'])) {
if ($this->isNew()) { if ($this->isNew()) {
$link .= '<sup style="color:red">&nbsp;new</sup>'; $link .= '<sup style="color:red">&nbsp;new</sup>';
@ -191,6 +209,15 @@ class UOJBlog {
]; ];
uojIncludeView('blog-preview', $cfg); uojIncludeView('blog-preview', $cfg);
} }
public function getSolutionProblemId() {
return DB::selectSingle([
DB::lc(), "select 1 from problems_solutions",
"where", [
"blog_id" => $this->info['id'],
],
]);
}
} }
UOJBlog::$table_for_content = 'blogs'; UOJBlog::$table_for_content = 'blogs';

View File

@ -28,12 +28,22 @@ class UOJContest {
])); ]));
} }
public static function queryContestsHasProblem(UOJProblem $problem) {
return array_map(fn ($x) => UOJContest::query($x['contest_id']), DB::selectAll([
"select contest_id from contests_problems",
"where", [
"problem_id" => $problem->info['id'],
],
"order by contest_id",
]));
}
public static function userCanManageSomeContest(array $user = null) { public static function userCanManageSomeContest(array $user = null) {
if (!$user) { if (!$user) {
return false; return false;
} }
if (isSuperUser($user)) { if (isSuperUser($user) || UOJUser::checkPermission($user, 'contests.manage')) {
return true; return true;
} }
@ -45,6 +55,14 @@ class UOJContest {
]) != null; ]) != null;
} }
public static function userCanCreateContest(array $user = null) {
if (!$user) {
return false;
}
return isSuperUser($user) || UOJUser::checkPermission($user, 'contests.create');
}
public static function finalTest() { public static function finalTest() {
$contest = self::info(); $contest = self::info();
@ -306,6 +324,10 @@ class UOJContest {
$cfg['ensure'] && $this->redirectToAnnouncementBlog(); $cfg['ensure'] && $this->redirectToAnnouncementBlog();
return false; return false;
} }
if (!UOJUser::checkPermission($user, 'contests.register')) {
$cfg['ensure'] && UOJResponse::page403();
return false;
}
if ($this->progress() == CONTEST_IN_PROGRESS && !$this->allowExtraRegistration()) { if ($this->progress() == CONTEST_IN_PROGRESS && !$this->allowExtraRegistration()) {
$cfg['ensure'] && redirectTo('/contests'); $cfg['ensure'] && redirectTo('/contests');
return false; return false;
@ -351,6 +373,7 @@ class UOJContest {
return true; return true;
} }
if ($cfg['ensure']) { if ($cfg['ensure']) {
if ($this->info['extra_config']['extra_registration']) { if ($this->info['extra_config']['extra_registration']) {
redirectTo($this->getUri('/register')); redirectTo($this->getUri('/register'));
@ -358,11 +381,17 @@ class UOJContest {
UOJResponse::message("<h1>比赛正在进行中</h1><p>很遗憾,您尚未报名。比赛结束后再来看吧~</p>"); UOJResponse::message("<h1>比赛正在进行中</h1><p>很遗憾,您尚未报名。比赛结束后再来看吧~</p>");
} }
} }
return false; return false;
} else { } else {
return true; return true;
} }
} else { } else {
if (!$this->userHasRegistered($user) && !UOJUser::checkPermission($user, 'contests.view')) {
$cfg['ensure'] && UOJResponse::page403();
return false;
}
return true; return true;
} }
} }
@ -381,9 +410,11 @@ class UOJContest {
if (!$user) { if (!$user) {
return false; return false;
} }
if (isSuperUser($user)) {
if (isSuperUser($user) || UOJUser::checkPermission($user, 'contests.manage')) {
return true; return true;
} }
return DB::selectFirst([ return DB::selectFirst([
DB::lc(), "select 1 from contests_permissions", DB::lc(), "select 1 from contests_permissions",
"where", [ "where", [
@ -393,6 +424,10 @@ class UOJContest {
]) != null; ]) != null;
} }
public function userCanStartFinalTest(array $user = null) {
return $this->userCanManage($user) || UOJUser::checkPermission($user, 'contests.start_final_test');
}
public function userHasRegistered(array $user = null) { public function userHasRegistered(array $user = null) {
if (!$user) { if (!$user) {
return false; return false;
@ -473,6 +508,10 @@ class UOJContest {
return HTML::tag('a', ['class' => $cfg['class'], 'href' => $this->getUri($cfg['where'])], $this->info['name']); return HTML::tag('a', ['class' => $cfg['class'], 'href' => $this->getUri($cfg['where'])], $this->info['name']);
} }
public function getZanBlock() {
return ClickZans::getBlock('C', $this->info['id'], $this->info['zan']);
}
public function redirectToAnnouncementBlog() { public function redirectToAnnouncementBlog() {
$url = getContestBlogLink($this->info, '公告'); $url = getContestBlogLink($this->info, '公告');
if ($url !== null) { if ($url !== null) {

View File

@ -2,7 +2,40 @@
class UOJContext { class UOJContext {
public static $meta_default = [ public static $meta_default = [
'active_duration_M' => 12, 'users_default_permissions' => [
'problems' => [
'view' => true,
'download_testdata' => false,
'create' => false,
'manage' => false,
],
'contests' => [
'view' => true,
'register' => true,
'create' => false,
'start_final_test' => false,
'manage' => false,
],
'lists' => [
'view' => true,
'create' => false,
'manage' => false,
],
'groups' => [
'view' => true,
'create' => false,
'manage' => false,
],
'blogs' => [
'view' => true,
'create' => true,
'manage' => false,
],
'users' => [
'view' => true,
'upload_image' => true,
],
],
]; ];
public static $data = [ public static $data = [
@ -39,7 +72,7 @@ class UOJContext {
return $_SERVER['DOCUMENT_ROOT']; return $_SERVER['DOCUMENT_ROOT'];
} }
public static function storagePath() { public static function storagePath() {
return $_SERVER['DOCUMENT_ROOT'].'/app/storage'; return $_SERVER['DOCUMENT_ROOT'] . '/app/storage';
} }
public static function remoteAddr() { public static function remoteAddr() {
return $_SERVER['REMOTE_ADDR']; return $_SERVER['REMOTE_ADDR'];
@ -100,7 +133,7 @@ class UOJContext {
if (validateIP($domain) || strpos($domain, '.') === false) { if (validateIP($domain) || strpos($domain, '.') === false) {
$domain = ''; $domain = '';
} else { } else {
$domain = '.'.$domain; $domain = '.' . $domain;
} }
return $domain; return $domain;
} }

View File

@ -1,36 +1,41 @@
<?php <?php
class UOJForm { class UOJForm {
public $form_name; public ?string $form_name;
public $succ_href; public ?string $succ_href;
public $back_href = null;
public $no_submit = false;
public $ctrl_enter_submit = false;
public $extra_validator = null; public $extra_validator = null;
public $is_big = false; public $handle;
public $has_file = false; private $ajax_submit_js = null;
public $ajax_submit_js = null; private $run_at_server_handler = [];
public $run_at_server_handler = [];
private $data = []; private $data = [];
private $vdata = []; private $vdata = [];
private $main_html = ''; private $main_html = '';
public $max_post_size = 15728640; // 15M
public $max_file_size_mb = 10; // 10M
public $handle;
public $config = [ public $config = [
'container' => [ 'is_big' => false,
'has_file' => false,
'ctrl_enter_submit' => false,
'max_post_size' => 15728640, // 15M
'max_file_size_mb' => 10, // 10M
'form' => [
'class' => '', 'class' => '',
], ],
'submit_container' => [
'class' => 'mt-3 text-center',
],
'submit_button' => [ 'submit_button' => [
'class' => 'btn btn-primary',
'text' => '提交',
],
'back_button' => [
'href' => null,
'class' => 'btn btn-secondary', 'class' => 'btn btn-secondary',
], ],
'confirm' => [
'smart' => false,
'text' => null,
]
]; ];
public $submit_button_config = [];
public $control_label_config = ['class' => 'col-sm-2'];
public $input_config = ['class' => 'col-sm-3'];
public $textarea_config = ['class' => 'col-sm-10'];
public function __construct($form_name) { public function __construct($form_name) {
$this->form_name = $form_name; $this->form_name = $form_name;
@ -42,7 +47,7 @@ class UOJForm {
die(json_encode($this->validateAtServer())); die(json_encode($this->validateAtServer()));
}; };
$this->run_at_server_handler["submit-{$this->form_name}"] = function () { $this->run_at_server_handler["submit-{$this->form_name}"] = function () {
if ($this->no_submit) { if ($this->config['no_submit']) {
UOJResponse::page404(); UOJResponse::page404();
} }
foreach ($this->data as $field) { foreach ($this->data as $field) {
@ -55,7 +60,7 @@ class UOJForm {
$len = UOJContext::contentLength(); $len = UOJContext::contentLength();
if ($len === null) { if ($len === null) {
UOJResponse::page403(); UOJResponse::page403();
} elseif ($len > $this->max_post_size) { } elseif ($len > $this->config['max_post_size']) {
UOJResponse::message('The form is too large.'); UOJResponse::message('The form is too large.');
} }
} }
@ -87,14 +92,11 @@ class UOJForm {
public function add($name, $html, $validator_php, $validator_js) { public function add($name, $html, $validator_php, $validator_js) {
$this->main_html .= $html; $this->main_html .= $html;
$this->data[] = array( $this->data[] = [
'name' => $name, 'name' => $name,
'validator_php' => $validator_php, 'validator_php' => $validator_php,
'validator_js' => $validator_js 'validator_js' => $validator_js
); ];
}
public function appendHTML($html) {
$this->main_html .= $html;
} }
public function addNoVal($name, $html) { public function addNoVal($name, $html) {
@ -106,6 +108,10 @@ class UOJForm {
); );
} }
public function appendHTML($html) {
$this->main_html .= $html;
}
public function addHidden($name, $default_value, $validator_php, $validator_js) { public function addHidden($name, $default_value, $validator_php, $validator_js) {
$default_value = HTML::escape($default_value); $default_value = HTML::escape($default_value);
$html = <<<EOD $html = <<<EOD
@ -114,78 +120,102 @@ class UOJForm {
$this->add($name, $html, $validator_php, $validator_js); $this->add($name, $html, $validator_php, $validator_js);
} }
public function printHTML() { public function addCheckbox($name, $config) {
$form_entype_str = $this->is_big ? ' enctype="multipart/form-data"' : ''; $config += [
'checked' => false,
'div_class' => 'form-check',
'role' => 'checkbox',
'input_class' => 'form-check-input',
'label' => '',
'label_class' => 'form-check-label',
'help' => '',
'help_class' => 'form-text',
'disabled' => false,
];
echo '<form action="', $_SERVER['REQUEST_URI'], '" method="post" class="" id="form-', $this->form_name, '"', $form_entype_str, '>'; $html = '';
echo HTML::hiddenToken(); $html .= HTML::tag_begin('div', ['class' => $config['div_class']]);
echo $this->main_html; $html .= HTML::empty_tag('input', [
'class' => $config['input_class'],
'type' => 'checkbox',
'name' => $name,
'id' => "input-$name",
'checked' => $config['checked'] ? 'checked' : null,
'value' => '1',
'disabled' => $config['disabled'] ? 'disabled' : null,
]);
$html .= HTML::tag('label', [
'class' => $config['label_class'],
'for' => "input-$name",
], $config['label']);
if (!$this->no_submit) { if ($config['help']) {
if (!isset($this->submit_button_config['align'])) { $html .= HTML::tag('div', ['class' => $config['help_class']], $config['help']);
$this->submit_button_config['align'] = 'center';
}
if (!isset($this->submit_button_config['text'])) {
$this->submit_button_config['text'] = UOJLocale::get('submit');
}
if (!isset($this->submit_button_config['class_str'])) {
$this->submit_button_config['class_str'] = 'btn btn-secondary';
}
if ($this->submit_button_config['align'] == 'offset') {
echo '<div class="form-group">';
echo '<div class="col-sm-offset-2 col-sm-3">';
} else {
echo '<div class="text-', $this->submit_button_config['align'], '">';
}
if ($this->back_href !== null) {
echo '<div class="btn-toolbar">';
}
echo HTML::tag('button', [
'type' => 'submit', 'id' => "button-submit-{$this->form_name}", 'name' => "submit-{$this->form_name}",
'value' => $this->form_name, 'class' => $this->submit_button_config['class_str']
], $this->submit_button_config['text']);
if ($this->back_href !== null) {
echo HTML::tag('a', [
'class' => 'btn btn-secondary', 'href' => $this->back_href
], '返回');
}
if ($this->back_href !== null) {
echo '</div>';
}
if ($this->submit_button_config['align'] == 'offset') {
echo '</div>';
}
echo '</div>';
} }
echo '</form>'; $html .= HTML::tag_end('div');
if ($this->no_submit) { $this->addNoVal($name, $html);
}
public function printHTML() {
echo HTML::tag_begin('form', [
'action' => UOJContext::requestURI(),
'method' => 'POST',
'class' => $this->config['form']['class'],
'id' => "form-{$this->form_name}",
'enctype' => $this->config['is_big'] ? 'multipart/form-data' : 'application/x-www-form-urlencoded',
]);
echo HTML::hiddenToken();
echo $this->main_html;
if (!$this->config['no_submit']) {
echo HTML::tag_begin('div', ['class' => $this->config['submit_container']['class']]);
echo HTML::tag('button', [
'type' => 'submit',
'id' => "button-submit-{$this->form_name}",
'name' => "submit-{$this->form_name}",
'value' => $this->form_name,
'class' => $this->config['submit_button']['class']
], $this->config['submit_button']['text']);
if ($this->config['back_button']['href'] !== null) {
echo HTML::tag('a', [
'class' => $this->config['back_button']['class'],
'href' => $this->config['back_button']['href']
], '返回');
}
echo HTML::tag_end('div');
}
echo HTML::tag_end('form');
if ($this->config['no_submit']) {
return; return;
} }
echo <<<EOD echo <<<EOD
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function() { $(document).ready(function() {
EOD;
EOD; if ($this->config['ctrl_enter_submit']) {
if ($this->ctrl_enter_submit) {
echo <<<EOD echo <<<EOD
$('#form-{$this->form_name}').keydown(function(e) { $('#form-{$this->form_name}').keydown(function(e) {
if (e.keyCode == 13 && e.ctrlKey) { if (e.keyCode == 13 && e.ctrlKey) {
$('#button-submit-{$this->form_name}').click(); $('#button-submit-{$this->form_name}').click();
} }
}); });
EOD;
EOD;
} }
echo <<<EOD echo <<<EOD
$('#form-{$this->form_name}').submit(function(e) { $('#form-{$this->form_name}').submit(function(e) {
var ok = true; var ok = true;
EOD; EOD;
$need_ajax = false; $need_ajax = false;
if ($this->extra_validator) { if ($this->extra_validator) {
$need_ajax = true; $need_ajax = true;
@ -194,8 +224,7 @@ class UOJForm {
if ($field['validator_js'] != null) { if ($field['validator_js'] != null) {
if ($field['validator_js'] != 'always_ok') { if ($field['validator_js'] != 'always_ok') {
echo <<<EOD echo <<<EOD
var {$field['name']}_err = ({$field['validator_js']})($('#input-{$field['name']}').val()); var {$field['name']}_err = ({$field['validator_js']})($('#input-{$field['name']}').val());
EOD; EOD;
} }
} else { } else {
@ -205,125 +234,116 @@ class UOJForm {
if ($need_ajax) { if ($need_ajax) {
echo <<<EOD echo <<<EOD
var post_data = {}; var post_data = {};
EOD;
EOD;
foreach ($this->data as $field) { foreach ($this->data as $field) {
if ($field['validator_js'] == null) { if ($field['validator_js'] == null) {
echo <<<EOD echo <<<EOD
var {$field['name']}_err = 'Unknown error'; var {$field['name']}_err = 'Unknown error';
post_data.{$field['name']} = $('#input-{$field['name']}').val(); post_data.{$field['name']} = $('#input-{$field['name']}').val();
EOD; EOD;
} }
} }
echo <<<EOD echo <<<EOD
post_data['check-{$this->form_name}'] = ""; post_data['check-{$this->form_name}'] = "";
$.ajax({ $.ajax({
url : '{$_SERVER['REQUEST_URI']}', url: '{$_SERVER['REQUEST_URI']}',
type : 'POST', type: 'POST',
dataType : 'json', dataType: 'json',
async : false, async: false,
data : post_data, data: post_data,
success : function(data) { success: function(data) {
EOD;
EOD;
foreach ($this->data as $field) { foreach ($this->data as $field) {
if ($field['validator_js'] == null) { if ($field['validator_js'] == null) {
echo <<<EOD echo <<<EOD
{$field['name']}_err = data.${field['name']}; {$field['name']}_err = data.${field['name']};
EOD; EOD;
} }
} }
echo <<<EOD echo <<<EOD
if (data.extra != undefined) { if (data.extra != undefined) {
alert(data.extra); alert(data.extra);
ok = false; ok = false;
} }
} }
}); });
EOD;
EOD;
} }
foreach ($this->data as $field) { foreach ($this->data as $field) {
if ($field['validator_js'] != 'always_ok') { if ($field['validator_js'] != 'always_ok') {
echo <<<EOD echo <<<EOD
if (${field['name']}_err) { if (${field['name']}_err) {
$('#div-${field['name']}').addClass('has-validation has-error'); $('#div-${field['name']}').addClass('has-validation has-error');
$('#div-${field['name']}').addClass('is-invalid'); $('#div-${field['name']}').addClass('is-invalid');
$('#input-${field['name']}').addClass('is-invalid'); $('#input-${field['name']}').addClass('is-invalid');
$('#help-${field['name']}').text(${field['name']}_err); $('#help-${field['name']}').text(${field['name']}_err);
ok = false; ok = false;
} else { } else {
$('#div-${field['name']}').removeClass('has-validation has-error'); $('#div-${field['name']}').removeClass('has-validation has-error');
$('#div-${field['name']}').removeClass('is-invalid'); $('#div-${field['name']}').removeClass('is-invalid');
$('#input-${field['name']}').removeClass('is-invalid'); $('#input-${field['name']}').removeClass('is-invalid');
$('#help-${field['name']}').text(''); $('#help-${field['name']}').text('');
} }
EOD; EOD;
} }
} }
if (isset($this->submit_button_config['smart_confirm'])) { if ($this->config['confirm']['smart']) {
$this->submit_button_config['confirm_text'] = '你真的要' . $this->submit_button_config['text'] . '吗?'; $this->config['confirm']['text'] = '你真的要' . $this->config['submit']['text'] . '吗?';
} }
if (isset($this->submit_button_config['confirm_text'])) { if ($this->config['confirm']['text']) {
echo <<<EOD echo <<<EOD
if (!confirm('{$this->submit_button_config['confirm_text']}')) { if (!confirm('{$this->config['confirm']['text']}')) {
ok = false; ok = false;
} }
EOD;
EOD;
} }
if ($this->has_file) { if ($this->config['has_file']) {
echo <<<EOD echo <<<EOD
$(this).find("input[type='file']").each(function() { $(this).find("input[type='file']").each(function() {
for (var i = 0; i < this.files.length; i++) { for (var i = 0; i < this.files.length; i++) {
if (this.files[i].size > {$this->max_file_size_mb} * 1024 * 1024) { if (this.files[i].size > {$this->config['max_file_size_mb']} * 1024 * 1024) {
$('#div-' + $(this).attr('name')).addClass('has-validation has-error'); $('#div-' + $(this).attr('name')).addClass('has-validation has-error');
$('#div-' + $(this).attr('name')).addClass('is-invalid'); $('#div-' + $(this).attr('name')).addClass('is-invalid');
$('#input-' + $(this).attr('name')).addClass('is-invalid'); $('#input-' + $(this).attr('name')).addClass('is-invalid');
$('#help-' + $(this).attr('name')).text('文件大小不能超过{$this->max_file_size_mb}M'); $('#help-' + $(this).attr('name')).text('文件大小不能超过 {$this->config['max_file_size_mb']} MB');
ok = false; ok = false;
} else { } else {
$('#div-' + $(this).attr('name')).removeClass('has-validation has-error'); $('#div-' + $(this).attr('name')).removeClass('has-validation has-error');
$('#div-' + $(this).attr('name')).removeClass('is-invalid'); $('#div-' + $(this).attr('name')).removeClass('is-invalid');
$('#input-' + $(this).attr('name')).removeClass('is-invalid'); $('#input-' + $(this).attr('name')).removeClass('is-invalid');
$('#help-' + $(this).attr('name')).text(''); $('#help-' + $(this).attr('name')).text('');
} }
} }
}); });
EOD;
EOD;
} }
if ($this->ajax_submit_js !== null) { if ($this->ajax_submit_js !== null) {
echo <<<EOD echo <<<EOD
e.preventDefault(); e.preventDefault();
if (ok) { if (ok) {
$(this).ajaxSubmit({ $(this).ajaxSubmit({
beforeSubmit: function(formData) { beforeSubmit: function(formData) {
formData.push({name: 'submit-{$this->form_name}', value: '{$this->form_name}', type: 'submit'}); formData.push({name: 'submit-{$this->form_name}', value: '{$this->form_name}', type: 'submit'});
}, },
success : {$this->ajax_submit_js} success: {$this->ajax_submit_js}
}); });
} }
EOD;
EOD;
} else { } else {
echo <<<EOD echo <<<EOD
return ok; return ok;
EOD;
EOD;
} }
echo <<<EOD echo <<<EOD
}); });
}); });
</script> </script>
EOD; EOD;
} }
private function validateAtServer() { private function validateAtServer() {

View File

@ -22,11 +22,19 @@ class UOJGroup {
return []; return [];
} }
return array_map(fn ($x) => UOJGroup::query($x['group_id']), DB::selectAll([ return array_filter(array_map(fn ($x) => UOJGroup::query($x['group_id']), DB::selectAll([
DB::lc(), "select group_id from groups_users", DB::lc(), "select group_id from groups_users",
"where", ['username' => $user['username']], "where", ['username' => $user['username']],
"order by group_id" "order by group_id"
])); ])), fn ($group) => $group->userCanView($user));
}
public static function userCanCreateGroup($user) {
if (!$user) {
return false;
}
return isSuperUser($user) || UOJUser::checkPermission($user, 'groups.create');
} }
public function __construct($info) { public function __construct($info) {
@ -34,15 +42,22 @@ class UOJGroup {
} }
public function userCanManage(array $user = null) { public function userCanManage(array $user = null) {
return isSuperUser($user); return isSuperUser($user) || UOJUser::checkPermission($user, 'groups.manage');
} }
public function userCanView(array $user = null, array $cfg = []) { public function userCanView(array $user = null, array $cfg = []) {
$cfg += ['ensure' => false]; $cfg += ['ensure' => false];
if ($this->info['is_hidden'] && !$this->userCanManage($user)) { if ($this->info['is_hidden'] && !$this->userCanManage($user)) {
$cfg['ensure'] && UOJResponse::page404(); $cfg['ensure'] && UOJResponse::page404();
return false; return false;
} }
if (!$this->hasUser($user) && !UOJUser::checkPermission($user, 'groups.view')) {
$cfg['ensure'] && UOJResponse::page403();
return false;
}
return true; return true;
} }

View File

@ -18,6 +18,14 @@ class UOJList {
return new UOJList($info); return new UOJList($info);
} }
public static function userCanCreateList(array $user = null) {
if (!$user) {
return false;
}
return isSuperUser($user) || UOJUser::checkPermission($user, 'lists.create');
}
public function __construct($info) { public function __construct($info) {
$this->info = $info; $this->info = $info;
} }
@ -59,15 +67,22 @@ class UOJList {
} }
public function userCanManage(array $user = null) { public function userCanManage(array $user = null) {
return isSuperUser($user); return isSuperUser($user) || UOJUser::checkPermission($user, 'lists.manage');
} }
public function userCanView(array $user = null, array $cfg = []) { public function userCanView(array $user = null, array $cfg = []) {
$cfg += ['ensure' => false]; $cfg += ['ensure' => false];
if ($this->info['is_hidden'] && !$this->userCanManage($user)) { if ($this->info['is_hidden'] && !$this->userCanManage($user)) {
$cfg['ensure'] && UOJResponse::page404(); $cfg['ensure'] && UOJResponse::page404();
return false; return false;
} }
if (!UOJUser::checkPermission($user, 'lists.view')) {
$cfg['ensure'] && UOJResponse::page403();
return false;
}
return true; return true;
} }
} }

View File

@ -54,7 +54,7 @@ class UOJMarkdown extends ParsedownMath {
// https://gist.github.com/ShNURoK42/b5ce8baa570975db487c // https://gist.github.com/ShNURoK42/b5ce8baa570975db487c
protected function inlineUserMention($Excerpt) { protected function inlineUserMention($Excerpt) {
if (preg_match('/^@([^\s]+)/', $Excerpt['text'], $matches)) { if (preg_match('/^@([^\s]+)/', $Excerpt['text'], $matches)) {
if (validateUsername($matches[1]) && ($user = queryUser($matches[1])) && $user['usergroup'] != 'B') { if (($user = UOJUser::query($matches[1])) && $user['usergroup'] != 'B') {
return [ return [
'extent' => strlen($matches[0]), 'extent' => strlen($matches[0]),
'element' => [ 'element' => [

View File

@ -31,6 +31,10 @@ class UOJProblem {
return false; return false;
} }
if (isSuperUser($user) || UOJUser::checkPermission($user, 'problems.manage')) {
return true;
}
return DB::selectFirst([ return DB::selectFirst([
DB::lc(), "select 1 from problems_permissions", DB::lc(), "select 1 from problems_permissions",
"where", [ "where", [
@ -44,6 +48,14 @@ class UOJProblem {
]) != null; ]) != null;
} }
public static function userCanCreateProblem(array $user = null) {
if (!$user) {
return false;
}
return isSuperUser($user) || UOJUser::checkPermission($user, 'problems.create');
}
public function __construct($info) { public function __construct($info) {
$this->info = $info; $this->info = $info;
} }
@ -162,10 +174,17 @@ class UOJProblem {
public function userCanView(array $user = null, array $cfg = []) { public function userCanView(array $user = null, array $cfg = []) {
$cfg += ['ensure' => false]; $cfg += ['ensure' => false];
if ($this->info['is_hidden'] && !$this->userCanManage($user)) { if ($this->info['is_hidden'] && !$this->userCanManage($user)) {
$cfg['ensure'] && UOJResponse::page404(); $cfg['ensure'] && UOJResponse::page404();
return false; return false;
} }
if (!UOJUser::checkPermission($user, 'problems.view')) {
$cfg['ensure'] && UOJResponse::page403();
return false;
}
return true; return true;
} }
@ -174,7 +193,7 @@ class UOJProblem {
* Need to be consistent with the member function userCanView * Need to be consistent with the member function userCanView
*/ */
public static function sqlForUserCanView(array $user = null) { public static function sqlForUserCanView(array $user = null) {
if (isSuperUser($user)) { if (isSuperUser($user) || UOJUser::checkPermission($user, 'problems.manage')) {
return "(1)"; return "(1)";
} elseif (UOJProblem::userCanManageSomeProblem($user)) { } elseif (UOJProblem::userCanManageSomeProblem($user)) {
return DB::lor([ return DB::lor([
@ -247,9 +266,11 @@ class UOJProblem {
if (!$user) { if (!$user) {
return false; return false;
} }
if (isSuperUser($user) || $user['username'] == $this->info['poster'] || isProblemManager($user)) {
if (isSuperUser($user) || $this->isUserOwnProblem($user) || UOJUser::checkPermission($user, 'problems.manage')) {
return true; return true;
} }
return DB::selectFirst([ return DB::selectFirst([
DB::lc(), "select 1 from problems_permissions", DB::lc(), "select 1 from problems_permissions",
"where", [ "where", [
@ -260,7 +281,7 @@ class UOJProblem {
} }
public function userCanDownloadTestData(array $user = null) { public function userCanDownloadTestData(array $user = null) {
return $this->userCanManage($user); return $this->userCanManage($user) || UOJUser::checkPermission($user, 'problems.download_testdata');
} }
public function preHackCheck(array $user = null) { public function preHackCheck(array $user = null) {

View File

@ -38,7 +38,7 @@ class UOJSubmission {
* Need to be consistent with the member function userCanView * Need to be consistent with the member function userCanView
*/ */
public static function sqlForUserCanView(array $user = null, UOJProblem $problem = null) { public static function sqlForUserCanView(array $user = null, UOJProblem $problem = null) {
if (isSuperUser($user) || isProblemManager($user)) { if (isSuperUser($user) || UOJUser::checkPermission($user, 'problems.manage')) {
// MySQL can find appropriate keys to speed up the query if we write "true" in this way. // MySQL can find appropriate keys to speed up the query if we write "true" in this way.
return "(submissions.is_hidden = true or submissions.is_hidden = false)"; return "(submissions.is_hidden = true or submissions.is_hidden = false)";
} elseif ($problem) { } elseif ($problem) {

View File

@ -50,7 +50,11 @@ trait UOJSubmissionLikeTrait {
public function userCanView(array $user = null, array $cfg = []) { public function userCanView(array $user = null, array $cfg = []) {
$cfg += ['ensure' => false]; $cfg += ['ensure' => false];
if (!$this->info['is_hidden']) {
if (!$this->problem->userCanView($user) && !$this->userIsSubmitter($user)) {
$cfg['ensure'] && UOJResponse::page403();
return false;
} elseif (!$this->info['is_hidden']) {
return true; return true;
} elseif ($this->userCanManageProblemOrContest($user)) { } elseif ($this->userCanManageProblemOrContest($user)) {
return true; return true;
@ -107,7 +111,7 @@ trait UOJSubmissionLikeTrait {
return $this->info['id']; return $this->info['id'];
} }
public function getLink() { public function getLink() {
return '<a class="text-decoration-none" href="'.$this->getUri().'">#'.$this->info['id'].'</a></td>'; return '<a class="text-decoration-none" href="' . $this->getUri() . '">#' . $this->info['id'] . '</a></td>';
} }
public function getResult($key = null) { public function getResult($key = null) {
@ -139,7 +143,7 @@ trait UOJSubmissionLikeTrait {
} }
$zip_file = new ZipArchive(); $zip_file = new ZipArchive();
if ($zip_file->open(UOJContext::storagePath().$content['file_name'], ZipArchive::RDONLY) !== true) { if ($zip_file->open(UOJContext::storagePath() . $content['file_name'], ZipArchive::RDONLY) !== true) {
echo <<<EOD echo <<<EOD
<div class="card mb-3"> <div class="card mb-3">
<div class="card-header text-bg-danger fw-bold"> <div class="card-header text-bg-danger fw-bold">
@ -172,7 +176,7 @@ trait UOJSubmissionLikeTrait {
} }
$file_content = uojTextEncode($file_content, array('allow_CR' => true, 'html_escape' => true)); $file_content = uojTextEncode($file_content, array('allow_CR' => true, 'html_escape' => true));
$footer_text = UOJLocale::get('problems::source code').': '; $footer_text = UOJLocale::get('problems::source code') . ': ';
$footer_text .= UOJLang::getLanguageDisplayName($file_language); $footer_text .= UOJLang::getLanguageDisplayName($file_language);
$sh_class = UOJLang::getLanguagesCSSClass($file_language); $sh_class = UOJLang::getLanguagesCSSClass($file_language);
echo <<<EOD echo <<<EOD
@ -233,14 +237,14 @@ trait UOJSubmissionLikeTrait {
break; break;
case 'used_time': case 'used_time':
if ($cfg['show_actual_score']) { if ($cfg['show_actual_score']) {
echo $this->info['used_time'].'ms'; echo $this->info['used_time'] . 'ms';
} else { } else {
echo '/'; echo '/';
} }
break; break;
case 'used_memory': case 'used_memory':
if ($cfg['show_actual_score']) { if ($cfg['show_actual_score']) {
echo $this->info['used_memory'].'kb'; echo $this->info['used_memory'] . 'kb';
} else { } else {
echo '/'; echo '/';
} }
@ -254,7 +258,7 @@ trait UOJSubmissionLikeTrait {
break; break;
case 'submit_time': case 'submit_time':
case 'judge_time': case 'judge_time':
echo '<small>', $this->info[$name],'</small>'; echo '<small>', $this->info[$name], '</small>';
break; break;
default: default:
echo '?'; echo '?';

View File

@ -212,6 +212,7 @@ class UOJUser {
$extra = []; $extra = [];
} }
mergeConfig($extra, [ mergeConfig($extra, [
'permissions' => UOJContext::getMeta('users_default_permissions'),
'social' => [ 'social' => [
'codeforces' => null, 'codeforces' => null,
'github' => null, 'github' => null,
@ -252,6 +253,24 @@ class UOJUser {
]; ];
} }
public static function checkPermission(array $user = null, string $perm = '') {
if ($user == null) {
return false;
}
$extra = UOJUser::getExtra($user);
$cur = $extra['permissions'];
foreach (explode('.', $perm) as $p) {
if (!is_assoc($cur) || !isset($cur[$p])) {
return false;
}
$cur = $cur[$p];
}
return $cur;
}
public static function updateVisitHistory($user, $info) { public static function updateVisitHistory($user, $info) {
$extra = UOJUser::getExtra($user); $extra = UOJUser::getExtra($user);
$cur = [ $cur = [

View File

@ -26,10 +26,17 @@ class UOJUserBlog {
return self::$user; return self::$user;
} }
public static function userIsOwner(?array $user) {
if ($user === null) {
return false;
}
return self::$user['username'] === $user['username'];
}
public static function userCanManage(?array $user, ?string $whose_blog = null) { public static function userCanManage(?array $user, ?string $whose_blog = null) {
if ($whose_blog === null) { if ($whose_blog === null) {
$whose_blog = self::id(); $whose_blog = self::id();
} }
return $user && (isSuperUser($user) || $user['username'] === $whose_blog); return $user && (isSuperUser($user) || UOJUser::checkPermission($user, 'blogs.manage') || $user['username'] === $whose_blog);
} }
} }

View File

@ -85,7 +85,8 @@ Route::group(
Route::any('/super_manage(?:/{tab})?', '/super_manage.php'); Route::any('/super_manage(?:/{tab})?', '/super_manage.php');
Route::any('/download.php', '/download.php'); Route::any('/download/problem/{id}/data.zip', '/download.php?type=problem');
Route::any('/download/problem/{id}/attachment.zip', '/download.php?type=attachment');
Route::any('/check-notice', '/check_notice.php'); Route::any('/check-notice', '/check_notice.php');
Route::any('/click-zan', '/click_zan.php'); Route::any('/click-zan', '/click_zan.php');

View File

@ -1,83 +1,85 @@
<?php <?php
if ($is_preview) { if ($is_preview) {
$readmore_pos = strpos($blog->content['content'], '<!-- readmore -->'); $readmore_pos = strpos($blog->content['content'], '<!-- readmore -->');
if ($readmore_pos !== false) { if ($readmore_pos !== false) {
$content = substr($blog->content['content'], 0, $readmore_pos).'<p><a href="/blog/'.$blog->info['id'].'">阅读更多……</a></p>'; $content = substr($blog->content['content'], 0, $readmore_pos) . '<p><a href="/blog/' . $blog->info['id'] . '">阅读更多……</a></p>';
} else {
$content = $blog->content['content'];
}
} else { } else {
$content = $blog->content['content']; $content = $blog->content['content'];
} }
} else {
$content = $blog->content['content'];
}
$extra_text = $blog->info['is_hidden'] ? '<span class="text-muted">[已隐藏]</span> ' : ''; $extra_text = $blog->info['is_hidden'] ? '<span class="text-muted">[已隐藏]</span> ' : '';
?> ?>
<h1> <h1>
<?= $extra_text ?> <?= $extra_text ?>
<a class="header-a text-decoration-none text-body" href="<?= HTML::blog_url($blog->info['poster'], '/post/'.$blog->info['id']) ?>"> <a class="header-a text-decoration-none text-body" href="<?= HTML::blog_url($blog->info['poster'], '/post/' . $blog->info['id']) ?>">
<?= $blog->info['title'] ?> <?= $blog->info['title'] ?>
</a> </a>
</h1> </h1>
<div><?= $blog->info['post_time'] ?> <strong>By</strong> <?= getUserLink($blog->info['poster']) ?> (<strong>博客 ID: </strong> <?= $blog->info['id'] ?>)</div> <div><?= $blog->info['post_time'] ?> <strong>By</strong> <?= getUserLink($blog->info['poster']) ?> (<strong>博客 ID: </strong> <?= $blog->info['id'] ?>)</div>
<?php if (!$show_title_only): ?> <?php if (!$show_title_only) : ?>
<div class="card mb-4"> <div class="card mb-4">
<div class="card-body"> <div class="card-body">
<?php if ($blog->isTypeB()): ?> <?php if ($blog->isTypeB()) : ?>
<!-- content --> <!-- content -->
<article class="markdown-body"> <article class="markdown-body">
<?= $content ?> <?= $content ?>
</article> </article>
<!-- content end --> <!-- content end -->
<?php elseif ($blog->isTypeS()): ?> <?php elseif ($blog->isTypeS()) : ?>
<!-- slide --> <!-- slide -->
<article> <article>
<div class="ratio ratio-16x9"> <div class="ratio ratio-16x9">
<iframe class="embed-responsive-item" src="<?= HTML::blog_url($blog->info['poster'], '/slide/'.$blog->info['id']) ?>"></iframe> <iframe class="embed-responsive-item" src="<?= HTML::blog_url($blog->info['poster'], '/slide/' . $blog->info['id']) ?>"></iframe>
</div> </div>
<div class="text-end mt-2"> <div class="text-end mt-2">
<a class="btn btn-secondary btn-md" href="<?= HTML::blog_url($blog->info['poster'], '/slide/'.$blog->info['id']) ?>"> <a class="btn btn-secondary btn-md" href="<?= HTML::blog_url($blog->info['poster'], '/slide/' . $blog->info['id']) ?>">
<i class="bi bi-arrows-fullscreen"></i> <i class="bi bi-arrows-fullscreen"></i>
全屏 全屏
</a> </a>
</div> </div>
</article> </article>
<!-- slide end --> <!-- slide end -->
<?php endif ?>
</div>
<div class="card-footer text-end text-right">
<ul class="list-inline mb-0">
<li class="list-inline-item">
<?php foreach ($blog->tags as $tag): ?>
<?php echoBlogTag($tag) ?>
<?php endforeach ?>
</li>
<?php if ($is_preview): ?>
<li class="list-inline-item">
<a class="text-decoration-none" href="<?= HTML::blog_url($blog->info['poster'], '/post/'.$blog->info['id']) ?>">
阅读全文
</a>
</li>
<?php endif ?>
<?php if (Auth::check() && (isSuperUser(Auth::user()) || Auth::id() == $blog->info['poster'])): ?>
<li class="list-inline-item">
<a class="text-decoration-none" href="<?= HTML::blog_url($blog->info['poster'], '/'.($blog->info['type'] == 'B' ? 'post' : 'slide').'/'.$blog->info['id'].'/write') ?>">
修改
</a>
</li>
<li class="list-inline-item">
<a class="text-decoration-none" href="<?= HTML::blog_url($blog->info['poster'], '/post/'.$blog->info['id'].'/delete') ?>">
删除
</a>
</li>
<?php endif ?> <?php endif ?>
<li class="list-inline-item"><?= ClickZans::getBlock('B', $blog->info['id'], $blog->info['zan']) ?></li> </div>
</ul> <div class="card-footer text-end text-right">
<ul class="list-inline mb-0">
<li class="list-inline-item">
<?php foreach ($blog->tags as $tag) : ?>
<?php echoBlogTag($tag) ?>
<?php endforeach ?>
</li>
<?php if ($is_preview) : ?>
<li class="list-inline-item">
<a class="text-decoration-none" href="<?= HTML::blog_url($blog->info['poster'], '/post/' . $blog->info['id']) ?>">
阅读全文
</a>
</li>
<?php endif ?>
<?php if ($blog->userCanManage(Auth::user())) : ?>
<li class="list-inline-item">
<a class="text-decoration-none" href="<?= HTML::blog_url($blog->info['poster'], '/' . ($blog->info['type'] == 'B' ? 'post' : 'slide') . '/' . $blog->info['id'] . '/write') ?>">
修改
</a>
</li>
<li class="list-inline-item">
<a class="text-decoration-none" href="<?= HTML::blog_url($blog->info['poster'], '/post/' . $blog->info['id'] . '/delete') ?>">
删除
</a>
</li>
<?php endif ?>
<li class="list-inline-item">
<?= ClickZans::getBlock('B', $blog->info['id'], $blog->info['zan']) ?>
</li>
</ul>
</div>
</div> </div>
</div>
<?php endif ?> <?php endif ?>

View File

@ -192,7 +192,7 @@
</nav> </nav>
<?php if (!isset($is_blog_aboutme)) : ?> <?php if (!isset($is_blog_aboutme)) : ?>
<?php $groups = UOJGroup::queryGroupsOfUser($user['username']) ?> <?php $groups = UOJGroup::queryGroupsOfUser($user) ?>
<div class="card mb-2"> <div class="card mb-2">
<div class="card-body"> <div class="card-body">
<h4 class="card-title"> <h4 class="card-title">