mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
修复 @param 在类扩展时作用域污染的问题,完善interface
This commit is contained in:
1 parent
cd6938dd6c
commit
dd7914e1fb
31 files changed
+269
-179
No files matched your search
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"gruntfuggly.todo-tree",
|
||||
"ronnidc.nunjucks",
|
||||
"sysoev.language-stylus"
|
||||
]
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
Hydro: {
|
||||
model: any
|
||||
handler: any
|
||||
script: any
|
||||
service: any
|
||||
lib: any
|
||||
stat: any
|
||||
wiki: any
|
||||
template: any
|
||||
ui: any
|
||||
error: any
|
||||
locales: any
|
||||
}
|
||||
nodeModules: any
|
||||
onDestory: Function[]
|
||||
isFirstWorker: boolean
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'cluster' {
|
||||
let isFirstWorker: boolean;
|
||||
}
|
||||
|
||||
export { };
|
||||
@@ -98,7 +98,6 @@ export const DiscussionNodeNotFoundError = Err('DiscussionNodeNotFoundError', Do
|
||||
export const InvalidOperationError = Err('InvalidOperationError', MethodNotAllowedError);
|
||||
|
||||
global.Hydro.error = {
|
||||
Err,
|
||||
HydroError,
|
||||
BadRequestError,
|
||||
BlacklistedError,
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { ObjectID, GridFSBucket } from 'mongodb';
|
||||
import fs from 'fs';
|
||||
|
||||
export interface Setting {
|
||||
family: string,
|
||||
key: string,
|
||||
range: Array<[string, string]> | { [key: string]: string },
|
||||
value: any,
|
||||
type: string,
|
||||
name: string,
|
||||
desc: string,
|
||||
flag: number,
|
||||
}
|
||||
|
||||
export interface Pdoc {
|
||||
_id: ObjectID
|
||||
domainId: string
|
||||
docId: number
|
||||
pid: string
|
||||
owner: number
|
||||
title: string
|
||||
content: string
|
||||
nSubmit: number
|
||||
nAccept: number
|
||||
tag: string[]
|
||||
category: string[],
|
||||
data: ObjectID | null
|
||||
hidden: boolean
|
||||
config: string
|
||||
}
|
||||
|
||||
export interface TestCase {
|
||||
time: number,
|
||||
memory: number,
|
||||
status: number,
|
||||
message: string,
|
||||
}
|
||||
|
||||
export interface Rdoc {
|
||||
_id: ObjectID,
|
||||
domainId: string,
|
||||
pid: number
|
||||
uid: number,
|
||||
lang: string,
|
||||
code: string,
|
||||
score: number,
|
||||
memory: number,
|
||||
time: number,
|
||||
judgeTexts: string[],
|
||||
compilerTexts: string[],
|
||||
testCases: TestCase[],
|
||||
rejudged: boolean,
|
||||
judger: string,
|
||||
judgeAt: Date,
|
||||
status: number,
|
||||
type: string,
|
||||
hidden: boolean,
|
||||
input?: string,
|
||||
stdout?: string,
|
||||
stderr?: string,
|
||||
tid?: ObjectID,
|
||||
ttype?: number,
|
||||
}
|
||||
|
||||
export type ProblemImporter = (url: string, handler: any) =>
|
||||
Promise<[Pdoc, fs.ReadStream?]> | [Pdoc, fs.ReadStream?];
|
||||
|
||||
export interface Script {
|
||||
run: (args: any, report: Function) => any,
|
||||
description: string,
|
||||
validate: any,
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
Hydro: {
|
||||
model: {
|
||||
blacklist: typeof import('./model/blacklist'),
|
||||
builtin: typeof import('./model/builtin'),
|
||||
contest: typeof import('./model/contest'),
|
||||
discussion: typeof import('./model/discussion'),
|
||||
document: typeof import('./model/document'),
|
||||
domain: typeof import('./model/domain'),
|
||||
file: typeof import('./model/file'),
|
||||
message: typeof import('./model/message'),
|
||||
opcount: typeof import('./model/opcount'),
|
||||
problem: typeof import('./model/problem'),
|
||||
record: typeof import('./model/record'),
|
||||
setting: typeof import('./model/setting'),
|
||||
solution: typeof import('./model/solution'),
|
||||
system: typeof import('./model/system'),
|
||||
task: typeof import('./model/task'),
|
||||
token: typeof import('./model/token'),
|
||||
training: typeof import('./model/training'),
|
||||
user: typeof import('./model/user'),
|
||||
[key: string]: any,
|
||||
},
|
||||
handler: { [key: string]: Function },
|
||||
script: { [key: string]: Script },
|
||||
service: {
|
||||
bus: typeof import('./service/bus'),
|
||||
db: typeof import('./service/db'),
|
||||
gridfs: GridFSBucket,
|
||||
monitor: typeof import('./service/monitor'),
|
||||
server: typeof import('./service/server'),
|
||||
},
|
||||
lib: {
|
||||
download: typeof import('./lib/download').default,
|
||||
'hash.hydro': typeof import('./lib/hash.hydro').default,
|
||||
hpm: typeof import('./lib/hpm'),
|
||||
i18n: typeof import('./lib/i18n').default,
|
||||
'import.syzoj': typeof import('./lib/import.syzoj').syzoj,
|
||||
jwt: typeof import('./lib/jwt'),
|
||||
logger: typeof import('./lib/logger').default,
|
||||
mail: typeof import('./lib/mail'),
|
||||
markdown: typeof import('./lib/markdown'),
|
||||
md5: typeof import('./lib/md5').default,
|
||||
misc: typeof import('./lib/misc'),
|
||||
nav: typeof import('./lib/nav').default,
|
||||
paginate: typeof import('./lib/paginate').default,
|
||||
rank: typeof import('./lib/rank').default,
|
||||
rating: typeof import('./lib/rating').default,
|
||||
readConfig: typeof import('./lib/readConfig').default,
|
||||
sha1: typeof import('./lib/sha1').default,
|
||||
sysinfo: typeof import('./lib/sysinfo'),
|
||||
template: typeof import('./lib/template'),
|
||||
'testdata.convert.ini': typeof import('./lib/testdata.convert.ini').default,
|
||||
useragent: typeof import('./lib/useragent'),
|
||||
validator: typeof import('./lib/validator'),
|
||||
[key: string]: any
|
||||
},
|
||||
stat: any,
|
||||
wiki: { [category: string]: { [page: string]: any } },
|
||||
template: { [key: string]: string },
|
||||
ui: any,
|
||||
error: typeof import('./error'),
|
||||
locales: { [id: string]: { [key: string]: string } },
|
||||
},
|
||||
nodeModules: any,
|
||||
onDestory: Function[],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'cluster' {
|
||||
let isFirstWorker: boolean;
|
||||
}
|
||||
@@ -11,7 +11,7 @@ async function _download(url: string, path: string, retry: number) {
|
||||
return path;
|
||||
}
|
||||
|
||||
export default function download(url: string, path: string | undefined | null, retry = 3) {
|
||||
export default function download(url: string, path?: string, retry = 3) {
|
||||
if (path) return _download(url, path, retry);
|
||||
return superagent.get(url).retry(retry);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
const assert = require('assert');
|
||||
import assert from 'assert';
|
||||
import superagent from 'superagent';
|
||||
import download from './download';
|
||||
import { ValidationError, RemoteOnlineJudgeError } from '../error';
|
||||
|
||||
const { download } = global.Hydro.lib;
|
||||
const { superagent } = global.nodeModules;
|
||||
const { ValidationError, RemoteOnlineJudgeError } = global.Hydro.error;
|
||||
const RE_SYZOJ = /https?:\/\/([a-zA-Z0-9.]+)\/problem\/([0-9]+)\/?/i;
|
||||
|
||||
async function syzoj(url, handler) {
|
||||
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);
|
||||
@@ -68,4 +68,4 @@ async function syzoj(url, handler) {
|
||||
return [pdoc, r];
|
||||
}
|
||||
|
||||
global.Hydro.lib['import.syzoj'] = module.exports = syzoj;
|
||||
global.Hydro.lib['import.syzoj'] = syzoj;
|
||||
+1
-1
@@ -56,7 +56,7 @@ export function size(s, base = 1) {
|
||||
return '{0} {1}'.format(Math.round(s * unit), unitNames[unitNames.length - 1]);
|
||||
}
|
||||
|
||||
export function _digit2(number: number) {
|
||||
function _digit2(number: number) {
|
||||
if (number < 10) return `0${number}`;
|
||||
return number.toString();
|
||||
}
|
||||
|
||||
@@ -17,4 +17,5 @@ async function readConfig(filePath: string) {
|
||||
}
|
||||
|
||||
global.Hydro.lib.readConfig = readConfig;
|
||||
|
||||
export default readConfig;
|
||||
@@ -9,4 +9,3 @@ export function icon(str: string) {
|
||||
}
|
||||
|
||||
global.Hydro.lib.useragent = { parse, icon };
|
||||
export default { parse, icon };
|
||||
+5
-1
@@ -2,20 +2,24 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
/* eslint-disable no-eval */
|
||||
|
||||
import './declare';
|
||||
import './interface';
|
||||
import cluster from 'cluster';
|
||||
import { argv } from 'yargs';
|
||||
|
||||
global.Hydro = {
|
||||
stat: { reqCount: 0 },
|
||||
handler: {},
|
||||
// @ts-ignore
|
||||
service: {},
|
||||
// @ts-ignore
|
||||
model: {},
|
||||
script: {},
|
||||
// @ts-ignore
|
||||
lib: {},
|
||||
wiki: {},
|
||||
template: {},
|
||||
ui: {},
|
||||
// @ts-ignore
|
||||
error: {},
|
||||
locales: {},
|
||||
};
|
||||
|
||||
@@ -609,6 +609,7 @@ export const USER_GENDER_ICONS = {
|
||||
};
|
||||
|
||||
global.Hydro.model.builtin = {
|
||||
Permission,
|
||||
PERM,
|
||||
PERMS,
|
||||
PERMS_BY_FAMILY,
|
||||
|
||||
@@ -531,7 +531,7 @@ export function getMulti(domainId: string, query = {}, type = document.TYPE_CONT
|
||||
return document.getMulti(domainId, type, query);
|
||||
}
|
||||
|
||||
export function _getStatusJournal(tsdoc) {
|
||||
function _getStatusJournal(tsdoc) {
|
||||
return tsdoc.journal.sort((a, b) => (a.rid.generationTime - b.rid.generationTime));
|
||||
}
|
||||
|
||||
|
||||
@@ -222,6 +222,7 @@ global.Hydro.model.discussion = {
|
||||
setStar,
|
||||
getStatus,
|
||||
addNode,
|
||||
getNode,
|
||||
getNodes,
|
||||
getVnode,
|
||||
getListVnodes,
|
||||
|
||||
@@ -417,5 +417,3 @@ global.Hydro.model.document = {
|
||||
TYPE_FILE,
|
||||
TYPE_TRAINING,
|
||||
};
|
||||
|
||||
export default global.Hydro.model.document;
|
||||
+2
-17
@@ -3,26 +3,10 @@ import { STATUS } from './builtin';
|
||||
import * as file from './file';
|
||||
import * as document from './document';
|
||||
import * as domain from './domain';
|
||||
import { Pdoc } from '../interface';
|
||||
import { ProblemNotFoundError } from '../error';
|
||||
import readConfig from '../lib/readConfig';
|
||||
|
||||
export interface Pdoc {
|
||||
_id: ObjectID
|
||||
domainId: string
|
||||
docId: number
|
||||
pid: string
|
||||
owner: number
|
||||
title: string
|
||||
content: string
|
||||
nSubmit: number
|
||||
nAccept: number
|
||||
tag: string[]
|
||||
category: string[],
|
||||
data: ObjectID | null
|
||||
hidden: boolean
|
||||
config: string
|
||||
}
|
||||
|
||||
export const pdocHidden: Pdoc = {
|
||||
_id: new ObjectID(),
|
||||
domainId: 'system',
|
||||
@@ -180,6 +164,7 @@ export async function setTestdata(domainId: string, _id: number, filePath: strin
|
||||
}
|
||||
|
||||
global.Hydro.model.problem = {
|
||||
pdocHidden,
|
||||
add,
|
||||
inc,
|
||||
get,
|
||||
|
||||
+9
-37
@@ -1,45 +1,15 @@
|
||||
import _ from 'lodash';
|
||||
import yaml from 'js-yaml';
|
||||
import { ObjectID, FilterQuery } from 'mongodb';
|
||||
import { ObjectID } from 'mongodb';
|
||||
import { STATUS } from './builtin';
|
||||
import * as task from './task';
|
||||
import * as problem from './problem';
|
||||
import { Rdoc, TestCase } from '../interface';
|
||||
import { RecordNotFoundError } from '../error';
|
||||
import * as db from '../service/db';
|
||||
|
||||
const coll = db.collection('record');
|
||||
|
||||
export interface TestCase {
|
||||
time: number,
|
||||
memory: number,
|
||||
status: number,
|
||||
message: string,
|
||||
}
|
||||
|
||||
export interface Rdoc {
|
||||
_id: ObjectID,
|
||||
domainId: string,
|
||||
pid: ObjectID
|
||||
uid: number,
|
||||
lang: string,
|
||||
code: string,
|
||||
score: number,
|
||||
memory: number,
|
||||
time: number,
|
||||
judgeTexts: string[],
|
||||
compilerTexts: string[],
|
||||
testCases: TestCase[],
|
||||
rejudged: boolean,
|
||||
judger: string,
|
||||
judgeAt: Date,
|
||||
status: number,
|
||||
type: string,
|
||||
hidden: boolean,
|
||||
input?: string,
|
||||
tid?: ObjectID,
|
||||
ttype?: number,
|
||||
}
|
||||
|
||||
export interface RdocBase {
|
||||
_id?: ObjectID,
|
||||
domainId?: string,
|
||||
@@ -119,7 +89,7 @@ export async function add(domainId: string, data: RdocBase, addTask = true) {
|
||||
return res.insertedId;
|
||||
}
|
||||
|
||||
export async function get(domainId: string, _id: ObjectID) {
|
||||
export async function get(domainId: string, _id: ObjectID): Promise<Rdoc> {
|
||||
const rdoc = await coll.findOne({ domainId, _id });
|
||||
if (!rdoc) throw new RecordNotFoundError(_id);
|
||||
return rdoc;
|
||||
@@ -132,7 +102,7 @@ export function getMulti(domainId: string, query: any) {
|
||||
export async function update(
|
||||
domainId: string, _id: ObjectID,
|
||||
$set: any = {}, $push: any = {}, $unset: any = {},
|
||||
) {
|
||||
): Promise<Rdoc> {
|
||||
const $update: any = {};
|
||||
if ($set && Object.keys($set).length) $update.$set = $set;
|
||||
if ($push && Object.keys($push).length) $update.$push = $push;
|
||||
@@ -157,11 +127,13 @@ export function reset(domainId: string, rid: ObjectID) {
|
||||
});
|
||||
}
|
||||
|
||||
export function count<T>(domainId: string, query: FilterQuery<T>) {
|
||||
export function count(domainId: string, query: any) {
|
||||
return coll.find({ domainId, ...query }).count();
|
||||
}
|
||||
|
||||
export async function getList(domainId: string, rids: ObjectID[], showHidden = false) {
|
||||
export async function getList(
|
||||
domainId: string, rids: ObjectID[], showHidden = false,
|
||||
): Promise<{ [key: string]: Rdoc }> {
|
||||
const r = {};
|
||||
for (const rid of rids) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
@@ -184,7 +156,7 @@ export function getUserInProblemMulti(
|
||||
return coll.find({ domainId, uid, pid });
|
||||
}
|
||||
|
||||
export function getByUid(domainId: string, uid: number) {
|
||||
export function getByUid(domainId: string, uid: number): Promise<Rdoc[]> {
|
||||
return coll.find({ domainId, uid }).toArray();
|
||||
}
|
||||
|
||||
|
||||
+11
-10
@@ -1,8 +1,9 @@
|
||||
import moment from 'moment-timezone';
|
||||
import * as builtin from './builtin';
|
||||
import { Setting as _Setting } from '../interface';
|
||||
|
||||
const countries = moment.tz.countries();
|
||||
const tzs = new Set();
|
||||
const tzs: Set<string> = new Set();
|
||||
for (const country of countries) {
|
||||
const tz = moment.tz.zonesForCountry(country);
|
||||
for (const t of tz) tzs.add(t);
|
||||
@@ -25,40 +26,40 @@ export const DOMAIN_SETTINGS_BY_KEY = {};
|
||||
export const SYSTEM_SETTINGS_BY_KEY = {};
|
||||
|
||||
export const Setting = (
|
||||
family, key, range = null,
|
||||
value = null, type = 'text', name = '',
|
||||
family: string, key: string, range: Array<[string, string]> | { [key: string]: string } = null,
|
||||
value: any = null, type = 'text', name = '',
|
||||
desc = '', flag = 0,
|
||||
) => ({
|
||||
): _Setting => ({
|
||||
family, key, range, value, type, name, desc, flag,
|
||||
});
|
||||
|
||||
export const PreferenceSetting = (...settings) => {
|
||||
export const PreferenceSetting = (...settings: _Setting[]) => {
|
||||
for (const setting of settings) {
|
||||
PREFERENCE_SETTINGS.push(setting);
|
||||
SETTINGS.push(setting);
|
||||
SETTINGS_BY_KEY[setting.key] = setting;
|
||||
}
|
||||
};
|
||||
export const AccountSetting = (...settings) => {
|
||||
export const AccountSetting = (...settings: _Setting[]) => {
|
||||
for (const setting of settings) {
|
||||
ACCOUNT_SETTINGS.push(setting);
|
||||
SETTINGS.push(setting);
|
||||
SETTINGS_BY_KEY[setting.key] = setting;
|
||||
}
|
||||
};
|
||||
export const DomainUserSetting = (...settings) => {
|
||||
export const DomainUserSetting = (...settings: _Setting[]) => {
|
||||
for (const setting of settings) {
|
||||
DOMAIN_USER_SETTINGS.push(setting);
|
||||
DOMAIN_USER_SETTINGS_BY_KEY[setting.key] = setting;
|
||||
}
|
||||
};
|
||||
export const DomainSetting = (...settings) => {
|
||||
export const DomainSetting = (...settings: _Setting[]) => {
|
||||
for (const setting of settings) {
|
||||
DOMAIN_SETTINGS.push(setting);
|
||||
DOMAIN_SETTINGS_BY_KEY[setting.key] = setting;
|
||||
}
|
||||
};
|
||||
export const SystemSetting = (...settings) => {
|
||||
export const SystemSetting = (...settings: _Setting[]) => {
|
||||
for (const setting of settings) {
|
||||
SYSTEM_SETTINGS.push(setting);
|
||||
SYSTEM_SETTINGS_BY_KEY[setting.key] = setting;
|
||||
@@ -69,7 +70,7 @@ PreferenceSetting(
|
||||
// TODO generate by global.Hydro.locales
|
||||
Setting('setting_display', 'viewLang', builtin.VIEW_LANGS.map((i) => [i.code, i.name]),
|
||||
'zh_CN', 'select', 'UI Language'),
|
||||
Setting('setting_display', 'timezone', timezones,
|
||||
Setting('setting_display', 'timezone', timezones as [string, string][],
|
||||
'Asia/Shanghai', 'select', 'Timezone'),
|
||||
Setting('setting_usage', 'codeLang', builtin.LANG_TEXTS,
|
||||
null, 'select', 'Default Code Language'),
|
||||
|
||||
@@ -4,12 +4,6 @@ import * as db from '../service/db';
|
||||
|
||||
const coll = db.collection('task');
|
||||
|
||||
export interface Task {
|
||||
_id: ObjectID,
|
||||
count: number,
|
||||
executeAfter: number,
|
||||
}
|
||||
|
||||
export async function add(task: any) {
|
||||
const t = { ...task };
|
||||
if (typeof t.executeAfter === 'object') t.executeAfter = t.executeAfter.getTime();
|
||||
|
||||
@@ -90,6 +90,7 @@ global.Hydro.model.token = {
|
||||
TYPE_CSRF_TOKEN,
|
||||
TYPE_OAUTH,
|
||||
TYPE_REGISTRATION,
|
||||
TYPE_LOSTPASS,
|
||||
|
||||
ensureIndexes,
|
||||
add,
|
||||
|
||||
@@ -304,6 +304,7 @@ export function ensureIndexes() {
|
||||
}
|
||||
|
||||
global.Hydro.model.user = {
|
||||
User,
|
||||
changePassword,
|
||||
create,
|
||||
getByEmail,
|
||||
|
||||
@@ -43,5 +43,3 @@ export function publish(event, payload, isMaster = true) {
|
||||
global.Hydro.service.bus = {
|
||||
subscribe, unsubscribe, publish,
|
||||
};
|
||||
|
||||
export default global.Hydro.service.bus;
|
||||
+1
-3
@@ -19,6 +19,4 @@ export function collection(c: string) {
|
||||
return db.collection(c);
|
||||
}
|
||||
|
||||
global.Hydro.service.db = { collection };
|
||||
|
||||
export default { collection };
|
||||
global.Hydro.service.db = { collection, db };
|
||||
@@ -1,8 +1,8 @@
|
||||
import { GridFSBucket } from 'mongodb';
|
||||
import { db } from './db';
|
||||
|
||||
const exp = new GridFSBucket(db);
|
||||
export const fs = new GridFSBucket(db);
|
||||
|
||||
global.Hydro.service.gridfs = exp;
|
||||
global.Hydro.service.gridfs = fs;
|
||||
|
||||
export default exp;
|
||||
export default fs;
|
||||
@@ -3,7 +3,7 @@ import * as sysinfo from '../lib/sysinfo';
|
||||
|
||||
const coll = db.collection('status');
|
||||
|
||||
async function update() {
|
||||
export async function update() {
|
||||
const [mid, $set] = await sysinfo.update();
|
||||
await coll.updateOne(
|
||||
{ mid, type: 'server' },
|
||||
@@ -13,7 +13,7 @@ async function update() {
|
||||
global.Hydro.stat.reqCount = 0;
|
||||
}
|
||||
|
||||
async function postInit() {
|
||||
export async function postInit() {
|
||||
const info = await sysinfo.get();
|
||||
await coll.updateOne(
|
||||
{ mid: info.mid, type: 'server' },
|
||||
@@ -23,6 +23,4 @@ async function postInit() {
|
||||
setInterval(update, 60 * 1000);
|
||||
}
|
||||
|
||||
global.Hydro.service.monitor = { postInit };
|
||||
|
||||
export default { postInit };
|
||||
global.Hydro.service.monitor = { update, postInit };
|
||||
@@ -138,12 +138,13 @@ export function param(...args: any): MethodDecorator {
|
||||
}
|
||||
return function desc(target: any, funcName: string, obj: any) {
|
||||
if (!target.__param) target.__param = {};
|
||||
if (!target.__param[funcName]) {
|
||||
target.__param[funcName] = [{ name: 'domainId', type: 'string' }];
|
||||
if (!target.__param[target.constructor.name]) target.__param[target.constructor.name] = {};
|
||||
if (!target.__param[target.constructor.name][funcName]) {
|
||||
target.__param[target.constructor.name][funcName] = [{ name: 'domainId', type: 'string' }];
|
||||
const originalMethod = obj.value;
|
||||
obj.value = function func(rawArgs: any) {
|
||||
const c = [];
|
||||
const arglist: ParamOption[] = this.__param[funcName];
|
||||
const arglist: ParamOption[] = this.__param[target.constructor.name][funcName];
|
||||
for (const item of arglist) {
|
||||
if (!item.isOptional || rawArgs[item.name]) {
|
||||
if (!rawArgs[item.name]) throw new ValidationError(item.name);
|
||||
@@ -160,7 +161,7 @@ export function param(...args: any): MethodDecorator {
|
||||
return originalMethod.call(this, ...c);
|
||||
};
|
||||
}
|
||||
target.__param[funcName].splice(1, 0, ...d);
|
||||
target.__param[target.constructor.name][funcName].splice(1, 0, ...d);
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -63,6 +63,12 @@ problem_statistics: Problem Statistics
|
||||
problem_submit: Problem Submit
|
||||
problem-category-delim: '|'
|
||||
problem-subcategory-delim: ', '
|
||||
problem.import.additional_file: '## Additional Files'
|
||||
problem.import.hint: '## Hint'
|
||||
problem.import.input_format: '## Input Format'
|
||||
problem.import.limit_and_hint: '## Limits'
|
||||
problem.import.output_format: '## Output Format'
|
||||
problem.import.problem_description: '## Description'
|
||||
ranking: Ranking
|
||||
record_detail: Record Detail
|
||||
record_main: Judging Queue
|
||||
|
||||
@@ -337,7 +337,9 @@ hour(s): 小时
|
||||
If enabled, source code will be emailed to you after the submission is accepted.: 如果启用,在您通过题目后,源代码会以 Email 的形式发送给您。
|
||||
If left blank, the built-in template of the corresponding language will be used.: 若留空,则将使用对应语言的内置代码模板。
|
||||
Images: 图片
|
||||
Import problem from syzoj.: 从运行 syzoj 系统的 OJ 导入题目。
|
||||
Import Problem: 导入题目
|
||||
import: 导入
|
||||
In 1 day: 一天后
|
||||
In 1 month: 一个月后
|
||||
In 1 week: 一周后
|
||||
@@ -516,6 +518,12 @@ problem_submit: 递交代码
|
||||
problem-category-delim: '|'
|
||||
problem-subcategory-delim: 、
|
||||
Problem: 题目
|
||||
problem.import.additional_file: '## 附加文件'
|
||||
problem.import.hint: '## 提示'
|
||||
problem.import.input_format: '## 输入格式'
|
||||
problem.import.limit_and_hint: '## 限制'
|
||||
problem.import.output_format: '## 输出格式'
|
||||
problem.import.problem_description: '## 题目描述'
|
||||
Problems Sets: 题库
|
||||
Problems: 题目
|
||||
Profile Background Image: 背景图片
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# Problem-Import-Syzoj
|
||||
|
||||
从运行 syzoj 系统的 OJ 导入题目。
|
||||
|
||||
使用方式:题目->导入题目(`/problem/import`)->选择类型:syzoj
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"id": "problem-import-syzoj",
|
||||
"version": "1.0.1",
|
||||
"description": "Import problem from syzoj."
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
Import problem from syzoj.: 从运行 syzoj 系统的 OJ 导入题目。
|
||||
problem.import.problem_description: '## 题目描述'
|
||||
problem.import.input_format: '## 输入格式'
|
||||
problem.import.output_format: '## 输出格式'
|
||||
problem.import.hint: '## 提示'
|
||||
problem.import.limit_and_hint: '## 限制'
|
||||
problem.import.additional_file: '## 附加文件'
|
||||
import: 导入
|
||||
@@ -63,16 +63,16 @@ class CustomHandler extends Handler {
|
||||
// this.checkPerm(), this.user.hasPerm(), this.user.hasPriv(), etc.
|
||||
}
|
||||
|
||||
async get({ username, password }) {
|
||||
async get(){
|
||||
this.response.template = 'user_login.html';
|
||||
}
|
||||
|
||||
async post({ username, password }) {
|
||||
const udoc = await user.getByUname(username);
|
||||
udoc.checkPassword(password);
|
||||
this.response.body = { udoc };
|
||||
}
|
||||
|
||||
async post() {
|
||||
// 当提交表单时会执行该函数
|
||||
}
|
||||
|
||||
async postConfirm() {
|
||||
// 当提交表单并存在 operation 值为 confirm 时执行。
|
||||
}
|
||||
@@ -82,7 +82,7 @@ async function apply() {
|
||||
Route('/route/:username', CustomHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.handlerName = module.exports = apply;
|
||||
global.Hydro.handler.handlerName = apply;
|
||||
```
|
||||
|
||||
在路由中定义所有的函数应均为异步函数,支持的函数如下:
|
||||
@@ -92,31 +92,7 @@ prepare, get, post, post[Operation], cleanup
|
||||
具体流程如下:
|
||||
|
||||
先执行 prepare(args) (如果存在)
|
||||
args 为传入的参数集合(包括 QueryString, Body, Path)中的全部参数,并对以下字段进行了校验:
|
||||
|
||||
| Key | Type |
|
||||
|:--------:|:----------------:|
|
||||
| content | string |
|
||||
| title | string |
|
||||
| uid | number(int) |
|
||||
| password | string |
|
||||
| mail | string(mail) |
|
||||
| uname | string |
|
||||
| page | number(int) |
|
||||
| duration | number(float) |
|
||||
| role | string |
|
||||
| roles | string[] |
|
||||
| pids | string |
|
||||
| tid | mongodb.ObjectID |
|
||||
| rid | mongodb.ObjectID |
|
||||
| did | mongodb.ObjectID |
|
||||
| drid | mongodb.ObjectID |
|
||||
| drrid | mongodb.ObjectID |
|
||||
| psid | mongodb.ObjectID |
|
||||
| psrid | mongodb.ObjectID |
|
||||
| docId | mongodb.ObjectID |
|
||||
| mongoId | mongodb.ObjectID |
|
||||
|
||||
args 为传入的参数集合(包括 QueryString, Body, Path)中的全部参数,
|
||||
再执行 prepare(args) (如果存在)
|
||||
检查请求类型:
|
||||
|
||||
@@ -140,6 +116,43 @@ args 为传入的参数集合(包括 QueryString, Body, Path)中的全部参
|
||||
应当提供 `apply` 函数,并与定义的 Handler 一同挂载到 `global.Hydro.handler[模块名]` 位置。
|
||||
`apply` 函数将在初始化阶段被调用。
|
||||
|
||||
### 表单验证
|
||||
|
||||
若使用 Typescript 开发插件,可使用 Hydro 提供的验证工具。
|
||||
|
||||
`@param` 会修改 arguments,首个参数为请求所在的 domainId,剩余参数为指定的内容。
|
||||
|
||||
```ts
|
||||
const { Handler, Route, Types, param } = global.Hydro.service.server;
|
||||
const { user, builtin } = global.Hydro.model;
|
||||
|
||||
class CustomHandler extends Handler {
|
||||
async prepare() {
|
||||
this.checkPriv(builtin.PRIV.PRIV_USER_PROFILE);
|
||||
}
|
||||
|
||||
async get(){
|
||||
this.response.template = 'user_login.html';
|
||||
}
|
||||
|
||||
@param('username', Types.String)
|
||||
@param('password', Types.String)
|
||||
async post(domainId:string, username:string, password:string) {
|
||||
const udoc = await user.getByUname(username);
|
||||
udoc.checkPassword(password);
|
||||
this.response.body = { udoc };
|
||||
}
|
||||
}
|
||||
|
||||
export async function apply() {
|
||||
Route('/route/:username', CustomHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.handlerName = apply;
|
||||
```
|
||||
|
||||
若使用 Javascript 开发插件,则可使用 `global.Hydro.lib.validator` 中提供的相关工具。
|
||||
|
||||
# Service | service
|
||||
|
||||
通常用于提供与其他程序对接的接口或启动其他外部程序。(如内置的 MongoDB / 外置的沙箱模块等)
|
||||
|
||||
Reference in new issue
Block a user