mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-21 01:46:28 +08:00
core: feat: problem_delete
This commit is contained in:
1 parent
3d9acf2c1a
commit
1543a374e3
12 files changed
+151
-174
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.15.16",
|
"version": "2.15.17",
|
||||||
"bin": "bin/hydrooj.js",
|
"bin": "bin/hydrooj.js",
|
||||||
"main": "dist/loader.js",
|
"main": "dist/loader.js",
|
||||||
"typings": "dist/loader.d.ts",
|
"typings": "dist/loader.d.ts",
|
||||||
|
|||||||
@@ -73,16 +73,14 @@ class RecordDetailHandler extends RecordHandler {
|
|||||||
const tdoc = await contest.get(domainId, rdoc.contest.tid, rdoc.contest.type);
|
const tdoc = await contest.get(domainId, rdoc.contest.tid, rdoc.contest.type);
|
||||||
if (!this.canShowRecord(tdoc, true)) throw new PermissionError(rid);
|
if (!this.canShowRecord(tdoc, true)) throw new PermissionError(rid);
|
||||||
}
|
}
|
||||||
if (rdoc.uid !== this.user.uid && !this.user.hasPerm(PERM.PERM_READ_RECORD_CODE)) {
|
if (rdoc.uid !== this.user.uid && !this.user.hasPerm(PERM.PERM_READ_RECORD_CODE)) rdoc.code = null;
|
||||||
rdoc.code = null;
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line prefer-const
|
// eslint-disable-next-line prefer-const
|
||||||
let [pdoc, udoc] = await Promise.all([
|
let [pdoc, udoc] = await Promise.all([
|
||||||
problem.get(domainId, rdoc.pid),
|
problem.get(domainId, rdoc.pid),
|
||||||
user.getById(domainId, rdoc.uid),
|
user.getById(domainId, rdoc.uid),
|
||||||
]);
|
]);
|
||||||
if (!rdoc.contest && pdoc.hidden && pdoc.owner !== this.user._id) {
|
if (!rdoc.contest && pdoc.hidden && pdoc.owner !== this.user._id) {
|
||||||
if (this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN)) {
|
if (!this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN)) {
|
||||||
pdoc = problem.Pdoc.create(pdoc.docId, pdoc.pid);
|
pdoc = problem.Pdoc.create(pdoc.docId, pdoc.pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,22 +128,6 @@ class RecordDetailHandler extends RecordHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
* use RecordDetailHandler.postRejudge instead.
|
|
||||||
*/
|
|
||||||
class RecordRejudgeHandler extends Handler {
|
|
||||||
@param('rid', Types.ObjectID)
|
|
||||||
async post(domainId: string, rid: ObjectID) {
|
|
||||||
const rdoc = await record.get(domainId, rid);
|
|
||||||
if (rdoc) {
|
|
||||||
await record.reset(domainId, rid, true);
|
|
||||||
await record.judge(domainId, rid, 0);
|
|
||||||
}
|
|
||||||
this.back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const RecordConnectionHandler = contest.ContestHandlerMixin(ConnectionHandler);
|
const RecordConnectionHandler = contest.ContestHandlerMixin(ConnectionHandler);
|
||||||
|
|
||||||
class RecordMainConnectionHandler extends RecordConnectionHandler {
|
class RecordMainConnectionHandler extends RecordConnectionHandler {
|
||||||
@@ -230,7 +212,6 @@ class RecordDetailConnectionHandler extends contest.ContestHandlerMixin(Connecti
|
|||||||
export async function apply() {
|
export async function apply() {
|
||||||
Route('record_main', '/record', RecordListHandler);
|
Route('record_main', '/record', RecordListHandler);
|
||||||
Route('record_detail', '/record/:rid', RecordDetailHandler);
|
Route('record_detail', '/record/:rid', RecordDetailHandler);
|
||||||
Route('record_rejudge', '/record/:rid/rejudge', RecordRejudgeHandler);
|
|
||||||
Connection('record_conn', '/record-conn', RecordMainConnectionHandler);
|
Connection('record_conn', '/record-conn', RecordMainConnectionHandler);
|
||||||
Connection('record_detail_conn', '/record-detail-conn', RecordDetailConnectionHandler);
|
Connection('record_detail_conn', '/record-detail-conn', RecordDetailConnectionHandler);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export interface SystemKeys {
|
|||||||
'server.worker': number,
|
'server.worker': number,
|
||||||
'server.port': number,
|
'server.port': number,
|
||||||
'server.language': string,
|
'server.language': string,
|
||||||
|
'problem.categories': string,
|
||||||
'session.keys': string[],
|
'session.keys': string[],
|
||||||
'session.secure': boolean,
|
'session.secure': boolean,
|
||||||
'session.expire_seconds': number,
|
'session.expire_seconds': number,
|
||||||
|
|||||||
@@ -4,11 +4,6 @@ import * as bus from '../service/bus';
|
|||||||
const coll = db.collection('blacklist');
|
const coll = db.collection('blacklist');
|
||||||
|
|
||||||
export async function add(ip: string) {
|
export async function add(ip: string) {
|
||||||
/**
|
|
||||||
* Add a ip into blacklist.
|
|
||||||
* @param {string} ip
|
|
||||||
* @returns {Promise<Bdoc>}
|
|
||||||
*/
|
|
||||||
const expireAt = new Date(new Date().getTime() + 365 * 24 * 60 * 60 * 1000);
|
const expireAt = new Date(new Date().getTime() + 365 * 24 * 60 * 60 * 1000);
|
||||||
const res = await coll.findOneAndUpdate(
|
const res = await coll.findOneAndUpdate(
|
||||||
{ _id: ip },
|
{ _id: ip },
|
||||||
@@ -18,21 +13,16 @@ export async function add(ip: string) {
|
|||||||
return res.value;
|
return res.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get(ip: string) {
|
export async function get(ip: string) {
|
||||||
/**
|
return await coll.findOne({ _id: ip });
|
||||||
* Get a ip, return null if not.
|
|
||||||
* @param {string} ip
|
|
||||||
* @returns {Promise<Bdoc>}
|
|
||||||
*/
|
|
||||||
return coll.findOne({ _id: ip });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function del(ip: string) {
|
export async function del(ip: string) {
|
||||||
return coll.deleteOne({ _id: ip });
|
return await coll.deleteOne({ _id: ip });
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureIndexes() {
|
async function ensureIndexes() {
|
||||||
return coll.createIndex('expireAt', { expireAfterSeconds: 0 });
|
return await coll.createIndex('expireAt', { expireAfterSeconds: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
bus.once('app/started', ensureIndexes);
|
bus.once('app/started', ensureIndexes);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import * as training from './training';
|
|||||||
import * as document from './document';
|
import * as document from './document';
|
||||||
import { DocumentNotFoundError } from '../error';
|
import { DocumentNotFoundError } from '../error';
|
||||||
import { Ddoc, Drdoc, Drrdoc } from '../interface';
|
import { Ddoc, Drdoc, Drrdoc } from '../interface';
|
||||||
|
import * as bus from '../service/bus';
|
||||||
|
|
||||||
export const typeDisplay = {
|
export const typeDisplay = {
|
||||||
[document.TYPE_PROBLEM]: 'problem',
|
[document.TYPE_PROBLEM]: 'problem',
|
||||||
@@ -215,6 +216,22 @@ export async function getListVnodes(domainId: string, ddocs: any, getHidden: boo
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bus.on('problem/delete', async (domainId, docId) => {
|
||||||
|
const dids = await document.getMulti(
|
||||||
|
domainId, document.TYPE_DISCUSSION,
|
||||||
|
{ parentType: document.TYPE_PROBLEM, parentId: docId },
|
||||||
|
).project({ docId: 1 }).map((ddoc) => ddoc.docId).toArray();
|
||||||
|
const drids = await document.getMulti(
|
||||||
|
domainId, document.TYPE_DISCUSSION_REPLY,
|
||||||
|
{ parentType: document.TYPE_DISCUSSION, parentId: { $in: dids } },
|
||||||
|
).project({ docId: 1 }).map((drdoc) => drdoc.docId).toArray();
|
||||||
|
return await Promise.all([
|
||||||
|
document.deleteMultiStatus(domainId, document.TYPE_DISCUSSION, { docId: { $in: dids } }),
|
||||||
|
document.deleteMulti(domainId, document.TYPE_DISCUSSION, { docId: { $in: dids } }),
|
||||||
|
document.deleteMulti(domainId, document.TYPE_DISCUSSION_REPLY, { docId: { $in: drids } }),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
global.Hydro.model.discussion = {
|
global.Hydro.model.discussion = {
|
||||||
typeDisplay,
|
typeDisplay,
|
||||||
add,
|
add,
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ export const TYPE_DISCUSSION = 21;
|
|||||||
export const TYPE_DISCUSSION_REPLY = 22;
|
export const TYPE_DISCUSSION_REPLY = 22;
|
||||||
export const TYPE_CONTEST = 30;
|
export const TYPE_CONTEST = 30;
|
||||||
export const TYPE_TRAINING = 40;
|
export const TYPE_TRAINING = 40;
|
||||||
export const TYPE_FILE = 50;
|
|
||||||
export const TYPE_HOMEWORK = 60;
|
export const TYPE_HOMEWORK = 60;
|
||||||
|
|
||||||
export interface DocType {
|
export interface DocType {
|
||||||
@@ -37,7 +36,6 @@ export interface DocType {
|
|||||||
[TYPE_DISCUSSION_REPLY]: Drdoc,
|
[TYPE_DISCUSSION_REPLY]: Drdoc,
|
||||||
[TYPE_CONTEST]: Tdoc,
|
[TYPE_CONTEST]: Tdoc,
|
||||||
[TYPE_TRAINING]: TrainingDoc,
|
[TYPE_TRAINING]: TrainingDoc,
|
||||||
[TYPE_FILE]: any,
|
|
||||||
[TYPE_HOMEWORK]: Tdoc,
|
[TYPE_HOMEWORK]: Tdoc,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,6 +455,5 @@ global.Hydro.model.document = {
|
|||||||
TYPE_PROBLEM,
|
TYPE_PROBLEM,
|
||||||
TYPE_PROBLEM_LIST,
|
TYPE_PROBLEM_LIST,
|
||||||
TYPE_PROBLEM_SOLUTION,
|
TYPE_PROBLEM_SOLUTION,
|
||||||
TYPE_FILE,
|
|
||||||
TYPE_TRAINING,
|
TYPE_TRAINING,
|
||||||
};
|
};
|
||||||
@@ -9,6 +9,7 @@ import { Content } from '../loader';
|
|||||||
import { ArrayKeys, NumberKeys, Projection } from '../typeutils';
|
import { ArrayKeys, NumberKeys, Projection } from '../typeutils';
|
||||||
import { ProblemNotFoundError } from '../error';
|
import { ProblemNotFoundError } from '../error';
|
||||||
import storage from '../service/storage';
|
import storage from '../service/storage';
|
||||||
|
import * as bus from '../service/bus';
|
||||||
|
|
||||||
export interface Pdoc {
|
export interface Pdoc {
|
||||||
_id: ObjectID
|
_id: ObjectID
|
||||||
@@ -207,6 +208,11 @@ export function setStar(domainId: string, pid: number, uid: number, star: boolea
|
|||||||
return document.setStatus(domainId, document.TYPE_PROBLEM, pid, uid, { star });
|
return document.setStatus(domainId, document.TYPE_PROBLEM, pid, uid, { star });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bus.on('problem/delete', (domainId, docId) => Promise.all([
|
||||||
|
document.deleteOne(domainId, document.TYPE_PROBLEM, docId),
|
||||||
|
document.deleteMultiStatus(domainId, document.TYPE_PROBLEM, { docId }),
|
||||||
|
]));
|
||||||
|
|
||||||
global.Hydro.model.problem = {
|
global.Hydro.model.problem = {
|
||||||
Pdoc,
|
Pdoc,
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,15 @@ import {
|
|||||||
ObjectID, Collection, UpdateQuery, PushOperator, MatchKeysAndValues, OnlyFieldsOfType,
|
ObjectID, Collection, UpdateQuery, PushOperator, MatchKeysAndValues, OnlyFieldsOfType,
|
||||||
} from 'mongodb';
|
} from 'mongodb';
|
||||||
import { Dictionary } from 'lodash';
|
import { Dictionary } from 'lodash';
|
||||||
|
import moment from 'moment';
|
||||||
import { STATUS } from './builtin';
|
import { STATUS } from './builtin';
|
||||||
import * as task from './task';
|
import * as task from './task';
|
||||||
import * as problem from './problem';
|
import * as problem from './problem';
|
||||||
import {
|
import {
|
||||||
Rdoc, TestCase, RunConfig, ContestInfo, ProblemConfig,
|
Rdoc, TestCase, RunConfig, ContestInfo, ProblemConfig,
|
||||||
} from '../interface';
|
} from '../interface';
|
||||||
|
import { Time } from '../utils';
|
||||||
|
import * as bus from '../service/bus';
|
||||||
import db from '../service/db';
|
import db from '../service/db';
|
||||||
import storage from '../service/storage';
|
import storage from '../service/storage';
|
||||||
|
|
||||||
@@ -55,6 +58,19 @@ export async function get(domainId: string, _id: ObjectID): Promise<Rdoc | null>
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function stat(domainId?: string) {
|
||||||
|
const [d5min, d1h, d1d, d1m, total] = await Promise.all([
|
||||||
|
coll.find({ _id: { $gte: Time.getObjectID(moment().add(-5, 'minutes')) }, ...domainId ? { domainId } : {} }).count(),
|
||||||
|
coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'hour')) }, ...domainId ? { domainId } : {} }).count(),
|
||||||
|
coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'day')) }, ...domainId ? { domainId } : {} }).count(),
|
||||||
|
coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'month')) }, ...domainId ? { domainId } : {} }).count(),
|
||||||
|
coll.find(domainId ? { domainId } : {}).count(),
|
||||||
|
]);
|
||||||
|
return {
|
||||||
|
d5min, d1h, d1d, d1m, total,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export async function judge(domainId: string, rid: ObjectID, priority = 1) {
|
export async function judge(domainId: string, rid: ObjectID, priority = 1) {
|
||||||
const rdoc = await get(domainId, rid);
|
const rdoc = await get(domainId, rid);
|
||||||
let config: RunConfig | ProblemConfig = rdoc.config;
|
let config: RunConfig | ProblemConfig = rdoc.config;
|
||||||
@@ -186,11 +202,14 @@ export function getByUid(domainId: string, uid: number, limit: number): Promise<
|
|||||||
return coll.find({ domainId, uid }).limit(limit).toArray();
|
return coll.find({ domainId, uid }).limit(limit).toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bus.on('problem/delete', (domainId, docId) => coll.deleteMany({ domainId, pid: docId }));
|
||||||
|
|
||||||
global.Hydro.model.record = {
|
global.Hydro.model.record = {
|
||||||
coll,
|
coll,
|
||||||
add,
|
add,
|
||||||
get,
|
get,
|
||||||
getMulti,
|
getMulti,
|
||||||
|
stat,
|
||||||
update,
|
update,
|
||||||
count,
|
count,
|
||||||
reset,
|
reset,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ObjectID } from 'mongodb';
|
import { ObjectID } from 'mongodb';
|
||||||
import * as document from './document';
|
import * as document from './document';
|
||||||
import { SolutionNotFoundError } from '../error';
|
import { SolutionNotFoundError } from '../error';
|
||||||
|
import * as bus from '../service/bus';
|
||||||
|
|
||||||
export function add(domainId: string, pid: number, owner: number, content: string) {
|
export function add(domainId: string, pid: number, owner: number, content: string) {
|
||||||
return document.add(
|
return document.add(
|
||||||
@@ -26,8 +27,11 @@ export function edit(domainId: string, psid: ObjectID, content: string) {
|
|||||||
return document.set(domainId, document.TYPE_PROBLEM_SOLUTION, psid, { content });
|
return document.set(domainId, document.TYPE_PROBLEM_SOLUTION, psid, { content });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function del(domainId: string, psid: ObjectID) {
|
export async function del(domainId: string, psid: ObjectID) {
|
||||||
return document.deleteOne(domainId, document.TYPE_PROBLEM_SOLUTION, psid);
|
return await Promise.all([
|
||||||
|
document.deleteOne(domainId, document.TYPE_PROBLEM_SOLUTION, psid),
|
||||||
|
document.deleteMultiStatus(domainId, document.TYPE_PROBLEM_SOLUTION, { docId: psid }),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function count(domainId: string, query: any) {
|
export function count(domainId: string, query: any) {
|
||||||
@@ -75,6 +79,17 @@ export async function getListStatus(domainId: string, psids: ObjectID[], uid: nu
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bus.on('problem/delete', async (domainId, docId) => {
|
||||||
|
const psids = await document.getMulti(
|
||||||
|
domainId, document.TYPE_PROBLEM_SOLUTION,
|
||||||
|
{ parentType: document.TYPE_PROBLEM, parentId: docId },
|
||||||
|
).project({ docId: 1 }).map((psdoc) => psdoc.docId).toArray();
|
||||||
|
return await Promise.all([
|
||||||
|
document.deleteMulti(domainId, document.TYPE_PROBLEM_SOLUTION, { docId: { $in: psids } }),
|
||||||
|
document.deleteMultiStatus(domainId, document.TYPE_PROBLEM_SOLUTION, { docId: { $in: psids } }),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
global.Hydro.model.solution = {
|
global.Hydro.model.solution = {
|
||||||
count,
|
count,
|
||||||
add,
|
add,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ function isBailed(value: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type Disposable = () => void
|
export type Disposable = () => void
|
||||||
export type VoidReturn = Promise<void> | void
|
export type VoidReturn = Promise<any> | any
|
||||||
|
|
||||||
export interface EventMap {
|
export interface EventMap {
|
||||||
'app/started': () => void
|
'app/started': () => void
|
||||||
@@ -57,6 +57,7 @@ export interface EventMap {
|
|||||||
'problem/list': (query: FilterQuery<Pdoc>, handler: any) => VoidReturn
|
'problem/list': (query: FilterQuery<Pdoc>, handler: any) => VoidReturn
|
||||||
'problem/setting': (update: Partial<Pdoc>, handler: any) => VoidReturn
|
'problem/setting': (update: Partial<Pdoc>, handler: any) => VoidReturn
|
||||||
'problem/get': (doc: Pdoc, handler: any) => VoidReturn
|
'problem/get': (doc: Pdoc, handler: any) => VoidReturn
|
||||||
|
'problem/delete': (domainId: string, docId: number) => VoidReturn
|
||||||
|
|
||||||
'training/list': (query: FilterQuery<TrainingDoc>, handler: any) => VoidReturn
|
'training/list': (query: FilterQuery<TrainingDoc>, handler: any) => VoidReturn
|
||||||
'training/get': (tdoc: TrainingDoc, handler: any) => VoidReturn
|
'training/get': (tdoc: TrainingDoc, handler: any) => VoidReturn
|
||||||
|
|||||||
@@ -293,13 +293,68 @@ export async function prepare() {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Handler {
|
export class HandlerCommon {
|
||||||
UIContext: any;
|
|
||||||
|
|
||||||
args: any;
|
|
||||||
|
|
||||||
domainId: string;
|
domainId: string;
|
||||||
|
domain: DomainDoc;
|
||||||
|
user: User;
|
||||||
|
session: Record<string, any>;
|
||||||
|
request: Record<string, any>;
|
||||||
|
|
||||||
|
async limitRate(op: string, periodSecs: number, maxOperations: number) {
|
||||||
|
await opcount.inc(op, this.request.ip, periodSecs, maxOperations);
|
||||||
|
}
|
||||||
|
|
||||||
|
translate(str: string) {
|
||||||
|
if (!str) return '';
|
||||||
|
return str.toString().translate(this.user.viewLang, this.session.viewLang);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTitle(str: string) {
|
||||||
|
return `${this.translate(str)} - ${system.get('server.name')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkPerm(...args: bigint[]) {
|
||||||
|
// @ts-ignore
|
||||||
|
if (!this.user.hasPerm(...args)) throw new PermissionError(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkPriv(...args: number[]) {
|
||||||
|
// @ts-ignore
|
||||||
|
if (!this.user.hasPriv(...args)) throw new PrivilegeError(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
url(name: string, kwargs: any = {}) {
|
||||||
|
let res = '#';
|
||||||
|
const args: any = {};
|
||||||
|
const query: any = {};
|
||||||
|
for (const key in kwargs) {
|
||||||
|
if (kwargs[key] instanceof ObjectID) args[key] = kwargs[key].toHexString();
|
||||||
|
else args[key] = kwargs[key].toString();
|
||||||
|
}
|
||||||
|
for (const key in kwargs.query || {}) {
|
||||||
|
if (query[key] instanceof ObjectID) query[key] = kwargs.query[key].toHexString();
|
||||||
|
else query[key] = kwargs.query[key].toString();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (this.domainId !== 'system' || args.domainId) {
|
||||||
|
name += '_with_domainId';
|
||||||
|
args.domainId = args.domainId || this.domainId;
|
||||||
|
}
|
||||||
|
const { anchor } = args;
|
||||||
|
res = router.url(name, args, { query });
|
||||||
|
if (anchor) return `${res}#${anchor}`;
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn(e.message);
|
||||||
|
logger.info('%s %o', name, args);
|
||||||
|
logger.info('%s', e.stack);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Handler extends HandlerCommon {
|
||||||
|
UIContext: any;
|
||||||
|
args: any;
|
||||||
ctx: Koa.Context;
|
ctx: Koa.Context;
|
||||||
|
|
||||||
request: {
|
request: {
|
||||||
@@ -327,19 +382,12 @@ export class Handler {
|
|||||||
attachment: (name: string, stream?: any) => void,
|
attachment: (name: string, stream?: any) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
session: any;
|
|
||||||
|
|
||||||
csrfToken: string;
|
csrfToken: string;
|
||||||
|
|
||||||
user: User;
|
|
||||||
|
|
||||||
domain: DomainDoc;
|
|
||||||
|
|
||||||
loginMethods: any;
|
loginMethods: any;
|
||||||
|
|
||||||
__param: Record<string, ParamOption[]>;
|
__param: Record<string, ParamOption[]>;
|
||||||
|
|
||||||
constructor(ctx: Koa.Context) {
|
constructor(ctx: Koa.Context) {
|
||||||
|
super();
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.request = {
|
this.request = {
|
||||||
host: ctx.request.host,
|
host: ctx.request.host,
|
||||||
@@ -405,57 +453,6 @@ export class Handler {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
async limitRate(op: string, periodSecs: number, maxOperations: number) {
|
|
||||||
await opcount.inc(op, this.request.ip, periodSecs, maxOperations);
|
|
||||||
}
|
|
||||||
|
|
||||||
translate(str: string) {
|
|
||||||
if (!str) return '';
|
|
||||||
return str.toString().translate(this.user.viewLang, this.session.viewLang);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTitle(str: string) {
|
|
||||||
return `${this.translate(str)} - ${system.get('server.name')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkPerm(...args: bigint[]) {
|
|
||||||
// @ts-ignore
|
|
||||||
if (!this.user.hasPerm(...args)) throw new PermissionError(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkPriv(...args: number[]) {
|
|
||||||
// @ts-ignore
|
|
||||||
if (!this.user.hasPriv(...args)) throw new PrivilegeError(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
url(name: string, kwargs: any = {}) {
|
|
||||||
let res = '#';
|
|
||||||
const args: any = {};
|
|
||||||
const query: any = {};
|
|
||||||
for (const key in kwargs) {
|
|
||||||
if (kwargs[key] instanceof ObjectID) args[key] = kwargs[key].toHexString();
|
|
||||||
else args[key] = kwargs[key].toString();
|
|
||||||
}
|
|
||||||
for (const key in kwargs.query || {}) {
|
|
||||||
if (query[key] instanceof ObjectID) query[key] = kwargs.query[key].toHexString();
|
|
||||||
else query[key] = kwargs.query[key].toString();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (this.domainId !== 'system' || args.domainId) {
|
|
||||||
name += '_with_domainId';
|
|
||||||
args.domainId = args.domainId || this.domainId;
|
|
||||||
}
|
|
||||||
const { anchor } = args;
|
|
||||||
res = router.url(name, args, { query });
|
|
||||||
if (anchor) return `${res}#${anchor}`;
|
|
||||||
} catch (e) {
|
|
||||||
logger.warn(e.message);
|
|
||||||
logger.info('%s %o', name, args);
|
|
||||||
logger.info('%s', e.stack);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
async render(name: string, context: any) {
|
async render(name: string, context: any) {
|
||||||
this.response.body = await this.renderHTML(name, context);
|
this.response.body = await this.renderHTML(name, context);
|
||||||
this.response.type = 'text/html';
|
this.response.type = 'text/html';
|
||||||
@@ -584,8 +581,8 @@ export class Handler {
|
|||||||
|
|
||||||
async saveCookie() {
|
async saveCookie() {
|
||||||
const expireSeconds = this.session.save
|
const expireSeconds = this.session.save
|
||||||
? system.get('session.expire_seconds') as number
|
? system.get('session.expire_seconds')
|
||||||
: system.get('session.unsaved_expire_seconds') as number;
|
: system.get('session.unsaved_expire_seconds');
|
||||||
if (this.session._id) {
|
if (this.session._id) {
|
||||||
await token.update(
|
await token.update(
|
||||||
this.session._id,
|
this.session._id,
|
||||||
@@ -614,10 +611,6 @@ export class Handler {
|
|||||||
secure: !!system.get('session.secure'),
|
secure: !!system.get('session.secure'),
|
||||||
httpOnly: false,
|
httpOnly: false,
|
||||||
};
|
};
|
||||||
if (this.session.save) {
|
|
||||||
cookie.expires = this.session.expireAt;
|
|
||||||
cookie.maxAge = expireSeconds;
|
|
||||||
}
|
|
||||||
this.ctx.cookies.set('sid', this.session._id, cookie);
|
this.ctx.cookies.set('sid', this.session._id, cookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,26 +710,17 @@ export function Route(name: string, path: string, RouteHandler: any, ...permPriv
|
|||||||
router.all(`${name}_with_domainId`, `/d/:domainId${path}`, (ctx) => handle(ctx, RouteHandler, checker));
|
router.all(`${name}_with_domainId`, `/d/:domainId${path}`, (ctx) => handle(ctx, RouteHandler, checker));
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ConnectionHandler {
|
export class ConnectionHandler extends HandlerCommon {
|
||||||
conn: sockjs.Connection;
|
conn: sockjs.Connection;
|
||||||
|
args: any;
|
||||||
request: {
|
request: {
|
||||||
params: any;
|
params: any;
|
||||||
headers: any;
|
headers: any;
|
||||||
ip: string;
|
ip: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
domainId: string;
|
|
||||||
|
|
||||||
session: any;
|
|
||||||
|
|
||||||
args: any;
|
|
||||||
|
|
||||||
user: User;
|
|
||||||
|
|
||||||
domain: DomainDoc;
|
|
||||||
|
|
||||||
constructor(conn: sockjs.Connection) {
|
constructor(conn: sockjs.Connection) {
|
||||||
|
super();
|
||||||
this.conn = conn;
|
this.conn = conn;
|
||||||
this.request = {
|
this.request = {
|
||||||
params: {},
|
params: {},
|
||||||
@@ -758,54 +742,6 @@ export class ConnectionHandler {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
async limitRate(op: string, periodSecs: number, maxOperations: number) {
|
|
||||||
await opcount.inc(op, this.request.ip, periodSecs, maxOperations);
|
|
||||||
}
|
|
||||||
|
|
||||||
translate(str: string) {
|
|
||||||
return str ? str.toString().translate(this.user.viewLang || this.session.viewLang) : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTitle(str: string) {
|
|
||||||
return `${this.translate(str)} - ${system.get('server.name')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkPerm(...args: bigint[]) {
|
|
||||||
if (!this.user.hasPerm(...args)) throw new PermissionError(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkPriv(...args: number[]) {
|
|
||||||
// @ts-ignore
|
|
||||||
if (!this.user.hasPriv(...args)) throw new PrivilegeError(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
url(name: string, kwargs: any = {}) {
|
|
||||||
let res = '#';
|
|
||||||
const args: any = {};
|
|
||||||
const query: any = {};
|
|
||||||
for (const key in kwargs) {
|
|
||||||
if (kwargs[key] instanceof ObjectID) args[key] = kwargs[key].toHexString();
|
|
||||||
else args[key] = kwargs[key].toString();
|
|
||||||
}
|
|
||||||
for (const key in kwargs.query || {}) {
|
|
||||||
if (query[key] instanceof ObjectID) query[key] = kwargs.query[key].toHexString();
|
|
||||||
else query[key] = kwargs.query[key].toString();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (this.args.domainId !== 'system' || args.domainId) {
|
|
||||||
name += '_with_domainId';
|
|
||||||
args.domainId = args.domainId || this.args.domainId;
|
|
||||||
}
|
|
||||||
const { anchor } = args;
|
|
||||||
res = router.url(name, args, { query });
|
|
||||||
if (anchor) return `${res}#${anchor}`;
|
|
||||||
} catch (e) {
|
|
||||||
logger.error(e.message);
|
|
||||||
logger.info(name, args);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
send(data: any) {
|
send(data: any) {
|
||||||
this.conn.write(JSON.stringify(data));
|
this.conn.write(JSON.stringify(data));
|
||||||
}
|
}
|
||||||
@@ -934,6 +870,7 @@ global.Hydro.service.server = {
|
|||||||
route,
|
route,
|
||||||
param,
|
param,
|
||||||
requireCsrfToken,
|
requireCsrfToken,
|
||||||
|
HandlerCommon,
|
||||||
Handler,
|
Handler,
|
||||||
ConnectionHandler,
|
ConnectionHandler,
|
||||||
Route,
|
Route,
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import cluster from 'cluster';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import serialize from 'serialize-javascript';
|
import serialize from 'serialize-javascript';
|
||||||
import Lru from 'lru-cache';
|
import Lru from 'lru-cache';
|
||||||
|
import { ObjectID } from 'mongodb';
|
||||||
|
import { isMoment } from 'moment';
|
||||||
|
import { Moment } from 'moment-timezone';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface StringConstructor {
|
interface StringConstructor {
|
||||||
@@ -240,4 +243,14 @@ export namespace Time {
|
|||||||
}
|
}
|
||||||
return `${ms}ms`;
|
return `${ms}ms`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getObjectID(timestamp: string | Date | Moment) {
|
||||||
|
let _timestamp: number;
|
||||||
|
if (typeof timestamp === 'string') _timestamp = new Date(timestamp).getTime();
|
||||||
|
else if (isMoment(timestamp)) _timestamp = timestamp.toDate().getTime();
|
||||||
|
else _timestamp = timestamp.getTime();
|
||||||
|
const hexSeconds = Math.floor(_timestamp / 1000).toString(16);
|
||||||
|
const constructedObjectId = new ObjectID(`${hexSeconds}0000000000000000`);
|
||||||
|
return constructedObjectId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user