mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 17:38:19 +08:00
添加全局rate_limit,更换ui节点接口
This commit is contained in:
1 parent
02c1866963
commit
03dc8903e2
22 files changed
+230
-215
No files matched your search
@@ -10,6 +10,7 @@ import {
|
|||||||
Route, Handler, param, Types,
|
Route, Handler, param, Types,
|
||||||
} from 'hydrooj/dist/service/server';
|
} from 'hydrooj/dist/service/server';
|
||||||
import { streamToBuffer } from 'hydrooj/dist/utils';
|
import { streamToBuffer } from 'hydrooj/dist/utils';
|
||||||
|
import { ProblemAdd } from 'hydrooj/dist/lib/ui';
|
||||||
import * as file from 'hydrooj/dist/model/file';
|
import * as file from 'hydrooj/dist/model/file';
|
||||||
import { PERM } from 'hydrooj/dist/model/builtin';
|
import { PERM } from 'hydrooj/dist/model/builtin';
|
||||||
|
|
||||||
@@ -123,6 +124,7 @@ class FpsProblemImportHandler extends Handler {
|
|||||||
|
|
||||||
export async function apply() {
|
export async function apply() {
|
||||||
Route('problem_import_fps', '/problem/import/fps', FpsProblemImportHandler, PERM.PERM_CREATE_PROBLEM);
|
Route('problem_import_fps', '/problem/import/fps', FpsProblemImportHandler, PERM.PERM_CREATE_PROBLEM);
|
||||||
|
ProblemAdd('problem_import_fps', {}, 'copy', 'From FPS File');
|
||||||
}
|
}
|
||||||
|
|
||||||
global.Hydro.handler.fpsImport = apply;
|
global.Hydro.handler.fpsImport = apply;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/fps-importer",
|
"name": "@hydrooj/fps-importer",
|
||||||
"version": "1.0.8",
|
"version": "1.1.0",
|
||||||
"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",
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
"bson": "^4.1.0"
|
"bson": "^4.1.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"hydrooj": "^2.12.22"
|
"hydrooj": "^2.13.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'hydrooj';
|
import 'hydrooj';
|
||||||
import 'hydrooj/src/lib/i18n';
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { Reader } from 'maxmind';
|
import { Reader } from 'maxmind';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/geoip",
|
"name": "@hydrooj/geoip",
|
||||||
"version": "1.1.13",
|
"version": "1.1.14",
|
||||||
"main": "package.json",
|
"main": "package.json",
|
||||||
"repository": "git@github.com:hydro-dev/Hydro.git",
|
"repository": "git@github.com:hydro-dev/Hydro.git",
|
||||||
"author": "undefined <masnn0@outlook.com>",
|
"author": "undefined <masnn0@outlook.com>",
|
||||||
@@ -9,6 +9,6 @@
|
|||||||
"maxmind": "^4.1.3"
|
"maxmind": "^4.1.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"hydrooj": "^2.12.0"
|
"hydrooj": "^2.12.0||^2.13.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
jest.mock('hydrooj/src/loader');
|
jest.mock('hydrooj/src/loader');
|
||||||
|
import 'hydrooj';
|
||||||
|
import 'hydrooj/src/lib/i18n';
|
||||||
import * as lib from '@hydrooj/geoip/lib';
|
import * as lib from '@hydrooj/geoip/lib';
|
||||||
|
|
||||||
describe('geoip', () => {
|
describe('geoip', () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/hydrojudge",
|
"name": "@hydrooj/hydrojudge",
|
||||||
"version": "2.0.9",
|
"version": "2.0.10",
|
||||||
"main": "package.json",
|
"main": "package.json",
|
||||||
"author": "masnn",
|
"author": "masnn",
|
||||||
"os": [
|
"os": [
|
||||||
@@ -10,13 +10,15 @@
|
|||||||
"axios": "^0.19.0",
|
"axios": "^0.19.0",
|
||||||
"bson": "^4.1.0",
|
"bson": "^4.1.0",
|
||||||
"fs-extra": "^9.0.1",
|
"fs-extra": "^9.0.1",
|
||||||
"hydrooj": "^2.12.0",
|
|
||||||
"js-yaml": "^3.14.0",
|
"js-yaml": "^3.14.0",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"p-queue": "^6.6.1",
|
"p-queue": "^6.6.1",
|
||||||
"shell-quote": "^1.7.2",
|
"shell-quote": "^1.7.2",
|
||||||
"systeminformation": "^4.27.3"
|
"systeminformation": "^4.27.3"
|
||||||
},
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"hydrooj": "^2.12.0||^2.13.0"
|
||||||
|
},
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bson": "^4.0.2",
|
"@types/bson": "^4.0.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.12.27",
|
"version": "2.13.0",
|
||||||
"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",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { argv } from 'yargs';
|
|||||||
export const builtinLib = [
|
export const builtinLib = [
|
||||||
'jwt', 'download', 'i18n', 'mail', 'useragent',
|
'jwt', 'download', 'i18n', 'mail', 'useragent',
|
||||||
'md5', 'misc', 'paginate', 'hash.hydro', 'rank',
|
'md5', 'misc', 'paginate', 'hash.hydro', 'rank',
|
||||||
'validator', 'nav', 'sysinfo', 'testdata.convert.ini', 'testdataConfig',
|
'validator', 'ui', 'sysinfo', 'testdata.convert.ini', 'testdataConfig',
|
||||||
'logger',
|
'logger',
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ export const builtinModel = [
|
|||||||
|
|
||||||
export const builtinHandler = [
|
export const builtinHandler = [
|
||||||
'home', 'problem', 'record', 'judge', 'user',
|
'home', 'problem', 'record', 'judge', 'user',
|
||||||
'contest', 'training', 'discussion', 'manage', 'import',
|
'contest', 'training', 'discussion', 'manage', 'import.syzoj',
|
||||||
'misc', 'homework', 'domain',
|
'misc', 'homework', 'domain',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import os from 'os';
|
||||||
|
import assert from 'assert';
|
||||||
|
import superagent from 'superagent';
|
||||||
|
import { ValidationError, RemoteOnlineJudgeError } from '../error';
|
||||||
|
import * as problem from '../model/problem';
|
||||||
|
import { PERM } from '../model/builtin';
|
||||||
|
import {
|
||||||
|
Route, Handler, Types, param,
|
||||||
|
} from '../service/server';
|
||||||
|
import { isPid } from '../lib/validator';
|
||||||
|
import download from '../lib/download';
|
||||||
|
|
||||||
|
const RE_SYZOJ = /https?:\/\/([a-zA-Z0-9.]+)\/problem\/([0-9]+)\/?/i;
|
||||||
|
|
||||||
|
class ProblemImportSYZOJHandler extends Handler {
|
||||||
|
async get() {
|
||||||
|
this.response.template = 'problem_import_syzoj.html';
|
||||||
|
this.response.body = {
|
||||||
|
path: [
|
||||||
|
['Hydro', 'homepage'],
|
||||||
|
['problem_main', 'problem_main'],
|
||||||
|
['problem_import_syzoj', null],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@param('url', Types.String)
|
||||||
|
@param('pid', Types.String, true, isPid)
|
||||||
|
@param('hidden', Types.Boolean)
|
||||||
|
async post(domainId: string, url: string, targetPid: string, hidden = false) {
|
||||||
|
assert(url.match(RE_SYZOJ), new ValidationError('url'));
|
||||||
|
if (!url.endsWith('/')) url += '/';
|
||||||
|
const [, host, pid] = RE_SYZOJ.exec(url);
|
||||||
|
const res = await superagent.get(`${url}export`);
|
||||||
|
assert(res.status === 200, new RemoteOnlineJudgeError('Cannot connect to target server'));
|
||||||
|
assert(res.body.success, new RemoteOnlineJudgeError((res.body.error || {}).message));
|
||||||
|
const p = res.body.obj;
|
||||||
|
const content = [];
|
||||||
|
if (p.description) {
|
||||||
|
content.push(
|
||||||
|
`## ${this.translate('Description')}`,
|
||||||
|
p.description,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (p.input_format) {
|
||||||
|
content.push(
|
||||||
|
`## ${this.translate('Input Format')}`,
|
||||||
|
p.input_format,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (p.output_format) {
|
||||||
|
content.push(
|
||||||
|
`## ${this.translate('Output Format')}`,
|
||||||
|
p.output_format,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (p.example) content.push(p.example);
|
||||||
|
if (p.hint) {
|
||||||
|
content.push(
|
||||||
|
`## ${this.translate('Hint')}`,
|
||||||
|
p.hint,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (p.limit_and_hint) {
|
||||||
|
content.push(
|
||||||
|
`## ${this.translate('Limit And Hint')}`,
|
||||||
|
p.limit_and_hint,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (p.have_additional_file) {
|
||||||
|
content.push(
|
||||||
|
`## ${this.translate('Additional File')}`,
|
||||||
|
`${url}download/additional_file`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const docId = await problem.add(
|
||||||
|
domainId, targetPid || `${host}_${pid}`, p.title, content.join(' \n'), this.user._id,
|
||||||
|
p.tags || [], [], null, hidden,
|
||||||
|
);
|
||||||
|
const r = download(`${url}testdata/download`);
|
||||||
|
const file = path.resolve(os.tmpdir(), 'hydro', `import_${domainId}_${docId}.zip`);
|
||||||
|
const w = fs.createWriteStream(file);
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
w.on('finish', resolve);
|
||||||
|
w.on('error', reject);
|
||||||
|
r.pipe(w);
|
||||||
|
});
|
||||||
|
await problem.setTestdata(domainId, docId, file);
|
||||||
|
await problem.edit(domainId, docId, {
|
||||||
|
config: {
|
||||||
|
time: `${p.time_limit}ms`,
|
||||||
|
memory: `${p.memory_limit}m`,
|
||||||
|
filename: p.file_io_input_name.split('.')[0],
|
||||||
|
type: p.type === 'traditional' ? 'default' : p.type,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.response.body = { pid: pid || docId };
|
||||||
|
this.response.redirect = this.url('problem_settings', { pid: pid || docId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function apply() {
|
||||||
|
Route('problem_import_syzoj', '/problem/import/syzoj', ProblemImportSYZOJHandler, PERM.PERM_CREATE_PROBLEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
global.Hydro.handler['import.syzoj'] = apply;
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
import fs from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
import os from 'os';
|
|
||||||
import { ValidationError } from '../error';
|
|
||||||
import * as problem from '../model/problem';
|
|
||||||
import { PERM } from '../model/builtin';
|
|
||||||
import {
|
|
||||||
Route, Handler, Types, param,
|
|
||||||
} from '../service/server';
|
|
||||||
import { isPid } from '../lib/validator';
|
|
||||||
|
|
||||||
class ProblemImportHandler extends Handler {
|
|
||||||
async get() {
|
|
||||||
this.response.template = 'problem_import.html';
|
|
||||||
this.response.body = {
|
|
||||||
path: [
|
|
||||||
['Hydro', 'homepage'],
|
|
||||||
['problem_main', 'problem_main'],
|
|
||||||
['problem_import', null],
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@param('url', Types.String)
|
|
||||||
@param('pid', Types.String, true, isPid)
|
|
||||||
@param('hidden', Types.Boolean)
|
|
||||||
@param('remoteType', Types.String)
|
|
||||||
async post(domainId: string, url: string, pid: string, hidden = false, remoteType: string) {
|
|
||||||
if (typeof global.Hydro.lib[`import.${remoteType}`] !== 'function') {
|
|
||||||
throw new ValidationError('remoteType');
|
|
||||||
}
|
|
||||||
const [pdoc, testdata] = await global.Hydro.lib[`import.${remoteType}`](url, this);
|
|
||||||
if (hidden) pdoc.hidden = true;
|
|
||||||
const docId = await problem.add(
|
|
||||||
domainId, pid || pdoc.pid, pdoc.title, pdoc.content, this.user._id,
|
|
||||||
pdoc.tag || [], pdoc.category || [], null, pdoc.hidden,
|
|
||||||
);
|
|
||||||
if (testdata) {
|
|
||||||
const file = path.resolve(os.tmpdir(), 'hydro', `import_${domainId}_${pid || pdoc.pid || docId}.zip`);
|
|
||||||
const w = fs.createWriteStream(file);
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
w.on('finish', resolve);
|
|
||||||
w.on('error', reject);
|
|
||||||
testdata.pipe(w);
|
|
||||||
});
|
|
||||||
await problem.setTestdata(domainId, docId, file);
|
|
||||||
}
|
|
||||||
this.response.body = { pid: pid || docId };
|
|
||||||
this.response.redirect = this.url('problem_settings', { pid: pid || docId });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function apply() {
|
|
||||||
Route('problem_import', '/problem/import', ProblemImportHandler, PERM.PERM_CREATE_PROBLEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
global.Hydro.handler.import = apply;
|
|
||||||
@@ -101,10 +101,9 @@ export interface SubtaskConfig {
|
|||||||
export interface LocalProblemConfig {
|
export interface LocalProblemConfig {
|
||||||
type?: LocalProblemType,
|
type?: LocalProblemType,
|
||||||
score?: number,
|
score?: number,
|
||||||
/** ms */
|
|
||||||
time?: string,
|
time?: string,
|
||||||
/** Megabytes */
|
|
||||||
memory?: string,
|
memory?: string,
|
||||||
|
filename?: string,
|
||||||
checker_type?: string,
|
checker_type?: string,
|
||||||
checker?: string,
|
checker?: string,
|
||||||
interactor?: string,
|
interactor?: string,
|
||||||
@@ -415,13 +414,11 @@ export interface Lib {
|
|||||||
download: typeof import('./lib/download'),
|
download: typeof import('./lib/download'),
|
||||||
'hash.hydro': typeof import('./lib/hash.hydro'),
|
'hash.hydro': typeof import('./lib/hash.hydro'),
|
||||||
i18n: typeof import('./lib/i18n'),
|
i18n: typeof import('./lib/i18n'),
|
||||||
'import.syzoj': typeof import('./lib/import.syzoj').syzoj,
|
|
||||||
jwt: typeof import('./lib/jwt'),
|
jwt: typeof import('./lib/jwt'),
|
||||||
logger: typeof import('./lib/logger'),
|
logger: typeof import('./lib/logger'),
|
||||||
mail: typeof import('./lib/mail'),
|
mail: typeof import('./lib/mail'),
|
||||||
md5: typeof import('./lib/md5'),
|
md5: typeof import('./lib/md5'),
|
||||||
misc: typeof import('./lib/misc'),
|
misc: typeof import('./lib/misc'),
|
||||||
nav: typeof import('./lib/nav'),
|
|
||||||
paginate: typeof import('./lib/paginate'),
|
paginate: typeof import('./lib/paginate'),
|
||||||
rank: typeof import('./lib/rank'),
|
rank: typeof import('./lib/rank'),
|
||||||
rating: typeof import('./lib/rating'),
|
rating: typeof import('./lib/rating'),
|
||||||
@@ -434,6 +431,17 @@ export interface Lib {
|
|||||||
[key: string]: any
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UI {
|
||||||
|
manifest: Dictionary<string>,
|
||||||
|
template: Dictionary<string>,
|
||||||
|
nodes: {
|
||||||
|
nav: any[],
|
||||||
|
problem_add: any[],
|
||||||
|
},
|
||||||
|
Nav: typeof import('./lib/ui').Nav,
|
||||||
|
ProblemAdd: typeof import('./lib/ui').ProblemAdd,
|
||||||
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
namespace NodeJS {
|
namespace NodeJS {
|
||||||
interface Global {
|
interface Global {
|
||||||
@@ -444,11 +452,7 @@ declare global {
|
|||||||
service: Service,
|
service: Service,
|
||||||
lib: Lib,
|
lib: Lib,
|
||||||
stat: any,
|
stat: any,
|
||||||
ui: {
|
ui: UI,
|
||||||
manifest: Dict<string>,
|
|
||||||
template: Dict<string>,
|
|
||||||
nav: any,
|
|
||||||
},
|
|
||||||
error: typeof import('./error'),
|
error: typeof import('./error'),
|
||||||
locales: Dict<Dict<string>>,
|
locales: Dict<Dict<string>>,
|
||||||
postInit: Array<() => Promise<any>>,
|
postInit: Array<() => Promise<any>>,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import superagent from 'superagent';
|
import superagent, { SuperAgentRequest } from 'superagent';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
async function _download(url: string, path: string, retry: number) {
|
async function _download(url: string, path: string, retry: number) {
|
||||||
@@ -11,6 +11,7 @@ async function _download(url: string, path: string, retry: number) {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function download(url: string): SuperAgentRequest
|
||||||
function download(url: string, path?: string, retry = 3) {
|
function download(url: string, path?: string, retry = 3) {
|
||||||
if (path) return _download(url, path, retry);
|
if (path) return _download(url, path, retry);
|
||||||
return superagent.get(url).retry(retry);
|
return superagent.get(url).retry(retry);
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
import assert from 'assert';
|
|
||||||
import superagent from 'superagent';
|
|
||||||
import download from './download';
|
|
||||||
import { ValidationError, RemoteOnlineJudgeError } from '../error';
|
|
||||||
|
|
||||||
const RE_SYZOJ = /https?:\/\/([a-zA-Z0-9.]+)\/problem\/([0-9]+)\/?/i;
|
|
||||||
|
|
||||||
export async function syzoj(url: string, handler: any) {
|
|
||||||
assert(url.match(RE_SYZOJ), new ValidationError('url'));
|
|
||||||
if (!url.endsWith('/')) url += '/';
|
|
||||||
const [, host, pid] = RE_SYZOJ.exec(url);
|
|
||||||
const res = await superagent.get(`${url}export`);
|
|
||||||
assert(res.status === 200, new RemoteOnlineJudgeError('Cannot connect to target server'));
|
|
||||||
assert(res.body.success, new RemoteOnlineJudgeError((res.body.error || {}).message));
|
|
||||||
const p = res.body.obj;
|
|
||||||
const content = [];
|
|
||||||
if (p.description) {
|
|
||||||
content.push(
|
|
||||||
handler.translate('problem.import.problem_description'),
|
|
||||||
p.description,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (p.input_format) {
|
|
||||||
content.push(
|
|
||||||
handler.translate('problem.import.input_format'),
|
|
||||||
p.input_format,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (p.output_format) {
|
|
||||||
content.push(
|
|
||||||
handler.translate('problem.import.output_format'),
|
|
||||||
p.output_format,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (p.hint) {
|
|
||||||
content.push(
|
|
||||||
handler.translate('problem.import.hint'),
|
|
||||||
p.hint,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (p.limit_and_hint) {
|
|
||||||
content.push(
|
|
||||||
handler.translate('problem.import.limit_and_hint'),
|
|
||||||
p.limit_and_hint,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (p.have_additional_file) {
|
|
||||||
content.push(
|
|
||||||
handler.translate('problem.import.additional_file'),
|
|
||||||
`${url}download/additional_file`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const pdoc = {
|
|
||||||
title: p.title,
|
|
||||||
content: content.join(' \n'),
|
|
||||||
owner: handler.user._id,
|
|
||||||
from: url,
|
|
||||||
pid: `${host}_${pid}`,
|
|
||||||
tags: p.tags,
|
|
||||||
config: {
|
|
||||||
time: p.time_limit,
|
|
||||||
memory: p.memory_limit * 1024,
|
|
||||||
filename: p.file_io_input_name,
|
|
||||||
type: p.type,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const r = download(`${url}testdata/download`);
|
|
||||||
return [pdoc, r];
|
|
||||||
}
|
|
||||||
|
|
||||||
global.Hydro.lib['import.syzoj'] = syzoj;
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
import { isNull } from 'lodash';
|
|
||||||
import { PERM, PRIV } from '../model/builtin';
|
|
||||||
|
|
||||||
global.Hydro.ui.nav = [];
|
|
||||||
|
|
||||||
const trueChecker = () => true;
|
|
||||||
const Checker = (perm: bigint, priv: number, checker: Function = trueChecker) => (handler) => (
|
|
||||||
checker(handler)
|
|
||||||
&& (perm ? handler.user.hasPerm(perm) : true)
|
|
||||||
&& (priv ? handler.user.hasPriv(priv) : true)
|
|
||||||
);
|
|
||||||
|
|
||||||
const Item = (
|
|
||||||
name: string, args: any, prefix: string,
|
|
||||||
...permPrivChecker: Array<number | bigint | Function>
|
|
||||||
) => {
|
|
||||||
let _priv: number;
|
|
||||||
let _perm: bigint;
|
|
||||||
let checker: Function = trueChecker;
|
|
||||||
for (const item of permPrivChecker) {
|
|
||||||
if (item instanceof Object && !isNull(item)) {
|
|
||||||
if (item instanceof Array) {
|
|
||||||
if (typeof item[0] === 'number') {
|
|
||||||
// @ts-ignore
|
|
||||||
_priv = item;
|
|
||||||
} else if (typeof item[0] === 'bigint') {
|
|
||||||
// @ts-ignore
|
|
||||||
_perm = item;
|
|
||||||
}
|
|
||||||
} else if (typeof item.call !== 'undefined') {
|
|
||||||
checker = item;
|
|
||||||
}
|
|
||||||
} else if (typeof item === 'number') {
|
|
||||||
_priv = item;
|
|
||||||
} else if (typeof item === 'bigint') {
|
|
||||||
_perm = item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checker = Checker(_perm, _priv, checker);
|
|
||||||
global.Hydro.ui.nav.push({
|
|
||||||
name, args: args || {}, prefix, checker,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Item('homepage', null, 'homepage');
|
|
||||||
Item('problem_main', null, 'problem', PERM.PERM_VIEW_PROBLEM);
|
|
||||||
Item('training_main', null, 'training', PERM.PERM_VIEW_TRAINING);
|
|
||||||
Item('homework_main', null, 'homework', PERM.PERM_VIEW_HOMEWORK);
|
|
||||||
Item('discussion_main', null, 'discussion', PERM.PERM_VIEW_DISCUSSION);
|
|
||||||
Item('contest_main', null, 'contest', PERM.PERM_VIEW_CONTEST);
|
|
||||||
Item('record_main', null, 'record');
|
|
||||||
Item('ranking', null, 'ranking', PERM.PERM_VIEW_RANKING);
|
|
||||||
Item('domain_dashboard', null, 'domain', PERM.PERM_EDIT_DOMAIN);
|
|
||||||
Item('manage_dashboard', null, 'manage', PRIV.PRIV_EDIT_SYSTEM);
|
|
||||||
|
|
||||||
global.Hydro.lib.nav = Item;
|
|
||||||
export = Item;
|
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import { Dictionary, isNull } from 'lodash';
|
||||||
|
import { PERM, PRIV } from '../model/builtin';
|
||||||
|
|
||||||
|
const trueChecker = () => true;
|
||||||
|
const Checker = (perm: bigint, priv: number, checker: Function = trueChecker) => (handler) => (
|
||||||
|
checker(handler)
|
||||||
|
&& (perm ? handler.user.hasPerm(perm) : true)
|
||||||
|
&& (priv ? handler.user.hasPriv(priv) : true)
|
||||||
|
);
|
||||||
|
const buildChecker = (...permPrivChecker: Array<number | bigint | Function>) => {
|
||||||
|
let _priv: number;
|
||||||
|
let _perm: bigint;
|
||||||
|
let checker: Function = trueChecker;
|
||||||
|
for (const item of permPrivChecker) {
|
||||||
|
if (item instanceof Object && !isNull(item)) {
|
||||||
|
if (item instanceof Array) {
|
||||||
|
if (typeof item[0] === 'number') {
|
||||||
|
// @ts-ignore
|
||||||
|
_priv = item;
|
||||||
|
} else if (typeof item[0] === 'bigint') {
|
||||||
|
// @ts-ignore
|
||||||
|
_perm = item;
|
||||||
|
}
|
||||||
|
} else if (typeof item.call !== 'undefined') {
|
||||||
|
checker = item;
|
||||||
|
}
|
||||||
|
} else if (typeof item === 'number') {
|
||||||
|
_priv = item;
|
||||||
|
} else if (typeof item === 'bigint') {
|
||||||
|
_perm = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Checker(_perm, _priv, checker);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Nav = (
|
||||||
|
name: string, args: Dictionary<any> = {}, prefix: string,
|
||||||
|
...permPrivChecker: Array<number | bigint | Function>
|
||||||
|
) => {
|
||||||
|
global.Hydro.ui.nodes.nav.push({
|
||||||
|
name, args: args || {}, prefix, checker: buildChecker(...permPrivChecker),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ProblemAdd = (
|
||||||
|
name: string, args: Dictionary<any> = {}, icon = 'add', text = 'Create Problem',
|
||||||
|
) => {
|
||||||
|
global.Hydro.ui.nodes.problem_add.push({
|
||||||
|
name, args, icon, text,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Nav('homepage', {}, 'homepage');
|
||||||
|
Nav('problem_main', {}, 'problem', PERM.PERM_VIEW_PROBLEM);
|
||||||
|
Nav('training_main', {}, 'training', PERM.PERM_VIEW_TRAINING);
|
||||||
|
Nav('homework_main', {}, 'homework', PERM.PERM_VIEW_HOMEWORK);
|
||||||
|
Nav('discussion_main', {}, 'discussion', PERM.PERM_VIEW_DISCUSSION);
|
||||||
|
Nav('contest_main', {}, 'contest', PERM.PERM_VIEW_CONTEST);
|
||||||
|
Nav('record_main', {}, 'record');
|
||||||
|
Nav('ranking', {}, 'ranking', PERM.PERM_VIEW_RANKING);
|
||||||
|
Nav('domain_dashboard', {}, 'domain', PERM.PERM_EDIT_DOMAIN);
|
||||||
|
Nav('manage_dashboard', {}, 'manage', PRIV.PRIV_EDIT_SYSTEM);
|
||||||
|
ProblemAdd('problem_create');
|
||||||
|
ProblemAdd('problem_import_syzoj', {}, 'copy', 'Import From SYZOJ');
|
||||||
|
|
||||||
|
global.Hydro.ui.Nav = Nav;
|
||||||
|
global.Hydro.ui.ProblemAdd = ProblemAdd;
|
||||||
@@ -24,9 +24,13 @@ if (!global.Hydro) {
|
|||||||
script: {},
|
script: {},
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
lib: {},
|
lib: {},
|
||||||
|
// @ts-ignore
|
||||||
ui: {
|
ui: {
|
||||||
manifest: {},
|
manifest: {},
|
||||||
|
nodes: {
|
||||||
nav: [],
|
nav: [],
|
||||||
|
problem_add: [],
|
||||||
|
},
|
||||||
template: {},
|
template: {},
|
||||||
},
|
},
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
@@ -807,6 +807,17 @@ export async function start() {
|
|||||||
skip: (req, res) => res.hasHeader('nolog'),
|
skip: (req, res) => res.hasHeader('nolog'),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
app.use(async (ctx, next) => {
|
||||||
|
const xff = await system.get('server.xff');
|
||||||
|
const ip = xff ? ctx.request.headers[xff] : ctx.request.ip;
|
||||||
|
try {
|
||||||
|
await opcount.inc('global', ip, 10, 100);
|
||||||
|
} catch (e) {
|
||||||
|
ctx.status = 429;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return await next();
|
||||||
|
});
|
||||||
app.use(router.routes()).use(router.allowedMethods());
|
app.use(router.routes()).use(router.allowedMethods());
|
||||||
server.listen(argv.port || port);
|
server.listen(argv.port || port);
|
||||||
console.log('Server listening at: %s', argv.port || port);
|
console.log('Server listening at: %s', argv.port || port);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/login-with-github",
|
"name": "@hydrooj/login-with-github",
|
||||||
"version": "0.0.6",
|
"version": "0.0.7",
|
||||||
"main": "package.json",
|
"main": "package.json",
|
||||||
"repository": "git@github.com:hydro-dev/Hydro.git",
|
"repository": "git@github.com:hydro-dev/Hydro.git",
|
||||||
"author": "undefined <masnn0@outlook.com>",
|
"author": "undefined <masnn0@outlook.com>",
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
"@types/superagent-proxy": "^2.0.0"
|
"@types/superagent-proxy": "^2.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"hydrooj": "^2.12.1"
|
"hydrooj": "^2.12.1||^2.13.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"superagent": "^6.1.0",
|
"superagent": "^6.1.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/login-with-google",
|
"name": "@hydrooj/login-with-google",
|
||||||
"version": "0.0.6",
|
"version": "0.0.7",
|
||||||
"main": "package.json",
|
"main": "package.json",
|
||||||
"repository": "git@github.com:hydro-dev/Hydro.git",
|
"repository": "git@github.com:hydro-dev/Hydro.git",
|
||||||
"author": "undefined <masnn0@outlook.com>",
|
"author": "undefined <masnn0@outlook.com>",
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
"@types/superagent-proxy": "^2.0.0"
|
"@types/superagent-proxy": "^2.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"hydrooj": "^2.12.1"
|
"hydrooj": "^2.12.1||^2.13.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"superagent": "^6.1.0",
|
"superagent": "^6.1.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/login-with-osu",
|
"name": "@hydrooj/login-with-osu",
|
||||||
"version": "0.0.6",
|
"version": "0.0.7",
|
||||||
"main": "package.json",
|
"main": "package.json",
|
||||||
"repository": "git@github.com:hydro-dev/Hydro.git",
|
"repository": "git@github.com:hydro-dev/Hydro.git",
|
||||||
"author": "undefined <masnn0@outlook.com>",
|
"author": "undefined <masnn0@outlook.com>",
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
"@types/superagent-proxy": "^2.0.0"
|
"@types/superagent-proxy": "^2.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"hydrooj": "^2.12.1"
|
"hydrooj": "^2.12.1||^2.13.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"superagent": "^6.1.0",
|
"superagent": "^6.1.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/login-with-qq",
|
"name": "@hydrooj/login-with-qq",
|
||||||
"version": "0.0.2",
|
"version": "0.0.3",
|
||||||
"main": "package.json",
|
"main": "package.json",
|
||||||
"repository": "git@github.com:hydro-dev/Hydro.git",
|
"repository": "git@github.com:hydro-dev/Hydro.git",
|
||||||
"author": "undefined <masnn0@outlook.com>",
|
"author": "undefined <masnn0@outlook.com>",
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"build": "tsc"
|
"build": "tsc"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"hydrooj": "^2.12.1"
|
"hydrooj": "^2.12.1||^2.13.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ws": "^7.3.1"
|
"ws": "^7.3.1"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/migrate-vijos",
|
"name": "@hydrooj/migrate-vijos",
|
||||||
"version": "1.3.6",
|
"version": "1.3.7",
|
||||||
"main": "package.json",
|
"main": "package.json",
|
||||||
"repository": "git@github.com:hydro-dev/Hydro.git",
|
"repository": "git@github.com:hydro-dev/Hydro.git",
|
||||||
"author": "undefined <masnn0@outlook.com>",
|
"author": "undefined <masnn0@outlook.com>",
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
"@types/mongodb": "^3.5.27"
|
"@types/mongodb": "^3.5.27"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"hydrooj": "^2.12.3"
|
"hydrooj": "^2.13.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"js-yaml": "^3.14.0",
|
"js-yaml": "^3.14.0",
|
||||||
|
|||||||
Reference in new issue
Block a user