From dd7914e1fb2944d6632581717f611d3a208b9d69 Mon Sep 17 00:00:00 2001 From: undefined Date: Sat, 11 Jul 2020 13:35:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20@param=20=E5=9C=A8?= =?UTF-8?q?=E7=B1=BB=E6=89=A9=E5=B1=95=E6=97=B6=E4=BD=9C=E7=94=A8=E5=9F=9F?= =?UTF-8?q?=E6=B1=A1=E6=9F=93=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C=E5=AE=8C?= =?UTF-8?q?=E5=96=84interface?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/extensions.json | 8 + hydro/declare.ts | 28 ---- hydro/error.ts | 1 - hydro/interface.ts | 149 ++++++++++++++++++ hydro/lib/download.ts | 2 +- .../lib.js => hydro/lib/import.syzoj.ts | 14 +- hydro/lib/misc.ts | 2 +- hydro/lib/readConfig.ts | 1 + hydro/lib/useragent.ts | 1 - hydro/loader.ts | 6 +- hydro/model/builtin.ts | 1 + hydro/model/contest.ts | 2 +- hydro/model/discussion.ts | 1 + hydro/model/document.ts | 2 - hydro/model/problem.ts | 19 +-- hydro/model/record.ts | 46 ++---- hydro/model/setting.ts | 21 +-- hydro/model/task.ts | 6 - hydro/model/token.ts | 1 + hydro/model/user.ts | 1 + hydro/service/bus.ts | 2 - hydro/service/db.ts | 4 +- hydro/service/gridfs.ts | 6 +- hydro/service/monitor.ts | 8 +- hydro/service/server.ts | 9 +- locales/en.yaml | 6 + locales/zh_CN.yaml | 8 + module/problem-import-syzoj/README.md | 5 - module/problem-import-syzoj/hydro.json | 5 - module/problem-import-syzoj/locale/zh_CN.yaml | 8 - wiki/development/development.md | 75 +++++---- 31 files changed, 269 insertions(+), 179 deletions(-) create mode 100644 .vscode/extensions.json delete mode 100644 hydro/declare.ts create mode 100644 hydro/interface.ts rename module/problem-import-syzoj/lib.js => hydro/lib/import.syzoj.ts (83%) delete mode 100644 module/problem-import-syzoj/README.md delete mode 100644 module/problem-import-syzoj/hydro.json delete mode 100644 module/problem-import-syzoj/locale/zh_CN.yaml diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..772d9684 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "gruntfuggly.todo-tree", + "ronnidc.nunjucks", + "sysoev.language-stylus" + ] +} \ No newline at end of file diff --git a/hydro/declare.ts b/hydro/declare.ts deleted file mode 100644 index 93f36449..00000000 --- a/hydro/declare.ts +++ /dev/null @@ -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 { }; diff --git a/hydro/error.ts b/hydro/error.ts index 3d7afa26..55ec7943 100644 --- a/hydro/error.ts +++ b/hydro/error.ts @@ -98,7 +98,6 @@ export const DiscussionNodeNotFoundError = Err('DiscussionNodeNotFoundError', Do export const InvalidOperationError = Err('InvalidOperationError', MethodNotAllowedError); global.Hydro.error = { - Err, HydroError, BadRequestError, BlacklistedError, diff --git a/hydro/interface.ts b/hydro/interface.ts new file mode 100644 index 00000000..08cd8562 --- /dev/null +++ b/hydro/interface.ts @@ -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; +} diff --git a/hydro/lib/download.ts b/hydro/lib/download.ts index e6aa1979..b885ae82 100644 --- a/hydro/lib/download.ts +++ b/hydro/lib/download.ts @@ -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); } diff --git a/module/problem-import-syzoj/lib.js b/hydro/lib/import.syzoj.ts similarity index 83% rename from module/problem-import-syzoj/lib.js rename to hydro/lib/import.syzoj.ts index 62b9f5a4..88adc7c1 100644 --- a/module/problem-import-syzoj/lib.js +++ b/hydro/lib/import.syzoj.ts @@ -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; diff --git a/hydro/lib/misc.ts b/hydro/lib/misc.ts index b1bcf6e4..db5bb016 100644 --- a/hydro/lib/misc.ts +++ b/hydro/lib/misc.ts @@ -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(); } diff --git a/hydro/lib/readConfig.ts b/hydro/lib/readConfig.ts index 27fa6aad..654b1959 100644 --- a/hydro/lib/readConfig.ts +++ b/hydro/lib/readConfig.ts @@ -17,4 +17,5 @@ async function readConfig(filePath: string) { } global.Hydro.lib.readConfig = readConfig; + export default readConfig; diff --git a/hydro/lib/useragent.ts b/hydro/lib/useragent.ts index e414b504..3beb1e43 100644 --- a/hydro/lib/useragent.ts +++ b/hydro/lib/useragent.ts @@ -9,4 +9,3 @@ export function icon(str: string) { } global.Hydro.lib.useragent = { parse, icon }; -export default { parse, icon }; diff --git a/hydro/loader.ts b/hydro/loader.ts index ff6887b2..fbec6e86 100644 --- a/hydro/loader.ts +++ b/hydro/loader.ts @@ -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: {}, }; diff --git a/hydro/model/builtin.ts b/hydro/model/builtin.ts index 7c83b6f2..d819611b 100644 --- a/hydro/model/builtin.ts +++ b/hydro/model/builtin.ts @@ -609,6 +609,7 @@ export const USER_GENDER_ICONS = { }; global.Hydro.model.builtin = { + Permission, PERM, PERMS, PERMS_BY_FAMILY, diff --git a/hydro/model/contest.ts b/hydro/model/contest.ts index f43ec401..8a402bcc 100644 --- a/hydro/model/contest.ts +++ b/hydro/model/contest.ts @@ -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)); } diff --git a/hydro/model/discussion.ts b/hydro/model/discussion.ts index c85157dd..c37aadf2 100644 --- a/hydro/model/discussion.ts +++ b/hydro/model/discussion.ts @@ -222,6 +222,7 @@ global.Hydro.model.discussion = { setStar, getStatus, addNode, + getNode, getNodes, getVnode, getListVnodes, diff --git a/hydro/model/document.ts b/hydro/model/document.ts index 40a9b5d0..9f288537 100644 --- a/hydro/model/document.ts +++ b/hydro/model/document.ts @@ -417,5 +417,3 @@ global.Hydro.model.document = { TYPE_FILE, TYPE_TRAINING, }; - -export default global.Hydro.model.document; diff --git a/hydro/model/problem.ts b/hydro/model/problem.ts index d5cc54ed..1388ea0c 100644 --- a/hydro/model/problem.ts +++ b/hydro/model/problem.ts @@ -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, diff --git a/hydro/model/record.ts b/hydro/model/record.ts index 89618ab4..1121adae 100644 --- a/hydro/model/record.ts +++ b/hydro/model/record.ts @@ -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 { 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 { 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(domainId: string, query: FilterQuery) { +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 { return coll.find({ domainId, uid }).toArray(); } diff --git a/hydro/model/setting.ts b/hydro/model/setting.ts index 9f5757b5..b94913cd 100644 --- a/hydro/model/setting.ts +++ b/hydro/model/setting.ts @@ -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 = 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'), diff --git a/hydro/model/task.ts b/hydro/model/task.ts index 0b204bb5..8c8f5b79 100644 --- a/hydro/model/task.ts +++ b/hydro/model/task.ts @@ -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(); diff --git a/hydro/model/token.ts b/hydro/model/token.ts index 2cec9fbb..a51826a1 100644 --- a/hydro/model/token.ts +++ b/hydro/model/token.ts @@ -90,6 +90,7 @@ global.Hydro.model.token = { TYPE_CSRF_TOKEN, TYPE_OAUTH, TYPE_REGISTRATION, + TYPE_LOSTPASS, ensureIndexes, add, diff --git a/hydro/model/user.ts b/hydro/model/user.ts index 2e29d1ce..55093983 100644 --- a/hydro/model/user.ts +++ b/hydro/model/user.ts @@ -304,6 +304,7 @@ export function ensureIndexes() { } global.Hydro.model.user = { + User, changePassword, create, getByEmail, diff --git a/hydro/service/bus.ts b/hydro/service/bus.ts index 45c7a652..2285aa8b 100644 --- a/hydro/service/bus.ts +++ b/hydro/service/bus.ts @@ -43,5 +43,3 @@ export function publish(event, payload, isMaster = true) { global.Hydro.service.bus = { subscribe, unsubscribe, publish, }; - -export default global.Hydro.service.bus; diff --git a/hydro/service/db.ts b/hydro/service/db.ts index dcdc5fcf..fe47ff0d 100644 --- a/hydro/service/db.ts +++ b/hydro/service/db.ts @@ -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 }; diff --git a/hydro/service/gridfs.ts b/hydro/service/gridfs.ts index 2582b312..0491b6a5 100644 --- a/hydro/service/gridfs.ts +++ b/hydro/service/gridfs.ts @@ -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; diff --git a/hydro/service/monitor.ts b/hydro/service/monitor.ts index b13199e3..a2e8ebf5 100644 --- a/hydro/service/monitor.ts +++ b/hydro/service/monitor.ts @@ -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 }; diff --git a/hydro/service/server.ts b/hydro/service/server.ts index c52d7f0a..d2f2d1ab 100644 --- a/hydro/service/server.ts +++ b/hydro/service/server.ts @@ -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; }; } diff --git a/locales/en.yaml b/locales/en.yaml index 3ea82366..00a2db3d 100644 --- a/locales/en.yaml +++ b/locales/en.yaml @@ -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 diff --git a/locales/zh_CN.yaml b/locales/zh_CN.yaml index 0c63b741..f9883f08 100644 --- a/locales/zh_CN.yaml +++ b/locales/zh_CN.yaml @@ -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: 背景图片 diff --git a/module/problem-import-syzoj/README.md b/module/problem-import-syzoj/README.md deleted file mode 100644 index 0e32aed8..00000000 --- a/module/problem-import-syzoj/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Problem-Import-Syzoj - -从运行 syzoj 系统的 OJ 导入题目。 - -使用方式:题目->导入题目(`/problem/import`)->选择类型:syzoj diff --git a/module/problem-import-syzoj/hydro.json b/module/problem-import-syzoj/hydro.json deleted file mode 100644 index 1907311c..00000000 --- a/module/problem-import-syzoj/hydro.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "problem-import-syzoj", - "version": "1.0.1", - "description": "Import problem from syzoj." -} \ No newline at end of file diff --git a/module/problem-import-syzoj/locale/zh_CN.yaml b/module/problem-import-syzoj/locale/zh_CN.yaml deleted file mode 100644 index a013924c..00000000 --- a/module/problem-import-syzoj/locale/zh_CN.yaml +++ /dev/null @@ -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: 导入 \ No newline at end of file diff --git a/wiki/development/development.md b/wiki/development/development.md index 6169a1c2..3b930c68 100644 --- a/wiki/development/development.md +++ b/wiki/development/development.md @@ -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 / 外置的沙箱模块等)