mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
加域申请管理
This commit is contained in:
1 parent
16108993cf
commit
c3ff5856e4
16 files changed
+164
-32
No files matched your search
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
"lint": "eslint packages --ext ts --fix",
|
"lint": "eslint packages --ext ts --fix",
|
||||||
"pub": "node build/publish",
|
"pub": "node build/publish",
|
||||||
"jest": "node build/jest",
|
"jest": "node build/jest",
|
||||||
"start": "node_modules/.bin/hydrooj"
|
"start": "node --async-stack-traces --trace-deprecation --enable-source-maps node_modules/.bin/hydrooj"
|
||||||
},
|
},
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
|
|||||||
@@ -4,4 +4,3 @@ SETTINGS_PRIVACY.allowRegisteredUsers
|
|||||||
model.setting.ui.name
|
model.setting.ui.name
|
||||||
pdoc.secretConfig?
|
pdoc.secretConfig?
|
||||||
message.markAsRead
|
message.markAsRead
|
||||||
domain_join_application
|
|
||||||
@@ -237,6 +237,7 @@ Domain ID: 域 ID
|
|||||||
domain_dashboard: 管理域
|
domain_dashboard: 管理域
|
||||||
domain_discussion: 讨论节点
|
domain_discussion: 讨论节点
|
||||||
domain_edit: 编辑域资料
|
domain_edit: 编辑域资料
|
||||||
|
domain_join_applications: 加域申请
|
||||||
domain_join: 加入域
|
domain_join: 加入域
|
||||||
domain_main: 首页
|
domain_main: 首页
|
||||||
domain_permission: 管理权限
|
domain_permission: 管理权限
|
||||||
@@ -408,7 +409,6 @@ Lucky: 手气不错
|
|||||||
manage_dashboard: 控制面板
|
manage_dashboard: 控制面板
|
||||||
manage_join_applications: 加域申请
|
manage_join_applications: 加域申请
|
||||||
manage_module: 管理模块
|
manage_module: 管理模块
|
||||||
manage_script: 脚本管理
|
|
||||||
manage_setting: 系统设置
|
manage_setting: 系统设置
|
||||||
manage: 管理
|
manage: 管理
|
||||||
Manage: 管理
|
Manage: 管理
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.12.6",
|
"version": "2.12.7",
|
||||||
"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,11 +13,15 @@ const lockfile = path.resolve(tmpdir, 'lock.json');
|
|||||||
|
|
||||||
export async function load(call: Entry) {
|
export async function load(call: Entry) {
|
||||||
if (fs.existsSync(lockfile) && !argv.ignorelock) {
|
if (fs.existsSync(lockfile) && !argv.ignorelock) {
|
||||||
const file = require(lockfile);
|
try {
|
||||||
const plist = await pslist();
|
const file = require(lockfile);
|
||||||
if (file.pid && plist.map((i) => i.pid).includes(file.pid)) {
|
const plist = await pslist();
|
||||||
console.error(`Lockfile exists, pid=${file.pid}`);
|
if (file.pid && plist.map((i) => i.pid).includes(file.pid)) {
|
||||||
process.exit(1);
|
console.error(`Lockfile exists, pid=${file.pid}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Invalid lockfile. ignore.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const context = {
|
const context = {
|
||||||
|
|||||||
@@ -84,6 +84,9 @@ export const HomeworkNotLiveError = Err('HomeworkNotLiveError', ForbiddenError,
|
|||||||
export const HomeworkNotAttendedError = Err('HomeworkNotAttendedError', ForbiddenError, "You haven't claimed this homework yet.");
|
export const HomeworkNotAttendedError = Err('HomeworkNotAttendedError', ForbiddenError, "You haven't claimed this homework yet.");
|
||||||
export const RoleAlreadyExistError = Err('RoleAlreadyExistError', ForbiddenError, 'This role already exists.');
|
export const RoleAlreadyExistError = Err('RoleAlreadyExistError', ForbiddenError, 'This role already exists.');
|
||||||
export const CsrfTokenError = Err('CsrfTokenError', ForbiddenError, 'CsrfTokenError');
|
export const CsrfTokenError = Err('CsrfTokenError', ForbiddenError, 'CsrfTokenError');
|
||||||
|
export const DomainJoinForbiddenError = Err('DomainJoinForbiddenError', ForbiddenError, 'You are not allowed to join the domain. The link is either invalid or expired.');
|
||||||
|
export const DomainJoinAlreadyMemberError = Err('DomainJoinAlreadyMemberError', ForbiddenError, 'Failed to join the domain. You are already a member.');
|
||||||
|
export const InvalidJoinInvitationCodeError = Err('InvalidJoinInvitationCodeError', ForbiddenError, 'The invitation code you provided is invalid.');
|
||||||
|
|
||||||
export const UserNotFoundError = Err('UserNotFoundError', NotFoundError, 'User {0} not found.');
|
export const UserNotFoundError = Err('UserNotFoundError', NotFoundError, 'User {0} not found.');
|
||||||
export const NoProblemError = Err('NoProblemError', NotFoundError, 'No problem.');
|
export const NoProblemError = Err('NoProblemError', NotFoundError, 'No problem.');
|
||||||
@@ -132,6 +135,9 @@ global.Hydro.error = {
|
|||||||
ContestNotLiveError,
|
ContestNotLiveError,
|
||||||
ContestScoreboardHiddenError,
|
ContestScoreboardHiddenError,
|
||||||
ContestAlreadyAttendedError,
|
ContestAlreadyAttendedError,
|
||||||
|
DomainJoinAlreadyMemberError,
|
||||||
|
DomainJoinForbiddenError,
|
||||||
|
InvalidJoinInvitationCodeError,
|
||||||
UserFacingError,
|
UserFacingError,
|
||||||
SystemError,
|
SystemError,
|
||||||
TrainingAlreadyEnrollError,
|
TrainingAlreadyEnrollError,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const ContestHandler = contest.ContestHandlerMixin(Handler);
|
|||||||
|
|
||||||
class ContestListHandler extends ContestHandler {
|
class ContestListHandler extends ContestHandler {
|
||||||
@param('rule', Types.String, true)
|
@param('rule', Types.String, true)
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
async get(domainId: string, rule = '', page = 1) {
|
async get(domainId: string, rule = '', page = 1) {
|
||||||
this.response.template = 'contest_main.html';
|
this.response.template = 'contest_main.html';
|
||||||
let tdocs;
|
let tdocs;
|
||||||
@@ -55,7 +55,7 @@ class ContestListHandler extends ContestHandler {
|
|||||||
|
|
||||||
class ContestDetailHandler extends ContestHandler {
|
class ContestDetailHandler extends ContestHandler {
|
||||||
@param('tid', Types.ObjectID)
|
@param('tid', Types.ObjectID)
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
async get(domainId: string, tid: ObjectID, page = 1) {
|
async get(domainId: string, tid: ObjectID, page = 1) {
|
||||||
const tdoc = await contest.get(domainId, tid);
|
const tdoc = await contest.get(domainId, tid);
|
||||||
this.response.template = 'contest_detail.html';
|
this.response.template = 'contest_detail.html';
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class DiscussionHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DiscussionMainHandler extends Handler {
|
class DiscussionMainHandler extends Handler {
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
async get(domainId: string, page = 1) {
|
async get(domainId: string, page = 1) {
|
||||||
const [ddocs, dpcount] = await paginate(
|
const [ddocs, dpcount] = await paginate(
|
||||||
discussion.getMulti(domainId),
|
discussion.getMulti(domainId),
|
||||||
@@ -99,7 +99,7 @@ class DiscussionMainHandler extends Handler {
|
|||||||
class DiscussionNodeHandler extends DiscussionHandler {
|
class DiscussionNodeHandler extends DiscussionHandler {
|
||||||
@param('type', Types.String)
|
@param('type', Types.String)
|
||||||
@param('name', Types.String)
|
@param('name', Types.String)
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
async get(domainId: string, type: string, _name: string, page = 1) {
|
async get(domainId: string, type: string, _name: string, page = 1) {
|
||||||
let name: ObjectID | string | number;
|
let name: ObjectID | string | number;
|
||||||
if (ObjectID.isValid(_name)) name = new ObjectID(_name);
|
if (ObjectID.isValid(_name)) name = new ObjectID(_name);
|
||||||
@@ -177,7 +177,7 @@ class DiscussionCreateHandler extends DiscussionHandler {
|
|||||||
|
|
||||||
class DiscussionDetailHandler extends DiscussionHandler {
|
class DiscussionDetailHandler extends DiscussionHandler {
|
||||||
@param('did', Types.ObjectID)
|
@param('did', Types.ObjectID)
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
async get(domainId: string, did: ObjectID, page = 1) {
|
async get(domainId: string, did: ObjectID, page = 1) {
|
||||||
const dsdoc = this.user.hasPriv(PRIV.PRIV_USER_PROFILE)
|
const dsdoc = this.user.hasPriv(PRIV.PRIV_USER_PROFILE)
|
||||||
? await discussion.getStatus(domainId, did, this.user._id)
|
? await discussion.getStatus(domainId, did, this.user._id)
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { RoleAlreadyExistError, ValidationError } from '../error';
|
import moment from 'moment-timezone';
|
||||||
|
import {
|
||||||
|
RoleAlreadyExistError, ValidationError, DomainJoinForbiddenError,
|
||||||
|
DomainJoinAlreadyMemberError, InvalidJoinInvitationCodeError,
|
||||||
|
} from '../error';
|
||||||
import * as user from '../model/user';
|
import * as user from '../model/user';
|
||||||
import * as domain from '../model/domain';
|
import * as domain from '../model/domain';
|
||||||
import { DOMAIN_SETTINGS, DOMAIN_SETTINGS_BY_KEY } from '../model/setting';
|
import { DOMAIN_SETTINGS, DOMAIN_SETTINGS_BY_KEY } from '../model/setting';
|
||||||
@@ -10,7 +14,7 @@ import {
|
|||||||
} from '../service/server';
|
} from '../service/server';
|
||||||
|
|
||||||
class DomainRankHandler extends Handler {
|
class DomainRankHandler extends Handler {
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
async get(domainId: string, page = 1) {
|
async get(domainId: string, page = 1) {
|
||||||
const [dudocs, upcount, ucount] = await paginate(
|
const [dudocs, upcount, ucount] = await paginate(
|
||||||
domain.getMultiInDomain(domainId).sort({ rp: -1 }),
|
domain.getMultiInDomain(domainId).sort({ rp: -1 }),
|
||||||
@@ -184,6 +188,75 @@ class DomainRoleHandler extends ManageHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DomainJoinApplicationsHandler extends ManageHandler {
|
||||||
|
async get() {
|
||||||
|
const r = await domain.getRoles(this.domain);
|
||||||
|
const roles = r.map((role) => role._id).sort();
|
||||||
|
const rolesWithText = roles.map((role) => [role, role]);
|
||||||
|
const joinSettings = domain.getJoinSettings(this.domain, roles);
|
||||||
|
const expirations = { ...domain.JOIN_EXPIRATION_RANGE };
|
||||||
|
if (!joinSettings) delete expirations[domain.JOIN_EXPIRATION_KEEP_CURRENT];
|
||||||
|
this.response.template = 'domain_join_applications.html';
|
||||||
|
this.response.body = { rolesWithText, joinSettings, expirations };
|
||||||
|
}
|
||||||
|
|
||||||
|
@param('method', Types.UnsignedInt)
|
||||||
|
@param('role', Types.String, true)
|
||||||
|
@param('expire', Types.UnsignedInt, true)
|
||||||
|
@param('invitationCode', Types.String, true)
|
||||||
|
async post(domainId: string, method: number, role: string, expire: number, invitationCode = '') {
|
||||||
|
const r = await domain.getRoles(this.domain);
|
||||||
|
const roles = r.map((rl) => rl._id);
|
||||||
|
const current = domain.getJoinSettings(this.domain, roles);
|
||||||
|
if (!domain.JOIN_METHOD_RANGE[method]) throw new ValidationError('method');
|
||||||
|
let joinSettings;
|
||||||
|
if (method === domain.JOIN_METHOD_NONE) joinSettings = null;
|
||||||
|
else {
|
||||||
|
if (!roles.includes(role)) throw new ValidationError('role');
|
||||||
|
if (!domain.JOIN_EXPIRATION_RANGE[expire]) throw new ValidationError('expire');
|
||||||
|
if (!current && expire === domain.JOIN_EXPIRATION_KEEP_CURRENT) throw new ValidationError('expire');
|
||||||
|
joinSettings = { method, role };
|
||||||
|
if (method === domain.JOIN_METHOD_CODE) joinSettings.code = invitationCode;
|
||||||
|
if (expire === domain.JOIN_EXPIRATION_KEEP_CURRENT) {
|
||||||
|
joinSettings.expire = current.expire;
|
||||||
|
} else if (expire === domain.JOIN_EXPIRATION_UNLIMITED) joinSettings.expire = null;
|
||||||
|
else joinSettings.expire = moment().add(expire, 'hours').toDate();
|
||||||
|
}
|
||||||
|
await domain.edit(this.domain._id, { join: joinSettings });
|
||||||
|
this.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DomainJoinHandler extends Handler {
|
||||||
|
joinSettings: any;
|
||||||
|
|
||||||
|
async prepare() {
|
||||||
|
const r = await domain.getRoles(this.domain);
|
||||||
|
const roles = r.map((role) => role._id);
|
||||||
|
this.joinSettings = domain.getJoinSettings(this.domain, roles);
|
||||||
|
if (!this.joinSettings) throw new DomainJoinForbiddenError(this.domain._id);
|
||||||
|
if (this.user.role !== 'default') throw new DomainJoinAlreadyMemberError(this.domain._id, this.user._id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @base.require_priv(builtin.PRIV_USER_PROFILE)
|
||||||
|
@param('code', Types.String, true)
|
||||||
|
async get(domainId: string, code: string) {
|
||||||
|
this.response.template = 'domain_join.html';
|
||||||
|
this.response.body = { joinSettings: this.joinSettings, code };
|
||||||
|
}
|
||||||
|
|
||||||
|
@param('code', Types.String, true)
|
||||||
|
async post(domainId: string, code: string) {
|
||||||
|
if (this.joinSettings.method === domain.JOIN_METHOD_CODE) {
|
||||||
|
if (this.joinSettings.code !== code) {
|
||||||
|
throw new InvalidJoinInvitationCodeError(this.domain._id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await domain.setUserRole(this.domain._id, this.user._id, this.joinSettings.role);
|
||||||
|
this.response.redirect = this.url('domain_main');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class DomainSearchHandler extends Handler {
|
class DomainSearchHandler extends Handler {
|
||||||
@param('q', Types.String)
|
@param('q', Types.String)
|
||||||
async get(domainId: string, q: string) {
|
async get(domainId: string, q: string) {
|
||||||
@@ -202,6 +275,8 @@ export async function apply() {
|
|||||||
Route('domain_user', '/domain/user', DomainUserHandler);
|
Route('domain_user', '/domain/user', DomainUserHandler);
|
||||||
Route('domain_permission', '/domain/permission', DomainPermissionHandler);
|
Route('domain_permission', '/domain/permission', DomainPermissionHandler);
|
||||||
Route('domain_role', '/domain/role', DomainRoleHandler);
|
Route('domain_role', '/domain/role', DomainRoleHandler);
|
||||||
|
Route('domain_join_applications', '/domain/join_applications', DomainJoinApplicationsHandler);
|
||||||
|
Route('domain_join', '/domain/join', DomainJoinHandler, PRIV.PRIV_USER_PROFILE);
|
||||||
Route('domain_search', '/domain/search', DomainSearchHandler, PRIV.PRIV_USER_PROFILE);
|
Route('domain_search', '/domain/search', DomainSearchHandler, PRIV.PRIV_USER_PROFILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class HomeworkMainHandler extends HomeworkHandler {
|
|||||||
|
|
||||||
class HomeworkDetailHandler extends HomeworkHandler {
|
class HomeworkDetailHandler extends HomeworkHandler {
|
||||||
@param('tid', Types.ObjectID)
|
@param('tid', Types.ObjectID)
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
async get(domainId: string, tid: ObjectID, page = 1) {
|
async get(domainId: string, tid: ObjectID, page = 1) {
|
||||||
const tdoc = await contest.get(domainId, tid, document.TYPE_HOMEWORK);
|
const tdoc = await contest.get(domainId, tid, document.TYPE_HOMEWORK);
|
||||||
const [tsdoc, pdict] = await Promise.all([
|
const [tsdoc, pdict] = await Promise.all([
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class ProblemHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ProblemMainHandler extends ProblemHandler {
|
class ProblemMainHandler extends ProblemHandler {
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
@param('q', Types.String, true)
|
@param('q', Types.String, true)
|
||||||
async get(domainId: string, page = 1, q = '') {
|
async get(domainId: string, page = 1, q = '') {
|
||||||
this.response.template = 'problem_main.html';
|
this.response.template = 'problem_main.html';
|
||||||
@@ -103,7 +103,7 @@ class ProblemMainHandler extends ProblemHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ProblemCategoryHandler extends ProblemHandler {
|
class ProblemCategoryHandler extends ProblemHandler {
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
@param('category', Types.String, null, parseCategory)
|
@param('category', Types.String, null, parseCategory)
|
||||||
async get(domainId: string, page = 1, category: string[]) {
|
async get(domainId: string, page = 1, category: string[]) {
|
||||||
this.response.template = 'problem_main.html';
|
this.response.template = 'problem_main.html';
|
||||||
@@ -469,7 +469,7 @@ class ProblemDataDownloadHandler extends ProblemDetailHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ProblemSolutionHandler extends ProblemDetailHandler {
|
class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
async get(domainId: string, page = 1) {
|
async get(domainId: string, page = 1) {
|
||||||
this.response.template = 'problem_solution.html';
|
this.response.template = 'problem_solution.html';
|
||||||
this.checkPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION);
|
this.checkPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { Rdoc } from '../interface';
|
|||||||
const RecordHandler = contest.ContestHandlerMixin(Handler);
|
const RecordHandler = contest.ContestHandlerMixin(Handler);
|
||||||
|
|
||||||
class RecordListHandler extends RecordHandler {
|
class RecordListHandler extends RecordHandler {
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
@param('pid', Types.String, true)
|
@param('pid', Types.String, true)
|
||||||
@param('tid', Types.ObjectID, true)
|
@param('tid', Types.ObjectID, true)
|
||||||
@param('uidOrName', Types.String, true)
|
@param('uidOrName', Types.String, true)
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ async function _parseDagJson(domainId, dag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TrainingMainHandler extends Handler {
|
class TrainingMainHandler extends Handler {
|
||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.PositiveInt, true)
|
||||||
async get(domainId: string, page = 1) {
|
async get(domainId: string, page = 1) {
|
||||||
const [tdocs, tpcount] = await paginate(
|
const [tdocs, tpcount] = await paginate(
|
||||||
training.getMulti(domainId),
|
training.getMulti(domainId),
|
||||||
|
|||||||
@@ -106,6 +106,13 @@ async function executeCommand(input: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function reload(count = 1) {
|
||||||
|
console.log('Reloading');
|
||||||
|
await stopWorker();
|
||||||
|
console.log('Worker stopped');
|
||||||
|
await startWorker(count);
|
||||||
|
}
|
||||||
|
|
||||||
async function messageHandler(worker: cluster.Worker, msg: any) {
|
async function messageHandler(worker: cluster.Worker, msg: any) {
|
||||||
if (!msg) msg = worker;
|
if (!msg) msg = worker;
|
||||||
if (msg.event) {
|
if (msg.event) {
|
||||||
@@ -120,10 +127,7 @@ async function messageHandler(worker: cluster.Worker, msg: any) {
|
|||||||
} else if (msg.event === 'stat') {
|
} else if (msg.event === 'stat') {
|
||||||
global.Hydro.stat.reqCount += msg.count;
|
global.Hydro.stat.reqCount += msg.count;
|
||||||
} else if (msg.event === 'restart') {
|
} else if (msg.event === 'restart') {
|
||||||
console.log('Restarting');
|
await reload(msg.count);
|
||||||
await stopWorker();
|
|
||||||
console.log('Worker stopped');
|
|
||||||
await startWorker(msg.count);
|
|
||||||
} else if (msg.event === 'run') {
|
} else if (msg.event === 'run') {
|
||||||
await executeCommand(msg.command);
|
await executeCommand(msg.command);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,34 @@
|
|||||||
import { Dictionary } from 'lodash';
|
import { Dictionary } from 'lodash';
|
||||||
|
import { Collection } from 'mongodb';
|
||||||
import { BUILTIN_ROLES, PRIV } from './builtin';
|
import { BUILTIN_ROLES, PRIV } from './builtin';
|
||||||
import { DomainDoc } from '../interface';
|
import { DomainDoc } from '../interface';
|
||||||
import * as db from '../service/db';
|
import * as db from '../service/db';
|
||||||
|
|
||||||
const coll = db.collection('domain');
|
const coll: Collection<DomainDoc> = 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) {
|
export async function add(domainId: string, owner: number, name: string, bulletin: string) {
|
||||||
const ddoc: DomainDoc = {
|
const ddoc: DomainDoc = {
|
||||||
_id: domainId,
|
_id: domainId,
|
||||||
@@ -32,9 +55,11 @@ export function edit(domainId: string, $set: any) {
|
|||||||
return coll.updateOne({ _id: domainId }, { $set });
|
return coll.updateOne({ _id: domainId }, { $set });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function inc(domainId: string, field: string, n: number): Promise<number | null> {
|
export async function inc(domainId: string, field: any, n: number): Promise<number | null> {
|
||||||
const res = await coll.findOneAndUpdate(
|
const res = await coll.findOneAndUpdate(
|
||||||
{ _id: domainId },
|
{ _id: domainId },
|
||||||
|
// FIXME
|
||||||
|
// @ts-ignore
|
||||||
{ $inc: { [field]: n } },
|
{ $inc: { [field]: n } },
|
||||||
{ returnOriginal: false },
|
{ returnOriginal: false },
|
||||||
);
|
);
|
||||||
@@ -52,6 +77,8 @@ export function setUserRole(domainId: string, uid: number, role: string) {
|
|||||||
return collUser.updateOne({ uid, domainId }, { role }, { upsert: true });
|
return collUser.updateOne({ uid, domainId }, { 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) {
|
export async function getRoles(arg: string | DomainDoc) {
|
||||||
let ddoc: DomainDoc;
|
let ddoc: DomainDoc;
|
||||||
if (typeof arg === 'string') ddoc = await get(arg);
|
if (typeof arg === 'string') ddoc = await get(arg);
|
||||||
@@ -144,6 +171,15 @@ export async function getDictUserByDomainId(uid: number) {
|
|||||||
return dudict;
|
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) {
|
export async function getPrefixSearch(prefix: string, limit = 50) {
|
||||||
const $regex = new RegExp(prefix, 'mi');
|
const $regex = new RegExp(prefix, 'mi');
|
||||||
const ddocs = await coll.find({
|
const ddocs = await coll.find({
|
||||||
@@ -153,6 +189,14 @@ export async function getPrefixSearch(prefix: string, limit = 50) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
global.Hydro.model.domain = {
|
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,
|
getRoles,
|
||||||
add,
|
add,
|
||||||
inc,
|
inc,
|
||||||
@@ -170,5 +214,6 @@ global.Hydro.model.domain = {
|
|||||||
incUserInDomain,
|
incUserInDomain,
|
||||||
getMultiInDomain,
|
getMultiInDomain,
|
||||||
getDictUserByDomainId,
|
getDictUserByDomainId,
|
||||||
|
getJoinSettings,
|
||||||
getPrefixSearch,
|
getPrefixSearch,
|
||||||
};
|
};
|
||||||
@@ -47,15 +47,15 @@ interface ParamOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
export enum Types { String, Int, UnsignedInt, Float, ObjectID, Boolean, Date, Time }
|
export enum Types { String, Int, UnsignedInt, PositiveInt, Float, ObjectID, Boolean, Date, Time }
|
||||||
|
|
||||||
const Tools: Array<[Converter, Validator, boolean?]> = [
|
const Tools: Array<[Converter, Validator, boolean?]> = [
|
||||||
[(v) => v.toString(), null],
|
[(v) => v.toString(), null],
|
||||||
[(v) => parseInt(v, 10), (v) => isSafeInteger(parseInt(v, 10))],
|
[(v) => parseInt(v, 10), (v) => isSafeInteger(parseInt(v, 10))],
|
||||||
|
[(v) => parseInt(v, 10), (v) => parseInt(v, 10) >= 0],
|
||||||
[(v) => parseInt(v, 10), (v) => parseInt(v, 10) > 0],
|
[(v) => parseInt(v, 10), (v) => parseInt(v, 10) > 0],
|
||||||
[(v) => parseFloat(v), (v) => {
|
[(v) => parseFloat(v), (v) => {
|
||||||
const t = parseFloat(v);
|
const t = parseFloat(v);
|
||||||
console.log(t);
|
|
||||||
return t && !Number.isNaN(t) && Number.isFinite(t);
|
return t && !Number.isNaN(t) && Number.isFinite(t);
|
||||||
}],
|
}],
|
||||||
[(v) => new ObjectID(v), ObjectID.isValid],
|
[(v) => new ObjectID(v), ObjectID.isValid],
|
||||||
@@ -117,8 +117,7 @@ export function param(name: string, ...args: any): MethodDecorator {
|
|||||||
if (args[cursor] !== null) v.validate = args[cursor];
|
if (args[cursor] !== null) v.validate = args[cursor];
|
||||||
isValidate = false;
|
isValidate = false;
|
||||||
} else {
|
} else {
|
||||||
const I = args[cursor];
|
v.convert = args[cursor];
|
||||||
v.convert = I;
|
|
||||||
}
|
}
|
||||||
cursor++;
|
cursor++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user