From 489327cc0d73611e25d2da2fef125eb7198e9a6f Mon Sep 17 00:00:00 2001 From: undefined Date: Tue, 14 Dec 2021 13:25:20 +0800 Subject: [PATCH] core: allow view solution & others code after accept --- packages/hydrooj/package.json | 2 +- packages/hydrooj/src/handler/problem.ts | 12 ++++++-- packages/hydrooj/src/handler/record.ts | 28 ++++++++++++------- packages/hydrooj/src/model/builtin.ts | 10 ++++++- packages/ui-default/backendlib/template.js | 8 +----- packages/ui-default/package.json | 2 +- .../ui-default/templates/user_detail.html | 4 +-- 7 files changed, 41 insertions(+), 25 deletions(-) diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 95f99695b..b2fc358d7 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "3.2.16", + "version": "3.2.17", "bin": "bin/hydrooj.js", "main": "src/loader", "module": "src/loader", diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index 6a923065d..b2735fd82 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -16,7 +16,7 @@ import { } from '../interface'; import paginate from '../lib/paginate'; import { isPid, parsePid as convertPid } from '../lib/validator'; -import { PERM, PRIV } from '../model/builtin'; +import { PERM, PRIV, STATUS } from '../model/builtin'; import * as contest from '../model/contest'; import * as discussion from '../model/discussion'; import domain from '../model/domain'; @@ -650,7 +650,10 @@ export class ProblemSolutionHandler extends ProblemDetailHandler { async get(domainId: string, page = 1, tid?: ObjectID) { if (tid) throw new PermissionError(PERM.PERM_VIEW_PROBLEM_SOLUTION); this.response.template = 'problem_solution.html'; - this.checkPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION); + const accepted = this.tsdoc?.status === STATUS.STATUS_ACCEPTED; + if (!accepted || !this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION_ACCEPT)) { + this.checkPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION); + } const [psdocs, pcount, pscount] = await paginate( solution.getMulti(domainId, this.pdoc.docId), page, @@ -754,7 +757,10 @@ export class ProblemSolutionRawHandler extends ProblemDetailHandler { @param('tid', Types.ObjectID, true) async get(domainId: string, psid: ObjectID, psrid?: ObjectID, tid?: ObjectID) { if (tid) throw new PermissionError(PERM.PERM_VIEW_PROBLEM_SOLUTION); - this.checkPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION); + const accepted = this.tsdoc?.status === STATUS.STATUS_ACCEPTED; + if (!accepted || !this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION_ACCEPT)) { + this.checkPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION); + } if (psrid) { const [psdoc, psrdoc] = await solution.getReply(domainId, psid, psrid); if ((!psdoc) || psdoc.parentId !== this.pdoc.docId) throw new SolutionNotFoundError(psid, psrid); diff --git a/packages/hydrooj/src/handler/record.ts b/packages/hydrooj/src/handler/record.ts index 69fb5b41e..e3073fd03 100644 --- a/packages/hydrooj/src/handler/record.ts +++ b/packages/hydrooj/src/handler/record.ts @@ -115,11 +115,15 @@ class RecordDetailHandler extends Handler { canView ||= contest.canShowSelfRecord.call(this, tdoc, true) && rdoc.uid === this.user._id; if (!canView) throw new PermissionError(rid); } - if (rdoc.uid !== this.user._id && !this.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE)) { - if (!this.user.hasPerm(PERM.PERM_READ_RECORD_CODE)) { - rdoc.code = ''; - rdoc.compilerTexts = []; - } + let canViewCode = rdoc.uid === this.user._id; + canViewCode ||= this.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE); + if (!canViewCode && this.user.hasPerm(PERM.PERM_READ_RECORD_CODE_ACCEPT)) { + const self = await problem.getStatus(domainId, rdoc.pid, this.user._id); + canViewCode ||= self.status === STATUS.STATUS_ACCEPTED; + } + if (!canViewCode) { + rdoc.code = ''; + rdoc.compilerTexts = []; } // eslint-disable-next-line prefer-const let [pdoc, udoc] = await Promise.all([ @@ -277,11 +281,15 @@ class RecordDetailConnectionHandler extends ConnectionHandler { canView ||= this.user._id === rdoc.uid && contest.canShowSelfRecord.call(this, tdoc); if (!canView) throw new PermissionError(PERM.PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD); } - if (rdoc.uid !== this.user._id && !this.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE)) { - if (!this.user.hasPerm(PERM.PERM_READ_RECORD_CODE)) { - rdoc.code = ''; - rdoc.compilerTexts = []; - } + let canViewCode = rdoc.uid === this.user._id; + canViewCode ||= this.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE); + if (!canViewCode && this.user.hasPerm(PERM.PERM_READ_RECORD_CODE_ACCEPT)) { + const self = await problem.getStatus(domainId, rdoc.pid, this.user._id); + canViewCode ||= self.status === STATUS.STATUS_ACCEPTED; + } + if (!canViewCode) { + rdoc.code = ''; + rdoc.compilerTexts = []; } const pdoc = await problem.get(rdoc.domainId, rdoc.pid); let canView = pdoc && this.user.own(pdoc); diff --git a/packages/hydrooj/src/model/builtin.ts b/packages/hydrooj/src/model/builtin.ts index 048d2cb85..8807bda44 100644 --- a/packages/hydrooj/src/model/builtin.ts +++ b/packages/hydrooj/src/model/builtin.ts @@ -14,7 +14,7 @@ export const PERM = { PERM_EDIT_DOMAIN: 1n << 1n, PERM_MOD_BADGE: 1n << 2n, - // Problem and Record + // Problem PERM_CREATE_PROBLEM: 1n << 4n, PERM_EDIT_PROBLEM: 1n << 5n, PERM_EDIT_PROBLEM_SELF: 1n << 6n, @@ -22,12 +22,16 @@ export const PERM = { PERM_VIEW_PROBLEM_HIDDEN: 1n << 8n, PERM_SUBMIT_PROBLEM: 1n << 9n, PERM_READ_PROBLEM_DATA: 1n << 10n, + + // Record PERM_READ_RECORD_CODE: 1n << 12n, + PERM_READ_RECORD_CODE_ACCEPT: 1n << 64n, PERM_REJUDGE_PROBLEM: 1n << 13n, PERM_REJUDGE: 1n << 14n, // Problem Solution PERM_VIEW_PROBLEM_SOLUTION: 1n << 15n, + PERM_VIEW_PROBLEM_SOLUTION_ACCEPT: 1n << 65n, PERM_CREATE_PROBLEM_SOLUTION: 1n << 16n, PERM_VOTE_PROBLEM_SOLUTION: 1n << 17n, PERM_EDIT_PROBLEM_SOLUTION: 1n << 18n, @@ -106,9 +110,11 @@ export const PERMS = [ Permission('perm_problem', PERM.PERM_SUBMIT_PROBLEM, 'Submit problem'), Permission('perm_problem', PERM.PERM_READ_PROBLEM_DATA, 'Read data of problem'), Permission('perm_record', PERM.PERM_READ_RECORD_CODE, 'Read record codes'), + Permission('perm_record', PERM.PERM_READ_RECORD_CODE_ACCEPT, 'Read record codes after accept'), Permission('perm_record', PERM.PERM_REJUDGE_PROBLEM, 'Rejudge problems'), Permission('perm_record', PERM.PERM_REJUDGE, 'Rejudge records'), Permission('perm_problem_solution', PERM.PERM_VIEW_PROBLEM_SOLUTION, 'View problem solutions'), + Permission('perm_problem_solution', PERM.PERM_VIEW_PROBLEM_SOLUTION_ACCEPT, 'View problem solutions after accept'), Permission('perm_problem_solution', PERM.PERM_CREATE_PROBLEM_SOLUTION, 'Create problem solutions'), Permission('perm_problem_solution', PERM.PERM_VOTE_PROBLEM_SOLUTION, 'Vote problem solutions'), Permission('perm_problem_solution', PERM.PERM_EDIT_PROBLEM_SOLUTION, 'Edit problem solutions'), @@ -164,6 +170,7 @@ for (const p of PERMS) { PERM.PERM_BASIC = PERM.PERM_VIEW | PERM.PERM_VIEW_PROBLEM | PERM.PERM_VIEW_PROBLEM_SOLUTION + | PERM.PERM_VIEW_PROBLEM_SOLUTION_ACCEPT | PERM.PERM_VIEW_DISCUSSION | PERM.PERM_VIEW_CONTEST | PERM.PERM_VIEW_CONTEST_SCOREBOARD @@ -177,6 +184,7 @@ PERM.PERM_DEFAULT = PERM.PERM_VIEW | PERM.PERM_EDIT_PROBLEM_SELF | PERM.PERM_SUBMIT_PROBLEM | PERM.PERM_VIEW_PROBLEM_SOLUTION + | PERM.PERM_VIEW_PROBLEM_SOLUTION_ACCEPT | PERM.PERM_CREATE_PROBLEM_SOLUTION | PERM.PERM_VOTE_PROBLEM_SOLUTION | PERM.PERM_EDIT_PROBLEM_SOLUTION_SELF diff --git a/packages/ui-default/backendlib/template.js b/packages/ui-default/backendlib/template.js index ee0bd8d11..699f7c4ac 100644 --- a/packages/ui-default/backendlib/template.js +++ b/packages/ui-default/backendlib/template.js @@ -121,6 +121,7 @@ env.addGlobal('static_url', (assetName) => { // eslint-disable-next-line no-eval env.addGlobal('eval', eval); env.addGlobal('Date', Date); +env.addGlobal('Math', Math); env.addGlobal('process', process); env.addGlobal('global', global); env.addGlobal('typeof', (o) => typeof o); @@ -141,13 +142,6 @@ env.addGlobal('set', (obj, key, val) => { env.addGlobal('findSubModule', (prefix) => { filter(Object.keys(global.Hydro.ui.template), (n) => n.startsWith(prefix)); }); -env.addGlobal('parseContestProblemId', (pdoc, tdoc) => { - if (tdoc.pids[parseInt(pdoc.pid, 36) - 10]) return pdoc.pid; - let cur = tdoc.pids.indexOf(pdoc.docId); - if (cur !== -1) return (cur + 10).toString(36).toUpperCase(); - cur = tdoc.pids.indexOf(`${pdoc.domainId}:${pdoc.docId}`); - return (cur + 10).toString(36).toUpperCase(); -}); async function render(name, state) { // eslint-disable-next-line no-return-await diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 1829aff04..8c03ee350 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/ui-default", - "version": "4.27.5", + "version": "4.27.6", "author": "undefined ", "license": "AGPL-3.0", "main": "hydro.js", diff --git a/packages/ui-default/templates/user_detail.html b/packages/ui-default/templates/user_detail.html index 8d1d46673..017ce4368 100644 --- a/packages/ui-default/templates/user_detail.html +++ b/packages/ui-default/templates/user_detail.html @@ -108,11 +108,11 @@

{{ _('Accepted Problems') }}

- {% set _mark = (pdocs.length/4)|int %} + {% set _mark = Math.ceil(pdocs.length/4) %} {% set _one = pdocs.slice(0, _mark) %} {% set _two = pdocs.slice(_mark, _mark*2) %} {% set _three = pdocs.slice(_mark*2, _mark*3) %} - {% set _four = pdocs.slice(_mark*3, pdocs.length) %} + {% set _four = pdocs.slice(_mark*3, pdocs.length - 1) %}