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
@@ -13,10 +13,10 @@ import * as contest from '../model/contest';
|
||||
import * as system from '../model/system';
|
||||
import * as document from '../model/document';
|
||||
import * as problem from '../model/problem';
|
||||
import * as domain from '../model/domain';
|
||||
import * as record from '../model/record';
|
||||
import domain from '../model/domain';
|
||||
import record from '../model/record';
|
||||
import user from '../model/user';
|
||||
import * as message from '../model/message';
|
||||
import message from '../model/message';
|
||||
import {
|
||||
Route, Handler, Types, param,
|
||||
} from '../service/server';
|
||||
|
||||
@@ -8,7 +8,7 @@ import paginate from '../lib/paginate';
|
||||
import * as system from '../model/system';
|
||||
import user from '../model/user';
|
||||
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 document from '../model/document';
|
||||
import { PERM, PRIV } from '../model/builtin';
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import { log2 } from '../utils';
|
||||
import type { DomainDoc } from '../interface';
|
||||
import user from '../model/user';
|
||||
import * as domain from '../model/domain';
|
||||
import domain from '../model/domain';
|
||||
import * as discussion from '../model/discussion';
|
||||
import * as system from '../model/system';
|
||||
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 * as mail from '../lib/mail';
|
||||
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 system from '../model/system';
|
||||
import user from '../model/user';
|
||||
import * as setting from '../model/setting';
|
||||
import * as domain from '../model/domain';
|
||||
import domain from '../model/domain';
|
||||
import * as discussion from '../model/discussion';
|
||||
import token from '../model/token';
|
||||
import * as training from '../model/training';
|
||||
|
||||
@@ -12,14 +12,14 @@ import {
|
||||
Route, Handler, Types, param,
|
||||
} from '../service/server';
|
||||
import * as bus from '../service/bus';
|
||||
import * as domain from '../model/domain';
|
||||
import domain from '../model/domain';
|
||||
import { PERM } from '../model/builtin';
|
||||
import user from '../model/user';
|
||||
import * as system from '../model/system';
|
||||
import * as contest from '../model/contest';
|
||||
import * as discussion from '../model/discussion';
|
||||
import * as problem from '../model/problem';
|
||||
import * as record from '../model/record';
|
||||
import record from '../model/record';
|
||||
import * as document from '../model/document';
|
||||
import paginate from '../lib/paginate';
|
||||
import { isTitle, isContent } from '../lib/validator';
|
||||
|
||||
@@ -3,12 +3,12 @@ import { JudgeResultBody, Rdoc, TestCase } from '../interface';
|
||||
import { sleep } from '../utils';
|
||||
import { Logger } from '../logger';
|
||||
import difficultyAlgorithm from '../lib/difficulty';
|
||||
import * as record from '../model/record';
|
||||
import record from '../model/record';
|
||||
import * as problem from '../model/problem';
|
||||
import * as builtin from '../model/builtin';
|
||||
import * as contest from '../model/contest';
|
||||
import * as domain from '../model/domain';
|
||||
import * as task from '../model/task';
|
||||
import domain from '../model/domain';
|
||||
import task from '../model/task';
|
||||
import * as bus from '../service/bus';
|
||||
import {
|
||||
Route, Handler, Connection, ConnectionHandler, post, Types,
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as setting from '../model/setting';
|
||||
import * as system from '../model/system';
|
||||
import user from '../model/user';
|
||||
import { STATUS, PRIV } from '../model/builtin';
|
||||
import * as record from '../model/record';
|
||||
import record from '../model/record';
|
||||
import {
|
||||
Route, Connection, Handler, ConnectionHandler, param, Types,
|
||||
} from '../service/server';
|
||||
|
||||
@@ -13,10 +13,10 @@ import { isTitle, isContent, isPid } from '../lib/validator';
|
||||
import difficultyAlgorithm from '../lib/difficulty';
|
||||
import * as system from '../model/system';
|
||||
import * as problem from '../model/problem';
|
||||
import * as record from '../model/record';
|
||||
import * as domain from '../model/domain';
|
||||
import record from '../model/record';
|
||||
import domain from '../model/domain';
|
||||
import user from '../model/user';
|
||||
import * as solution from '../model/solution';
|
||||
import solution from '../model/solution';
|
||||
import { PERM, PRIV } from '../model/builtin';
|
||||
import storage from '../service/storage';
|
||||
import * as bus from '../service/bus';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Rdoc } from '../interface';
|
||||
import { PERM, STATUS, PRIV } from '../model/builtin';
|
||||
import * as system from '../model/system';
|
||||
import * as problem from '../model/problem';
|
||||
import * as record from '../model/record';
|
||||
import record from '../model/record';
|
||||
import * as contest from '../model/contest';
|
||||
import user from '../model/user';
|
||||
import paginate from '../lib/paginate';
|
||||
|
||||
@@ -8,11 +8,11 @@ import {
|
||||
Route, Handler, Types, param, post,
|
||||
} from '../service/server';
|
||||
import user from '../model/user';
|
||||
import * as oauth from '../model/oauth';
|
||||
import oauth from '../model/oauth';
|
||||
import token from '../model/token';
|
||||
import * as record from '../model/record';
|
||||
import record from '../model/record';
|
||||
import * as problem from '../model/problem';
|
||||
import * as task from '../model/task';
|
||||
import task from '../model/task';
|
||||
import * as system from '../model/system';
|
||||
import { PERM, PRIV } from '../model/builtin';
|
||||
import { isEmail, isPassword, isUname } from '../lib/validator';
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Dictionary } from 'lodash';
|
||||
import { FilterQuery } from 'mongodb';
|
||||
import { BUILTIN_ROLES, PRIV } from './builtin';
|
||||
import { DomainDoc } from '../interface';
|
||||
import { ArgMethod } from '../utils';
|
||||
import { NumberKeys } from '../typeutils';
|
||||
import * as bus from '../service/bus';
|
||||
import db from '../service/db';
|
||||
@@ -9,232 +10,218 @@ import db from '../service/db';
|
||||
const coll = db.collection('domain');
|
||||
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 {
|
||||
_id: 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) {
|
||||
return collUser.updateMany({ domainId, ...query }, { $set: params });
|
||||
}
|
||||
class DomainModel {
|
||||
static JOIN_METHOD_NONE = 0;
|
||||
static JOIN_METHOD_ALL = 1;
|
||||
static JOIN_METHOD_CODE = 2;
|
||||
|
||||
export function getMultiUserInDomain(domainId: string, query: any = {}) {
|
||||
return collUser.find({ domainId, ...query });
|
||||
}
|
||||
static JOIN_METHOD_RANGE = {
|
||||
[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) {
|
||||
return collUser.updateOne({ domainId, uid }, { $set: params });
|
||||
}
|
||||
static JOIN_EXPIRATION_KEEP_CURRENT = 0;
|
||||
static JOIN_EXPIRATION_UNLIMITED = -1;
|
||||
|
||||
export async function incUserInDomain(domainId: string, uid: number, field: string, n = 1) {
|
||||
// @ts-ignore
|
||||
const dudoc = await getDomainUser(domainId, { _id: uid });
|
||||
dudoc[field] = dudoc[field] + n || n;
|
||||
await setUserInDomain(domainId, uid, { [field]: dudoc[field] });
|
||||
return dudoc;
|
||||
}
|
||||
static JOIN_EXPIRATION_RANGE = {
|
||||
[DomainModel.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',
|
||||
[DomainModel.JOIN_EXPIRATION_UNLIMITED]: 'Never expire',
|
||||
};
|
||||
|
||||
export async function 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 get(dudoc.domainId);
|
||||
dudict[dudoc.domainId].role = dudoc.role;
|
||||
@ArgMethod
|
||||
static async 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;
|
||||
}
|
||||
|
||||
@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[]) {
|
||||
if (!ddoc.join) return null;
|
||||
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,
|
||||
};
|
||||
export = DomainModel;
|
||||
global.Hydro.model.domain = DomainModel;
|
||||
@@ -1,65 +1,71 @@
|
||||
import { FilterQuery, ObjectID } from 'mongodb';
|
||||
import user from './user';
|
||||
import { Mdoc } from '../interface';
|
||||
import { ArgMethod } from '../utils';
|
||||
import db from '../service/db';
|
||||
import * as bus from '../service/bus';
|
||||
|
||||
const coll = db.collection('message');
|
||||
|
||||
export const FLAG_UNREAD = 1;
|
||||
export const FLAG_ALERT = 2;
|
||||
class MessageModel {
|
||||
static FLAG_UNREAD = 1;
|
||||
static FLAG_ALERT = 2;
|
||||
|
||||
export async function send(
|
||||
from: number, to: number,
|
||||
content: string, flag: number = FLAG_UNREAD,
|
||||
): Promise<Mdoc> {
|
||||
const res = await coll.insertOne({
|
||||
from, to, content, flag,
|
||||
});
|
||||
const mdoc = {
|
||||
from, to, content, _id: res.insertedId, flag,
|
||||
};
|
||||
if (from !== to) {
|
||||
// ENHANCE domainId?
|
||||
const udoc = await user.getById('system', to);
|
||||
bus.boardcast('user/message', to, mdoc, udoc);
|
||||
@ArgMethod
|
||||
static async send(
|
||||
from: number, to: number,
|
||||
content: string, flag: number = MessageModel.FLAG_UNREAD,
|
||||
): Promise<Mdoc> {
|
||||
const res = await coll.insertOne({
|
||||
from, to, content, flag,
|
||||
});
|
||||
const mdoc = {
|
||||
from, to, content, _id: res.insertedId, flag,
|
||||
};
|
||||
if (from !== to) {
|
||||
// ENHANCE domainId?
|
||||
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> {
|
||||
return await coll.findOne({ _id });
|
||||
}
|
||||
static async get(_id: ObjectID): Promise<Mdoc | null> {
|
||||
return await coll.findOne({ _id });
|
||||
}
|
||||
|
||||
export async function getByUser(uid: number): Promise<Mdoc[]> {
|
||||
return await coll.find({ $or: [{ from: uid }, { to: uid }] }).sort('_id', 1).toArray();
|
||||
}
|
||||
@ArgMethod
|
||||
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[]> {
|
||||
return await coll.find(query).sort(sort)
|
||||
.skip((page - 1) * limit).limit(limit)
|
||||
.toArray();
|
||||
}
|
||||
static async getMany(query: FilterQuery<Mdoc>, sort: any, page: number, limit: number): Promise<Mdoc[]> {
|
||||
return await coll.find(query).sort(sort)
|
||||
.skip((page - 1) * limit).limit(limit)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
export async function setFlag(messageId: ObjectID, flag: number): Promise<Mdoc | null> {
|
||||
const result = await coll.findOneAndUpdate(
|
||||
{ _id: messageId },
|
||||
{ $bit: { flag: { xor: flag } } },
|
||||
{ returnOriginal: false },
|
||||
);
|
||||
return result.value;
|
||||
}
|
||||
static async setFlag(messageId: ObjectID, flag: number): Promise<Mdoc | null> {
|
||||
const result = await coll.findOneAndUpdate(
|
||||
{ _id: messageId },
|
||||
{ $bit: { flag: { xor: flag } } },
|
||||
{ returnOriginal: false },
|
||||
);
|
||||
return result.value;
|
||||
}
|
||||
|
||||
export async function del(_id: ObjectID) {
|
||||
return await coll.deleteOne({ _id });
|
||||
}
|
||||
static async del(_id: ObjectID) {
|
||||
return await coll.deleteOne({ _id });
|
||||
}
|
||||
|
||||
export function count(query: FilterQuery<Mdoc> = {}) {
|
||||
return coll.find(query).count();
|
||||
}
|
||||
@ArgMethod
|
||||
static count(query: FilterQuery<Mdoc> = {}) {
|
||||
return coll.find(query).count();
|
||||
}
|
||||
|
||||
export function getMulti(uid: number) {
|
||||
return coll.find({ $or: [{ from: uid }, { to: uid }] });
|
||||
static getMulti(uid: number) {
|
||||
return coll.find({ $or: [{ from: uid }, { to: uid }] });
|
||||
}
|
||||
}
|
||||
|
||||
function ensureIndexes() {
|
||||
@@ -70,16 +76,5 @@ function ensureIndexes() {
|
||||
}
|
||||
|
||||
bus.once('app/started', ensureIndexes);
|
||||
global.Hydro.model.message = {
|
||||
FLAG_UNREAD,
|
||||
FLAG_ALERT,
|
||||
|
||||
count,
|
||||
get,
|
||||
getByUser,
|
||||
del,
|
||||
setFlag,
|
||||
getMany,
|
||||
getMulti,
|
||||
send,
|
||||
};
|
||||
export = MessageModel;
|
||||
global.Hydro.model.message = MessageModel;
|
||||
@@ -12,25 +12,25 @@ const cache = new Lru({
|
||||
maxAge: 5000,
|
||||
});
|
||||
|
||||
export async function get(_id: string) {
|
||||
const res = cache.get(_id);
|
||||
if (res !== undefined) return res;
|
||||
const doc = await coll.findOne({ _id });
|
||||
if (doc) return doc.uid;
|
||||
return null;
|
||||
class OauthModel {
|
||||
static async get(_id: string) {
|
||||
const res = cache.get(_id);
|
||||
if (res !== undefined) return res;
|
||||
const doc = await coll.findOne({ _id });
|
||||
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) {
|
||||
cache.set(_id, value);
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ _id },
|
||||
{ $set: { value } },
|
||||
{ upsert: true, returnOriginal: false },
|
||||
);
|
||||
return res.value.uid;
|
||||
}
|
||||
|
||||
global.Hydro.model.oauth = {
|
||||
get,
|
||||
set,
|
||||
};
|
||||
export = OauthModel;
|
||||
global.Hydro.model.oauth = OauthModel;
|
||||
@@ -3,7 +3,7 @@ import { ObjectID, FilterQuery } from 'mongodb';
|
||||
import { Dictionary, pick } from 'lodash';
|
||||
import { STATUS } from './builtin';
|
||||
import * as document from './document';
|
||||
import * as domain from './domain';
|
||||
import domain from './domain';
|
||||
import { buildProjection } from '../utils';
|
||||
import type { ProblemStatusDoc, Pdict, Document } from '../interface';
|
||||
import { Content } from '../loader';
|
||||
|
||||
@@ -4,213 +4,167 @@ import {
|
||||
import { Dictionary } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { STATUS } from './builtin';
|
||||
import * as task from './task';
|
||||
import task from './task';
|
||||
import * as problem from './problem';
|
||||
import {
|
||||
Rdoc, TestCase, ContestInfo, ProblemConfig,
|
||||
} from '../interface';
|
||||
import { Time } from '../utils';
|
||||
import { Rdoc, ContestInfo, ProblemConfig } from '../interface';
|
||||
import { ArgMethod, Time } from '../utils';
|
||||
import * as bus from '../service/bus';
|
||||
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 {
|
||||
_id?: ObjectID,
|
||||
domainId?: string,
|
||||
pid: number
|
||||
uid: number,
|
||||
lang: string,
|
||||
code: string,
|
||||
score?: number,
|
||||
memory?: number,
|
||||
time?: number,
|
||||
judgeTexts?: string[],
|
||||
compilerTexts?: string[],
|
||||
testCases?: TestCase[],
|
||||
rejudged?: boolean,
|
||||
judger?: string,
|
||||
judgeAt?: Date,
|
||||
status?: number,
|
||||
type?: string,
|
||||
hidden?: boolean,
|
||||
input?: string,
|
||||
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;
|
||||
static async get(domainId: string, _id: ObjectID): Promise<Rdoc | null> {
|
||||
const res = await RecordModel.coll.findOne({ _id });
|
||||
if (res && res.domainId === domainId) return res;
|
||||
return null;
|
||||
}
|
||||
delete rdoc._id;
|
||||
await task.add({
|
||||
...rdoc,
|
||||
priority,
|
||||
type: 'judge',
|
||||
rid,
|
||||
domainId,
|
||||
config,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export async function 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 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;
|
||||
@ArgMethod
|
||||
static async stat(domainId?: 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(),
|
||||
RecordModel.coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'hour')) }, ...domainId ? { domainId } : {} }).count(),
|
||||
RecordModel.coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'day')) }, ...domainId ? { domainId } : {} }).count(),
|
||||
RecordModel.coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'week')) }, ...domainId ? { domainId } : {} }).count(),
|
||||
RecordModel.coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'month')) }, ...domainId ? { domainId } : {} }).count(),
|
||||
RecordModel.coll.find({ _id: { $gte: Time.getObjectID(moment().add(-1, 'year')) }, ...domainId ? { domainId } : {} }).count(),
|
||||
RecordModel.coll.find(domainId ? { domainId } : {}).count(),
|
||||
]);
|
||||
return {
|
||||
d5min, d1h, day, week, month, year, total,
|
||||
};
|
||||
}
|
||||
return await get(domainId, _id);
|
||||
}
|
||||
|
||||
export function 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 update(domainId, rid, upd);
|
||||
}
|
||||
|
||||
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,
|
||||
static async judge(domainId: string, rid: ObjectID, priority = 1, config: ProblemConfig = {}) {
|
||||
const rdoc = await RecordModel.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,
|
||||
});
|
||||
}
|
||||
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[]> {
|
||||
return coll.find({ domainId, uid }).limit(limit).toArray();
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
bus.on('problem/delete', (domainId, docId) => RecordModel.coll.deleteMany({ domainId, pid: docId }));
|
||||
export = RecordModel;
|
||||
global.Hydro.model.record = RecordModel;
|
||||
@@ -3,80 +3,82 @@ import * as document from './document';
|
||||
import { SolutionNotFoundError } from '../error';
|
||||
import * as bus from '../service/bus';
|
||||
|
||||
export function add(domainId: string, pid: number, owner: number, content: string) {
|
||||
return document.add(
|
||||
domainId, content, owner, document.TYPE_PROBLEM_SOLUTION,
|
||||
null, document.TYPE_PROBLEM, pid, { reply: [], vote: 0 },
|
||||
);
|
||||
}
|
||||
class SolutionModel {
|
||||
static add(domainId: string, pid: number, owner: number, content: string) {
|
||||
return document.add(
|
||||
domainId, content, owner, document.TYPE_PROBLEM_SOLUTION,
|
||||
null, document.TYPE_PROBLEM, pid, { reply: [], vote: 0 },
|
||||
);
|
||||
}
|
||||
|
||||
export async function get(domainId: string, psid: ObjectID) {
|
||||
const psdoc = await document.get(domainId, document.TYPE_PROBLEM_SOLUTION, psid);
|
||||
if (!psdoc) throw new SolutionNotFoundError();
|
||||
return psdoc;
|
||||
}
|
||||
static async get(domainId: string, psid: ObjectID) {
|
||||
const psdoc = await document.get(domainId, document.TYPE_PROBLEM_SOLUTION, psid);
|
||||
if (!psdoc) throw new SolutionNotFoundError();
|
||||
return psdoc;
|
||||
}
|
||||
|
||||
export function getMany(domainId: string, query: any, sort: any, page: number, limit: number) {
|
||||
return document.getMulti(domainId, document.TYPE_PROBLEM_SOLUTION, query)
|
||||
.sort(sort)
|
||||
.skip((page - 1) * limit).limit(limit)
|
||||
.toArray();
|
||||
}
|
||||
static getMany(domainId: string, query: any, sort: any, page: number, limit: number) {
|
||||
return document.getMulti(domainId, document.TYPE_PROBLEM_SOLUTION, query)
|
||||
.sort(sort)
|
||||
.skip((page - 1) * limit).limit(limit)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
export function edit(domainId: string, psid: ObjectID, content: string) {
|
||||
return document.set(domainId, document.TYPE_PROBLEM_SOLUTION, psid, { content });
|
||||
}
|
||||
static edit(domainId: string, psid: ObjectID, content: string) {
|
||||
return document.set(domainId, document.TYPE_PROBLEM_SOLUTION, psid, { content });
|
||||
}
|
||||
|
||||
export async function del(domainId: string, psid: ObjectID) {
|
||||
return await Promise.all([
|
||||
document.deleteOne(domainId, document.TYPE_PROBLEM_SOLUTION, psid),
|
||||
document.deleteMultiStatus(domainId, document.TYPE_PROBLEM_SOLUTION, { docId: psid }),
|
||||
]);
|
||||
}
|
||||
static async del(domainId: string, psid: ObjectID) {
|
||||
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) {
|
||||
return document.count(domainId, document.TYPE_PROBLEM_SOLUTION, query);
|
||||
}
|
||||
static count(domainId: string, query: any) {
|
||||
return document.count(domainId, document.TYPE_PROBLEM_SOLUTION, query);
|
||||
}
|
||||
|
||||
export function getMulti(domainId: string, pid: number) {
|
||||
return document.getMulti(
|
||||
domainId, document.TYPE_PROBLEM_SOLUTION,
|
||||
{ parentType: document.TYPE_PROBLEM, parentId: pid },
|
||||
).sort({ vote: -1 });
|
||||
}
|
||||
static getMulti(domainId: string, pid: number) {
|
||||
return document.getMulti(
|
||||
domainId, document.TYPE_PROBLEM_SOLUTION,
|
||||
{ parentType: document.TYPE_PROBLEM, parentId: pid },
|
||||
).sort({ vote: -1 });
|
||||
}
|
||||
|
||||
export function reply(domainId: string, psid: ObjectID, owner: number, content: string) {
|
||||
return document.push(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', content, owner);
|
||||
}
|
||||
static reply(domainId: string, psid: ObjectID, owner: number, content: string) {
|
||||
return document.push(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', content, owner);
|
||||
}
|
||||
|
||||
export function getReply(domainId: string, psid: ObjectID, psrid: ObjectID) {
|
||||
return document.getSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid);
|
||||
}
|
||||
static getReply(domainId: string, psid: ObjectID, psrid: ObjectID) {
|
||||
return document.getSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid);
|
||||
}
|
||||
|
||||
export function editReply(domainId: string, psid: ObjectID, psrid: ObjectID, content: string) {
|
||||
return document.setSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid, { content });
|
||||
}
|
||||
static editReply(domainId: string, psid: ObjectID, psrid: ObjectID, content: string) {
|
||||
return document.setSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid, { content });
|
||||
}
|
||||
|
||||
export function delReply(domainId: string, psid: ObjectID, psrid: ObjectID) {
|
||||
return document.deleteSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid);
|
||||
}
|
||||
static delReply(domainId: string, psid: ObjectID, psrid: ObjectID) {
|
||||
return document.deleteSub(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'reply', psrid);
|
||||
}
|
||||
|
||||
export async function vote(domainId: string, psid: ObjectID, uid: number, value: number) {
|
||||
let pssdoc = await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid);
|
||||
await document.setStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid, { vote: value });
|
||||
if (pssdoc) value += -pssdoc.vote;
|
||||
const psdoc = await document.inc(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'vote', value);
|
||||
pssdoc = await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid);
|
||||
return [psdoc, pssdoc];
|
||||
}
|
||||
static async vote(domainId: string, psid: ObjectID, uid: number, value: number) {
|
||||
let pssdoc = await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid);
|
||||
await document.setStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid, { vote: value });
|
||||
if (pssdoc) value += -pssdoc.vote;
|
||||
const psdoc = await document.inc(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'vote', value);
|
||||
pssdoc = await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid);
|
||||
return [psdoc, pssdoc];
|
||||
}
|
||||
|
||||
export async function getListStatus(domainId: string, psids: ObjectID[], uid: number) {
|
||||
const result = {};
|
||||
const res = await document.getMultiStatus(
|
||||
domainId, document.TYPE_PROBLEM_SOLUTION, { uid, psid: { $in: psids } },
|
||||
).toArray();
|
||||
for (const i of res) result[i.psid] = i;
|
||||
return result;
|
||||
static async getListStatus(domainId: string, psids: ObjectID[], uid: number) {
|
||||
const result = {};
|
||||
const res = await document.getMultiStatus(
|
||||
domainId, document.TYPE_PROBLEM_SOLUTION, { uid, psid: { $in: psids } },
|
||||
).toArray();
|
||||
for (const i of res) result[i.psid] = i;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
bus.on('problem/delete', async (domainId, docId) => {
|
||||
@@ -90,18 +92,5 @@ bus.on('problem/delete', async (domainId, docId) => {
|
||||
]);
|
||||
});
|
||||
|
||||
global.Hydro.model.solution = {
|
||||
count,
|
||||
add,
|
||||
get,
|
||||
edit,
|
||||
del,
|
||||
getMany,
|
||||
getMulti,
|
||||
reply,
|
||||
getReply,
|
||||
editReply,
|
||||
delReply,
|
||||
vote,
|
||||
getListStatus,
|
||||
};
|
||||
export = SolutionModel;
|
||||
global.Hydro.model.solution = SolutionModel;
|
||||
@@ -7,98 +7,95 @@ import db from '../service/db';
|
||||
const logger = new Logger('model/task');
|
||||
const coll = db.collection('task');
|
||||
|
||||
export async function add(task: Partial<Task> & { type: string }) {
|
||||
const t: Task = {
|
||||
...task,
|
||||
count: task.count ?? 1,
|
||||
priority: task.priority ?? 1,
|
||||
executeAfter: task.executeAfter || new Date(),
|
||||
_id: new ObjectID(),
|
||||
};
|
||||
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;
|
||||
class TaskModel {
|
||||
static async add(task: Partial<Task> & { type: string }) {
|
||||
const t: Task = {
|
||||
...task,
|
||||
count: task.count ?? 1,
|
||||
priority: task.priority ?? 1,
|
||||
executeAfter: task.executeAfter || new Date(),
|
||||
_id: new ObjectID(),
|
||||
};
|
||||
const res = await coll.insertOne(t);
|
||||
return res.insertedId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function consume(query: any, cb: Function) {
|
||||
let isRunning = false;
|
||||
const interval = setInterval(async () => {
|
||||
if (isRunning) return;
|
||||
isRunning = true;
|
||||
const res = await getFirst(query);
|
||||
if (res) {
|
||||
try {
|
||||
await cb(res);
|
||||
} catch (e) {
|
||||
clearInterval(interval);
|
||||
static get(_id: ObjectID) {
|
||||
return coll.findOne({ _id });
|
||||
}
|
||||
|
||||
static count(query: FilterQuery<Task>) {
|
||||
return coll.find(query).count();
|
||||
}
|
||||
|
||||
static del(_id: ObjectID) {
|
||||
return coll.deleteOne({ _id });
|
||||
}
|
||||
|
||||
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 {
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
|
||||
async destory() {
|
||||
this.consuming = false;
|
||||
clearInterval(this.interval);
|
||||
if (this.running) await this.running;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
global.Hydro.model.task = {
|
||||
Consumer, add, get, del, count, getFirst, consume,
|
||||
};
|
||||
export = TaskModel;
|
||||
global.Hydro.model.task = TaskModel;
|
||||
@@ -2,7 +2,7 @@ import { Collection } from 'mongodb';
|
||||
import * as system from './system';
|
||||
import token from './token';
|
||||
import * as setting from './setting';
|
||||
import * as domain from './domain';
|
||||
import domain from './domain';
|
||||
import { BUILTIN_USERS, PERM, PRIV } from './builtin';
|
||||
import { ArgMethod } from '../utils';
|
||||
import { UserNotFoundError, UserAlreadyExistError, LoginError } from '../error';
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
import { NumericDictionary } from 'lodash';
|
||||
import { ObjectID, FilterQuery } from 'mongodb';
|
||||
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 problem from '../model/problem';
|
||||
import * as record from '../model/record';
|
||||
import record from '../model/record';
|
||||
import { STATUS } from '../model/builtin';
|
||||
import rating from '../lib/rating';
|
||||
import paginate from '../lib/paginate';
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
import hash from '../lib/hash.hydro';
|
||||
import * as misc from '../lib/misc';
|
||||
import user from '../model/user';
|
||||
import * as domain from '../model/domain';
|
||||
import domain from '../model/domain';
|
||||
import * as system from '../model/system';
|
||||
import blacklist from '../model/blacklist';
|
||||
import token from '../model/token';
|
||||
|
||||
@@ -12,7 +12,7 @@ import gridfs from './service/gridfs';
|
||||
import storage from './service/storage';
|
||||
import db from './service/db';
|
||||
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 system from './model/system';
|
||||
import difficultyAlgorithm from './lib/difficulty';
|
||||
|
||||
Reference in new issue
Block a user