refactor(web/group): group v2

This commit is contained in:
Baoshuo Ren 2022-10-21 20:42:48 +08:00
parent c222f736fe
commit 639d09b8c3
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
18 changed files with 683 additions and 455 deletions

View File

@ -366,7 +366,7 @@ UNLOCK TABLES;
CREATE TABLE `countdowns` ( CREATE TABLE `countdowns` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` text NOT NULL, `title` text NOT NULL,
`endtime` datetime NOT NULL, `end_time` datetime NOT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@ -448,6 +448,21 @@ CREATE TABLE `groups` (
) 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 `groups_assignments`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `groups_assignments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`list_id` int(11) NOT NULL,
`group_id` int(11) NOT NULL,
`end_time` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;
-- --
-- Table structure for table `groups_users` -- Table structure for table `groups_users`
-- --
@ -461,22 +476,6 @@ CREATE TABLE `groups_users` (
) 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 `assignments`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `assignments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`list_id` int(11) NOT NULL,
`group_id` int(11) NOT NULL,
`create_time` datetime NOT NULL,
`deadline` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */;
-- --
-- Table structure for table `hacks` -- Table structure for table `hacks`
-- --

View File

@ -1,4 +1,5 @@
<?php <?php
requireLib('bootstrap5');
requirePHPLib('form'); requirePHPLib('form');
requirePHPLib('judger'); requirePHPLib('judger');
requirePHPLib('data'); requirePHPLib('data');
@ -16,20 +17,19 @@
become404Page(); become404Page();
} }
if (!isset($_COOKIE['bootstrap4'])) { if (!isSuperUser($myUser) && $group['is_hidden']) {
$REQUIRE_LIB['bootstrap5'] = ''; become403Page();
} }
?> ?>
<?php echoUOJPageHeader(UOJLocale::get('groups')) ?> <?php echoUOJPageHeader(UOJLocale::get('groups')) ?>
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
<div class="row"> <div class="row">
<!-- left col -->
<div class="col-lg-9"> <div class="col-lg-9">
<div class="d-flex justify-content-between">
<?php endif ?>
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?> <!-- title -->
<div class="d-flex justify-content-between">
<h1 class="h2"> <h1 class="h2">
<?php if ($group['is_hidden']): ?> <?php if ($group['is_hidden']): ?>
<span class="fs-5 text-danger">[隐藏]</span> <span class="fs-5 text-danger">[隐藏]</span>
@ -37,57 +37,48 @@
<?= $group['title'] ?> <?= $group['title'] ?>
<span class="fs-5">(ID: #<?= $group['id'] ?>)</span> <span class="fs-5">(ID: #<?= $group['id'] ?>)</span>
</h1> </h1>
<?php else: ?>
<h2 style="margin-top: 24px"><?= $group['title'] ?></h2>
<p>(<b>小组 ID</b>: <?= $group['id'] ?>)</p>
<?php endif ?>
<?php if (isSuperUser($myUser)): ?> <?php if (isSuperUser($myUser)): ?>
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
<div class="text-end"> <div class="text-end">
<a class="btn btn-primary" href="/group/<?= $group['id'] ?>/manage" role="button"> <a class="btn btn-primary" href="/group/<?= $group['id'] ?>/manage" role="button">
<?= UOJLocale::get('problems::manage') ?> <?= UOJLocale::get('problems::manage') ?>
</a> </a>
</div> </div>
<?php else: ?>
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item"><a class="nav-link" href="/group/<?= $group['id'] ?>/manage" role="tab">管理</a></li>
</ul>
<?php endif ?> <?php endif ?>
<?php endif ?>
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
</div> </div>
<?php endif ?> <!-- end title -->
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?> <!-- main content -->
<div class="card card-default mb-3"> <div class="card mb-3">
<div class="card-body">
<h2 class="h4">
<?= UOJLocale::get('group announcement') ?>
</h2>
<?php if ($group['announcement']): ?>
<div class="text-break">
<?= HTML::purifier_inline()->purify(HTML::parsedown()->line($group['announcement'])) ?>
</div>
<?php else: ?>
<div class="text-muted">
<?= UOJLocale::get('none') ?>
</div>
<?php endif ?>
</div>
</div>
<div class="card mb-3">
<div class="card-body"> <div class="card-body">
<h2 class="card-title h4"> <h2 class="card-title h4">
<?php else: ?>
<div class="row">
<div class="col-sm-12 mt-4">
<h5>
<?php endif ?>
<?= UOJLocale::get('news') ?> <?= UOJLocale::get('news') ?>
</h5> </h5>
<ul <ul class="mb-0">
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
class="mb-0"
<?php endif ?>
>
<?php <?php
$current_ac = queryGroupCurrentAC($group['id']); $current_ac = queryGroupCurrentAC($group['id']);
foreach ($current_ac as $ac) { foreach ($current_ac as $ac) {
echo '<li>'; echo '<li>';
echo getUserLink($ac['submitter']); echo getUserLink($ac['submitter']);
echo ' 解决了问题 '; echo ' 解决了问题 ';
echo '<a '; echo '<a class="text-decoration-none" href="/problem/', $ac['problem_id'], '">', $ac['problem_title'], '</a> ';
if (isset($REQUIRE_LIB['bootstrap5'])) {
echo ' class="text-decoration-none" ';
}
echo ' href="/problem/', $ac['problem_id'], '">', $ac['problem_title'], '</a> ';
echo '<time class="time">(', $ac['submit_time'], ')</time>'; echo '<time class="time">(', $ac['submit_time'], ')</time>';
echo '</li>'; echo '</li>';
} }
@ -99,94 +90,72 @@
</div> </div>
</div> </div>
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
<div class="card card-default mb-3"> <div class="card card-default mb-3">
<div class="card-body"> <div class="card-body">
<h2 class="card-title h4"> <h2 class="card-title h4">
<?php else: ?>
<div class="row">
<div class="col-sm-12 mt-4">
<h5>
<?php endif ?>
<?= UOJLocale::get('assignments') ?> <?= UOJLocale::get('assignments') ?>
</h5> </h5>
<ul <?php
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?> $now = new DateTime();
class="mb-0" echoLongTable(
<?php endif ?> ['groups_assignments.list_id as list_id', 'lists.title as title', 'groups_assignments.end_time as end_time'],
> 'groups_assignments left join lists on lists.id = groups_assignments.list_id',
<?php "groups_assignments.group_id = {$group['id']} and groups_assignments.end_time > addtime(now(), '-168:00:00')",
$assignments = queryGroupActiveAssignments($group['id']); 'order by end_time desc, list_id desc',
foreach ($assignments as $ass) { <<<EOD
$ddl = DateTime::createFromFormat('Y-m-d H:i:s', $ass['deadline']); <tr>
$create_time = DateTime::createFromFormat('Y-m-d H:i:s', $ass['create_time']); <th style="width:3em" class="text-center">ID</th>
$now = new DateTime(); <th style="width:12em">标题</th>
<th style="width:4em">状态</th>
<th style="width:8em">结束时间</th>
</tr>
EOD,
function($row) use ($group, $now) {
$end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']);
echo '<li>'; echo '<tr>';
echo '<a '; echo '<td class="text-center">', $row['list_id'], '</td>';
if (isset($REQUIRE_LIB['bootstrap5'])) { echo '<td>', '<a class="text-decoration-none" href="/group/', $group['id'], '/assignment/', $row['list_id'],'">', HTML::escape($row['title']), '</a>', '</td>';
echo ' class="text-decoration-none" '; if ($end_time < $now) {
} echo '<td class="text-danger">已结束</td>';
echo ' href="/problem_list/', $ass['list_id'], '">', $ass['title'], ' (题单 #', $ass['list_id'], ')</a>'; } else {
echo '<td class="text-success">进行中</td>';
if ($ddl < $now) { }
echo '<sup style="color:red">&nbsp;overdue</sup>'; echo '<td>', $end_time->format('Y-m-d H:i:s'), '</td>';
} elseif ($ddl->getTimestamp() - $now->getTimestamp() < 86400) { // 1d echo '</tr>';
echo '<sup style="color:red">&nbsp;soon</sup>'; },
} elseif ($now->getTimestamp() - $create_time->getTimestamp() < 86400) { // 1d [
echo '<sup style="color:red">&nbsp;new</sup>'; 'echo_full' => true,
} 'div_classes' => ['table-responsive'],
'table_classes' => ['table', 'align-middle', 'mb-0'],
$ddl_str = $ddl->format('Y-m-d H:i'); ]
echo ' (截止时间: ', $ddl_str, '<a '; );
if (isset($REQUIRE_LIB['bootstrap5'])) {
echo ' class="text-decoration-none" ';
}
echo ' href="/group/',$group['id'],'/assignment/', $ass['list_id'], '">查看完成情况</a>)';
echo '</li>';
}
if (count($assignments) == 0) {
echo '<p>暂无作业</p>';
}
?> ?>
</ul>
</div> </div>
</div> </div>
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
<div class="card card-default mb-3"> <div class="card card-default mb-3">
<div class="card-body"> <div class="card-body">
<h2 class="card-title h4"> <h2 class="card-title h4">
<?php else: ?>
<div class="row">
<div class="col-sm-12 mt-4">
<h5>
<?php endif ?>
<?= UOJLocale::get('top solver') ?> <?= UOJLocale::get('top solver') ?>
</h5> </h5>
<?php echoRanklist(array( <?php echoRanklist([
'echo_full' => true, 'page_len' => 50,
'group_id' => $group_id, 'group_id' => $group_id,
'by_accepted' => true, 'by_accepted' => true,
'table_classes' => isset($REQUIRE_LIB['bootstrap5']) 'table_classes' => ['table', 'text-center', 'mb-0'],
? array('table', 'text-center', 'mb-0') ]) ?>
: array('table', 'table-bordered', 'table-hover', 'table-striped', 'table-text-center')
)) ?>
</div> </div>
</div> </div>
<?php if (isset($REQUIRE_LIB['bootstrap5'])): ?>
<!-- end left col --> <!-- end left col -->
</div> </div>
<!-- right col --> <!-- right col -->
<aside class="col-lg-3 mt-3 mt-lg-0"> <aside class="col-lg-3 mt-3 mt-lg-0">
<?php uojIncludeView('sidebar', array()); ?> <?php uojIncludeView('sidebar'); ?>
</aside> </aside>
</div> </div>
<?php endif ?>
<?php echoUOJPageFooter() ?> <?php echoUOJPageFooter() ?>

View File

@ -40,83 +40,128 @@
<small class="fs-4">作业:</small><?= $list['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('/problem_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['create_time'] ?></li> <li>结束时间:<?= $assignment['end_time'] ?></li>
<li>结束时间:<?= $assignment['deadline'] ?></li>
</ul> </ul>
<?php <?php
$query = DB::query("select problem_id from lists_problems where list_id = {$list['id']}"); $problems = DB::selectAll("select problem_id from lists_problems where list_id = {$list['id']}");
$users = queryGroupUsers($group['id']);
$problem_ids = []; $problem_ids = [];
while ($row = DB::fetch($query)) { $usernames = [];
$problem_ids[] = $row['problem_id']; $n_users = count($users);
$n_problems = count($problems);
foreach ($problems as $problem) {
$problem_ids[] = $problem['problem_id'];
} }
$header_row = ''; sort($problem_ids);
$header_row .= '<tr>';
$header_row .= '<th style="width: 10em;">'.UOJLocale::get('username').'</th>'; foreach ($users as $user) {
$header_row .= '<th style="width: 2em;">'.UOJLocale::get('contests::total score').'</th>'; $usernames[] = $user['username'];
foreach ($problem_ids as $problem_id) {
$header_row .= '<th style="width: 2em;">' . '<a class="text-decoration-none" href="'.HTML::url('/problem/'.$problem_id).'">#'.$problem_id.'</a>' . '</th>';
} }
$header_row .= '</tr>';
// standings: rank => [user => [username, realname], scores[], rank]
$standings = [];
$print_row = function($row) use ($problem_ids) { foreach ($usernames as $username) {
$username = $row['username']; $user = queryUser($username);
$row = ['total_score' => 0];
$scores = []; $row['user'] = [
$sum = 0; 'username' => $user['username'],
$total_score = count($problem_ids) * 100; 'realname' => $user['realname'],
$query = DB::query("SELECT MAX(id), problem_id, MAX(score) FROM submissions WHERE (problem_id, score) IN (SELECT problem_id, MAX(score) FROM submissions WHERE submitter = '{$username}' AND problem_id IN (".implode(',', $problem_ids).") GROUP BY problem_id) AND submitter = '{$username}' GROUP BY problem_id"); ];
while ($row = DB::fetch($query)) {
$scores[$row['problem_id']] = [
'submission_id' => $row['MAX(id)'],
'score' => $row['MAX(score)'],
];
$sum += $row['MAX(score)'];
}
if ($sum == $total_score) {
echo '<tr class="table-success">';
} else {
echo '<tr>';
}
echo '<td>' . getUserLink($username) . '</td>';
echo '<td>';
echo '<span class="uoj-score" data-max="', $total_score, '">', $sum, '</span>';
echo '</td>';
foreach ($problem_ids as $problem_id) { foreach ($problem_ids as $problem_id) {
if (!isset($scores[$problem_id])) { $cond = "submitter = '{$user['username']}' AND problem_id = $problem_id";
echo '<td>'; $submission = DB::selectFirst("SELECT id, score FROM submissions INNER JOIN (SELECT MAX(score) AS score FROM submissions WHERE $cond) AS max USING (score) WHERE $cond ORDER BY submit_time DESC");
if ($submission) {
$row['scores'][] = [
'submission_id' => $submission['id'],
'score' => intval($submission['score']),
];
$row['total_score'] += $submission['score'];
} else { } else {
if ($scores[$problem_id]['score'] == 100) { $row['scores'][] = null;
echo '<td class="table-success">';
} else {
echo '<td>';
}
echo '<a class="text-decoration-none uoj-score" href="'.HTML::url('/submission/'.$scores[$problem_id]['submission_id']).'">'.$scores[$problem_id]['score'].'</a>';
} }
echo '</td>';
} }
echo '</tr>';
};
$from = "user_info a inner join groups_users b on (b.group_id = {$group['id']} and a.username = b.username)"; $standings[] = $row;
$col_names = array('a.username as username'); }
$cond = "1";
$tail = "order by a.username asc"; usort($standings, function($lhs, $rhs) {
$config = [ if ($lhs['total_score'] != $rhs['total_score']) {
'page_len' => 50, return $rhs['total_score'] - $lhs['total_score'];
'div_classes' => ['card', 'my-3', 'table-responsive', 'text-center'], }
'table_classes' => ['table', 'uoj-table', 'mb-0'],
];
echoLongTable($col_names, $from, $cond, $tail, $header_row, $print_row, $config); return strcmp($lhs['user']['username'], $rhs['user']['username']);
});
?> ?>
<div id="standings"></div>
<script>
var n_problems = <?= $n_problems ?>;
var max_total_score = <?= $n_problems * 100 ?>;
var standings = <?= json_encode($standings) ?>;
$('#standings').long_table(
standings,
1,
'<tr>' +
'<th style="width:10em"><?= UOJLocale::get('username') ?></th>' +
'<th style="width:2em"><?= UOJLocale::get('contests::total score') ?></th>' +
<?php foreach ($problem_ids as $problem_id): ?>
'<th style="width:2em">' +
'<a class="text-decoration-none" href="<?= HTML::url('/problem/' . $problem_id) ?>">#<?= $problem_id ?></a>' +
'</th>' +
<?php endforeach ?>
'</tr>',
function(row) {
var col_tr = '';
if (row['total_score'] == max_total_score) {
col_tr += '<tr class="table-success">';
} else {
col_tr += '<tr>';
}
col_tr += '<td>' + getUserLink(row['user']['username'], row['user']['realname']) + '</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>' +
'</td>';
for (var i = 0; i < row['scores'].length; i++) {
var col = row['scores'][i];
if (col) {
if (col['score'] == 100) {
col_tr += '<td class="table-success">';
} else {
col_tr += '<td>';
}
col_tr += '<a class="text-decoration-none uoj-score" href="/submission/' + col['submission_id'] + '" style="color:' + getColOfScore(col['score']) + '">' + col['score'] + '</a>';
col_tr += '</td>';
} else {
col_tr += '<td></td>';
}
}
col_tr += '</tr>';
return col_tr;
},
{
div_classes: ['card', 'my-3', 'table-responsive', 'text-center'],
table_classes: ['table', 'uoj-table', 'mb-0'],
page_len: 20,
}
);
</script>
<!-- end left col --> <!-- end left col -->
</div> </div>

View File

@ -3,6 +3,7 @@
redirectToLogin(); redirectToLogin();
} }
requireLib('bootstrap5');
requirePHPLib('form'); requirePHPLib('form');
requirePHPLib('judger'); requirePHPLib('judger');
requirePHPLib('data'); requirePHPLib('data');
@ -16,258 +17,453 @@
become403Page(); become403Page();
} }
$group_editor = new UOJBlogEditor(); if (isset($_GET['tab'])) {
$group_editor->name = 'group'; $cur_tab = $_GET['tab'];
$group_editor->blog_url = null; } else {
$group_editor->cur_data = array( $cur_tab = 'profile';
'title' => $group['title'], }
'tags' => array(),
'is_hidden' => $group['is_hidden']
);
$group_editor->label_text = array_merge($group_editor->label_text, array(
'view blog' => '保存小组信息',
'blog visibility' => '小组可见性'
));
$group_editor->show_editor = false;
$group_editor->show_tags = false;
$group_editor->save = function($data) {
global $group_id, $group;
DB::update("update `groups` set title = '".DB::escape($data['title'])."' where id = {$group_id}");
if ($data['is_hidden'] != $group['is_hidden'] ) {
DB::update("update `groups` set is_hidden = {$data['is_hidden']} where id = {$group_id}");
}
};
$group_editor->runAtServer();
$add_new_user_form = new UOJForm('add_new_user');
$add_new_user_form->addInput('new_username', 'text', '用户名', '',
function ($x) {
global $group_id;
if (!validateUsername($x)) {
return '用户名不合法';
}
$user = queryUser($x);
if (!$user) {
return '用户不存在';
}
if (queryUserInGroup($group_id, $x)) {
return '该用户已经在小组中';
}
return '';
},
null
);
$add_new_user_form->submit_button_config['align'] = 'compressed';
$add_new_user_form->submit_button_config['text'] = '添加到小组';
$add_new_user_form->handle = function() {
global $group_id, $myUser;
$username = $_POST['new_username'];
DB::insert("insert into groups_users (group_id, username) values ({$group_id}, '{$username}')");
};
$add_new_user_form->runAtServer();
$delete_user_form = new UOJForm('delete_user'); $tabs_info = [
$delete_user_form->addInput('del_username', 'text', '用户名', '', 'profile' => [
function ($x) { 'name' => '基本信息',
global $group_id; 'url' => "/group/{$group['id']}/manage/profile",
],
'assignments' => [
'name' => '作业管理',
'url' => "/group/{$group['id']}/manage/assignments",
],
'users' => [
'name' => '用户管理',
'url' => "/group/{$group['id']}/manage/users",
]
];
if (!isset($tabs_info[$cur_tab])) {
become404Page();
}
if (!validateUsername($x)) { if ($cur_tab == 'profile') {
return '用户名不合法'; $update_profile_form = new UOJForm('update_profile');
} $update_profile_form->addVInput('name', 'text', '名称', $group['title'],
if (!queryUserInGroup($group_id, $x)) { function($title, &$vdata) {
return '该用户不在小组中'; if ($title == '') {
return '名称不能为空';
}
if (strlen($title) > 100) {
return '名称过长';
}
if (HTML::escape($title) === '') {
return '无效编码';
}
$vdata['title'] = $title;
return '';
},
null
);
$update_profile_form->addVCheckboxes('is_hidden', [
'0' => '公开',
'1' => '隐藏',
], '可见性', $group['is_hidden']);
$update_profile_form->addVTextArea('announcement', '公告', $group['announcement'],
function($announcement, &$vdata) {
if (strlen($announcement) > 3000) {
return '公告过长';
}
$vdata['announcement'] = $announcement;
return '';
}, null);
$update_profile_form->handle = function($vdata) use ($group) {
$esc_title = DB::escape($vdata['title']);
$is_hidden = $_POST['is_hidden'];
$esc_announcement = $vdata['announcement'];
DB::update("UPDATE `groups` SET title = '$esc_title', is_hidden = '$is_hidden', announcement = '$esc_announcement' WHERE id = {$group['id']}");
dieWithJsonData(['status' => 'success', 'message' => '修改成功']);
};
$update_profile_form->setAjaxSubmit(<<<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['margin_class'] = 'mt-3';
$update_profile_form->submit_button_config['text'] = '更新';
$update_profile_form->runAtServer();
} elseif ($cur_tab == 'assignments') {
if (isset($_POST['submit-remove_assignment']) && $_POST['submit-remove_assignment'] == 'remove_assignment') {
$list_id = $_POST['list_id'];
if (!validateUInt($list_id)) {
dieWithAlert('题单 ID 不合法。');
} }
return ''; if (!queryAssignmentByGroupListID($group['id'], $list_id)) {
}, dieWithAlert('该题单不在作业中。');
null
);
$delete_user_form->submit_button_config['align'] = 'compressed';
$delete_user_form->submit_button_config['text'] = '从小组中删除';
$delete_user_form->handle = function() {
global $group_id, $myUser;
$username = $_POST['del_username'];
DB::query("delete from groups_users where username='{$username}' and group_id={$group_id}");
};
$delete_user_form->runAtServer();
$add_new_assignment_form = new UOJForm('add_new_assignment');
$add_new_assignment_form->addInput('new_assignment_list_id', 'text', '题单 ID', '',
function ($x) {
global $group_id;
if (!validateUInt($x)) {
return '题单 ID 不合法';
}
$list = queryProblemList($x);
if (!$list) {
return '题单不存在';
}
if ($list['is_hidden'] != 0) {
return '题单是隐藏的';
} }
if (queryAssignmentByGroupListID($group_id, $x)) { DB::delete("DELETE FROM `groups_assignments` WHERE `list_id` = $list_id AND `group_id` = {$group['id']}");
return '该题单已经在作业中';
dieWithAlert('移除成功!');
}
$add_new_assignment_form = new UOJForm('add_new_assignment');
$add_new_assignment_form->addVInput('new_assignment_list_id', 'text', '题单 ID', '',
function ($list_id, &$vdata) use ($group) {
if (!validateUInt($list_id)) {
return '题单 ID 不合法';
}
if (!($list = queryProblemList($list_id))) {
return '题单不存在';
}
if ($list['is_hidden'] != 0) {
return '题单是隐藏的';
}
if (queryAssignmentByGroupListID($group['id'], $list_id)) {
return '该题单已经在作业中';
}
$vdata['list_id'] = $list_id;
return '';
},
null
);
$default_end_time = new DateTime();
$default_end_time->setTime(17, 0, 0);
$default_end_time->add(new DateInterval("P7D"));
$add_new_assignment_form->addVInput('new_assignment_end_time', 'text', '截止时间', $default_end_time->format('Y-m-d H:i'),
function ($end_time, &$vdata) {
try {
$vdata['end_time'] = new DateTime($end_time);
} catch (Exception $e) {
return '无效时间格式';
}
return '';
},
null
);
$add_new_assignment_form->handle = function(&$vdata) use ($group) {
$esc_end_time = DB::escape($vdata['end_time']->format('Y-m-d H:i:s'));
DB::insert("insert into groups_assignments (group_id, list_id, end_time) values ({$group['id']}, '{$vdata['list_id']}', '{$esc_end_time}')");
dieWithJsonData([
'status' => 'success',
'message' => '题单 #' . $vdata['list_id'] . ' 已经被添加到作业列表中,结束时间为 ' . $vdata['end_time']->format('Y-m-d H:i:s') . '。'
]);
};
$add_new_assignment_form->submit_button_config['margin_class'] = 'mt-3';
$add_new_assignment_form->submit_button_config['text'] = '添加';
$add_new_assignment_form->setAjaxSubmit(<<<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();
} elseif ($cur_tab == 'users') {
if (isset($_POST['submit-remove_user']) && $_POST['submit-remove_user'] == 'remove_user') {
$username = $_POST['remove_username'];
if (!validateUsername($username)) {
dieWithAlert('用户名不合法。');
} }
return ''; if (!queryUser($username)) {
}, dieWithAlert('用户不存在。');
null
);
$default_ddl = new DateTime();
$default_ddl->setTime(17, 0, 0);
$default_ddl->add(new DateInterval("P7D"));
$add_new_assignment_form->addInput('new_assignment_deadline', 'text', '截止时间', $default_ddl->format('Y-m-d H:i'),
function ($x) {
$ddl = DateTime::createFromFormat('Y-m-d H:i', $x);
if (!$ddl) {
return '截止时间格式不正确,请以类似 "2020-10-1 17:00" 的格式输入';
} }
return ''; if (!queryUserInGroup($group['id'], $username)) {
}, dieWithAlert('该用户不在小组中。');
null
);
$add_new_assignment_form->submit_button_config['align'] = 'compressed';
$add_new_assignment_form->submit_button_config['text'] = '添加作业';
$add_new_assignment_form->handle = function() {
global $group_id, $myUser;
$list_id = $_POST['new_assignment_list_id'];
$ddl = DateTime::createFromFormat('Y-m-d H:i', $_POST['new_assignment_deadline']);
$ddl_str = $ddl->format('Y-m-d H:i:s');
DB::insert("insert into assignments (group_id, list_id, create_time, deadline) values ({$group_id}, '{$list_id}', now(), '{$ddl_str}')");
};
$add_new_assignment_form->runAtServer();
$remove_assignment_form = new UOJForm('remove_assignment');
$remove_assignment_form->addInput('remove_assignment_list_id', 'text', '题单 ID', '',
function ($x) {
global $group_id;
if (!validateUInt($x)) {
return '题单 ID 不合法';
}
if (!queryAssignmentByGroupListID($group_id, $x)) {
return '该题单不在作业中';
} }
return ''; DB::delete("DELETE FROM `groups_users` WHERE `username` = '$username' AND `group_id` = {$group['id']}");
},
null
);
$remove_assignment_form->submit_button_config['align'] = 'compressed'; dieWithAlert('移除成功!');
$remove_assignment_form->submit_button_config['text'] = '删除作业'; }
$remove_assignment_form->handle = function() {
global $group_id, $myUser;
$list_id = $_POST['remove_assignment_list_id'];
DB::query("delete from assignments where list_id='{$list_id}' and group_id={$group_id}"); $add_new_user_form = new UOJForm('add_new_user');
}; $add_new_user_form->addVInput('new_username', 'text', '用户名', '',
$remove_assignment_form->runAtServer(); function ($username, &$vdata) {
global $group_id;
$announcement_form = new UOJForm('announcement_form'); if (!validateUsername($username)) {
$announcement_form->addVTextArea('announcement_content', '公告', $group['announcement'], return '用户名不合法';
function ($x) { }
return '';
},
null
);
$announcement_form->submit_button_config['text'] = '更新公告';
$announcement_form->handle = function() {
global $group_id, $myUser;
$content = $_POST['announcement_content']; if (!queryUser($username)) {
$esc_content = DB::escape($content); return '用户不存在';
DB::query("update groups set announcement = '{$esc_content}' where id = {$group_id}"); }
};
$announcement_form->runAtServer(); if (queryUserInGroup($group_id, $username)) {
return '该用户已经在小组中';
}
$vdata['username'] = $username;
return '';
},
null
);
$add_new_user_form->submit_button_config['margin_class'] = 'mt-3';
$add_new_user_form->submit_button_config['text'] = '添加';
$add_new_user_form->handle = function(&$vdata) use ($group) {
DB::insert("insert into groups_users (group_id, username) values ({$group['id']}, '{$vdata['username']}')");
dieWithJsonData(['status' => 'success', 'message' => '已将用户名为 ' . $vdata['username'] . ' 的用户添加到本小组。']);
};
$add_new_user_form->setAjaxSubmit(<<<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_user_form->runAtServer();
}
?> ?>
<?php echoUOJPageHeader('管理 - ' . $group['title']); ?>
<?php echoUOJPageHeader($group['title'] . ' 管理'); ?> <h1 class="h2 d-block d-md-inline-block">
<?= $group['title'] ?>
<h1 class="h2"> <small class="fs-5">(ID: #<?= $group['id'] ?>)</small>
<?= $group['title'] ?>#<?= $group['id'] ?>)管理 管理
</h1> </h1>
<ul class="nav nav-tabs" role="tablist"> <div class="row mt-4">
<li class="nav-item"><a class="nav-link" href="/group/<?= $group['id'] ?>/manage" role="tab">管理</a></li> <!-- left col -->
<li class="nav-item"><a class="nav-link" href="/group/<?= $group['id'] ?>" role="tab">返回</a></li> <div class="col-md-3">
</ul>
<div class="top-buffer-md"></div> <?= HTML::navListGroup($tabs_info, $cur_tab) ?>
<h5>编辑小组信息</h5> <a
<div class="mb-4"> class="btn btn-light d-block mt-2 w-100 text-start text-primary"
<?php $group_editor->printHTML(); ?> 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> 返回
</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">
<h5>注意事项</h5>
<ul class="mb-0">
<li>隐藏的小组无法被普通用户查看,即使该用户属于本小组。</li>
<li>公告支持 Markdown 语法,但不支持添加数学公式。</li>
</ul>
</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
$now = new DateTime();
echoLongTable(
['*'],
'groups_assignments',
"group_id = {$group['id']}",
'order by end_time desc, list_id desc',
<<<EOD
<tr>
<th style="width:3em" 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 ($group, $now) {
$list = queryProblemList($row['list_id']);
$end_time = DateTime::createFromFormat('Y-m-d H:i:s', $row['end_time']);
echo '<tr>';
echo '<td class="text-center">', $list['id'], '</td>';
echo '<td>', '<a class="text-decoration-none" href="/group/', $group['id'], '/assignment/', $list['id'],'">', HTML::escape($list['title']), '</a>', '</td>';
if ($end_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="/problem_list/', $list['id'], '/edit">编辑</a> ';
echo ' <form class="d-inline-block" method="POST" onsubmit=\'return confirm("你真的要移除这份作业吗?移除作业不会删除题单。")\'>'
. '<input type="hidden" name="_token" value="' . crsf_token() . '">'
. '<input type="hidden" name="list_id" value="' . $list['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>如需延长结束时间请删除后再次添加,排行数据不会丢失。</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<?php elseif ($cur_tab == 'users'): ?>
<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="#users" data-bs-toggle="tab" data-bs-target="#users">用户列表</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#add-user" data-bs-toggle="tab" data-bs-target="#add-user">添加用户</a>
</li>
</ul>
</div>
<div class="card-body">
<div class="tab-content">
<div class="tab-pane active" id="users">
<?php
echoLongTable(
['*'],
'groups_users',
"group_id = {$group['id']}",
'order by username asc',
<<<EOD
<tr>
<th>用户名</th>
<th>操作</th>
</tr>
EOD,
function($row) use ($group) {
echo '<tr>';
echo '<td>', getUserLink($row['username']), '</td>';
echo '<td>';
echo '<form class="d-inline-block" method="POST" onsubmit=\'return confirm("你真的要从小组中移除这个用户吗?")\'>'
. '<input type="hidden" name="_token" value="' . crsf_token() . '">'
. '<input type="hidden" name="remove_username" value="' . $row['username'] . '">'
. '<button class="btn btn-link text-danger text-decoration-none p-0" type="submit" name="submit-remove_user" value="remove_user">移除</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-user">
<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_user_form->printHTML() ?>
</div>
<div class="col">
<h5>注意事项</h5>
<ul class="mb-0">
<li>添加用户前请确认用户名是否正确以免带来不必要的麻烦。</li>
<li>用户被添加到小组后将自动被加入组内的所有作业排行中。</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<?php endif ?>
</div>
</div> </div>
<h5>编辑小组公告</h5>
<?php $announcement_form->printHTML(); ?>
<h5>添加用户到小组</h5>
<?php $add_new_user_form->printHTML(); ?>
<h5>从小组中删除用户</h5>
<?php $delete_user_form->printHTML(); ?>
<h5>为小组添加作业</h5>
<?php $add_new_assignment_form->printHTML(); ?>
<h5>删除小组的作业</h5>
<?php $remove_assignment_form->printHTML(); ?>
<h5>已被自动隐藏的作业</h5>
<ul>
<?php
$assignments = queryGroupAssignments($group['id']);
foreach ($assignments as $ass) {
$ddl = DateTime::createFromFormat('Y-m-d H:i:s', $ass['deadline']);
$create_time = DateTime::createFromFormat('Y-m-d H:i:s', $ass['create_time']);
$now = new DateTime();
if ($now->getTimestamp() - $ddl->getTimestamp() <= 604800) {
continue;
} // 7d
echo '<li>';
echo '<a ';
if (isset($REQUIRE_LIB['bootstrap5'])) {
echo ' class="text-decoration-none" ';
}
echo ' href="/problem_list/', $ass['list_id'], '">', $ass['title'], ' (题单 #', $ass['list_id'], ')</a>';
if ($ddl < $now) {
echo '<sup style="color:red">&nbsp;overdue</sup>';
} elseif ($ddl->getTimestamp() - $now->getTimestamp() < 86400) { // 1d
echo '<sup style="color:red">&nbsp;soon</sup>';
} elseif ($now->getTimestamp() - $create_time->getTimestamp() < 86400) { // 1d
echo '<sup style="color:red">&nbsp;new</sup>';
}
$ddl_str = $ddl->format('Y-m-d H:i');
echo ' (截止时间: ', $ddl_str, '<a ';
if (isset($REQUIRE_LIB['bootstrap5'])) {
echo ' class="text-decoration-none" ';
}
echo ' href="/group/',$group['id'],'/assignment/', $ass['list_id'], '">查看完成情况</a>)';
echo '</li>';
}
if (count($assignments) == 0) {
echo '<p>暂无作业</p>';
}
?>
</ul>
<?php echoUOJPageFooter() ?> <?php echoUOJPageFooter() ?>

View File

@ -19,7 +19,7 @@
$count = $_result["count(*)"]; $count = $_result["count(*)"];
function throwError($msg) { function throwError($msg) {
returnJSONData(['status' => 'error', 'message' => $msg]); dieWithJsonData(['status' => 'error', 'message' => $msg]);
} }
$allowedTypes = [IMAGETYPE_PNG, IMAGETYPE_JPEG]; $allowedTypes = [IMAGETYPE_PNG, IMAGETYPE_JPEG];
@ -66,7 +66,7 @@
$existing_image = DB::selectFirst("SELECT * FROM users_images WHERE `hash` = '$hash'"); $existing_image = DB::selectFirst("SELECT * FROM users_images WHERE `hash` = '$hash'");
if ($existing_image) { if ($existing_image) {
returnJSONData(['status' => 'success', 'path' => $existing_image['path']]); dieWithJsonData(['status' => 'success', 'path' => $existing_image['path']]);
} }
$image = new Imagick($_FILES["image_upload_file"]["tmp_name"]); $image = new Imagick($_FILES["image_upload_file"]["tmp_name"]);
@ -92,7 +92,7 @@
DB::insert("INSERT INTO users_images (`path`, uploader, width, height, upload_time, size, `hash`) VALUES ('$filename', '{$myUser['username']}', $width, $height, now(), {$_FILES["image_upload_file"]["size"]}, '$hash')"); DB::insert("INSERT INTO users_images (`path`, uploader, width, height, upload_time, size, `hash`) VALUES ('$filename', '{$myUser['username']}', $width, $height, now(), {$_FILES["image_upload_file"]["size"]}, '$hash')");
returnJSONData(['status' => 'success', 'path' => $filename]); dieWithJsonData(['status' => 'success', 'path' => $filename]);
} elseif ($_POST['image_delete_submit'] == 'submit') { } elseif ($_POST['image_delete_submit'] == 'submit') {
crsf_defend(); crsf_defend();

View File

@ -1,6 +1,6 @@
<?php <?php
$blogs = DB::selectAll("select blogs.id, title, poster, post_time from important_blogs, blogs where is_hidden = 0 and important_blogs.blog_id = blogs.id order by level desc, important_blogs.blog_id desc limit 5"); $blogs = DB::selectAll("select blogs.id, title, poster, post_time from important_blogs, blogs where is_hidden = 0 and important_blogs.blog_id = blogs.id order by level desc, important_blogs.blog_id desc limit 5");
$countdowns = DB::selectAll("select * from countdowns order by endtime asc"); $countdowns = DB::selectAll("select * from countdowns order by end_time asc");
$friend_links = DB::selectAll("select * from friend_links order by level desc, id asc"); $friend_links = DB::selectAll("select * from friend_links order by level desc, id asc");
if (!isset($_COOKIE['bootstrap4'])) { if (!isset($_COOKIE['bootstrap4'])) {
@ -134,7 +134,7 @@
<?php endif ?> mb-0"> <?php endif ?> mb-0">
<?php foreach ($countdowns as $countdown): ?> <?php foreach ($countdowns as $countdown): ?>
<?php <?php
$enddate = strtotime($countdown['endtime']); $enddate = strtotime($countdown['end_time']);
$nowdate = time(); $nowdate = time();
$diff = floor(($enddate - $nowdate) / (24 * 60 * 60)); $diff = floor(($enddate - $nowdate) / (24 * 60 * 60));
?> ?>

View File

@ -56,12 +56,12 @@
$blog_id = $_POST['blog_id']; $blog_id = $_POST['blog_id'];
if (!validateUInt($blog_id)) { if (!validateUInt($blog_id)) {
die('<script>alert("移除失败:博客 ID 无效");</script>' . SCRIPT_REFRESH_AS_GET); dieWithAlert('移除失败:博客 ID 无效');
} }
DB::delete("DELETE FROM important_blogs WHERE blog_id = {$blog_id}"); DB::delete("DELETE FROM important_blogs WHERE blog_id = {$blog_id}");
die('<script>alert("移除成功!");</script>' . SCRIPT_REFRESH_AS_GET); dieWithAlert('移除成功!');
} }
$announcements = DB::selectAll("SELECT blogs.id as id, blogs.title as title, blogs.poster as poster, user_info.realname as realname, blogs.post_time as post_time, important_blogs.level as level, blogs.is_hidden as is_hidden FROM important_blogs INNER JOIN blogs ON important_blogs.blog_id = blogs.id INNER JOIN user_info ON blogs.poster = user_info.username ORDER BY level DESC, important_blogs.blog_id DESC"); $announcements = DB::selectAll("SELECT blogs.id as id, blogs.title as title, blogs.poster as poster, user_info.realname as realname, blogs.post_time as post_time, important_blogs.level as level, blogs.is_hidden as is_hidden FROM important_blogs INNER JOIN blogs ON important_blogs.blog_id = blogs.id INNER JOIN user_info ON blogs.poster = user_info.username ORDER BY level DESC, important_blogs.blog_id DESC");
@ -121,15 +121,15 @@
$countdown_id = $_POST['countdown_id']; $countdown_id = $_POST['countdown_id'];
if (!validateUInt($countdown_id)) { if (!validateUInt($countdown_id)) {
die('<script>alert("删除失败:倒计时 ID 无效");</script>' . SCRIPT_REFRESH_AS_GET); dieWithAlert('删除失败:倒计时 ID 无效');
} }
DB::delete("DELETE FROM countdowns WHERE id = {$countdown_id}"); DB::delete("DELETE FROM countdowns WHERE id = {$countdown_id}");
die('<script>alert("删除成功!");</script>' . SCRIPT_REFRESH_AS_GET); dieWithAlert('删除成功!');
} }
$countdowns = DB::selectAll("SELECT id, title, endtime FROM countdowns ORDER BY endtime ASC"); $countdowns = DB::selectAll("SELECT id, title, end_time FROM countdowns ORDER BY end_time ASC");
$add_countdown_form = new UOJForm('add_countdown'); $add_countdown_form = new UOJForm('add_countdown');
$add_countdown_form->addInput('countdown_title', 'text', '标题', '', $add_countdown_form->addInput('countdown_title', 'text', '标题', '',
@ -144,10 +144,10 @@
}, },
null null
); );
$add_countdown_form->addInput('countdown_endtime', 'text', '结束时间', date("Y-m-d H:i:s"), $add_countdown_form->addInput('countdown_end_time', 'text', '结束时间', date("Y-m-d H:i:s"),
function($endtime, &$vdata) { function($end_time, &$vdata) {
try { try {
$vdata['endtime'] = new DateTime($endtime); $vdata['end_time'] = new DateTime($end_time);
} catch (Exception $e) { } catch (Exception $e) {
return '无效时间格式'; return '无效时间格式';
} }
@ -158,9 +158,9 @@
); );
$add_countdown_form->handle = function(&$vdata) { $add_countdown_form->handle = function(&$vdata) {
$esc_title = DB::escape($vdata['title']); $esc_title = DB::escape($vdata['title']);
$esc_endtime = DB::escape($vdata['endtime']->format('Y-m-d H:i:s')); $esc_end_time = DB::escape($vdata['end_time']->format('Y-m-d H:i:s'));
DB::insert("INSERT INTO countdowns (title, endtime) VALUES ('{$esc_title}', '{$esc_endtime}')"); DB::insert("INSERT INTO countdowns (title, end_time) VALUES ('{$esc_title}', '{$esc_end_time}')");
}; };
$add_countdown_form->submit_button_config['align'] = 'compressed'; $add_countdown_form->submit_button_config['align'] = 'compressed';
$add_countdown_form->submit_button_config['text'] = '添加'; $add_countdown_form->submit_button_config['text'] = '添加';
@ -174,12 +174,12 @@
$item_id = $_POST['item_id']; $item_id = $_POST['item_id'];
if (!validateUInt($item_id)) { if (!validateUInt($item_id)) {
die('<script>alert("删除失败ID 无效");</script>' . SCRIPT_REFRESH_AS_GET); dieWithAlert('删除失败ID 无效');
} }
DB::delete("DELETE FROM links WHERE id = {$item_id}"); DB::delete("DELETE FROM links WHERE id = {$item_id}");
die('<script>alert("删除成功!");</script>' . SCRIPT_REFRESH_AS_GET); dieWithAlert('删除成功!');
} }
$links = DB::selectAll("SELECT `id`, `title`, `url`, `level` FROM `friend_links` ORDER BY `level` DESC, `id` ASC"); $links = DB::selectAll("SELECT `id`, `title`, `url`, `level` FROM `friend_links` ORDER BY `level` DESC, `id` ASC");
@ -315,7 +315,7 @@
DB::query("insert into user_info (username, realname, email, school, password, svn_password, register_time, usergroup) values ('$username', '$realname', '$email', '$school', '$password', '$svn_password', now(), 'U')"); DB::query("insert into user_info (username, realname, email, school, password, svn_password, register_time, usergroup) values ('$username', '$realname', '$email', '$school', '$password', '$svn_password', now(), 'U')");
returnJSONData(['status' => 'success', 'message' => '']); dieWithJsonData(['status' => 'success', 'message' => '']);
}; };
$register_form->setAjaxSubmit(<<<EOD $register_form->setAjaxSubmit(<<<EOD
function(res) { function(res) {
@ -370,7 +370,7 @@ EOD);
DB::query("update user_info set password = '$esc_password' where username = '$esc_username'"); DB::query("update user_info set password = '$esc_password' where username = '$esc_username'");
returnJSONData(['status' => 'success', 'message' => '用户 ' . $vdata['username'] . ' 的密码已经被成功重置。']); dieWithJsonData(['status' => 'success', 'message' => '用户 ' . $vdata['username'] . ' 的密码已经被成功重置。']);
}; };
$change_password_form->submit_button_config['margin_class'] = 'mt-3'; $change_password_form->submit_button_config['margin_class'] = 'mt-3';
$change_password_form->submit_button_config['text'] = '重置'; $change_password_form->submit_button_config['text'] = '重置';
@ -436,7 +436,7 @@ EOD);
break; break;
} }
returnJSONData(['status' => 'success', 'message' => '用户 ' . $username . ' 现在是 ' . $usergroup . '。']); dieWithJsonData(['status' => 'success', 'message' => '用户 ' . $username . ' 现在是 ' . $usergroup . '。']);
}; };
$change_usergroup_form->setAjaxSubmit(<<<EOD $change_usergroup_form->setAjaxSubmit(<<<EOD
function(res) { function(res) {
@ -539,17 +539,17 @@ EOD);
$image_id = $_POST['image_id']; $image_id = $_POST['image_id'];
if (!validateUInt($image_id)) { if (!validateUInt($image_id)) {
die('<script>alert("删除失败:图片 ID 无效");</script>' . SCRIPT_REFRESH_AS_GET); dieWithAlert('删除失败:图片 ID 无效');
} }
if (!($image = DB::selectFirst("SELECT * from users_images where id = $image_id"))) { if (!($image = DB::selectFirst("SELECT * from users_images where id = $image_id"))) {
die('<script>alert("删除失败:图片不存在");</script>' . SCRIPT_REFRESH_AS_GET); dieWithAlert('删除失败:图片不存在');
} }
unlink(UOJContext::storagePath().$result['path']); unlink(UOJContext::storagePath().$result['path']);
DB::delete("DELETE FROM users_images WHERE id = $image_id"); DB::delete("DELETE FROM users_images WHERE id = $image_id");
die('<script>alert("删除成功!");</script>' . SCRIPT_REFRESH_AS_GET); dieWithAlert('删除成功!');
} }
@ -710,7 +710,7 @@ EOD);
col_tr += '<tr>'; col_tr += '<tr>';
col_tr += '<td>' + row['title'] + '</td>'; col_tr += '<td>' + row['title'] + '</td>';
col_tr += '<td>' + row['endtime'] + '</td>'; col_tr += '<td>' + row['end_time'] + '</td>';
col_tr += '<td>' + col_tr += '<td>' +
'<form method="POST" onsubmit=\'return confirm("你真的要删除这个倒计时吗?")\'>' + '<form method="POST" onsubmit=\'return confirm("你真的要删除这个倒计时吗?")\'>' +
'<input type="hidden" name="_token" value="<?= crsf_token() ?>">' + '<input type="hidden" name="_token" value="<?= crsf_token() ?>">' +

View File

@ -179,7 +179,7 @@ EOD);
DB::update("UPDATE user_info SET email = '$esc_email', qq = '$esc_qq', sex = '$esc_sex', motto = '$esc_motto', codeforces_handle = '$esc_codeforces_handle', github = '$esc_github', website = '$esc_website', avatar_source = '$esc_avatar_source' WHERE username = '{$user['username']}'"); DB::update("UPDATE user_info SET email = '$esc_email', qq = '$esc_qq', sex = '$esc_sex', motto = '$esc_motto', codeforces_handle = '$esc_codeforces_handle', github = '$esc_github', website = '$esc_website', avatar_source = '$esc_avatar_source' WHERE username = '{$user['username']}'");
returnJSONData(['status' => 'success']); dieWithJsonData(['status' => 'success']);
}; };
$update_profile_form->submit_button_config['margin_class'] = 'mt-3'; $update_profile_form->submit_button_config['margin_class'] = 'mt-3';
$update_profile_form->submit_button_config['text'] = '更新'; $update_profile_form->submit_button_config['text'] = '更新';
@ -209,21 +209,21 @@ EOD);
$new_password = $_POST['new_password']; $new_password = $_POST['new_password'];
if (!validatePassword($old_password) || !checkPassword($user, $old_password)) { if (!validatePassword($old_password) || !checkPassword($user, $old_password)) {
returnJSONData(['status' => 'error', 'message' => '旧密码错误']); dieWithJsonData(['status' => 'error', 'message' => '旧密码错误']);
} }
if (!validatePassword($new_password)) { if (!validatePassword($new_password)) {
returnJSONData(['status' => 'error', 'message' => '新密码不合法']); dieWithJsonData(['status' => 'error', 'message' => '新密码不合法']);
} }
if ($old_password == $new_password) { if ($old_password == $new_password) {
returnJSONData(['status' => 'error', 'message' => '新密码不能与旧密码相同']); dieWithJsonData(['status' => 'error', 'message' => '新密码不能与旧密码相同']);
} }
$password = getPasswordToStore($new_password, $user['username']); $password = getPasswordToStore($new_password, $user['username']);
DB::update("UPDATE `user_info` SET `password` = '$password' where `username` = '{$user['username']}'"); DB::update("UPDATE `user_info` SET `password` = '$password' where `username` = '{$user['username']}'");
returnJSONData(['status' => 'success', 'message' => '密码修改成功']); dieWithJsonData(['status' => 'success', 'message' => '密码修改成功']);
} }
} elseif ($cur_tab == 'privilege') { } elseif ($cur_tab == 'privilege') {
if (isset($_POST['submit-privilege']) && $_POST['submit-privilege'] == 'privilege' && isSuperUser($myUser)) { if (isset($_POST['submit-privilege']) && $_POST['submit-privilege'] == 'privilege' && isSuperUser($myUser)) {
@ -254,7 +254,7 @@ EOD);
DB::update("UPDATE `user_info` SET `usertype` = '{$user['usertype']}' where `username` = '{$user['username']}'"); DB::update("UPDATE `user_info` SET `usertype` = '{$user['usertype']}' where `username` = '{$user['username']}'");
returnJSONData(['status' => 'success', 'message' => '权限修改成功']); dieWithJsonData(['status' => 'success', 'message' => '权限修改成功']);
} }
} }

View File

@ -1,4 +1,6 @@
<?php <?php
define('SCRIPT_REFRESH_AS_GET', '<script>;window.location = window.location.origin + window.location.pathname + (window.location.search.length ? window.location.search + "&" : "?") + "_refresh_" + (+new Date()) + "=" + (+new Date()) + window.location.hash;</script>');
class UOJForm { class UOJForm {
public $form_name; public $form_name;
public $succ_href; public $succ_href;
@ -862,8 +864,12 @@ EOD;
return $form; return $form;
} }
function returnJSONData($data) { function dieWithJsonData($data) {
header('Content-Type: application/json'); header('Content-Type: application/json');
die(json_encode($data)); die(json_encode($data));
} }
function dieWithAlert($str) {
die('<script>alert(decodeURIComponent("'.rawurlencode($str).'"));</script>'.SCRIPT_REFRESH_AS_GET);
}
?> ?>

View File

@ -130,6 +130,9 @@ function queryContestProblems($id) {
function queryGroup($id) { function queryGroup($id) {
return DB::selectFirst("select * from groups where id = $id", MYSQLI_ASSOC); return DB::selectFirst("select * from groups where id = $id", MYSQLI_ASSOC);
} }
function queryGroupUsers($id) {
return DB::selectAll("SELECT * FROM groups_users WHERE group_id = $id");
}
function queryUserInGroup($group_id, $username) { function queryUserInGroup($group_id, $username) {
return DB::selectFirst("select * from groups_users where username='$username' and group_id='$group_id'", MYSQLI_ASSOC); return DB::selectFirst("select * from groups_users where username='$username' and group_id='$group_id'", MYSQLI_ASSOC);
} }
@ -143,17 +146,13 @@ function queryGroupCurrentAC($group_id) {
return DB::selectAll("select a.problem_id as problem_id, a.submitter as submitter, a.submission_id as submission_id, b.submit_time as submit_time, d.title as problem_title, b.submit_time as submit_time, e.realname as realname from best_ac_submissions a inner join submissions b on (a.submission_id = b.id) inner join groups_users c on (a.submitter = c.username and c.group_id = $group_id) inner join problems d on (a.problem_id = d.id and d.is_hidden = 0) inner join user_info e on (a.submitter = e.username) where b.submit_time > addtime(now(), '-360:00:00') order by b.submit_time desc limit 10", MYSQLI_ASSOC); return DB::selectAll("select a.problem_id as problem_id, a.submitter as submitter, a.submission_id as submission_id, b.submit_time as submit_time, d.title as problem_title, b.submit_time as submit_time, e.realname as realname from best_ac_submissions a inner join submissions b on (a.submission_id = b.id) inner join groups_users c on (a.submitter = c.username and c.group_id = $group_id) inner join problems d on (a.problem_id = d.id and d.is_hidden = 0) inner join user_info e on (a.submitter = e.username) where b.submit_time > addtime(now(), '-360:00:00') order by b.submit_time desc limit 10", MYSQLI_ASSOC);
} }
function queryGroupAssignments($group_id) { function queryGroupAssignments($group_id) {
return DB::selectAll("select a.id as id, a.list_id as list_id, a.create_time as create_time, a.deadline as deadline, b.title from assignments a left join lists b on a.list_id = b.id where a.group_id = $group_id order by a.deadline asc", MYSQLI_ASSOC); return DB::selectAll("select a.id as id, a.list_id as list_id, a.end_time as end_time, b.title from groups_assignments a left join lists b on a.list_id = b.id where a.group_id = $group_id order by a.end_time asc", MYSQLI_ASSOC);
} }
function queryGroupActiveAssignments($group_id) { function queryGroupActiveAssignments($group_id) {
return DB::selectAll("select a.id as id, a.group_id as group_id, a.list_id as list_id, a.create_time as create_time, a.deadline as deadline, b.title from assignments a left join lists b on a.list_id = b.id where a.group_id = $group_id and a.deadline > addtime(now(), '-168:00:00') order by a.deadline asc", MYSQLI_ASSOC); return DB::selectAll("select a.id as id, a.group_id as group_id, a.list_id as list_id, a.end_time as end_time, b.title from groups_assignments a left join lists b on a.list_id = b.id where a.group_id = $group_id and a.end_time > addtime(now(), '-168:00:00') order by a.end_time asc", MYSQLI_ASSOC);
}
function queryAssignment($id) {
return DB::selectFirst("select * from assignments where id = $id", MYSQLI_ASSOC);
} }
function queryAssignmentByGroupListID($group_id, $list_id) { function queryAssignmentByGroupListID($group_id, $list_id) {
return DB::selectFirst("select * from assignments where list_id='$list_id' and group_id='$group_id'", MYSQLI_ASSOC); return DB::selectFirst("select * from groups_assignments where list_id='$list_id' and group_id='$group_id'", MYSQLI_ASSOC);
} }
function queryZanVal($id, $type, $user) { function queryZanVal($id, $type, $user) {

View File

@ -15,6 +15,7 @@ return [
'problems lists' => 'Problems Lists', 'problems lists' => 'Problems Lists',
'groups' => 'Groups', 'groups' => 'Groups',
'add new group' => 'Add new group', 'add new group' => 'Add new group',
'group announcement' => 'Group Announcement',
'group announcements' => 'Group Announcements', 'group announcements' => 'Group Announcements',
'users count' => 'Users', 'users count' => 'Users',
'submissions' => 'Submissions', 'submissions' => 'Submissions',

View File

@ -15,6 +15,7 @@ return [
'problems lists' => '题单', 'problems lists' => '题单',
'groups' => '小组', 'groups' => '小组',
'add new group' => '添加新小组', 'add new group' => '添加新小组',
'group announcement' => '小组公告',
'group announcements' => '小组公告', 'group announcements' => '小组公告',
'users count' => '用户数量', 'users count' => '用户数量',
'submissions' => '提交记录', 'submissions' => '提交记录',

View File

@ -49,7 +49,7 @@ Route::group([
Route::any('/groups', '/groups.php'); Route::any('/groups', '/groups.php');
Route::any('/group/{id}', '/group.php'); Route::any('/group/{id}', '/group.php');
Route::any('/group/{id}/manage', '/group_manage.php'); Route::any('/group/{id}/manage(?:/{tab})?', '/group_manage.php');
Route::any('/group/{id}/assignment/{list_id}', '/group_assignment.php'); Route::any('/group/{id}/assignment/{list_id}', '/group_assignment.php');
Route::any('/blogs', '/blogs.php'); Route::any('/blogs', '/blogs.php');

View File

@ -0,0 +1 @@
ref: https://github.com/renbaoshuo/S2OJ/pull/8

View File

@ -0,0 +1,4 @@
RENAME TABLE groups_assignments TO assignments;
ALTER TABLE `assignments` ADD COLUMN `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE `assignments` CHANGE COLUMN `end_time` `deadline` datetime NOT NULL;
ALTER TABLE `countdowns` CHANGE COLUMN `end_time` `endtime` datetime NOT NULL;

View File

@ -0,0 +1,4 @@
RENAME TABLE assignments TO groups_assignments;
ALTER TABLE `groups_assignments` DROP COLUMN `create_time`;
ALTER TABLE `groups_assignments` CHANGE COLUMN `deadline` `end_time` datetime NOT NULL;
ALTER TABLE `countdowns` CHANGE COLUMN `endtime` `end_time` datetime NOT NULL;

View File

@ -11,6 +11,8 @@
<?php <?php
$group_detail = DB::selectFirst("select * from groups where id = {$group['id']}"); $group_detail = DB::selectFirst("select * from groups where id = {$group['id']}");
$group_announcement = $group_detail['announcement']; $group_announcement = $group_detail['announcement'];
$purifier = HTML::purifier_inline();
$parsedown = HTML::parsedown();
?> ?>
<li class="list-group-item"> <li class="list-group-item">
<a class="fw-bold text-decoration-none" href="<?= HTML::url('/group/'.$group['id']) ?>"> <a class="fw-bold text-decoration-none" href="<?= HTML::url('/group/'.$group['id']) ?>">
@ -18,7 +20,7 @@
</a> </a>
<?php if ($group_announcement): ?> <?php if ($group_announcement): ?>
<div class="text-break"> <div class="text-break">
<?= HTML::purifier_inline()->purify($group_announcement) ?> <?= $purifier->purify($parsedown->line($group_announcement)) ?>
</div> </div>
<?php else: ?> <?php else: ?>
<div class="text-muted"> <div class="text-muted">
@ -38,11 +40,13 @@
} }
usort($assignments, function($a, $b) { usort($assignments, function($a, $b) {
$deadline_a = DateTime::createFromFormat('Y-m-d H:i:s', $a['deadline']); $end_time_a = DateTime::createFromFormat('Y-m-d H:i:s', $a['end_time']);
$deadline_b = DateTime::createFromFormat('Y-m-d H:i:s', $b['deadline']); $end_time_b = DateTime::createFromFormat('Y-m-d H:i:s', $b['end_time']);
return $deadline_b->getTimestamp() - $deadline_a->getTimestamp(); return $end_time_b->getTimestamp() - $end_time_a->getTimestamp();
}); });
$assignments = array_slice($assignments, 0, 5);
?> ?>
<?php if (count($assignments)): ?> <?php if (count($assignments)): ?>
<div class="card card-default mb-2" id="group-assignments"> <div class="card card-default mb-2" id="group-assignments">
@ -53,22 +57,19 @@
<?php foreach ($assignments as $assignment): ?> <?php foreach ($assignments as $assignment): ?>
<li class="list-group-item"> <li class="list-group-item">
<?php <?php
$deadline = DateTime::createFromFormat('Y-m-d H:i:s', $assignment['deadline']); $end_time = DateTime::createFromFormat('Y-m-d H:i:s', $assignment['end_time']);
$create_time = DateTime::createFromFormat('Y-m-d H:i:s', $assignment['create_time']);
$now = new DateTime(); $now = new DateTime();
?> ?>
<a href="<?= HTML::url('/group/'.$assignment['group_id'].'/assignment/'.$assignment['list_id']) ?>" class="fw-bold text-decoration-none"> <a href="<?= HTML::url('/group/'.$assignment['group_id'].'/assignment/'.$assignment['list_id']) ?>" class="fw-bold text-decoration-none">
<?= $assignment['title'] ?> <?= $assignment['title'] ?>
<?php if ($deadline < $now): ?> <?php if ($end_time < $now): ?>
<sup class="fw-normal text-danger">overdue</sup> <sup class="fw-normal text-danger">overdue</sup>
<?php elseif ($deadline->getTimestamp() - $now->getTimestamp() < 86400): ?> <?php elseif ($end_time->getTimestamp() - $now->getTimestamp() < 86400): ?>
<sup class="fw-normal text-danger">soon</sup> <sup class="fw-normal text-danger">soon</sup>
<?php elseif ($now->getTimestamp() - $create_time->getTimestamp() < 86400): ?>
<sup class="fw-normal text-danger">new</sup>
<?php endif ?> <?php endif ?>
</a> </a>
<div class="text-end small text-muted"> <div class="text-end small text-muted">
截止时间: <?= $deadline->format('Y-m-d H:i') ?> 截止时间: <?= $end_time->format('Y-m-d H:i') ?>
</div> </div>
</li> </li>
<?php endforeach ?> <?php endforeach ?>

View File

@ -51,11 +51,13 @@ label {
float: right; float: right;
} }
.uoj-table > tbody > tr:last-child { .uoj-table > tbody > tr:last-child,
.uoj-table > tbody > tr:last-child > td {
border-bottom-color: transparent; border-bottom-color: transparent;
} }
.uoj-table > thead > tr:first-child { .uoj-table > thead > tr:first-child,
.uoj-table > thead > tr:first-child > td {
border-top-color: transparent; border-top-color: transparent;
} }