mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-11-22 19:28:41 +00:00
refactor(web/list): list_v3 (#16)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
commit
91fb9c8e01
@ -745,6 +745,29 @@ CREATE TABLE `lists` (
|
|||||||
) 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 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `lists_contents`
|
||||||
|
--
|
||||||
|
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `lists_contents` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`content` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`content_md` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `lists_contents`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `lists_contents` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `lists_contents` DISABLE KEYS */;
|
||||||
|
/*!40000 ALTER TABLE `lists_contents` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `lists_problems`
|
-- Table structure for table `lists_problems`
|
||||||
--
|
--
|
||||||
@ -759,6 +782,15 @@ CREATE TABLE `lists_problems` (
|
|||||||
) 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 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `lists_problems`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `lists_problems` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `lists_problems` DISABLE KEYS */;
|
||||||
|
/*!40000 ALTER TABLE `lists_problems` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `lists_tags`
|
-- Table structure for table `lists_tags`
|
||||||
--
|
--
|
||||||
@ -775,6 +807,15 @@ CREATE TABLE `lists_tags` (
|
|||||||
) 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 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `lists_tags`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `lists_tags` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `lists_tags` DISABLE KEYS */;
|
||||||
|
/*!40000 ALTER TABLE `lists_tags` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `search_requests`
|
-- Table structure for table `search_requests`
|
||||||
--
|
--
|
||||||
|
@ -1,65 +1,53 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check()) {
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
|
|
||||||
$group_id = $_GET['id'];
|
$group_id = $_GET['id'];
|
||||||
if (!validateUInt($group_id)) {
|
if (!validateUInt($group_id)) {
|
||||||
become404Page();
|
become404Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
$list_id = $_GET['list_id'];
|
UOJList::init(UOJRequest::get('list_id')) || UOJResponse::page404();
|
||||||
if (!validateUInt($list_id)) {
|
|
||||||
|
$assignment = queryAssignmentByGroupListID($group_id, UOJList::info('id'));
|
||||||
|
|
||||||
|
if (!$assignment) {
|
||||||
become404Page();
|
become404Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
$assignment = queryAssignmentByGroupListID($group_id, $list_id);
|
$group = queryGroup($assignment['group_id']);
|
||||||
|
$list = UOJList::info();
|
||||||
|
|
||||||
if (!$assignment) {
|
if (($group['is_hidden'] || $list['is_hidden']) && !isSuperUser($myUser)) {
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$group = queryGroup($assignment['group_id']);
|
|
||||||
$list = queryProblemList($assignment['list_id']);
|
|
||||||
|
|
||||||
if (($group['is_hidden'] || $list['is_hidden']) && !isSuperUser($myUser)) {
|
|
||||||
become403Page();
|
become403Page();
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('assignments')) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('assignments')) ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
<h1>
|
||||||
<h1>
|
<small class="fs-4">作业:</small><?= UOJList::info('title') ?>
|
||||||
<small class="fs-4">作业:</small><?= $list['title'] ?>
|
</h1>
|
||||||
</h1>
|
<ul class="mt-3">
|
||||||
<ul class="mt-3">
|
<li>对应题单:<a class="text-decoration-none" href="<?= HTML::url('/list/' . UOJList::info('id')) ?>">#<?= UOJList::info('id') ?></a></li>
|
||||||
<li>对应题单:<a class="text-decoration-none" href="<?= HTML::url('/list/'.$list['id']) ?>">#<?= $list['id'] ?></a></li>
|
<li>所属小组:<a class="text-decoration-none" href="<?= HTML::url('/group/' . $group['id']) ?>"><?= $group['title'] ?></a></li>
|
||||||
<li>所属小组:<a class="text-decoration-none" href="<?= HTML::url('/group/'.$group['id']) ?>"><?= $group['title'] ?></a></li>
|
|
||||||
<li>结束时间:<?= $assignment['end_time'] ?></li>
|
<li>结束时间:<?= $assignment['end_time'] ?></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$problems = DB::selectAll("select problem_id from lists_problems where list_id = {$list['id']}");
|
$problems = UOJList::cur()->getProblemIDs();
|
||||||
$users = queryGroupUsers($group['id']);
|
$users = queryGroupUsers($group['id']);
|
||||||
$problem_ids = [];
|
|
||||||
$usernames = [];
|
$usernames = [];
|
||||||
$n_users = count($users);
|
$n_users = count($users);
|
||||||
$n_problems = count($problems);
|
|
||||||
$submission_end_time = min(new DateTime(), DateTime::createFromFormat('Y-m-d H:i:s', $assignment['end_time']));
|
$submission_end_time = min(new DateTime(), DateTime::createFromFormat('Y-m-d H:i:s', $assignment['end_time']));
|
||||||
|
|
||||||
foreach ($problems as $problem) {
|
|
||||||
$problem_ids[] = $problem['problem_id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
sort($problem_ids);
|
|
||||||
|
|
||||||
foreach ($users as $user) {
|
foreach ($users as $user) {
|
||||||
$usernames[] = $user['username'];
|
$usernames[] = $user['username'];
|
||||||
}
|
}
|
||||||
@ -68,7 +56,7 @@
|
|||||||
$standings = [];
|
$standings = [];
|
||||||
|
|
||||||
foreach ($usernames as $username) {
|
foreach ($usernames as $username) {
|
||||||
$user = queryUser($username);
|
$user = UOJUser::query($username);
|
||||||
$row = ['total_score' => 0];
|
$row = ['total_score' => 0];
|
||||||
$scores = [];
|
$scores = [];
|
||||||
|
|
||||||
@ -79,13 +67,13 @@
|
|||||||
|
|
||||||
$cond = "submitter = '{$user['username']}' AND unix_timestamp(submit_time) <= " . $submission_end_time->getTimestamp();
|
$cond = "submitter = '{$user['username']}' AND unix_timestamp(submit_time) <= " . $submission_end_time->getTimestamp();
|
||||||
|
|
||||||
foreach ($problem_ids as $problem_id) {
|
foreach ($problems as $problem_id) {
|
||||||
$submission = DB::selectFirst("SELECT id, score FROM submissions WHERE problem_id = $problem_id AND $cond ORDER BY score DESC, id DESC");
|
$submission = DB::selectFirst("SELECT id, score FROM submissions WHERE problem_id = $problem_id AND $cond ORDER BY score DESC, id DESC");
|
||||||
|
|
||||||
if ($submission) {
|
if ($submission) {
|
||||||
$row['scores'][] = [
|
$row['scores'][] = [
|
||||||
'submission_id' => $submission['id'],
|
'submission_id' => (int)$submission['id'],
|
||||||
'score' => intval($submission['score']),
|
'score' => (int)$submission['score'],
|
||||||
];
|
];
|
||||||
$row['total_score'] += $submission['score'];
|
$row['total_score'] += $submission['score'];
|
||||||
} else {
|
} else {
|
||||||
@ -96,7 +84,7 @@
|
|||||||
$standings[] = $row;
|
$standings[] = $row;
|
||||||
}
|
}
|
||||||
|
|
||||||
usort($standings, function($lhs, $rhs) {
|
usort($standings, function ($lhs, $rhs) {
|
||||||
if ($lhs['total_score'] != $rhs['total_score']) {
|
if ($lhs['total_score'] != $rhs['total_score']) {
|
||||||
return $rhs['total_score'] - $lhs['total_score'];
|
return $rhs['total_score'] - $lhs['total_score'];
|
||||||
}
|
}
|
||||||
@ -105,29 +93,26 @@
|
|||||||
});
|
});
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div id="standings"></div>
|
<div id="standings"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var n_problems = <?= $n_problems ?>;
|
var problems = <?= json_encode($problems) ?>;
|
||||||
var max_total_score = <?= $n_problems * 100 ?>;
|
var standings = <?= json_encode($standings) ?>;
|
||||||
var standings = <?= json_encode($standings) ?>;
|
|
||||||
|
|
||||||
$('#standings').long_table(
|
$('#standings').long_table(
|
||||||
standings,
|
standings,
|
||||||
1,
|
1,
|
||||||
'<tr>' +
|
'<tr>' +
|
||||||
'<th style="width:10em"><?= UOJLocale::get('username') ?></th>' +
|
'<th style="width:10em"><?= UOJLocale::get('username') ?></th>' +
|
||||||
'<th style="width:2em"><?= UOJLocale::get('contests::total score') ?></th>' +
|
'<th style="width:2em"><?= UOJLocale::get('contests::total score') ?></th>' +
|
||||||
<?php foreach ($problem_ids as $problem_id): ?>
|
$.map(problems, function(problem, idx) {
|
||||||
'<th style="width:2em">' +
|
return '<th style="width:2em"><a href="/problem/' + problem + '">#' + problem + '</a></th>';
|
||||||
'<a class="text-decoration-none" href="<?= HTML::url('/problem/' . $problem_id) ?>">#<?= $problem_id ?></a>' +
|
}).join('') +
|
||||||
'</th>' +
|
|
||||||
<?php endforeach ?>
|
|
||||||
'</tr>',
|
'</tr>',
|
||||||
function(row) {
|
function(row) {
|
||||||
var col_tr = '';
|
var col_tr = '';
|
||||||
|
|
||||||
if (row['total_score'] == max_total_score) {
|
if (row['total_score'] == problems.length * 100) {
|
||||||
col_tr += '<tr class="table-success">';
|
col_tr += '<tr class="table-success">';
|
||||||
} else {
|
} else {
|
||||||
col_tr += '<tr>';
|
col_tr += '<tr>';
|
||||||
@ -135,7 +120,7 @@ $('#standings').long_table(
|
|||||||
|
|
||||||
col_tr += '<td>' + getUserLink(row['user']['username'], row['user']['realname']) + '</td>';
|
col_tr += '<td>' + getUserLink(row['user']['username'], row['user']['realname']) + '</td>';
|
||||||
col_tr += '<td>' +
|
col_tr += '<td>' +
|
||||||
'<span class="uoj-score" data-max="' + max_total_score + '" style="color:' + getColOfScore(row['total_score'] / n_problems) + '">' + row['total_score'] + '</span>' +
|
'<span class="uoj-score" data-max="' + (problems.length * 100) + '" style="color:' + getColOfScore(row['total_score'] / problems.length) + '">' + row['total_score'] + '</span>' +
|
||||||
'</td>';
|
'</td>';
|
||||||
for (var i = 0; i < row['scores'].length; i++) {
|
for (var i = 0; i < row['scores'].length; i++) {
|
||||||
var col = row['scores'][i];
|
var col = row['scores'][i];
|
||||||
@ -156,8 +141,7 @@ $('#standings').long_table(
|
|||||||
col_tr += '</tr>';
|
col_tr += '</tr>';
|
||||||
|
|
||||||
return col_tr;
|
return col_tr;
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
div_classes: ['card', 'my-3', 'table-responsive', 'text-center'],
|
div_classes: ['card', 'my-3', 'table-responsive', 'text-center'],
|
||||||
table_classes: ['table', 'uoj-table', 'table-bordered', 'mb-0'],
|
table_classes: ['table', 'uoj-table', 'table-bordered', 'mb-0'],
|
||||||
page_len: 50,
|
page_len: 50,
|
||||||
@ -171,19 +155,17 @@ $('#standings').long_table(
|
|||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- end left col -->
|
<!-- end left col -->
|
||||||
|
|
||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
|
||||||
<!-- right col -->
|
|
||||||
|
|
||||||
<?php uojIncludeView('sidebar', ['assignments_hidden' => true]); ?>
|
|
||||||
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
|
<!-- right col -->
|
||||||
|
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||||
|
<?php uojIncludeView('sidebar', ['assignments_hidden' => true]) ?>
|
||||||
|
</aside>
|
||||||
|
<!-- end right col -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check()) {
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
requirePHPLib('data');
|
requirePHPLib('data');
|
||||||
|
|
||||||
$group_id = $_GET['id'];
|
$group_id = $_GET['id'];
|
||||||
if (!validateUInt($group_id) || !($group = queryGroup($group_id))) {
|
if (!validateUInt($group_id) || !($group = queryGroup($group_id))) {
|
||||||
become404Page();
|
become404Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSuperUser($myUser)) {
|
if (!isSuperUser($myUser)) {
|
||||||
become403Page();
|
become403Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_GET['tab'])) {
|
if (isset($_GET['tab'])) {
|
||||||
$cur_tab = $_GET['tab'];
|
$cur_tab = $_GET['tab'];
|
||||||
} else {
|
} else {
|
||||||
$cur_tab = 'profile';
|
$cur_tab = 'profile';
|
||||||
}
|
}
|
||||||
|
|
||||||
$tabs_info = [
|
$tabs_info = [
|
||||||
'profile' => [
|
'profile' => [
|
||||||
'name' => '基本信息',
|
'name' => '基本信息',
|
||||||
'url' => "/group/{$group['id']}/manage/profile",
|
'url' => "/group/{$group['id']}/manage/profile",
|
||||||
@ -36,16 +36,20 @@
|
|||||||
'name' => '用户管理',
|
'name' => '用户管理',
|
||||||
'url' => "/group/{$group['id']}/manage/users",
|
'url' => "/group/{$group['id']}/manage/users",
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!isset($tabs_info[$cur_tab])) {
|
if (!isset($tabs_info[$cur_tab])) {
|
||||||
become404Page();
|
become404Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cur_tab == 'profile') {
|
if ($cur_tab == 'profile') {
|
||||||
$update_profile_form = new UOJBs4Form('update_profile');
|
$update_profile_form = new UOJBs4Form('update_profile');
|
||||||
$update_profile_form->addVInput('name', 'text', '名称', $group['title'],
|
$update_profile_form->addVInput(
|
||||||
function($title, &$vdata) {
|
'name',
|
||||||
|
'text',
|
||||||
|
'名称',
|
||||||
|
$group['title'],
|
||||||
|
function ($title, &$vdata) {
|
||||||
if ($title == '') {
|
if ($title == '') {
|
||||||
return '名称不能为空';
|
return '名称不能为空';
|
||||||
}
|
}
|
||||||
@ -69,8 +73,11 @@
|
|||||||
'0' => '公开',
|
'0' => '公开',
|
||||||
'1' => '隐藏',
|
'1' => '隐藏',
|
||||||
], '可见性', $group['is_hidden']);
|
], '可见性', $group['is_hidden']);
|
||||||
$update_profile_form->addVTextArea('announcement', '公告', $group['announcement'],
|
$update_profile_form->addVTextArea(
|
||||||
function($announcement, &$vdata) {
|
'announcement',
|
||||||
|
'公告',
|
||||||
|
$group['announcement'],
|
||||||
|
function ($announcement, &$vdata) {
|
||||||
if (strlen($announcement) > 3000) {
|
if (strlen($announcement) > 3000) {
|
||||||
return '公告过长';
|
return '公告过长';
|
||||||
}
|
}
|
||||||
@ -78,8 +85,10 @@
|
|||||||
$vdata['announcement'] = $announcement;
|
$vdata['announcement'] = $announcement;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}, null);
|
},
|
||||||
$update_profile_form->handle = function($vdata) use ($group) {
|
null
|
||||||
|
);
|
||||||
|
$update_profile_form->handle = function ($vdata) use ($group) {
|
||||||
$esc_title = DB::escape($vdata['title']);
|
$esc_title = DB::escape($vdata['title']);
|
||||||
$is_hidden = $_POST['is_hidden'];
|
$is_hidden = $_POST['is_hidden'];
|
||||||
$esc_announcement = DB::escape($vdata['announcement']);
|
$esc_announcement = DB::escape($vdata['announcement']);
|
||||||
@ -110,7 +119,7 @@ EOD);
|
|||||||
$update_profile_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
$update_profile_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
||||||
$update_profile_form->submit_button_config['text'] = '更新';
|
$update_profile_form->submit_button_config['text'] = '更新';
|
||||||
$update_profile_form->runAtServer();
|
$update_profile_form->runAtServer();
|
||||||
} elseif ($cur_tab == 'assignments') {
|
} elseif ($cur_tab == 'assignments') {
|
||||||
if (isset($_POST['submit-remove_assignment']) && $_POST['submit-remove_assignment'] == 'remove_assignment') {
|
if (isset($_POST['submit-remove_assignment']) && $_POST['submit-remove_assignment'] == 'remove_assignment') {
|
||||||
$list_id = $_POST['list_id'];
|
$list_id = $_POST['list_id'];
|
||||||
|
|
||||||
@ -128,21 +137,27 @@ EOD);
|
|||||||
}
|
}
|
||||||
|
|
||||||
$add_new_assignment_form = new UOJBs4Form('add_new_assignment');
|
$add_new_assignment_form = new UOJBs4Form('add_new_assignment');
|
||||||
$add_new_assignment_form->addVInput('new_assignment_list_id', 'text', '题单 ID', '',
|
$add_new_assignment_form->addVInput(
|
||||||
|
'new_assignment_list_id',
|
||||||
|
'text',
|
||||||
|
'题单 ID',
|
||||||
|
'',
|
||||||
function ($list_id, &$vdata) use ($group) {
|
function ($list_id, &$vdata) use ($group) {
|
||||||
if (!validateUInt($list_id)) {
|
if (!validateUInt($list_id)) {
|
||||||
return '题单 ID 不合法';
|
return '题单 ID 不合法';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!($list = queryProblemList($list_id))) {
|
$list = UOJList::query($list_id);
|
||||||
|
|
||||||
|
if (!$list) {
|
||||||
return '题单不存在';
|
return '题单不存在';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($list['is_hidden'] != 0) {
|
if ($list->info['is_hidden']) {
|
||||||
return '题单是隐藏的';
|
return '题单是隐藏的';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queryAssignmentByGroupListID($group['id'], $list_id)) {
|
if (queryAssignmentByGroupListID($group['id'], $list->info['id'])) {
|
||||||
return '该题单已经在作业中';
|
return '该题单已经在作业中';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +170,11 @@ EOD);
|
|||||||
$default_end_time = new DateTime();
|
$default_end_time = new DateTime();
|
||||||
$default_end_time->setTime(22, 30, 0);
|
$default_end_time->setTime(22, 30, 0);
|
||||||
$default_end_time->add(new DateInterval("P7D"));
|
$default_end_time->add(new DateInterval("P7D"));
|
||||||
$add_new_assignment_form->addVInput('new_assignment_end_time', 'text', '截止时间', $default_end_time->format('Y-m-d H:i'),
|
$add_new_assignment_form->addVInput(
|
||||||
|
'new_assignment_end_time',
|
||||||
|
'text',
|
||||||
|
'截止时间',
|
||||||
|
$default_end_time->format('Y-m-d H:i'),
|
||||||
function ($end_time, &$vdata) {
|
function ($end_time, &$vdata) {
|
||||||
try {
|
try {
|
||||||
$vdata['end_time'] = new DateTime($end_time);
|
$vdata['end_time'] = new DateTime($end_time);
|
||||||
@ -167,7 +186,7 @@ EOD);
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_new_assignment_form->handle = function(&$vdata) use ($group) {
|
$add_new_assignment_form->handle = function (&$vdata) use ($group) {
|
||||||
$esc_end_time = DB::escape($vdata['end_time']->format('Y-m-d H:i:s'));
|
$esc_end_time = DB::escape($vdata['end_time']->format('Y-m-d H:i:s'));
|
||||||
|
|
||||||
DB::insert("insert into groups_assignments (group_id, list_id, end_time) values ({$group['id']}, '{$vdata['list_id']}', '{$esc_end_time}')");
|
DB::insert("insert into groups_assignments (group_id, list_id, end_time) values ({$group['id']}, '{$vdata['list_id']}', '{$esc_end_time}')");
|
||||||
@ -202,7 +221,7 @@ EOD);
|
|||||||
|
|
||||||
$hidden_time = new DateTime();
|
$hidden_time = new DateTime();
|
||||||
$hidden_time->sub(new DateInterval('P7D'));
|
$hidden_time->sub(new DateInterval('P7D'));
|
||||||
} elseif ($cur_tab == 'users') {
|
} elseif ($cur_tab == 'users') {
|
||||||
if (isset($_POST['submit-remove_user']) && $_POST['submit-remove_user'] == 'remove_user') {
|
if (isset($_POST['submit-remove_user']) && $_POST['submit-remove_user'] == 'remove_user') {
|
||||||
$username = $_POST['remove_username'];
|
$username = $_POST['remove_username'];
|
||||||
|
|
||||||
@ -224,7 +243,11 @@ EOD);
|
|||||||
}
|
}
|
||||||
|
|
||||||
$add_new_user_form = new UOJBs4Form('add_new_user');
|
$add_new_user_form = new UOJBs4Form('add_new_user');
|
||||||
$add_new_user_form->addVInput('new_username', 'text', '用户名', '',
|
$add_new_user_form->addVInput(
|
||||||
|
'new_username',
|
||||||
|
'text',
|
||||||
|
'用户名',
|
||||||
|
'',
|
||||||
function ($username, &$vdata) {
|
function ($username, &$vdata) {
|
||||||
global $group_id;
|
global $group_id;
|
||||||
|
|
||||||
@ -248,7 +271,7 @@ EOD);
|
|||||||
);
|
);
|
||||||
$add_new_user_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
$add_new_user_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
||||||
$add_new_user_form->submit_button_config['text'] = '添加';
|
$add_new_user_form->submit_button_config['text'] = '添加';
|
||||||
$add_new_user_form->handle = function(&$vdata) use ($group) {
|
$add_new_user_form->handle = function (&$vdata) use ($group) {
|
||||||
DB::insert("insert into groups_users (group_id, username) values ({$group['id']}, '{$vdata['username']}')");
|
DB::insert("insert into groups_users (group_id, username) values ({$group['id']}, '{$vdata['username']}')");
|
||||||
|
|
||||||
dieWithJsonData(['status' => 'success', 'message' => '已将用户名为 ' . $vdata['username'] . ' 的用户添加到本小组。']);
|
dieWithJsonData(['status' => 'success', 'message' => '已将用户名为 ' . $vdata['username'] . ' 的用户添加到本小组。']);
|
||||||
@ -273,8 +296,8 @@ function(res) {
|
|||||||
}
|
}
|
||||||
EOD);
|
EOD);
|
||||||
$add_new_user_form->runAtServer();
|
$add_new_user_form->runAtServer();
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader('管理 - ' . $group['title']); ?>
|
<?php echoUOJPageHeader('管理 - ' . $group['title']); ?>
|
||||||
|
|
||||||
<h1 class="d-block d-md-inline-block">
|
<h1 class="d-block d-md-inline-block">
|
||||||
@ -284,25 +307,22 @@ EOD);
|
|||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
|
|
||||||
<?= HTML::navListGroup($tabs_info, $cur_tab) ?>
|
<?= HTML::navListGroup($tabs_info, $cur_tab) ?>
|
||||||
|
|
||||||
<a
|
<a class="btn btn-light d-block mt-2 w-100 text-start text-primary" style="--bs-btn-hover-bg: #d3d4d570; --bs-btn-hover-border-color: transparent;" href="<?= HTML::url("/group/{$group['id']}") ?>">
|
||||||
class="btn btn-light d-block mt-2 w-100 text-start text-primary"
|
|
||||||
style="--bs-btn-hover-bg: #d3d4d570; --bs-btn-hover-border-color: transparent;"
|
|
||||||
href="<?= HTML::url("/group/{$group['id']}") ?>">
|
|
||||||
<i class="bi bi-arrow-left"></i> 返回
|
<i class="bi bi-arrow-left"></i> 返回
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- end left col -->
|
<!-- end left col -->
|
||||||
|
|
||||||
<!-- right col -->
|
<!-- right col -->
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<?php if ($cur_tab == 'profile'): ?>
|
<?php if ($cur_tab == 'profile') : ?>
|
||||||
<div class="card mt-3 mt-md-0">
|
<div class="card mt-3 mt-md-0">
|
||||||
<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>
|
||||||
<div class="row row-cols-1 row-cols-md-2">
|
<div class="row row-cols-1 row-cols-md-2">
|
||||||
@ -318,9 +338,9 @@ EOD);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php elseif ($cur_tab == 'assignments'): ?>
|
<?php elseif ($cur_tab == 'assignments') : ?>
|
||||||
<div class="card mt-3 mt-md-0">
|
<div class="card mt-3 mt-md-0">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<ul class="nav nav-tabs card-header-tabs" role="tablist">
|
<ul class="nav nav-tabs card-header-tabs" role="tablist">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
@ -349,15 +369,15 @@ EOD);
|
|||||||
<th style="width:8em">操作</th>
|
<th style="width:8em">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
EOD,
|
EOD,
|
||||||
function($row) use ($group, $hidden_time) {
|
function ($row) use ($group, $hidden_time) {
|
||||||
$list = queryProblemList($row['list_id']);
|
$list = UOJList::query($row['list_id']);
|
||||||
$end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']);
|
$end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']);
|
||||||
|
|
||||||
echo '<tr>';
|
echo '<tr>';
|
||||||
echo '<td class="text-center">', $list['id'], '</td>';
|
echo '<td class="text-center">', $list->info['id'], '</td>';
|
||||||
echo '<td>';
|
echo '<td>';
|
||||||
echo '<a class="text-decoration-none" href="/group/', $group['id'], '/assignment/', $list['id'],'">', HTML::escape($list['title']), '</a>';
|
echo '<a class="text-decoration-none" href="/group/', $group['id'], '/assignment/', $list->info['id'], '">', $list->info['title'], '</a>';
|
||||||
if ($list['is_hidden']) {
|
if ($list->info['is_hidden']) {
|
||||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
||||||
}
|
}
|
||||||
echo '</td>';
|
echo '</td>';
|
||||||
@ -370,10 +390,10 @@ EOD,
|
|||||||
}
|
}
|
||||||
echo '<td>', $end_time->format('Y-m-d H:i:s'), '</td>';
|
echo '<td>', $end_time->format('Y-m-d H:i:s'), '</td>';
|
||||||
echo '<td>';
|
echo '<td>';
|
||||||
echo ' <a class="text-decoration-none d-inline-block align-middle" href="/list/', $list['id'], '/edit">编辑</a> ';
|
echo ' <a class="text-decoration-none d-inline-block align-middle" href="/list/', $list->info['id'], '/manage">编辑</a> ';
|
||||||
echo ' <form class="d-inline-block" method="POST" onsubmit=\'return confirm("你真的要移除这份作业(题单 #', $row['id'], ')吗?移除作业不会删除题单。")\'>'
|
echo ' <form class="d-inline-block" method="POST" onsubmit=\'return confirm("你真的要移除这份作业(题单 #', $list->info['id'], ')吗?移除作业不会删除题单。")\'>'
|
||||||
. '<input type="hidden" name="_token" value="' . crsf_token() . '">'
|
. '<input type="hidden" name="_token" value="' . crsf_token() . '">'
|
||||||
. '<input type="hidden" name="list_id" value="' . $list['id'] . '">'
|
. '<input type="hidden" name="list_id" value="' . $list->info['id'] . '">'
|
||||||
. '<button class="btn btn-link text-danger text-decoration-none p-0" type="submit" name="submit-remove_assignment" value="remove_assignment">移除</button>'
|
. '<button class="btn btn-link text-danger text-decoration-none p-0" type="submit" name="submit-remove_assignment" value="remove_assignment">移除</button>'
|
||||||
. '</form>';
|
. '</form>';
|
||||||
echo '</td>';
|
echo '</td>';
|
||||||
@ -407,9 +427,9 @@ EOD,
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php elseif ($cur_tab == 'users'): ?>
|
<?php elseif ($cur_tab == 'users') : ?>
|
||||||
<div class="card mt-3 mt-md-0">
|
<div class="card mt-3 mt-md-0">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<ul class="nav nav-tabs card-header-tabs" role="tablist">
|
<ul class="nav nav-tabs card-header-tabs" role="tablist">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
@ -435,7 +455,7 @@ EOD,
|
|||||||
<th>操作</th>
|
<th>操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
EOD,
|
EOD,
|
||||||
function($row) use ($group) {
|
function ($row) use ($group) {
|
||||||
echo '<tr>';
|
echo '<tr>';
|
||||||
echo '<td>', getUserLink($row['username']), '</td>';
|
echo '<td>', getUserLink($row['username']), '</td>';
|
||||||
echo '<td>';
|
echo '<td>';
|
||||||
@ -472,9 +492,9 @@ EOD,
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -1,94 +1,69 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check()) {
|
|
||||||
redirectToLogin();
|
requireLib('bootstrap5');
|
||||||
|
requireLib('mathjax');
|
||||||
|
requirePHPLib('form');
|
||||||
|
requirePHPLib('judger');
|
||||||
|
requirePHPLib('data');
|
||||||
|
|
||||||
|
Auth::check() || redirectToLogin();
|
||||||
|
UOJList::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
|
UOJList::cur()->userCanView(Auth::user(), ['ensure' => true]);
|
||||||
|
|
||||||
|
function getProblemTR($info) {
|
||||||
|
$problem = new UOJProblem($info);
|
||||||
|
|
||||||
|
$html = HTML::tag_begin('tr', ['class' => 'text-center']);
|
||||||
|
$html .= HTML::tag('td', ['class' => $info['submission_id'] ? 'table-success' : ''], "#{$info['id']}");
|
||||||
|
$html .= HTML::tag_begin('td', ['class' => 'text-start']);
|
||||||
|
$html .= $problem->getLink(['with' => 'none']);
|
||||||
|
if ($problem->isUserOwnProblem(Auth::user())) {
|
||||||
|
$html .= ' <span class="badge text-white bg-info">' . UOJLocale::get('problems::my problem') . '</span> ';
|
||||||
}
|
}
|
||||||
|
if ($info['is_hidden']) {
|
||||||
requireLib('bootstrap5');
|
$html .= ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ' . UOJLocale::get('hidden') . '</span> ';
|
||||||
requireLib('mathjax');
|
|
||||||
requirePHPLib('form');
|
|
||||||
requirePHPLib('judger');
|
|
||||||
requirePHPLib('data');
|
|
||||||
|
|
||||||
$list_id = $_GET['id'];
|
|
||||||
|
|
||||||
if (!validateUInt($list_id) || !($list = queryProblemList($list_id))) {
|
|
||||||
become404Page();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($list['is_hidden'] && !isSuperUser($myUser)) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
function echoProblem($problem) {
|
|
||||||
global $myUser;
|
|
||||||
|
|
||||||
if (isProblemVisibleToUser($problem, $myUser)) {
|
|
||||||
echo '<tr class="text-center">';
|
|
||||||
if ($problem['submission_id']) {
|
|
||||||
echo '<td class="table-success">';
|
|
||||||
} else {
|
|
||||||
echo '<td>';
|
|
||||||
}
|
|
||||||
echo '#', $problem['id'], '</td>';
|
|
||||||
echo '<td class="text-start">';
|
|
||||||
echo '<a class="text-decoration-none" href="/problem/', $problem['id'], '">', $problem['title'], '</a>';
|
|
||||||
|
|
||||||
if ($problem['uploader'] == $myUser['username']) {
|
|
||||||
echo ' <span class="badge text-white bg-info">', UOJLocale::get('problems::my problem') ,'</span> ';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($problem['is_hidden']) {
|
|
||||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_COOKIE['show_tags_mode'])) {
|
if (isset($_COOKIE['show_tags_mode'])) {
|
||||||
foreach (queryProblemTags($problem['id']) as $tag) {
|
foreach ($problem->queryTags() as $tag) {
|
||||||
echo ' <a class="uoj-problem-tag my-1">';
|
$html .= ' <a class="uoj-problem-tag">' . '<span class="badge text-bg-secondary">' . HTML::escape($tag) . '</span>' . '</a> ';
|
||||||
echo '<span class="badge bg-secondary">', HTML::escape($tag), '</span>';
|
|
||||||
echo '</a> ';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
echo '</td>';
|
$html .= HTML::tag_end('td');
|
||||||
if (isset($_COOKIE['show_submit_mode'])) {
|
if (isset($_COOKIE['show_submit_mode'])) {
|
||||||
$perc = $problem['submit_num'] > 0 ? round(100 * $problem['ac_num'] / $problem['submit_num']) : 0;
|
$perc = $info['submit_num'] > 0 ? round(100 * $info['ac_num'] / $info['submit_num']) : 0;
|
||||||
echo <<<EOD
|
$html .= '<td><a href="/submissions?problem_id=' . $info['id'] . '&min_score=100&max_score=100">×' . $info['ac_num'] . '</a></td>';
|
||||||
<td><a href="/submissions?problem_id={$problem['id']}&min_score=100&max_score=100">×{$problem['ac_num']}</a></td>
|
$html .= '<td><a href="/submissions?problem_id=' . $info['id'] . '">×' . $info['submit_num'] . '</a></td>';
|
||||||
<td><a href="/submissions?problem_id={$problem['id']}">×{$problem['submit_num']}</a></td>
|
$html .= '<td>';
|
||||||
<td>
|
$html .= '<div class="progress bot-buffer-no">';
|
||||||
<div class="progress bot-buffer-no">
|
$html .= '<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="' . $perc . '" aria-valuemin="0" aria-valuemax="100" style="width: ' . $perc . '%; min-width: 20px;">';
|
||||||
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="$perc" aria-valuemin="0" aria-valuemax="100" style="width: $perc%; min-width: 20px;">{$perc}%</div>
|
$html .= $perc . '%';
|
||||||
</div>
|
$html .= '</div>';
|
||||||
</td>
|
$html .= '</div>';
|
||||||
EOD;
|
$html .= '</td>';
|
||||||
}
|
}
|
||||||
if (isset($_COOKIE['show_difficulty'])) {
|
if (isset($_COOKIE['show_difficulty'])) {
|
||||||
$extra_config = getProblemExtraConfig($problem);
|
$html .= HTML::tag('td', [], $problem->getExtraConfig('difficulty'));
|
||||||
if ($extra_config['difficulty'] == 0) {
|
|
||||||
echo "<td></td>";
|
|
||||||
} else {
|
|
||||||
echo "<td>{$extra_config['difficulty']}</td>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
echo '<td class="text-start">', ClickZans::getBlock('P', $problem['id'], $problem['zan'], null, false), '</td>';
|
|
||||||
echo '</tr>';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
$html .= HTML::tag('td', [], ClickZans::getCntBlock($problem->info['zan']));
|
||||||
|
$html .= HTML::tag_end('tr');
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
$header = '<tr>';
|
$header = '<tr>';
|
||||||
$header .= '<th class="text-center" style="width:5em;">ID</th>';
|
$header .= '<th class="text-center" style="width:5em;">ID</th>';
|
||||||
$header .= '<th>'.UOJLocale::get('problems::problem').'</th>';
|
$header .= '<th>' . UOJLocale::get('problems::problem') . '</th>';
|
||||||
if (isset($_COOKIE['show_submit_mode'])) {
|
if (isset($_COOKIE['show_submit_mode'])) {
|
||||||
$header .= '<th class="text-center" style="width:4em">'.UOJLocale::get('problems::ac').'</th>';
|
$header .= '<th class="text-center" style="width:4em">' . UOJLocale::get('problems::ac') . '</th>';
|
||||||
$header .= '<th class="text-center" style="width:4em">'.UOJLocale::get('problems::submit').'</th>';
|
$header .= '<th class="text-center" style="width:4em">' . UOJLocale::get('problems::submit') . '</th>';
|
||||||
$header .= '<th class="text-center" style="width:125px;">'.UOJLocale::get('problems::ac ratio').'</th>';
|
$header .= '<th class="text-center" style="width:125px;">' . UOJLocale::get('problems::ac ratio') . '</th>';
|
||||||
}
|
}
|
||||||
if (isset($_COOKIE['show_difficulty'])) {
|
if (isset($_COOKIE['show_difficulty'])) {
|
||||||
$header .= '<th class="text-center" style="width:3em;">'.UOJLocale::get('problems::difficulty').'</th>';
|
$header .= '<th class="text-center" style="width:3em;">' . UOJLocale::get('problems::difficulty') . '</th>';
|
||||||
}
|
}
|
||||||
$header .= '<th class="text-center" style="width:100px;">'.UOJLocale::get('appraisal').'</th>';
|
$header .= '<th class="text-center" style="width:50px;">' . UOJLocale::get('appraisal') . '</th>';
|
||||||
$header .= '</tr>';
|
$header .= '</tr>';
|
||||||
|
|
||||||
$pag_config = [
|
$pag_config = [
|
||||||
'page_len' => 40,
|
'page_len' => 40,
|
||||||
'col_names' => [
|
'col_names' => [
|
||||||
'best_ac_submissions.submission_id as submission_id',
|
'best_ac_submissions.submission_id as submission_id',
|
||||||
@ -101,146 +76,154 @@ EOD;
|
|||||||
'problems.extra_config as extra_config',
|
'problems.extra_config as extra_config',
|
||||||
'problems.uploader as uploader',
|
'problems.uploader as uploader',
|
||||||
],
|
],
|
||||||
'table_name' => "problems left join best_ac_submissions on best_ac_submissions.submitter = '{$myUser['username']}' and problems.id = best_ac_submissions.problem_id inner join lists_problems lp on lp.list_id = {$list_id} and lp.problem_id = problems.id",
|
'table_name' => [
|
||||||
|
"problems",
|
||||||
|
"left join best_ac_submissions",
|
||||||
|
"on", [
|
||||||
|
"best_ac_submissions.submitter" => Auth::id(),
|
||||||
|
"problems.id" => DB::raw("best_ac_submissions.problem_id")
|
||||||
|
],
|
||||||
|
"inner join lists_problems",
|
||||||
|
"on", [
|
||||||
|
"lists_problems.list_id" => UOJList::info('id'),
|
||||||
|
"lists_problems.problem_id" => DB::raw("problems.id"),
|
||||||
|
],
|
||||||
|
],
|
||||||
'cond' => '1',
|
'cond' => '1',
|
||||||
'tail' => 'ORDER BY `id` ASC',
|
'tail' => "order by id asc",
|
||||||
];
|
'page_len' => 40,
|
||||||
$pag = new Paginator($pag_config);
|
'post_filter' => function ($problem) {
|
||||||
?>
|
return (new UOJProblem($problem))->userCanView(Auth::user());
|
||||||
|
}
|
||||||
|
];
|
||||||
|
$pag = new Paginator($pag_config);
|
||||||
|
?>
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('problems lists')); ?>
|
<?php echoUOJPageHeader(UOJLocale::get('problems lists')); ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<!-- left col -->
|
||||||
<!-- left col -->
|
<div class="col-lg-9">
|
||||||
<div class="col-lg-9">
|
<!-- title container -->
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
<!-- title container -->
|
<h1>
|
||||||
<div class="d-flex justify-content-between">
|
<?= UOJList::info('title') ?>
|
||||||
|
<span class="fs-5">(ID: #<?= UOJList::info('id') ?>)</span>
|
||||||
<h1>
|
<?php if (UOJList::info('is_hidden')) : ?>
|
||||||
<?= $list['title'] ?>
|
|
||||||
<span class="fs-5">(ID: #<?= $list['id'] ?>)</span>
|
|
||||||
<?php if ($list['is_hidden']): ?>
|
|
||||||
<span class="badge text-bg-danger fs-6">
|
<span class="badge text-bg-danger fs-6">
|
||||||
<i class="bi bi-eye-slash-fill"></i>
|
<i class="bi bi-eye-slash-fill"></i>
|
||||||
<?= UOJLocale::get('hidden') ?>
|
<?= UOJLocale::get('hidden') ?>
|
||||||
</span>
|
</span>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<?php if (isSuperUser($myUser)): ?>
|
<?php if (UOJList::cur()->userCanManage(Auth::user())) : ?>
|
||||||
<div class="text-end">
|
<div class="text-end">
|
||||||
<a class="btn btn-primary" href="/list/<?= $list['id'] ?>/edit" role="button">
|
<a class="btn btn-primary" href="/list/<?= UOJList::info('id') ?>/manage" role="button">
|
||||||
<?= UOJLocale::get('problems::manage') ?>
|
<?= UOJLocale::get('problems::manage') ?>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!-- end title container -->
|
|
||||||
|
|
||||||
<!-- description -->
|
|
||||||
<div class="card my-2">
|
|
||||||
<div class="card-body">
|
|
||||||
<h2 class="h4 mb-3">题单简介</h2>
|
|
||||||
<?php $description = HTML::purifier()->purify(HTML::parsedown()->text($list['description'])) ?>
|
|
||||||
<?php if ($description): ?>
|
|
||||||
<?= $description ?>
|
|
||||||
<?php else: ?>
|
|
||||||
<p class="text-muted">暂无简介</p>
|
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<!-- end title container -->
|
||||||
|
|
||||||
<div class="row">
|
<!-- description -->
|
||||||
|
<div class="card my-2">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="h4 mb-3">题单简介</h2>
|
||||||
|
<div class="markdown-body">
|
||||||
|
<?= UOJList::cur()->queryContent()['content'] ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
<div class="col-sm-4 col-12"></div>
|
<div class="col-sm-4 col-12"></div>
|
||||||
<div class="text-end p-2 col-12 col-sm-8">
|
<div class="text-end p-2 col-12 col-sm-8">
|
||||||
<div class="form-check d-inline-block me-2">
|
<div class="form-check d-inline-block me-2">
|
||||||
<input type="checkbox" id="input-show_tags_mode" class="form-check-input"
|
<input type="checkbox" id="input-show_tags_mode" class="form-check-input" <?= isset($_COOKIE['show_tags_mode']) ? 'checked="checked" ' : '' ?> />
|
||||||
<?= isset($_COOKIE['show_tags_mode']) ? 'checked="checked" ': ''?>
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="input-show_tags_mode">
|
<label class="form-check-label" for="input-show_tags_mode">
|
||||||
<?= UOJLocale::get('problems::show tags') ?>
|
<?= UOJLocale::get('problems::show tags') ?>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check d-inline-block">
|
<div class="form-check d-inline-block">
|
||||||
<input type="checkbox" id="input-show_submit_mode" class="form-check-input"
|
<input type="checkbox" id="input-show_submit_mode" class="form-check-input" <?= isset($_COOKIE['show_submit_mode']) ? 'checked="checked" ' : '' ?> />
|
||||||
<?= isset($_COOKIE['show_submit_mode']) ? 'checked="checked" ': ''?>
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="input-show_submit_mode">
|
<label class="form-check-label" for="input-show_submit_mode">
|
||||||
<?= UOJLocale::get('problems::show statistics') ?>
|
<?= UOJLocale::get('problems::show statistics') ?>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check d-inline-block">
|
<div class="form-check d-inline-block">
|
||||||
<input type="checkbox" id="input-show_difficulty" class="form-check-input"
|
<input type="checkbox" id="input-show_difficulty" class="form-check-input" <?= isset($_COOKIE['show_difficulty']) ? 'checked="checked" ' : '' ?> />
|
||||||
<?= isset($_COOKIE['show_difficulty']) ? 'checked="checked" ': ''?>
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="input-show_difficulty">
|
<label class="form-check-label" for="input-show_difficulty">
|
||||||
<?= UOJLocale::get('problems::show difficulty') ?>
|
<?= UOJLocale::get('problems::show difficulty') ?>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$('#input-show_tags_mode').click(function() {
|
$('#input-show_tags_mode').click(function() {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
$.cookie('show_tags_mode', '', {path: '/'});
|
$.cookie('show_tags_mode', '', {
|
||||||
|
path: '/'
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
$.removeCookie('show_tags_mode', {path: '/'});
|
$.removeCookie('show_tags_mode', {
|
||||||
|
path: '/'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
$('#input-show_submit_mode').click(function() {
|
$('#input-show_submit_mode').click(function() {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
$.cookie('show_submit_mode', '', {path: '/'});
|
$.cookie('show_submit_mode', '', {
|
||||||
|
path: '/'
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
$.removeCookie('show_submit_mode', {path: '/'});
|
$.removeCookie('show_submit_mode', {
|
||||||
|
path: '/'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
$('#input-show_difficulty').click(function() {
|
$('#input-show_difficulty').click(function() {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
$.cookie('show_difficulty', '', {path: '/'});
|
$.cookie('show_difficulty', '', {
|
||||||
|
path: '/'
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
$.removeCookie('show_difficulty', {path: '/'});
|
$.removeCookie('show_difficulty', {
|
||||||
|
path: '/'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<?= $pag->pagination() ?>
|
<?= $pag->pagination() ?>
|
||||||
|
|
||||||
<div class="card my-3 table-responsive">
|
<div class="card my-3 table-responsive">
|
||||||
<table class="table uoj-table mb-0">
|
<?=
|
||||||
<thead>
|
HTML::responsive_table($header, $pag->get(), [
|
||||||
<?= $header ?>
|
'table_attr' => [
|
||||||
</thead>
|
'class' => ['table', 'uoj-table', 'mb-0'],
|
||||||
<tbody>
|
],
|
||||||
<?php foreach ($pag->get() as $idx => $row): ?>
|
'tr' => function ($row, $idx) {
|
||||||
<?php echoProblem($row) ?>
|
return getProblemTR($row);
|
||||||
<?php endforeach ?>
|
}
|
||||||
<?php if ($pag->isEmpty()): ?>
|
]);
|
||||||
<tr>
|
?>
|
||||||
<td class="text-center" colspan="233">
|
</div>
|
||||||
<?= UOJLocale::get('none') ?>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php endif ?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?= $pag->pagination() ?>
|
<?= $pag->pagination() ?>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- end left col -->
|
<!-- end left col -->
|
||||||
|
|
||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||||
<?php uojIncludeView('sidebar'); ?>
|
<?php uojIncludeView('sidebar') ?>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,542 +0,0 @@
|
|||||||
<?php
|
|
||||||
if (!Auth::check()) {
|
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
requireLib('bootstrap5');
|
|
||||||
requirePHPLib('form');
|
|
||||||
|
|
||||||
$list_id = $_GET['id'];
|
|
||||||
|
|
||||||
if (!validateUInt($list_id) || !($list = queryProblemList($list_id))) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSuperUser($myUser)) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_GET['tab'])) {
|
|
||||||
$cur_tab = $_GET['tab'];
|
|
||||||
} else {
|
|
||||||
$cur_tab = 'profile';
|
|
||||||
}
|
|
||||||
|
|
||||||
$tabs_info = [
|
|
||||||
'profile' => [
|
|
||||||
'name' => '基本信息',
|
|
||||||
'url' => "/list/{$list['id']}/edit/profile",
|
|
||||||
],
|
|
||||||
'problems' => [
|
|
||||||
'name' => '题目管理',
|
|
||||||
'url' => "/list/{$list['id']}/edit/problems",
|
|
||||||
],
|
|
||||||
'assignments' => [
|
|
||||||
'name' => '对应作业',
|
|
||||||
'url' => "/list/{$list['id']}/edit/assignments",
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
if (!isset($tabs_info[$cur_tab])) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cur_tab == 'profile') {
|
|
||||||
$list_tags = queryProblemListTags($list_id);
|
|
||||||
|
|
||||||
$update_profile_form = new UOJBs4Form('update_profile');
|
|
||||||
$update_profile_form->addVInput('name', 'text', '标题', $list['title'],
|
|
||||||
function($title, &$vdata) {
|
|
||||||
if ($title == '') {
|
|
||||||
return '标题不能为空';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen($title) > 100) {
|
|
||||||
return '标题过长';
|
|
||||||
}
|
|
||||||
|
|
||||||
$title = HTML::escape($title);
|
|
||||||
if ($title === '') {
|
|
||||||
return '无效编码';
|
|
||||||
}
|
|
||||||
|
|
||||||
$vdata['title'] = $title;
|
|
||||||
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
null
|
|
||||||
);
|
|
||||||
$update_profile_form->addVCheckboxes('is_hidden', [
|
|
||||||
'0' => '公开',
|
|
||||||
'1' => '隐藏',
|
|
||||||
], '可见性', $list['is_hidden']);
|
|
||||||
$update_profile_form->addVInput('tags', 'text', '标签(多个标签用逗号隔开)', implode(', ', $list_tags),
|
|
||||||
function($tags_str, &$vdata) {
|
|
||||||
$tags_str = str_replace(',', ',', $tags_str);
|
|
||||||
$tags_raw = explode(',', $tags_str);
|
|
||||||
$tags = [];
|
|
||||||
|
|
||||||
if (count($tags_raw) > 10) {
|
|
||||||
return '不能存在超过 10 个标签';
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($tags_raw as $tag) {
|
|
||||||
$tag = HTML::escape(trim($tag));
|
|
||||||
|
|
||||||
if (strlen($tag) == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen($tag) > 30) {
|
|
||||||
return '标签 “' . $tag .'” 太长';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array($tag, $tags, true)) {
|
|
||||||
return '标签 “' . $tag .'” 重复出现';
|
|
||||||
}
|
|
||||||
|
|
||||||
$tags[] = $tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
$vdata['tags'] = $tags;
|
|
||||||
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
null);
|
|
||||||
$update_profile_form->addVTextArea('description', '描述', $list['description'],
|
|
||||||
function($description, &$vdata) {
|
|
||||||
if (strlen($description) > 3000) {
|
|
||||||
return '描述过长';
|
|
||||||
}
|
|
||||||
|
|
||||||
$vdata['description'] = $description;
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}, null);
|
|
||||||
$update_profile_form->handle = function($vdata) use ($list, $list_tags) {
|
|
||||||
$esc_title = DB::escape($vdata['title']);
|
|
||||||
$is_hidden = $_POST['is_hidden'];
|
|
||||||
$esc_description = DB::escape($vdata['description']);
|
|
||||||
|
|
||||||
DB::update("UPDATE `lists` SET `title` = '$esc_title', `is_hidden` = '$is_hidden', `description` = '$esc_description' WHERE id = {$list['id']}");
|
|
||||||
|
|
||||||
if ($vdata['tags'] !== $list_tags) {
|
|
||||||
DB::delete("DELETE FROM `lists_tags` WHERE `list_id` = {$list['id']}");
|
|
||||||
|
|
||||||
foreach ($vdata['tags'] as $tag) {
|
|
||||||
$esc_tag = DB::escape($tag);
|
|
||||||
|
|
||||||
DB::insert("INSERT INTO `lists_tags` (list_id, tag) VALUES ({$list['id']}, '$esc_tag')");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dieWithJsonData(['status' => 'success', 'message' => '修改成功']);
|
|
||||||
};
|
|
||||||
$update_profile_form->setAjaxSubmit(<<<EOD
|
|
||||||
function(res) {
|
|
||||||
if (res.status === 'success') {
|
|
||||||
$('#result-alert')
|
|
||||||
.html('题单信息修改成功!')
|
|
||||||
.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_profile_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
|
||||||
$update_profile_form->submit_button_config['text'] = '更新';
|
|
||||||
$update_profile_form->runAtServer();
|
|
||||||
} elseif ($cur_tab == 'problems') {
|
|
||||||
if (isset($_POST['submit-remove_problem']) && $_POST['submit-remove_problem'] == 'remove_problem') {
|
|
||||||
crsf_defend();
|
|
||||||
|
|
||||||
$problem_id = $_POST['problem_id'];
|
|
||||||
|
|
||||||
if (!validateUInt($problem_id)) {
|
|
||||||
dieWithAlert('题目 ID 不合法');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!queryProblemBrief($problem_id)) {
|
|
||||||
dieWithAlert('题目不存在');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!queryProblemInList($list['id'], $problem_id)) {
|
|
||||||
dieWithAlert('题目不在题单中');
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::delete("DELETE FROM lists_problems WHERE problem_id = {$problem_id} AND list_id = {$list['id']}");
|
|
||||||
|
|
||||||
dieWithAlert('移除成功!');
|
|
||||||
}
|
|
||||||
|
|
||||||
$n_problems = DB::selectCount("SELECT count(*) FROM `lists_problems` WHERE `list_id` = {$list['id']}");
|
|
||||||
|
|
||||||
$add_new_problem_form = new UOJBs4Form('add_new_problem');
|
|
||||||
$add_new_problem_form->addVInput('problem_id', 'text', '题目 ID', '',
|
|
||||||
function ($problem_id, &$vdata) use ($list) {
|
|
||||||
if (!validateUInt($problem_id)) {
|
|
||||||
return 'ID 不合法';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!queryProblemBrief($problem_id)) {
|
|
||||||
return '题目不存在';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryProblemInList($list['id'], $problem_id)) {
|
|
||||||
return '该题目已经在题单中';
|
|
||||||
}
|
|
||||||
|
|
||||||
$vdata['problem_id'] = $problem_id;
|
|
||||||
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
null
|
|
||||||
);
|
|
||||||
$add_new_problem_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
|
||||||
$add_new_problem_form->submit_button_config['text'] = '添加';
|
|
||||||
$add_new_problem_form->handle = function($vdata) use ($list) {
|
|
||||||
DB::insert("INSERT INTO `lists_problems` (`list_id`, `problem_id`) values ({$list['id']}, {$vdata['problem_id']})");
|
|
||||||
|
|
||||||
dieWithJsonData(['status' => 'success', 'message' => '已将题目 #' . $vdata['problem_id'] . ' 添加到题单 #' . $list['id'] .' 中']);
|
|
||||||
};
|
|
||||||
$add_new_problem_form->setAjaxSubmit(<<<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);
|
|
||||||
$add_new_problem_form->runAtServer();
|
|
||||||
} elseif ($cur_tab == 'assignments') {
|
|
||||||
if (isset($_POST['submit-remove_assignment']) && $_POST['submit-remove_assignment'] == 'remove_assignment') {
|
|
||||||
crsf_defend();
|
|
||||||
|
|
||||||
$group_id = $_POST['group_id'];
|
|
||||||
|
|
||||||
if (!validateUInt($group_id)) {
|
|
||||||
dieWithAlert('小组 ID 不合法。');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!queryGroup($group_id)) {
|
|
||||||
dieWithAlert('小组不存在。');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!queryAssignmentByGroupListID($group_id, $list['id'])) {
|
|
||||||
dieWithAlert('该小组并未将本题单布置为作业。');
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::delete("DELETE FROM groups_assignments WHERE group_id = {$group_id} AND list_id = {$list['id']}");
|
|
||||||
|
|
||||||
dieWithAlert('移除成功!');
|
|
||||||
}
|
|
||||||
|
|
||||||
$add_new_assignment_form = new UOJBs4Form('add_new_assignment');
|
|
||||||
$add_new_assignment_form->addVInput('new_assignment_group_id', 'text', '小组 ID', '',
|
|
||||||
function ($group_id, &$vdata) use ($list) {
|
|
||||||
if (!validateUInt($group_id)) {
|
|
||||||
return '小组 ID 不合法';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!($list = queryGroup($group_id))) {
|
|
||||||
return '小组不存在';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($list['is_hidden'] != 0) {
|
|
||||||
return '题单是隐藏的';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryAssignmentByGroupListID($group_id, $list['id'])) {
|
|
||||||
return '该题单已经是这个小组的作业';
|
|
||||||
}
|
|
||||||
|
|
||||||
$vdata['group_id'] = $group_id;
|
|
||||||
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
null
|
|
||||||
);
|
|
||||||
$default_end_time = new DateTime();
|
|
||||||
$default_end_time->setTime(22, 30, 0);
|
|
||||||
$default_end_time->add(new DateInterval("P7D"));
|
|
||||||
$add_new_assignment_form->addVInput('new_assignment_end_time', 'text', '截止时间', $default_end_time->format('Y-m-d H:i'),
|
|
||||||
function ($end_time, &$vdata) {
|
|
||||||
try {
|
|
||||||
$vdata['end_time'] = new DateTime($end_time);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
return '无效时间格式';
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
null
|
|
||||||
);
|
|
||||||
$add_new_assignment_form->handle = function(&$vdata) use ($list) {
|
|
||||||
$esc_end_time = DB::escape($vdata['end_time']->format('Y-m-d H:i:s'));
|
|
||||||
|
|
||||||
DB::insert("insert into groups_assignments (group_id, list_id, end_time) values ({$vdata['group_id']}, '{$list['id']}', '{$esc_end_time}')");
|
|
||||||
|
|
||||||
dieWithJsonData([
|
|
||||||
'status' => 'success',
|
|
||||||
'message' => '题单 #' . $list['id'] . ' 已经被添加到小组 #' . $vdata['group_id'] . ' 的作业列表中,结束时间为 ' . $vdata['end_time']->format('Y-m-d H:i:s') . '。'
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
$add_new_assignment_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
|
||||||
$add_new_assignment_form->submit_button_config['text'] = '添加';
|
|
||||||
$add_new_assignment_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);
|
|
||||||
$add_new_assignment_form->runAtServer();
|
|
||||||
|
|
||||||
$hidden_time = new DateTime();
|
|
||||||
$hidden_time->sub(new DateInterval('P7D'));
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php echoUOJPageHeader('管理 - ' . $list['title']) ?>
|
|
||||||
|
|
||||||
<h1>
|
|
||||||
<?= $list['title'] ?>
|
|
||||||
<small class="fs-5">(ID: #<?= $list['id'] ?>)</small>
|
|
||||||
管理
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div class="row mt-4">
|
|
||||||
<!-- left col -->
|
|
||||||
<div class="col-md-3">
|
|
||||||
|
|
||||||
<?= HTML::navListGroup($tabs_info, $cur_tab) ?>
|
|
||||||
|
|
||||||
<a
|
|
||||||
class="btn btn-light d-block mt-2 w-100 text-start text-primary"
|
|
||||||
style="--bs-btn-hover-bg: #d3d4d570; --bs-btn-hover-border-color: transparent;"
|
|
||||||
href="<?= HTML::url("/list/{$list['id']}") ?>">
|
|
||||||
<i class="bi bi-arrow-left"></i> 返回
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!-- end left col -->
|
|
||||||
|
|
||||||
<!-- right col -->
|
|
||||||
<div class="col-md-9">
|
|
||||||
<?php if ($cur_tab == 'profile'): ?>
|
|
||||||
<div class="card mt-3 mt-md-0">
|
|
||||||
<div class="card-body">
|
|
||||||
<div id="result-alert" class="alert" role="alert" style="display: none"></div>
|
|
||||||
<div class="row row-cols-1 row-cols-md-2">
|
|
||||||
<div class="col">
|
|
||||||
<?= $update_profile_form->printHTML() ?>
|
|
||||||
</div>
|
|
||||||
<div class="col mt-3 mt-md-0">
|
|
||||||
<h5>注意事项</h5>
|
|
||||||
<ul class="mb-0">
|
|
||||||
<li>隐藏的题单无法被普通用户查看。</li>
|
|
||||||
<li>题单描述支持 Markdown 语法。</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?php elseif ($cur_tab == 'problems'): ?>
|
|
||||||
<div class="card mt-3 mt-md-0">
|
|
||||||
<div class="card-header">
|
|
||||||
<ul class="nav nav-tabs card-header-tabs" role="tablist">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link active" href="#problems" data-bs-toggle="tab" data-bs-target="#problems">题目列表</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#add-problem" data-bs-toggle="tab" data-bs-target="#add-problem">添加题目</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="card-body tab-content">
|
|
||||||
<div class="tab-pane active" id="problems">
|
|
||||||
<?php
|
|
||||||
echoLongTable(
|
|
||||||
[
|
|
||||||
'problems.id as id',
|
|
||||||
'problems.title as title',
|
|
||||||
'problems.is_hidden as is_hidden',
|
|
||||||
],
|
|
||||||
"problems inner join lists_problems on lists_problems.list_id = {$list['id']} and lists_problems.problem_id = problems.id",
|
|
||||||
"1",
|
|
||||||
'ORDER BY `id` ASC',
|
|
||||||
<<<EOD
|
|
||||||
<tr>
|
|
||||||
<th class="text-center" style="width:5em">ID</th>
|
|
||||||
<th>标题</th>
|
|
||||||
<th style="width:4em">操作</th>
|
|
||||||
</tr>
|
|
||||||
EOD,
|
|
||||||
function ($row) {
|
|
||||||
echo '<tr>';
|
|
||||||
|
|
||||||
echo '<td class="text-center">', $row['id'], '</td>';
|
|
||||||
echo '<td>', getProblemLink($row);
|
|
||||||
if ($row['is_hidden']) {
|
|
||||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
|
||||||
}
|
|
||||||
echo '</td>';
|
|
||||||
echo '<td>';
|
|
||||||
echo '<form target="_self" method="POST" class="d-inline-block" onsubmit=\'return confirm("你确定要将题目 #', $row['id'],' 从题单中移除吗?")\'>';
|
|
||||||
echo '<input type="hidden" name="_token" value="', crsf_token(), '">';
|
|
||||||
echo '<input type="hidden" name="problem_id" value="', $row['id'], '">';
|
|
||||||
echo '<button class="btn btn-link text-danger text-decoration-none p-0" name="submit-remove_problem" value="remove_problem">移除</button>';
|
|
||||||
echo '</form>';
|
|
||||||
echo '</td>';
|
|
||||||
|
|
||||||
echo '</tr>';
|
|
||||||
},
|
|
||||||
[
|
|
||||||
'page_len' => 20,
|
|
||||||
'div_classes' => ['table-responsive'],
|
|
||||||
'table_classes' => ['table', 'align-middle'],
|
|
||||||
'print_after_table' => function() use ($n_problems) {
|
|
||||||
echo '<div class="text-muted text-end">共 ', $n_problems,' 道题目</div>';
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
|
||||||
?>
|
|
||||||
</div>
|
|
||||||
<div class="tab-pane" id="add-problem">
|
|
||||||
<div id="result-alert" class="alert" role="alert" style="display: none"></div>
|
|
||||||
<div class="row row-cols-1 row-cols-md-2">
|
|
||||||
<div class="col">
|
|
||||||
<?php $add_new_problem_form->printHTML() ?>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<h5>注意事项</h5>
|
|
||||||
<ul class="mt-0">
|
|
||||||
<li>隐藏的题目添加进题单后无法被普通用户查看。</li>
|
|
||||||
<li>如当前题单已经被设置为某个小组的作业,则作业也会一并更新。</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?php elseif ($cur_tab == 'assignments'): ?>
|
|
||||||
<div class="card mt-3 mt-md-0">
|
|
||||||
<div class="card-header">
|
|
||||||
<ul class="nav nav-tabs card-header-tabs" role="tablist">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link active" href="#assignments" data-bs-toggle="tab" data-bs-target="#assignments">作业列表</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#add-assignment" data-bs-toggle="tab" data-bs-target="#add-assignment">添加作业</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="tab-content">
|
|
||||||
<div class="tab-pane active" id="assignments">
|
|
||||||
<?php
|
|
||||||
echoLongTable(
|
|
||||||
['*'],
|
|
||||||
'groups_assignments',
|
|
||||||
"list_id = {$list['id']}",
|
|
||||||
'order by end_time desc, group_id asc',
|
|
||||||
<<<EOD
|
|
||||||
<tr>
|
|
||||||
<th style="width:4em" class="text-center">小组 ID</th>
|
|
||||||
<th style="width:12em">名称</th>
|
|
||||||
<th style="width:4em">状态</th>
|
|
||||||
<th style="width:8em">结束时间</th>
|
|
||||||
<th style="width:8em">操作</th>
|
|
||||||
</tr>
|
|
||||||
EOD,
|
|
||||||
function($row) use ($list, $hidden_time) {
|
|
||||||
$group = queryGroup($row['group_id']);
|
|
||||||
$end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']);
|
|
||||||
|
|
||||||
echo '<tr>';
|
|
||||||
echo '<td class="text-center">', $group['id'], '</td>';
|
|
||||||
echo '<td>', '<a class="text-decoration-none" href="/group/', $group['id'], '">', HTML::escape($group['title']), '</a>', '</td>';
|
|
||||||
if ($end_time < $hidden_time) {
|
|
||||||
echo '<td class="text-secondary">已隐藏</td>';
|
|
||||||
} elseif ($end_time < UOJTime::$time_now) {
|
|
||||||
echo '<td class="text-danger">已结束</td>';
|
|
||||||
} else {
|
|
||||||
echo '<td class="text-success">进行中</td>';
|
|
||||||
}
|
|
||||||
echo '<td>', $end_time->format('Y-m-d H:i:s'), '</td>';
|
|
||||||
echo '<td>';
|
|
||||||
echo ' <a class="text-decoration-none d-inline-block align-middle" href="/group/', $group['id'], '/assignment/', $list['id'],'">排行榜</a> ';
|
|
||||||
echo ' <form class="d-inline-block" method="POST" onsubmit=\'return confirm("你真的要为小组 #', $group['id'], ' 移除这份作业吗?移除作业不会删除题单。")\'>'
|
|
||||||
. '<input type="hidden" name="_token" value="' . crsf_token() . '">'
|
|
||||||
. '<input type="hidden" name="group_id" value="' . $group['id'] . '">'
|
|
||||||
. '<button class="btn btn-link text-danger text-decoration-none p-0" type="submit" name="submit-remove_assignment" value="remove_assignment">移除</button>'
|
|
||||||
. '</form>';
|
|
||||||
echo '</td>';
|
|
||||||
echo '</tr>';
|
|
||||||
},
|
|
||||||
[
|
|
||||||
'page_len' => 20,
|
|
||||||
'div_classes' => ['table-responsive'],
|
|
||||||
'table_classes' => ['table', 'align-middle'],
|
|
||||||
]
|
|
||||||
);
|
|
||||||
?>
|
|
||||||
</div>
|
|
||||||
<div class="tab-pane" id="add-assignment">
|
|
||||||
<div id="result-alert" class="alert" role="alert" style="display: none"></div>
|
|
||||||
<div class="row row-cols-1 row-cols-md-2">
|
|
||||||
<div class="col">
|
|
||||||
<?php $add_new_assignment_form->printHTML() ?>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<h5>注意事项</h5>
|
|
||||||
<ul class="mt-0">
|
|
||||||
<li>请为学生预留合理的完成作业的时间。</li>
|
|
||||||
<li>排行榜将在作业结束后停止更新。</li>
|
|
||||||
<li>如需延长结束时间请删除后再次添加,排行数据不会丢失。</li>
|
|
||||||
<li>作业结束七天后将会自动在小组主页中隐藏,但仍可直接通过 URL 访问。</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?php endif ?>
|
|
||||||
</div>
|
|
||||||
<!-- end right col -->
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
|
379
web/app/controllers/list_manage.php
Normal file
379
web/app/controllers/list_manage.php
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
requireLib('bootstrap5');
|
||||||
|
requirePHPLib('form');
|
||||||
|
|
||||||
|
Auth::check() || redirectToLogin();
|
||||||
|
UOJList::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
|
UOJList::cur()->userCanManage(Auth::user()) || UOJResponse::page403();
|
||||||
|
|
||||||
|
$cur_tab = UOJRequest::get('tab', 'is_string', 'profile');
|
||||||
|
|
||||||
|
$tabs_info = [
|
||||||
|
'profile' => [
|
||||||
|
'name' => '基本信息',
|
||||||
|
'url' => '/list/' . UOJList::info('id') . '/manage/profile',
|
||||||
|
],
|
||||||
|
'problems' => [
|
||||||
|
'name' => '题目管理',
|
||||||
|
'url' => '/list/' . UOJList::info('id') . '/manage/problems',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!isset($tabs_info[$cur_tab])) {
|
||||||
|
become404Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cur_tab == 'profile') {
|
||||||
|
$update_profile_form = new UOJBs4Form('update_profile');
|
||||||
|
$update_profile_form->addVInput(
|
||||||
|
'name',
|
||||||
|
'text',
|
||||||
|
'标题',
|
||||||
|
UOJList::info('title'),
|
||||||
|
function ($title, &$vdata) {
|
||||||
|
if ($title == '') {
|
||||||
|
return '标题不能为空';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($title) > 100) {
|
||||||
|
return '标题过长';
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = HTML::escape($title);
|
||||||
|
if ($title === '') {
|
||||||
|
return '无效编码';
|
||||||
|
}
|
||||||
|
|
||||||
|
$vdata['title'] = $title;
|
||||||
|
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
|
$update_profile_form->addVCheckboxes('is_hidden', [
|
||||||
|
'0' => '公开',
|
||||||
|
'1' => '隐藏',
|
||||||
|
], '可见性', UOJList::info('is_hidden'));
|
||||||
|
$update_profile_form->addVInput(
|
||||||
|
'tags',
|
||||||
|
'text',
|
||||||
|
'标签(多个标签用逗号隔开)',
|
||||||
|
implode(', ', UOJList::cur()->queryTags()),
|
||||||
|
function ($tags_str, &$vdata) {
|
||||||
|
$tags_raw = explode(',', str_replace(',', ',', $tags_str));
|
||||||
|
$tags = [];
|
||||||
|
|
||||||
|
if (count($tags_raw) > 10) {
|
||||||
|
return '不能存在超过 10 个标签';
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($tags_raw as $tag) {
|
||||||
|
$tag = HTML::escape(trim($tag));
|
||||||
|
|
||||||
|
if (strlen($tag) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($tag) > 30) {
|
||||||
|
return '标签 “' . $tag . '” 太长';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($tag, $tags, true)) {
|
||||||
|
return '标签 “' . $tag . '” 重复出现';
|
||||||
|
}
|
||||||
|
|
||||||
|
$tags[] = $tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
$vdata['tags'] = $tags;
|
||||||
|
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
|
$update_profile_form->addVTextArea(
|
||||||
|
'content_md',
|
||||||
|
'描述',
|
||||||
|
UOJList::cur()->queryContent()['content_md'],
|
||||||
|
function ($content_md, &$vdata) {
|
||||||
|
if (strlen($content_md) > 3000) {
|
||||||
|
return '描述过长';
|
||||||
|
}
|
||||||
|
|
||||||
|
$vdata['content_md'] = $content_md;
|
||||||
|
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
|
$update_profile_form->handle = function ($vdata) {
|
||||||
|
DB::update([
|
||||||
|
"update lists",
|
||||||
|
"set", [
|
||||||
|
"title" => $vdata['title'],
|
||||||
|
"is_hidden" => $_POST['is_hidden'],
|
||||||
|
],
|
||||||
|
"where", [
|
||||||
|
"id" => UOJList::info('id'),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
DB::update([
|
||||||
|
"update lists_contents",
|
||||||
|
"set", [
|
||||||
|
"content" => HTML::purifier()->purify(HTML::parsedown()->text($vdata['content_md'])),
|
||||||
|
"content_md" => $vdata['content_md'],
|
||||||
|
],
|
||||||
|
"where", [
|
||||||
|
"id" => UOJList::info('id'),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
UOJList::cur()->updateTags($vdata['tags']);
|
||||||
|
|
||||||
|
dieWithJsonData(['status' => 'success', 'message' => '修改成功']);
|
||||||
|
};
|
||||||
|
$update_profile_form->setAjaxSubmit(<<<EOD
|
||||||
|
function(res) {
|
||||||
|
if (res.status === 'success') {
|
||||||
|
$('#result-alert')
|
||||||
|
.html('题单信息修改成功!')
|
||||||
|
.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_profile_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
||||||
|
$update_profile_form->submit_button_config['text'] = '更新';
|
||||||
|
$update_profile_form->runAtServer();
|
||||||
|
} elseif ($cur_tab == 'problems') {
|
||||||
|
if (isset($_POST['submit-remove_problem']) && $_POST['submit-remove_problem'] == 'remove_problem') {
|
||||||
|
crsf_defend();
|
||||||
|
|
||||||
|
$problem = UOJProblem::query(UOJRequest::post('problem_id', 'validateUInt'));
|
||||||
|
|
||||||
|
if (!$problem) {
|
||||||
|
dieWithAlert('题目不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UOJList::cur()->hasProblem($problem)) {
|
||||||
|
dieWithAlert('题目不在题单中');
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::delete([
|
||||||
|
"delete from lists_problems",
|
||||||
|
"where", [
|
||||||
|
"problem_id" => $problem->info['id'],
|
||||||
|
"list_id" => UOJList::info('id'),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
dieWithAlert('移除成功!');
|
||||||
|
}
|
||||||
|
|
||||||
|
$n_problems = DB::selectCount([
|
||||||
|
"select count(*)",
|
||||||
|
"from lists_problems",
|
||||||
|
"where", [
|
||||||
|
"list_id" => UOJList::info('id'),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$add_new_problem_form = new UOJBs4Form('add_new_problem');
|
||||||
|
$add_new_problem_form->addVInput(
|
||||||
|
'problem_id',
|
||||||
|
'text',
|
||||||
|
'题目 ID',
|
||||||
|
'',
|
||||||
|
function ($problem_id, &$vdata) {
|
||||||
|
$problem = UOJProblem::query($problem_id);
|
||||||
|
|
||||||
|
if (!$problem || !$problem->userCanView(Auth::user())) {
|
||||||
|
return '题目不存在';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UOJList::cur()->hasProblem($problem)) {
|
||||||
|
return '该题目已经在题单中';
|
||||||
|
}
|
||||||
|
|
||||||
|
$vdata['problem'] = $problem;
|
||||||
|
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
|
$add_new_problem_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
||||||
|
$add_new_problem_form->submit_button_config['text'] = '添加';
|
||||||
|
$add_new_problem_form->handle = function ($vdata) {
|
||||||
|
DB::insert([
|
||||||
|
"insert into lists_problems",
|
||||||
|
DB::bracketed_fields(["list_id", "problem_id"]),
|
||||||
|
"values", DB::tuple([UOJList::info('id'), $vdata['problem']->info['id']]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
dieWithJsonData(['status' => 'success', 'message' => '已将题目 #' . $vdata['problem']->info['id'] . ' 添加到题单 #' . UOJList::info('id') . ' 中']);
|
||||||
|
};
|
||||||
|
$add_new_problem_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);
|
||||||
|
$add_new_problem_form->runAtServer();
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php echoUOJPageHeader('管理 - ' . UOJList::info('title')) ?>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
<?= UOJList::info('title') ?>
|
||||||
|
<small class="fs-5">(ID: #<?= UOJList::info('id') ?>)</small>
|
||||||
|
管理
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div class="row mt-4">
|
||||||
|
<!-- left col -->
|
||||||
|
<div class="col-md-3">
|
||||||
|
<?= HTML::navListGroup($tabs_info, $cur_tab) ?>
|
||||||
|
|
||||||
|
<a class="btn btn-light d-block mt-2 w-100 text-start text-primary" style="--bs-btn-hover-bg: #d3d4d570; --bs-btn-hover-border-color: transparent;" href="<?= HTML::url('/list/' . UOJList::info('id')) ?>">
|
||||||
|
<i class="bi bi-arrow-left"></i> 返回
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<!-- end left col -->
|
||||||
|
|
||||||
|
<!-- right col -->
|
||||||
|
<div class="col-md-9">
|
||||||
|
<?php if ($cur_tab == 'profile') : ?>
|
||||||
|
<div class="card mt-3 mt-md-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div id="result-alert" class="alert" role="alert" style="display: none"></div>
|
||||||
|
<div class="row row-cols-1 row-cols-md-2">
|
||||||
|
<div class="col">
|
||||||
|
<?= $update_profile_form->printHTML() ?>
|
||||||
|
</div>
|
||||||
|
<div class="col mt-3 mt-md-0">
|
||||||
|
<h5>注意事项</h5>
|
||||||
|
<ul class="mb-0">
|
||||||
|
<li>隐藏的题单无法被普通用户查看。</li>
|
||||||
|
<li>题单描述支持 Markdown 语法。</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php elseif ($cur_tab == 'problems') : ?>
|
||||||
|
<div class="card mt-3 mt-md-0">
|
||||||
|
<div class="card-header">
|
||||||
|
<ul class="nav nav-tabs card-header-tabs" role="tablist">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" href="#problems" data-bs-toggle="tab" data-bs-target="#problems">题目列表</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#add-problem" data-bs-toggle="tab" data-bs-target="#add-problem">添加题目</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="card-body tab-content">
|
||||||
|
<div class="tab-pane active" id="problems">
|
||||||
|
<?php
|
||||||
|
echoLongTable(
|
||||||
|
[
|
||||||
|
'problems.id as id',
|
||||||
|
'problems.title as title',
|
||||||
|
'problems.is_hidden as is_hidden',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"problems",
|
||||||
|
"inner join lists_problems",
|
||||||
|
"on", [
|
||||||
|
"lists_problems.list_id" => UOJList::info('id'),
|
||||||
|
"lists_problems.problem_id" => DB::raw("problems.id")
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"1",
|
||||||
|
"order by id asc",
|
||||||
|
<<<EOD
|
||||||
|
<tr>
|
||||||
|
<th class="text-center" style="width:5em">ID</th>
|
||||||
|
<th>标题</th>
|
||||||
|
<th style="width:4em">操作</th>
|
||||||
|
</tr>
|
||||||
|
EOD,
|
||||||
|
function ($row) {
|
||||||
|
echo HTML::tag_begin('tr');
|
||||||
|
|
||||||
|
echo HTML::tag('td', ['class' => 'text-center'], $row['id']);
|
||||||
|
echo HTML::tag_begin('td');
|
||||||
|
echo getProblemLink($row);
|
||||||
|
if ($row['is_hidden']) {
|
||||||
|
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
||||||
|
}
|
||||||
|
echo HTML::tag_end('td');
|
||||||
|
echo HTML::tag_begin('td');
|
||||||
|
echo '<form target="_self" method="POST" class="d-inline-block" onsubmit=\'return confirm("你确定要将题目 #', $row['id'], ' 从题单中移除吗?")\'>';
|
||||||
|
echo '<input type="hidden" name="_token" value="', crsf_token(), '">';
|
||||||
|
echo '<input type="hidden" name="problem_id" value="', $row['id'], '">';
|
||||||
|
echo '<button class="btn btn-link text-danger text-decoration-none p-0" name="submit-remove_problem" value="remove_problem">移除</button>';
|
||||||
|
echo '</form>';
|
||||||
|
echo HTML::tag_end('td');
|
||||||
|
|
||||||
|
echo HTML::tag_end('tr');
|
||||||
|
},
|
||||||
|
[
|
||||||
|
'page_len' => 20,
|
||||||
|
'div_classes' => ['table-responsive'],
|
||||||
|
'table_classes' => ['table', 'align-middle'],
|
||||||
|
'print_after_table' => function () use ($n_problems) {
|
||||||
|
echo '<div class="text-muted text-end">共 ', $n_problems, ' 道题目</div>';
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="add-problem">
|
||||||
|
<div id="result-alert" class="alert" role="alert" style="display: none"></div>
|
||||||
|
<div class="row row-cols-1 row-cols-md-2">
|
||||||
|
<div class="col">
|
||||||
|
<?php $add_new_problem_form->printHTML() ?>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<h5>注意事项</h5>
|
||||||
|
<ul class="mt-0">
|
||||||
|
<li>隐藏的题目添加进题单后无法被普通用户查看。</li>
|
||||||
|
<li>如当前题单已经被设置为某个小组的作业,则作业也会一并更新。</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
|
</div>
|
||||||
|
<!-- end right col -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php echoUOJPageFooter() ?>
|
@ -1,16 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check()) {
|
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
requirePHPLib('data');
|
requirePHPLib('data');
|
||||||
|
|
||||||
if (isSuperUser($myUser)) {
|
Auth::check() || redirectToLogin();
|
||||||
|
|
||||||
|
if (isSuperUser($myUser)) {
|
||||||
$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::query("insert into lists (title, is_hidden) values ('未命名题单', 1)");
|
||||||
};
|
};
|
||||||
$new_list_form->submit_button_config['align'] = 'right';
|
$new_list_form->submit_button_config['align'] = 'right';
|
||||||
@ -19,142 +18,138 @@
|
|||||||
$new_list_form->submit_button_config['smart_confirm'] = '';
|
$new_list_form->submit_button_config['smart_confirm'] = '';
|
||||||
|
|
||||||
$new_list_form->runAtServer();
|
$new_list_form->runAtServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getListTR($info) {
|
||||||
|
$list = new UOJList($info);
|
||||||
|
$problems = $list->getProblemIDs();
|
||||||
|
$accepted = DB::selectCount([
|
||||||
|
"select count(*)",
|
||||||
|
"from best_ac_submissions",
|
||||||
|
"where", [
|
||||||
|
"submitter" => Auth::id(),
|
||||||
|
["problem_id", "in", DB::tuple($problems)],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$html = HTML::tag_begin('tr', ['class' => 'text-center']);
|
||||||
|
$html .= HTML::tag('td', ['class' => $accepted == count($problems) ? 'table-success' : ''], "#{$list->info['id']}");
|
||||||
|
$html .= HTML::tag_begin('td', ['class' => 'text-start']);
|
||||||
|
$html .= HTML::tag('a', ['href' => "/list/{$list->info['id']}"], $list->info['title']);
|
||||||
|
if ($list->info['is_hidden']) {
|
||||||
|
$html .= ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ' . UOJLocale::get('hidden') . '</span> ';
|
||||||
}
|
}
|
||||||
|
foreach ($list->queryTags() as $tag) {
|
||||||
function echoList($list) {
|
$html .= ' <a class="uoj-list-tag"><span class="badge text-bg-secondary">' . $tag['tag'] . '</span></a> ';
|
||||||
global $myUser;
|
|
||||||
|
|
||||||
if (isListVisibleToUser($list, $myUser)) {
|
|
||||||
echo '<tr class="text-center">';
|
|
||||||
if ($list['problem_count'] == $list['accepted'] && $list['problem_count'] > 0) {
|
|
||||||
echo '<td class="success">';
|
|
||||||
} else {
|
|
||||||
echo '<td>';
|
|
||||||
}
|
}
|
||||||
echo '#', $list['list_id'], '</td>';
|
$html .= HTML::tag('td', [], $accepted);
|
||||||
|
$html .= HTML::tag('td', [], count($problems));
|
||||||
|
$html .= HTML::tag_end('td');
|
||||||
|
|
||||||
echo '<td class="text-start">';
|
return $html;
|
||||||
echo '<a class="text-decoration-none" href="/list/', $list['list_id'], '">', $list['title'], '</a> ';
|
}
|
||||||
|
|
||||||
if ($list['is_hidden']) {
|
$cond = [];
|
||||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
$search_tag = UOJRequest::get('tag', 'is_string', null);
|
||||||
|
if (is_string($search_tag)) {
|
||||||
|
$cond[] = [
|
||||||
|
DB::rawvalue($search_tag), "in", DB::rawbracket([
|
||||||
|
"select tag from lists_tags",
|
||||||
|
"where", ["lists_tags.list_id" => DB::raw("lists.id")]
|
||||||
|
])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($cond)) {
|
||||||
|
$cond = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
$header = HTML::tag('tr', [], [
|
||||||
|
HTML::tag('th', ['class' => 'text-center', 'style' => 'width:5em'], 'ID'),
|
||||||
|
HTML::tag('th', [], UOJLocale::get('problems::problem list')),
|
||||||
|
HTML::tag('th', ['class' => 'text-center', 'style' => 'width:5em'], UOJLocale::get('problems::ac')),
|
||||||
|
HTML::tag('th', ['class' => 'text-center', 'style' => 'width:5em'], UOJLocale::get('problems::total')),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$pag = new Paginator([
|
||||||
|
'col_names' => ['*'],
|
||||||
|
'table_name' => 'lists',
|
||||||
|
'cond' => $cond,
|
||||||
|
'tail' => "order by id desc",
|
||||||
|
'page_len' => 40,
|
||||||
|
'post_filter' => function ($info) {
|
||||||
|
return (new UOJList($info))->userCanView(Auth::user());
|
||||||
}
|
}
|
||||||
|
]);
|
||||||
foreach (queryProblemListTags($list['list_id']) as $tag) {
|
?>
|
||||||
echo '<a class="uoj-list-tag my-1">', '<span class="badge bg-secondary">', HTML::escape($tag), '</span>', '</a> ';
|
|
||||||
}
|
|
||||||
echo '</td>';
|
|
||||||
|
|
||||||
echo "<td>{$list['accepted']}</td>";
|
|
||||||
echo "<td>{$list['problem_count']}</td>";
|
|
||||||
|
|
||||||
echo '</tr>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('problems lists')) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('problems lists')) ?>
|
||||||
|
|
||||||
<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 mb-2">
|
|
||||||
<?php $new_list_form->printHTML(); ?>
|
<?php $new_list_form->printHTML(); ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
</div>
|
||||||
|
<!-- end title container -->
|
||||||
|
|
||||||
</div>
|
<div class="text-end">
|
||||||
<!-- end title container -->
|
<div class="form-check d-inline-block me-2">
|
||||||
|
<input type="checkbox" id="input-show_tags_mode" class="form-check-input" <?= isset($_COOKIE['show_tags_mode']) ? 'checked="checked" ' : '' ?> />
|
||||||
|
<label class="form-check-label" for="input-show_tags_mode">
|
||||||
|
<?= UOJLocale::get('problems::show tags') ?>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php
|
<script type="text/javascript">
|
||||||
$list_caption = UOJLocale::get('problems::problem list');
|
$('#input-show_tags_mode').click(function() {
|
||||||
$ac_caption = UOJLocale::get('problems::ac');
|
if (this.checked) {
|
||||||
$total_caption = UOJLocale::get('problems::total');
|
$.cookie('show_tags_mode', '', {
|
||||||
$header = <<<EOD
|
path: '/'
|
||||||
<tr>
|
});
|
||||||
<th class="text-center" style="width:5em;">ID</th>
|
|
||||||
<th>{$list_caption}</th>
|
|
||||||
<th class="text-center" style="width:5em;">{$ac_caption}</th>
|
|
||||||
<th class="text-center" style="width:5em;">{$total_caption}</th>
|
|
||||||
</tr>
|
|
||||||
EOD;
|
|
||||||
|
|
||||||
$cond = [];
|
|
||||||
$search_tag = null;
|
|
||||||
|
|
||||||
if (isset($_GET['tag'])) {
|
|
||||||
$search_tag = $_GET['tag'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($search_tag) {
|
|
||||||
$cond[] = "'" . DB::escape($search_tag) . "' in (select tag from lists_tags where lists_tags.list_id = a.id)";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cond) {
|
|
||||||
$cond = join($cond, ' and ');
|
|
||||||
} else {
|
} else {
|
||||||
$cond = '1';
|
$.removeCookie('show_tags_mode', {
|
||||||
|
path: '/'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
echoLongTable(
|
<?= $pag->pagination() ?>
|
||||||
array('a.id as list_id', 'a.title as title', 'a.is_hidden as is_hidden', 'count(b.problem_id) as problem_count', 'count(c.submitter) as accepted'),
|
|
||||||
"lists a left join lists_problems b on a.id = b.list_id left join best_ac_submissions c on (b.problem_id = c.problem_id and c.submitter = '{$myUser['username']}')",
|
<div class="card my-3">
|
||||||
$cond,
|
<?=
|
||||||
'group by a.id order by a.id desc',
|
HTML::responsive_table($header, $pag->get(), [
|
||||||
$header,
|
'table_attr' => [
|
||||||
function($list) use ($myUser) {
|
'class' => ['table', 'uoj-table', 'mb-0'],
|
||||||
if (isListVisibleToUser($list, $myUser)) {
|
],
|
||||||
echo '<tr class="text-center">';
|
'tr' => function ($row, $idx) {
|
||||||
if ($list['problem_count'] == $list['accepted'] && $list['problem_count'] > 0) {
|
return getListTR($row);
|
||||||
echo '<td class="success">';
|
|
||||||
} else {
|
|
||||||
echo '<td>';
|
|
||||||
}
|
}
|
||||||
echo '#', $list['list_id'], '</td>';
|
]);
|
||||||
|
|
||||||
echo '<td class="text-start">';
|
|
||||||
echo '<a class="text-decoration-none" href="/list/', $list['list_id'], '">', $list['title'], '</a> ';
|
|
||||||
|
|
||||||
if ($list['is_hidden']) {
|
|
||||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (queryProblemListTags($list['list_id']) as $tag) {
|
|
||||||
echo '<a class="uoj-list-tag my-1">', '<span class="badge bg-secondary">', HTML::escape($tag), '</span>', '</a> ';
|
|
||||||
}
|
|
||||||
echo '</td>';
|
|
||||||
|
|
||||||
echo "<td>{$list['accepted']}</td>";
|
|
||||||
echo "<td>{$list['problem_count']}</td>";
|
|
||||||
|
|
||||||
echo '</tr>';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[
|
|
||||||
'page_len' => 40,
|
|
||||||
'table_classes' => ['table', 'table-bordered', 'table-hover', 'table-striped'],
|
|
||||||
'head_pagination' => true,
|
|
||||||
'div_classes' => ['card', 'my-3'],
|
|
||||||
'table_classes' => ['table', 'uoj-table', 'mb-0'],
|
|
||||||
]
|
|
||||||
);
|
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
<!-- end left col -->
|
|
||||||
|
|
||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
<?= $pag->pagination() ?>
|
||||||
<?php uojIncludeView('sidebar') ?>
|
</div>
|
||||||
</aside>
|
<!-- end left col -->
|
||||||
|
|
||||||
|
<!-- right col -->
|
||||||
|
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||||
|
<?php uojIncludeView('sidebar') ?>
|
||||||
|
</aside>
|
||||||
|
<!-- end right col -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -288,11 +288,11 @@ $pag = new Paginator([
|
|||||||
$('#input-show_tags_mode').click(function() {
|
$('#input-show_tags_mode').click(function() {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
$.cookie('show_tags_mode', '', {
|
$.cookie('show_tags_mode', '', {
|
||||||
path: '/problems'
|
path: '/'
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$.removeCookie('show_tags_mode', {
|
$.removeCookie('show_tags_mode', {
|
||||||
path: '/problems'
|
path: '/'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
location.reload();
|
location.reload();
|
||||||
@ -300,11 +300,11 @@ $pag = new Paginator([
|
|||||||
$('#input-show_submit_mode').click(function() {
|
$('#input-show_submit_mode').click(function() {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
$.cookie('show_submit_mode', '', {
|
$.cookie('show_submit_mode', '', {
|
||||||
path: '/problems'
|
path: '/'
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$.removeCookie('show_submit_mode', {
|
$.removeCookie('show_submit_mode', {
|
||||||
path: '/problems'
|
path: '/'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
location.reload();
|
location.reload();
|
||||||
|
@ -37,33 +37,6 @@ 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 queryProblemTags($id) {
|
|
||||||
$tags = array();
|
|
||||||
$result = DB::query("select tag from problems_tags where problem_id = $id order by id");
|
|
||||||
while ($row = DB::fetch($result, MYSQLI_NUM)) {
|
|
||||||
$tags[] = $row[0];
|
|
||||||
}
|
|
||||||
return $tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
function queryProblemList($id) {
|
|
||||||
return DB::selectFirst("select * from lists where id = $id", MYSQLI_ASSOC);
|
|
||||||
}
|
|
||||||
function queryProblemListTags($id) {
|
|
||||||
$tags = array();
|
|
||||||
$result = DB::query("select tag from lists_tags where list_id = $id order by id");
|
|
||||||
if (!$result) {
|
|
||||||
return $tags;
|
|
||||||
}
|
|
||||||
while ($row = DB::fetch($result, MYSQLI_NUM)) {
|
|
||||||
$tags[] = $row[0];
|
|
||||||
}
|
|
||||||
return $tags;
|
|
||||||
}
|
|
||||||
function queryProblemInList($list_id, $problem_id) {
|
|
||||||
return DB::selectFirst("SELECT * FROM lists_problems WHERE list_id = '$list_id' AND problem_id = '$problem_id'", MYSQLI_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
function querySolution($problem_id, $blog_id) {
|
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);
|
return DB::selectFirst("select * from problems_solutions where blog_id='$blog_id' and problem_id='$problem_id'", MYSQLI_ASSOC);
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ class HTML {
|
|||||||
return '</' . $name . '>';
|
return '</' . $name . '>';
|
||||||
}
|
}
|
||||||
public static function tag(string $name, array $attr, $content) {
|
public static function tag(string $name, array $attr, $content) {
|
||||||
return HTML::tag_begin($name, $attr) . $content . HTML::tag_end($name);
|
return HTML::tag_begin($name, $attr) . (is_array($content) ? implode('', $content) : $content) . HTML::tag_end($name);
|
||||||
}
|
}
|
||||||
public static function empty_tag(string $name, array $attr) {
|
public static function empty_tag(string $name, array $attr) {
|
||||||
return '<' . $name . HTML::attr($attr) . ' />';
|
return '<' . $name . HTML::attr($attr) . ' />';
|
||||||
|
61
web/app/models/UOJList.php
Normal file
61
web/app/models/UOJList.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class UOJList {
|
||||||
|
use UOJDataTrait;
|
||||||
|
use UOJArticleTrait;
|
||||||
|
|
||||||
|
public static function query($id) {
|
||||||
|
if (!isset($id) || !validateUInt($id)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$info = DB::selectFirst([
|
||||||
|
"select * from lists",
|
||||||
|
"where", ["id" => $id]
|
||||||
|
]);
|
||||||
|
if (!$info) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new UOJList($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct($info) {
|
||||||
|
$this->info = $info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProblemIDs() {
|
||||||
|
return array_map(fn ($x) => $x['problem_id'], DB::selectAll([
|
||||||
|
DB::lc(), "select problem_id from lists_problems",
|
||||||
|
"where", ['list_id' => $this->info['id']],
|
||||||
|
"order by problem_id"
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasProblem(UOJProblem $problem) {
|
||||||
|
return DB::selectFirst([
|
||||||
|
DB::lc(), "select 1 from lists_problems",
|
||||||
|
"where", [
|
||||||
|
'list_id' => $this->info['id'],
|
||||||
|
'problem_id' => $problem->info['id']
|
||||||
|
]
|
||||||
|
]) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userCanManage(array $user = null) {
|
||||||
|
return isSuperUser($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userCanView(array $user = null, array $cfg = []) {
|
||||||
|
$cfg += ['ensure' => false];
|
||||||
|
if ($this->info['is_hidden'] && !$this->userCanManage($user)) {
|
||||||
|
$cfg['ensure'] && UOJResponse::page404();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UOJList::$table_for_content = 'lists_contents';
|
||||||
|
UOJList::$key_for_content = 'id';
|
||||||
|
UOJList::$fields_for_content = ['*'];
|
||||||
|
UOJList::$table_for_tags = 'lists_tags';
|
||||||
|
UOJList::$key_for_tags = 'list_id';
|
@ -4,7 +4,7 @@ class UOJRequest {
|
|||||||
const GET = 'get';
|
const GET = 'get';
|
||||||
const POST = 'post';
|
const POST = 'post';
|
||||||
|
|
||||||
public static function get($name, $val=null, $default=null) {
|
public static function get($name, $val = null, $default = null) {
|
||||||
if (!isset($_GET[$name])) {
|
if (!isset($_GET[$name])) {
|
||||||
return $default;
|
return $default;
|
||||||
}
|
}
|
||||||
@ -14,7 +14,7 @@ class UOJRequest {
|
|||||||
return $_GET[$name];
|
return $_GET[$name];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function post($name, $val=null, $default=null) {
|
public static function post($name, $val = null, $default = null) {
|
||||||
if (!isset($_POST[$name])) {
|
if (!isset($_POST[$name])) {
|
||||||
return $default;
|
return $default;
|
||||||
}
|
}
|
||||||
@ -24,7 +24,7 @@ class UOJRequest {
|
|||||||
return $_POST[$name];
|
return $_POST[$name];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function data(string $method, string $name, callable $val=null, $default=null) {
|
public static function data(string $method, string $name, callable $val = null, $default = null) {
|
||||||
if ($method == self::GET) {
|
if ($method == self::GET) {
|
||||||
return self::get($name, $val, $default);
|
return self::get($name, $val, $default);
|
||||||
} elseif ($method == self::POST) {
|
} elseif ($method == self::POST) {
|
||||||
|
@ -28,7 +28,7 @@ Route::group(
|
|||||||
|
|
||||||
Route::any('/lists', '/lists.php');
|
Route::any('/lists', '/lists.php');
|
||||||
Route::any('/list/{id}', '/list.php');
|
Route::any('/list/{id}', '/list.php');
|
||||||
Route::any('/list/{id}/edit(?:/{tab})?', '/list_edit.php');
|
Route::any('/list/{id}/manage(?:/{tab})?', '/list_manage.php');
|
||||||
|
|
||||||
Route::any('/contests', '/contests.php');
|
Route::any('/contests', '/contests.php');
|
||||||
Route::any('/contest/new', '/add_contest.php');
|
Route::any('/contest/new', '/add_contest.php');
|
||||||
|
6
web/app/upgrade/16_list_v3/up.sql
Normal file
6
web/app/upgrade/16_list_v3/up.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
CREATE TABLE `lists_contents` (
|
||||||
|
`id` int NOT NULL,
|
||||||
|
`content` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
`content_md` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
28
web/app/upgrade/16_list_v3/upgrade.php
Normal file
28
web/app/upgrade/16_list_v3/upgrade.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return function (string $type) {
|
||||||
|
if ($type == 'up_after_sql') {
|
||||||
|
DB::init();
|
||||||
|
|
||||||
|
$lists = DB::selectAll([
|
||||||
|
"select * from lists",
|
||||||
|
]);
|
||||||
|
$parsedown = HTML::parsedown();
|
||||||
|
$purifier = HTML::purifier();
|
||||||
|
|
||||||
|
foreach ($lists as $info) {
|
||||||
|
DB::insert([
|
||||||
|
"insert into lists_contents",
|
||||||
|
DB::bracketed_fields(['id', 'content', 'content_md']),
|
||||||
|
"values",
|
||||||
|
DB::tuple([
|
||||||
|
$info['id'],
|
||||||
|
$purifier->purify($parsedown->text($info['description'])),
|
||||||
|
$info['description'],
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::query("alter table lists drop column description");
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user