mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
一些优化
优化 Date.prototype.format 修复题目分类解析错误的问题 Interface Tdoc X-Forwarded-For 支持
This commit is contained in:
1 parent
1722fbfaca
commit
82c193b5ee
19 files changed
+286
-179
No files matched your search
+2
-5
@@ -52,6 +52,7 @@ export const ForbiddenError = Err('ForbiddenError', UserFacingError, 'ForbiddenE
|
|||||||
export const NotFoundError = Err('NotFoundError', UserFacingError, 'NotFoundError', 404);
|
export const NotFoundError = Err('NotFoundError', UserFacingError, 'NotFoundError', 404);
|
||||||
export const MethodNotAllowedError = Err('MethodNotAllowedError', UserFacingError, 'MethodNotAllowedError', 405);
|
export const MethodNotAllowedError = Err('MethodNotAllowedError', UserFacingError, 'MethodNotAllowedError', 405);
|
||||||
export const RemoteOnlineJudgeError = Err('RemoteOnlineJudgeError', UserFacingError, 'RemoteOnlineJudgeError', 500);
|
export const RemoteOnlineJudgeError = Err('RemoteOnlineJudgeError', UserFacingError, 'RemoteOnlineJudgeError', 500);
|
||||||
|
export const SendMailError = Err('SendMailError', UserFacingError, 'Failed to send mail to {0}.', 500);
|
||||||
|
|
||||||
export const AlreadyVotedError = Err('AlreadyVotedError', ForbiddenError, "You've already voted.");
|
export const AlreadyVotedError = Err('AlreadyVotedError', ForbiddenError, "You've already voted.");
|
||||||
export const LoginError = Err('LoginError', ForbiddenError, 'Invalid password for user {0}.');
|
export const LoginError = Err('LoginError', ForbiddenError, 'Invalid password for user {0}.');
|
||||||
@@ -103,6 +104,7 @@ global.Hydro.error = {
|
|||||||
BlacklistedError,
|
BlacklistedError,
|
||||||
ForbiddenError,
|
ForbiddenError,
|
||||||
NotFoundError,
|
NotFoundError,
|
||||||
|
SendMailError,
|
||||||
LoginError,
|
LoginError,
|
||||||
CsrfTokenError,
|
CsrfTokenError,
|
||||||
MethodNotAllowedError,
|
MethodNotAllowedError,
|
||||||
@@ -188,9 +190,4 @@ class InvalidArgumentError(BadRequestError):
|
|||||||
@property
|
@property
|
||||||
def message(self):
|
def message(self):
|
||||||
return 'Argument {0} is invalid.'
|
return 'Argument {0} is invalid.'
|
||||||
|
|
||||||
class SendMailError(UserFacingError):
|
|
||||||
@property
|
|
||||||
def message(self):
|
|
||||||
return 'Failed to send mail to {0}.'
|
|
||||||
*/
|
*/
|
||||||
@@ -155,8 +155,8 @@ class ContestEditHandler extends ContestHandler {
|
|||||||
duration,
|
duration,
|
||||||
path,
|
path,
|
||||||
pids: this.tdoc.pids.join(','),
|
pids: this.tdoc.pids.join(','),
|
||||||
date_text: `${dt.getFullYear()}-${dt.getMonth() + 1}-${dt.getDate()}`,
|
date_text: dt.format('%Y-%m-%d'),
|
||||||
time_text: `${dt.getHours()}:${dt.getMinutes()}`,
|
time_text: dt.format('%H:%M'),
|
||||||
page_name: 'contest_edit',
|
page_name: 'contest_edit',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -337,8 +337,8 @@ class ContestCreateHandler extends ContestHandler {
|
|||||||
rules,
|
rules,
|
||||||
path,
|
path,
|
||||||
page_name: 'contest_create',
|
page_name: 'contest_create',
|
||||||
date_text: `${dt.getFullYear()}-${dt.getMonth() + 1}-${dt.getDate()}`,
|
date_text: dt.format('%Y-%m-%d'),
|
||||||
time_text: `${dt.getHours()}:${dt.getMinutes()}`,
|
time_text: dt.format('%M:%S'),
|
||||||
pids: '1000, 1001',
|
pids: '1000, 1001',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ export const typeMapper = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class DiscussionHandler extends Handler {
|
class DiscussionHandler extends Handler {
|
||||||
|
ddoc?: any;
|
||||||
|
|
||||||
|
drdoc?: any;
|
||||||
|
|
||||||
|
drrdoc?: any;
|
||||||
|
|
||||||
|
vnode?: any;
|
||||||
|
|
||||||
async _prepare({
|
async _prepare({
|
||||||
domainId, type, name, did, drid, drrid,
|
domainId, type, name, did, drid, drrid,
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ class DomainCreateHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ManageHandler extends Handler {
|
class ManageHandler extends Handler {
|
||||||
|
domain: any;
|
||||||
|
|
||||||
async prepare({ domainId }) {
|
async prepare({ domainId }) {
|
||||||
this.checkPerm(PERM.PERM_EDIT_DOMAIN);
|
this.checkPerm(PERM.PERM_EDIT_DOMAIN);
|
||||||
this.domain = await domain.get(domainId);
|
this.domain = await domain.get(domainId);
|
||||||
|
|||||||
@@ -147,10 +147,10 @@ class HomeSecurityHandler extends Handler {
|
|||||||
const [code] = await token.add(
|
const [code] = await token.add(
|
||||||
token.TYPE_CHANGEMAIL,
|
token.TYPE_CHANGEMAIL,
|
||||||
await system.get('changemail_token_expire_seconds'),
|
await system.get('changemail_token_expire_seconds'),
|
||||||
{ uid: this.udoc._id, mail },
|
{ uid: this.user._id, mail },
|
||||||
);
|
);
|
||||||
await mail.sendMail(mail, 'Change Email', 'user_changemail_mail.html', {
|
await mail.sendMail(mail, 'Change Email', 'user_changemail_mail.html', {
|
||||||
url: this.url('user_changemail_with_code', { code }), uname: this.udoc.uname,
|
url: this.url('user_changemail_with_code', { code }), uname: this.user.uname,
|
||||||
});
|
});
|
||||||
this.response.template = 'user_changemail_mail_sent.html';
|
this.response.template = 'user_changemail_mail_sent.html';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,6 +155,8 @@ class JudgeHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class JudgeConnectionHandler extends ConnectionHandler {
|
class JudgeConnectionHandler extends ConnectionHandler {
|
||||||
|
processing: any;
|
||||||
|
|
||||||
async message(msg) {
|
async message(msg) {
|
||||||
if (msg.key === 'next') await next(msg);
|
if (msg.key === 'next') await next(msg);
|
||||||
else if (msg.key === 'end') {
|
else if (msg.key === 'end') {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ function set(key, value) {
|
|||||||
if (setting.SYSTEM_SETTINGS_BY_KEY[key]) {
|
if (setting.SYSTEM_SETTINGS_BY_KEY[key]) {
|
||||||
const s = setting.SYSTEM_SETTINGS_BY_KEY[key];
|
const s = setting.SYSTEM_SETTINGS_BY_KEY[key];
|
||||||
if (s.flag & setting.FLAG_DISABLED) return undefined;
|
if (s.flag & setting.FLAG_DISABLED) return undefined;
|
||||||
|
if (s.flag & setting.FLAG_SECRET && !value) return undefined;
|
||||||
if (s.type === 'boolean') {
|
if (s.type === 'boolean') {
|
||||||
if (value === 'on') return true;
|
if (value === 'on') return true;
|
||||||
return false;
|
return false;
|
||||||
@@ -48,6 +49,8 @@ class SystemMainHandler extends SystemHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SystemCheckConnHandler extends ConnectionHandler {
|
class SystemCheckConnHandler extends ConnectionHandler {
|
||||||
|
id: any;
|
||||||
|
|
||||||
async prepare() {
|
async prepare() {
|
||||||
this.checkPriv(PRIV.PRIV_EDIT_SYSTEM);
|
this.checkPriv(PRIV.PRIV_EDIT_SYSTEM);
|
||||||
await this.check();
|
await this.check();
|
||||||
@@ -61,7 +64,7 @@ class SystemCheckConnHandler extends ConnectionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async cleanup() {
|
async cleanup() {
|
||||||
check.cancel(this.token);
|
check.cancel(this.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class FileDownloadHandler extends Handler {
|
|||||||
@param('name', Types.String, true)
|
@param('name', Types.String, true)
|
||||||
async get(domainId: string, fileId: ObjectID, secret: string, name: string) {
|
async get(domainId: string, fileId: ObjectID, secret: string, name: string) {
|
||||||
if (name) name = Buffer.from(name, 'base64').toString();
|
if (name) name = Buffer.from(name, 'base64').toString();
|
||||||
this.response.attachment(name || fileId);
|
this.response.attachment(name || fileId.toHexString());
|
||||||
this.response.body = await file.getWithSecret(fileId, secret);
|
this.response.body = await file.getWithSecret(fileId, secret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-22
@@ -19,8 +19,13 @@ import {
|
|||||||
NoProblemError, ProblemDataNotFoundError, BadRequestError,
|
NoProblemError, ProblemDataNotFoundError, BadRequestError,
|
||||||
SolutionNotFoundError,
|
SolutionNotFoundError,
|
||||||
} from '../error';
|
} from '../error';
|
||||||
|
import { Pdoc, Udoc, Rdoc } from '../interface';
|
||||||
|
|
||||||
const parseCategory = (value: string) => flatten(value.split('+').map((e) => e.split(','))).map((e) => e.trim());
|
const parseCategory = (value: string) => {
|
||||||
|
if (!value) return [];
|
||||||
|
console.log(value);
|
||||||
|
return flatten(value.split('+').map((e) => e.split(','))).map((e) => e.trim());
|
||||||
|
};
|
||||||
const parsePid = (value: string) => (isSafeInteger(value) ? parseInt(value, 10) : value);
|
const parsePid = (value: string) => (isSafeInteger(value) ? parseInt(value, 10) : value);
|
||||||
|
|
||||||
class ProblemHandler extends Handler {
|
class ProblemHandler extends Handler {
|
||||||
@@ -99,7 +104,7 @@ class ProblemMainHandler extends ProblemHandler {
|
|||||||
|
|
||||||
class ProblemCategoryHandler extends ProblemHandler {
|
class ProblemCategoryHandler extends ProblemHandler {
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.UnsignedInt, true)
|
||||||
@param('category', Types.String, parseCategory)
|
@param('category', Types.String, null, parseCategory)
|
||||||
async get(domainId: string, page = 1, category: string[]) {
|
async get(domainId: string, page = 1, category: string[]) {
|
||||||
this.response.template = 'problem_main.html';
|
this.response.template = 'problem_main.html';
|
||||||
const q: any = { $and: [] };
|
const q: any = { $and: [] };
|
||||||
@@ -136,7 +141,7 @@ class ProblemCategoryHandler extends ProblemHandler {
|
|||||||
|
|
||||||
class ProblemRandomHandler extends ProblemHandler {
|
class ProblemRandomHandler extends ProblemHandler {
|
||||||
@param('category', Types.String, true, null, parseCategory)
|
@param('category', Types.String, true, null, parseCategory)
|
||||||
async get(domainId: string, category: string[]) {
|
async get(domainId: string, category: string[] = []) {
|
||||||
const q: any = category.length ? { $and: [] } : {};
|
const q: any = category.length ? { $and: [] } : {};
|
||||||
for (const name of category) {
|
for (const name of category) {
|
||||||
if (name) {
|
if (name) {
|
||||||
@@ -157,31 +162,32 @@ class ProblemRandomHandler extends ProblemHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ProblemDetailHandler extends ProblemHandler {
|
class ProblemDetailHandler extends ProblemHandler {
|
||||||
|
pdoc: Pdoc;
|
||||||
|
|
||||||
|
udoc: Udoc;
|
||||||
|
|
||||||
@param('pid', Types.String, null, parsePid)
|
@param('pid', Types.String, null, parsePid)
|
||||||
async _prepare(domainId: string, pid: number | string) {
|
async _prepare(domainId: string, pid: number | string) {
|
||||||
this.response.template = 'problem_detail.html';
|
this.response.template = 'problem_detail.html';
|
||||||
if (pid) {
|
this.pdoc = await problem.get(domainId, pid, this.user._id, true);
|
||||||
this.pdoc = await problem.get(domainId, pid, this.user._id);
|
|
||||||
if (this.pdoc.hidden && this.pdoc.owner !== this.user._id) {
|
if (this.pdoc.hidden && this.pdoc.owner !== this.user._id) {
|
||||||
this.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
|
this.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
|
||||||
}
|
}
|
||||||
if (this.pdoc) this.udoc = await user.getById(domainId, this.pdoc.owner);
|
this.udoc = await user.getById(domainId, this.pdoc.owner);
|
||||||
}
|
|
||||||
this.response.body = {
|
this.response.body = {
|
||||||
pdoc: this.pdoc,
|
pdoc: this.pdoc,
|
||||||
udoc: this.udoc,
|
udoc: this.udoc,
|
||||||
title: (this.pdoc || {}).title || '',
|
title: this.pdoc.title,
|
||||||
};
|
path: [
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
async get(...args: any) {
|
|
||||||
this.response.body.path = [
|
|
||||||
['Hydro', 'homepage'],
|
['Hydro', 'homepage'],
|
||||||
['problem_main', 'problem_main'],
|
['problem_main', 'problem_main'],
|
||||||
[this.pdoc.title, null, true],
|
[this.pdoc.title, null, true],
|
||||||
];
|
],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line
|
||||||
|
async get(...args: any[]) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProblemSubmitHandler extends ProblemDetailHandler {
|
class ProblemSubmitHandler extends ProblemDetailHandler {
|
||||||
@@ -234,6 +240,10 @@ class ProblemPretestHandler extends ProblemDetailHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ProblemPretestConnectionHandler extends ConnectionHandler {
|
class ProblemPretestConnectionHandler extends ConnectionHandler {
|
||||||
|
pid: string;
|
||||||
|
|
||||||
|
domainId: string;
|
||||||
|
|
||||||
@param('pid', Types.String)
|
@param('pid', Types.String)
|
||||||
async prepare(domainId: string, pid: string) {
|
async prepare(domainId: string, pid: string) {
|
||||||
this.pid = pid;
|
this.pid = pid;
|
||||||
@@ -242,7 +252,7 @@ class ProblemPretestConnectionHandler extends ConnectionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async onRecordChange(data) {
|
async onRecordChange(data) {
|
||||||
const rdoc = data.value;
|
const rdoc: Rdoc = data.value;
|
||||||
if (
|
if (
|
||||||
rdoc.uid !== this.user._id
|
rdoc.uid !== this.user._id
|
||||||
|| rdoc.pid.toString() !== this.pid
|
|| rdoc.pid.toString() !== this.pid
|
||||||
@@ -339,23 +349,25 @@ class ProblemDataUploadHandler extends ProblemManageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async get() {
|
async get() {
|
||||||
|
let md5;
|
||||||
if (this.pdoc.data && typeof this.pdoc.data === 'object') {
|
if (this.pdoc.data && typeof this.pdoc.data === 'object') {
|
||||||
const f = await file.getMeta(this.pdoc.data);
|
const f = await file.getMeta(this.pdoc.data);
|
||||||
this.md5 = f.md5;
|
md5 = f.md5;
|
||||||
}
|
}
|
||||||
this.response.body.md5 = this.md5;
|
this.response.body.md5 = md5;
|
||||||
}
|
}
|
||||||
|
|
||||||
async post({ domainId }) {
|
async post({ domainId }) {
|
||||||
|
let md5;
|
||||||
if (!this.request.files.file) throw new BadRequestError();
|
if (!this.request.files.file) throw new BadRequestError();
|
||||||
await problem.setTestdata(
|
await problem.setTestdata(
|
||||||
domainId, this.pdoc.docId, this.request.files.file.path,
|
domainId, this.pdoc.docId, this.request.files.file.path,
|
||||||
);
|
);
|
||||||
if (this.pdoc.data && typeof this.pdoc.data === 'object') {
|
if (this.pdoc.data && typeof this.pdoc.data === 'object') {
|
||||||
const f = await file.getMeta(this.pdoc.data);
|
const f = await file.getMeta(this.pdoc.data);
|
||||||
this.md5 = f.md5;
|
md5 = f.md5;
|
||||||
}
|
}
|
||||||
this.response.body.md5 = this.md5;
|
this.response.body.md5 = md5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,7 +380,7 @@ class ProblemDataDownloadHandler extends ProblemDetailHandler {
|
|||||||
}
|
}
|
||||||
if (!this.pdoc.data) throw new ProblemDataNotFoundError(pid);
|
if (!this.pdoc.data) throw new ProblemDataNotFoundError(pid);
|
||||||
else if (typeof this.pdoc.data === 'string') [, this.response.redirect] = this.pdoc.data.split('from:');
|
else if (typeof this.pdoc.data === 'string') [, this.response.redirect] = this.pdoc.data.split('from:');
|
||||||
this.response.redirect = await file.url(this.pdoc.data, `${this.pdoc.title}.zip`);
|
else this.response.redirect = await file.url(this.pdoc.data, `${this.pdoc.title}.zip`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,7 +428,7 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
|||||||
let psdoc = await solution.get(domainId, psid);
|
let psdoc = await solution.get(domainId, psid);
|
||||||
if (psdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION);
|
if (psdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION);
|
||||||
else this.checkPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION_SELF);
|
else this.checkPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION_SELF);
|
||||||
psdoc = await solution.edit(domainId, this.psdoc.docId, content);
|
psdoc = await solution.edit(domainId, psdoc.docId, content);
|
||||||
this.back({ psdoc });
|
this.back({ psdoc });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import * as system from '../model/system';
|
|||||||
import {
|
import {
|
||||||
Route, Handler, Types, param,
|
Route, Handler, Types, param,
|
||||||
} from '../service/server';
|
} from '../service/server';
|
||||||
|
import { Tdoc } from '../interface';
|
||||||
|
|
||||||
async function _parseDagJson(domainId, dag) {
|
async function _parseDagJson(domainId, dag) {
|
||||||
const parsed = [];
|
const parsed = [];
|
||||||
@@ -199,6 +200,8 @@ class TrainingCreateHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TrainingEditHandler extends Handler {
|
class TrainingEditHandler extends Handler {
|
||||||
|
tdoc: Tdoc;
|
||||||
|
|
||||||
@param('tid', Types.ObjectID)
|
@param('tid', Types.ObjectID)
|
||||||
async prepare(domainId: string, tid: ObjectID) {
|
async prepare(domainId: string, tid: ObjectID) {
|
||||||
this.tdoc = await training.get(domainId, tid);
|
this.tdoc = await training.get(domainId, tid);
|
||||||
|
|||||||
+13
-4
@@ -2,10 +2,12 @@
|
|||||||
import { ObjectID, GridFSBucket } from 'mongodb';
|
import { ObjectID, GridFSBucket } from 'mongodb';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
|
export type Dict<T> = { [key: string]: T };
|
||||||
|
|
||||||
export interface Setting {
|
export interface Setting {
|
||||||
family: string,
|
family: string,
|
||||||
key: string,
|
key: string,
|
||||||
range: Array<[string, string]> | { [key: string]: string },
|
range: Array<[string, string]> | Dict<string>,
|
||||||
value: any,
|
value: any,
|
||||||
type: string,
|
type: string,
|
||||||
name: string,
|
name: string,
|
||||||
@@ -51,7 +53,8 @@ export interface Pdoc {
|
|||||||
nAccept: number,
|
nAccept: number,
|
||||||
tag: string[],
|
tag: string[],
|
||||||
category: string[],
|
category: string[],
|
||||||
data?: ObjectID,
|
// ObjectID for built-in files, string for other source (RemoteJudge, etc.)
|
||||||
|
data?: ObjectID | string,
|
||||||
hidden: boolean,
|
hidden: boolean,
|
||||||
config: string,
|
config: string,
|
||||||
}
|
}
|
||||||
@@ -108,15 +111,21 @@ export interface Tdoc {
|
|||||||
domainId: string,
|
domainId: string,
|
||||||
docId: ObjectID,
|
docId: ObjectID,
|
||||||
docType: number,
|
docType: number,
|
||||||
|
owner: number,
|
||||||
beginAt: Date,
|
beginAt: Date,
|
||||||
endAt: Date,
|
endAt: Date,
|
||||||
penaltySince?: Date,
|
|
||||||
penaltyRules?: PenaltyRules,
|
|
||||||
attend: number,
|
attend: number,
|
||||||
title: string,
|
title: string,
|
||||||
content: string,
|
content: string,
|
||||||
rule: string,
|
rule: string,
|
||||||
pids: number[],
|
pids: number[],
|
||||||
|
|
||||||
|
// For homework
|
||||||
|
penaltySince?: Date,
|
||||||
|
penaltyRules?: PenaltyRules,
|
||||||
|
|
||||||
|
// For training
|
||||||
|
dag: any
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ContestStat {
|
interface ContestStat {
|
||||||
|
|||||||
+1
-8
@@ -1,13 +1,6 @@
|
|||||||
import nodemailer from 'nodemailer';
|
import nodemailer from 'nodemailer';
|
||||||
|
import { SendMailError } from '../error';
|
||||||
|
|
||||||
const { SendMailError } = require('../error');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} to
|
|
||||||
* @param {string} subject
|
|
||||||
* @param {string} text
|
|
||||||
* @param {string} html
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
export async function sendMail(to: string, subject: string, text: string, html: string) {
|
export async function sendMail(to: string, subject: string, text: string, html: string) {
|
||||||
let t: unknown;
|
let t: unknown;
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ export const BUILTIN_USERS = [
|
|||||||
regip: '127.0.0.1',
|
regip: '127.0.0.1',
|
||||||
loginat: new Date(0),
|
loginat: new Date(0),
|
||||||
loginip: '127.0.0.1',
|
loginip: '127.0.0.1',
|
||||||
priv: PRIV.PRIV_NONE,
|
priv: PRIV.PRIV_REGISTER_USER,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_id: 1,
|
_id: 1,
|
||||||
|
|||||||
@@ -390,8 +390,10 @@ export async function edit(
|
|||||||
return await document.set(domainId, type, tid, $set);
|
return await document.set(domainId, type, tid, $set);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get(domainId: string, tid: ObjectID, type = document.TYPE_CONTEST) {
|
export async function get(
|
||||||
let tdoc;
|
domainId: string, tid: ObjectID, type = document.TYPE_CONTEST,
|
||||||
|
) {
|
||||||
|
let tdoc: Tdoc;
|
||||||
if (type === -1) {
|
if (type === -1) {
|
||||||
tdoc = await document.get(domainId, document.TYPE_CONTEST, tid);
|
tdoc = await document.get(domainId, document.TYPE_CONTEST, tid);
|
||||||
if (!tdoc) tdoc = await document.get(domainId, document.TYPE_HOMEWORK, tid);
|
if (!tdoc) tdoc = await document.get(domainId, document.TYPE_HOMEWORK, tid);
|
||||||
@@ -535,7 +537,7 @@ export function getMulti(domainId: string, query = {}, type = document.TYPE_CONT
|
|||||||
|
|
||||||
export async function getAndListStatus(
|
export async function getAndListStatus(
|
||||||
domainId: string, tid: ObjectID, docType = document.TYPE_CONTEST,
|
domainId: string, tid: ObjectID, docType = document.TYPE_CONTEST,
|
||||||
) {
|
): Promise<[Tdoc, any[]]> {
|
||||||
// TODO(iceboy): projection, pagination.
|
// TODO(iceboy): projection, pagination.
|
||||||
const tdoc = await get(domainId, tid, docType);
|
const tdoc = await get(domainId, tid, docType);
|
||||||
const tsdocs = await document.getMultiStatus(domainId, docType, { docId: tid })
|
const tsdocs = await document.getMultiStatus(domainId, docType, { docId: tid })
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ObjectID, FilterQuery } from 'mongodb';
|
import { ObjectID } from 'mongodb';
|
||||||
import { STATUS } from './builtin';
|
import { STATUS } from './builtin';
|
||||||
import * as file from './file';
|
import * as file from './file';
|
||||||
import * as document from './document';
|
import * as document from './document';
|
||||||
@@ -47,8 +47,6 @@ export async function get(
|
|||||||
): Promise<Pdoc> {
|
): Promise<Pdoc> {
|
||||||
if (typeof pid !== 'number') {
|
if (typeof pid !== 'number') {
|
||||||
if (!Number.isNaN(parseInt(pid, 10))) pid = parseInt(pid, 10);
|
if (!Number.isNaN(parseInt(pid, 10))) pid = parseInt(pid, 10);
|
||||||
else if (doThrow) throw new ProblemNotFoundError(domainId, pid);
|
|
||||||
else return null;
|
|
||||||
}
|
}
|
||||||
const pdoc = Number.isInteger(pid)
|
const pdoc = Number.isInteger(pid)
|
||||||
? await document.get(domainId, document.TYPE_PROBLEM, pid)
|
? await document.get(domainId, document.TYPE_PROBLEM, pid)
|
||||||
@@ -87,11 +85,11 @@ export function inc(domainId: string, _id: number, field: string, n: number) {
|
|||||||
return document.inc(domainId, document.TYPE_PROBLEM, _id, field, n);
|
return document.inc(domainId, document.TYPE_PROBLEM, _id, field, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function count<T>(domainId: string, query: FilterQuery<T>) {
|
export function count(domainId: string, query: any) {
|
||||||
return document.count(domainId, document.TYPE_PROBLEM, query);
|
return document.count(domainId, document.TYPE_PROBLEM, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function random<T>(domainId: string, query: FilterQuery<T>) {
|
export async function random(domainId: string, query: any) {
|
||||||
const cursor = document.getMulti(domainId, document.TYPE_PROBLEM, query);
|
const cursor = document.getMulti(domainId, document.TYPE_PROBLEM, query);
|
||||||
const pcount = await cursor.count();
|
const pcount = await cursor.count();
|
||||||
if (pcount) {
|
if (pcount) {
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ SystemSetting(
|
|||||||
Setting('setting_server', 'server.host', null, null, 'text', 'Server Host'),
|
Setting('setting_server', 'server.host', null, null, 'text', 'Server Host'),
|
||||||
Setting('setting_server', 'server.url', null, null, 'text', 'Server BaseURL'),
|
Setting('setting_server', 'server.url', null, null, 'text', 'Server BaseURL'),
|
||||||
Setting('setting_server', 'server.port', null, 8888, 'number', 'Server Port'),
|
Setting('setting_server', 'server.port', null, 8888, 'number', 'Server Port'),
|
||||||
|
Setting('setting_server', 'server.xff', null, null, 'text', 'IP Header'),
|
||||||
Setting('setting_server', 'server.log', null, false, 'boolean', 'Disable Access Log'),
|
Setting('setting_server', 'server.log', null, false, 'boolean', 'Disable Access Log'),
|
||||||
Setting('setting_ui', 'ui.header', null, null, 'text', 'Header Logo'),
|
Setting('setting_ui', 'ui.header', null, null, 'text', 'Header Logo'),
|
||||||
Setting('setting_ui', 'ui.headerBackground', null, null, 'text', 'Header Background'),
|
Setting('setting_ui', 'ui.headerBackground', null, null, 'text', 'Header Background'),
|
||||||
|
|||||||
+184
-111
@@ -31,10 +31,11 @@ const app = new Koa();
|
|||||||
let server;
|
let server;
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
|
|
||||||
interface IConstructor {
|
// TODO fix this ugly hack
|
||||||
// @ts-ignore
|
interface H {
|
||||||
new(value: any): any;
|
[key: string]: any,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IHandler {
|
interface IHandler {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
new(ctx: Koa.Context): Handler;
|
new(ctx: Koa.Context): Handler;
|
||||||
@@ -44,7 +45,7 @@ interface IConnectionHandler {
|
|||||||
new(conn: sockjs.Connection): ConnectionHandler;
|
new(conn: sockjs.Connection): ConnectionHandler;
|
||||||
}
|
}
|
||||||
type MethodDecorator = (target: any, name: string, obj: any) => any;
|
type MethodDecorator = (target: any, name: string, obj: any) => any;
|
||||||
type Converter = IConstructor | ((value: any) => any);
|
type Converter = (value: any) => any;
|
||||||
type Validator = (value: any) => boolean;
|
type Validator = (value: any) => boolean;
|
||||||
interface ParamOption {
|
interface ParamOption {
|
||||||
name: string,
|
name: string,
|
||||||
@@ -64,7 +65,7 @@ const Tools: Array<[Converter, Validator, boolean?]> = [
|
|||||||
const t = parseFloat(v);
|
const t = parseFloat(v);
|
||||||
return t && !Number.isNaN(t) && !Number.isFinite(t);
|
return t && !Number.isNaN(t) && !Number.isFinite(t);
|
||||||
}],
|
}],
|
||||||
[ObjectID, ObjectID.isValid],
|
[(v) => new ObjectID(v), ObjectID.isValid],
|
||||||
[(v) => !!v, null, true],
|
[(v) => !!v, null, true],
|
||||||
[
|
[
|
||||||
(v) => {
|
(v) => {
|
||||||
@@ -105,36 +106,28 @@ export function param(
|
|||||||
): MethodDecorator;
|
): MethodDecorator;
|
||||||
export function param(
|
export function param(
|
||||||
name: string, ...args: Array<Types | boolean | Converter | Validator>
|
name: string, ...args: Array<Types | boolean | Converter | Validator>
|
||||||
)
|
): MethodDecorator;
|
||||||
export function param(...args: any): MethodDecorator {
|
export function param(name: string, ...args: any): MethodDecorator {
|
||||||
let cursor = 0;
|
let cursor = 0;
|
||||||
let v: ParamOption = null;
|
const v: ParamOption = { name };
|
||||||
let isValidate = true;
|
let isValidate = true;
|
||||||
const d: ParamOption[] = [];
|
while (cursor < args.length) {
|
||||||
while (cursor <= args.length) {
|
if (typeof args[cursor] === 'number') {
|
||||||
if (typeof args[cursor] === 'string') {
|
|
||||||
v = { name: args[cursor] };
|
|
||||||
d.push(v);
|
|
||||||
isValidate = true;
|
|
||||||
} else if (typeof args[cursor] === 'number') {
|
|
||||||
const type = args[cursor];
|
const type = args[cursor];
|
||||||
if (Tools[type]) {
|
if (Tools[type]) {
|
||||||
if (Tools[type][0]) d[d.length - 1].convert = Tools[type][0];
|
if (Tools[type][0]) v.convert = Tools[type][0];
|
||||||
if (Tools[type][1]) d[d.length - 1].validate = Tools[type][1];
|
if (Tools[type][1]) v.validate = Tools[type][1];
|
||||||
if (Tools[type][2]) d[d.length - 1].isOptional = Tools[type][2];
|
if (Tools[type][2]) v.isOptional = Tools[type][2];
|
||||||
}
|
}
|
||||||
} else if (typeof args[cursor] === 'boolean') d[d.length - 1].isOptional = args[cursor];
|
} else if (typeof args[cursor] === 'boolean') v.isOptional = args[cursor];
|
||||||
else if (!isValidate) {
|
else if (isValidate) {
|
||||||
const I = args[cursor];
|
if (args[cursor] !== null) v.validate = args[cursor];
|
||||||
if (typeof I.constructor === 'function') {
|
|
||||||
d[d.length - 1].convert = (val: any) => new I(val);
|
|
||||||
} else d[d.length - 1].convert = I;
|
|
||||||
isValidate = false;
|
isValidate = false;
|
||||||
} else d[d.length - 1].validate = args[cursor];
|
} else {
|
||||||
cursor++;
|
const I = args[cursor];
|
||||||
|
v.convert = I;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < d.length; i++) {
|
cursor++;
|
||||||
d[i].isOptional = d[i].isOptional || false;
|
|
||||||
}
|
}
|
||||||
return function desc(target: any, funcName: string, obj: any) {
|
return function desc(target: any, funcName: string, obj: any) {
|
||||||
if (!target.__param) target.__param = {};
|
if (!target.__param) target.__param = {};
|
||||||
@@ -153,7 +146,6 @@ export function param(...args: any): MethodDecorator {
|
|||||||
throw new ValidationError(item.name);
|
throw new ValidationError(item.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
|
||||||
if (item.convert) c.push(item.convert(rawArgs[item.name]));
|
if (item.convert) c.push(item.convert(rawArgs[item.name]));
|
||||||
else c.push(rawArgs[item.name]);
|
else c.push(rawArgs[item.name]);
|
||||||
} else c.push(undefined);
|
} else c.push(undefined);
|
||||||
@@ -161,7 +153,7 @@ export function param(...args: any): MethodDecorator {
|
|||||||
return originalMethod.call(this, ...c);
|
return originalMethod.call(this, ...c);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
target.__param[target.constructor.name][funcName].splice(1, 0, ...d);
|
target.__param[target.constructor.name][funcName].splice(1, 0, v);
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -180,11 +172,80 @@ export async function prepare() {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const HandlerMixin = (Class: IConstructor) => class extends Class {
|
export class Handler {
|
||||||
|
UIContext: any;
|
||||||
|
|
||||||
|
args: any;
|
||||||
|
|
||||||
|
ctx: Koa.Context;
|
||||||
|
|
||||||
|
request: {
|
||||||
|
host: string,
|
||||||
|
hostname: string,
|
||||||
|
ip: string,
|
||||||
|
headers: any,
|
||||||
|
cookies: any,
|
||||||
|
body: any,
|
||||||
|
files: any,
|
||||||
|
query: any,
|
||||||
|
path: string,
|
||||||
|
params: any,
|
||||||
|
referer: any,
|
||||||
|
json: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
response: {
|
||||||
|
body: any,
|
||||||
|
type: string,
|
||||||
|
status: number,
|
||||||
|
template: string | undefined,
|
||||||
|
redirect: string | undefined,
|
||||||
|
disposition: string | undefined,
|
||||||
|
attachment: (name: string) => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
session: any;
|
||||||
|
|
||||||
|
csrfToken: string;
|
||||||
|
|
||||||
|
user: any;
|
||||||
|
|
||||||
|
constructor(ctx: Koa.Context) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.request = {
|
||||||
|
host: ctx.request.host,
|
||||||
|
hostname: ctx.request.hostname,
|
||||||
|
ip: ctx.request.ip,
|
||||||
|
headers: ctx.request.headers,
|
||||||
|
cookies: ctx.cookies,
|
||||||
|
body: ctx.request.body,
|
||||||
|
files: ctx.request.files,
|
||||||
|
query: ctx.query,
|
||||||
|
path: ctx.path,
|
||||||
|
params: ctx.params,
|
||||||
|
referer: ctx.request.headers.referer || '/',
|
||||||
|
json: (ctx.request.headers.accept || '').includes('application/json'),
|
||||||
|
};
|
||||||
|
this.response = {
|
||||||
|
body: {},
|
||||||
|
type: '',
|
||||||
|
status: null,
|
||||||
|
template: null,
|
||||||
|
redirect: null,
|
||||||
|
attachment: (name) => ctx.attachment(name),
|
||||||
|
disposition: null,
|
||||||
|
};
|
||||||
|
this.UIContext = {
|
||||||
|
cdn_prefix: '/',
|
||||||
|
url_prefix: '/',
|
||||||
|
};
|
||||||
|
this.session = {};
|
||||||
|
}
|
||||||
|
|
||||||
async renderHTML(name: string, context: any): Promise<string> {
|
async renderHTML(name: string, context: any): Promise<string> {
|
||||||
if (enableLog) console.time(name);
|
if (enableLog) console.time(name);
|
||||||
this.hasPerm = (perm) => this.user.hasPerm(perm);
|
|
||||||
// FIXME fix this ugly hack
|
// FIXME fix this ugly hack
|
||||||
|
// @ts-ignore
|
||||||
this._user = { ...this.user, gravatar: misc.gravatar(this.user.gravatar, 128) };
|
this._user = { ...this.user, gravatar: misc.gravatar(this.user.gravatar, 128) };
|
||||||
const res = await render(name, Object.assign(context, {
|
const res = await render(name, Object.assign(context, {
|
||||||
handler: this,
|
handler: this,
|
||||||
@@ -261,77 +322,6 @@ const HandlerMixin = (Class: IConstructor) => class extends Class {
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
export const Handler = HandlerMixin(class {
|
|
||||||
UIContext: any;
|
|
||||||
|
|
||||||
args: any;
|
|
||||||
|
|
||||||
ctx: Koa.Context;
|
|
||||||
|
|
||||||
request: {
|
|
||||||
host: string,
|
|
||||||
hostname: string,
|
|
||||||
ip: string,
|
|
||||||
headers: any,
|
|
||||||
cookies: any,
|
|
||||||
body: any,
|
|
||||||
files: any,
|
|
||||||
query: any,
|
|
||||||
path: string,
|
|
||||||
params: any,
|
|
||||||
referer: any,
|
|
||||||
json: boolean,
|
|
||||||
};
|
|
||||||
|
|
||||||
response: {
|
|
||||||
body: any,
|
|
||||||
type: string,
|
|
||||||
status: number,
|
|
||||||
template: string | undefined,
|
|
||||||
redirect: string | undefined,
|
|
||||||
disposition: string | undefined,
|
|
||||||
attachment: (name: string) => void,
|
|
||||||
};
|
|
||||||
|
|
||||||
session: any;
|
|
||||||
|
|
||||||
csrfToken: string;
|
|
||||||
|
|
||||||
user: any;
|
|
||||||
|
|
||||||
constructor(ctx: Koa.Context) {
|
|
||||||
this.ctx = ctx;
|
|
||||||
this.request = {
|
|
||||||
host: ctx.request.host,
|
|
||||||
hostname: ctx.request.hostname,
|
|
||||||
ip: ctx.request.ip,
|
|
||||||
headers: ctx.request.headers,
|
|
||||||
cookies: ctx.cookies,
|
|
||||||
body: ctx.request.body,
|
|
||||||
files: ctx.request.files,
|
|
||||||
query: ctx.query,
|
|
||||||
path: ctx.path,
|
|
||||||
params: ctx.params,
|
|
||||||
referer: ctx.request.headers.referer || '/',
|
|
||||||
json: (ctx.request.headers.accept || '').includes('application/json'),
|
|
||||||
};
|
|
||||||
this.response = {
|
|
||||||
body: {},
|
|
||||||
type: '',
|
|
||||||
status: null,
|
|
||||||
template: null,
|
|
||||||
redirect: null,
|
|
||||||
attachment: (name) => ctx.attachment(name),
|
|
||||||
disposition: null,
|
|
||||||
};
|
|
||||||
this.UIContext = {
|
|
||||||
cdn_prefix: '/',
|
|
||||||
url_prefix: '/',
|
|
||||||
};
|
|
||||||
this.session = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
async render(name: string, context: any) {
|
async render(name: string, context: any) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -339,7 +329,7 @@ export const Handler = HandlerMixin(class {
|
|||||||
this.response.type = 'text/html';
|
this.response.type = 'text/html';
|
||||||
}
|
}
|
||||||
|
|
||||||
back(body: any) {
|
back(body?: any) {
|
||||||
this.response.body = body || this.response.body || {};
|
this.response.body = body || this.response.body || {};
|
||||||
this.response.redirect = this.request.headers.referer || '/';
|
this.response.redirect = this.request.headers.referer || '/';
|
||||||
}
|
}
|
||||||
@@ -371,6 +361,8 @@ export const Handler = HandlerMixin(class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async init({ domainId }) {
|
async init({ domainId }) {
|
||||||
|
const xff = await system.get('server.xff');
|
||||||
|
if (xff) this.request.ip = this.request.headers[xff.toLowerCase()];
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.getSession(),
|
this.getSession(),
|
||||||
this.getBdoc(),
|
this.getBdoc(),
|
||||||
@@ -481,7 +473,7 @@ export const Handler = HandlerMixin(class {
|
|||||||
};
|
};
|
||||||
await this.finish().catch(() => { });
|
await this.finish().catch(() => { });
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
async function handle(ctx, HandlerClass, checker) {
|
async function handle(ctx, HandlerClass, checker) {
|
||||||
global.Hydro.stat.reqCount++;
|
global.Hydro.stat.reqCount++;
|
||||||
@@ -553,13 +545,13 @@ const Checker = (permPrivChecker) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Route(name: string, route: string, RouteHandler: IHandler, ...permPrivChecker) {
|
export function Route(name: string, route: string, RouteHandler: any, ...permPrivChecker) {
|
||||||
const checker = Checker(permPrivChecker);
|
const checker = Checker(permPrivChecker);
|
||||||
router.all(name, route, (ctx) => handle(ctx, RouteHandler, checker));
|
router.all(name, route, (ctx) => handle(ctx, RouteHandler, checker));
|
||||||
router.all(`${name}_with_domainId`, `/d/:domainId${route}`, (ctx) => handle(ctx, RouteHandler, checker));
|
router.all(`${name}_with_domainId`, `/d/:domainId${route}`, (ctx) => handle(ctx, RouteHandler, checker));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ConnectionHandler = HandlerMixin(class {
|
export class ConnectionHandler {
|
||||||
conn: sockjs.Connection;
|
conn: sockjs.Connection;
|
||||||
|
|
||||||
request: {
|
request: {
|
||||||
@@ -587,7 +579,88 @@ export const ConnectionHandler = HandlerMixin(class {
|
|||||||
for (const i in p) this.request.params[p[i][0]] = decodeURIComponent(p[i][1]);
|
for (const i in p) this.request.params[p[i][0]] = decodeURIComponent(p[i][1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
send(data: JSON) {
|
async renderHTML(name: string, context: any): Promise<string> {
|
||||||
|
if (enableLog) console.time(name);
|
||||||
|
// FIXME fix this ugly hack
|
||||||
|
// @ts-ignore
|
||||||
|
this._user = { ...this.user, gravatar: misc.gravatar(this.user.gravatar, 128) };
|
||||||
|
const res = await render(name, Object.assign(context, {
|
||||||
|
handler: this,
|
||||||
|
// @ts-ignore
|
||||||
|
url: (...args) => this.url(...args),
|
||||||
|
_: (str: string) => (str ? str.toString().translate(this.user.viewLang || this.session.viewLang) : ''),
|
||||||
|
user: this.user,
|
||||||
|
}));
|
||||||
|
if (enableLog) console.timeEnd(name);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async limitRate(op, periodSecs, maxOperations) {
|
||||||
|
await opcount.inc(op, this.request.ip, periodSecs, maxOperations);
|
||||||
|
}
|
||||||
|
|
||||||
|
translate(str) {
|
||||||
|
return str ? str.toString().translate(this.user.viewLang || this.session.viewLang) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTitle(str) {
|
||||||
|
return `${this.translate(str)} - Hydro`;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkPerm(...args) {
|
||||||
|
for (const i in args) {
|
||||||
|
if (args[i] instanceof Array) {
|
||||||
|
let p = false;
|
||||||
|
for (const j in args) {
|
||||||
|
if (this.user.hasPerm(args[i][j])) {
|
||||||
|
p = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!p) throw new PermissionError([args[i]]);
|
||||||
|
} else if (!this.user.hasPerm(args[i])) {
|
||||||
|
throw new PermissionError([[args[i]]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkPriv(...args) {
|
||||||
|
for (const i in args) {
|
||||||
|
if (args[i] instanceof Array) {
|
||||||
|
let p = false;
|
||||||
|
for (const j in args) {
|
||||||
|
if (this.user.hasPriv(args[i][j])) {
|
||||||
|
p = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!p) throw new PrivilegeError([args[i]]);
|
||||||
|
} else if (!this.user.hasPriv(args[i])) {
|
||||||
|
throw new PrivilegeError([[args[i]]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
url(name, kwargs = {}) {
|
||||||
|
let res = '#';
|
||||||
|
const args: any = { ...kwargs };
|
||||||
|
try {
|
||||||
|
if (this.args.domainId !== 'system') {
|
||||||
|
name += '_with_domainId';
|
||||||
|
args.domainId = args.domainId || this.args.domainId;
|
||||||
|
}
|
||||||
|
const { anchor, query } = args;
|
||||||
|
if (query) res = router.url(name, args, { query });
|
||||||
|
else res = router.url(name, args);
|
||||||
|
if (anchor) return `${res}#${anchor}`;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e.message);
|
||||||
|
console.log(name, args);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
send(data: any) {
|
||||||
this.conn.write(JSON.stringify(data));
|
this.conn.write(JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,17 +684,17 @@ export const ConnectionHandler = HandlerMixin(class {
|
|||||||
this.user = await user.getById(domainId, this.session.uid);
|
this.user = await user.getById(domainId, this.session.uid);
|
||||||
if (!this.user) throw new UserNotFoundError(this.session.uid);
|
if (!this.user) throw new UserNotFoundError(this.session.uid);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
export function Connection(
|
export function Connection(
|
||||||
name: string, prefix: string,
|
name: string, prefix: string,
|
||||||
RouteConnHandler: IConnectionHandler,
|
RouteConnHandler: any,
|
||||||
...permPrivChecker: Array<number | string | Function>
|
...permPrivChecker: Array<number | string | Function>
|
||||||
) {
|
) {
|
||||||
const sock = sockjs.createServer({ prefix });
|
const sock = sockjs.createServer({ prefix });
|
||||||
const checker = Checker(permPrivChecker);
|
const checker = Checker(permPrivChecker);
|
||||||
sock.on('connection', async (conn) => {
|
sock.on('connection', async (conn) => {
|
||||||
const h = new RouteConnHandler(conn);
|
const h: H = new RouteConnHandler(conn);
|
||||||
try {
|
try {
|
||||||
const args = { domainId: 'system', ...h.request.params };
|
const args = { domainId: 'system', ...h.request.params };
|
||||||
h.args = args;
|
h.args = args;
|
||||||
|
|||||||
+14
-10
@@ -50,19 +50,23 @@ Array.isDiff = function isDiff(a, b) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Date.prototype.format = function formatDate(fmt = '%Y-%m-%d %H:%M:%S') {
|
Date.prototype.format = function formatDate(fmt = '%Y-%m-%d %H:%M:%S') {
|
||||||
let h = this.getHours();
|
let m = this.getMonth() + 1;
|
||||||
if (h < 10) h = `0${h}`;
|
|
||||||
let m = this.getMinutes();
|
|
||||||
if (m < 10) m = `0${m}`;
|
if (m < 10) m = `0${m}`;
|
||||||
let s = this.getSeconds();
|
let d = this.getDate();
|
||||||
if (s < 10) s = `0${s}`;
|
if (d < 10) d = `0${d}`;
|
||||||
|
let H = this.getHours();
|
||||||
|
if (H < 10) H = `0${H}`;
|
||||||
|
let M = this.getMinutes();
|
||||||
|
if (M < 10) M = `0${M}`;
|
||||||
|
let S = this.getSeconds();
|
||||||
|
if (S < 10) S = `0${S}`;
|
||||||
return fmt
|
return fmt
|
||||||
.replace('%Y', this.getFullYear())
|
.replace('%Y', this.getFullYear())
|
||||||
.replace('%m', this.getMonth() + 1)
|
.replace('%m', m)
|
||||||
.replace('%d', this.getDate())
|
.replace('%d', d)
|
||||||
.replace('%H', h)
|
.replace('%H', H)
|
||||||
.replace('%M', m)
|
.replace('%M', M)
|
||||||
.replace('%S', s);
|
.replace('%S', S);
|
||||||
};
|
};
|
||||||
|
|
||||||
Math.sum = function sum(...args) {
|
Math.sum = function sum(...args) {
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.7.0",
|
"version": "2.7.2",
|
||||||
"main": "hydro/loader.js",
|
"main": "hydro/loader.ts",
|
||||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
"author": "masnn",
|
"author": "masnn",
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
|
|||||||
Reference in new issue
Block a user