diff --git a/web/app/controllers/contest_inside.php b/web/app/controllers/contest_inside.php index aaee9cb..aff8540 100644 --- a/web/app/controllers/contest_inside.php +++ b/web/app/controllers/contest_inside.php @@ -54,10 +54,10 @@ if ($is_manager) { isset($tabs_info[$cur_tab]) || UOJResponse::page404(); if (UOJContest::cur()->userCanStartFinalTest(Auth::user())) { - if (CONTEST_PENDING_FINAL_TEST <= $contest['cur_progress']) { + if (CONTEST_PENDING_FINAL_TEST == $contest['cur_progress']) { $start_test_form = new UOJForm('start_test'); $start_test_form->handle = function () { - UOJContest::finalTest(); + UOJContest::cur()->finalTest(); }; $start_test_form->config['submit_container']['class'] = 'mt-2'; $start_test_form->config['submit_button']['class'] = 'btn btn-danger d-block w-100'; @@ -65,7 +65,7 @@ if (UOJContest::cur()->userCanStartFinalTest(Auth::user())) { $start_test_form->config['confirm']['smart'] = true; $start_test_form->runAtServer(); } - if ($contest['cur_progress'] >= CONTEST_TESTING) { + 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(); diff --git a/web/app/controllers/problem.php b/web/app/controllers/problem.php index f346386..9ddba6b 100644 --- a/web/app/controllers/problem.php +++ b/web/app/controllers/problem.php @@ -101,7 +101,7 @@ if (UOJContest::cur()) { $submission_requirement = UOJProblem::cur()->getSubmissionRequirement(); $custom_test_requirement = UOJProblem::cur()->getCustomTestRequirement(); -$custom_test_enabled = $custom_test_requirement && $pre_submit_check_ret === true; +$custom_test_enabled = $custom_test_requirement && $pre_submit_check_ret === true && UOJProblem::info('type') != 'remote'; function handleUpload($zip_file_name, $content, $tot_size) { global $is_participating; @@ -168,11 +168,8 @@ if ($custom_test_enabled) { $custom_test_form->runAtServer(); } -$can_use_zip_upload = true; -foreach ($submission_requirement as $req) { - if ($req['type'] == 'source code') { - $can_use_zip_upload = false; - } +if (empty($submission_requirement)) { + $no_more_submission = '当前题目未配置提交文件,请联系管理员!'; } if ($pre_submit_check_ret === true && !$no_more_submission) { @@ -271,12 +268,12 @@ if (UOJContest::cur()) {
= $pre_submit_check_ret ?>
-= $no_more_submission ?>
-= $submission_warning ?>
printHTML(); ?> diff --git a/web/app/controllers/subdomain/blog/blog.php b/web/app/controllers/subdomain/blog/blog.php index d723201..95c0330 100644 --- a/web/app/controllers/subdomain/blog/blog.php +++ b/web/app/controllers/subdomain/blog/blog.php @@ -88,7 +88,7 @@ $reply_form->addHidden( return '您要回复的对象不存在'; } $comment = UOJBlogComment::query($reply_id); - if (!$comment || $comment['blog_id'] != $blog['id']) { + if (!$comment || $comment->info['blog_id'] != $blog['id']) { return '您要回复的对象不存在'; } $vdata['parent'] = $comment; diff --git a/web/app/models/UOJContest.php b/web/app/models/UOJContest.php index e7496d9..41cb363 100644 --- a/web/app/models/UOJContest.php +++ b/web/app/models/UOJContest.php @@ -53,65 +53,6 @@ class UOJContest { return isSuperUser($user) || UOJUser::checkPermission($user, 'contests.create'); } - public static function finalTest() { - $contest = self::info(); - - $res = DB::selectAll([ - "select id, problem_id, content, submitter, hide_score_to_others from submissions", - "where", ["contest_id" => $contest['id']] - ]); - foreach ($res as $submission) { - $content = json_decode($submission['content'], true); - if (isset($content['final_test_config'])) { - $content['config'] = $content['final_test_config']; - unset($content['final_test_config']); - } - if (isset($content['first_test_config'])) { - unset($content['first_test_config']); - } - UOJSubmission::rejudgeById($submission['id'], [ - 'reason_text' => HTML::stripTags($contest['name']) . ' 最终测试', - 'reason_url' => HTML::url(UOJContest::cur()->getUri()), - 'set_q' => [ - "content" => json_encode($content) - ] - ]); - } - - // warning: check if this command works well when the database is not MySQL - DB::update([ - "update submissions", - "set", [ - "score = hidden_score", - "hidden_score = NULL", - "hide_score_to_others = 0" - ], "where", [ - "contest_id" => $contest['id'], - "hide_score_to_others" => 1 - ] - ]); - - $updated = []; - foreach ($res as $submission) { - $submitter = $submission['submitter']; - $pid = $submission['problem_id']; - if (isset($updated[$submitter]) && isset($updated[$submitter][$pid])) { - continue; - } - updateBestACSubmissions($submitter, $pid); - if (!isset($updated[$submitter])) { - $updated[$submitter] = []; - } - $updated[$submitter][$pid] = true; - } - - DB::update([ - "update contests", - "set", ["status" => 'testing'], - "where", ["id" => $contest['id']] - ]); - } - public static function announceOfficialResults() { // time config set_time_limit(0); @@ -246,17 +187,128 @@ class UOJContest { $label = '开始最终测试'; } - if ($this->progress() >= CONTEST_TESTING) { - $label = '重新' . $label; + return $label; + } + + public function finalTest() { + ignore_user_abort(true); + set_time_limit(0); + + DB::update([ + "update contests", + "set", ["status" => 'testing'], + "where", ["id" => $this->info['id']] + ]); + + if (DB::affected_rows() !== 1) { + // 已经有其他人开始评测了,不进行任何操作 + return; } - return $label; + $res = DB::selectAll([ + "select id, problem_id, content, result, submitter, hide_score_to_others from submissions", + "where", ["contest_id" => $this->info['id']] + ]); + foreach ($res as $submission) { + $content = json_decode($submission['content'], true); + + if (isset($content['final_test_config'])) { + $content['config'] = $content['final_test_config']; + unset($content['final_test_config']); + } + + if (isset($content['first_test_config'])) { + unset($content['first_test_config']); + } + + $q = [ + 'content' => json_encode($content), + ]; + + $problem_judge_type = $this->info['extra_config']["problem_{$submission['problem_id']}"] ?: $this->defaultProblemJudgeType(); + $result = json_decode($submission['result'], true); + + switch ($problem_judge_type) { + case 'sample': + if (isset($result['final_result']) && $result['final_result']['status'] == 'Judged') { + $q += [ + 'result' => json_encode($result['final_result']), + 'score' => $result['final_result']['score'], + 'used_time' => $result['final_result']['time'], + 'used_memory' => $result['final_result']['memory'], + 'judge_time' => $this->info['end_time_str'], + 'status' => 'Judged', + ]; + + if ($submission['hide_score_to_others']) { + $q['hidden_score'] = $q['score']; + $q['score'] = null; + } + } + + break; + + case 'no-details': + case 'full': + if ($result['status'] == 'Judged') { + $q += [ + 'result' => $submission['result'], + 'score' => $result['score'], + 'used_time' => $result['time'], + 'used_memory' => $result['memory'], + 'judge_time' => $this->info['end_time_str'], + 'status' => 'Judged', + ]; + + if ($submission['hide_score_to_others']) { + $q['hidden_score'] = $q['score']; + $q['score'] = null; + } + } + + break; + } + + UOJSubmission::rejudgeById($submission['id'], [ + 'reason_text' => HTML::stripTags($this->info['name']) . ' 最终测试', + 'reason_url' => HTML::url(UOJContest::cur()->getUri()), + 'set_q' => $q, + ]); + } + + // warning: check if this command works well when the database is not MySQL + DB::update([ + "update submissions", + "set", [ + "score = hidden_score", + "hidden_score = NULL", + "hide_score_to_others = 0" + ], "where", [ + "contest_id" => $this->info['id'], + "hide_score_to_others" => 1 + ] + ]); + + $updated = []; + foreach ($res as $submission) { + $submitter = $submission['submitter']; + $pid = $submission['problem_id']; + if (isset($updated[$submitter]) && isset($updated[$submitter][$pid])) { + continue; + } + updateBestACSubmissions($submitter, $pid); + if (!isset($updated[$submitter])) { + $updated[$submitter] = []; + } + $updated[$submitter][$pid] = true; + } } public function queryJudgeProgress() { if ($this->basicRule() == 'OI' && $this->progress() < CONTEST_TESTING) { $rop = 0; $title = UOJLocale::get('contests::contest pending final test'); + $fully_judged = false; } else { $total = DB::selectCount([ "select count(*) from submissions", @@ -272,13 +324,15 @@ class UOJContest { $rop = $total == 0 ? 100 : (int)($n_judged / $total * 100); $title = UOJLocale::get('contests::contest final testing'); - if ($this->basicRule() != 'OI' && $n_judged == $total) { + $fully_judged = $n_judged == $total; + if ($this->basicRule() != 'OI' && $fully_judged) { $title = UOJLocale::get('contests::contest official results to be announced'); } } return [ 'rop' => $rop, - 'title' => $title + 'title' => $title, + 'fully_judged' => $fully_judged, ]; } diff --git a/web/app/models/UOJProblem.php b/web/app/models/UOJProblem.php index 96b2c95..ee0da7d 100644 --- a/web/app/models/UOJProblem.php +++ b/web/app/models/UOJProblem.php @@ -460,10 +460,6 @@ class UOJProblem { return $key === null ? $extra_config : $extra_config[$key]; } public function getCustomTestRequirement() { - if ($this->info['type'] == 'remote') { - return []; - } - $extra_config = json_decode($this->info['extra_config'], true); if (isset($extra_config['custom_test_requirement'])) { @@ -559,11 +555,16 @@ class UOJProblem { } public function userCanUploadSubmissionViaZip(array $user = null) { - foreach ($this->getSubmissionRequirement() as $req) { + $submission_requirement = $this->getSubmissionRequirement(); + + if (empty($submission_requirement)) return false; + + foreach ($submission_requirement as $req) { if ($req['type'] == 'source code') { return false; } } + return true; } diff --git a/web/app/views/page-header.php b/web/app/views/page-header.php index c6d1af3..cd105f7 100644 --- a/web/app/views/page-header.php +++ b/web/app/views/page-header.php @@ -180,7 +180,50 @@ if (!isset($ShowPageHeader)) { skipHtmlTags: { '[-]': ['pre'] }, - } + renderActions: { + addCopyText: [ + 155, + (doc) => { + for (const math of doc.math) { + MathJax.config.addCopyText(math, doc); + } + }, + function(math, doc) { + MathJax.config.addCopyText(math, doc); + } + ] + }, + }, + addCopyText(math, doc) { + doc.adaptor.append( + math.typesetRoot, + doc.adaptor.node( + 'mjx-copytext', { + 'aria-hidden': true, + }, + [ + doc.adaptor.text( + math.start.delim + + math.math + + math.end.delim) + ] + ) + ); + }, + startup: { + ready() { + MathJax._.output.chtml_ts.CHTML.commonStyles['mjx-copytext'] = { + display: 'inline-block', + position: 'absolute', + top: 0, + left: 0, + width: 0, + height: 0, + opacity: 0, + }; + MathJax.startup.defaultReady(); + } + }, };