mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-11-25 21:58:41 +00:00
chore: merge branch 'develop' into master
This commit is contained in:
commit
7a7d46e057
@ -697,6 +697,27 @@ LOCK TABLES `user_system_msg` WRITE;
|
|||||||
/*!40000 ALTER TABLE `user_system_msg` DISABLE KEYS */;
|
/*!40000 ALTER TABLE `user_system_msg` DISABLE KEYS */;
|
||||||
/*!40000 ALTER TABLE `user_system_msg` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `user_system_msg` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
create table pastes
|
||||||
|
(
|
||||||
|
`index` varchar(20) null,
|
||||||
|
creator varchar(20) null,
|
||||||
|
created_at datetime null,
|
||||||
|
content text null
|
||||||
|
);
|
||||||
|
|
||||||
|
create unique index pastes_index_uindex
|
||||||
|
on pastes (`index`);
|
||||||
|
|
||||||
|
create index pastes_created_at_index
|
||||||
|
on pastes (created_at);
|
||||||
|
|
||||||
|
alter table pastes
|
||||||
|
add constraint pastes_pk
|
||||||
|
primary key (`index`);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||||
|
|
||||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||||
|
20
judger/.gitignore
vendored
Normal file
20
judger/.gitignore
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
.conf.json
|
||||||
|
log/*
|
||||||
|
!/log/.gitkeep
|
||||||
|
uoj_judger/builtin/checker/*
|
||||||
|
!uoj_judger/builtin/checker/*.cpp
|
||||||
|
!uoj_judger/builtin/checker/*.h
|
||||||
|
uoj_judger/builtin/judger/*
|
||||||
|
!uoj_judger/builtin/judger/*.cpp
|
||||||
|
!uoj_judger/builtin/judger/*.h
|
||||||
|
uoj_judger/data
|
||||||
|
uoj_judger/include/uoj_work_path.h
|
||||||
|
uoj_judger/main_judger
|
||||||
|
uoj_judger/run/*
|
||||||
|
!uoj_judger/run/*.cpp
|
||||||
|
!uoj_judger/run/*.h
|
||||||
|
uoj_judger/work/*
|
||||||
|
uoj_judger/result/*
|
||||||
|
!uoj_judger/work/.gitkeep
|
||||||
|
!uoj_judger/result/.gitkeep
|
||||||
|
|
4
judger/judge_client
Normal file → Executable file
4
judger/judge_client
Normal file → Executable file
@ -140,7 +140,7 @@ def handle_task():
|
|||||||
uoj_download('/judger', 'judger_update.zip')
|
uoj_download('/judger', 'judger_update.zip')
|
||||||
execute('unzip -o judger_update.zip && cd %s && make clean && make' % uoj_judger_path())
|
execute('unzip -o judger_update.zip && cd %s && make clean && make' % uoj_judger_path())
|
||||||
except:
|
except:
|
||||||
print(sys.stderr, "error when update")
|
print("error when update", file=sys.stderr)
|
||||||
if jconf['judger_name'] == 'main_judger':
|
if jconf['judger_name'] == 'main_judger':
|
||||||
uoj_sync_judge_client()
|
uoj_sync_judge_client()
|
||||||
need_restart = True
|
need_restart = True
|
||||||
@ -149,7 +149,7 @@ def handle_task():
|
|||||||
socket_server_thread.join()
|
socket_server_thread.join()
|
||||||
|
|
||||||
print_judge_client_status()
|
print_judge_client_status()
|
||||||
print(sys.stderr, "goodbye!")
|
print("goodbye!", file=sys.stderr)
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ void ordinary_test() {
|
|||||||
po.scr = scale_score(po.scr, conf_int("point_score", i, 100 / n));
|
po.scr = scale_score(po.scr, conf_int("point_score", i, 100 / n));
|
||||||
add_point_info(po);
|
add_point_info(po);
|
||||||
}
|
}
|
||||||
} else if (nT == 1) {
|
} else if (nT == 1 && conf_str("subtask_type", 1, "packed") == "packed") {
|
||||||
for (int i = 1; i <= n; i++) {
|
for (int i = 1; i <= n; i++) {
|
||||||
report_judge_status_f("Judging Test #%d", i);
|
report_judge_status_f("Judging Test #%d", i);
|
||||||
PointInfo po = test_point("answer", i);
|
PointInfo po = test_point("answer", i);
|
||||||
|
@ -160,7 +160,7 @@ inline bool is_writable_file(string name) {
|
|||||||
if (name == "/") {
|
if (name == "/") {
|
||||||
return writable_file_name_set.count("system_root");
|
return writable_file_name_set.count("system_root");
|
||||||
}
|
}
|
||||||
return is_in_set_smart(name, writable_file_name_set) || is_in_set_smart(realpath(name), readable_file_name_set);
|
return is_in_set_smart(name, writable_file_name_set) || is_in_set_smart(realpath(name), writable_file_name_set);
|
||||||
}
|
}
|
||||||
inline bool is_readable_file(const string &name) {
|
inline bool is_readable_file(const string &name) {
|
||||||
if (is_writable_file(name)) {
|
if (is_writable_file(name)) {
|
||||||
|
8
web/.gitignore
vendored
8
web/.gitignore
vendored
@ -3,3 +3,11 @@
|
|||||||
|
|
||||||
composer.phar
|
composer.phar
|
||||||
composer.lock
|
composer.lock
|
||||||
|
|
||||||
|
app/.config.php
|
||||||
|
app/storage/tmp/*
|
||||||
|
app/storage/submission/*
|
||||||
|
app/storage/paste/*
|
||||||
|
!app/storage/tmp/.gitkeep
|
||||||
|
!app/storage/submission/.gitkeep
|
||||||
|
!app/storage/paste/.gitkeep
|
||||||
|
@ -53,5 +53,10 @@ return [
|
|||||||
'switch' => [
|
'switch' => [
|
||||||
'web-analytics' => false,
|
'web-analytics' => false,
|
||||||
'blog-domain-mode' => 3
|
'blog-domain-mode' => 3
|
||||||
|
],
|
||||||
|
'tools' => [
|
||||||
|
// 请仅在https下启用以下功能.
|
||||||
|
// 非https下, chrome无法进行复制.
|
||||||
|
'map-copy-enabled' => false,
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
@ -62,13 +62,14 @@ EOD;
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ($rest_second <= 86400) {
|
if ($rest_second <= 86400) {
|
||||||
|
$notification = json_encode($upcoming_contest_name . " 已经开始了。是否要跳转到比赛页面?");
|
||||||
echo <<<EOD
|
echo <<<EOD
|
||||||
<div class="text-center bot-buffer-lg">
|
<div class="text-center bot-buffer-lg">
|
||||||
<div class="text-warning">$upcoming_contest_name 倒计时</div>
|
<div class="text-warning">$upcoming_contest_name 倒计时</div>
|
||||||
<div id="contest-countdown"></div>
|
<div id="contest-countdown"></div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$('#contest-countdown').countdown($rest_second, function() {
|
$('#contest-countdown').countdown($rest_second, function() {
|
||||||
if (confirm('$upcoming_contest_name 已经开始了。是否要跳转到比赛页面?')) {
|
if (confirm($notification)) {
|
||||||
window.location.href = "$upcoming_contest_href";
|
window.location.href = "$upcoming_contest_href";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
132
web/app/controllers/map_visualizer.php
Normal file
132
web/app/controllers/map_visualizer.php
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$REQUIRE_LIB['shjs'] = "";
|
||||||
|
$REQUIRE_LIB['dracula'] = "";
|
||||||
|
$REQUIRE_LIB['base64'] = "";
|
||||||
|
$REQUIRE_LIB['raphael'] = "";
|
||||||
|
echoUOJPageHeader("图可视化");
|
||||||
|
|
||||||
|
?>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="directed" name="directed">
|
||||||
|
<label class="form-check-label" for="directed">
|
||||||
|
是否有向
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<textarea class="form-control" id="edges" rows="3" placeholder="格式:
|
||||||
|
第一条边起点 第一条边终点 [第一条边权重]
|
||||||
|
第二条边起点 第二条边终点 [第二条边权重]
|
||||||
|
第三条边起点 第三条边终点 [第三条边权重]
|
||||||
|
如:
|
||||||
|
1 2
|
||||||
|
2 3
|
||||||
|
1 3 2
|
||||||
|
"></textarea>
|
||||||
|
</div>
|
||||||
|
<?php if (UOJConfig::$data['tools']['map-copy-enabled']): ?>
|
||||||
|
<button type="button" class="btn btn-secondary" id="copy">复制图片</button>
|
||||||
|
<?php endif ?>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-9" id="paper">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
<?php if (UOJConfig::$data['tools']['map-copy-enabled']): ?>
|
||||||
|
$("#copy").click(function () {
|
||||||
|
if(navigator.permissions) {
|
||||||
|
navigator.permissions.query({name: "clipboard-write"}).then(result => {
|
||||||
|
if (result.state === "granted" || result.state === "prompt") {
|
||||||
|
let paper = $("#paper")
|
||||||
|
// First, we create an canvas and a img which has the same size with the canvas.
|
||||||
|
let canvas = document.createElement('canvas');
|
||||||
|
let s_img = document.createElement('img');
|
||||||
|
s_img.height = paper.height()
|
||||||
|
s_img.width = paper.width()
|
||||||
|
canvas.height = paper.height()
|
||||||
|
canvas.width = paper.width()
|
||||||
|
// After this image is loaded, we draw it on our canvas
|
||||||
|
s_img.onload = function () {
|
||||||
|
// On some browsers, the exported png have a black background.
|
||||||
|
// So we will draw a white background first.
|
||||||
|
ctx = canvas.getContext('2d');
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.rect(0, 0, paper.width(), paper.height());
|
||||||
|
ctx.fillStyle = "white";
|
||||||
|
ctx.fill();
|
||||||
|
// We put our image created from the svg to the canvas
|
||||||
|
canvas.getContext('2d').drawImage(s_img, 0, 0);
|
||||||
|
// Then we export canvas as a png file, paste it to clipboard.
|
||||||
|
canvas.toBlob(function (blob) {
|
||||||
|
const item = new ClipboardItem({[blob.type]: blob});
|
||||||
|
navigator.clipboard.write([item]).then(function () {
|
||||||
|
alert("图片已经复制到剪切板中");
|
||||||
|
}, function (err) {
|
||||||
|
alert(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Load our svg to this image.
|
||||||
|
s_img.src = "data:image/svg+xml;base64," + Base64.encode(new XMLSerializer().serializeToString(document.querySelector("#paper > svg")));
|
||||||
|
} else {
|
||||||
|
alert("获取剪切板权限失败, 请打开网页设置并授予剪切板权限!")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
alert("获取剪切板权限失败, 请使用最新Chrome浏览器, 打开网页设置并授予剪切板权限!")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
<?php endif ?>
|
||||||
|
let repaint = function () {
|
||||||
|
let paper = $("#paper");
|
||||||
|
// Clear existing elements.
|
||||||
|
paper.html("");
|
||||||
|
let directed = $('#directed').is(":checked");
|
||||||
|
let Graph = Dracula.Graph;
|
||||||
|
let Renderer = Dracula.Renderer.Raphael;
|
||||||
|
let Layout = Dracula.Layout.Spring;
|
||||||
|
let graph = new Graph();
|
||||||
|
let render = function(r, n) {
|
||||||
|
let color = Raphael.getColor();
|
||||||
|
return r.set()
|
||||||
|
.push(
|
||||||
|
r.ellipse(0, 0, 30, 20).attr({stroke: color, "stroke-width": 2, fill: color, "fill-opacity": 0})
|
||||||
|
)
|
||||||
|
.push(r.text(0, 0, n.id).attr({ opacity: 1, 'font-size': 20,}));
|
||||||
|
}
|
||||||
|
$("#edges").val().split("\n").forEach(function (edge) {
|
||||||
|
if (edge.split(" ").length >= 2) {
|
||||||
|
if (edge.split(" ")[0].length !== 0 && edge.split(" ")[1].length !== 0 ){
|
||||||
|
graph.addNode(edge.split(" ")[0], {
|
||||||
|
render: render
|
||||||
|
});
|
||||||
|
graph.addNode(edge.split(" ")[1], {
|
||||||
|
render: render
|
||||||
|
});
|
||||||
|
graph.addEdge(edge.split(" ")[0], edge.split(" ")[1], {
|
||||||
|
directed: directed,
|
||||||
|
label:edge.split(" ")[2],
|
||||||
|
'label-style' : {
|
||||||
|
'font-size': 20,
|
||||||
|
"fill-opacity":"1"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
var layout = new Layout(graph)
|
||||||
|
var renderer = new Renderer('#paper', graph, paper.width(), paper.height())
|
||||||
|
renderer.draw()
|
||||||
|
}
|
||||||
|
$("#edges").on("input", repaint)
|
||||||
|
$("#directed").on("input", repaint)
|
||||||
|
})()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
echoUOJPageFooter();
|
37
web/app/controllers/paste_post.php
Normal file
37
web/app/controllers/paste_post.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
requirePHPLib('form');
|
||||||
|
requirePHPLib('judger');
|
||||||
|
|
||||||
|
if ($myUser == null) {
|
||||||
|
becomeMsgPage("请先登录!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleUpload($zip_file_name, $content, $tot_size) {
|
||||||
|
global $myUser;
|
||||||
|
$esc_content = DB::escape(json_encode($content));
|
||||||
|
$index = uojRandString(20);
|
||||||
|
$esc_index = DB::escape($index);
|
||||||
|
while (DB::selectFirst("select count(*) as count from pastes where `index` = '$esc_index'")['count'] != "0") {
|
||||||
|
$index = uojRandString(20);
|
||||||
|
$esc_index = DB::escape($index);
|
||||||
|
}
|
||||||
|
DB::query("insert into pastes (`index`, `creator`, `content`, `created_at`) values ('$esc_index', '${myUser['username']}', '$esc_content', '".date('Y-m-d H:i:s')."')");
|
||||||
|
redirectTo("/pastes/".$index);
|
||||||
|
}
|
||||||
|
|
||||||
|
$paste_form = newSubmissionForm('paste',
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'type' => "source code",
|
||||||
|
"name" => "paste",
|
||||||
|
"file_name" => "paste.code"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'uojRandAvaiablePasteFileName',
|
||||||
|
'handleUpload');
|
||||||
|
$paste_form->succ_href = '/paste';
|
||||||
|
$paste_form->runAtServer();
|
||||||
|
echoUOJPageHeader("Paste!");
|
||||||
|
$paste_form->printHTML();
|
||||||
|
echoUOJPageFooter();
|
12
web/app/controllers/paste_view.php
Normal file
12
web/app/controllers/paste_view.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$paste_id = $_GET['rand_str_id'];
|
||||||
|
|
||||||
|
$paste = DB::selectFirst("select * from pastes where `index` = '".DB::escape($paste_id)."'");
|
||||||
|
if (!$paste) {
|
||||||
|
become404Page();
|
||||||
|
}
|
||||||
|
$REQUIRE_LIB['shjs'] = "";
|
||||||
|
echoUOJPageHeader("Paste!");
|
||||||
|
echoPasteContent($paste);
|
||||||
|
echoUOJPageFooter();
|
@ -50,7 +50,7 @@
|
|||||||
becomeMsgPage('<div>' . $errmsg . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
|
becomeMsgPage('<div>' . $errmsg . '</div><a href="/problem/'.$problem['id'].'/manage/data">返回</a>');
|
||||||
} else {
|
} else {
|
||||||
$zip_mime_types = array('application/zip', 'application/x-zip', 'application/x-zip-compressed');
|
$zip_mime_types = array('application/zip', 'application/x-zip', 'application/x-zip-compressed');
|
||||||
if (in_array($_FILES["problem_data_file"]["type"], $zip_mime_types)) {
|
if (in_array($_FILES["problem_data_file"]["type"], $zip_mime_types) || $_FILES["problem_data_file"]["type"] == 'application/octet-stream' && substr($_FILES["problem_data_file"]["name"], -4) == '.zip') {
|
||||||
$up_filename="/tmp/".rand(0,100000000)."data.zip";
|
$up_filename="/tmp/".rand(0,100000000)."data.zip";
|
||||||
move_uploaded_file($_FILES["problem_data_file"]["tmp_name"], $up_filename);
|
move_uploaded_file($_FILES["problem_data_file"]["tmp_name"], $up_filename);
|
||||||
$zip = new ZipArchive;
|
$zip = new ZipArchive;
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
if (isProblemVisibleToUser($problem, $myUser)) {
|
if (isProblemVisibleToUser($problem, $myUser)) {
|
||||||
echo '<tr class="text-center">';
|
echo '<tr class="text-center">';
|
||||||
if ($problem['submission_id']) {
|
if ($problem['submission_id']) {
|
||||||
echo '<td class="success">';
|
echo '<td class="table-success">';
|
||||||
} else {
|
} else {
|
||||||
echo '<td>';
|
echo '<td>';
|
||||||
}
|
}
|
||||||
|
@ -265,6 +265,22 @@
|
|||||||
};
|
};
|
||||||
$judger_deleter->runAtServer();
|
$judger_deleter->runAtServer();
|
||||||
|
|
||||||
|
$paste_deleter = new UOJForm('paste_deleter');
|
||||||
|
$paste_deleter->addInput('paste_deleter_name', 'text', 'Paste ID', '',
|
||||||
|
function ($x, &$vdata) {
|
||||||
|
if (DB::selectCount("select count(*) from pastes where `index`='$x'")==0) {
|
||||||
|
return '不合法';
|
||||||
|
}
|
||||||
|
$vdata['name'] = $x;
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
|
$paste_deleter->handle = function(&$vdata) {
|
||||||
|
DB::delete("delete from pastes where `index` = '${vdata['name']}'");
|
||||||
|
};
|
||||||
|
$paste_deleter->runAtServer();
|
||||||
|
|
||||||
$judgerlist_cols = array('judger_name', 'password');
|
$judgerlist_cols = array('judger_name', 'password');
|
||||||
$judgerlist_config = array();
|
$judgerlist_config = array();
|
||||||
$judgerlist_header_row = <<<EOD
|
$judgerlist_header_row = <<<EOD
|
||||||
@ -328,6 +344,10 @@ EOD;
|
|||||||
'judger' => array(
|
'judger' => array(
|
||||||
'name' => '评测机管理',
|
'name' => '评测机管理',
|
||||||
'url' => '/super-manage/judger'
|
'url' => '/super-manage/judger'
|
||||||
|
),
|
||||||
|
'paste' => array(
|
||||||
|
'name' => 'Paste管理',
|
||||||
|
'url' => '/super-manage/paste'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -458,6 +478,11 @@ EOD;
|
|||||||
</div>
|
</div>
|
||||||
<h3>评测机列表</h3>
|
<h3>评测机列表</h3>
|
||||||
<?php echoLongTable($judgerlist_cols, 'judger_info', "1=1", '', $judgerlist_header_row, $judgerlist_print_row, $judgerlist_config) ?>
|
<?php echoLongTable($judgerlist_cols, 'judger_info', "1=1", '', $judgerlist_header_row, $judgerlist_print_row, $judgerlist_config) ?>
|
||||||
|
<?php elseif ($cur_tab === 'paste'): ?>
|
||||||
|
<div>
|
||||||
|
<h4>Paste管理</h4>
|
||||||
|
<?php echoPastesList() ?>
|
||||||
|
</div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -104,20 +104,20 @@
|
|||||||
var rating_data = [[
|
var rating_data = [[
|
||||||
<?php
|
<?php
|
||||||
$user_rating_min = $user_rating_max = 1500;
|
$user_rating_min = $user_rating_max = 1500;
|
||||||
$result = DB::query("select contest_id, rank, user_rating from contests_registrants where username = '{$user['username']}' and has_participated = 1 order by contest_id");
|
$result = DB::query("select contest_id, `rank`, user_rating from contests_registrants where username = '{$user['username']}' and has_participated = 1 order by contest_id");
|
||||||
$is_first_row = true;
|
$is_first_row = true;
|
||||||
$last_rating = 1500;
|
$last_rating = 1500;
|
||||||
while ($row = DB::fetch($result)) {
|
while ($row = DB::fetch($result)) {
|
||||||
$contest = queryContest($row['contest_id']);
|
$contest = queryContest($row['contest_id']);
|
||||||
$rating_delta = $row['user_rating'] - $last_rating;
|
$rating_delta = $row['user_rating'] - $last_rating;
|
||||||
if (!$is_first_row) {
|
if (!$is_first_row) {
|
||||||
echo "[$last_contest_time, {$row['user_rating']}, $last_contest_id, '$last_contest_name', $last_rank, $rating_delta],";
|
echo "[$last_contest_time, {$row['user_rating']}, $last_contest_id, $last_contest_name, $last_rank, $rating_delta],";
|
||||||
} else {
|
} else {
|
||||||
$is_first_row = false;
|
$is_first_row = false;
|
||||||
}
|
}
|
||||||
$contest_start_time = new DateTime($contest['start_time']);
|
$contest_start_time = new DateTime($contest['start_time']);
|
||||||
$last_contest_time = ($contest_start_time->getTimestamp() + $contest_start_time->getOffset()) * 1000;
|
$last_contest_time = ($contest_start_time->getTimestamp() + $contest_start_time->getOffset()) * 1000;
|
||||||
$last_contest_name = $contest['name'];
|
$last_contest_name = json_encode($contest['name']);
|
||||||
$last_contest_id = $contest['id'];
|
$last_contest_id = $contest['id'];
|
||||||
$last_rank = $row['rank'];
|
$last_rank = $row['rank'];
|
||||||
$last_rating = $row['user_rating'];
|
$last_rating = $row['user_rating'];
|
||||||
@ -134,7 +134,7 @@ var rating_data = [[
|
|||||||
echo "[{$time_now_stamp}, {$user['rating']}, 0]";
|
echo "[{$time_now_stamp}, {$user['rating']}, 0]";
|
||||||
} else {
|
} else {
|
||||||
$rating_delta = $user['rating'] - $last_rating;
|
$rating_delta = $user['rating'] - $last_rating;
|
||||||
echo "[$last_contest_time, {$user['rating']}, $last_contest_id, '$last_contest_name', $last_rank, $rating_delta]";
|
echo "[$last_contest_time, {$user['rating']}, $last_contest_id, $last_contest_name, $last_rank, $rating_delta]";
|
||||||
}
|
}
|
||||||
if ($user['rating'] < $user_rating_min) {
|
if ($user['rating'] < $user_rating_min) {
|
||||||
$user_rating_min = $user['rating'];
|
$user_rating_min = $user['rating'];
|
||||||
|
@ -233,7 +233,7 @@
|
|||||||
} else {
|
} else {
|
||||||
$n_ex_tests = getUOJConfVal($this->problem_conf, 'n_ex_tests', 0);
|
$n_ex_tests = getUOJConfVal($this->problem_conf, 'n_ex_tests', 0);
|
||||||
if (!validateUInt($n_ex_tests) || $n_ex_tests < 0) {
|
if (!validateUInt($n_ex_tests) || $n_ex_tests < 0) {
|
||||||
throw new UOJProblemConfException("n_ex_tests must be a non-nagative integer");
|
throw new UOJProblemConfException("n_ex_tests must be a non-negative integer");
|
||||||
}
|
}
|
||||||
|
|
||||||
for ($num = 1; $num <= $n_ex_tests; $num++) {
|
for ($num = 1; $num <= $n_ex_tests; $num++) {
|
||||||
@ -267,7 +267,7 @@
|
|||||||
|
|
||||||
$n_sample_tests = getUOJConfVal($this->problem_conf, 'n_sample_tests', $n_tests);
|
$n_sample_tests = getUOJConfVal($this->problem_conf, 'n_sample_tests', $n_tests);
|
||||||
if (!validateUInt($n_sample_tests) || $n_sample_tests < 0) {
|
if (!validateUInt($n_sample_tests) || $n_sample_tests < 0) {
|
||||||
throw new UOJProblemConfException("n_sample_tests must be a non-nagative integer");
|
throw new UOJProblemConfException("n_sample_tests must be a non-negative integer");
|
||||||
}
|
}
|
||||||
if ($n_sample_tests > $n_ex_tests) {
|
if ($n_sample_tests > $n_ex_tests) {
|
||||||
throw new UOJProblemConfException("n_sample_tests can't be greater than n_ex_tests");
|
throw new UOJProblemConfException("n_sample_tests can't be greater than n_ex_tests");
|
||||||
|
@ -393,6 +393,96 @@ function echoSubmissionsList($cond, $tail, $config, $user) {
|
|||||||
}, $table_config);
|
}, $table_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function echoPastesList() {
|
||||||
|
$header_row = '<tr>';
|
||||||
|
$col_names = ['`index`','creator','created_at'];
|
||||||
|
$header_row .= '<th>ID</th>';
|
||||||
|
$header_row .= '<th>'.UOJLocale::get("problems::submitter").'</th>';
|
||||||
|
$header_row .= '<th>'.UOJLocale::get('problems::submit time').'</th>';
|
||||||
|
$header_row .= '<th> 操作 </th>';
|
||||||
|
$header_row .= '</tr>';
|
||||||
|
$table_name = 'pastes';
|
||||||
|
echoLongTable($col_names, $table_name, "1", 'order by created_at desc', $header_row,
|
||||||
|
function($paste) {
|
||||||
|
$user = getUserLink($paste['creator']);
|
||||||
|
$token = HTML::hiddenToken();
|
||||||
|
echo <<<HTML
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/pastes/{$paste['index']}">{$paste['index']}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{$user}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{$paste['created_at']}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<form action="/super-manage/paste" method="post" class="form-horizontal">
|
||||||
|
{$token}
|
||||||
|
<input type="text" class="form-control" name="paste_deleter_name" id="input-paste_deleter_name" value="{$paste['index']}" style="display: none;">
|
||||||
|
<button type="submit" name="submit-paste_deleter" value="paste_deleter" class="btn btn-sm btn-danger" style="margin: 0">删除</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
HTML;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
function echoPasteContent($paste) {
|
||||||
|
$zip_file = new ZipArchive();
|
||||||
|
$submission_content = json_decode($paste['content'], true);
|
||||||
|
$zip_file->open(UOJContext::storagePath().$submission_content['file_name']);
|
||||||
|
|
||||||
|
$config = array();
|
||||||
|
foreach ($submission_content['config'] as $config_key => $config_val) {
|
||||||
|
$config[$config_val[0]] = $config_val[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
$file_content = $zip_file->getFromName("paste.code");
|
||||||
|
$file_content = uojTextEncode($file_content, array('allow_CR' => true, 'html_escape' => true));
|
||||||
|
$file_language = htmlspecialchars($config["paste_language"]);
|
||||||
|
$footer_text = UOJLocale::get('problems::source code').', '.UOJLocale::get('problems::language').': '.$file_language;
|
||||||
|
$footer_text .= ", ".UOJLocale::get("problems::submitter") . <<<HTML
|
||||||
|
: <a href="/user/profile/${paste['creator']}">${paste['creator']}</a>
|
||||||
|
HTML;
|
||||||
|
$footer_text .= ", ".UOJLocale::get("problems::submit time").": ".$paste['created_at'];
|
||||||
|
|
||||||
|
switch ($file_language) {
|
||||||
|
case 'C++':
|
||||||
|
case 'C++11':
|
||||||
|
$sh_class = 'sh_cpp';
|
||||||
|
break;
|
||||||
|
case 'Python2':
|
||||||
|
case 'Python3':
|
||||||
|
$sh_class = 'sh_python';
|
||||||
|
break;
|
||||||
|
case 'Java8':
|
||||||
|
case 'Java11':
|
||||||
|
$sh_class = 'sh_java';
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
$sh_class = 'sh_c';
|
||||||
|
break;
|
||||||
|
case 'Pascal':
|
||||||
|
$sh_class = 'sh_pascal';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$sh_class = '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
echo '<div class="card border-info mb-3">';
|
||||||
|
echo '<div class="card-header bg-info">';
|
||||||
|
echo '<h4 class="card-title">Paste!</h4>';
|
||||||
|
echo '</div>';
|
||||||
|
echo '<div class="card-body">';
|
||||||
|
echo '<pre><code class="'.$sh_class.'">'.$file_content."\n".'</code></pre>';
|
||||||
|
echo '</div>';
|
||||||
|
echo '<div class="card-footer">'.$footer_text.'</div>';
|
||||||
|
echo '</div>';
|
||||||
|
|
||||||
|
$zip_file->close();
|
||||||
|
}
|
||||||
|
|
||||||
function echoSubmissionContent($submission, $requirement) {
|
function echoSubmissionContent($submission, $requirement) {
|
||||||
$zip_file = new ZipArchive();
|
$zip_file = new ZipArchive();
|
||||||
|
@ -31,3 +31,7 @@ function uojRandAvaiableSubmissionFileName() {
|
|||||||
}
|
}
|
||||||
return uojRandAvaiableFileName("/submission/$num/");
|
return uojRandAvaiableFileName("/submission/$num/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function uojRandAvaiablePasteFileName() {
|
||||||
|
return uojRandAvaiableFileName('/paste/');
|
||||||
|
}
|
||||||
|
@ -65,6 +65,11 @@ Route::group([
|
|||||||
Route::any('/download.php', '/download.php');
|
Route::any('/download.php', '/download.php');
|
||||||
|
|
||||||
Route::any('/click-zan', '/click_zan.php');
|
Route::any('/click-zan', '/click_zan.php');
|
||||||
|
|
||||||
|
Route::any('/paste', '/paste_post.php');
|
||||||
|
Route::any('/pastes/{rand_str_id}', '/paste_view.php');
|
||||||
|
|
||||||
|
Route::any('/map_visualizer', '/map_visualizer.php');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
0
web/app/storage/paste/.gitkeep
Normal file
0
web/app/storage/paste/.gitkeep
Normal file
@ -11,6 +11,16 @@
|
|||||||
<li class="nav-item"><a class="nav-link" href="<?= HTML::url('/hacks') ?>"><span class="glyphicon glyphicon-flag"></span> <?= UOJLocale::get('hacks') ?></a></li>
|
<li class="nav-item"><a class="nav-link" href="<?= HTML::url('/hacks') ?>"><span class="glyphicon glyphicon-flag"></span> <?= UOJLocale::get('hacks') ?></a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="<?= HTML::blog_list_url() ?>"><span class="glyphicon glyphicon-edit"></span> <?= UOJLocale::get('blogs') ?></a></li>
|
<li class="nav-item"><a class="nav-link" href="<?= HTML::blog_list_url() ?>"><span class="glyphicon glyphicon-edit"></span> <?= UOJLocale::get('blogs') ?></a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="<?= HTML::url('/faq') ?>"><span class="glyphicon glyphicon-info-sign"></span> <?= UOJLocale::get('help') ?></a></li>
|
<li class="nav-item"><a class="nav-link" href="<?= HTML::url('/faq') ?>"><span class="glyphicon glyphicon-info-sign"></span> <?= UOJLocale::get('help') ?></a></li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle" href="#" id="toolsDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="glyphicon glyphicon-wrench"></span>
|
||||||
|
工具
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||||
|
<a class="dropdown-item" href="<?= HTML::url('/paste') ?>"><span class="glyphicon glyphicon-paste"></span> 代码分享 </a>
|
||||||
|
<a class="dropdown-item" href="<?= HTML::url('/map_visualizer') ?>"><span class="glyphicon glyphicon-retweet"></span> 图可视化 </a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<form id="form-search-problem" class="form-inline my-2 my-lg-0" method="get">
|
<form id="form-search-problem" class="form-inline my-2 my-lg-0" method="get">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
|
@ -153,7 +153,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script src="//cdn.bootcss.com/mathjax/2.6.0/MathJax.js?config=TeX-AMS_HTML"></script>
|
<script src="//cdn.bootcss.com/mathjax/2.7.7/MathJax.js?config=TeX-AMS_HTML"></script>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<?php if (isset($REQUIRE_LIB['jquery.form'])): ?>
|
<?php if (isset($REQUIRE_LIB['jquery.form'])): ?>
|
||||||
@ -205,6 +205,16 @@
|
|||||||
<?= HTML::js_src('/js/ckeditor/ckeditor.js') ?>
|
<?= HTML::js_src('/js/ckeditor/ckeditor.js') ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
|
<?php if (isset($REQUIRE_LIB['dracula'])): ?>
|
||||||
|
<!-- dracula.js -->
|
||||||
|
<?= HTML::js_src('/js/dracula.min.js') ?>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<?php if (isset($REQUIRE_LIB['base64'])): ?>
|
||||||
|
<!-- base64.js -->
|
||||||
|
<?= HTML::js_src('/js/base64.min.js') ?>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||||
|
8
web/js/base64.min.js
vendored
Normal file
8
web/js/base64.min.js
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* Minified by jsDelivr using Terser v3.14.1.
|
||||||
|
* Original file: /npm/js-base64@3.4.4/base64.js
|
||||||
|
*
|
||||||
|
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
||||||
|
*/
|
||||||
|
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):function(){const r=e.Base64,n=t();n.noConflict=(()=>(e.Base64=r,n)),e.Meteor&&(Base64=n),e.Base64=n}()}("undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:this,function(){"use strict";const e="function"==typeof atob,t="function"==typeof btoa,r="function"==typeof Buffer,n=[..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="],o=(e=>{let t={};return n.forEach((e,r)=>t[e]=r),t})(),a=/^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/,f=String.fromCharCode.bind(String),i="function"==typeof Uint8Array.from?Uint8Array.from.bind(Uint8Array):(e,t=(e=>e))=>new Uint8Array(Array.prototype.slice.call(e,0).map(t)),c=e=>e.replace(/[+\/]/g,e=>"+"==e?"-":"_").replace(/=+$/m,""),u=e=>e.replace(/[^A-Za-z0-9\+\/]/g,""),s=e=>{let t,r,o,a,f="";const i=e.length%3;for(let i=0;i<e.length;){if((r=e.charCodeAt(i++))>255||(o=e.charCodeAt(i++))>255||(a=e.charCodeAt(i++))>255)throw new TypeError("invalid character found");f+=n[(t=r<<16|o<<8|a)>>18&63]+n[t>>12&63]+n[t>>6&63]+n[63&t]}return i?f.slice(0,i-3)+"===".substring(i):f},l=t?e=>btoa(e):r?e=>Buffer.from(e,"binary").toString("base64"):s,d=r?e=>Buffer.from(e).toString("base64"):e=>{let t=[];for(let r=0,n=e.length;r<n;r+=4096)t.push(f.apply(null,e.subarray(r,r+4096)));return btoa(t.join(""))},p=(e,t=!1)=>t?c(d(e)):d(e),y=e=>unescape(encodeURIComponent(e)),b=r?e=>Buffer.from(e,"utf8").toString("base64"):e=>l(y(e)),h=(e,t=!1)=>t?c(b(e)):b(e),B=e=>h(e,!0),g=e=>decodeURIComponent(escape(e)),m=e=>{if(e=e.replace(/\s+/g,""),!a.test(e))throw new TypeError("malformed base64.");e+="==".slice(2-(3&e.length));let t,r,n,i="";for(let a=0;a<e.length;)t=o[e.charAt(a++)]<<18|o[e.charAt(a++)]<<12|(r=o[e.charAt(a++)])<<6|(n=o[e.charAt(a++)]),i+=64===r?f(t>>16&255):64===n?f(t>>16&255,t>>8&255):f(t>>16&255,t>>8&255,255&t);return i},A=e?e=>atob(u(e)):r?e=>Buffer.from(e,"base64").toString("binary"):m,U=r?e=>Buffer.from(e,"base64").toString("utf8"):e=>g(A(e)),w=e=>u(e.replace(/[-_]/g,e=>"-"==e?"+":"/")),S=e=>U(w(e)),C=r?e=>i(Buffer.from(w(e),"base64")):e=>i(A(w(e)),e=>e.charCodeAt(0)),R=e=>({value:e,enumerable:!1,writable:!0,configurable:!0}),I=function(){const e=(e,t)=>Object.defineProperty(String.prototype,e,R(t));e("fromBase64",function(){return S(this)}),e("toBase64",function(e){return h(this,e)}),e("toBase64URI",function(){return h(this,!0)}),e("toBase64URL",function(){return h(this,!0)}),e("toUint8Array",function(){return C(this)})},j=function(){const e=(e,t)=>Object.defineProperty(Uint8Array.prototype,e,R(t));e("toBase64",function(e){return p(this,e)}),e("toBase64URI",function(){return p(this,!0)}),e("toBase64URL",function(){return p(this,!0)})},x={version:"3.4.4",VERSION:"3.4.4",atob:A,atobPolyfill:m,btoa:l,btoaPolyfill:s,fromBase64:S,toBase64:h,encode:h,encodeURI:B,encodeURL:B,utob:y,btou:g,decode:S,fromUint8Array:p,toUint8Array:C,extendString:I,extendUint8Array:j,extendBuiltins:()=>{I(),j()},Base64:{}};return Object.keys(x).forEach(e=>x.Base64[e]=x[e]),x});
|
||||||
|
//# sourceMappingURL=/sm/d011865b76fc8428bebb88d3ec34fb9679a1de489566eef3d3a5c2171d590667.map
|
1
web/js/dracula.min.js
vendored
Normal file
1
web/js/dracula.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user