InvalidOperationError & MethodNotAllowedError

This commit is contained in:
undefined committed 2020-06-30 22:34:29 +08:00
1 parent e15c05d36b
commit 0de7cd7b59
4 files changed
+48 -26

No files matched your search

+5 -3
View File
@@ -36,6 +36,7 @@ const SystemError = Err('SystemError', HydroError, 'SystemError', 500);
const BadRequestError = Err('BadRequestError', UserFacingError, 400); const BadRequestError = Err('BadRequestError', UserFacingError, 400);
const ForbiddenError = Err('ForbiddenError', UserFacingError, 403); const ForbiddenError = Err('ForbiddenError', UserFacingError, 403);
const NotFoundError = Err('NotFoundError', UserFacingError, 404); const NotFoundError = Err('NotFoundError', UserFacingError, 404);
const MethodNotAllowedError = Err('MethodNotAllowedError', UserFacingError, 405);
const RemoteOnlineJudgeError = Err('RemoteOnlineJudgeError', UserFacingError, 500); const RemoteOnlineJudgeError = Err('RemoteOnlineJudgeError', UserFacingError, 500);
const AlreadyVotedError = Err('AlreadyVotedError', ForbiddenError, "You've already voted."); const AlreadyVotedError = Err('AlreadyVotedError', ForbiddenError, "You've already voted.");
@@ -78,6 +79,8 @@ const ContestNotFoundError = Err('ContestNotFoundError', DocumentNotFoundError);
const DiscussionNotFoundError = Err('DiscussionNotFoundError', DocumentNotFoundError, 'Discussion {0} not found.'); const DiscussionNotFoundError = Err('DiscussionNotFoundError', DocumentNotFoundError, 'Discussion {0} not found.');
const DiscussionNodeNotFoundError = Err('DiscussionNodeNotFoundError', DocumentNotFoundError, 'Discussion node {1} not found.'); const DiscussionNodeNotFoundError = Err('DiscussionNodeNotFoundError', DocumentNotFoundError, 'Discussion node {1} not found.');
const InvalidOperationError = Err('InvalidOperationError', MethodNotAllowedError);
global.Hydro.error = module.exports = { global.Hydro.error = module.exports = {
Err, Err,
HydroError, HydroError,
@@ -87,6 +90,8 @@ global.Hydro.error = module.exports = {
NotFoundError, NotFoundError,
LoginError, LoginError,
CsrfTokenError, CsrfTokenError,
MethodNotAllowedError,
InvalidOperationError,
UserAlreadyExistError, UserAlreadyExistError,
InvalidTokenError, InvalidTokenError,
UserNotFoundError, UserNotFoundError,
@@ -129,9 +134,6 @@ class FileTypeNotAllowedError(ValidationError):
def message(self): def message(self):
return 'This type of files are not allowed to be uploaded.' return 'This type of files are not allowed to be uploaded.'
class InvalidOperationError(ForbiddenError):
pass
class InvalidTokenDigestError(ForbiddenError): class InvalidTokenDigestError(ForbiddenError):
pass pass
+7
View File
@@ -64,6 +64,12 @@ class MarkdownHandler extends Handler {
} }
} }
class SockToken extends Handler {
async get() {
this.response.body = { token: this.csrfToken };
}
}
async function apply() { async function apply() {
Route('file_download', '/fs/:docId/:secret', FileDownloadHandler); Route('file_download', '/fs/:docId/:secret', FileDownloadHandler);
Route('file_download_with_name', '/fs/:docId/:name/:secret', FileDownloadHandler); Route('file_download_with_name', '/fs/:docId/:name/:secret', FileDownloadHandler);
@@ -71,6 +77,7 @@ async function apply() {
Route('status_update', '/status/update', StatusUpdateHandler); Route('status_update', '/status/update', StatusUpdateHandler);
Route('switch_language', '/language/:lang', SwitchLanguageHandler); Route('switch_language', '/language/:lang', SwitchLanguageHandler);
Route('markdown', '/markdown', MarkdownHandler); Route('markdown', '/markdown', MarkdownHandler);
Route('token', '/token', SockToken);
} }
apply.updateStatus = function updateStatus(args) { apply.updateStatus = function updateStatus(args) {
+17 -21
View File
@@ -4,7 +4,7 @@ const paginate = require('../lib/paginate');
const { const {
PERM: { PERM: {
PERM_VIEW_TRAINING, PERM_VIEW_PROBLEM_HIDDEN, PERM_CREATE_TRAINING, PERM_VIEW_TRAINING, PERM_VIEW_PROBLEM_HIDDEN, PERM_CREATE_TRAINING,
PERM_EDIT_TRAINING, PERM_EDIT_TRAINING, PERM_EDIT_TRAINING_SELF,
}, },
PRIV: { PRIV: {
PRIV_USER_PROFILE, PRIV_USER_PROFILE,
@@ -57,13 +57,7 @@ async function _parseDagJson(domainId, dag) {
return parsed; return parsed;
} }
class TrainingHandler extends Handler { class TrainingMainHandler extends Handler {
async _prepare() {
this.checkPerm(PERM_VIEW_TRAINING);
}
}
class TrainingMainHandler extends TrainingHandler {
async get({ domainId, sort, page }) { async get({ domainId, sort, page }) {
const qs = sort ? 'sort={0}'.format(sort) : ''; const qs = sort ? 'sort={0}'.format(sort) : '';
const [tdocs, tpcount] = await paginate( const [tdocs, tpcount] = await paginate(
@@ -102,7 +96,7 @@ class TrainingMainHandler extends TrainingHandler {
} }
} }
class TrainingDetailHandler extends TrainingHandler { class TrainingDetailHandler extends Handler {
async get({ domainId, tid }) { async get({ domainId, tid }) {
const tdoc = await training.get(domainId, tid); const tdoc = await training.get(domainId, tid);
const pids = training.getPids(tdoc); const pids = training.getPids(tdoc);
@@ -162,7 +156,7 @@ class TrainingDetailHandler extends TrainingHandler {
} }
} }
class TrainingCreateHandler extends TrainingHandler { class TrainingCreateHandler extends Handler {
async get() { async get() {
const path = [ const path = [
['Hydro', 'homepage'], ['Hydro', 'homepage'],
@@ -201,28 +195,30 @@ class TrainingCreateHandler extends TrainingHandler {
} }
} }
class TrainingEditHandler extends TrainingHandler { class TrainingEditHandler extends Handler {
async get({ domainId, tid }) { async prepare({ domainId, tid }) {
const tdoc = await training.get(domainId, tid); this.tdoc = await training.get(domainId, tid);
if (tdoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_TRAINING); if (this.tdoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_TRAINING);
const dag = JSON.stringify(tdoc.dag, null, 2); else this.checkPerm(PERM_EDIT_TRAINING_SELF);
}
async get({ tid }) {
const dag = JSON.stringify(this.tdoc.dag, null, 2);
const path = [ const path = [
['Hydro', 'homepage'], ['Hydro', 'homepage'],
['training_main', 'training_main'], ['training_main', 'training_main'],
[tdoc.title, 'training_detail', { tid: tdoc.docId }, true], [this.tdoc.title, 'training_detail', { tid }, true],
['training_edit', null], ['training_edit', null],
]; ];
this.response.template = 'training_edit.html'; this.response.template = 'training_edit.html';
this.response.body = { this.response.body = {
tdoc, dag, path, page_name: 'training_edit', tdoc: this.tdoc, dag, path, page_name: 'training_edit',
}; };
} }
async post({ async post({
domainId, tid, title, content, dag, description, domainId, tid, title, content, dag, description,
}) { }) {
const tdoc = await training.get(domainId, tid);
if (!this.user._id === tdoc.owner) this.checkPerm(PERM_EDIT_TRAINING);
dag = await _parseDagJson(domainId, dag); dag = await _parseDagJson(domainId, dag);
const pids = training.getPids({ dag }); const pids = training.getPids({ dag });
assert(pids.length, new ValidationError('dag')); assert(pids.length, new ValidationError('dag'));
@@ -254,9 +250,9 @@ class TrainingEditHandler extends TrainingHandler {
} }
async function apply() { async function apply() {
Route('training_main', '/training', TrainingMainHandler); Route('training_main', '/training', TrainingMainHandler, PERM_VIEW_TRAINING);
Route('training_create', '/training/create', TrainingCreateHandler, PERM_CREATE_TRAINING); Route('training_create', '/training/create', TrainingCreateHandler, PERM_CREATE_TRAINING);
Route('training_detail', '/training/:tid', TrainingDetailHandler); Route('training_detail', '/training/:tid', TrainingDetailHandler, PERM_VIEW_TRAINING);
Route('training_edit', '/training/:tid/edit', TrainingEditHandler); Route('training_edit', '/training/:tid/edit', TrainingEditHandler);
} }
+19 -2
View File
@@ -22,7 +22,7 @@ const opcount = require('../model/opcount');
const { const {
UserNotFoundError, BlacklistedError, PermissionError, UserNotFoundError, BlacklistedError, PermissionError,
UserFacingError, ValidationError, PrivilegeError, UserFacingError, ValidationError, PrivilegeError,
CsrfTokenError, CsrfTokenError, InvalidOperationError, MethodNotAllowedError,
} = require('../error'); } = require('../error');
let enableLog = true; let enableLog = true;
@@ -387,10 +387,26 @@ async function handle(ctx, HandlerClass, checker) {
domainId: 'system', ...ctx.params, ...ctx.query, ...ctx.request.body, domainId: 'system', ...ctx.params, ...ctx.query, ...ctx.request.body,
}; };
h.args = args; h.args = args;
let operation;
if (method === 'post' && ctx.request.body.operation) {
operation = `_${ctx.request.body.operation}`
.replace(/_([a-z])/gm, (s) => s[1].toUpperCase());
}
if (h.___prepare) await h.___prepare(args); if (h.___prepare) await h.___prepare(args);
if (checker) checker.call(h); if (checker) checker.call(h);
if (method === 'post') await h.checkCsrfToken(args.csrfToken); if (method === 'post') {
await h.checkCsrfToken(args.csrfToken);
if (operation) {
if (typeof h[`post${operation}`] !== 'function') {
throw new InvalidOperationError(operation);
}
} else if (typeof h.post !== 'function') {
throw new MethodNotAllowedError(method);
}
} else if (typeof h[method] !== 'function') {
throw new MethodNotAllowedError(method);
}
let checking = ''; let checking = '';
try { try {
@@ -404,6 +420,7 @@ async function handle(ctx, HandlerClass, checker) {
if (e instanceof ValidationError) throw e; if (e instanceof ValidationError) throw e;
throw new ValidationError(`Argument ${checking} check failed`); throw new ValidationError(`Argument ${checking} check failed`);
} }
if (h.__prepare) await h.__prepare(args); if (h.__prepare) await h.__prepare(args);
if (h._prepare) await h._prepare(args); if (h._prepare) await h._prepare(args);
if (h.prepare) await h.prepare(args); if (h.prepare) await h.prepare(args);