diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index a5717b67..99a528e0 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -738,18 +738,24 @@ export class ProblemFileDownloadHandler extends ProblemDetailHandler { export class ProblemSolutionHandler extends ProblemDetailHandler { @param('page', Types.PositiveInt, true) @param('tid', Types.ObjectID, true) - async get(domainId: string, page = 1, tid?: ObjectID) { + @param('sid', Types.ObjectID, true) + async get(domainId: string, page = 1, tid?: ObjectID, sid?: ObjectID) { if (tid) throw new PermissionError(PERM.PERM_VIEW_PROBLEM_SOLUTION); this.response.template = 'problem_solution.html'; 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( + // eslint-disable-next-line prefer-const + let [psdocs, pcount, pscount] = await paginate( solution.getMulti(domainId, this.pdoc.docId), page, system.get('pagination.solution'), ); + if (sid) { + psdocs = [await solution.get(domainId, sid)]; + if (!psdocs[0]) throw new SolutionNotFoundError(domainId, sid); + } const uids = [this.pdoc.owner]; const docids = []; for (const psdoc of psdocs) { @@ -762,7 +768,7 @@ export class ProblemSolutionHandler extends ProblemDetailHandler { const udict = await user.getList(domainId, uids); const pssdict = await solution.getListStatus(domainId, docids, this.user._id); this.response.body = { - psdocs, page, pcount, pscount, udict, pssdict, pdoc: this.pdoc, + psdocs, page, pcount, pscount, udict, pssdict, pdoc: this.pdoc, sid, }; await bus.serial('handler/solution/get', this); } @@ -934,6 +940,7 @@ export async function apply() { Route('problem_files', '/p/:pid/files', ProblemFilesHandler, PERM.PERM_VIEW_PROBLEM); Route('problem_file_download', '/p/:pid/file/:filename', ProblemFileDownloadHandler, PERM.PERM_VIEW_PROBLEM); Route('problem_solution', '/p/:pid/solution', ProblemSolutionHandler, PERM.PERM_VIEW_PROBLEM); + Route('problem_solution_detail', '/p/:pid/solution/:sid', ProblemSolutionHandler, PERM.PERM_VIEW_PROBLEM); Route('problem_solution_raw', '/p/:pid/solution/:psid/raw', ProblemSolutionRawHandler, PERM.PERM_VIEW_PROBLEM); Route('problem_solution_reply_raw', '/p/:pid/solution/:psid/:psrid/raw', ProblemSolutionRawHandler, PERM.PERM_VIEW_PROBLEM); Route('problem_create', '/problem/create', ProblemCreateHandler, PERM.PERM_CREATE_PROBLEM); diff --git a/packages/ui-default/components/clipboard.page.ts b/packages/ui-default/components/clipboard.page.ts new file mode 100644 index 00000000..a4f0fbfe --- /dev/null +++ b/packages/ui-default/components/clipboard.page.ts @@ -0,0 +1,17 @@ +import Clipboard from 'clipboard'; +import Notification from 'vj/components/notification'; +import { AutoloadPage } from 'vj/misc/Page'; +import i18n from 'vj/utils/i18n'; + +export default new AutoloadPage('clipboard', () => { + $('[data-copy]').each(function () { + const clip = new Clipboard(this, { text: () => this.dataset.copy }); + clip.on('success', () => Notification.success(i18n('Copied to clipboard!'))); + clip.on('error', () => Notification.error(i18n('Copy failed :('))); + }); + $('[data-copylink]').each(function () { + const clip = new Clipboard(this, { text: () => new URL(this.dataset.copylink, document.location.href).toString() }); + clip.on('success', () => Notification.success(i18n('Link copied to clipboard!'))); + clip.on('error', () => Notification.error(i18n('Copy failed :('))); + }); +}); diff --git a/packages/ui-default/templates/components/comments_solution.html b/packages/ui-default/templates/components/comments_solution.html index eace1c6f..d3aa9721 100644 --- a/packages/ui-default/templates/components/comments_solution.html +++ b/packages/ui-default/templates/components/comments_solution.html @@ -112,6 +112,9 @@ {{ user.render_inline(udoc) }} @ {{ datetimeSpan(doc._id)|safe }}
+ + + {% if handler.user.hasPerm(reply_post_perm) %}
+ {% if sid %} +
+ {{ _('View all {0} solutions').format(pscount) }} +
+ {% endif %}
{% set owner_udoc = udict[pdoc.owner] %}