diff --git a/models/contest.js b/models/contest.js index 3309dc1..e59eb01 100644 --- a/models/contest.js +++ b/models/contest.js @@ -93,7 +93,7 @@ class Contest extends Model { } async isAllowedSeeResultBy(user) { - if (this.type === 'acm' || this.type === 'ioi') return true; + if (this.type === 'acm') return true; return (user && (user.is_admin || this.holder_id === user.id)) || !(await this.isRunning()); } diff --git a/models/contest_player.js b/models/contest_player.js index 3999b36..c64659a 100644 --- a/models/contest_player.js +++ b/models/contest_player.js @@ -131,6 +131,7 @@ class ContestPlayer extends Model { this.score_details[judge_state.problem_id].submissions[judge_state.id] = { judge_id: judge_state.id, accepted: judge_state.status === 'Accepted', + compiled: judge_state.status !== 'Compile Error', time: judge_state.submit_time }; @@ -145,7 +146,7 @@ class ContestPlayer extends Model { this.score_details[judge_state.problem_id].acceptedTime = x.time; this.score_details[judge_state.problem_id].judge_id = x.judge_id; break; - } else { + } else if (x.compiled) { this.score_details[judge_state.problem_id].unacceptedCount++; } } diff --git a/models/judge_state.js b/models/judge_state.js index 5e1b123..28f6cc1 100644 --- a/models/judge_state.js +++ b/models/judge_state.js @@ -99,26 +99,21 @@ class JudgeState extends Model { if (this.problem_id) this.problem = await Problem.fromID(this.problem_id); } - async isAllowedSeeResultBy(user) { + async isAllowedVisitBy(user) { await this.loadRelationships(); if (user && user.id === this.problem.user_id) return true; - else if (this.type === 0) return this.problem.is_public || (user && (await user.hasPrivilege('manage_problem'))); + else if (this.type === 0 || this.type == 2) return this.problem.is_public || (user && (await user.hasPrivilege('manage_problem'))); else if (this.type === 1) { - let contest = await Contest.fromID(this.type_info); - if (await contest.isRunning()) { - return (contest.type === 'acm' || contest.type === 'ioi') || (user && user.is_admin); - } else { - return true; - } - } else if (this.type === 2) return user && (await user.hasPrivilege('manage_problem')); + return user && (user.is_admin || user.id === this.user_id); + } } async isAllowedSeeCodeBy(user) { await this.loadRelationships(); if (user && user.id === this.problem.user_id) return true; - else if (this.type === 0) return this.problem.is_public || (user && (await user.hasPrivilege('manage_problem'))); + else if (this.type === 0 || this.type === 2) return this.problem.is_public || (user && (await user.hasPrivilege('manage_problem'))); else if (this.type === 1) { let contest = await Contest.fromID(this.type_info); if (await contest.isRunning()) { @@ -126,14 +121,14 @@ class JudgeState extends Model { } else { return true; } - } else if (this.type === 2) return user && (await user.hasPrivilege('manage_problem')); + } } async isAllowedSeeCaseBy(user) { await this.loadRelationships(); if (user && user.id === this.problem.user_id) return true; - else if (this.type === 0) return this.problem.is_public || (user && (await user.hasPrivilege('manage_problem'))); + else if (this.type === 0 || this.type === 2) return this.problem.is_public || (user && (await user.hasPrivilege('manage_problem'))); else if (this.type === 1) { let contest = await Contest.fromID(this.type_info); if (await contest.isRunning()) { @@ -141,14 +136,14 @@ class JudgeState extends Model { } else { return true; } - } else if (this.type === 2) return user && (await user.hasPrivilege('manage_problem')); + } } async isAllowedSeeDataBy(user) { await this.loadRelationships(); if (user && user.id === this.problem.user_id) return true; - else if (this.type === 0) return this.problem.is_public || (user && (await user.hasPrivilege('manage_problem'))); + else if (this.type === 0 || this.type === 2) return this.problem.is_public || (user && (await user.hasPrivilege('manage_problem'))); else if (this.type === 1) { let contest = await Contest.fromID(this.type_info); if (await contest.isRunning()) { @@ -156,7 +151,7 @@ class JudgeState extends Model { } else { return true; } - } else if (this.type === 2) return true; + } } async updateResult(result) { @@ -169,7 +164,7 @@ class JudgeState extends Model { } async updateRelatedInfo(newSubmission) { - if (this.type === 0) { + if (this.type === 0 || this.type === 2) { if (newSubmission) { await this.loadRelationships(); await this.user.refreshSubmitInfo(); @@ -222,7 +217,7 @@ class JudgeState extends Model { await this.user.save(); } - if (this.type === 0) { + if (this.type === 0 || this.type === 2) { if (oldStatus === 'Accepted') { this.problem.ac_num--; await this.problem.save(); diff --git a/modules/contest.js b/modules/contest.js index cf24d52..1454fcf 100644 --- a/modules/contest.js +++ b/modules/contest.js @@ -138,17 +138,12 @@ app.get('/contest/:id', async (req, res) => { for (let problem of problems) { if (contest.type === 'noi') { if (player.score_details[problem.problem.id]) { - if (await contest.isRunning()) { - problem.status = true; - } else { - let judge_state = await JudgeState.fromID(player.score_details[problem.problem.id].judge_id); - problem.status = judge_state.status; + let judge_state = await JudgeState.fromID(player.score_details[problem.problem.id].judge_id); + problem.status = judge_state.status; + if (!contest.ended && !await problem.problem.isAllowedEditBy(res.locals.user) && !['Compile Error', 'Waiting', 'Compiling'].includes(problem.status)) { + problem.status = 'Compiled'; } problem.judge_id = player.score_details[problem.problem.id].judge_id; - } else { - if (contest.isRunning()) { - problem.status = false; - } } } else if (contest.type === 'ioi') { if (player.score_details[problem.problem.id]) { @@ -215,8 +210,8 @@ app.get('/contest/:id/ranklist', async (req, res) => { try { let contest_id = parseInt(req.params.id); let contest = await Contest.fromID(contest_id); - if (!contest) throw new ErrorMessage('无此比赛。'); + if (!contest) throw new ErrorMessage('无此比赛。'); if (!await contest.isAllowedSeeResultBy(res.locals.user)) throw new ErrorMessage('您没有权限进行此操作。'); await contest.loadRelationships(); @@ -260,6 +255,7 @@ app.get('/contest/:id/submissions', async (req, res) => { let contest = await Contest.fromID(contest_id); if (!contest) throw new ErrorMessage('无此比赛。'); + if (!await contest.isAllowedSeeResultBy(res.locals.user)) throw new ErrorMessage('您没有权限进行此操作。'); contest.ended = await contest.isEnded(); @@ -272,7 +268,7 @@ app.get('/contest/:id/submissions', async (req, res) => { where.type = 1; where.type_info = contest_id; - if (contest.ended || contest.type !== 'noi' || (res.locals.user && res.locals.user.is_admin)) { + if (contest.ended || (res.locals.user && res.locals.user.is_admin)) { if (!((!res.locals.user || !res.locals.user.is_admin) && !contest.ended && contest.type === 'acm')) { let minScore = parseInt(req.query.min_score); if (isNaN(minScore)) minScore = 0; @@ -294,12 +290,17 @@ app.get('/contest/:id/submissions', async (req, res) => { let paginate = syzoj.utils.paginate(await JudgeState.count(where), req.query.page, syzoj.config.page.judge_state); let judge_state = await JudgeState.query(paginate, where, [['submit_time', 'desc']]); - await judge_state.forEachAsync(async obj => obj.hidden = !(await obj.isAllowedSeeResultBy(res.locals.user))); await judge_state.forEachAsync(async obj => obj.allowedSeeCode = await obj.isAllowedSeeCodeBy(res.locals.user)); await judge_state.forEachAsync(async obj => { await obj.loadRelationships(); obj.problem_id = problems_id.indexOf(obj.problem_id) + 1; obj.problem.title = syzoj.utils.removeTitleTag(obj.problem.title); + + if (contest.type === 'noi' && !contest.ended && !await obj.problem.isAllowedEditBy(res.locals.user)) { + if (!['Compile Error', 'Waiting', 'Compiling'].includes(obj.status)) { + obj.status = 'Compiled'; + } + } }); res.render('contest_submissions', { diff --git a/modules/problem.js b/modules/problem.js index b823406..7144b30 100644 --- a/modules/problem.js +++ b/modules/problem.js @@ -557,8 +557,6 @@ app.post('/problem/:id/submit', async (req, res) => { judge_state.type_info = contest_id; await judge_state.save(); - - if (contest.type === 'noi') redirectToContest = true; } else { if (!await problem.isAllowedUseBy(res.locals.user)) throw new ErrorMessage('您没有权限进行此操作。'); judge_state.type = problem.is_public ? 0 : 2; @@ -572,11 +570,7 @@ app.post('/problem/:id/submit', async (req, res) => { await waiting_judge.save(); - if (redirectToContest) { - res.redirect(syzoj.utils.makeUrl(['contest', contest_id])); - } else { - res.redirect(syzoj.utils.makeUrl(['submission', judge_state.id])); - } + res.redirect(syzoj.utils.makeUrl(['submission', judge_state.id])); } catch (e) { syzoj.log(e); res.render('error', { diff --git a/modules/submission.js b/modules/submission.js index 3499a15..ffb1bea 100644 --- a/modules/submission.js +++ b/modules/submission.js @@ -68,7 +68,6 @@ app.get('/submissions', async (req, res) => { let judge_state = await JudgeState.query(paginate, where, [['submit_time', 'desc']]); await judge_state.forEachAsync(async obj => obj.loadRelationships()); - await judge_state.forEachAsync(async obj => obj.hidden = !(await obj.isAllowedSeeResultBy(res.locals.user))); await judge_state.forEachAsync(async obj => obj.allowedSeeCode = await obj.isAllowedSeeCodeBy(res.locals.user)); await judge_state.forEachAsync(async obj => obj.allowedSeeData = await obj.isAllowedSeeDataBy(res.locals.user)); @@ -92,7 +91,6 @@ app.get('/submissions/:id/ajax', async (req, res) => { await judge_state.loadRelationships(); - judge_state.hidden = !(await judge_state.isAllowedSeeResultBy(res.locals.user)); judge_state.allowedSeeCode = await judge_state.isAllowedSeeCodeBy(res.locals.user); judge_state.allowedSeeData = await judge_state.isAllowedSeeDataBy(res.locals.user); @@ -102,6 +100,12 @@ app.get('/submissions/:id/ajax', async (req, res) => { let problems_id = await contest.getProblems(); judge_state.problem_id = problems_id.indexOf(judge_state.problem_id) + 1; judge_state.problem.title = syzoj.utils.removeTitleTag(judge_state.problem.title); + + if (contest.type === 'noi' && !contest.ended && !await judge_state.problem.isAllowedEditBy(res.locals.user)) { + if (!['Compile Error', 'Waiting', 'Compiling'].includes(judge_state.status)) { + judge_state.status = 'Compiled'; + } + } } res.render('submissions_item', { @@ -120,6 +124,7 @@ app.get('/submission/:id', async (req, res) => { try { let id = parseInt(req.params.id); let judge = await JudgeState.fromID(id); + if (!judge || !await judge.isAllowedVisitBy(res.locals.user)) throw new ErrorMessage('您没有权限进行此操作。'); let contest; if (judge.type === 1) contest = await Contest.fromID(judge.type_info); @@ -128,7 +133,6 @@ app.get('/submission/:id', async (req, res) => { judge.codeLength = judge.code.length; judge.code = await syzoj.utils.highlight(judge.code, syzoj.config.languages[judge.language].highlight); - judge.allowedSeeResult = await judge.isAllowedSeeResultBy(res.locals.user); judge.allowedSeeCode = await judge.isAllowedSeeCodeBy(res.locals.user); judge.allowedSeeCase = await judge.isAllowedSeeCaseBy(res.locals.user); judge.allowedSeeData = await judge.isAllowedSeeDataBy(res.locals.user); @@ -138,6 +142,12 @@ app.get('/submission/:id', async (req, res) => { let problems_id = await contest.getProblems(); judge.problem_id = problems_id.indexOf(judge.problem_id) + 1; judge.problem.title = syzoj.utils.removeTitleTag(judge.problem.title); + + if (contest.type === 'noi' && !contest.ended && !await judge.problem.isAllowedEditBy(res.locals.user)) { + if (!['Compile Error', 'Waiting', 'Compiling'].includes(judge.status)) { + judge.status = 'Compiled'; + } + } } res.render('submission', { @@ -156,6 +166,7 @@ app.get('/submission/:id/ajax', async (req, res) => { try { let id = parseInt(req.params.id); let judge = await JudgeState.fromID(id); + if (!judge || !await judge.isAllowedVisitBy(res.locals.user)) throw new ErrorMessage('您没有权限进行此操作。'); let contest; if (judge.type === 1) contest = await Contest.fromID(judge.type_info); @@ -164,7 +175,6 @@ app.get('/submission/:id/ajax', async (req, res) => { judge.codeLength = judge.code.length; judge.code = await syzoj.utils.highlight(judge.code, syzoj.config.languages[judge.language].highlight); - judge.allowedSeeResult = await judge.isAllowedSeeResultBy(res.locals.user); judge.allowedSeeCode = await judge.isAllowedSeeCodeBy(res.locals.user); judge.allowedSeeCase = await judge.isAllowedSeeCaseBy(res.locals.user); judge.allowedSeeData = await judge.isAllowedSeeDataBy(res.locals.user); @@ -174,6 +184,12 @@ app.get('/submission/:id/ajax', async (req, res) => { let problems_id = await contest.getProblems(); judge.problem_id = problems_id.indexOf(judge.problem_id) + 1; judge.problem.title = syzoj.utils.removeTitleTag(judge.problem.title); + + if (contest.type === 'noi' && !contest.ended && !await judge.problem.isAllowedEditBy(res.locals.user)) { + if (!['Compile Error', 'Waiting', 'Compiling'].includes(judge.status)) { + judge.status = 'Compiled'; + } + } } res.render('submission_content', { diff --git a/static/style.css b/static/style.css index 2280ab0..944b0c5 100644 --- a/static/style.css +++ b/static/style.css @@ -357,6 +357,9 @@ table.center.aligned ul, table.center.aligned ol { } */ +:not(.status_detail).status.compiled, +.title:hover .status_detail.status.compiled, +.title.active .status_detail.status.compiled, :not(.status_detail).status.accepted, .title:hover .status_detail.status.accepted, .title.active .status_detail.status.accepted { diff --git a/views/contest.ejs b/views/contest.ejs index 3360235..303acdd 100644 --- a/views/contest.ejs +++ b/views/contest.ejs @@ -22,7 +22,7 @@
- <% if (contest.allowedEdit || (unveiled && (!contest.running || contest.type !== 'noi'))) { %> + <% if (contest.allowedEdit || (unveiled && (!contest.running || contest.type === 'acm'))) { %>
@@ -66,9 +66,7 @@ <% if (problem.judge_id) { %> - <% if (problem.status === true) { %> - - <% } else if (typeof problem.status === 'string') { %> + <% if (typeof problem.status === 'string') { %> <%= problem.status %> diff --git a/views/contest_ranklist.ejs b/views/contest_ranklist.ejs index 4b9b6c6..f7e5e03 100644 --- a/views/contest_ranklist.ejs +++ b/views/contest_ranklist.ejs @@ -87,7 +87,7 @@
<%= syzoj.utils.formatTime(item.player.score_details[problem.id].acceptedTime - contest.start_time) %>
- <% } else { %> + <% } else if (item.player.score_details[problem.id].unacceptedCount) { %> -<%= item.player.score_details[problem.id].unacceptedCount %> diff --git a/views/contest_submissions.ejs b/views/contest_submissions.ejs index aa2d376..afecb15 100644 --- a/views/contest_submissions.ejs +++ b/views/contest_submissions.ejs @@ -10,7 +10,7 @@
<% if ((typeof contest === 'undefined' || !contest) || contest.ended || contest.type !== 'noi' || (user && user.is_admin)) { %> - <% if ((typeof contest === 'undefined' || !contest) || !((!user || !user.is_admin) && !contest.ended && contest.type === 'acm')) { %> + <% if ((typeof contest === 'undefined' || !contest) || !((!user || !user.is_admin) && !contest.ended && (contest.type === 'acm' || contest.type === 'noi'))) { %>
@@ -71,7 +71,7 @@ 编号 题目 状态 - <% if ((typeof contest === 'undefined' || !contest) || !((!user || !user.is_admin) && !contest.ended && contest.type === 'acm')) { %> + <% if ((typeof contest === 'undefined' || !contest) || !((!user || !user.is_admin) && !contest.ended && (contest.type === 'acm' || contest.type === 'noi'))) { %> 分数 <% } %> 总时间 diff --git a/views/submission_content.ejs b/views/submission_content.ejs index 4c11ac9..1039782 100644 --- a/views/submission_content.ejs +++ b/views/submission_content.ejs @@ -2,7 +2,7 @@ // Sanitize judge results for backward compatibility and clarity if (!judge.result.subtasks) { judge.result.subtasks = [ - { case_num: judge.result.case_num, status: judge.result.status, score: judge.result.score } + { case_num: judge.result.case_num, status: judge.status, score: judge.result.score } ]; for (let i = 0; i < judge.result.case_num; ++i) { judge.result.subtasks[0][i] = judge.result[i]; @@ -35,7 +35,7 @@ else problemUrl = syzoj.utils.makeUrl(['problem', judge.problem_id]); 编号 题目名称 状态 - <% if ((typeof contest === 'undefined' || !contest) || !((!user || !user.is_admin) && !contest.ended && contest.type === 'acm')) { %> + <% if ((typeof contest === 'undefined' || !contest) || !((!user || !user.is_admin) && !contest.ended && (contest.type === 'acm' || contest.type === 'noi'))) { %> 分数 <% } %> 总时间 @@ -49,27 +49,19 @@ else problemUrl = syzoj.utils.makeUrl(['problem', judge.problem_id]); #<%= judge.id %>
<%= (typeof contest !== 'undefined' && contest) ? this.alpha(judge.problem_id) : ('#' + judge.problem_id) %>. <%= judge.problem.title %> - <% if (judge.allowedSeeResult) { %> - - - <%= judge.result.status %> - - <% if ((typeof contest === 'undefined' || !contest) || !((!user || !user.is_admin) && !contest.ended && contest.type === 'acm')) { %> - <%= judge.result.score %> - <% } %> - <%= judge.result.total_time %> ms - <%= parseInt(judge.result.max_memory) || 0 %> K - <% if (judge.allowedSeeCode) { %> - <%= syzoj.config.languages[judge.language].show %> / <%= syzoj.utils.formatSize(judge.codeLength) %> - <% } else { %> - <%= syzoj.config.languages[judge.language].show %> / 隐藏 %> - <% } %> + + + <%= judge.status %> + + <% if ((typeof contest === 'undefined' || !contest) || !((!user || !user.is_admin) && !contest.ended && (contest.type === 'acm' || contest.type === 'noi'))) { %> + <%= judge.result.score %> + <% } %> + <%= judge.result.total_time %> ms + <%= parseInt(judge.result.max_memory) || 0 %> K + <% if (judge.allowedSeeCode) { %> + <%= syzoj.config.languages[judge.language].show %> / <%= syzoj.utils.formatSize(judge.codeLength) %> <% } else { %> - 隐藏 - 隐藏 - 隐藏 - 隐藏 - 隐藏 + <%= syzoj.config.languages[judge.language].show %> / 隐藏 %> <% } %> <%= judge.user.username %><% if (judge.user.nameplate) { %><%- judge.user.nameplate %><% } %> <%= syzoj.utils.formatDate(judge.submit_time) %> @@ -104,13 +96,13 @@ else problemUrl = syzoj.utils.makeUrl(['problem', judge.problem_id]); }); <% } %> -<% if (judge.result.compiler_output && judge.result.status === 'Compile Error' && judge.allowedSeeCode) { %> +<% if (judge.result.compiler_output && judge.status === 'Compile Error' && judge.allowedSeeCode) { %>

编译信息

<%- syzoj.utils.ansiToHTML(judge.result.compiler_output) %>
<% } else if (judge.result.spj_compiler_output) { %>

Special Judge 编译信息

<%- syzoj.utils.ansiToHTML(judge.result.spj_compiler_output) %>
-<% } else if (judge.allowedSeeResult && judge.allowedSeeCase && judge.result.subtasks && (judge.result.subtasks.length !== 1 || judge.result.subtasks[0].case_num)) { %> +<% } else if (judge.allowedSeeCase && judge.result.subtasks && (judge.result.subtasks.length !== 1 || judge.result.subtasks[0].case_num)) { %>
<% let subtask_count = 0; %> <% for (let subtask_cases of (judge.result.subtasks || [])) { %> @@ -186,7 +178,7 @@ $(function() { <% if (!isPending(judge.status)) { %>
<% } %> -<% if (!judge.hidden) { %> <%= judge.status %> -<% if ((typeof contest === 'undefined' || !contest) || !((!user || !user.is_admin) && !contest.ended && contest.type === 'acm')) { %> +<% if ((typeof contest === 'undefined' || !contest) || !((!user || !user.is_admin) && !contest.ended && (contest.type === 'acm' || contest.type === 'noi'))) { %> <%= judge.result.score %> <% } %> <%= judge.result.total_time %> ms @@ -27,15 +26,6 @@ textFit(e, { maxFontSize: 14 }); <% } else { %> <%= syzoj.config.languages[judge.language].show %> / 隐藏 <% } %> -<% } else { %> - 隐藏 - <% if ((typeof contest === 'undefined' || !contest) || !((!user || !user.is_admin) && !contest.ended && contest.type === 'acm')) { %> - 隐藏 - <% } %> - 隐藏 - 隐藏 - 隐藏 -<% } %> <%= judge.user.username %><% if (judge.user.nameplate) { %><%- judge.user.nameplate %><% } %> <%= syzoj.utils.formatDate(judge.submit_time) %> <% if (isPending(judge.status)) { %> diff --git a/views/util.ejs b/views/util.ejs index 7cb8575..709e0db 100644 --- a/views/util.ejs +++ b/views/util.ejs @@ -29,6 +29,7 @@ this.icon = { 'Running': 'spinner', 'Compiling': 'spinner', 'Compile Error': 'code', + 'Compiled': 'checkmark', 'System Error': 'server', 'No Testdata': 'folder open outline', 'Partially Correct': 'minus',