mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
core: change export mode
This commit is contained in:
1 parent
b371ee6464
commit
0bed88ff99
26 files changed
+609
-687
No files matched your search
@@ -8,7 +8,7 @@ import type { ProblemConfig } from 'hydrooj';
|
|||||||
import { Route, Handler } from 'hydrooj/dist/service/server';
|
import { Route, Handler } from 'hydrooj/dist/service/server';
|
||||||
import { buildContent } from 'hydrooj/dist/lib/content';
|
import { buildContent } from 'hydrooj/dist/lib/content';
|
||||||
import { ProblemAdd } from 'hydrooj/dist/lib/ui';
|
import { ProblemAdd } from 'hydrooj/dist/lib/ui';
|
||||||
import * as solution from 'hydrooj/dist/model/solution';
|
import solution from 'hydrooj/dist/model/solution';
|
||||||
import { PERM } from 'hydrooj/dist/model/builtin';
|
import { PERM } from 'hydrooj/dist/model/builtin';
|
||||||
import { FileTooLargeError, ValidationError } from 'hydrooj/dist/error';
|
import { FileTooLargeError, ValidationError } from 'hydrooj/dist/error';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/fps-importer",
|
"name": "@hydrooj/fps-importer",
|
||||||
"version": "1.1.9",
|
"version": "1.1.10",
|
||||||
"description": "Import FPS problems",
|
"description": "Import FPS problems",
|
||||||
"main": "package.json",
|
"main": "package.json",
|
||||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.20.21",
|
"version": "2.20.22",
|
||||||
"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",
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import * as contest from '../model/contest';
|
|||||||
import * as system from '../model/system';
|
import * as system from '../model/system';
|
||||||
import * as document from '../model/document';
|
import * as document from '../model/document';
|
||||||
import * as problem from '../model/problem';
|
import * as problem from '../model/problem';
|
||||||
import * as domain from '../model/domain';
|
import domain from '../model/domain';
|
||||||
import * as record from '../model/record';
|
import record from '../model/record';
|
||||||
import user from '../model/user';
|
import user from '../model/user';
|
||||||
import * as message from '../model/message';
|
import message from '../model/message';
|
||||||
import {
|
import {
|
||||||
Route, Handler, Types, param,
|
Route, Handler, Types, param,
|
||||||
} from '../service/server';
|
} from '../service/server';
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import paginate from '../lib/paginate';
|
|||||||
import * as system from '../model/system';
|
import * as system from '../model/system';
|
||||||
import user from '../model/user';
|
import user from '../model/user';
|
||||||
import * as oplog from '../model/oplog';
|
import * as oplog from '../model/oplog';
|
||||||
import * as message from '../model/message';
|
import message from '../model/message';
|
||||||
import * as discussion from '../model/discussion';
|
import * as discussion from '../model/discussion';
|
||||||
import * as document from '../model/document';
|
import * as document from '../model/document';
|
||||||
import { PERM, PRIV } from '../model/builtin';
|
import { PERM, PRIV } from '../model/builtin';
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
import { log2 } from '../utils';
|
import { log2 } from '../utils';
|
||||||
import type { DomainDoc } from '../interface';
|
import type { DomainDoc } from '../interface';
|
||||||
import user from '../model/user';
|
import user from '../model/user';
|
||||||
import * as domain from '../model/domain';
|
import domain from '../model/domain';
|
||||||
import * as discussion from '../model/discussion';
|
import * as discussion from '../model/discussion';
|
||||||
import * as system from '../model/system';
|
import * as system from '../model/system';
|
||||||
import { DOMAIN_SETTINGS, DOMAIN_SETTINGS_BY_KEY } from '../model/setting';
|
import { DOMAIN_SETTINGS, DOMAIN_SETTINGS_BY_KEY } from '../model/setting';
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import * as misc from '../lib/misc';
|
|||||||
import { md5 } from '../lib/crypto';
|
import { md5 } from '../lib/crypto';
|
||||||
import * as mail from '../lib/mail';
|
import * as mail from '../lib/mail';
|
||||||
import * as contest from '../model/contest';
|
import * as contest from '../model/contest';
|
||||||
import * as message from '../model/message';
|
import message from '../model/message';
|
||||||
import * as document from '../model/document';
|
import * as document from '../model/document';
|
||||||
import * as system from '../model/system';
|
import * as system from '../model/system';
|
||||||
import user from '../model/user';
|
import user from '../model/user';
|
||||||
import * as setting from '../model/setting';
|
import * as setting from '../model/setting';
|
||||||
import * as domain from '../model/domain';
|
import domain from '../model/domain';
|
||||||
import * as discussion from '../model/discussion';
|
import * as discussion from '../model/discussion';
|
||||||
import token from '../model/token';
|
import token from '../model/token';
|
||||||
import * as training from '../model/training';
|
import * as training from '../model/training';
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ import {
|
|||||||
Route, Handler, Types, param,
|
Route, Handler, Types, param,
|
||||||
} from '../service/server';
|
} from '../service/server';
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
import * as domain from '../model/domain';
|
import domain from '../model/domain';
|
||||||
import { PERM } from '../model/builtin';
|
import { PERM } from '../model/builtin';
|
||||||
import user from '../model/user';
|
import user from '../model/user';
|
||||||
import * as system from '../model/system';
|
import * as system from '../model/system';
|
||||||
import * as contest from '../model/contest';
|
import * as contest from '../model/contest';
|
||||||
import * as discussion from '../model/discussion';
|
import * as discussion from '../model/discussion';
|
||||||
import * as problem from '../model/problem';
|
import * as problem from '../model/problem';
|
||||||
import * as record from '../model/record';
|
import record from '../model/record';
|
||||||
import * as document from '../model/document';
|
import * as document from '../model/document';
|
||||||
import paginate from '../lib/paginate';
|
import paginate from '../lib/paginate';
|
||||||
import { isTitle, isContent } from '../lib/validator';
|
import { isTitle, isContent } from '../lib/validator';
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import { JudgeResultBody, Rdoc, TestCase } from '../interface';
|
|||||||
import { sleep } from '../utils';
|
import { sleep } from '../utils';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import difficultyAlgorithm from '../lib/difficulty';
|
import difficultyAlgorithm from '../lib/difficulty';
|
||||||
import * as record from '../model/record';
|
import record from '../model/record';
|
||||||
import * as problem from '../model/problem';
|
import * as problem from '../model/problem';
|
||||||
import * as builtin from '../model/builtin';
|
import * as builtin from '../model/builtin';
|
||||||
import * as contest from '../model/contest';
|
import * as contest from '../model/contest';
|
||||||
import * as domain from '../model/domain';
|
import domain from '../model/domain';
|
||||||
import * as task from '../model/task';
|
import task from '../model/task';
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
import {
|
import {
|
||||||
Route, Handler, Connection, ConnectionHandler, post, Types,
|
Route, Handler, Connection, ConnectionHandler, post, Types,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import * as setting from '../model/setting';
|
|||||||
import * as system from '../model/system';
|
import * as system from '../model/system';
|
||||||
import user from '../model/user';
|
import user from '../model/user';
|
||||||
import { STATUS, PRIV } from '../model/builtin';
|
import { STATUS, PRIV } from '../model/builtin';
|
||||||
import * as record from '../model/record';
|
import record from '../model/record';
|
||||||
import {
|
import {
|
||||||
Route, Connection, Handler, ConnectionHandler, param, Types,
|
Route, Connection, Handler, ConnectionHandler, param, Types,
|
||||||
} from '../service/server';
|
} from '../service/server';
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import { isTitle, isContent, isPid } from '../lib/validator';
|
|||||||
import difficultyAlgorithm from '../lib/difficulty';
|
import difficultyAlgorithm from '../lib/difficulty';
|
||||||
import * as system from '../model/system';
|
import * as system from '../model/system';
|
||||||
import * as problem from '../model/problem';
|
import * as problem from '../model/problem';
|
||||||
import * as record from '../model/record';
|
import record from '../model/record';
|
||||||
import * as domain from '../model/domain';
|
import domain from '../model/domain';
|
||||||
import user from '../model/user';
|
import user from '../model/user';
|
||||||
import * as solution from '../model/solution';
|
import solution from '../model/solution';
|
||||||
import { PERM, PRIV } from '../model/builtin';
|
import { PERM, PRIV } from '../model/builtin';
|
||||||
import storage from '../service/storage';
|
import storage from '../service/storage';
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Rdoc } from '../interface';
|
|||||||
import { PERM, STATUS, PRIV } from '../model/builtin';
|
import { PERM, STATUS, PRIV } from '../model/builtin';
|
||||||
import * as system from '../model/system';
|
import * as system from '../model/system';
|
||||||
import * as problem from '../model/problem';
|
import * as problem from '../model/problem';
|
||||||
import * as record from '../model/record';
|
import record from '../model/record';
|
||||||
import * as contest from '../model/contest';
|
import * as contest from '../model/contest';
|
||||||
import user from '../model/user';
|
import user from '../model/user';
|
||||||
import paginate from '../lib/paginate';
|
import paginate from '../lib/paginate';
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import {
|
|||||||
Route, Handler, Types, param, post,
|
Route, Handler, Types, param, post,
|
||||||
} from '../service/server';
|
} from '../service/server';
|
||||||
import user from '../model/user';
|
import user from '../model/user';
|
||||||
import * as oauth from '../model/oauth';
|
import oauth from '../model/oauth';
|
||||||
import token from '../model/token';
|
import token from '../model/token';
|
||||||
import * as record from '../model/record';
|
import record from '../model/record';
|
||||||
import * as problem from '../model/problem';
|
import * as problem from '../model/problem';
|
||||||
import * as task from '../model/task';
|
import task from '../model/task';
|
||||||
import * as system from '../model/system';
|
import * as system from '../model/system';
|
||||||
import { PERM, PRIV } from '../model/builtin';
|
import { PERM, PRIV } from '../model/builtin';
|
||||||
import { isEmail, isPassword, isUname } from '../lib/validator';
|
import { isEmail, isPassword, isUname } from '../lib/validator';
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Dictionary } from 'lodash';
|
|||||||
import { FilterQuery } from 'mongodb';
|
import { FilterQuery } from 'mongodb';
|
||||||
import { BUILTIN_ROLES, PRIV } from './builtin';
|
import { BUILTIN_ROLES, PRIV } from './builtin';
|
||||||
import { DomainDoc } from '../interface';
|
import { DomainDoc } from '../interface';
|
||||||
|
import { ArgMethod } from '../utils';
|
||||||
import { NumberKeys } from '../typeutils';
|
import { NumberKeys } from '../typeutils';
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
import db from '../service/db';
|
import db from '../service/db';
|
||||||
@@ -9,232 +10,218 @@ import db from '../service/db';
|
|||||||
const coll = db.collection('domain');
|
const coll = db.collection('domain');
|
||||||
const collUser = db.collection('domain.user');
|
const collUser = db.collection('domain.user');
|
||||||
|
|
||||||
export const JOIN_METHOD_NONE = 0;
|
|
||||||
export const JOIN_METHOD_ALL = 1;
|
|
||||||
export const JOIN_METHOD_CODE = 2;
|
|
||||||
export const JOIN_METHOD_RANGE = {
|
|
||||||
[JOIN_METHOD_NONE]: 'No user is allowed to join this domain',
|
|
||||||
[JOIN_METHOD_ALL]: 'Any user is allowed to join this domain',
|
|
||||||
[JOIN_METHOD_CODE]: 'Any user is allowed to join this domain with an invitation code',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const JOIN_EXPIRATION_KEEP_CURRENT = 0;
|
|
||||||
export const JOIN_EXPIRATION_UNLIMITED = -1;
|
|
||||||
|
|
||||||
export const JOIN_EXPIRATION_RANGE = {
|
|
||||||
[JOIN_EXPIRATION_KEEP_CURRENT]: 'Keep current expiration',
|
|
||||||
3: 'In 3 hours',
|
|
||||||
24: 'In 1 day',
|
|
||||||
[24 * 3]: 'In 3 days',
|
|
||||||
[24 * 7]: 'In 1 week',
|
|
||||||
[24 * 30]: 'In 1 month',
|
|
||||||
[JOIN_EXPIRATION_UNLIMITED]: 'Never expire',
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function add(domainId: string, owner: number, name: string, bulletin: string) {
|
|
||||||
const ddoc: DomainDoc = {
|
|
||||||
_id: domainId,
|
|
||||||
owner,
|
|
||||||
name,
|
|
||||||
bulletin,
|
|
||||||
roles: {},
|
|
||||||
gravatar: '',
|
|
||||||
pidCounter: 0,
|
|
||||||
};
|
|
||||||
await bus.serial('domain/create', ddoc);
|
|
||||||
await coll.insertOne(ddoc);
|
|
||||||
return domainId;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function get(domainId: string): Promise<DomainDoc | null> {
|
|
||||||
const query: FilterQuery<DomainDoc> = { _id: domainId };
|
|
||||||
await bus.serial('domain/before-get', query);
|
|
||||||
const result = await coll.findOne(query);
|
|
||||||
await bus.serial('domain/get', result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getByHost(host: string): Promise<DomainDoc | null> {
|
|
||||||
const query: FilterQuery<DomainDoc> = { host };
|
|
||||||
await bus.serial('domain/before-get', query);
|
|
||||||
const result = await coll.findOne(query);
|
|
||||||
await bus.serial('domain/get', result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMulti(query: FilterQuery<DomainDoc> = {}) {
|
|
||||||
return coll.find(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function edit(domainId: string, $set: Partial<DomainDoc>) {
|
|
||||||
await bus.serial('domain/before-update', domainId, $set);
|
|
||||||
const result = await coll.findOneAndUpdate({ _id: domainId }, { $set }, { returnOriginal: false });
|
|
||||||
await bus.serial('domain/update', domainId, $set, result.value);
|
|
||||||
return result.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function inc(domainId: string, field: NumberKeys<DomainDoc>, n: number): Promise<number | null> {
|
|
||||||
const res = await coll.findOneAndUpdate(
|
|
||||||
{ _id: domainId },
|
|
||||||
// FIXME
|
|
||||||
// @ts-ignore
|
|
||||||
{ $inc: { [field]: n } },
|
|
||||||
{ returnOriginal: false },
|
|
||||||
);
|
|
||||||
return res.value[field];
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getList(domainIds: string[]): Promise<Dictionary<DomainDoc>> {
|
|
||||||
const r = {};
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
for (const domainId of domainIds) r[domainId] = await get(domainId);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setUserRole(domainId: string, uid: number, role: string) {
|
|
||||||
return collUser.updateOne({ uid, domainId }, { $set: { role } }, { upsert: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getRoles(domainId: string): Promise<any[]>;
|
|
||||||
export async function getRoles(domain: DomainDoc): Promise<any[]>;
|
|
||||||
export async function getRoles(arg: string | DomainDoc) {
|
|
||||||
let ddoc: DomainDoc;
|
|
||||||
if (typeof arg === 'string') ddoc = await get(arg);
|
|
||||||
else ddoc = arg;
|
|
||||||
const roles = [];
|
|
||||||
const r = [];
|
|
||||||
for (const role in ddoc.roles) {
|
|
||||||
roles.push({ _id: role, perm: BigInt(ddoc.roles[role]) });
|
|
||||||
r.push(role);
|
|
||||||
}
|
|
||||||
for (const role in BUILTIN_ROLES) {
|
|
||||||
if (!r.includes(role)) {
|
|
||||||
roles.push({ _id: role, perm: BUILTIN_ROLES[role] });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function setRoles(domainId: string, roles: Dictionary<bigint>) {
|
|
||||||
const current = await get(domainId);
|
|
||||||
for (const role in roles) {
|
|
||||||
current.roles[role] = roles[role].toString();
|
|
||||||
}
|
|
||||||
return await coll.updateOne({ _id: domainId }, { $set: { roles: current.roles } });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function addRole(domainId: string, name: string, permission: bigint) {
|
|
||||||
const current = await get(domainId);
|
|
||||||
current.roles[name] = permission.toString();
|
|
||||||
return await coll.updateOne({ _id: domainId }, { $set: { roles: current.roles } });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function deleteRoles(domainId: string, roles: string[]) {
|
|
||||||
const current = await get(domainId);
|
|
||||||
for (const role of roles) delete current.roles[role];
|
|
||||||
await Promise.all([
|
|
||||||
coll.updateOne({ _id: domainId }, { $set: current }),
|
|
||||||
collUser.updateMany({ domainId, role: { $in: roles } }, { $set: { role: 'default' } }),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DomainUserArg {
|
interface DomainUserArg {
|
||||||
_id: number,
|
_id: number,
|
||||||
priv: number,
|
priv: number,
|
||||||
}
|
}
|
||||||
export async function getDomainUser(domainId: string, udoc: DomainUserArg) {
|
|
||||||
let dudoc = await collUser.findOne({ domainId, uid: udoc._id });
|
|
||||||
dudoc = dudoc || {};
|
|
||||||
if (!(udoc.priv & PRIV.PRIV_USER_PROFILE)) dudoc.role = 'guest';
|
|
||||||
if (udoc.priv & PRIV.PRIV_MANAGE_ALL_DOMAIN) dudoc.role = 'admin';
|
|
||||||
dudoc.role = dudoc.role || 'default';
|
|
||||||
const ddoc = await get(domainId);
|
|
||||||
if (ddoc.owner === udoc._id) dudoc.role = 'admin';
|
|
||||||
dudoc.perm = ddoc.roles[dudoc.role]
|
|
||||||
? BigInt(ddoc.roles[dudoc.role])
|
|
||||||
: BUILTIN_ROLES[dudoc.role];
|
|
||||||
return dudoc;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setMultiUserInDomain(domainId: string, query: any, params: any) {
|
class DomainModel {
|
||||||
return collUser.updateMany({ domainId, ...query }, { $set: params });
|
static JOIN_METHOD_NONE = 0;
|
||||||
}
|
static JOIN_METHOD_ALL = 1;
|
||||||
|
static JOIN_METHOD_CODE = 2;
|
||||||
|
|
||||||
export function getMultiUserInDomain(domainId: string, query: any = {}) {
|
static JOIN_METHOD_RANGE = {
|
||||||
return collUser.find({ domainId, ...query });
|
[DomainModel.JOIN_METHOD_NONE]: 'No user is allowed to join this domain',
|
||||||
}
|
[DomainModel.JOIN_METHOD_ALL]: 'Any user is allowed to join this domain',
|
||||||
|
[DomainModel.JOIN_METHOD_CODE]: 'Any user is allowed to join this domain with an invitation code',
|
||||||
|
};
|
||||||
|
|
||||||
export function setUserInDomain(domainId: string, uid: number, params: any) {
|
static JOIN_EXPIRATION_KEEP_CURRENT = 0;
|
||||||
return collUser.updateOne({ domainId, uid }, { $set: params });
|
static JOIN_EXPIRATION_UNLIMITED = -1;
|
||||||
}
|
|
||||||
|
|
||||||
export async function incUserInDomain(domainId: string, uid: number, field: string, n = 1) {
|
static JOIN_EXPIRATION_RANGE = {
|
||||||
// @ts-ignore
|
[DomainModel.JOIN_EXPIRATION_KEEP_CURRENT]: 'Keep current expiration',
|
||||||
const dudoc = await getDomainUser(domainId, { _id: uid });
|
3: 'In 3 hours',
|
||||||
dudoc[field] = dudoc[field] + n || n;
|
24: 'In 1 day',
|
||||||
await setUserInDomain(domainId, uid, { [field]: dudoc[field] });
|
[24 * 3]: 'In 3 days',
|
||||||
return dudoc;
|
[24 * 7]: 'In 1 week',
|
||||||
}
|
[24 * 30]: 'In 1 month',
|
||||||
|
[DomainModel.JOIN_EXPIRATION_UNLIMITED]: 'Never expire',
|
||||||
|
};
|
||||||
|
|
||||||
export async function getDictUserByDomainId(uid: number) {
|
@ArgMethod
|
||||||
const [dudocs, ddocs] = await Promise.all([
|
static async add(domainId: string, owner: number, name: string, bulletin: string) {
|
||||||
collUser.find({ uid }).toArray(),
|
const ddoc: DomainDoc = {
|
||||||
coll.find({ owner: uid }).toArray(),
|
_id: domainId,
|
||||||
]);
|
owner,
|
||||||
const dudict = {};
|
name,
|
||||||
for (const dudoc of dudocs) {
|
bulletin,
|
||||||
// eslint-disable-next-line no-await-in-loop
|
roles: {},
|
||||||
dudict[dudoc.domainId] = await get(dudoc.domainId);
|
gravatar: '',
|
||||||
dudict[dudoc.domainId].role = dudoc.role;
|
pidCounter: 0,
|
||||||
|
};
|
||||||
|
await bus.serial('domain/create', ddoc);
|
||||||
|
await coll.insertOne(ddoc);
|
||||||
|
return domainId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgMethod
|
||||||
|
static async get(domainId: string): Promise<DomainDoc | null> {
|
||||||
|
const query: FilterQuery<DomainDoc> = { _id: domainId };
|
||||||
|
await bus.serial('domain/before-get', query);
|
||||||
|
const result = await coll.findOne(query);
|
||||||
|
await bus.serial('domain/get', result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgMethod
|
||||||
|
static async getByHost(host: string): Promise<DomainDoc | null> {
|
||||||
|
const query: FilterQuery<DomainDoc> = { host };
|
||||||
|
await bus.serial('domain/before-get', query);
|
||||||
|
const result = await coll.findOne(query);
|
||||||
|
await bus.serial('domain/get', result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getMulti(query: FilterQuery<DomainDoc> = {}) {
|
||||||
|
return coll.find(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async edit(domainId: string, $set: Partial<DomainDoc>) {
|
||||||
|
await bus.serial('domain/before-update', domainId, $set);
|
||||||
|
const result = await coll.findOneAndUpdate({ _id: domainId }, { $set }, { returnOriginal: false });
|
||||||
|
await bus.serial('domain/update', domainId, $set, result.value);
|
||||||
|
return result.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgMethod
|
||||||
|
static async inc(domainId: string, field: NumberKeys<DomainDoc>, n: number): Promise<number | null> {
|
||||||
|
const res = await coll.findOneAndUpdate(
|
||||||
|
{ _id: domainId },
|
||||||
|
// FIXME
|
||||||
|
// @ts-ignore
|
||||||
|
{ $inc: { [field]: n } },
|
||||||
|
{ returnOriginal: false },
|
||||||
|
);
|
||||||
|
return res.value[field];
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgMethod
|
||||||
|
static async getList(domainIds: string[]): Promise<Dictionary<DomainDoc>> {
|
||||||
|
const r = {};
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
for (const domainId of domainIds) r[domainId] = await DomainModel.get(domainId);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgMethod
|
||||||
|
static setUserRole(domainId: string, uid: number, role: string) {
|
||||||
|
return collUser.updateOne({ uid, domainId }, { $set: { role } }, { upsert: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getRoles(domainId: string): Promise<any[]>;
|
||||||
|
static async getRoles(domain: DomainDoc): Promise<any[]>;
|
||||||
|
@ArgMethod
|
||||||
|
static async getRoles(arg: string | DomainDoc) {
|
||||||
|
let ddoc: DomainDoc;
|
||||||
|
if (typeof arg === 'string') ddoc = await DomainModel.get(arg);
|
||||||
|
else ddoc = arg;
|
||||||
|
const roles = [];
|
||||||
|
const r = [];
|
||||||
|
for (const role in ddoc.roles) {
|
||||||
|
roles.push({ _id: role, perm: BigInt(ddoc.roles[role]) });
|
||||||
|
r.push(role);
|
||||||
|
}
|
||||||
|
for (const role in BUILTIN_ROLES) {
|
||||||
|
if (!r.includes(role)) {
|
||||||
|
roles.push({ _id: role, perm: BUILTIN_ROLES[role] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async setRoles(domainId: string, roles: Dictionary<bigint>) {
|
||||||
|
const current = await DomainModel.get(domainId);
|
||||||
|
for (const role in roles) {
|
||||||
|
current.roles[role] = roles[role].toString();
|
||||||
|
}
|
||||||
|
return await coll.updateOne({ _id: domainId }, { $set: { roles: current.roles } });
|
||||||
|
}
|
||||||
|
|
||||||
|
static async addRole(domainId: string, name: string, permission: bigint) {
|
||||||
|
const current = await DomainModel.get(domainId);
|
||||||
|
current.roles[name] = permission.toString();
|
||||||
|
return await coll.updateOne({ _id: domainId }, { $set: { roles: current.roles } });
|
||||||
|
}
|
||||||
|
|
||||||
|
static async deleteRoles(domainId: string, roles: string[]) {
|
||||||
|
const current = await DomainModel.get(domainId);
|
||||||
|
for (const role of roles) delete current.roles[role];
|
||||||
|
await Promise.all([
|
||||||
|
coll.updateOne({ _id: domainId }, { $set: current }),
|
||||||
|
collUser.updateMany({ domainId, role: { $in: roles } }, { $set: { role: 'default' } }),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getDomainUser(domainId: string, udoc: DomainUserArg) {
|
||||||
|
let dudoc = await collUser.findOne({ domainId, uid: udoc._id });
|
||||||
|
dudoc = dudoc || {};
|
||||||
|
if (!(udoc.priv & PRIV.PRIV_USER_PROFILE)) dudoc.role = 'guest';
|
||||||
|
if (udoc.priv & PRIV.PRIV_MANAGE_ALL_DOMAIN) dudoc.role = 'admin';
|
||||||
|
dudoc.role = dudoc.role || 'default';
|
||||||
|
const ddoc = await DomainModel.get(domainId);
|
||||||
|
if (ddoc.owner === udoc._id) dudoc.role = 'admin';
|
||||||
|
dudoc.perm = ddoc.roles[dudoc.role]
|
||||||
|
? BigInt(ddoc.roles[dudoc.role])
|
||||||
|
: BUILTIN_ROLES[dudoc.role];
|
||||||
|
return dudoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static setMultiUserInDomain(domainId: string, query: any, params: any) {
|
||||||
|
return collUser.updateMany({ domainId, ...query }, { $set: params });
|
||||||
|
}
|
||||||
|
|
||||||
|
static getMultiUserInDomain(domainId: string, query: any = {}) {
|
||||||
|
return collUser.find({ domainId, ...query });
|
||||||
|
}
|
||||||
|
|
||||||
|
static setUserInDomain(domainId: string, uid: number, params: any) {
|
||||||
|
return collUser.updateOne({ domainId, uid }, { $set: params });
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgMethod
|
||||||
|
static async incUserInDomain(domainId: string, uid: number, field: string, n: number = 1) {
|
||||||
|
// @ts-ignore
|
||||||
|
const dudoc = await getDomainUser(domainId, { _id: uid });
|
||||||
|
dudoc[field] = dudoc[field] + n || n;
|
||||||
|
await DomainModel.setUserInDomain(domainId, uid, { [field]: dudoc[field] });
|
||||||
|
return dudoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgMethod
|
||||||
|
static async getDictUserByDomainId(uid: number) {
|
||||||
|
const [dudocs, ddocs] = await Promise.all([
|
||||||
|
collUser.find({ uid }).toArray(),
|
||||||
|
coll.find({ owner: uid }).toArray(),
|
||||||
|
]);
|
||||||
|
const dudict = {};
|
||||||
|
for (const dudoc of dudocs) {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
dudict[dudoc.domainId] = await DomainModel.get(dudoc.domainId);
|
||||||
|
dudict[dudoc.domainId].role = dudoc.role;
|
||||||
|
}
|
||||||
|
for (const ddoc of ddocs) dudict[ddoc._id] = 'admin';
|
||||||
|
return dudict;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getJoinSettings(ddoc: DomainDoc, roles: string[]) {
|
||||||
|
if (!ddoc.join) return null;
|
||||||
|
const joinSettings = ddoc.join;
|
||||||
|
if (joinSettings.method === DomainModel.JOIN_METHOD_NONE) return null;
|
||||||
|
if (!roles.includes(joinSettings.role)) return null;
|
||||||
|
if (joinSettings.expire && joinSettings.expire < new Date()) return null;
|
||||||
|
return joinSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgMethod
|
||||||
|
static async getPrefixSearch(prefix: string, limit: number = 50) {
|
||||||
|
const $regex = new RegExp(prefix, 'mi');
|
||||||
|
const ddocs = await coll.find({
|
||||||
|
$or: [{ _id: { $regex } }, { name: { $regex } }],
|
||||||
|
}).limit(limit).toArray();
|
||||||
|
return ddocs;
|
||||||
}
|
}
|
||||||
for (const ddoc of ddocs) dudict[ddoc._id] = 'admin';
|
|
||||||
return dudict;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getJoinSettings(ddoc: DomainDoc, roles: string[]) {
|
export = DomainModel;
|
||||||
if (!ddoc.join) return null;
|
global.Hydro.model.domain = DomainModel;
|
||||||
const joinSettings = ddoc.join;
|
|
||||||
if (joinSettings.method === JOIN_METHOD_NONE) return null;
|
|
||||||
if (!roles.includes(joinSettings.role)) return null;
|
|
||||||
if (joinSettings.expire && joinSettings.expire < new Date()) return null;
|
|
||||||
return joinSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getPrefixSearch(prefix: string, limit = 50) {
|
|
||||||
const $regex = new RegExp(prefix, 'mi');
|
|
||||||
const ddocs = await coll.find({
|
|
||||||
$or: [{ _id: { $regex } }, { name: { $regex } }],
|
|
||||||
}).limit(limit).toArray();
|
|
||||||
return ddocs;
|
|
||||||
}
|
|
||||||
|
|
||||||
global.Hydro.model.domain = {
|
|
||||||
JOIN_METHOD_NONE,
|
|
||||||
JOIN_METHOD_ALL,
|
|
||||||
JOIN_METHOD_CODE,
|
|
||||||
JOIN_METHOD_RANGE,
|
|
||||||
JOIN_EXPIRATION_KEEP_CURRENT,
|
|
||||||
JOIN_EXPIRATION_UNLIMITED,
|
|
||||||
JOIN_EXPIRATION_RANGE,
|
|
||||||
|
|
||||||
getRoles,
|
|
||||||
add,
|
|
||||||
inc,
|
|
||||||
get,
|
|
||||||
getByHost,
|
|
||||||
edit,
|
|
||||||
getMulti,
|
|
||||||
getList,
|
|
||||||
setRoles,
|
|
||||||
addRole,
|
|
||||||
deleteRoles,
|
|
||||||
setUserRole,
|
|
||||||
getDomainUser,
|
|
||||||
setMultiUserInDomain,
|
|
||||||
setUserInDomain,
|
|
||||||
incUserInDomain,
|
|
||||||
getMultiUserInDomain,
|
|
||||||
getDictUserByDomainId,
|
|
||||||
getJoinSettings,
|
|
||||||
getPrefixSearch,
|
|
||||||
};
|
|
||||||
@@ -1,65 +1,71 @@
|
|||||||
import { FilterQuery, ObjectID } from 'mongodb';
|
import { FilterQuery, ObjectID } from 'mongodb';
|
||||||
import user from './user';
|
import user from './user';
|
||||||
import { Mdoc } from '../interface';
|
import { Mdoc } from '../interface';
|
||||||
|
import { ArgMethod } from '../utils';
|
||||||
import db from '../service/db';
|
import db from '../service/db';
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
|
|
||||||
const coll = db.collection('message');
|
const coll = db.collection('message');
|
||||||
|
|
||||||
export const FLAG_UNREAD = 1;
|
class MessageModel {
|
||||||
export const FLAG_ALERT = 2;
|
static FLAG_UNREAD = 1;
|
||||||
|
static FLAG_ALERT = 2;
|
||||||
|
|
||||||
export async function send(
|
@ArgMethod
|
||||||
from: number, to: number,
|
static async send(
|
||||||
content: string, flag: number = FLAG_UNREAD,
|
from: number, to: number,
|
||||||
): Promise<Mdoc> {
|
content: string, flag: number = MessageModel.FLAG_UNREAD,
|
||||||
const res = await coll.insertOne({
|
): Promise<Mdoc> {
|
||||||
from, to, content, flag,
|
const res = await coll.insertOne({
|
||||||
});
|
from, to, content, flag,
|
||||||
const mdoc = {
|
});
|
||||||
from, to, content, _id: res.insertedId, flag,
|
const mdoc = {
|
||||||
};
|
from, to, content, _id: res.insertedId, flag,
|
||||||
if (from !== to) {
|
};
|
||||||
// ENHANCE domainId?
|
if (from !== to) {
|
||||||
const udoc = await user.getById('system', to);
|
// ENHANCE domainId?
|
||||||
bus.boardcast('user/message', to, mdoc, udoc);
|
const udoc = await user.getById('system', to);
|
||||||
|
bus.boardcast('user/message', to, mdoc, udoc);
|
||||||
|
}
|
||||||
|
return mdoc;
|
||||||
}
|
}
|
||||||
return mdoc;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function get(_id: ObjectID): Promise<Mdoc | null> {
|
static async get(_id: ObjectID): Promise<Mdoc | null> {
|
||||||
return await coll.findOne({ _id });
|
return await coll.findOne({ _id });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getByUser(uid: number): Promise<Mdoc[]> {
|
@ArgMethod
|
||||||
return await coll.find({ $or: [{ from: uid }, { to: uid }] }).sort('_id', 1).toArray();
|
static async getByUser(uid: number): Promise<Mdoc[]> {
|
||||||
}
|
return await coll.find({ $or: [{ from: uid }, { to: uid }] }).sort('_id', 1).toArray();
|
||||||
|
}
|
||||||
|
|
||||||
export async function getMany(query: FilterQuery<Mdoc>, sort: any, page: number, limit: number): Promise<Mdoc[]> {
|
static async getMany(query: FilterQuery<Mdoc>, sort: any, page: number, limit: number): Promise<Mdoc[]> {
|
||||||
return await coll.find(query).sort(sort)
|
return await coll.find(query).sort(sort)
|
||||||
.skip((page - 1) * limit).limit(limit)
|
.skip((page - 1) * limit).limit(limit)
|
||||||
.toArray();
|
.toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setFlag(messageId: ObjectID, flag: number): Promise<Mdoc | null> {
|
static async setFlag(messageId: ObjectID, flag: number): Promise<Mdoc | null> {
|
||||||
const result = await coll.findOneAndUpdate(
|
const result = await coll.findOneAndUpdate(
|
||||||
{ _id: messageId },
|
{ _id: messageId },
|
||||||
{ $bit: { flag: { xor: flag } } },
|
{ $bit: { flag: { xor: flag } } },
|
||||||
{ returnOriginal: false },
|
{ returnOriginal: false },
|
||||||
);
|
);
|
||||||
return result.value;
|
return result.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function del(_id: ObjectID) {
|
static async del(_id: ObjectID) {
|
||||||
return await coll.deleteOne({ _id });
|
return await coll.deleteOne({ _id });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function count(query: FilterQuery<Mdoc> = {}) {
|
@ArgMethod
|
||||||
return coll.find(query).count();
|
static count(query: FilterQuery<Mdoc> = {}) {
|
||||||
}
|
return coll.find(query).count();
|
||||||
|
}
|
||||||
|
|
||||||
export function getMulti(uid: number) {
|
static getMulti(uid: number) {
|
||||||
return coll.find({ $or: [{ from: uid }, { to: uid }] });
|
return coll.find({ $or: [{ from: uid }, { to: uid }] });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureIndexes() {
|
function ensureIndexes() {
|
||||||
@@ -70,16 +76,5 @@ function ensureIndexes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bus.once('app/started', ensureIndexes);
|
bus.once('app/started', ensureIndexes);
|
||||||
global.Hydro.model.message = {
|
export = MessageModel;
|
||||||
FLAG_UNREAD,
|
global.Hydro.model.message = MessageModel;
|
||||||
FLAG_ALERT,
|
|
||||||
|
|
||||||
count,
|
|
||||||
get,
|
|
||||||
getByUser,
|
|
||||||
del,
|
|
||||||
setFlag,
|
|
||||||
getMany,
|
|
||||||
getMulti,
|
|
||||||
send,
|
|
||||||
};
|
|
||||||
@@ -12,25 +12,25 @@ const cache = new Lru({
|
|||||||
maxAge: 5000,
|
maxAge: 5000,
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function get(_id: string) {
|
class OauthModel {
|
||||||
const res = cache.get(_id);
|
static async get(_id: string) {
|
||||||
if (res !== undefined) return res;
|
const res = cache.get(_id);
|
||||||
const doc = await coll.findOne({ _id });
|
if (res !== undefined) return res;
|
||||||
if (doc) return doc.uid;
|
const doc = await coll.findOne({ _id });
|
||||||
return null;
|
if (doc) return doc.uid;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async set(_id: string, value: number) {
|
||||||
|
cache.set(_id, value);
|
||||||
|
const res = await coll.findOneAndUpdate(
|
||||||
|
{ _id },
|
||||||
|
{ $set: { value } },
|
||||||
|
{ upsert: true, returnOriginal: false },
|
||||||
|
);
|
||||||
|
return res.value.uid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function set(_id: string, value: number) {
|
export = OauthModel;
|
||||||
cache.set(_id, value);
|
global.Hydro.model.oauth = OauthModel;
|
||||||
const res = await coll.findOneAndUpdate(
|
|
||||||
{ _id },
|
|
||||||
{ $set: { value } },
|
|
||||||
{ upsert: true, returnOriginal: false },
|
|
||||||
);
|
|
||||||
return res.value.uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
global.Hydro.model.oauth = {
|
|
||||||
get,
|
|
||||||
set,
|
|
||||||
};
|
|
||||||
@@ -3,7 +3,7 @@ import { ObjectID, FilterQuery } from 'mongodb';
|
|||||||
import { Dictionary, pick } from 'lodash';
|
import { Dictionary, pick } from 'lodash';
|
||||||
import { STATUS } from './builtin';
|
import { STATUS } from './builtin';
|
||||||
import * as document from './document';
|
import * as document from './document';
|
||||||
import * as domain from './domain';
|
import domain from './domain';
|
||||||
import { buildProjection } from '../utils';
|
import { buildProjection } from '../utils';
|
||||||
import type { ProblemStatusDoc, Pdict, Document } from '../interface';
|
import type { ProblemStatusDoc, Pdict, Document } from '../interface';
|
||||||
import { Content } from '../loader';
|
import { Content } from '../loader';
|
||||||
|
|||||||
@@ -4,213 +4,167 @@ import {
|
|||||||
import { Dictionary } from 'lodash';
|
import { Dictionary } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { STATUS } from './builtin';
|
import { STATUS } from './builtin';
|
||||||
import * as task from './task';
|
import task from './task';
|
||||||
import * as problem from './problem';
|
import * as problem from './problem';
|
||||||
import {
|
import { Rdoc, ContestInfo, ProblemConfig } from '../interface';
|
||||||
Rdoc, TestCase, ContestInfo, ProblemConfig,
|
import { ArgMethod, Time } from '../utils';
|
||||||
} from '../interface';
|
|
||||||
import { Time } from '../utils';
|
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
import db from '../service/db';
|
import db from '../service/db';
|
||||||
|
|
||||||
export const coll: Collection<Rdoc> = db.collection('record');
|
class RecordModel {
|
||||||
|
static coll: Collection<Rdoc> = db.collection('record');
|
||||||
|
|
||||||
export interface RdocBase {
|
static async get(domainId: string, _id: ObjectID): Promise<Rdoc | null> {
|
||||||
_id?: ObjectID,
|
const res = await RecordModel.coll.findOne({ _id });
|
||||||
domainId?: string,
|
if (res && res.domainId === domainId) return res;
|
||||||
pid: number
|
return null;
|
||||||
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 JudgeTask {
|
|
||||||
_id: ObjectID,
|
|
||||||
rid: ObjectID,
|
|
||||||
domainId: string,
|
|
||||||
pid: number
|
|
||||||
lang: string,
|
|
||||||
code: string,
|
|
||||||
data?: ObjectID,
|
|
||||||
config: string,
|
|
||||||
type?: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function get(domainId: string, _id: ObjectID): Promise<Rdoc | null> {
|
|
||||||
const res = await coll.findOne({ _id });
|
|
||||||
if (res && res.domainId === domainId) return res;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function stat(domainId?: string) {
|
|
||||||
const [d5min, d1h, day, week, month, year, 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, 'week')) }, ...domainId ? { domainId } : {} }).count(),
|
|
||||||
coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'month')) }, ...domainId ? { domainId } : {} }).count(),
|
|
||||||
coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'year')) }, ...domainId ? { domainId } : {} }).count(),
|
|
||||||
coll.find(domainId ? { domainId } : {}).count(),
|
|
||||||
]);
|
|
||||||
return {
|
|
||||||
d5min, d1h, day, week, month, year, total,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function judge(domainId: string, rid: ObjectID, priority = 1, config: ProblemConfig = {}) {
|
|
||||||
const rdoc = await get(domainId, rid);
|
|
||||||
let data = [];
|
|
||||||
if (rdoc.pid) {
|
|
||||||
const pdoc = await problem.get(domainId, rdoc.pid);
|
|
||||||
data = pdoc.data;
|
|
||||||
}
|
}
|
||||||
delete rdoc._id;
|
|
||||||
await task.add({
|
|
||||||
...rdoc,
|
|
||||||
priority,
|
|
||||||
type: 'judge',
|
|
||||||
rid,
|
|
||||||
domainId,
|
|
||||||
config,
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function add(
|
@ArgMethod
|
||||||
domainId: string, pid: number, uid: number,
|
static async stat(domainId?: string) {
|
||||||
lang: string, code: string, addTask: boolean, contestOrConfig?: ContestInfo | string,
|
const [d5min, d1h, day, week, month, year, total] = await Promise.all([
|
||||||
) {
|
RecordModel.coll.find({ _id: { $gte: Time.getObjectID(moment().add(-5, 'minutes')) }, ...domainId ? { domainId } : {} }).count(),
|
||||||
const data: Rdoc = {
|
RecordModel.coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'hour')) }, ...domainId ? { domainId } : {} }).count(),
|
||||||
status: STATUS.STATUS_WAITING,
|
RecordModel.coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'day')) }, ...domainId ? { domainId } : {} }).count(),
|
||||||
_id: new ObjectID(),
|
RecordModel.coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'week')) }, ...domainId ? { domainId } : {} }).count(),
|
||||||
uid,
|
RecordModel.coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'month')) }, ...domainId ? { domainId } : {} }).count(),
|
||||||
code,
|
RecordModel.coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'year')) }, ...domainId ? { domainId } : {} }).count(),
|
||||||
lang,
|
RecordModel.coll.find(domainId ? { domainId } : {}).count(),
|
||||||
pid,
|
]);
|
||||||
domainId,
|
return {
|
||||||
score: 0,
|
d5min, d1h, day, week, month, year, total,
|
||||||
time: 0,
|
};
|
||||||
memory: 0,
|
|
||||||
hidden: false,
|
|
||||||
judgeTexts: [],
|
|
||||||
compilerTexts: [],
|
|
||||||
testCases: [],
|
|
||||||
judger: null,
|
|
||||||
judgeAt: null,
|
|
||||||
rejudged: false,
|
|
||||||
};
|
|
||||||
if (typeof contestOrConfig === 'string') {
|
|
||||||
// is Run
|
|
||||||
data.input = contestOrConfig;
|
|
||||||
data.hidden = true;
|
|
||||||
} else data.contest = contestOrConfig;
|
|
||||||
const res = await coll.insertOne(data);
|
|
||||||
if (addTask) await judge(domainId, res.insertedId);
|
|
||||||
return res.insertedId;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMulti(domainId: string, query: any) {
|
|
||||||
return coll.find({ ...query, domainId });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function update(
|
|
||||||
domainId: string, _id: ObjectID,
|
|
||||||
$set?: MatchKeysAndValues<Rdoc>,
|
|
||||||
$push?: PushOperator<Rdoc>,
|
|
||||||
$unset?: OnlyFieldsOfType<Rdoc, any, true | '' | 1>,
|
|
||||||
): Promise<Rdoc | null> {
|
|
||||||
const $update: UpdateQuery<Rdoc> = {};
|
|
||||||
if ($set && Object.keys($set).length) $update.$set = $set;
|
|
||||||
if ($push && Object.keys($push).length) $update.$push = $push;
|
|
||||||
if ($unset && Object.keys($unset).length) $update.$unset = $unset;
|
|
||||||
if (Object.keys($update).length) {
|
|
||||||
const res = await coll.findOneAndUpdate(
|
|
||||||
{ _id, domainId },
|
|
||||||
$update,
|
|
||||||
{ returnOriginal: false },
|
|
||||||
);
|
|
||||||
return res.value;
|
|
||||||
}
|
}
|
||||||
return await get(domainId, _id);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function reset(domainId: string, rid: ObjectID, isRejudge: boolean) {
|
static async judge(domainId: string, rid: ObjectID, priority = 1, config: ProblemConfig = {}) {
|
||||||
const upd: any = {
|
const rdoc = await RecordModel.get(domainId, rid);
|
||||||
score: 0,
|
let data = [];
|
||||||
status: STATUS.STATUS_WAITING,
|
if (rdoc.pid) {
|
||||||
time: 0,
|
const pdoc = await problem.get(domainId, rdoc.pid);
|
||||||
memory: 0,
|
data = pdoc.data;
|
||||||
testCases: [],
|
}
|
||||||
judgeTexts: [],
|
delete rdoc._id;
|
||||||
compilerTexts: [],
|
await task.add({
|
||||||
judgeAt: null,
|
...rdoc,
|
||||||
judger: null,
|
priority,
|
||||||
};
|
type: 'judge',
|
||||||
if (isRejudge) upd.rejudged = true;
|
rid,
|
||||||
return update(domainId, rid, upd);
|
domainId,
|
||||||
}
|
config,
|
||||||
|
data,
|
||||||
export function count(domainId: string, query: any) {
|
|
||||||
return coll.find({ domainId, ...query }).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getList(
|
|
||||||
domainId: string, rids: ObjectID[], showHidden: boolean,
|
|
||||||
): Promise<Dictionary<Rdoc>> {
|
|
||||||
const r = {};
|
|
||||||
rids = Array.from(new Set(rids));
|
|
||||||
const rdocs = await coll.find({ domainId, _id: { $in: rids } }).toArray();
|
|
||||||
for (const rdoc of rdocs) {
|
|
||||||
if (rdoc.hidden && !showHidden) r[rdoc._id.toHexString()] = null;
|
|
||||||
else r[rdoc._id.toHexString()] = rdoc;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getUserInProblemMulti(
|
|
||||||
domainId: string, uid: number, pid: number,
|
|
||||||
getHidden = false,
|
|
||||||
) {
|
|
||||||
if (!getHidden) {
|
|
||||||
return coll.find({
|
|
||||||
domainId, uid, pid, hidden: false,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return coll.find({ domainId, uid, pid });
|
|
||||||
|
static async add(
|
||||||
|
domainId: string, pid: number, uid: number,
|
||||||
|
lang: string, code: string, addTask: boolean, contestOrConfig?: ContestInfo | string,
|
||||||
|
) {
|
||||||
|
const data: Rdoc = {
|
||||||
|
status: STATUS.STATUS_WAITING,
|
||||||
|
_id: new ObjectID(),
|
||||||
|
uid,
|
||||||
|
code,
|
||||||
|
lang,
|
||||||
|
pid,
|
||||||
|
domainId,
|
||||||
|
score: 0,
|
||||||
|
time: 0,
|
||||||
|
memory: 0,
|
||||||
|
hidden: false,
|
||||||
|
judgeTexts: [],
|
||||||
|
compilerTexts: [],
|
||||||
|
testCases: [],
|
||||||
|
judger: null,
|
||||||
|
judgeAt: null,
|
||||||
|
rejudged: false,
|
||||||
|
};
|
||||||
|
if (typeof contestOrConfig === 'string') {
|
||||||
|
// is Run
|
||||||
|
data.input = contestOrConfig;
|
||||||
|
data.hidden = true;
|
||||||
|
} else data.contest = contestOrConfig;
|
||||||
|
const res = await RecordModel.coll.insertOne(data);
|
||||||
|
if (addTask) await RecordModel.judge(domainId, res.insertedId);
|
||||||
|
return res.insertedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getMulti(domainId: string, query: any) {
|
||||||
|
return RecordModel.coll.find({ ...query, domainId });
|
||||||
|
}
|
||||||
|
|
||||||
|
static async update(
|
||||||
|
domainId: string, _id: ObjectID,
|
||||||
|
$set?: MatchKeysAndValues<Rdoc>,
|
||||||
|
$push?: PushOperator<Rdoc>,
|
||||||
|
$unset?: OnlyFieldsOfType<Rdoc, any, true | '' | 1>,
|
||||||
|
): Promise<Rdoc | null> {
|
||||||
|
const $update: UpdateQuery<Rdoc> = {};
|
||||||
|
if ($set && Object.keys($set).length) $update.$set = $set;
|
||||||
|
if ($push && Object.keys($push).length) $update.$push = $push;
|
||||||
|
if ($unset && Object.keys($unset).length) $update.$unset = $unset;
|
||||||
|
if (Object.keys($update).length) {
|
||||||
|
const res = await RecordModel.coll.findOneAndUpdate(
|
||||||
|
{ _id, domainId },
|
||||||
|
$update,
|
||||||
|
{ returnOriginal: false },
|
||||||
|
);
|
||||||
|
return res.value;
|
||||||
|
}
|
||||||
|
return await RecordModel.get(domainId, _id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static reset(domainId: string, rid: ObjectID, isRejudge: boolean) {
|
||||||
|
const upd: any = {
|
||||||
|
score: 0,
|
||||||
|
status: STATUS.STATUS_WAITING,
|
||||||
|
time: 0,
|
||||||
|
memory: 0,
|
||||||
|
testCases: [],
|
||||||
|
judgeTexts: [],
|
||||||
|
compilerTexts: [],
|
||||||
|
judgeAt: null,
|
||||||
|
judger: null,
|
||||||
|
};
|
||||||
|
if (isRejudge) upd.rejudged = true;
|
||||||
|
return RecordModel.update(domainId, rid, upd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static count(domainId: string, query: any) {
|
||||||
|
return RecordModel.coll.find({ domainId, ...query }).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getList(
|
||||||
|
domainId: string, rids: ObjectID[], showHidden: boolean,
|
||||||
|
): Promise<Dictionary<Rdoc>> {
|
||||||
|
const r = {};
|
||||||
|
rids = Array.from(new Set(rids));
|
||||||
|
const rdocs = await RecordModel.coll.find({ domainId, _id: { $in: rids } }).toArray();
|
||||||
|
for (const rdoc of rdocs) {
|
||||||
|
if (rdoc.hidden && !showHidden) r[rdoc._id.toHexString()] = null;
|
||||||
|
else r[rdoc._id.toHexString()] = rdoc;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgMethod
|
||||||
|
static getUserInProblemMulti(
|
||||||
|
domainId: string, uid: number, pid: number,
|
||||||
|
getHidden: boolean = false,
|
||||||
|
) {
|
||||||
|
if (!getHidden) {
|
||||||
|
return RecordModel.coll.find({
|
||||||
|
domainId, uid, pid, hidden: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return RecordModel.coll.find({ domainId, uid, pid });
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgMethod
|
||||||
|
static getByUid(domainId: string, uid: number, limit: number): Promise<Rdoc[]> {
|
||||||
|
return RecordModel.coll.find({ domainId, uid }).limit(limit).toArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getByUid(domainId: string, uid: number, limit: number): Promise<Rdoc[]> {
|
bus.on('problem/delete', (domainId, docId) => RecordModel.coll.deleteMany({ domainId, pid: docId }));
|
||||||
return coll.find({ domainId, uid }).limit(limit).toArray();
|
export = RecordModel;
|
||||||
}
|
global.Hydro.model.record = RecordModel;
|
||||||
|
|
||||||
bus.on('problem/delete', (domainId, docId) => coll.deleteMany({ domainId, pid: docId }));
|
|
||||||
|
|
||||||
global.Hydro.model.record = {
|
|
||||||
coll,
|
|
||||||
add,
|
|
||||||
get,
|
|
||||||
getMulti,
|
|
||||||
stat,
|
|
||||||
update,
|
|
||||||
count,
|
|
||||||
reset,
|
|
||||||
getList,
|
|
||||||
getUserInProblemMulti,
|
|
||||||
getByUid,
|
|
||||||
judge,
|
|
||||||
};
|
|
||||||
@@ -3,80 +3,82 @@ import * as document from './document';
|
|||||||
import { SolutionNotFoundError } from '../error';
|
import { SolutionNotFoundError } from '../error';
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
|
|
||||||
export function add(domainId: string, pid: number, owner: number, content: string) {
|
class SolutionModel {
|
||||||
return document.add(
|
static add(domainId: string, pid: number, owner: number, content: string) {
|
||||||
domainId, content, owner, document.TYPE_PROBLEM_SOLUTION,
|
return document.add(
|
||||||
null, document.TYPE_PROBLEM, pid, { reply: [], vote: 0 },
|
domainId, content, owner, document.TYPE_PROBLEM_SOLUTION,
|
||||||
);
|
null, document.TYPE_PROBLEM, pid, { reply: [], vote: 0 },
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export async function get(domainId: string, psid: ObjectID) {
|
static async get(domainId: string, psid: ObjectID) {
|
||||||
const psdoc = await document.get(domainId, document.TYPE_PROBLEM_SOLUTION, psid);
|
const psdoc = await document.get(domainId, document.TYPE_PROBLEM_SOLUTION, psid);
|
||||||
if (!psdoc) throw new SolutionNotFoundError();
|
if (!psdoc) throw new SolutionNotFoundError();
|
||||||
return psdoc;
|
return psdoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMany(domainId: string, query: any, sort: any, page: number, limit: number) {
|
static getMany(domainId: string, query: any, sort: any, page: number, limit: number) {
|
||||||
return document.getMulti(domainId, document.TYPE_PROBLEM_SOLUTION, query)
|
return document.getMulti(domainId, document.TYPE_PROBLEM_SOLUTION, query)
|
||||||
.sort(sort)
|
.sort(sort)
|
||||||
.skip((page - 1) * limit).limit(limit)
|
.skip((page - 1) * limit).limit(limit)
|
||||||
.toArray();
|
.toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function edit(domainId: string, psid: ObjectID, content: string) {
|
static 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 async function del(domainId: string, psid: ObjectID) {
|
static async del(domainId: string, psid: ObjectID) {
|
||||||
return await Promise.all([
|
return await Promise.all([
|
||||||
document.deleteOne(domainId, document.TYPE_PROBLEM_SOLUTION, psid),
|
document.deleteOne(domainId, document.TYPE_PROBLEM_SOLUTION, psid),
|
||||||
document.deleteMultiStatus(domainId, document.TYPE_PROBLEM_SOLUTION, { docId: psid }),
|
document.deleteMultiStatus(domainId, document.TYPE_PROBLEM_SOLUTION, { docId: psid }),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function count(domainId: string, query: any) {
|
static count(domainId: string, query: any) {
|
||||||
return document.count(domainId, document.TYPE_PROBLEM_SOLUTION, query);
|
return document.count(domainId, document.TYPE_PROBLEM_SOLUTION, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMulti(domainId: string, pid: number) {
|
static getMulti(domainId: string, pid: number) {
|
||||||
return document.getMulti(
|
return document.getMulti(
|
||||||
domainId, document.TYPE_PROBLEM_SOLUTION,
|
domainId, document.TYPE_PROBLEM_SOLUTION,
|
||||||
{ parentType: document.TYPE_PROBLEM, parentId: pid },
|
{ parentType: document.TYPE_PROBLEM, parentId: pid },
|
||||||
).sort({ vote: -1 });
|
).sort({ vote: -1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function reply(domainId: string, psid: ObjectID, owner: number, content: string) {
|
static reply(domainId: string, psid: ObjectID, owner: number, content: string) {
|
||||||
return document.push(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', content, owner);
|
return document.push(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', content, owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getReply(domainId: string, psid: ObjectID, psrid: ObjectID) {
|
static getReply(domainId: string, psid: ObjectID, psrid: ObjectID) {
|
||||||
return document.getSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid);
|
return document.getSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function editReply(domainId: string, psid: ObjectID, psrid: ObjectID, content: string) {
|
static editReply(domainId: string, psid: ObjectID, psrid: ObjectID, content: string) {
|
||||||
return document.setSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid, { content });
|
return document.setSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid, { content });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function delReply(domainId: string, psid: ObjectID, psrid: ObjectID) {
|
static delReply(domainId: string, psid: ObjectID, psrid: ObjectID) {
|
||||||
return document.deleteSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid);
|
return document.deleteSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function vote(domainId: string, psid: ObjectID, uid: number, value: number) {
|
static async vote(domainId: string, psid: ObjectID, uid: number, value: number) {
|
||||||
let pssdoc = await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid);
|
let pssdoc = await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid);
|
||||||
await document.setStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid, { vote: value });
|
await document.setStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid, { vote: value });
|
||||||
if (pssdoc) value += -pssdoc.vote;
|
if (pssdoc) value += -pssdoc.vote;
|
||||||
const psdoc = await document.inc(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'vote', value);
|
const psdoc = await document.inc(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'vote', value);
|
||||||
pssdoc = await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid);
|
pssdoc = await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid);
|
||||||
return [psdoc, pssdoc];
|
return [psdoc, pssdoc];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getListStatus(domainId: string, psids: ObjectID[], uid: number) {
|
static async getListStatus(domainId: string, psids: ObjectID[], uid: number) {
|
||||||
const result = {};
|
const result = {};
|
||||||
const res = await document.getMultiStatus(
|
const res = await document.getMultiStatus(
|
||||||
domainId, document.TYPE_PROBLEM_SOLUTION, { uid, psid: { $in: psids } },
|
domainId, document.TYPE_PROBLEM_SOLUTION, { uid, psid: { $in: psids } },
|
||||||
).toArray();
|
).toArray();
|
||||||
for (const i of res) result[i.psid] = i;
|
for (const i of res) result[i.psid] = i;
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bus.on('problem/delete', async (domainId, docId) => {
|
bus.on('problem/delete', async (domainId, docId) => {
|
||||||
@@ -90,18 +92,5 @@ bus.on('problem/delete', async (domainId, docId) => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
global.Hydro.model.solution = {
|
export = SolutionModel;
|
||||||
count,
|
global.Hydro.model.solution = SolutionModel;
|
||||||
add,
|
|
||||||
get,
|
|
||||||
edit,
|
|
||||||
del,
|
|
||||||
getMany,
|
|
||||||
getMulti,
|
|
||||||
reply,
|
|
||||||
getReply,
|
|
||||||
editReply,
|
|
||||||
delReply,
|
|
||||||
vote,
|
|
||||||
getListStatus,
|
|
||||||
};
|
|
||||||
@@ -7,98 +7,95 @@ import db from '../service/db';
|
|||||||
const logger = new Logger('model/task');
|
const logger = new Logger('model/task');
|
||||||
const coll = db.collection('task');
|
const coll = db.collection('task');
|
||||||
|
|
||||||
export async function add(task: Partial<Task> & { type: string }) {
|
class TaskModel {
|
||||||
const t: Task = {
|
static async add(task: Partial<Task> & { type: string }) {
|
||||||
...task,
|
const t: Task = {
|
||||||
count: task.count ?? 1,
|
...task,
|
||||||
priority: task.priority ?? 1,
|
count: task.count ?? 1,
|
||||||
executeAfter: task.executeAfter || new Date(),
|
priority: task.priority ?? 1,
|
||||||
_id: new ObjectID(),
|
executeAfter: task.executeAfter || new Date(),
|
||||||
};
|
_id: new ObjectID(),
|
||||||
const res = await coll.insertOne(t);
|
};
|
||||||
return res.insertedId;
|
const res = await coll.insertOne(t);
|
||||||
}
|
return res.insertedId;
|
||||||
|
|
||||||
export function get(_id: ObjectID) {
|
|
||||||
return coll.findOne({ _id });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function count(query: FilterQuery<Task>) {
|
|
||||||
return coll.find(query).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function del(_id: ObjectID) {
|
|
||||||
return coll.deleteOne({ _id });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getFirst(query: FilterQuery<Task>) {
|
|
||||||
const q = { ...query };
|
|
||||||
q.executeAfter = q.executeAfter || { $lt: new Date() };
|
|
||||||
const res = await coll.findOneAndDelete(q, { sort: { priority: -1 } });
|
|
||||||
if (res.value) {
|
|
||||||
logger.debug('%o', res.value);
|
|
||||||
if (res.value.interval) {
|
|
||||||
await coll.insertOne({
|
|
||||||
...res.value, executeAfter: moment().add(...res.value.interval).toDate(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return res.value;
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function consume(query: any, cb: Function) {
|
static get(_id: ObjectID) {
|
||||||
let isRunning = false;
|
return coll.findOne({ _id });
|
||||||
const interval = setInterval(async () => {
|
}
|
||||||
if (isRunning) return;
|
|
||||||
isRunning = true;
|
static count(query: FilterQuery<Task>) {
|
||||||
const res = await getFirst(query);
|
return coll.find(query).count();
|
||||||
if (res) {
|
}
|
||||||
try {
|
|
||||||
await cb(res);
|
static del(_id: ObjectID) {
|
||||||
} catch (e) {
|
return coll.deleteOne({ _id });
|
||||||
clearInterval(interval);
|
}
|
||||||
|
|
||||||
|
static async getFirst(query: FilterQuery<Task>) {
|
||||||
|
const q = { ...query };
|
||||||
|
q.executeAfter = q.executeAfter || { $lt: new Date() };
|
||||||
|
const res = await coll.findOneAndDelete(q, { sort: { priority: -1 } });
|
||||||
|
if (res.value) {
|
||||||
|
logger.debug('%o', res.value);
|
||||||
|
if (res.value.interval) {
|
||||||
|
await coll.insertOne({
|
||||||
|
...res.value, executeAfter: moment().add(...res.value.interval).toDate(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return res.value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async consume(query: any, cb: Function) {
|
||||||
|
let isRunning = false;
|
||||||
|
const interval = setInterval(async () => {
|
||||||
|
if (isRunning) return;
|
||||||
|
isRunning = true;
|
||||||
|
const res = await TaskModel.getFirst(query);
|
||||||
|
if (res) {
|
||||||
|
try {
|
||||||
|
await cb(res);
|
||||||
|
} catch (e) {
|
||||||
|
clearInterval(interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isRunning = false;
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
Consumer = class Consumer {
|
||||||
|
consuming: boolean;
|
||||||
|
running?: Promise<any>;
|
||||||
|
interval: NodeJS.Timeout;
|
||||||
|
filter: any;
|
||||||
|
func: Function;
|
||||||
|
|
||||||
|
constructor(filter: any, func: Function) {
|
||||||
|
this.consuming = true;
|
||||||
|
this.filter = filter;
|
||||||
|
this.func = func;
|
||||||
|
this.interval = setInterval(this.consume.bind(this), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
async consume() {
|
||||||
|
if (this.running || !this.consuming) return;
|
||||||
|
const res = await TaskModel.getFirst(this.filter);
|
||||||
|
if (res) {
|
||||||
|
this.running = this.func(res);
|
||||||
|
if (this.running instanceof Promise) await this.running;
|
||||||
|
this.running = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isRunning = false;
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Consumer {
|
async destory() {
|
||||||
consuming: boolean;
|
this.consuming = false;
|
||||||
|
clearInterval(this.interval);
|
||||||
running?: Promise<any>;
|
if (this.running) await this.running;
|
||||||
|
|
||||||
interval: NodeJS.Timeout;
|
|
||||||
|
|
||||||
filter: any;
|
|
||||||
|
|
||||||
func: Function;
|
|
||||||
|
|
||||||
constructor(filter: any, func: Function) {
|
|
||||||
this.consuming = true;
|
|
||||||
this.filter = filter;
|
|
||||||
this.func = func;
|
|
||||||
this.interval = setInterval(this.consume.bind(this), 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
async consume() {
|
|
||||||
if (this.running || !this.consuming) return;
|
|
||||||
const res = await getFirst(this.filter);
|
|
||||||
if (res) {
|
|
||||||
this.running = this.func(res);
|
|
||||||
if (this.running instanceof Promise) await this.running;
|
|
||||||
this.running = null;
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
async destory() {
|
|
||||||
this.consuming = false;
|
|
||||||
clearInterval(this.interval);
|
|
||||||
if (this.running) await this.running;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
global.Hydro.model.task = {
|
export = TaskModel;
|
||||||
Consumer, add, get, del, count, getFirst, consume,
|
global.Hydro.model.task = TaskModel;
|
||||||
};
|
|
||||||
@@ -2,7 +2,7 @@ import { Collection } from 'mongodb';
|
|||||||
import * as system from './system';
|
import * as system from './system';
|
||||||
import token from './token';
|
import token from './token';
|
||||||
import * as setting from './setting';
|
import * as setting from './setting';
|
||||||
import * as domain from './domain';
|
import domain from './domain';
|
||||||
import { BUILTIN_USERS, PERM, PRIV } from './builtin';
|
import { BUILTIN_USERS, PERM, PRIV } from './builtin';
|
||||||
import { ArgMethod } from '../utils';
|
import { ArgMethod } from '../utils';
|
||||||
import { UserNotFoundError, UserAlreadyExistError, LoginError } from '../error';
|
import { UserNotFoundError, UserAlreadyExistError, LoginError } from '../error';
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
import { NumericDictionary } from 'lodash';
|
import { NumericDictionary } from 'lodash';
|
||||||
import { ObjectID, FilterQuery } from 'mongodb';
|
import { ObjectID, FilterQuery } from 'mongodb';
|
||||||
import { Tdoc, Pdoc, Udoc } from '../interface';
|
import { Tdoc, Pdoc, Udoc } from '../interface';
|
||||||
import * as domain from '../model/domain';
|
import domain from '../model/domain';
|
||||||
import * as contest from '../model/contest';
|
import * as contest from '../model/contest';
|
||||||
import * as problem from '../model/problem';
|
import * as problem from '../model/problem';
|
||||||
import * as record from '../model/record';
|
import record from '../model/record';
|
||||||
import { STATUS } from '../model/builtin';
|
import { STATUS } from '../model/builtin';
|
||||||
import rating from '../lib/rating';
|
import rating from '../lib/rating';
|
||||||
import paginate from '../lib/paginate';
|
import paginate from '../lib/paginate';
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import {
|
|||||||
import hash from '../lib/hash.hydro';
|
import hash from '../lib/hash.hydro';
|
||||||
import * as misc from '../lib/misc';
|
import * as misc from '../lib/misc';
|
||||||
import user from '../model/user';
|
import user from '../model/user';
|
||||||
import * as domain from '../model/domain';
|
import domain from '../model/domain';
|
||||||
import * as system from '../model/system';
|
import * as system from '../model/system';
|
||||||
import blacklist from '../model/blacklist';
|
import blacklist from '../model/blacklist';
|
||||||
import token from '../model/token';
|
import token from '../model/token';
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import gridfs from './service/gridfs';
|
|||||||
import storage from './service/storage';
|
import storage from './service/storage';
|
||||||
import db from './service/db';
|
import db from './service/db';
|
||||||
import * as problem from './model/problem';
|
import * as problem from './model/problem';
|
||||||
import * as domain from './model/domain';
|
import domain from './model/domain';
|
||||||
import * as document from './model/document';
|
import * as document from './model/document';
|
||||||
import * as system from './model/system';
|
import * as system from './model/system';
|
||||||
import difficultyAlgorithm from './lib/difficulty';
|
import difficultyAlgorithm from './lib/difficulty';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { FilterQuery } from 'mongodb';
|
import { FilterQuery } from 'mongodb';
|
||||||
import { Pdoc } from 'hydrooj/dist/interface';
|
import { Pdoc } from 'hydrooj/dist/interface';
|
||||||
import * as problem from 'hydrooj/dist/model/problem';
|
import * as problem from 'hydrooj/dist/model/problem';
|
||||||
import * as record from 'hydrooj/dist/model/record';
|
import record from 'hydrooj/dist/model/record';
|
||||||
import user from 'hydrooj/dist/model/user';
|
import user from 'hydrooj/dist/model/user';
|
||||||
import { PERM, PRIV } from 'hydrooj/dist/model/builtin';
|
import { PERM, PRIV } from 'hydrooj/dist/model/builtin';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/syzoj-ng-api",
|
"name": "@hydrooj/syzoj-ng-api",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"description": "A syzoj-ng API interface",
|
"description": "A syzoj-ng API interface",
|
||||||
"main": "package.json",
|
"main": "package.json",
|
||||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
|
|||||||
Reference in new issue
Block a user