mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 17:46:28 +08:00
core: update to mongodb5 (#514)
This commit is contained in:
1 parent
5a02010120
commit
0685b88066
59 files changed
+610
-601
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { ObjectID } from 'mongodb';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import { DiscussionNotFoundError } from '../error';
|
||||
import { BlogDoc } from '../interface';
|
||||
import paginate from '../lib/paginate';
|
||||
@@ -12,8 +12,8 @@ import { Handler, param, Types } from '../service/server';
|
||||
class BlogHandler extends Handler {
|
||||
ddoc?: BlogDoc;
|
||||
|
||||
@param('did', Types.ObjectID, true)
|
||||
async _prepare(domainId: string, did: ObjectID) {
|
||||
@param('did', Types.ObjectId, true)
|
||||
async _prepare(domainId: string, did: ObjectId) {
|
||||
if (did) {
|
||||
this.ddoc = await blog.get(did);
|
||||
if (!this.ddoc) throw new DiscussionNotFoundError(domainId, did);
|
||||
@@ -42,8 +42,8 @@ class BlogUserHandler extends BlogHandler {
|
||||
}
|
||||
|
||||
class BlogDetailHandler extends BlogHandler {
|
||||
@param('did', Types.ObjectID)
|
||||
async get(domainId: string, did: ObjectID) {
|
||||
@param('did', Types.ObjectId)
|
||||
async get(domainId: string, did: ObjectId) {
|
||||
const dsdoc = this.user.hasPriv(PRIV.PRIV_USER_PROFILE)
|
||||
? await blog.getStatus(did, this.user._id)
|
||||
: null;
|
||||
@@ -64,14 +64,14 @@ class BlogDetailHandler extends BlogHandler {
|
||||
this.checkPriv(PRIV.PRIV_USER_PROFILE);
|
||||
}
|
||||
|
||||
@param('did', Types.ObjectID)
|
||||
async postStar(domainId: string, did: ObjectID) {
|
||||
@param('did', Types.ObjectId)
|
||||
async postStar(domainId: string, did: ObjectId) {
|
||||
await blog.setStar(did, this.user._id, true);
|
||||
this.back({ star: true });
|
||||
}
|
||||
|
||||
@param('did', Types.ObjectID)
|
||||
async postUnstar(domainId: string, did: ObjectID) {
|
||||
@param('did', Types.ObjectId)
|
||||
async postUnstar(domainId: string, did: ObjectId) {
|
||||
await blog.setStar(did, this.user._id, false);
|
||||
this.back({ star: false });
|
||||
}
|
||||
@@ -92,10 +92,10 @@ class BlogEditHandler extends BlogHandler {
|
||||
this.response.redirect = this.url('blog_detail', { uid: this.user._id, did });
|
||||
}
|
||||
|
||||
@param('did', Types.ObjectID)
|
||||
@param('did', Types.ObjectId)
|
||||
@param('title', Types.Title)
|
||||
@param('content', Types.Content)
|
||||
async postUpdate(domainId: string, did: ObjectID, title: string, content: string) {
|
||||
async postUpdate(domainId: string, did: ObjectId, title: string, content: string) {
|
||||
if (!this.user.own(this.ddoc)) this.checkPriv(PRIV.PRIV_EDIT_SYSTEM);
|
||||
await Promise.all([
|
||||
blog.edit(did, title, content),
|
||||
@@ -105,8 +105,8 @@ class BlogEditHandler extends BlogHandler {
|
||||
this.response.redirect = this.url('blog_detail', { uid: this.user._id, did });
|
||||
}
|
||||
|
||||
@param('did', Types.ObjectID)
|
||||
async postDelete(domainId: string, did: ObjectID) {
|
||||
@param('did', Types.ObjectId)
|
||||
async postDelete(domainId: string, did: ObjectId) {
|
||||
if (!this.user.own(this.ddoc)) this.checkPriv(PRIV.PRIV_EDIT_SYSTEM);
|
||||
await Promise.all([
|
||||
blog.del(did),
|
||||
|
||||
@@ -2,7 +2,7 @@ import AdmZip from 'adm-zip';
|
||||
import { statSync } from 'fs-extra';
|
||||
import { pick } from 'lodash';
|
||||
import moment from 'moment-timezone';
|
||||
import { ObjectID } from 'mongodb';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import {
|
||||
Counter, sortFiles, streamToBuffer, Time,
|
||||
} from '@hydrooj/utils/lib/utils';
|
||||
@@ -47,8 +47,8 @@ registerResolver(
|
||||
'Query', 'contest(id: ObjectID!)', 'Contest',
|
||||
async (arg, ctx) => {
|
||||
ctx.checkPerm(PERM.PERM_VIEW);
|
||||
arg.id = new ObjectID(arg.id);
|
||||
ctx.tdoc = await contest.get(ctx.args.domainId, new ObjectID(arg.id));
|
||||
arg.id = new ObjectId(arg.id);
|
||||
ctx.tdoc = await contest.get(ctx.args.domainId, new ObjectId(arg.id));
|
||||
if (!ctx.tdoc) throw new ContestNotFoundError(ctx.args.domainId, arg.id);
|
||||
return ctx.tdoc;
|
||||
},
|
||||
@@ -92,8 +92,8 @@ export class ContestDetailBaseHandler extends Handler {
|
||||
tdoc?: Tdoc<30>;
|
||||
tsdoc?: any;
|
||||
|
||||
@param('tid', Types.ObjectID, true)
|
||||
async __prepare(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId, true)
|
||||
async __prepare(domainId: string, tid: ObjectId) {
|
||||
if (!tid) return; // ProblemDetailHandler also extends from ContestDetailBaseHandler
|
||||
[this.tdoc, this.tsdoc] = await Promise.all([
|
||||
contest.get(domainId, tid),
|
||||
@@ -110,8 +110,8 @@ export class ContestDetailBaseHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID, true)
|
||||
async after(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId, true)
|
||||
async after(domainId: string, tid: ObjectId) {
|
||||
if (!tid || this.tdoc.rule === 'homework') return;
|
||||
if (this.request.json || !this.response.template) return;
|
||||
const pdoc = 'pdoc' in this ? (this as any).pdoc : {};
|
||||
@@ -151,8 +151,8 @@ export class ContestDetailHandler extends Handler {
|
||||
tdoc?: Tdoc<30>;
|
||||
tsdoc?: any;
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
async prepare(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async prepare(domainId: string, tid: ObjectId) {
|
||||
[this.tdoc, this.tsdoc] = await Promise.all([
|
||||
contest.get(domainId, tid),
|
||||
contest.getStatus(domainId, tid, this.user._id),
|
||||
@@ -169,8 +169,8 @@ export class ContestDetailHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
async get(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async get(domainId: string, tid: ObjectId) {
|
||||
this.response.template = 'contest_detail.html';
|
||||
const udict = await user.getList(domainId, [this.tdoc.owner]);
|
||||
this.response.body = {
|
||||
@@ -216,9 +216,9 @@ export class ContestDetailHandler extends Handler {
|
||||
];
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@param('code', Types.String, true)
|
||||
async postAttend(domainId: string, tid: ObjectID, code = '') {
|
||||
async postAttend(domainId: string, tid: ObjectId, code = '') {
|
||||
if (contest.isDone(this.tdoc)) throw new ContestNotLiveError(tid);
|
||||
if (this.tdoc._code && code !== this.tdoc._code) throw new InvalidTokenError('Contest Invitation', code);
|
||||
await contest.attend(domainId, tid, this.user._id);
|
||||
@@ -227,8 +227,8 @@ export class ContestDetailHandler extends Handler {
|
||||
}
|
||||
|
||||
export class ContestProblemListHandler extends ContestDetailBaseHandler {
|
||||
@param('tid', Types.ObjectID)
|
||||
async get(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async get(domainId: string, tid: ObjectId) {
|
||||
if (contest.isNotStarted(this.tdoc)) throw new ContestNotLiveError(domainId, tid);
|
||||
if (!this.tsdoc?.attend && !contest.isDone(this.tdoc)) throw new ContestNotAttendedError(domainId, tid);
|
||||
const [pdict, udict] = await Promise.all([
|
||||
@@ -260,9 +260,9 @@ export class ContestProblemListHandler extends ContestDetailBaseHandler {
|
||||
}
|
||||
|
||||
export class ContestScoreboardHandler extends ContestDetailBaseHandler {
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@param('ext', Types.Range(['csv', 'html', 'ghost']), true)
|
||||
async get(domainId: string, tid: ObjectID, ext = '') {
|
||||
async get(domainId: string, tid: ObjectId, ext = '') {
|
||||
if (!contest.canShowScoreboard.call(this, this.tdoc, true)) throw new ContestScoreboardHiddenError(tid);
|
||||
if (ext) {
|
||||
await this.exportScoreboard(domainId, tid, ext);
|
||||
@@ -279,7 +279,7 @@ export class ContestScoreboardHandler extends ContestDetailBaseHandler {
|
||||
};
|
||||
}
|
||||
|
||||
async exportGhost(domainId: string, tid: ObjectID) {
|
||||
async exportGhost(domainId: string, tid: ObjectId) {
|
||||
const tdoc = this.tdoc;
|
||||
const [pdict, teams] = await Promise.all([
|
||||
problem.getList(domainId, tdoc.pids, true, false, problem.PROJECTION_LIST, true),
|
||||
@@ -288,7 +288,7 @@ export class ContestScoreboardHandler extends ContestDetailBaseHandler {
|
||||
const udict = await user.getList(domainId, teams.map((i) => i.uid));
|
||||
const teamIds: Record<number, number> = {};
|
||||
for (let i = 1; i <= teams.length; i++) teamIds[teams[i - 1].uid] = i;
|
||||
const time = (t: ObjectID) => Math.floor((t.getTimestamp().getTime() - tdoc.beginAt.getTime()) / Time.second);
|
||||
const time = (t: ObjectId) => Math.floor((t.getTimestamp().getTime() - tdoc.beginAt.getTime()) / Time.second);
|
||||
const pid = (i: number) => String.fromCharCode(65 + i);
|
||||
const escape = (i: string) => i.replace(/[",]/g, '');
|
||||
const unknownSchool = this.translate('Unknown School');
|
||||
@@ -316,7 +316,7 @@ export class ContestScoreboardHandler extends ContestDetailBaseHandler {
|
||||
this.binary(res.join('\n'), `${this.tdoc.title}.ghost`);
|
||||
}
|
||||
|
||||
async exportScoreboard(domainId: string, tid: ObjectID, ext: string) {
|
||||
async exportScoreboard(domainId: string, tid: ObjectId, ext: string) {
|
||||
await this.limitRate('scoreboard_download', 60, 3);
|
||||
if (ext === 'ghost') {
|
||||
await this.exportGhost(domainId, tid);
|
||||
@@ -330,8 +330,8 @@ export class ContestScoreboardHandler extends ContestDetailBaseHandler {
|
||||
this.binary(await getContent[ext](rows, this.tdoc), `${this.tdoc.title}.${ext}`);
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
async postUnlock(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async postUnlock(domainId: string, tid: ObjectId) {
|
||||
if (!this.user.own(this.tdoc)) this.checkPerm(PERM.PERM_EDIT_CONTEST);
|
||||
if (!contest.isDone(this.tdoc)) throw new ContestNotEndedError(domainId, tid);
|
||||
await contest.unlockScoreboard(domainId, tid);
|
||||
@@ -342,8 +342,8 @@ export class ContestScoreboardHandler extends ContestDetailBaseHandler {
|
||||
export class ContestEditHandler extends Handler {
|
||||
tdoc: Tdoc;
|
||||
|
||||
@param('tid', Types.ObjectID, true)
|
||||
async prepare(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId, true)
|
||||
async prepare(domainId: string, tid: ObjectId) {
|
||||
if (tid) {
|
||||
this.tdoc = await contest.get(domainId, tid);
|
||||
if (!this.tdoc) throw new ContestNotFoundError(domainId, tid);
|
||||
@@ -353,8 +353,8 @@ export class ContestEditHandler extends Handler {
|
||||
} else this.checkPerm(PERM.PERM_CREATE_CONTEST);
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID, true)
|
||||
async get(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId, true)
|
||||
async get(domainId: string, tid: ObjectId) {
|
||||
this.response.template = 'contest_edit.html';
|
||||
const rules = {};
|
||||
for (const i in contest.RULES) {
|
||||
@@ -375,7 +375,7 @@ export class ContestEditHandler extends Handler {
|
||||
};
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID, true)
|
||||
@param('tid', Types.ObjectId, true)
|
||||
@param('beginAtDate', Types.Date)
|
||||
@param('beginAtTime', Types.Time)
|
||||
@param('duration', Types.Float)
|
||||
@@ -392,7 +392,7 @@ export class ContestEditHandler extends Handler {
|
||||
@param('maintainer', Types.NumericArray, true)
|
||||
@param('allowViewCode', Types.Boolean)
|
||||
async postUpdate(
|
||||
domainId: string, tid: ObjectID, beginAtDate: string, beginAtTime: string, duration: number,
|
||||
domainId: string, tid: ObjectId, beginAtDate: string, beginAtTime: string, duration: number,
|
||||
title: string, content: string, rule: string, _pids: string, rated = false,
|
||||
_code = '', autoHide = false, assign: string[] = null, lock: number = null,
|
||||
contestDuration: number = null, maintainer: number[] = [], allowViewCode = false,
|
||||
@@ -442,8 +442,8 @@ export class ContestEditHandler extends Handler {
|
||||
this.response.redirect = this.url('contest_detail', { tid });
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
async postDelete(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async postDelete(domainId: string, tid: ObjectId) {
|
||||
if (!this.user.own(this.tdoc)) this.checkPerm(PERM.PERM_EDIT_CONTEST);
|
||||
await contest.del(domainId, tid);
|
||||
await record.updateMulti(domainId, { domainId, contest: tid }, undefined, undefined, { contest: '' });
|
||||
@@ -461,9 +461,9 @@ export class ContestManagementBaseHandler extends ContestDetailBaseHandler {
|
||||
}
|
||||
|
||||
export class ContestCodeHandler extends Handler {
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@param('all', Types.Boolean)
|
||||
async get(domainId: string, tid: ObjectID, all: boolean) {
|
||||
async get(domainId: string, tid: ObjectId, all: boolean) {
|
||||
await this.limitRate('contest_code', 60, 10);
|
||||
const [tdoc, tsdocs] = await contest.getAndListStatus(domainId, tid);
|
||||
if (!this.user.own(tdoc) && !this.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE)) {
|
||||
@@ -490,7 +490,7 @@ export class ContestCodeHandler extends Handler {
|
||||
}
|
||||
const zip = new AdmZip();
|
||||
const rdocs = await record.getMulti(domainId, {
|
||||
_id: { $in: Array.from(Object.keys(rnames)).map((id) => new ObjectID(id)) },
|
||||
_id: { $in: Array.from(Object.keys(rnames)).map((id) => new ObjectId(id)) },
|
||||
}).toArray();
|
||||
await Promise.all(rdocs.map(async (rdoc) => {
|
||||
if (rdoc.files?.code) {
|
||||
@@ -509,8 +509,8 @@ export class ContestCodeHandler extends Handler {
|
||||
}
|
||||
|
||||
export class ContestManagementHandler extends ContestManagementBaseHandler {
|
||||
@param('tid', Types.ObjectID)
|
||||
async get(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async get(domainId: string, tid: ObjectId) {
|
||||
this.response.body = {
|
||||
tdoc: this.tdoc,
|
||||
tsdoc: this.tsdoc,
|
||||
@@ -523,9 +523,9 @@ export class ContestManagementHandler extends ContestManagementBaseHandler {
|
||||
this.response.template = 'contest_manage.html';
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@param('content', Types.Content)
|
||||
async postBroadcast(domainId: string, tid: ObjectID, content: string) {
|
||||
async postBroadcast(domainId: string, tid: ObjectId, content: string) {
|
||||
const tsdocs = await contest.getMultiStatus(domainId, { docId: tid }).toArray();
|
||||
const uids = Array.from<number>(new Set(tsdocs.map((tsdoc) => tsdoc.uid)));
|
||||
const flag = contest.isOngoing(this.tdoc) ? message.FLAG_ALERT : message.FLAG_UNREAD;
|
||||
@@ -533,9 +533,9 @@ export class ContestManagementHandler extends ContestManagementBaseHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@post('filename', Types.Filename, true)
|
||||
async postUploadFile(domainId: string, tid: ObjectID, filename: string) {
|
||||
async postUploadFile(domainId: string, tid: ObjectId, filename: string) {
|
||||
if ((this.tdoc.files?.length || 0) >= system.get('limit.contest_files')) {
|
||||
throw new FileLimitExceededError('count');
|
||||
}
|
||||
@@ -556,9 +556,9 @@ export class ContestManagementHandler extends ContestManagementBaseHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@post('files', Types.ArrayOf(Types.Filename))
|
||||
async postDeleteFiles(domainId: string, tid: ObjectID, files: string[]) {
|
||||
async postDeleteFiles(domainId: string, tid: ObjectId, files: string[]) {
|
||||
await Promise.all([
|
||||
storage.del(files.map((t) => `contest/${domainId}/${tid}/${t}`), this.user._id),
|
||||
contest.edit(domainId, tid, { files: this.tdoc.files.filter((i) => !files.includes(i.name)) }),
|
||||
@@ -568,10 +568,10 @@ export class ContestManagementHandler extends ContestManagementBaseHandler {
|
||||
}
|
||||
|
||||
export class ContestFileDownloadHandler extends ContestDetailBaseHandler {
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@param('filename', Types.Filename)
|
||||
@param('noDisposition', Types.Boolean)
|
||||
async get(domainId: string, tid: ObjectID, filename: string, noDisposition = false) {
|
||||
async get(domainId: string, tid: ObjectId, filename: string, noDisposition = false) {
|
||||
this.response.addHeader('Cache-Control', 'public');
|
||||
const target = `contest/${domainId}/${tid}/${filename}`;
|
||||
const file = await storage.getMeta(target);
|
||||
@@ -586,8 +586,8 @@ export class ContestFileDownloadHandler extends ContestDetailBaseHandler {
|
||||
}
|
||||
|
||||
export class ContestUserHandler extends ContestManagementBaseHandler {
|
||||
@param('tid', Types.ObjectID)
|
||||
async get(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async get(domainId: string, tid: ObjectId) {
|
||||
const tsdocs = await contest.getMultiStatus(domainId, { docId: tid }).toArray();
|
||||
tsdocs.forEach((i) => {
|
||||
i.endAt = this.tdoc.duration ? moment(this.tsdoc.startAt).add(this.tdoc.duration, 'hours').toDate() : null;
|
||||
@@ -598,17 +598,17 @@ export class ContestUserHandler extends ContestManagementBaseHandler {
|
||||
this.response.template = 'contest_user.html';
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@param('uids', Types.NumericArray)
|
||||
@param('unrank', Types.Boolean)
|
||||
async postAddUser(domainId: string, tid: ObjectID, uids: number[], unrank = false) {
|
||||
async postAddUser(domainId: string, tid: ObjectId, uids: number[], unrank = false) {
|
||||
await Promise.all(uids.map((uid) => contest.attend(domainId, tid, uid, { unrank })));
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@param('uid', Types.PositiveInt)
|
||||
async postRank(domainId: string, tid: ObjectID, uid: number) {
|
||||
async postRank(domainId: string, tid: ObjectId, uid: number) {
|
||||
const tsdoc = await contest.getStatus(domainId, tid, uid);
|
||||
if (!tsdoc) throw new ContestNotAttendedError(uid);
|
||||
await contest.setStatus(domainId, tid, uid, { unrank: !tsdoc.unrank });
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { isSafeInteger } from 'lodash';
|
||||
import { ObjectID } from 'mongodb';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import {
|
||||
DiscussionLockedError, DiscussionNotFoundError, DocumentNotFoundError,
|
||||
PermissionError,
|
||||
@@ -31,12 +31,12 @@ class DiscussionHandler extends Handler {
|
||||
|
||||
@param('type', Types.Range(Object.keys(typeMapper)), true)
|
||||
@param('name', Types.Name, true)
|
||||
@param('did', Types.ObjectID, true)
|
||||
@param('drid', Types.ObjectID, true)
|
||||
@param('drrid', Types.ObjectID, true)
|
||||
@param('did', Types.ObjectId, true)
|
||||
@param('drid', Types.ObjectId, true)
|
||||
@param('drrid', Types.ObjectId, true)
|
||||
async _prepare(
|
||||
domainId: string, type: string, name: string,
|
||||
did: ObjectID, drid: ObjectID, drrid: ObjectID,
|
||||
did: ObjectId, drid: ObjectId, drrid: ObjectId,
|
||||
) {
|
||||
this.checkPerm(PERM.PERM_VIEW_DISCUSSION);
|
||||
if (did) {
|
||||
@@ -98,8 +98,8 @@ class DiscussionNodeHandler extends DiscussionHandler {
|
||||
@param('name', Types.Name)
|
||||
@param('page', Types.PositiveInt, true)
|
||||
async get(domainId: string, type: string, _name: string, page = 1) {
|
||||
let name: ObjectID | string | number;
|
||||
if (ObjectID.isValid(_name)) name = new ObjectID(_name);
|
||||
let name: ObjectId | string | number;
|
||||
if (ObjectId.isValid(_name)) name = new ObjectId(_name);
|
||||
else if (isSafeInteger(parseInt(_name, 10))) name = parseInt(_name, 10);
|
||||
else name = _name;
|
||||
const [ddocs, dpcount] = await paginate(
|
||||
@@ -162,9 +162,9 @@ class DiscussionCreateHandler extends DiscussionHandler {
|
||||
}
|
||||
|
||||
class DiscussionDetailHandler extends DiscussionHandler {
|
||||
@param('did', Types.ObjectID)
|
||||
@param('did', Types.ObjectId)
|
||||
@param('page', Types.PositiveInt, true)
|
||||
async get(domainId: string, did: ObjectID, page = 1) {
|
||||
async get(domainId: string, did: ObjectId, page = 1) {
|
||||
const dsdoc = this.user.hasPriv(PRIV.PRIV_USER_PROFILE)
|
||||
? await discussion.getStatus(domainId, did, this.user._id)
|
||||
: null;
|
||||
@@ -208,19 +208,19 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
this.checkPriv(PRIV.PRIV_USER_PROFILE);
|
||||
}
|
||||
|
||||
@param('did', Types.ObjectID)
|
||||
@param('did', Types.ObjectId)
|
||||
@param('lock', Types.Boolean)
|
||||
async postSetLock(domainId: string, did: ObjectID, lock: boolean) {
|
||||
async postSetLock(domainId: string, did: ObjectId, lock: boolean) {
|
||||
if (!this.user.own(this.ddoc)) this.checkPerm(PERM.PERM_LOCK_DISCUSSION);
|
||||
await discussion.edit(domainId, did, { lock });
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('type', Types.Range(['did', 'drid']))
|
||||
@param('id', Types.ObjectID)
|
||||
@param('id', Types.ObjectId)
|
||||
@param('emoji', Types.Emoji)
|
||||
@param('reverse', Types.Boolean)
|
||||
async postReaction(domainId: string, type: string, did: ObjectID, id: string, reverse = false) {
|
||||
async postReaction(domainId: string, type: string, did: ObjectId, id: string, reverse = false) {
|
||||
this.checkPerm(PERM.PERM_ADD_REACTION);
|
||||
const docType = type === 'did' ? document.TYPE_DISCUSSION : document.TYPE_DISCUSSION_REPLY;
|
||||
const [doc, sdoc] = await discussion.react(domainId, docType, did, id, this.user._id, reverse);
|
||||
@@ -228,9 +228,9 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('did', Types.ObjectID)
|
||||
@param('did', Types.ObjectId)
|
||||
@param('content', Types.Content)
|
||||
async postReply(domainId: string, did: ObjectID, content: string) {
|
||||
async postReply(domainId: string, did: ObjectId, content: string) {
|
||||
this.checkPerm(PERM.PERM_REPLY_DISCUSSION);
|
||||
if (this.ddoc.lock) throw new DiscussionLockedError(domainId, did);
|
||||
await this.limitRate('add_discussion', 3600, 60);
|
||||
@@ -247,9 +247,9 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
this.back({ drid });
|
||||
}
|
||||
|
||||
@param('drid', Types.ObjectID)
|
||||
@param('drid', Types.ObjectId)
|
||||
@param('content', Types.Content)
|
||||
async postTailReply(domainId: string, drid: ObjectID, content: string) {
|
||||
async postTailReply(domainId: string, drid: ObjectId, content: string) {
|
||||
this.checkPerm(PERM.PERM_REPLY_DISCUSSION);
|
||||
if (this.ddoc.lock) throw new DiscussionLockedError(domainId, this.ddoc.docId);
|
||||
await this.limitRate('add_discussion', 3600, 60);
|
||||
@@ -266,9 +266,9 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('drid', Types.ObjectID)
|
||||
@param('drid', Types.ObjectId)
|
||||
@param('content', Types.Content)
|
||||
async postEditReply(domainId: string, drid: ObjectID, content: string) {
|
||||
async postEditReply(domainId: string, drid: ObjectId, content: string) {
|
||||
this.checkPerm(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF);
|
||||
if (!this.user.own(this.drdoc)) throw new PermissionError(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF);
|
||||
await Promise.all([
|
||||
@@ -278,8 +278,8 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('drid', Types.ObjectID)
|
||||
async postDeleteReply(domainId: string, drid: ObjectID) {
|
||||
@param('drid', Types.ObjectId)
|
||||
async postDeleteReply(domainId: string, drid: ObjectId) {
|
||||
const deleteBy = this.user.own(this.drdoc) ? 'self' : this.user.own(this.ddoc) ? 'DiscussionOwner' : 'Admin';
|
||||
if (!(this.user.own(this.ddoc)
|
||||
&& this.user.hasPerm(PERM.PERM_DELETE_DISCUSSION_REPLY_SELF_DISCUSSION))) {
|
||||
@@ -305,10 +305,10 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('drid', Types.ObjectID)
|
||||
@param('drrid', Types.ObjectID)
|
||||
@param('drid', Types.ObjectId)
|
||||
@param('drrid', Types.ObjectId)
|
||||
@param('content', Types.Content)
|
||||
async postEditTailReply(domainId: string, drid: ObjectID, drrid: ObjectID, content: string) {
|
||||
async postEditTailReply(domainId: string, drid: ObjectId, drrid: ObjectId, content: string) {
|
||||
this.checkPerm(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF);
|
||||
if (!this.user.own(this.drrdoc)) throw new PermissionError(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF);
|
||||
await Promise.all([
|
||||
@@ -318,9 +318,9 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('drid', Types.ObjectID)
|
||||
@param('drrid', Types.ObjectID)
|
||||
async postDeleteTailReply(domainId: string, drid: ObjectID, drrid: ObjectID) {
|
||||
@param('drid', Types.ObjectId)
|
||||
@param('drrid', Types.ObjectId)
|
||||
async postDeleteTailReply(domainId: string, drid: ObjectId, drrid: ObjectId) {
|
||||
const deleteBy = this.user.own(this.drrdoc) ? 'self' : 'Admin';
|
||||
if (!this.user.own(this.drrdoc)) this.checkPerm(PERM.PERM_DELETE_DISCUSSION_REPLY);
|
||||
const msg = JSON.stringify({
|
||||
@@ -340,26 +340,26 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('did', Types.ObjectID)
|
||||
async postStar(domainId: string, did: ObjectID) {
|
||||
@param('did', Types.ObjectId)
|
||||
async postStar(domainId: string, did: ObjectId) {
|
||||
await discussion.setStar(domainId, did, this.user._id, true);
|
||||
this.back({ star: true });
|
||||
}
|
||||
|
||||
@param('did', Types.ObjectID)
|
||||
async postUnstar(domainId: string, did: ObjectID) {
|
||||
@param('did', Types.ObjectId)
|
||||
async postUnstar(domainId: string, did: ObjectId) {
|
||||
await discussion.setStar(domainId, did, this.user._id, false);
|
||||
this.back({ star: false });
|
||||
}
|
||||
}
|
||||
|
||||
class DiscussionRawHandler extends DiscussionHandler {
|
||||
@param('did', Types.ObjectID, true)
|
||||
@param('drid', Types.ObjectID, true)
|
||||
@param('drrid', Types.ObjectID, true)
|
||||
@param('did', Types.ObjectId, true)
|
||||
@param('drid', Types.ObjectId, true)
|
||||
@param('drrid', Types.ObjectId, true)
|
||||
@param('time', Types.UnsignedInt, true)
|
||||
@param('all', Types.Boolean)
|
||||
async get(domainId: string, did: ObjectID, drid: ObjectID, drrid: ObjectID, ts: number, all = false) {
|
||||
async get(domainId: string, did: ObjectId, drid: ObjectId, drrid: ObjectId, ts: number, all = false) {
|
||||
if (all) {
|
||||
this.response.body.history = await discussion.getHistory(domainId, drrid || drid || did);
|
||||
} else {
|
||||
@@ -384,13 +384,13 @@ class DiscussionEditHandler extends DiscussionHandler {
|
||||
this.response.body = { ddoc: this.ddoc, path };
|
||||
}
|
||||
|
||||
@param('did', Types.ObjectID)
|
||||
@param('did', Types.ObjectId)
|
||||
@param('title', Types.Title)
|
||||
@param('content', Types.Content)
|
||||
@param('highlight', Types.Boolean)
|
||||
@param('pin', Types.Boolean)
|
||||
async postUpdate(
|
||||
domainId: string, did: ObjectID, title: string, content: string,
|
||||
domainId: string, did: ObjectId, title: string, content: string,
|
||||
highlight = false, pin = false,
|
||||
) {
|
||||
if (!this.user.own(this.ddoc)) this.checkPerm(PERM.PERM_EDIT_DISCUSSION);
|
||||
@@ -407,8 +407,8 @@ class DiscussionEditHandler extends DiscussionHandler {
|
||||
this.response.redirect = this.url('discussion_detail', { did });
|
||||
}
|
||||
|
||||
@param('did', Types.ObjectID)
|
||||
async postDelete(domainId: string, did: ObjectID) {
|
||||
@param('did', Types.ObjectId)
|
||||
async postDelete(domainId: string, did: ObjectId) {
|
||||
const deleteBy = this.user.own(this.ddoc) ? 'self' : 'Admin';
|
||||
if (!this.user.own(this.ddoc)) this.checkPerm(PERM.PERM_DELETE_DISCUSSION);
|
||||
else this.checkPerm(PERM.PERM_DELETE_DISCUSSION_SELF);
|
||||
|
||||
@@ -2,7 +2,7 @@ import path from 'path';
|
||||
import { generateRegistrationOptions, verifyRegistrationResponse } from '@simplewebauthn/server';
|
||||
import yaml from 'js-yaml';
|
||||
import { pick } from 'lodash';
|
||||
import { Binary, ObjectID } from 'mongodb';
|
||||
import { Binary, ObjectId } from 'mongodb';
|
||||
import { Context } from '../context';
|
||||
import {
|
||||
AuthOperationError, BlacklistedError, DomainAlreadyExistsError, InvalidTokenError,
|
||||
@@ -293,7 +293,7 @@ class HomeSecurityHandler extends Handler {
|
||||
@requireSudo
|
||||
@param('id', Types.String)
|
||||
async postDisableAuthn(domainId: string, id: string) {
|
||||
const authenticators = this.user._authenticators?.filter((c) => c.credentialID.buffer.toString('base64') !== id);
|
||||
const authenticators = this.user._authenticators?.filter((c) => Buffer.from(c.credentialID.buffer).toString('base64') !== id);
|
||||
if (this.user._authenticators?.length === authenticators?.length) throw new ValidationError('authenticator');
|
||||
await user.setById(this.user._id, { authenticators });
|
||||
this.back();
|
||||
@@ -498,16 +498,16 @@ class HomeMessagesHandler extends Handler {
|
||||
this.back({ mdoc, udoc });
|
||||
}
|
||||
|
||||
@param('messageId', Types.ObjectID)
|
||||
async postDeleteMessage(domainId: string, messageId: ObjectID) {
|
||||
@param('messageId', Types.ObjectId)
|
||||
async postDeleteMessage(domainId: string, messageId: ObjectId) {
|
||||
const msg = await message.get(messageId);
|
||||
if ([msg.from, msg.to].includes(this.user._id)) await message.del(messageId);
|
||||
else throw new PermissionError();
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('messageId', Types.ObjectID)
|
||||
async postRead(domainId: string, messageId: ObjectID) {
|
||||
@param('messageId', Types.ObjectId)
|
||||
async postRead(domainId: string, messageId: ObjectId) {
|
||||
const msg = await message.get(messageId);
|
||||
if ([msg.from, msg.to].includes(this.user._id)) {
|
||||
await message.setFlag(messageId, message.FLAG_UNREAD);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import yaml from 'js-yaml';
|
||||
import moment from 'moment-timezone';
|
||||
import { ObjectID } from 'mongodb';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import { Time } from '@hydrooj/utils/lib/utils';
|
||||
import {
|
||||
ContestNotFoundError, HomeworkNotLiveError, NotAssignedError, ValidationError,
|
||||
@@ -42,8 +42,8 @@ class HomeworkMainHandler extends Handler {
|
||||
}
|
||||
|
||||
class HomeworkDetailHandler extends Handler {
|
||||
@param('tid', Types.ObjectID)
|
||||
async prepare(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async prepare(domainId: string, tid: ObjectId) {
|
||||
const tdoc = await contest.get(domainId, tid);
|
||||
if (tdoc.rule !== 'homework') throw new ContestNotFoundError(domainId, tid);
|
||||
if (tdoc.assign?.length && !this.user.own(tdoc)) {
|
||||
@@ -53,9 +53,9 @@ class HomeworkDetailHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@param('page', Types.PositiveInt, true)
|
||||
async get(domainId: string, tid: ObjectID, page = 1) {
|
||||
async get(domainId: string, tid: ObjectId, page = 1) {
|
||||
const [tdoc, tsdoc] = await Promise.all([
|
||||
contest.get(domainId, tid),
|
||||
contest.getStatus(domainId, tid, this.user._id),
|
||||
@@ -101,8 +101,8 @@ class HomeworkDetailHandler extends Handler {
|
||||
Object.assign(this.response.body, { pdict, psdict, rdict });
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
async postAttend(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async postAttend(domainId: string, tid: ObjectId) {
|
||||
this.checkPerm(PERM.PERM_ATTEND_HOMEWORK);
|
||||
const tdoc = await contest.get(domainId, tid);
|
||||
if (contest.isDone(tdoc)) throw new HomeworkNotLiveError(tdoc.docId);
|
||||
@@ -112,8 +112,8 @@ class HomeworkDetailHandler extends Handler {
|
||||
}
|
||||
|
||||
class HomeworkEditHandler extends Handler {
|
||||
@param('tid', Types.ObjectID, true)
|
||||
async get(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId, true)
|
||||
async get(domainId: string, tid: ObjectId) {
|
||||
const tdoc = tid ? await contest.get(domainId, tid) : null;
|
||||
if (!tid) this.checkPerm(PERM.PERM_CREATE_HOMEWORK);
|
||||
else if (!this.user.own(tdoc)) this.checkPerm(PERM.PERM_EDIT_HOMEWORK);
|
||||
@@ -143,7 +143,7 @@ class HomeworkEditHandler extends Handler {
|
||||
};
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID, true)
|
||||
@param('tid', Types.ObjectId, true)
|
||||
@param('beginAtDate', Types.Date)
|
||||
@param('beginAtTime', Types.Time)
|
||||
@param('penaltySinceDate', Types.Date)
|
||||
@@ -157,7 +157,7 @@ class HomeworkEditHandler extends Handler {
|
||||
@param('maintainer', Types.NumericArray, true)
|
||||
@param('assign', Types.CommaSeperatedArray, true)
|
||||
async postUpdate(
|
||||
domainId: string, tid: ObjectID, beginAtDate: string, beginAtTime: string,
|
||||
domainId: string, tid: ObjectId, beginAtDate: string, beginAtTime: string,
|
||||
penaltySinceDate: string, penaltySinceTime: string, extensionDays: number,
|
||||
penaltyRules: PenaltyRules, title: string, content: string, _pids: string, rated = false,
|
||||
maintainer: number[] = [], assign: string[] = [],
|
||||
@@ -203,8 +203,8 @@ class HomeworkEditHandler extends Handler {
|
||||
this.response.redirect = this.url('homework_detail', { tid });
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
async postDelete(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async postDelete(domainId: string, tid: ObjectId) {
|
||||
const tdoc = await contest.get(domainId, tid);
|
||||
if (!this.user.own(tdoc)) this.checkPerm(PERM.PERM_EDIT_HOMEWORK);
|
||||
await contest.del(domainId, tid);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import assert from 'assert';
|
||||
import yaml from 'js-yaml';
|
||||
import { omit } from 'lodash';
|
||||
import { ObjectID } from 'mongodb';
|
||||
import { ObjectId } from 'mongodb';
|
||||
import {
|
||||
JudgeResultBody, ProblemConfigFile, RecordDoc, TestCase,
|
||||
} from '../interface';
|
||||
@@ -63,7 +63,7 @@ function processPayload(rdoc: RecordDoc, body: Partial<JudgeResultBody>) {
|
||||
}
|
||||
|
||||
export async function next(body: Partial<JudgeResultBody>) {
|
||||
body.rid = new ObjectID(body.rid);
|
||||
body.rid = new ObjectId(body.rid);
|
||||
let rdoc = await record.get(body.rid);
|
||||
if (!rdoc) return;
|
||||
const { $set, $push } = processPayload(rdoc, body);
|
||||
@@ -113,7 +113,7 @@ export async function postJudge(rdoc: RecordDoc) {
|
||||
const rdocs = await record.getMulti(rdoc.domainId, {
|
||||
pid: rdoc.pid,
|
||||
status: STATUS.STATUS_ACCEPTED,
|
||||
contest: { $ne: new ObjectID('0'.repeat(24)) },
|
||||
contest: { $ne: new ObjectId('0'.repeat(24)) },
|
||||
}).project({ _id: 1, contest: 1 }).toArray();
|
||||
const priority = await record.submissionPriority(rdoc.uid, -5000 - rdocs.length * 5 - 50);
|
||||
await record.judge(rdoc.domainId, rdocs.map((r) => r._id), priority, {}, { hackRejudge: input });
|
||||
@@ -128,7 +128,7 @@ export async function postJudge(rdoc: RecordDoc) {
|
||||
}
|
||||
|
||||
export async function end(body: Partial<JudgeResultBody>) {
|
||||
body.rid &&= new ObjectID(body.rid);
|
||||
body.rid &&= new ObjectId(body.rid);
|
||||
let rdoc = await record.get(body.rid);
|
||||
if (!rdoc) return;
|
||||
const { $set, $push } = processPayload(rdoc, body);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { readFile, statSync } from 'fs-extra';
|
||||
import {
|
||||
escapeRegExp, flattenDeep, intersection, pick, uniqBy,
|
||||
} from 'lodash';
|
||||
import { FilterQuery, ObjectID } from 'mongodb';
|
||||
import { Filter, ObjectId } from 'mongodb';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { sortFiles, streamToBuffer } from '@hydrooj/utils/lib/utils';
|
||||
import {
|
||||
@@ -101,7 +101,7 @@ registerResolver(
|
||||
);
|
||||
|
||||
function buildQuery(udoc: User) {
|
||||
const q: FilterQuery<ProblemDoc> = {};
|
||||
const q: Filter<ProblemDoc> = {};
|
||||
if (!udoc.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN)) {
|
||||
q.$or = [
|
||||
{ hidden: false },
|
||||
@@ -309,8 +309,8 @@ export class ProblemDetailHandler extends ContestDetailBaseHandler {
|
||||
psdoc: ProblemStatusDoc;
|
||||
|
||||
@route('pid', Types.ProblemId, true)
|
||||
@query('tid', Types.ObjectID, true)
|
||||
async _prepare(domainId: string, pid: number | string, tid?: ObjectID) {
|
||||
@query('tid', Types.ObjectId, true)
|
||||
async _prepare(domainId: string, pid: number | string, tid?: ObjectId) {
|
||||
this.pdoc = await problem.get(domainId, pid);
|
||||
if (!this.pdoc) throw new ProblemNotFoundError(domainId, pid);
|
||||
if (tid) {
|
||||
@@ -375,7 +375,7 @@ export class ProblemDetailHandler extends ContestDetailBaseHandler {
|
||||
this.UiContext.extraTitleContent = this.pdoc.title;
|
||||
}
|
||||
|
||||
@query('tid', Types.ObjectID, true)
|
||||
@query('tid', Types.ObjectId, true)
|
||||
@query('pjax', Types.Boolean)
|
||||
async get(...args: any[]) {
|
||||
// Navigate to current additional file download
|
||||
@@ -433,7 +433,7 @@ export class ProblemDetailHandler extends ContestDetailBaseHandler {
|
||||
this.checkPerm(PERM.PERM_REJUDGE_PROBLEM);
|
||||
const rdocs = await record.getMulti(domainId, {
|
||||
pid,
|
||||
contest: { $ne: new ObjectID('0'.repeat(24)) },
|
||||
contest: { $ne: new ObjectId('0'.repeat(24)) },
|
||||
status: { $ne: STATUS.STATUS_CANCELED },
|
||||
'files.hack': { $exists: false },
|
||||
}).project({ _id: 1, contest: 1 }).toArray();
|
||||
@@ -469,8 +469,8 @@ export class ProblemDetailHandler extends ContestDetailBaseHandler {
|
||||
}
|
||||
|
||||
export class ProblemSubmitHandler extends ProblemDetailHandler {
|
||||
@param('tid', Types.ObjectID, true)
|
||||
async prepare(domainId: string, tid?: ObjectID) {
|
||||
@param('tid', Types.ObjectId, true)
|
||||
async prepare(domainId: string, tid?: ObjectId) {
|
||||
if (tid && !contest.isOngoing(this.tdoc, this.tsdoc)) throw new ContestNotLiveError(this.tdoc.docId);
|
||||
if (typeof this.pdoc.config === 'string') throw new ProblemConfigError();
|
||||
}
|
||||
@@ -497,8 +497,8 @@ export class ProblemSubmitHandler extends ProblemDetailHandler {
|
||||
@param('code', Types.Content, true)
|
||||
@param('pretest', Types.Boolean)
|
||||
@param('input', Types.String, true)
|
||||
@param('tid', Types.ObjectID, true)
|
||||
async post(domainId: string, lang: string, code: string, pretest = false, input = '', tid?: ObjectID) {
|
||||
@param('tid', Types.ObjectId, true)
|
||||
async post(domainId: string, lang: string, code: string, pretest = false, input = '', tid?: ObjectId) {
|
||||
const config = this.pdoc.config;
|
||||
if (typeof config === 'string' || config === null) throw new ProblemConfigError();
|
||||
if (['submit_answer', 'objective'].includes(config.type)) {
|
||||
@@ -558,9 +558,9 @@ export class ProblemSubmitHandler extends ProblemDetailHandler {
|
||||
export class ProblemHackHandler extends ProblemDetailHandler {
|
||||
rdoc: RecordDoc;
|
||||
|
||||
@param('rid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectID, true)
|
||||
async prepare(domainId: string, rid: ObjectID, tid?: ObjectID) {
|
||||
@param('rid', Types.ObjectId)
|
||||
@param('tid', Types.ObjectId, true)
|
||||
async prepare(domainId: string, rid: ObjectId, tid?: ObjectId) {
|
||||
if (typeof this.pdoc.config !== 'object' || !this.pdoc.config.hackable) throw new HackFailedError('This problem is not hackable.');
|
||||
this.rdoc = await record.get(domainId, rid);
|
||||
if (!this.rdoc || this.rdoc.pid !== this.pdoc.docId
|
||||
@@ -586,8 +586,8 @@ export class ProblemHackHandler extends ProblemDetailHandler {
|
||||
}
|
||||
|
||||
@param('input', Types.String, true)
|
||||
@param('tid', Types.ObjectID, true)
|
||||
async post(domainId: string, input = '', tid?: ObjectID) {
|
||||
@param('tid', Types.ObjectId, true)
|
||||
async post(domainId: string, input = '', tid?: ObjectId) {
|
||||
await this.limitRate('add_record', 60, system.get('limit.submission_user'), true);
|
||||
await this.limitRate('add_record', 60, system.get('limit.submission'), false);
|
||||
const id = `${this.user._id}/${nanoid()}`;
|
||||
@@ -814,9 +814,9 @@ export class ProblemFileDownloadHandler extends ProblemDetailHandler {
|
||||
|
||||
export class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
@param('page', Types.PositiveInt, true)
|
||||
@param('tid', Types.ObjectID, true)
|
||||
@param('sid', Types.ObjectID, true)
|
||||
async get(domainId: string, page = 1, tid?: ObjectID, sid?: ObjectID) {
|
||||
@param('tid', Types.ObjectId, true)
|
||||
@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;
|
||||
@@ -857,8 +857,8 @@ export class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
}
|
||||
|
||||
@param('content', Types.Content)
|
||||
@param('psid', Types.ObjectID)
|
||||
async postEditSolution(domainId: string, content: string, psid: ObjectID) {
|
||||
@param('psid', Types.ObjectId)
|
||||
async postEditSolution(domainId: string, content: string, psid: ObjectId) {
|
||||
let psdoc = await solution.get(domainId, psid);
|
||||
if (!this.user.own(psdoc)) this.checkPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION);
|
||||
else this.checkPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION_SELF);
|
||||
@@ -866,8 +866,8 @@ export class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
this.back({ psdoc });
|
||||
}
|
||||
|
||||
@param('psid', Types.ObjectID)
|
||||
async postDeleteSolution(domainId: string, psid: ObjectID) {
|
||||
@param('psid', Types.ObjectId)
|
||||
async postDeleteSolution(domainId: string, psid: ObjectId) {
|
||||
const psdoc = await solution.get(domainId, psid);
|
||||
if (!this.user.own(psdoc)) this.checkPerm(PERM.PERM_DELETE_PROBLEM_SOLUTION);
|
||||
else this.checkPerm(PERM.PERM_DELETE_PROBLEM_SOLUTION_SELF);
|
||||
@@ -875,19 +875,19 @@ export class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('psid', Types.ObjectID)
|
||||
@param('psid', Types.ObjectId)
|
||||
@param('content', Types.Content)
|
||||
async postReply(domainId: string, psid: ObjectID, content: string) {
|
||||
async postReply(domainId: string, psid: ObjectId, content: string) {
|
||||
this.checkPerm(PERM.PERM_REPLY_PROBLEM_SOLUTION);
|
||||
const psdoc = await solution.get(domainId, psid);
|
||||
await solution.reply(domainId, psdoc.docId, this.user._id, content);
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('psid', Types.ObjectID)
|
||||
@param('psrid', Types.ObjectID)
|
||||
@param('psid', Types.ObjectId)
|
||||
@param('psrid', Types.ObjectId)
|
||||
@param('content', Types.Content)
|
||||
async postEditReply(domainId: string, psid: ObjectID, psrid: ObjectID, content: string) {
|
||||
async postEditReply(domainId: string, psid: ObjectId, psrid: ObjectId, content: string) {
|
||||
const [psdoc, psrdoc] = await solution.getReply(domainId, psid, psrid);
|
||||
if ((!psdoc) || psdoc.parentId !== this.pdoc.docId) throw new SolutionNotFoundError(domainId, psid);
|
||||
if (!(this.user.own(psrdoc)
|
||||
@@ -898,9 +898,9 @@ export class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('psid', Types.ObjectID)
|
||||
@param('psrid', Types.ObjectID)
|
||||
async postDeleteReply(domainId: string, psid: ObjectID, psrid: ObjectID) {
|
||||
@param('psid', Types.ObjectId)
|
||||
@param('psrid', Types.ObjectId)
|
||||
async postDeleteReply(domainId: string, psid: ObjectId, psrid: ObjectId) {
|
||||
const [psdoc, psrdoc] = await solution.getReply(domainId, psid, psrid);
|
||||
if ((!psdoc) || psdoc.parentId !== this.pdoc.docId) throw new SolutionNotFoundError(psid);
|
||||
if (!(this.user.own(psrdoc)
|
||||
@@ -911,24 +911,24 @@ export class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('psid', Types.ObjectID)
|
||||
async postUpvote(domainId: string, psid: ObjectID) {
|
||||
@param('psid', Types.ObjectId)
|
||||
async postUpvote(domainId: string, psid: ObjectId) {
|
||||
const [psdoc, pssdoc] = await solution.vote(domainId, psid, this.user._id, 1);
|
||||
this.back({ vote: psdoc.vote, user_vote: pssdoc.vote });
|
||||
}
|
||||
|
||||
@param('psid', Types.ObjectID)
|
||||
async postDownvote(domainId: string, psid: ObjectID) {
|
||||
@param('psid', Types.ObjectId)
|
||||
async postDownvote(domainId: string, psid: ObjectId) {
|
||||
const [psdoc, pssdoc] = await solution.vote(domainId, psid, this.user._id, -1);
|
||||
this.back({ vote: psdoc.vote, user_vote: pssdoc.vote });
|
||||
}
|
||||
}
|
||||
|
||||
export class ProblemSolutionRawHandler extends ProblemDetailHandler {
|
||||
@param('psid', Types.ObjectID)
|
||||
@route('psrid', Types.ObjectID, true)
|
||||
@param('tid', Types.ObjectID, true)
|
||||
async get(domainId: string, psid: ObjectID, psrid?: ObjectID, tid?: ObjectID) {
|
||||
@param('psid', Types.ObjectId)
|
||||
@route('psrid', Types.ObjectId, true)
|
||||
@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);
|
||||
const accepted = this.tsdoc?.status === STATUS.STATUS_ACCEPTED;
|
||||
if (!accepted || !this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION_ACCEPT)) {
|
||||
@@ -1001,7 +1001,7 @@ export class ProblemPrefixListHandler extends Handler {
|
||||
const search = global.Hydro.lib.problemSearch || defaultSearch;
|
||||
const result = await search(domainId, prefix, { limit: 20 - pdocs.length });
|
||||
const docs = await problem.getMulti(domainId, { docId: { $in: result.hits.map((i) => +i.split('/')[1]) } })
|
||||
.project(buildProjection(projection)).toArray();
|
||||
.project<ProblemDoc>(buildProjection(projection)).toArray();
|
||||
pdocs.push(...docs);
|
||||
}
|
||||
this.response.body = uniqBy(pdocs, 'docId');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
omit, pick, throttle, uniqBy,
|
||||
} from 'lodash';
|
||||
import { FilterQuery, ObjectID } from 'mongodb';
|
||||
import { Filter, ObjectId } from 'mongodb';
|
||||
import {
|
||||
ContestNotAttendedError, ContestNotFoundError, HackRejudgeFailedError,
|
||||
PermissionError, ProblemConfigError,
|
||||
@@ -29,14 +29,14 @@ class RecordListHandler extends ContestDetailBaseHandler {
|
||||
|
||||
@param('page', Types.PositiveInt, true)
|
||||
@param('pid', Types.ProblemId, true)
|
||||
@param('tid', Types.ObjectID, true)
|
||||
@param('tid', Types.ObjectId, true)
|
||||
@param('uidOrName', Types.UidOrName, true)
|
||||
@param('lang', Types.String, true)
|
||||
@param('status', Types.Int, true)
|
||||
@param('fullStatus', Types.Boolean)
|
||||
@param('allDomain', Types.Boolean)
|
||||
async get(
|
||||
domainId: string, page = 1, pid?: string | number, tid?: ObjectID,
|
||||
domainId: string, page = 1, pid?: string | number, tid?: ObjectId,
|
||||
uidOrName?: string, lang?: string, status?: number, full = false,
|
||||
all = false,
|
||||
) {
|
||||
@@ -44,7 +44,7 @@ class RecordListHandler extends ContestDetailBaseHandler {
|
||||
let tdoc = null;
|
||||
let invalid = false;
|
||||
this.response.template = 'record_main.html';
|
||||
const q: FilterQuery<RecordDoc> = { contest: tid };
|
||||
const q: Filter<RecordDoc> = { contest: tid };
|
||||
if (full) uidOrName = this.user._id.toString();
|
||||
if (tid) {
|
||||
tdoc = await contest.get(domainId, tid);
|
||||
@@ -120,8 +120,8 @@ class RecordDetailHandler extends ContestDetailBaseHandler {
|
||||
rdoc: RecordDoc;
|
||||
tdoc?: Tdoc<30>;
|
||||
|
||||
@param('rid', Types.ObjectID)
|
||||
async prepare(domainId: string, rid: ObjectID) {
|
||||
@param('rid', Types.ObjectId)
|
||||
async prepare(domainId: string, rid: ObjectId) {
|
||||
this.rdoc = await record.get(domainId, rid);
|
||||
if (!this.rdoc) throw new RecordNotFoundError(rid);
|
||||
}
|
||||
@@ -140,10 +140,10 @@ class RecordDetailHandler extends ContestDetailBaseHandler {
|
||||
this.response.disposition = `attachment; filename="${langs[lang]?.code_file || `foo.${this.rdoc.lang}`}"`;
|
||||
}
|
||||
|
||||
@param('rid', Types.ObjectID)
|
||||
@param('rid', Types.ObjectId)
|
||||
@param('download', Types.Boolean)
|
||||
// eslint-disable-next-line consistent-return
|
||||
async get(domainId: string, rid: ObjectID, download = false) {
|
||||
async get(domainId: string, rid: ObjectId, download = false) {
|
||||
const rdoc = this.rdoc;
|
||||
let canViewDetail = true;
|
||||
if (rdoc.contest?.toString() === '000000000000000000000000') {
|
||||
@@ -187,14 +187,14 @@ class RecordDetailHandler extends ContestDetailBaseHandler {
|
||||
};
|
||||
}
|
||||
|
||||
@param('rid', Types.ObjectID)
|
||||
@param('rid', Types.ObjectId)
|
||||
async post() {
|
||||
this.checkPerm(PERM.PERM_REJUDGE);
|
||||
if (this.rdoc.files?.hack) throw new HackRejudgeFailedError();
|
||||
}
|
||||
|
||||
@param('rid', Types.ObjectID)
|
||||
async postRejudge(domainId: string, rid: ObjectID) {
|
||||
@param('rid', Types.ObjectId)
|
||||
async postRejudge(domainId: string, rid: ObjectId) {
|
||||
const pdoc = await problem.get(domainId, this.rdoc.pid);
|
||||
if (!pdoc?.config || typeof pdoc.config === 'string') throw new ProblemConfigError();
|
||||
const priority = await record.submissionPriority(this.user._id, -20);
|
||||
@@ -205,8 +205,8 @@ class RecordDetailHandler extends ContestDetailBaseHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('rid', Types.ObjectID)
|
||||
async postCancel(domainId: string, rid: ObjectID) {
|
||||
@param('rid', Types.ObjectId)
|
||||
async postCancel(domainId: string, rid: ObjectId) {
|
||||
const $set = {
|
||||
status: STATUS.STATUS_CANCELED,
|
||||
score: 0,
|
||||
@@ -237,14 +237,14 @@ class RecordMainConnectionHandler extends ConnectionHandler {
|
||||
pretest = false;
|
||||
tdoc: Tdoc<30>;
|
||||
|
||||
@param('tid', Types.ObjectID, true)
|
||||
@param('tid', Types.ObjectId, true)
|
||||
@param('pid', Types.ProblemId, true)
|
||||
@param('uidOrName', Types.UidOrName, true)
|
||||
@param('status', Types.Int, true)
|
||||
@param('pretest', Types.Boolean)
|
||||
@param('allDomain', Types.Boolean)
|
||||
async prepare(
|
||||
domainId: string, tid?: ObjectID, pid?: string | number, uidOrName?: string,
|
||||
domainId: string, tid?: ObjectId, pid?: string | number, uidOrName?: string,
|
||||
status?: number, pretest = false, all = false,
|
||||
) {
|
||||
if (tid) {
|
||||
@@ -279,8 +279,9 @@ class RecordMainConnectionHandler extends ConnectionHandler {
|
||||
|
||||
async message(msg: { rids: string[] }) {
|
||||
if (!(msg.rids instanceof Array)) return;
|
||||
const rids = msg.rids.map((id) => new ObjectID(id));
|
||||
const rdocs = await record.getMulti(this.args.domainId, { _id: { $in: rids } }).project(buildProjection(record.PROJECTION_LIST)).toArray();
|
||||
const rids = msg.rids.map((id) => new ObjectId(id));
|
||||
const rdocs = await record.getMulti(this.args.domainId, { _id: { $in: rids } })
|
||||
.project<RecordDoc>(buildProjection(record.PROJECTION_LIST)).toArray();
|
||||
for (const rdoc of rdocs) this.onRecordChange(rdoc);
|
||||
}
|
||||
|
||||
@@ -303,7 +304,7 @@ class RecordMainConnectionHandler extends ConnectionHandler {
|
||||
user.getById(this.args.domainId, rdoc.uid),
|
||||
problem.get(rdoc.domainId, rdoc.pid),
|
||||
]);
|
||||
const tdoc = this.tid ? this.tdoc || await contest.get(rdoc.domainId, new ObjectID(this.tid)) : null;
|
||||
const tdoc = this.tid ? this.tdoc || await contest.get(rdoc.domainId, new ObjectId(this.tid)) : null;
|
||||
if (pdoc && !rdoc.contest) {
|
||||
if (!problem.canViewBy(pdoc, this.user)) pdoc = null;
|
||||
if (!this.user.hasPerm(PERM.PERM_VIEW_PROBLEM)) pdoc = null;
|
||||
@@ -325,8 +326,8 @@ class RecordDetailConnectionHandler extends ConnectionHandler {
|
||||
disconnectTimeout: NodeJS.Timeout;
|
||||
throttleSend: any;
|
||||
|
||||
@param('rid', Types.ObjectID)
|
||||
async prepare(domainId: string, rid: ObjectID) {
|
||||
@param('rid', Types.ObjectId)
|
||||
async prepare(domainId: string, rid: ObjectId) {
|
||||
const rdoc = await record.get(domainId, rid);
|
||||
if (!rdoc) return;
|
||||
if (rdoc.contest && rdoc.input === undefined) {
|
||||
|
||||
@@ -39,11 +39,11 @@ class AdminStatusHandler extends Handler {
|
||||
const record = await RecordModel.stat();
|
||||
const status = await getStatus();
|
||||
const [domainCount, userCount, problemCount, discussionCount, recordCount] = await Promise.all([
|
||||
DomainModel.getMulti().count(),
|
||||
UserModel.getMulti().count(),
|
||||
DocumentModel.coll.find({ docType: DocumentModel.TYPE_PROBLEM }).count(),
|
||||
DocumentModel.coll.find({ docType: DocumentModel.TYPE_DISCUSSION }).count(),
|
||||
RecordModel.coll.find().count(),
|
||||
DomainModel.coll.countDocuments(),
|
||||
UserModel.coll.countDocuments(),
|
||||
DocumentModel.coll.countDocuments({ docType: DocumentModel.TYPE_PROBLEM }),
|
||||
DocumentModel.coll.countDocuments({ docType: DocumentModel.TYPE_DISCUSSION }),
|
||||
RecordModel.coll.countDocuments(),
|
||||
]);
|
||||
this.response.body = {
|
||||
record,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import assert from 'assert';
|
||||
import { statSync } from 'fs-extra';
|
||||
import { pick } from 'lodash';
|
||||
import { FilterQuery, ObjectID } from 'mongodb';
|
||||
import { Filter, ObjectId } from 'mongodb';
|
||||
import { sortFiles } from '@hydrooj/utils/lib/utils';
|
||||
import {
|
||||
FileLimitExceededError, FileUploadError, ProblemNotFoundError, ValidationError,
|
||||
@@ -62,19 +62,19 @@ async function _parseDagJson(domainId: string, _dag: string): Promise<Tdoc['dag'
|
||||
class TrainingMainHandler extends Handler {
|
||||
@param('page', Types.PositiveInt, true)
|
||||
async get(domainId: string, page = 1) {
|
||||
const query: FilterQuery<TrainingDoc> = {};
|
||||
const query: Filter<TrainingDoc> = {};
|
||||
await this.ctx.parallel('training/list', query, this);
|
||||
const [tdocs, tpcount] = await paginate(
|
||||
training.getMulti(domainId),
|
||||
page,
|
||||
system.get('pagination.training'),
|
||||
);
|
||||
const tids: Set<ObjectID> = new Set();
|
||||
const tids: Set<ObjectId> = new Set();
|
||||
for (const tdoc of tdocs) tids.add(tdoc.docId);
|
||||
const tsdict = {};
|
||||
let tdict = {};
|
||||
if (this.user.hasPriv(PRIV.PRIV_USER_PROFILE)) {
|
||||
const enrolledTids: Set<ObjectID> = new Set();
|
||||
const enrolledTids: Set<ObjectId> = new Set();
|
||||
const tsdocs = await training.getMultiStatus(domainId, {
|
||||
uid: this.user._id,
|
||||
$or: [{ docId: { $in: Array.from(tids) } }, { enroll: 1 }],
|
||||
@@ -97,9 +97,9 @@ class TrainingMainHandler extends Handler {
|
||||
}
|
||||
|
||||
class TrainingDetailHandler extends Handler {
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@param('uid', Types.PositiveInt, true)
|
||||
async get(domainId: string, tid: ObjectID, uid = this.user._id) {
|
||||
async get(domainId: string, tid: ObjectId, uid = this.user._id) {
|
||||
const tdoc = await training.get(domainId, tid);
|
||||
await this.ctx.parallel('training/get', tdoc, this);
|
||||
let enrollUsers: number[] = [];
|
||||
@@ -160,16 +160,16 @@ class TrainingDetailHandler extends Handler {
|
||||
this.response.template = 'training_detail.html';
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
async postEnroll(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async postEnroll(domainId: string, tid: ObjectId) {
|
||||
this.checkPriv(PRIV.PRIV_USER_PROFILE);
|
||||
const tdoc = await training.get(domainId, tid);
|
||||
await training.enroll(domainId, tdoc.docId, this.user._id);
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
async postDelete(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async postDelete(domainId: string, tid: ObjectId) {
|
||||
const tdoc = await training.get(domainId, tid);
|
||||
if (!this.user.own(tdoc)) this.checkPerm(PERM.PERM_EDIT_TRAINING);
|
||||
await training.del(domainId, tid);
|
||||
@@ -180,8 +180,8 @@ class TrainingDetailHandler extends Handler {
|
||||
class TrainingEditHandler extends Handler {
|
||||
tdoc: TrainingDoc;
|
||||
|
||||
@param('tid', Types.ObjectID, true)
|
||||
async prepare(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId, true)
|
||||
async prepare(domainId: string, tid: ObjectId) {
|
||||
if (tid) {
|
||||
this.tdoc = await training.get(domainId, tid);
|
||||
if (!this.user.own(this.tdoc)) this.checkPerm(PERM.PERM_EDIT_TRAINING);
|
||||
@@ -198,14 +198,14 @@ class TrainingEditHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID, true)
|
||||
@param('tid', Types.ObjectId, true)
|
||||
@param('title', Types.Title)
|
||||
@param('content', Types.Content)
|
||||
@param('dag', Types.Content)
|
||||
@param('pin', Types.Boolean)
|
||||
@param('description', Types.Content)
|
||||
async post(
|
||||
domainId: string, tid: ObjectID,
|
||||
domainId: string, tid: ObjectId,
|
||||
title: string, content: string,
|
||||
_dag: string, pin = false, description: string,
|
||||
) {
|
||||
@@ -229,15 +229,15 @@ class TrainingEditHandler extends Handler {
|
||||
export class TrainingFilesHandler extends Handler {
|
||||
tdoc: TrainingDoc;
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
async prepare(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async prepare(domainId: string, tid: ObjectId) {
|
||||
this.tdoc = await training.get(domainId, tid);
|
||||
if (!this.user.own(this.tdoc)) this.checkPerm(PERM.PERM_EDIT_TRAINING);
|
||||
else this.checkPerm(PERM.PERM_EDIT_TRAINING_SELF);
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
async get(domainId: string, tid: ObjectID) {
|
||||
@param('tid', Types.ObjectId)
|
||||
async get(domainId: string, tid: ObjectId) {
|
||||
if (!this.user.own(this.tdoc)) this.checkPerm(PERM.PERM_EDIT_TRAINING);
|
||||
this.response.body = {
|
||||
tdoc: this.tdoc,
|
||||
@@ -250,9 +250,9 @@ export class TrainingFilesHandler extends Handler {
|
||||
this.response.template = 'training_files.html';
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@post('filename', Types.Filename, true)
|
||||
async postUploadFile(domainId: string, tid: ObjectID, filename: string) {
|
||||
async postUploadFile(domainId: string, tid: ObjectId, filename: string) {
|
||||
if ((this.tdoc.files?.length || 0) >= system.get('limit.contest_files')) {
|
||||
throw new FileLimitExceededError('count');
|
||||
}
|
||||
@@ -271,9 +271,9 @@ export class TrainingFilesHandler extends Handler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@post('files', Types.ArrayOf(Types.Filename))
|
||||
async postDeleteFiles(domainId: string, tid: ObjectID, files: string[]) {
|
||||
async postDeleteFiles(domainId: string, tid: ObjectId, files: string[]) {
|
||||
await Promise.all([
|
||||
storage.del(files.map((t) => `contest/${domainId}/${tid}/${t}`), this.user._id),
|
||||
training.edit(domainId, tid, { files: this.tdoc.files.filter((i) => !files.includes(i.name)) }),
|
||||
@@ -282,10 +282,10 @@ export class TrainingFilesHandler extends Handler {
|
||||
}
|
||||
}
|
||||
export class TrainingFileDownloadHandler extends Handler {
|
||||
@param('tid', Types.ObjectID)
|
||||
@param('tid', Types.ObjectId)
|
||||
@param('filename', Types.Filename)
|
||||
@param('noDisposition', Types.Boolean)
|
||||
async get(domainId: string, tid: ObjectID, filename: string, noDisposition = false) {
|
||||
async get(domainId: string, tid: ObjectId, filename: string, noDisposition = false) {
|
||||
this.response.addHeader('Cache-Control', 'public');
|
||||
const target = `training/${domainId}/${tid}/${filename}`;
|
||||
const file = await storage.getMeta(target);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { generateAuthenticationOptions, verifyAuthenticationResponse } from '@simplewebauthn/server';
|
||||
import moment from 'moment-timezone';
|
||||
import type { Binary } from 'mongodb';
|
||||
import {
|
||||
AuthOperationError, BlacklistedError, BuiltinLoginError, ForbiddenError, InvalidTokenError,
|
||||
SystemError, UserAlreadyExistError, UserFacingError,
|
||||
@@ -181,7 +182,8 @@ class UserWebauthnHandler extends Handler {
|
||||
const tdoc = await token.get(challenge, token.TYPE_WEBAUTHN);
|
||||
if (!tdoc) throw new InvalidTokenError(token.TYPE_TEXTS[token.TYPE_WEBAUTHN]);
|
||||
const udoc = await user.getById(domainId, tdoc.uid);
|
||||
const authenticator = udoc._authenticators?.find((c) => c.credentialID.toString('base64url') === result.id);
|
||||
const parseId = (id: Binary) => Buffer.from(id.toString('hex'), 'hex').toString('base64url');
|
||||
const authenticator = udoc._authenticators?.find((c) => parseId(c.credentialID) === result.id);
|
||||
if (!authenticator) throw new ValidationError('authenticator');
|
||||
const verification = await verifyAuthenticationResponse({
|
||||
response: result,
|
||||
|
||||
Reference in new issue
Block a user