mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 17:38:19 +08:00
core: add FileTooLargeError
This commit is contained in:
1 parent
4a294f59a8
commit
1b53bfa2b4
8 files changed
+42
-27
No files matched your search
@@ -10,7 +10,7 @@ import { buildContent } from 'hydrooj/dist/lib/content';
|
|||||||
import { ProblemAdd } from 'hydrooj/dist/lib/ui';
|
import { ProblemAdd } from 'hydrooj/dist/lib/ui';
|
||||||
import * as solution from 'hydrooj/dist/model/solution';
|
import * as solution from 'hydrooj/dist/model/solution';
|
||||||
import { PERM } from 'hydrooj/dist/model/builtin';
|
import { PERM } from 'hydrooj/dist/model/builtin';
|
||||||
import { BadRequestError, ValidationError } from 'hydrooj/dist/error';
|
import { FileTooLargeError, ValidationError } from 'hydrooj/dist/error';
|
||||||
|
|
||||||
class FpsProblemImportHandler extends Handler {
|
class FpsProblemImportHandler extends Handler {
|
||||||
async get() {
|
async get() {
|
||||||
@@ -64,7 +64,7 @@ class FpsProblemImportHandler extends Handler {
|
|||||||
const tasks = [];
|
const tasks = [];
|
||||||
try {
|
try {
|
||||||
const file = await fs.stat(this.request.files.file.path);
|
const file = await fs.stat(this.request.files.file.path);
|
||||||
if (file.size > 64 * 1024 * 1024) throw new BadRequestError('File too large');
|
if (file.size > 64 * 1024 * 1024) throw new FileTooLargeError('64m');
|
||||||
const content = fs.readFile(this.request.files.file.path).toString();
|
const content = fs.readFile(this.request.files.file.path).toString();
|
||||||
const result = await xml2js.parseStringPromise(content);
|
const result = await xml2js.parseStringPromise(content);
|
||||||
tasks.push(result);
|
tasks.push(result);
|
||||||
@@ -73,7 +73,7 @@ class FpsProblemImportHandler extends Handler {
|
|||||||
for (const entry of zip.getEntries()) {
|
for (const entry of zip.getEntries()) {
|
||||||
try {
|
try {
|
||||||
const buf = entry.getData();
|
const buf = entry.getData();
|
||||||
if (buf.byteLength > 64 * 1024 * 1024) throw new BadRequestError('File too large');
|
if (buf.byteLength > 64 * 1024 * 1024) throw new FileTooLargeError('64m');
|
||||||
const content = buf.toString();
|
const content = buf.toString();
|
||||||
const result = await xml2js.parseStringPromise(content);
|
const result = await xml2js.parseStringPromise(content);
|
||||||
tasks.push(result);
|
tasks.push(result);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/fps-importer",
|
"name": "@hydrooj/fps-importer",
|
||||||
"version": "1.1.8",
|
"version": "1.1.9",
|
||||||
"description": "Import FPS problems",
|
"description": "Import FPS problems",
|
||||||
"main": "package.json",
|
"main": "package.json",
|
||||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.20.8",
|
"version": "2.20.9",
|
||||||
"bin": "bin/hydrooj.js",
|
"bin": "bin/hydrooj.js",
|
||||||
"main": "dist/loader.js",
|
"main": "dist/loader.js",
|
||||||
"typings": "dist/loader.d.ts",
|
"typings": "dist/loader.d.ts",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable max-len */
|
/* eslint-disable max-len */
|
||||||
/* eslint-disable func-names */
|
/* eslint-disable func-names */
|
||||||
import { isClass } from './utils';
|
import { isClass } from './utils';
|
||||||
|
import { PERMS } from './model/builtin';
|
||||||
|
|
||||||
interface IHydroError {
|
interface IHydroError {
|
||||||
new(...args: any[]): HydroError
|
new(...args: any[]): HydroError
|
||||||
@@ -10,8 +11,9 @@ function isHydroError(item: any): item is IHydroError {
|
|||||||
return isClass(item);
|
return isClass(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Err = (name: string, ...info: Array<IHydroError | (() => string) | string | number>) => {
|
const Err = (name: string, ...info: Array<IHydroError | (() => string) | ((_super: Function, ...args: any) => HydroError) | string | number>) => {
|
||||||
let Class: IHydroError;
|
let Class: IHydroError;
|
||||||
|
let constr: (_super: Function, ...args: any[]) => HydroError;
|
||||||
let msg: () => string;
|
let msg: () => string;
|
||||||
let code: number;
|
let code: number;
|
||||||
for (const item of info) {
|
for (const item of info) {
|
||||||
@@ -21,20 +23,29 @@ const Err = (name: string, ...info: Array<IHydroError | (() => string) | string
|
|||||||
msg = function () { return item; };
|
msg = function () { return item; };
|
||||||
} else if (isHydroError(item)) {
|
} else if (isHydroError(item)) {
|
||||||
Class = item;
|
Class = item;
|
||||||
} else if (typeof item === 'function') {
|
} else if (typeof item === 'function' && item.length === 0) {
|
||||||
|
// @ts-ignore
|
||||||
msg = item;
|
msg = item;
|
||||||
|
} else if (typeof item === 'function') {
|
||||||
|
// @ts-ignore
|
||||||
|
constr = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const HydroError = class extends Class { };
|
const HydroError = class extends Class { };
|
||||||
HydroError.prototype.name = name;
|
HydroError.prototype.name = name;
|
||||||
if (msg) HydroError.prototype.msg = msg;
|
if (msg) HydroError.prototype.msg = msg;
|
||||||
if (code) HydroError.prototype.code = code;
|
if (code) HydroError.prototype.code = code;
|
||||||
|
if (constr) {
|
||||||
|
const original = HydroError.prototype.constructor;
|
||||||
|
HydroError.prototype.constructor = function (...args: any[]) {
|
||||||
|
constr.call(this, original.bind(this, ...args));
|
||||||
|
};
|
||||||
|
}
|
||||||
return HydroError;
|
return HydroError;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class HydroError extends Error {
|
export class HydroError extends Error {
|
||||||
params: any[];
|
params: any[];
|
||||||
|
|
||||||
code: number;
|
code: number;
|
||||||
|
|
||||||
constructor(...params: any[]) {
|
constructor(...params: any[]) {
|
||||||
@@ -65,7 +76,12 @@ export const InvalidTokenError = Err('InvalidTokenError', ForbiddenError);
|
|||||||
export const BlacklistedError = Err('BlacklistedError', ForbiddenError, 'Address or user {0} is blacklisted.');
|
export const BlacklistedError = Err('BlacklistedError', ForbiddenError, 'Address or user {0} is blacklisted.');
|
||||||
export const VerifyPasswordError = Err('VerifyPasswordError', ForbiddenError, "Passwords don't match.");
|
export const VerifyPasswordError = Err('VerifyPasswordError', ForbiddenError, "Passwords don't match.");
|
||||||
export const OpcountExceededError = Err('OpcountExceededError', ForbiddenError, 'Too frequent operations of {0} (limit: {2} operations in {1} seconds).');
|
export const OpcountExceededError = Err('OpcountExceededError', ForbiddenError, 'Too frequent operations of {0} (limit: {2} operations in {1} seconds).');
|
||||||
export const PermissionError = Err('PermissionError', ForbiddenError, "You don't have the required permission ({0}) in this domain.");
|
export const PermissionError = Err('PermissionError', ForbiddenError, function () {
|
||||||
|
if (typeof this.params[0] === 'bigint') {
|
||||||
|
this.params[0] = PERMS.find(({ key }) => key === this.params[0])?.desc || this.params[0];
|
||||||
|
}
|
||||||
|
return "You don't have the required permission ({0}) in this domain.";
|
||||||
|
});
|
||||||
export const PrivilegeError = Err('PrivilegeError', ForbiddenError, function () {
|
export const PrivilegeError = Err('PrivilegeError', ForbiddenError, function () {
|
||||||
if (this.params.includes(global.Hydro.model.builtin.PRIV.PRIV_USER_PROFILE)) {
|
if (this.params.includes(global.Hydro.model.builtin.PRIV.PRIV_USER_PROFILE)) {
|
||||||
return "You're not logged in.";
|
return "You're not logged in.";
|
||||||
@@ -89,6 +105,7 @@ export const DomainAlreadyExistsError = Err('DomainAlreadyExistsError', Forbidde
|
|||||||
export const DomainJoinForbiddenError = Err('DomainJoinForbiddenError', ForbiddenError, 'You are not allowed to join the domain. The link is either invalid or expired.');
|
export const DomainJoinForbiddenError = Err('DomainJoinForbiddenError', ForbiddenError, 'You are not allowed to join the domain. The link is either invalid or expired.');
|
||||||
export const DomainJoinAlreadyMemberError = Err('DomainJoinAlreadyMemberError', ForbiddenError, 'Failed to join the domain. You are already a member.');
|
export const DomainJoinAlreadyMemberError = Err('DomainJoinAlreadyMemberError', ForbiddenError, 'Failed to join the domain. You are already a member.');
|
||||||
export const InvalidJoinInvitationCodeError = Err('InvalidJoinInvitationCodeError', ForbiddenError, 'The invitation code you provided is invalid.');
|
export const InvalidJoinInvitationCodeError = Err('InvalidJoinInvitationCodeError', ForbiddenError, 'The invitation code you provided is invalid.');
|
||||||
|
export const CurrentPasswordError = Err('CurrentPasswordError', ForbiddenError, "Current password doesn't match.");
|
||||||
|
|
||||||
export const UserNotFoundError = Err('UserNotFoundError', NotFoundError, 'User {0} not found.');
|
export const UserNotFoundError = Err('UserNotFoundError', NotFoundError, 'User {0} not found.');
|
||||||
export const NoProblemError = Err('NoProblemError', NotFoundError, 'No problem.');
|
export const NoProblemError = Err('NoProblemError', NotFoundError, 'No problem.');
|
||||||
@@ -105,6 +122,7 @@ export const DiscussionNotFoundError = Err('DiscussionNotFoundError', DocumentNo
|
|||||||
export const DiscussionNodeNotFoundError = Err('DiscussionNodeNotFoundError', DocumentNotFoundError, 'Discussion node {1} not found.');
|
export const DiscussionNodeNotFoundError = Err('DiscussionNodeNotFoundError', DocumentNotFoundError, 'Discussion node {1} not found.');
|
||||||
|
|
||||||
export const InvalidOperationError = Err('InvalidOperationError', MethodNotAllowedError);
|
export const InvalidOperationError = Err('InvalidOperationError', MethodNotAllowedError);
|
||||||
|
export const FileTooLargeError = Err('FileTooLargeError', ValidationError, 'The uploaded file is too long.');
|
||||||
|
|
||||||
global.Hydro.error = {
|
global.Hydro.error = {
|
||||||
HydroError,
|
HydroError,
|
||||||
@@ -152,14 +170,11 @@ global.Hydro.error = {
|
|||||||
DiscussionNotFoundError,
|
DiscussionNotFoundError,
|
||||||
RoleAlreadyExistError,
|
RoleAlreadyExistError,
|
||||||
MessageNotFoundError,
|
MessageNotFoundError,
|
||||||
|
FileTooLargeError,
|
||||||
|
CurrentPasswordError,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
class FileTooLongError(ValidationError):
|
|
||||||
@property
|
|
||||||
def message(self):
|
|
||||||
return 'The uploaded file is too long.'
|
|
||||||
|
|
||||||
class FileTypeNotAllowedError(ValidationError):
|
class FileTypeNotAllowedError(ValidationError):
|
||||||
@property
|
@property
|
||||||
def message(self):
|
def message(self):
|
||||||
@@ -168,11 +183,6 @@ class FileTypeNotAllowedError(ValidationError):
|
|||||||
class InvalidTokenDigestError(ForbiddenError):
|
class InvalidTokenDigestError(ForbiddenError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class CurrentPasswordError(ForbiddenError):
|
|
||||||
@property
|
|
||||||
def message(self):
|
|
||||||
return "Current password doesn't match."
|
|
||||||
|
|
||||||
class DiscussionCategoryAlreadyExistError(ForbiddenError):
|
class DiscussionCategoryAlreadyExistError(ForbiddenError):
|
||||||
@property
|
@property
|
||||||
def message(self):
|
def message(self):
|
||||||
|
|||||||
@@ -153,13 +153,12 @@ class ContestScoreboardRawHandler extends ContestHandler {
|
|||||||
|
|
||||||
class ContestScoreboardDownloadHandler extends ContestHandler {
|
class ContestScoreboardDownloadHandler extends ContestHandler {
|
||||||
@param('tid', Types.ObjectID)
|
@param('tid', Types.ObjectID)
|
||||||
@param('ext', Types.String)
|
@param('ext', Types.Range(['csv', 'html']))
|
||||||
async get(domainId: string, tid: ObjectID, ext: string) {
|
async get(domainId: string, tid: ObjectID, ext: string) {
|
||||||
const getContent = {
|
const getContent = {
|
||||||
csv: async (rows) => `\uFEFF${rows.map((c) => (c.map((i) => i.value).join(','))).join('\n')}`,
|
csv: async (rows) => `\uFEFF${rows.map((c) => (c.map((i) => i.value).join(','))).join('\n')}`,
|
||||||
html: (rows) => this.renderHTML('contest_scoreboard_download_html.html', { rows }),
|
html: (rows) => this.renderHTML('contest_scoreboard_download_html.html', { rows }),
|
||||||
};
|
};
|
||||||
if (!getContent[ext]) throw new ValidationError('ext');
|
|
||||||
const [tdoc, rows] = await this.getScoreboard(domainId, tid, true);
|
const [tdoc, rows] = await this.getScoreboard(domainId, tid, true);
|
||||||
this.binary(await getContent[ext](rows), `${tdoc.title}.${ext}`);
|
this.binary(await getContent[ext](rows), `${tdoc.title}.${ext}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import {
|
|||||||
RoleAlreadyExistError, ValidationError, DomainJoinForbiddenError,
|
RoleAlreadyExistError, ValidationError, DomainJoinForbiddenError,
|
||||||
DomainJoinAlreadyMemberError, InvalidJoinInvitationCodeError,
|
DomainJoinAlreadyMemberError, InvalidJoinInvitationCodeError,
|
||||||
} from '../error';
|
} from '../error';
|
||||||
|
import { log2 } from '../utils';
|
||||||
|
import type { DomainDoc } from '../interface';
|
||||||
import * as user from '../model/user';
|
import * as user from '../model/user';
|
||||||
import * as domain from '../model/domain';
|
import * as domain from '../model/domain';
|
||||||
import * as system from '../model/system';
|
import * as system from '../model/system';
|
||||||
@@ -14,7 +16,6 @@ import paginate from '../lib/paginate';
|
|||||||
import {
|
import {
|
||||||
Route, Handler, Types, param,
|
Route, Handler, Types, param,
|
||||||
} from '../service/server';
|
} from '../service/server';
|
||||||
import { DomainDoc } from '../interface';
|
|
||||||
|
|
||||||
class DomainRankHandler extends Handler {
|
class DomainRankHandler extends Handler {
|
||||||
@param('page', Types.PositiveInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
@@ -124,10 +125,6 @@ class DomainUserHandler extends ManageHandler {
|
|||||||
class DomainPermissionHandler extends ManageHandler {
|
class DomainPermissionHandler extends ManageHandler {
|
||||||
async get({ domainId }) {
|
async get({ domainId }) {
|
||||||
const roles = await domain.getRoles(domainId);
|
const roles = await domain.getRoles(domainId);
|
||||||
const log2 = (val: bigint) => {
|
|
||||||
// @ts-ignore
|
|
||||||
for (let i = 0n; ; i++) if (!(val >> i)) return +i.toString() - 1;
|
|
||||||
};
|
|
||||||
const path = [
|
const path = [
|
||||||
['Hydro', 'homepage'],
|
['Hydro', 'homepage'],
|
||||||
['domain', null],
|
['domain', null],
|
||||||
|
|||||||
@@ -521,7 +521,7 @@ interface GeoIP {
|
|||||||
lookup: (ip: string, locale?: string) => any,
|
lookup: (ip: string, locale?: string) => any,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Lib {
|
export interface Lib extends Record<string, any> {
|
||||||
download: typeof import('./lib/download'),
|
download: typeof import('./lib/download'),
|
||||||
buildContent: typeof import('./lib/content').buildContent,
|
buildContent: typeof import('./lib/content').buildContent,
|
||||||
'hash.hydro': typeof import('./lib/hash.hydro'),
|
'hash.hydro': typeof import('./lib/hash.hydro'),
|
||||||
|
|||||||
@@ -257,3 +257,12 @@ export namespace Time {
|
|||||||
return constructedObjectId;
|
return constructedObjectId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const log2 = (val: bigint | number) => {
|
||||||
|
if (typeof val === 'bigint') {
|
||||||
|
// @ts-ignore
|
||||||
|
for (let i = 0n; ; i++) if (!(val >> i)) return +i.toString() - 1;
|
||||||
|
} else {
|
||||||
|
for (let i = 0; ; i++) if (!(val >> i)) return i - 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in new issue
Block a user