mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-11-21 21:08:42 +00:00
feat(contest): contest resources (#40)
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
433e56c3eb
@ -181,7 +181,7 @@ CREATE TABLE `contests` (
|
||||
`last_min` int NOT NULL,
|
||||
`player_num` int NOT NULL DEFAULT '0',
|
||||
`status` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`extra_config` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '{}',
|
||||
`extra_config` json NOT NULL,
|
||||
`zan` int NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `status` (`status`,`id`) USING BTREE
|
||||
@ -995,7 +995,8 @@ INSERT INTO `upgrades` (`name`, `status`, `updated_at`) VALUES
|
||||
('21_problem_difficulty', 'up', now()),
|
||||
('28_remote_judge', 'up', now()),
|
||||
('31_problem_resources', 'up', now()),
|
||||
('36_decimal_score_range', 'up', now());
|
||||
('36_decimal_score_range', 'up', now()),
|
||||
('40_contest_resources', 'up', now());
|
||||
/*!40000 ALTER TABLE `upgrades` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
|
@ -71,8 +71,9 @@ $time_form->handle = function (&$vdata) {
|
||||
|
||||
DB::insert([
|
||||
"insert into contests",
|
||||
"(name, start_time, last_min, status)", "values",
|
||||
DB::tuple([$vdata['name'], $start_time_str, $vdata['last_min'], 'unfinished'])
|
||||
DB::bracketed_fields(["name", "start_time", "last_min", "status", "extra_config"]),
|
||||
"values",
|
||||
DB::tuple([$vdata['name'], $start_time_str, $vdata['last_min'], 'unfinished', "{}"])
|
||||
]);
|
||||
};
|
||||
$time_form->succ_href = "/contests";
|
||||
|
@ -64,7 +64,7 @@ if (UOJContest::cur()->userCanStartFinalTest(Auth::user())) {
|
||||
$start_test_form->config['confirm']['smart'] = true;
|
||||
$start_test_form->runAtServer();
|
||||
}
|
||||
if ($contest['cur_progress'] >= CONTEST_TESTING && UOJContest::cur()->queryJudgeProgress()['fully_judged']) {
|
||||
if ($contest['cur_progress'] == CONTEST_TESTING && UOJContest::cur()->queryJudgeProgress()['fully_judged']) {
|
||||
$publish_result_form = new UOJForm('publish_result');
|
||||
$publish_result_form->handle = function () {
|
||||
UOJContest::announceOfficialResults();
|
||||
@ -492,133 +492,132 @@ function echoSelfReviews() {
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div <?php if ($cur_tab == 'standings' || $cur_tab == 'after_contest_standings' || $cur_tab == 'self_reviews') : ?> class="col-12" <?php else : ?> class="col-md-9" <?php endif ?>>
|
||||
<?= HTML::tablist($tabs_info, $cur_tab, 'nav-pills') ?>
|
||||
<?php if ($cur_tab == 'standings' || $cur_tab == 'after_contest_standings' || $cur_tab == 'self_reviews') : ?>
|
||||
<div class="d-none d-md-block text-center">
|
||||
<h1 class="mt-2 mb-3"><?= $contest['name'] ?></h1>
|
||||
<div class="small text-muted">
|
||||
<?php if ($contest['cur_progress'] <= CONTEST_NOT_STARTED) : ?>
|
||||
<?= UOJLocale::get('contests::not started') ?>
|
||||
<?php elseif ($contest['cur_progress'] <= CONTEST_IN_PROGRESS) : ?>
|
||||
<?= UOJLocale::get('contests::in progress') ?>
|
||||
<?php elseif ($contest['cur_progress'] <= CONTEST_PENDING_FINAL_TEST) : ?>
|
||||
<?= UOJLocale::get('contests::pending final test') ?>
|
||||
<?php elseif ($contest['cur_progress'] <= CONTEST_TESTING) : ?>
|
||||
<?= UOJLocale::get('contests::final testing') ?>
|
||||
<?php else : ?>
|
||||
<?= UOJLocale::get('contests::ended') ?>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="mt-3">
|
||||
<?php
|
||||
if ($cur_tab == 'dashboard') {
|
||||
echoDashboard();
|
||||
} elseif ($cur_tab == 'submissions') {
|
||||
echoMySubmissions();
|
||||
} elseif ($cur_tab == 'standings') {
|
||||
echoStandings();
|
||||
} elseif ($cur_tab == 'after_contest_standings') {
|
||||
echoStandings(true);
|
||||
} elseif ($cur_tab == 'backstage') {
|
||||
echoBackstage();
|
||||
} elseif ($cur_tab == 'self_reviews') {
|
||||
echoSelfReviews();
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($cur_tab == 'standings' || $cur_tab == 'after_contest_standings' || $cur_tab == 'self_reviews') : ?>
|
||||
<div class="col-12">
|
||||
<?php else : ?>
|
||||
<div class="col-md-9">
|
||||
<?php endif ?>
|
||||
<?= HTML::tablist($tabs_info, $cur_tab, 'nav-pills') ?>
|
||||
<?php if ($cur_tab == 'standings' || $cur_tab == 'after_contest_standings' || $cur_tab == 'self_reviews') : ?>
|
||||
<div class="d-none d-md-block text-center">
|
||||
<h1 class="mt-2 mb-3"><?= $contest['name'] ?></h1>
|
||||
<div class="small text-muted">
|
||||
<?php if ($contest['cur_progress'] <= CONTEST_NOT_STARTED) : ?>
|
||||
<?= UOJLocale::get('contests::not started') ?>
|
||||
<?php elseif ($contest['cur_progress'] <= CONTEST_IN_PROGRESS) : ?>
|
||||
<?= UOJLocale::get('contests::in progress') ?>
|
||||
<?php elseif ($contest['cur_progress'] <= CONTEST_PENDING_FINAL_TEST) : ?>
|
||||
<?= UOJLocale::get('contests::pending final test') ?>
|
||||
<?php else : ?>
|
||||
<hr class="d-md-none" />
|
||||
|
||||
<div class="col-md-3">
|
||||
<div class="card card-default mb-2">
|
||||
<div class="card-body">
|
||||
<h3 class="h4 card-title text-center">
|
||||
<a class="text-decoration-none text-body" href="<?= UOJContest::cur()->getUri() ?>">
|
||||
<?= UOJContest::info('name') ?>
|
||||
</a>
|
||||
</h3>
|
||||
<div class="card-text text-center text-muted">
|
||||
<?php if ($contest['cur_progress'] <= CONTEST_IN_PROGRESS) : ?>
|
||||
<span id="contest-countdown"></span>
|
||||
<script type="text/javascript">
|
||||
$('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJTime::$time_now->getTimestamp() ?>, function() {}, '1.75rem', false);
|
||||
</script>
|
||||
<?php elseif ($contest['cur_progress'] <= CONTEST_TESTING) : ?>
|
||||
<?= UOJLocale::get('contests::final testing') ?>
|
||||
<?php $judge_progress = UOJContest::cur()->queryJudgeProgress() ?>
|
||||
<?= $judge_progress['title'] ?> (<?= $judge_progress['rop'] ?>%)
|
||||
<?php else : ?>
|
||||
<?= UOJLocale::get('contests::ended') ?>
|
||||
<?= UOJLocale::get('contests::contest ended') ?>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="mt-3">
|
||||
<?php
|
||||
if ($cur_tab == 'dashboard') {
|
||||
echoDashboard();
|
||||
} elseif ($cur_tab == 'submissions') {
|
||||
echoMySubmissions();
|
||||
} elseif ($cur_tab == 'standings') {
|
||||
echoStandings();
|
||||
} elseif ($cur_tab == 'after_contest_standings') {
|
||||
echoStandings(true);
|
||||
} elseif ($cur_tab == 'backstage') {
|
||||
echoBackstage();
|
||||
} elseif ($cur_tab == 'self_reviews') {
|
||||
echoSelfReviews();
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($cur_tab == 'standings' || $cur_tab == 'after_contest_standings' || $cur_tab == 'self_reviews') : ?>
|
||||
<?php else : ?>
|
||||
<div class="d-md-none">
|
||||
<hr />
|
||||
<div class="list-group list-group-flush">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<span class="flex-shrink-0">
|
||||
<?= UOJLocale::get('appraisal') ?>
|
||||
</span>
|
||||
<span>
|
||||
<?= UOJContest::cur()->getZanBlock() ?>
|
||||
</span>
|
||||
</li>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card card-default mb-2">
|
||||
<div class="card-body">
|
||||
<h3 class="h4 card-title text-center">
|
||||
<a class="text-decoration-none text-body" href="/contest/<?= $contest['id'] ?>">
|
||||
<?= $contest['name'] ?>
|
||||
</a>
|
||||
</h3>
|
||||
<div class="card-text text-center text-muted">
|
||||
<?php if ($contest['cur_progress'] <= CONTEST_IN_PROGRESS) : ?>
|
||||
<span id="contest-countdown"></span>
|
||||
<script type="text/javascript">
|
||||
$('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJTime::$time_now->getTimestamp() ?>, function() {}, '1.75rem', false);
|
||||
</script>
|
||||
<?php elseif ($contest['cur_progress'] <= CONTEST_TESTING) : ?>
|
||||
<?php if ($contest['cur_progress'] < CONTEST_TESTING) : ?>
|
||||
<?= UOJLocale::get('contests::contest pending final test') ?>
|
||||
<?php else : ?>
|
||||
<?php
|
||||
$total = DB::selectCount("select count(*) from submissions where contest_id = {$contest['id']}");
|
||||
$n_judged = DB::selectCount("select count(*) from submissions where contest_id = {$contest['id']} and status = 'Judged'");
|
||||
$rop = $total == 0 ? 100 : (int)($n_judged / $total * 100);
|
||||
?>
|
||||
<?= UOJLocale::get('contests::final testing') ?>
|
||||
(<?= $rop ?>%)
|
||||
<?php endif ?>
|
||||
<?php else : ?>
|
||||
<?= UOJLocale::get('contests::contest ended') ?>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
比赛评价:<?= UOJContest::cur()->getZanBlock() ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (UOJContest::cur()->basicRule() === 'OI') : ?>
|
||||
<p>此次比赛为 OI 赛制。</p>
|
||||
<p><strong>注意:比赛时只显示测样例的结果。</strong></p>
|
||||
<?php elseif (UOJContest::cur()->basicRule() === 'ACM') : ?>
|
||||
<p>此次比赛为 ACM 赛制。</p>
|
||||
<p><strong>封榜时间:<?= $contest['frozen_time']->format('Y-m-d H:i:s') ?></strong></p>
|
||||
<?php elseif (UOJContest::cur()->basicRule() === 'IOI') : ?>
|
||||
<p>此次比赛为 IOI 赛制。</p>
|
||||
<p>比赛时显示的得分即最终得分。</p>
|
||||
<?php endif ?>
|
||||
<?php if (UOJContest::cur()->basicRule() === 'OI') : ?>
|
||||
<p>此次比赛为 OI 赛制。</p>
|
||||
<p><strong>注意:比赛时只显示测样例的结果。</strong></p>
|
||||
<?php elseif (UOJContest::cur()->basicRule() === 'ACM') : ?>
|
||||
<p>此次比赛为 ACM 赛制。</p>
|
||||
<p><strong>封榜时间:<?= $contest['frozen_time']->format(UOJTime::FORMAT) ?></strong></p>
|
||||
<?php elseif (UOJContest::cur()->basicRule() === 'IOI') : ?>
|
||||
<p>此次比赛为 IOI 赛制。</p>
|
||||
<p>比赛时显示的得分即最终得分。</p>
|
||||
<?php endif ?>
|
||||
|
||||
<a href="/contest/<?= $contest['id'] ?>/registrants" class="btn btn-secondary d-block mt-2">
|
||||
<?= UOJLocale::get('contests::contest registrants') ?>
|
||||
<a href="<?= UOJContest::cur()->getUri('/registrants') ?>" class="btn btn-secondary d-block mt-2">
|
||||
<?= UOJLocale::get('contests::contest registrants') ?>
|
||||
</a>
|
||||
<?php if ($is_manager) : ?>
|
||||
<a href="<?= UOJContest::cur()->getUri('/manage') ?>" class="btn btn-primary d-block mt-2">
|
||||
管理
|
||||
</a>
|
||||
<?php endif ?>
|
||||
<?php if (isset($start_test_form)) : ?>
|
||||
<div class="mt-2">
|
||||
<?php $start_test_form->printHTML(); ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php if (isset($publish_result_form)) : ?>
|
||||
<div class="mt-2">
|
||||
<?php $publish_result_form->printHTML(); ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- 附件 -->
|
||||
<div class="card mt-3">
|
||||
<div class="card-header fw-bold">
|
||||
<?= UOJLocale::get('contests::links') ?>
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
<a class="list-group-item list-group-item-action" href="<?= HTML::url(UOJContest::cur()->getResourcesBaseUri()) ?>">
|
||||
<?= UOJLocale::get('contests::resources') ?>
|
||||
</a>
|
||||
<?php if ($is_manager) : ?>
|
||||
<a href="/contest/<?= $contest['id'] ?>/manage" class="btn btn-primary d-block mt-2">
|
||||
管理
|
||||
</a>
|
||||
<?php endif ?>
|
||||
<?php if (isset($start_test_form)) : ?>
|
||||
<div class="mt-2">
|
||||
<?php $start_test_form->printHTML(); ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php if (isset($publish_result_form)) : ?>
|
||||
<div class="mt-2">
|
||||
<?php $publish_result_form->printHTML(); ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php if ($contest['extra_config']['links']) : ?>
|
||||
<div class="card card-default border-info mt-3">
|
||||
<div class="card-header bg-info">
|
||||
<h3 class="card-title">比赛资料</h3>
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
<?php foreach ($contest['extra_config']['links'] as $link) : ?>
|
||||
<a href="/blogs/<?= $link[1] ?>" class="list-group-item"><?= $link[0] ?></a>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<?php echoUOJPageFooter() ?>
|
||||
<?php foreach (UOJContest::cur()->getAdditionalLinks() as $link) : ?>
|
||||
<a class="list-group-item list-group-item-action" href="<?= $link['url'] ?>">
|
||||
<?= HTML::escape($link['name']) ?>
|
||||
</a>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<?php echoUOJPageFooter() ?>
|
||||
|
@ -359,25 +359,156 @@ EOD);
|
||||
dieWithJsonData(['status' => 'success', 'message' => '修改成功']);
|
||||
};
|
||||
$rule_form->setAjaxSubmit(<<<EOD
|
||||
function(res) {
|
||||
if (res.status === 'success') {
|
||||
$('#type-result-alert')
|
||||
.html('修改成功!')
|
||||
.addClass('alert-success')
|
||||
.removeClass('alert-danger')
|
||||
.show();
|
||||
} else {
|
||||
$('#type-result-alert')
|
||||
.html('修改失败。' + (res.message || ''))
|
||||
.removeClass('alert-success')
|
||||
.addClass('alert-danger')
|
||||
.show();
|
||||
}
|
||||
function(res) {
|
||||
if (res.status === 'success') {
|
||||
$('#type-result-alert')
|
||||
.html('修改成功!')
|
||||
.addClass('alert-success')
|
||||
.removeClass('alert-danger')
|
||||
.show();
|
||||
} else {
|
||||
$('#type-result-alert')
|
||||
.html('修改失败。' + (res.message || ''))
|
||||
.removeClass('alert-success')
|
||||
.addClass('alert-danger')
|
||||
.show();
|
||||
}
|
||||
|
||||
$(window).scrollTop(0);
|
||||
}
|
||||
EOD);
|
||||
setTimeout(function() {
|
||||
$('#type-result-alert').hide();
|
||||
}, 5000);
|
||||
|
||||
$(window).scrollTop(0);
|
||||
}
|
||||
EOD);
|
||||
$rule_form->runAtServer();
|
||||
|
||||
$links = UOJContest::cur()->getAdditionalLinks();
|
||||
$links_str = json_encode($links, JSON_FORCE_OBJECT);
|
||||
$links_form = new UOJForm('links');
|
||||
$links_form->add('contest_links', '', function ($str, &$vdata) {
|
||||
$data = json_decode($str, true);
|
||||
$new_data = [];
|
||||
|
||||
if ($data === null) return '不合法的 JSON';
|
||||
|
||||
foreach ($data as $idx => $link) {
|
||||
$link_name = trim($link['name']);
|
||||
$link_url = trim($link['url']);
|
||||
|
||||
if ($link_name && $link_url) {
|
||||
$new_data[] = [
|
||||
'name' => $link_name,
|
||||
'url' => $link_url,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$vdata['links'] = $new_data;
|
||||
|
||||
return '';
|
||||
}, null);
|
||||
$links_form->appendHTML(<<<EOD
|
||||
<div id="div-contest_links"></div>
|
||||
<input type="hidden" name="contest_links" id="input-contest_links" value="">
|
||||
<script>
|
||||
var contest_links = {$links_str};
|
||||
var contest_links_cnt = Object.keys(contest_links).length;
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#input-contest_links').val(JSON.stringify(contest_links));
|
||||
|
||||
function newLinkRow(idx) {
|
||||
var div_link = $('<div class="row mt-2" />');
|
||||
var input_link_name = $('<input type="text" class="form-control" placeholder="名称" />').val(contest_links[idx].name);
|
||||
var input_link_url = $('<input type="text" class="form-control" placeholder="链接" />').val(contest_links[idx].url);
|
||||
var btn_del_cur_link = $('<button type="button" class="btn btn-sm btn-outline-secondary" />').html('<i class="bi bi-x-lg"></i>');
|
||||
|
||||
input_link_name.change(function() {
|
||||
contest_links[idx].name = input_link_name.val();
|
||||
$('#input-contest_links').val(JSON.stringify(contest_links));
|
||||
});
|
||||
input_link_url.change(function() {
|
||||
contest_links[idx].url = input_link_url.val();
|
||||
$('#input-contest_links').val(JSON.stringify(contest_links));
|
||||
});
|
||||
btn_del_cur_link.click(function() {
|
||||
contest_links[idx] = undefined;
|
||||
$('#input-contest_links').val(JSON.stringify(contest_links));
|
||||
div_link.remove();
|
||||
});
|
||||
|
||||
div_link.append(
|
||||
$('<div class="col-11" />').append(
|
||||
$('<div class="row" />').append(
|
||||
$('<div class="col-md-6" />').append(input_link_name)
|
||||
).append(
|
||||
$('<div class="col-md-6" />').append(input_link_url)
|
||||
)
|
||||
)
|
||||
).append(
|
||||
$('<div class="col-1 text-center" />').append(btn_del_cur_link)
|
||||
);
|
||||
|
||||
return div_link;
|
||||
};
|
||||
|
||||
$.map(contest_links, function(link, idx) {
|
||||
$('#div-contest_links').append(newLinkRow(idx));
|
||||
});
|
||||
|
||||
var row_add_link = $('<div class="row mt-2 justify-content-end" />');
|
||||
var btn_add_link = $('<button type="button" class="btn btn-sm btn-outline-secondary" />').html('<i class="bi bi-plus-lg"></i>');
|
||||
btn_add_link.click(function() {
|
||||
contest_links[++contest_links_cnt] = {name:'', url:''};
|
||||
row_add_link.before(newLinkRow(contest_links_cnt));
|
||||
});
|
||||
|
||||
$('#div-contest_links').append(row_add_link.append($('<div class="col-1 text-center" />').append(btn_add_link)));
|
||||
});
|
||||
</script>
|
||||
EOD);
|
||||
$links_form->setAjaxSubmit(<<<EOD
|
||||
function(res) {
|
||||
if (res.status === 'success') {
|
||||
$('#links-result-alert')
|
||||
.html('修改成功!')
|
||||
.addClass('alert-success')
|
||||
.removeClass('alert-danger')
|
||||
.show();
|
||||
} else {
|
||||
$('#links-result-alert')
|
||||
.html('修改失败。' + (res.message || ''))
|
||||
.removeClass('alert-success')
|
||||
.addClass('alert-danger')
|
||||
.show();
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
$('#links-result-alert').hide();
|
||||
}, 5000);
|
||||
|
||||
$(window).scrollTop(0);
|
||||
}
|
||||
EOD);
|
||||
$links_form->handle = function (&$vdata) {
|
||||
$extra_config = UOJContest::info('extra_config');
|
||||
$extra_config['links'] = $vdata['links'];
|
||||
$esc_extra_config = json_encode($extra_config);
|
||||
|
||||
DB::update([
|
||||
"update contests",
|
||||
"set", [
|
||||
"extra_config" => $esc_extra_config,
|
||||
],
|
||||
"where", [
|
||||
"id" => UOJContest::info('id'),
|
||||
],
|
||||
]);
|
||||
|
||||
dieWithJsonData(['status' => 'success', 'message' => '修改成功']);
|
||||
};
|
||||
$links_form->runAtServer();
|
||||
}
|
||||
|
||||
?>
|
||||
@ -527,6 +658,9 @@ EOD);
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#type" data-bs-toggle="tab" data-bs-target="#type">规则</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#contest-links" data-bs-toggle="tab" data-bs-target="#contest-links">链接</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body tab-content">
|
||||
@ -545,11 +679,15 @@ EOD);
|
||||
</ul>
|
||||
<h5>常见问题</h5>
|
||||
<ul class="mb-0">
|
||||
<li>暂无</li>
|
||||
<li>团体赛推荐使用团体账号报名参赛以解锁全部功能。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="contest-links">
|
||||
<div id="links-result-alert" class="alert" role="alert" style="display: none"></div>
|
||||
<?php $links_form->printHTML() ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
32
web/app/controllers/contest_resources.php
Normal file
32
web/app/controllers/contest_resources.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
UOJContest::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||
UOJContest::cur()->userCanView(Auth::user(), ['ensure' => true, 'check-register' => true]);
|
||||
|
||||
// Create directory if not exists
|
||||
if (!is_dir(UOJContest::cur()->getResourcesPath())) {
|
||||
mkdir(UOJContest::cur()->getResourcesPath(), 0755, true);
|
||||
}
|
||||
|
||||
define('APP_TITLE', '比赛资源 - ' . UOJContest::info('title'));
|
||||
define('FM_EMBED', true);
|
||||
define('FM_DISABLE_COLS', true);
|
||||
define('FM_DATETIME_FORMAT', UOJTime::FORMAT);
|
||||
define('FM_ROOT_PATH', UOJContest::cur()->getResourcesFolderPath());
|
||||
define('FM_ROOT_URL', UOJContest::cur()->getResourcesBaseUri());
|
||||
|
||||
$sub_path = UOJRequest::get('sub_path', 'is_string', '');
|
||||
|
||||
if ($sub_path) {
|
||||
$filepath = realpath(UOJContest::cur()->getResourcesPath(rawurldecode($sub_path)));
|
||||
$realbasepath = realpath(UOJContest::cur()->getResourcesPath());
|
||||
|
||||
if (!strStartWith($filepath, $realbasepath)) {
|
||||
UOJResponse::page406();
|
||||
}
|
||||
|
||||
UOJResponse::xsendfile($filepath);
|
||||
}
|
||||
|
||||
$global_readonly = !UOJContest::cur()->userCanManage(Auth::user());
|
||||
|
||||
include(__DIR__ . '/tinyfilemanager/tinyfilemanager.php');
|
@ -358,7 +358,7 @@ if (UOJContest::cur()) {
|
||||
<div class="card card-default mb-2">
|
||||
<div class="card-body">
|
||||
<h3 class="h4 card-title text-center">
|
||||
<a class="text-decoration-none text-body" href="/contest/<?= UOJContest::info('id') ?>">
|
||||
<a class="text-decoration-none text-body" href="<?= UOJContest::cur()->getUri() ?>">
|
||||
<?= UOJContest::info('name') ?>
|
||||
</a>
|
||||
</h3>
|
||||
|
@ -1,11 +1,7 @@
|
||||
<?php
|
||||
requireLib('hljs');
|
||||
|
||||
Auth::check() || redirectToLogin();
|
||||
UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||
|
||||
$problem = UOJProblem::cur()->info;
|
||||
$problem_content = UOJProblem::cur()->queryContent();
|
||||
$user_can_view = UOJProblem::cur()->userCanView(Auth::user());
|
||||
|
||||
if (!$user_can_view) {
|
||||
|
@ -36,7 +36,9 @@ return [
|
||||
'problem self review' => 'Problem self review',
|
||||
'contest self review' => 'Contest self review',
|
||||
'contest self reviews' => 'Contest self reviews',
|
||||
'will start in x days' => function($x) {
|
||||
return "will start in $x ".($x > 1 ? "days" : "day");
|
||||
'will start in x days' => function ($x) {
|
||||
return "will start in $x " . ($x > 1 ? "days" : "day");
|
||||
},
|
||||
'links' => 'Links',
|
||||
'resources' => 'Resources',
|
||||
];
|
||||
|
@ -36,7 +36,9 @@ return [
|
||||
'problem self review' => '题目总结',
|
||||
'contest self review' => '比赛总结',
|
||||
'contest self reviews' => '赛后总结',
|
||||
'will start in x days' => function($x) {
|
||||
'will start in x days' => function ($x) {
|
||||
return "将在 $x 天后开始";
|
||||
},
|
||||
'links' => '链接',
|
||||
'resources' => '相关资源',
|
||||
];
|
||||
|
@ -593,4 +593,24 @@ class UOJContest {
|
||||
updateContestPlayerNum($this->info);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getResourcesFolderPath() {
|
||||
return UOJContext::storagePath() . "/contest_resources/" . $this->info['id'];
|
||||
}
|
||||
|
||||
public function getResourcesPath($name = '') {
|
||||
return "{$this->getResourcesFolderPath()}/$name";
|
||||
}
|
||||
|
||||
public function getResourcesBaseUri() {
|
||||
return "/contest/{$this->info['id']}/resources";
|
||||
}
|
||||
|
||||
public function getResourcesUri($name = '') {
|
||||
return "{$this->getResourcesBaseUri()}/{$name}";
|
||||
}
|
||||
|
||||
public function getAdditionalLinks() {
|
||||
return $this->info['extra_config']['links'] ?: [];
|
||||
}
|
||||
}
|
||||
|
@ -42,13 +42,13 @@ Route::group(
|
||||
Route::any('/contest/{id}/registrants', '/contest_members.php');
|
||||
Route::any('/contest/{id}/register', '/contest_registration.php');
|
||||
Route::any('/contest/{id}/confirm', '/contest_confirmation.php');
|
||||
Route::any('/contest/{id}/resources(?:/{sub_path})?', '/contest_resources.php');
|
||||
Route::any('/contest/{id}/manage(?:/{tab})?', '/contest_manage.php');
|
||||
Route::any('/contest/{id}/submissions', '/contest_inside.php?tab=submissions');
|
||||
Route::any('/contest/{id}/standings', '/contest_inside.php?tab=standings');
|
||||
Route::any('/contest/{id}/after_contest_standings', '/contest_inside.php?tab=after_contest_standings');
|
||||
Route::any('/contest/{id}/self_reviews', '/contest_inside.php?tab=self_reviews');
|
||||
Route::any('/contest/{id}/backstage', '/contest_inside.php?tab=backstage');
|
||||
Route::any('/contest/{id}/standings_unfrozen', '/contest_inside.php?tab=standings_unfrozen');
|
||||
Route::any('/contest/{contest_id}/problem/{id}', '/problem.php');
|
||||
Route::any('/contest/{contest_id}/problem/{id}/statistics', '/problem_statistics.php');
|
||||
|
||||
|
0
web/app/storage/contest_resources/.gitkeep
Normal file
0
web/app/storage/contest_resources/.gitkeep
Normal file
1
web/app/upgrade/40_contest_resources/up.sql
Normal file
1
web/app/upgrade/40_contest_resources/up.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE `contests` MODIFY `extra_config` json NOT NULL;
|
37
web/app/upgrade/40_contest_resources/upgrade.php
Normal file
37
web/app/upgrade/40_contest_resources/upgrade.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
return function ($type) {
|
||||
if ($type == 'up_after_sql') {
|
||||
DB::init();
|
||||
|
||||
$contests = DB::selectAll("select * from contests");
|
||||
|
||||
foreach ($contests as $contest) {
|
||||
$extra_config = json_decode($contest['extra_config'], true);
|
||||
|
||||
if (isset($extra_config['links'])) {
|
||||
$new_links = [];
|
||||
|
||||
foreach ($extra_config['links'] as $link) {
|
||||
if (isset($link['name'])) continue;
|
||||
|
||||
$new_links[] = [
|
||||
'name' => $link[0],
|
||||
'url' => '/blogs/' . $link[1],
|
||||
];
|
||||
}
|
||||
|
||||
$extra_config['links'] = $new_links;
|
||||
}
|
||||
|
||||
DB::update([
|
||||
"update contests",
|
||||
"set", [
|
||||
"extra_config" => json_encode($extra_config, JSON_FORCE_OBJECT),
|
||||
],
|
||||
"where", [
|
||||
"id" => $contest['id'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
};
|
@ -83,6 +83,7 @@ initProgress(){
|
||||
mkdir -p /opt/uoj/web/app/storage/tmp
|
||||
mkdir -p /opt/uoj/web/app/storage/image_hosting
|
||||
mkdir -p /opt/uoj/web/app/storage/problem_resources
|
||||
mkdir -p /opt/uoj/web/app/storage/contest_resources
|
||||
chmod -R 777 /opt/uoj/web/app/storage
|
||||
#Using cli upgrade to latest
|
||||
sleep 15 # Wait for uoj-db
|
||||
|
Loading…
Reference in New Issue
Block a user