mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 17:38:19 +08:00
优化domain.user存储结构
This commit is contained in:
1 parent
3eb593d134
commit
a93da2badb
17 files changed
+220
-239
No files matched your search
@@ -85,7 +85,7 @@ export const PERM = {
|
||||
PERM_ADMIN: '',
|
||||
};
|
||||
|
||||
export const Permission = (family, key, desc) => ({ family, key, desc });
|
||||
export const Permission = (family: string, key: string, desc: string) => ({ family, key, desc });
|
||||
|
||||
export const PERMS = [
|
||||
Permission('perm_general', PERM.PERM_VIEW, 'View this domain'),
|
||||
@@ -298,9 +298,9 @@ export const BUILTIN_USERS = [
|
||||
];
|
||||
|
||||
export const BUILTIN_ROLES = {
|
||||
guest: { perm: PERM.PERM_BASIC },
|
||||
default: { perm: PERM.PERM_DEFAULT },
|
||||
admin: { perm: PERM.PERM_ADMIN },
|
||||
guest: PERM.PERM_BASIC,
|
||||
default: PERM.PERM_DEFAULT,
|
||||
admin: PERM.PERM_ADMIN,
|
||||
};
|
||||
|
||||
export const DEFAULT_NODES = {
|
||||
|
||||
@@ -7,7 +7,6 @@ type DocID = ObjectID | string | number;
|
||||
const coll = db.collection('document');
|
||||
const collStatus = db.collection('document.status');
|
||||
|
||||
export const TYPE_DOMAIN_USER = 0;
|
||||
export const TYPE_PROBLEM = 10;
|
||||
export const TYPE_PROBLEM_SOLUTION = 11;
|
||||
export const TYPE_PROBLEM_LIST = 12;
|
||||
@@ -52,14 +51,14 @@ export async function set(domainId: string, docType: number, docId: DocID, args:
|
||||
const res = await coll.findOneAndUpdate(
|
||||
{ domainId, docType, docId },
|
||||
{ $set: args },
|
||||
{ returnOriginal: false },
|
||||
{ returnOriginal: false, upsert: true },
|
||||
);
|
||||
return res.value;
|
||||
}
|
||||
|
||||
export function deleteOne(domainId: string, docType: number, docId: DocID) {
|
||||
return Promise.all([
|
||||
coll.deleteMany({ domainId, docType, docId }),
|
||||
collStatus.deleteMany({ domainId, docType, docId }),
|
||||
coll.deleteOne({ domainId, docType, docId }),
|
||||
]);
|
||||
}
|
||||
@@ -207,6 +206,10 @@ export function getMultiStatus(domainId: string, docType: number, args: any) {
|
||||
return collStatus.find({ ...args, docType, domainId });
|
||||
}
|
||||
|
||||
export function getMultiStatusWithoutDomain(docType: number, args: any) {
|
||||
return collStatus.find({ ...args, docType });
|
||||
}
|
||||
|
||||
export async function setStatus(
|
||||
domainId: string, docType: number, docId: DocID, uid: number, args: any,
|
||||
) {
|
||||
@@ -388,6 +391,7 @@ global.Hydro.model.document = {
|
||||
get,
|
||||
getMulti,
|
||||
getMultiStatus,
|
||||
getMultiStatusWithoutDomain,
|
||||
getStatus,
|
||||
getSub,
|
||||
inc,
|
||||
@@ -404,7 +408,6 @@ global.Hydro.model.document = {
|
||||
setMultiStatus,
|
||||
setSub,
|
||||
|
||||
TYPE_DOMAIN_USER,
|
||||
TYPE_CONTEST,
|
||||
TYPE_DISCUSSION,
|
||||
TYPE_DISCUSSION_NODE,
|
||||
|
||||
+110
-32
@@ -1,39 +1,18 @@
|
||||
import * as builtin from './builtin';
|
||||
import * as document from './document';
|
||||
import { BUILTIN_ROLES, PRIV } from './builtin';
|
||||
import { Udoc } from '../interface';
|
||||
import * as db from '../service/db';
|
||||
import * as validator from '../lib/validator';
|
||||
|
||||
const coll = db.collection('domain');
|
||||
const collUser = db.collection('domain.user');
|
||||
|
||||
export function add(domainId: string, owner: number, name: string, isEnsure = false) {
|
||||
const tasks = [];
|
||||
if (isEnsure) {
|
||||
tasks.push(
|
||||
coll.updateOne(
|
||||
{ _id: domainId },
|
||||
{ $set: { owner }, $setOnInsert: { name, bulletin: '' } },
|
||||
{ upsert: true },
|
||||
),
|
||||
);
|
||||
} else {
|
||||
tasks.push(
|
||||
coll.insertOne({
|
||||
_id: domainId, owner, name, bulletin: '',
|
||||
}),
|
||||
);
|
||||
}
|
||||
for (const id in builtin.BUILTIN_ROLES) {
|
||||
tasks.push(
|
||||
document.add(
|
||||
domainId, builtin.BUILTIN_ROLES[id].perm, owner,
|
||||
document.TYPE_DOMAIN_USER, id,
|
||||
),
|
||||
);
|
||||
}
|
||||
return Promise.all(tasks);
|
||||
export async function add(domainId: string, owner: number, name: string, bulletin: string) {
|
||||
await coll.insertOne({
|
||||
_id: domainId, owner, name, bulletin, roles: BUILTIN_ROLES,
|
||||
});
|
||||
return domainId;
|
||||
}
|
||||
|
||||
export async function get(domainId: string) {
|
||||
export function get(domainId: string) {
|
||||
return coll.findOne({ _id: domainId });
|
||||
}
|
||||
|
||||
@@ -47,8 +26,6 @@ export function getMulti(query: any = {}) {
|
||||
}
|
||||
|
||||
export function edit(domainId: string, $set: any) {
|
||||
if ($set.title) validator.checkTitle($set.title);
|
||||
if ($set.content) validator.checkContent($set.content);
|
||||
return coll.updateOne({ _id: domainId }, { $set });
|
||||
}
|
||||
|
||||
@@ -68,7 +45,98 @@ export async function getList(domainIds: string[]) {
|
||||
return r;
|
||||
}
|
||||
|
||||
export function setUserRole(domainId: string, uid: number, role: string) {
|
||||
return collUser.updateOne({ uid, domainId }, { role }, { upsert: true });
|
||||
}
|
||||
|
||||
export async function getRoles(arg: string | any) {
|
||||
let ddoc;
|
||||
if (typeof arg === 'string') ddoc = get(arg);
|
||||
else ddoc = arg;
|
||||
const roles = [];
|
||||
const r = [];
|
||||
for (const role in ddoc.roles) {
|
||||
roles.push({ _id: role, perm: 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: any) {
|
||||
const current = await get(domainId);
|
||||
for (const role in roles) {
|
||||
current.roles[role] = roles[role];
|
||||
}
|
||||
return await coll.updateOne({ _id: domainId }, { $set: { roles: current } });
|
||||
}
|
||||
|
||||
export async function addRole(domainId: string, name: string, permission: string) {
|
||||
const current = await get(domainId);
|
||||
current.roles[name] = permission;
|
||||
return await coll.updateOne({ _id: domainId }, { $set: { roles: current } });
|
||||
}
|
||||
|
||||
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' } }),
|
||||
]);
|
||||
}
|
||||
|
||||
export async function getDomainUser(domainId: string, udoc: Udoc) {
|
||||
let dudoc = await collUser.findOne({ domainId, uid: udoc._id });
|
||||
dudoc = dudoc || {};
|
||||
if (udoc._id === 1) dudoc.role = 'guest';
|
||||
if (udoc.priv & PRIV.PRIV_MANAGE_ALL_DOMAIN) dudoc.role = 'admin';
|
||||
dudoc.role = dudoc.role || 'default';
|
||||
const ddoc = await get(domainId);
|
||||
dudoc.perm = 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 });
|
||||
}
|
||||
|
||||
export function getMultiInDomain(domainId: string, query: any = {}) {
|
||||
return collUser.find({ domainId, ...query });
|
||||
}
|
||||
|
||||
export function setUserInDomain(domainId: string, uid: number, params: any) {
|
||||
return collUser.updateOne({ domainId, uid }, { $set: params });
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
export async function getDictUserByDomainId(uid: number) {
|
||||
const dudocs = await collUser.find({ uid }).toArray();
|
||||
const ddocs = await 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);
|
||||
}
|
||||
for (const ddoc of ddocs) {
|
||||
dudict[ddoc._id] = ddoc;
|
||||
}
|
||||
return dudict;
|
||||
}
|
||||
|
||||
global.Hydro.model.domain = {
|
||||
getRoles,
|
||||
add,
|
||||
inc,
|
||||
get,
|
||||
@@ -76,4 +144,14 @@ global.Hydro.model.domain = {
|
||||
edit,
|
||||
getMulti,
|
||||
getList,
|
||||
setRoles,
|
||||
addRole,
|
||||
deleteRoles,
|
||||
setUserRole,
|
||||
getDomainUser,
|
||||
setMultiUserInDomain,
|
||||
setUserInDomain,
|
||||
incUserInDomain,
|
||||
getMultiInDomain,
|
||||
getDictUserByDomainId,
|
||||
};
|
||||
+23
-12
@@ -1,7 +1,9 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
import moment from 'moment-timezone';
|
||||
import * as builtin from './builtin';
|
||||
import { Setting as _Setting } from '../interface';
|
||||
import { Setting as _Setting, Dict } from '../interface';
|
||||
|
||||
type SettingDict = Dict<_Setting>;
|
||||
|
||||
const countries = moment.tz.countries();
|
||||
const tzs: Set<string> = new Set();
|
||||
@@ -10,6 +12,11 @@ for (const country of countries) {
|
||||
for (const t of tz) tzs.add(t);
|
||||
}
|
||||
const timezones = Array.from(tzs).sort().map((tz) => [tz, tz]);
|
||||
const langRange: Dict<string> = {};
|
||||
|
||||
for (const lang in global.Hydro.locales) {
|
||||
langRange[lang] = global.Hydro.locales[lang].__langname;
|
||||
}
|
||||
|
||||
export const FLAG_HIDDEN = 1;
|
||||
export const FLAG_DISABLED = 2;
|
||||
@@ -21,13 +28,13 @@ export const DOMAIN_SETTINGS: _Setting[] = [];
|
||||
export const DOMAIN_USER_SETTINGS: _Setting[] = [];
|
||||
export const SYSTEM_SETTINGS: _Setting[] = [];
|
||||
export const SETTINGS: _Setting[] = [];
|
||||
export const SETTINGS_BY_KEY = {};
|
||||
export const DOMAIN_USER_SETTINGS_BY_KEY = {};
|
||||
export const DOMAIN_SETTINGS_BY_KEY = {};
|
||||
export const SYSTEM_SETTINGS_BY_KEY = {};
|
||||
export const SETTINGS_BY_KEY: SettingDict = {};
|
||||
export const DOMAIN_USER_SETTINGS_BY_KEY: SettingDict = {};
|
||||
export const DOMAIN_SETTINGS_BY_KEY: SettingDict = {};
|
||||
export const SYSTEM_SETTINGS_BY_KEY: SettingDict = {};
|
||||
|
||||
export const Setting = (
|
||||
family: string, key: string, range: Array<[string, string]> | { [key: string]: string } = null,
|
||||
family: string, key: string, range: Array<[string, string]> | Dict<string> = null,
|
||||
value: any = null, type = 'text', name = '',
|
||||
desc = '', flag = 0,
|
||||
): _Setting => ({
|
||||
@@ -68,8 +75,7 @@ export const SystemSetting = (...settings: _Setting[]) => {
|
||||
};
|
||||
|
||||
PreferenceSetting(
|
||||
// TODO generate by global.Hydro.locales
|
||||
Setting('setting_display', 'viewLang', builtin.VIEW_LANGS.map((i) => [i.code, i.name]),
|
||||
Setting('setting_display', 'viewLang', langRange,
|
||||
'zh_CN', 'select', 'UI Language'),
|
||||
Setting('setting_display', 'timeZone', timezones as [string, string][],
|
||||
'Asia/Shanghai', 'select', 'Timezone'),
|
||||
@@ -99,10 +105,10 @@ DomainSetting(
|
||||
Setting('setting_domain', 'name', null, 'New domain', 'text', 'name'),
|
||||
Setting('setting_domain', 'gravatar', null, '', 'text', 'gravatar', 'Will be used as the domain icon.'),
|
||||
Setting('setting_domain', 'bulletin', null, '', 'markdown', 'Bulletin'),
|
||||
Setting('storage', 'nAccept', null, 0, 'number', 'nAccept', null, FLAG_HIDDEN & FLAG_DISABLED),
|
||||
Setting('storage', 'nSubmit', null, 0, 'number', 'nSubmit', null, FLAG_HIDDEN & FLAG_DISABLED),
|
||||
Setting('storage', 'nLike', null, 0, 'number', 'nLike', null, FLAG_HIDDEN & FLAG_DISABLED),
|
||||
Setting('storage', 'rating', null, 1500, 'number', 'rating', null, FLAG_HIDDEN & FLAG_DISABLED),
|
||||
Setting('storage', 'nAccept', null, 0, 'number', 'nAccept', null, FLAG_HIDDEN | FLAG_DISABLED),
|
||||
Setting('storage', 'nSubmit', null, 0, 'number', 'nSubmit', null, FLAG_HIDDEN | FLAG_DISABLED),
|
||||
Setting('storage', 'nLike', null, 0, 'number', 'nLike', null, FLAG_HIDDEN | FLAG_DISABLED),
|
||||
Setting('storage', 'rating', null, 1500, 'number', 'rating', null, FLAG_HIDDEN | FLAG_DISABLED),
|
||||
);
|
||||
|
||||
SystemSetting(
|
||||
@@ -112,6 +118,7 @@ SystemSetting(
|
||||
Setting('setting_smtp', 'smtp.port', null, 465, 'number', 'SMTP Server Port'),
|
||||
Setting('setting_smtp', 'smtp.from', null, null, 'text', 'Mail From'),
|
||||
Setting('setting_smtp', 'smtp.secure', null, false, 'boolean', 'SSL'),
|
||||
Setting('setting_db', 'db.ver', null, 1, 'number', 'Database version', null, FLAG_DISABLED | FLAG_HIDDEN),
|
||||
Setting('setting_server', 'server.worker', null, 1, 'number', 'Server Workers Number'),
|
||||
Setting('setting_server', 'server.hostname', null, null, 'text', 'Server Hostname'),
|
||||
Setting('setting_server', 'server.host', null, null, 'text', 'Server Host'),
|
||||
@@ -119,6 +126,10 @@ SystemSetting(
|
||||
Setting('setting_server', 'server.port', null, 8888, 'number', 'Server Port'),
|
||||
Setting('setting_server', 'server.xff', null, null, 'text', 'IP Header'),
|
||||
Setting('setting_server', 'server.log', null, false, 'boolean', 'Disable Access Log'),
|
||||
Setting('setting_session', 'session.keys', null, [String.random(32)], 'text', 'session.keys', null, FLAG_DISABLED | FLAG_HIDDEN),
|
||||
Setting('setting_session', 'session.secure', null, false, 'boolean', 'session.secure'),
|
||||
Setting('setting_session', 'session.saved_expire_seconds', null, 3600 * 24 * 30, 'number', 'Saved session expire seconds'),
|
||||
Setting('setting_session', 'session.unsaved_expire_seconds', null, 3600 * 3, 'number', 'Unsaved session expire seconds'),
|
||||
Setting('setting_ui', 'ui.header_logo', null, '/components/header/header-logo.png', 'text', 'Header Logo'),
|
||||
Setting('setting_ui', 'ui.header_logo_2x', null, '/components/header/header-logo@2x.png', 'text', 'Header Logo@2x'),
|
||||
Setting('setting_ui', 'ui.header_background', null, '/components/header/header-background.png', 'text', 'Header Background'),
|
||||
|
||||
+5
-91
@@ -1,8 +1,8 @@
|
||||
import * as document from './document';
|
||||
import * as system from './system';
|
||||
import * as token from './token';
|
||||
import * as setting from './setting';
|
||||
import { BUILTIN_ROLES, BUILTIN_USERS, PRIV } from './builtin';
|
||||
import * as domain from './domain';
|
||||
import { BUILTIN_USERS, PRIV } from './builtin';
|
||||
import { UserNotFoundError, UserAlreadyExistError, LoginError } from '../error';
|
||||
import pwhash from '../lib/hash.hydro';
|
||||
import * as db from '../service/db';
|
||||
@@ -100,22 +100,12 @@ export class User implements Udoc {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getInDomain(domainId: string, udoc: User) {
|
||||
let dudoc = await document.getStatus(domainId, document.TYPE_DOMAIN_USER, 0, udoc._id);
|
||||
dudoc = dudoc || {};
|
||||
if (udoc._id === 1) dudoc.role = 'guest';
|
||||
if (udoc.priv & PRIV.PRIV_MANAGE_ALL_DOMAIN) dudoc.role = 'admin';
|
||||
const p = await document.get(domainId, document.TYPE_DOMAIN_USER, dudoc.role || 'default');
|
||||
dudoc.perm = p ? p.content : BUILTIN_ROLES[dudoc.role || 'default'].perm;
|
||||
return dudoc;
|
||||
}
|
||||
|
||||
export async function getById(domainId: string, _id: number): Promise<Udoc | null> {
|
||||
const udoc = _id === 0 || _id === 1
|
||||
? BUILTIN_USERS[_id]
|
||||
: await coll.findOne({ _id });
|
||||
if (!udoc) return null;
|
||||
const dudoc = await getInDomain(domainId, udoc);
|
||||
const dudoc = await domain.getDomainUser(domainId, udoc);
|
||||
return new User(udoc, dudoc);
|
||||
}
|
||||
|
||||
@@ -140,7 +130,7 @@ export async function getByUname(
|
||||
if (ignoreMissing) return null;
|
||||
throw new UserNotFoundError(uname);
|
||||
}
|
||||
const dudoc = await getInDomain(domainId, udoc);
|
||||
const dudoc = await domain.getDomainUser(domainId, udoc);
|
||||
return new User(udoc, dudoc);
|
||||
}
|
||||
|
||||
@@ -152,7 +142,7 @@ export async function getByEmail(domainId: string, mail: string): Promise<Udoc |
|
||||
? BUILTIN_USERS[1]
|
||||
: await coll.findOne({ mailLower });
|
||||
if (!udoc) return null;
|
||||
const dudoc = await getInDomain(domainId, udoc);
|
||||
const dudoc = await domain.getDomainUser(domainId, udoc);
|
||||
return new User(udoc, dudoc);
|
||||
}
|
||||
|
||||
@@ -186,18 +176,6 @@ export async function inc(_id: number, field: string, n = 1) {
|
||||
return udoc;
|
||||
}
|
||||
|
||||
export function setInDomain(domainId: string, uid: number, params: any) {
|
||||
return document.setStatus(domainId, document.TYPE_DOMAIN_USER, 0, uid, params);
|
||||
}
|
||||
|
||||
export async function incDomain(domainId: string, uid: number, field: string, n = 1) {
|
||||
// @ts-ignore
|
||||
const dudoc = await getInDomain(domainId, { _id: uid });
|
||||
dudoc[field] = dudoc[field] + n || n;
|
||||
await setInDomain(domainId, uid, { [field]: dudoc[field] });
|
||||
return dudoc;
|
||||
}
|
||||
|
||||
export async function create({
|
||||
uid = null, mail, uname, password, regip = '127.0.0.1', priv = PRIV.PRIV_DEFAULT,
|
||||
}) {
|
||||
@@ -230,10 +208,6 @@ export function getMulti(params) {
|
||||
return coll.find(params);
|
||||
}
|
||||
|
||||
export function setMultiInDomain(domainId: string, query: any, params: any) {
|
||||
return document.setMultiStatus(domainId, document.TYPE_DOMAIN_USER, query, params);
|
||||
}
|
||||
|
||||
export async function getPrefixList(prefix: string, limit = 50) {
|
||||
prefix = prefix.toLowerCase();
|
||||
const $regex = new RegExp(`\\A\\Q${prefix}\\E`, 'gmi');
|
||||
@@ -245,55 +219,6 @@ export function setPriv(uid: number, priv: number) {
|
||||
return coll.findOneAndUpdate({ _id: uid }, { $set: priv }, { returnOriginal: false });
|
||||
}
|
||||
|
||||
export function setRole(domainId: string, uid: number, role: string) {
|
||||
return document.setStatus(domainId, document.TYPE_DOMAIN_USER, 0, uid, { role });
|
||||
}
|
||||
|
||||
export function setRoles(domainId: string, roles: any) {
|
||||
const tasks = [];
|
||||
for (const role in roles) {
|
||||
tasks.push(document.set(
|
||||
domainId, document.TYPE_DOMAIN_USER, role, { content: roles[role] },
|
||||
));
|
||||
}
|
||||
return Promise.all(tasks);
|
||||
}
|
||||
|
||||
export async function getRoles(domainId: string) {
|
||||
const docs = await document.getMulti(domainId, document.TYPE_DOMAIN_USER).sort('_id', 1).toArray();
|
||||
const roles = [];
|
||||
const r = [];
|
||||
for (const doc of docs) {
|
||||
roles.push({ _id: doc.docId, perm: doc.content });
|
||||
r.push(doc.docId);
|
||||
}
|
||||
for (const role in BUILTIN_ROLES) {
|
||||
if (!r.includes(role)) {
|
||||
roles.push({ _id: role, perm: BUILTIN_ROLES[role].perm });
|
||||
}
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
export function getRole(domainId: string, name: string) {
|
||||
return document.get(domainId, document.TYPE_DOMAIN_USER, name);
|
||||
}
|
||||
|
||||
export function getMultiInDomain(domainId: string, query: any = {}) {
|
||||
return document.getMultiStatus(domainId, document.TYPE_DOMAIN_USER, query);
|
||||
}
|
||||
|
||||
export function addRole(domainId: string, name: string, permission: string) {
|
||||
return document.add(domainId, permission, 1, document.TYPE_DOMAIN_USER, name);
|
||||
}
|
||||
|
||||
export function deleteRoles(domainId: string, roles) {
|
||||
return Promise.all([
|
||||
document.deleteMulti(domainId, document.TYPE_DOMAIN_USER, { docId: { $in: roles } }),
|
||||
document.deleteMultiStatus(domainId, document.TYPE_DOMAIN_USER, { role: { $in: roles } }),
|
||||
]);
|
||||
}
|
||||
|
||||
export function ban(uid: number) {
|
||||
return Promise.all([
|
||||
setPriv(uid, PRIV.PRIV_NONE),
|
||||
@@ -317,23 +242,12 @@ global.Hydro.model.user = {
|
||||
getByUname,
|
||||
getMulti,
|
||||
inc,
|
||||
incDomain,
|
||||
setById,
|
||||
setEmail,
|
||||
setPassword,
|
||||
setInDomain,
|
||||
setMultiInDomain,
|
||||
getMultiInDomain,
|
||||
getPrefixList,
|
||||
setPriv,
|
||||
setRole,
|
||||
setRoles,
|
||||
getRole,
|
||||
getList,
|
||||
getRoles,
|
||||
getInDomain,
|
||||
addRole,
|
||||
deleteRoles,
|
||||
ban,
|
||||
ensureIndexes,
|
||||
};
|
||||
Reference in new issue
Block a user