'
diff --git a/web/app/models/UOJBlog.php b/web/app/models/UOJBlog.php
index 0d391c3..585d2f9 100644
--- a/web/app/models/UOJBlog.php
+++ b/web/app/models/UOJBlog.php
@@ -10,7 +10,7 @@ class UOJBlog {
}
$info = DB::selectFirst([
"select id, title, post_time, active_time, poster, zan, is_hidden, type from blogs",
- "where", ['id' => $id]
+ "where", ['id' => $id]
]);
if (!$info) {
return null;
@@ -21,7 +21,7 @@ class UOJBlog {
public function __construct($info) {
$this->info = $info;
}
-
+
/**
* Check if the blog belongs to the current user blog
*/
@@ -30,7 +30,25 @@ class UOJBlog {
}
public function userCanView(array $user = null) {
- return !$this->info['is_hidden'] || $this->userCanManage($user);
+ if ($this->userCanManage($user)) {
+ return true;
+ }
+
+ if ($this->info['poster'] != $user['username'] && !UOJUser::checkPermission($user, 'blogs.view')) {
+ return false;
+ }
+
+ if ($problem_id = $this->getSolutionProblemId()) {
+ $contests = UOJContest::queryContestsHasProblem($problem_id);
+
+ foreach ($contests as $contest) {
+ if ($contest->userHasRegistered($user) && $contest->progress() <= CONTEST_IN_PROGRESS) {
+ return false;
+ }
+ }
+ }
+
+ return !$this->info['is_hidden'];
}
public function userCanManage(array $user = null) {
@@ -70,7 +88,7 @@ class UOJBlog {
$link .= "{$level_str} ";
}
}
- $link .= '
'.$this->getTitle($cfg).'';
+ $link .= '
' . $this->getTitle($cfg) . '';
if (!empty($cfg['show_new_tag'])) {
if ($this->isNew()) {
$link .= '
new';
@@ -104,7 +122,7 @@ class UOJBlog {
return '';
}
}
-
+
public function queryNewestComment() {
return DB::selectFirst([
"select * from blogs_comments",
@@ -116,15 +134,15 @@ class UOJBlog {
DB::limit(1)
]);
}
-
+
public function updateActiveTime() {
$active_time = $this->info['post_time'];
-
+
$newest = $this->queryNewestComment();
if ($newest) {
$active_time = $newest['post_time'];
}
-
+
DB::update([
"update blogs",
"set", ['active_time' => $active_time],
@@ -191,6 +209,15 @@ class UOJBlog {
];
uojIncludeView('blog-preview', $cfg);
}
+
+ public function getSolutionProblemId() {
+ return DB::selectSingle([
+ DB::lc(), "select 1 from problems_solutions",
+ "where", [
+ "blog_id" => $this->info['id'],
+ ],
+ ]);
+ }
}
UOJBlog::$table_for_content = 'blogs';
diff --git a/web/app/models/UOJContest.php b/web/app/models/UOJContest.php
index 05609c9..ab3186e 100644
--- a/web/app/models/UOJContest.php
+++ b/web/app/models/UOJContest.php
@@ -28,12 +28,22 @@ class UOJContest {
]));
}
+ public static function queryContestsHasProblem(UOJProblem $problem) {
+ return array_map(fn ($x) => UOJContest::query($x['contest_id']), DB::selectAll([
+ "select contest_id from contests_problems",
+ "where", [
+ "problem_id" => $problem->info['id'],
+ ],
+ "order by contest_id",
+ ]));
+ }
+
public static function userCanManageSomeContest(array $user = null) {
if (!$user) {
return false;
}
- if (isSuperUser($user)) {
+ if (isSuperUser($user) || UOJUser::checkPermission($user, 'contests.manage')) {
return true;
}
@@ -45,6 +55,14 @@ class UOJContest {
]) != null;
}
+ public static function userCanCreateContest(array $user = null) {
+ if (!$user) {
+ return false;
+ }
+
+ return isSuperUser($user) || UOJUser::checkPermission($user, 'contests.create');
+ }
+
public static function finalTest() {
$contest = self::info();
@@ -117,7 +135,7 @@ class UOJContest {
calcStandings($contest, $data, $score, $standings, ['update_contests_submissions' => true]);
for ($i = 0; $i < count($standings); $i++) {
- $user_link = getUserLink($standings[$i][2][0]);
+ $user_link = UOJUser::getLink($standings[$i][2][0]);
$tail = $standings[$i][0] == $total_score ? ',请继续保持。' : ',请继续努力!';
$content = '
' . $user_link . ' 您好:
';
@@ -306,6 +324,10 @@ class UOJContest {
$cfg['ensure'] && $this->redirectToAnnouncementBlog();
return false;
}
+ if (!UOJUser::checkPermission($user, 'contests.register')) {
+ $cfg['ensure'] && UOJResponse::page403();
+ return false;
+ }
if ($this->progress() == CONTEST_IN_PROGRESS && !$this->allowExtraRegistration()) {
$cfg['ensure'] && redirectTo('/contests');
return false;
@@ -351,6 +373,7 @@ class UOJContest {
return true;
}
+
if ($cfg['ensure']) {
if ($this->info['extra_config']['extra_registration']) {
redirectTo($this->getUri('/register'));
@@ -358,11 +381,17 @@ class UOJContest {
UOJResponse::message("
比赛正在进行中
很遗憾,您尚未报名。比赛结束后再来看吧~
");
}
}
+
return false;
} else {
return true;
}
} else {
+ if (!$this->userHasRegistered($user) && !UOJUser::checkPermission($user, 'contests.view')) {
+ $cfg['ensure'] && UOJResponse::page403();
+ return false;
+ }
+
return true;
}
}
@@ -381,9 +410,11 @@ class UOJContest {
if (!$user) {
return false;
}
- if (isSuperUser($user)) {
+
+ if (isSuperUser($user) || UOJUser::checkPermission($user, 'contests.manage')) {
return true;
}
+
return DB::selectFirst([
DB::lc(), "select 1 from contests_permissions",
"where", [
@@ -393,6 +424,10 @@ class UOJContest {
]) != null;
}
+ public function userCanStartFinalTest(array $user = null) {
+ return $this->userCanManage($user) || UOJUser::checkPermission($user, 'contests.start_final_test');
+ }
+
public function userHasRegistered(array $user = null) {
if (!$user) {
return false;
@@ -473,6 +508,10 @@ class UOJContest {
return HTML::tag('a', ['class' => $cfg['class'], 'href' => $this->getUri($cfg['where'])], $this->info['name']);
}
+ public function getZanBlock() {
+ return ClickZans::getBlock('C', $this->info['id'], $this->info['zan']);
+ }
+
public function redirectToAnnouncementBlog() {
$url = getContestBlogLink($this->info, '公告');
if ($url !== null) {
diff --git a/web/app/models/UOJContext.php b/web/app/models/UOJContext.php
index b5736d1..69fb082 100644
--- a/web/app/models/UOJContext.php
+++ b/web/app/models/UOJContext.php
@@ -2,13 +2,46 @@
class UOJContext {
public static $meta_default = [
- 'active_duration_M' => 12,
+ 'users_default_permissions' => [
+ 'problems' => [
+ 'view' => true,
+ 'download_testdata' => false,
+ 'create' => false,
+ 'manage' => false,
+ ],
+ 'contests' => [
+ 'view' => true,
+ 'register' => true,
+ 'create' => false,
+ 'start_final_test' => false,
+ 'manage' => false,
+ ],
+ 'lists' => [
+ 'view' => true,
+ 'create' => false,
+ 'manage' => false,
+ ],
+ 'groups' => [
+ 'view' => true,
+ 'create' => false,
+ 'manage' => false,
+ ],
+ 'blogs' => [
+ 'view' => true,
+ 'create' => true,
+ 'manage' => false,
+ ],
+ 'users' => [
+ 'view' => true,
+ 'upload_image' => true,
+ ],
+ ],
];
public static $data = [
'type' => 'main'
];
-
+
public static function pageConfig() {
switch (self::$data['type']) {
case 'main':
@@ -23,23 +56,23 @@ class UOJContext {
];
}
}
-
+
public static function isAjax() {
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
}
-
+
public static function contentLength() {
if (!isset($_SERVER['CONTENT_LENGTH'])) {
return null;
}
return (int)$_SERVER['CONTENT_LENGTH'];
}
-
+
public static function documentRoot() {
return $_SERVER['DOCUMENT_ROOT'];
}
public static function storagePath() {
- return $_SERVER['DOCUMENT_ROOT'].'/app/storage';
+ return $_SERVER['DOCUMENT_ROOT'] . '/app/storage';
}
public static function remoteAddr() {
return $_SERVER['REMOTE_ADDR'];
@@ -100,7 +133,7 @@ class UOJContext {
if (validateIP($domain) || strpos($domain, '.') === false) {
$domain = '';
} else {
- $domain = '.'.$domain;
+ $domain = '.' . $domain;
}
return $domain;
}
@@ -112,7 +145,7 @@ class UOJContext {
public static function type() {
return self::$data['type'];
}
-
+
public static function setupBlog() {
UOJUserBlog::init();
self::$data['type'] = 'blog';
diff --git a/web/app/models/UOJForm.php b/web/app/models/UOJForm.php
index 870fd36..e41d51b 100644
--- a/web/app/models/UOJForm.php
+++ b/web/app/models/UOJForm.php
@@ -1,36 +1,41 @@
[
+ 'is_big' => false,
+ 'has_file' => false,
+ 'ctrl_enter_submit' => false,
+ 'max_post_size' => 15728640, // 15M
+ 'max_file_size_mb' => 10, // 10M
+ 'form' => [
'class' => '',
],
+ 'submit_container' => [
+ 'class' => 'mt-3 text-center',
+ ],
'submit_button' => [
+ 'class' => 'btn btn-primary',
+ 'text' => '提交',
+ ],
+ 'back_button' => [
+ 'href' => null,
'class' => 'btn btn-secondary',
],
+ 'confirm' => [
+ 'smart' => false,
+ 'text' => null,
+ ]
];
- public $submit_button_config = [];
- public $control_label_config = ['class' => 'col-sm-2'];
- public $input_config = ['class' => 'col-sm-3'];
- public $textarea_config = ['class' => 'col-sm-10'];
public function __construct($form_name) {
$this->form_name = $form_name;
@@ -42,7 +47,7 @@ class UOJForm {
die(json_encode($this->validateAtServer()));
};
$this->run_at_server_handler["submit-{$this->form_name}"] = function () {
- if ($this->no_submit) {
+ if ($this->config['no_submit']) {
UOJResponse::page404();
}
foreach ($this->data as $field) {
@@ -55,7 +60,7 @@ class UOJForm {
$len = UOJContext::contentLength();
if ($len === null) {
UOJResponse::page403();
- } elseif ($len > $this->max_post_size) {
+ } elseif ($len > $this->config['max_post_size']) {
UOJResponse::message('The form is too large.');
}
}
@@ -87,14 +92,11 @@ class UOJForm {
public function add($name, $html, $validator_php, $validator_js) {
$this->main_html .= $html;
- $this->data[] = array(
+ $this->data[] = [
'name' => $name,
'validator_php' => $validator_php,
'validator_js' => $validator_js
- );
- }
- public function appendHTML($html) {
- $this->main_html .= $html;
+ ];
}
public function addNoVal($name, $html) {
@@ -106,6 +108,10 @@ class UOJForm {
);
}
+ public function appendHTML($html) {
+ $this->main_html .= $html;
+ }
+
public function addHidden($name, $default_value, $validator_php, $validator_js) {
$default_value = HTML::escape($default_value);
$html = <<
add($name, $html, $validator_php, $validator_js);
}
- public function printHTML() {
- $form_entype_str = $this->is_big ? ' enctype="multipart/form-data"' : '';
+ public function addCheckbox($name, $config) {
+ $config += [
+ 'checked' => false,
+ 'div_class' => 'form-check',
+ 'role' => 'checkbox',
+ 'input_class' => 'form-check-input',
+ 'label' => '',
+ 'label_class' => 'form-check-label',
+ 'help' => '',
+ 'help_class' => 'form-text',
+ 'disabled' => false,
+ ];
- echo '