mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
优化domain.user存储结构
This commit is contained in:
1 parent
3eb593d134
commit
a93da2badb
17 files changed
+220
-239
No files matched your search
+14
-43
@@ -1,20 +1,18 @@
|
||||
import { RoleAlreadyExistError, ValidationError, PermissionError } from '../error';
|
||||
import { RoleAlreadyExistError, ValidationError } from '../error';
|
||||
import * as user from '../model/user';
|
||||
import * as domain from '../model/domain';
|
||||
import * as system from '../model/system';
|
||||
import { DOMAIN_SETTINGS, DOMAIN_SETTINGS_BY_KEY } from '../model/setting';
|
||||
import { PERM, PERMS_BY_FAMILY } from '../model/builtin';
|
||||
import paginate from '../lib/paginate';
|
||||
import {
|
||||
Route, Handler, Types, param,
|
||||
} from '../service/server';
|
||||
import { isTitle, isUname } from '../lib/validator';
|
||||
|
||||
class DomainRankHandler extends Handler {
|
||||
@param('page', Types.UnsignedInt, true)
|
||||
async get(domainId: string, page = 1) {
|
||||
const [dudocs, upcount, ucount] = await paginate(
|
||||
user.getMultiInDomain(domainId).sort({ rating: -1 }),
|
||||
domain.getMultiInDomain(domainId).sort({ rating: -1 }),
|
||||
page,
|
||||
100,
|
||||
);
|
||||
@@ -34,31 +32,6 @@ class DomainRankHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
class DomainCreateHandler extends Handler {
|
||||
async prepare() {
|
||||
if (this.user.priv !== 1) {
|
||||
if (!await system.get('user.create_domain')) throw new PermissionError('domain_create');
|
||||
}
|
||||
}
|
||||
|
||||
async get() {
|
||||
const path = [
|
||||
['Hydro', 'homepage'],
|
||||
['domain_create', null],
|
||||
];
|
||||
this.response.body = { path };
|
||||
this.response.template = 'domain_create.html';
|
||||
}
|
||||
|
||||
@param('id', Types.String, isUname)
|
||||
@param('name', Types.String, isTitle)
|
||||
async post(domainId: string, id: string, name: string) {
|
||||
await domain.add(id, this.user._id, name);
|
||||
this.response.body = { domainId: id };
|
||||
this.response.redirect = this.url('homepage', { domainId: id });
|
||||
}
|
||||
}
|
||||
|
||||
class ManageHandler extends Handler {
|
||||
domain: any;
|
||||
|
||||
@@ -105,13 +78,13 @@ class DomainUserHandler extends ManageHandler {
|
||||
async get({ domainId }) {
|
||||
const rudocs = {};
|
||||
const [dudocs, roles] = await Promise.all([
|
||||
user.getMultiInDomain(domainId, {
|
||||
domain.getMultiInDomain(domainId, {
|
||||
$and: [
|
||||
{ role: { $ne: 'default' } },
|
||||
{ role: { $ne: null } },
|
||||
],
|
||||
}).toArray(),
|
||||
user.getRoles(domainId),
|
||||
domain.getRoles(domainId),
|
||||
]);
|
||||
const uids = dudocs.map((dudoc) => dudoc.uid);
|
||||
const udict = await user.getList(domainId, uids);
|
||||
@@ -133,14 +106,14 @@ class DomainUserHandler extends ManageHandler {
|
||||
}
|
||||
|
||||
async postSetUser({ domainId, uid, role }) {
|
||||
await user.setRole(domainId, uid, role);
|
||||
await domain.setUserRole(domainId, uid, role);
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
|
||||
class DomainPermissionHandler extends ManageHandler {
|
||||
async get({ domainId }) {
|
||||
const roles = await user.getRoles(domainId);
|
||||
const roles = await domain.getRoles(domainId);
|
||||
const path = [
|
||||
['Hydro', 'homepage'],
|
||||
['domain', null],
|
||||
@@ -159,14 +132,14 @@ class DomainPermissionHandler extends ManageHandler {
|
||||
roles[role] = this.request.body[role].join('');
|
||||
}
|
||||
}
|
||||
await user.setRoles(domainId, roles);
|
||||
await domain.setRoles(domainId, roles);
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
|
||||
class DomainRoleHandler extends ManageHandler {
|
||||
async get({ domainId }) {
|
||||
const roles = await user.getRoles(domainId);
|
||||
const roles = await domain.getRoles(domainId);
|
||||
const path = [
|
||||
['Hydro', 'homepage'],
|
||||
['domain', null],
|
||||
@@ -177,12 +150,11 @@ class DomainRoleHandler extends ManageHandler {
|
||||
}
|
||||
|
||||
async postAdd({ domainId, role }) {
|
||||
const [r, u] = await Promise.all([
|
||||
user.getRole(domainId, role),
|
||||
user.getRole(domainId, 'default'),
|
||||
]);
|
||||
if (r) throw new RoleAlreadyExistError(role);
|
||||
await user.addRole(domainId, role, u.perm);
|
||||
const roles = await domain.getRoles(this.domain);
|
||||
const rdict: any = {};
|
||||
for (const r of roles) rdict[r._id] = r.perm;
|
||||
if (rdict[role]) throw new RoleAlreadyExistError(role);
|
||||
await domain.addRole(domainId, role, rdict.default.perm);
|
||||
this.back();
|
||||
}
|
||||
|
||||
@@ -192,14 +164,13 @@ class DomainRoleHandler extends ManageHandler {
|
||||
throw new ValidationError('role');
|
||||
}
|
||||
}
|
||||
await user.deleteRoles(domainId, roles);
|
||||
await domain.deleteRoles(domainId, roles);
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
|
||||
export async function apply() {
|
||||
Route('ranking', '/ranking', DomainRankHandler);
|
||||
Route('domain_create', '/domain/create', DomainCreateHandler);
|
||||
Route('domain_dashboard', '/domain/dashboard', DomainDashboardHandler);
|
||||
Route('domain_edit', '/domain/edit', DomainEditHandler);
|
||||
Route('domain_user', '/domain/user', DomainUserHandler);
|
||||
|
||||
+43
-3
@@ -24,7 +24,9 @@ import * as discussion from '../model/discussion';
|
||||
import * as token from '../model/token';
|
||||
import * as training from '../model/training';
|
||||
import { PERM, PRIV } from '../model/builtin';
|
||||
import { isContent, isPassword, isEmail } from '../lib/validator';
|
||||
import {
|
||||
isContent, isPassword, isEmail, isTitle,
|
||||
} from '../lib/validator';
|
||||
|
||||
const { geoip, useragent } = global.Hydro.lib;
|
||||
|
||||
@@ -133,7 +135,7 @@ class HomeSecurityHandler extends Handler {
|
||||
['home_security', null],
|
||||
];
|
||||
this.response.template = 'home_security.html';
|
||||
this.response.body = { sessions, geoipProvider: (geoip || {}).provider, path };
|
||||
this.response.body = { sessions, geoipProvider: geoip?.provider, path };
|
||||
if (useragent) this.response.body.icon = useragent.icon;
|
||||
}
|
||||
|
||||
@@ -210,7 +212,8 @@ class HomeSettingsHandler extends Handler {
|
||||
async post(args: any) {
|
||||
const $set = {};
|
||||
for (const key in args) {
|
||||
if (setting.SETTINGS_BY_KEY[key] && !setting.SETTINGS_BY_KEY[key].disabled) {
|
||||
if (setting.SETTINGS_BY_KEY[key]
|
||||
&& !(setting.SETTINGS_BY_KEY[key].flag & setting.FLAG_DISABLED)) {
|
||||
$set[key] = args[key];
|
||||
}
|
||||
}
|
||||
@@ -236,6 +239,41 @@ class UserChangemailWithCodeHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
class HomeDomainHandler extends Handler {
|
||||
async get() {
|
||||
const dudict = await domain.getDictUserByDomainId(this.user._id);
|
||||
const dids = Object.keys(dudict);
|
||||
const ddocs = await domain.getMulti({ _id: { $in: dids } }).toArray();
|
||||
const canManage = {};
|
||||
for (const ddoc of ddocs) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const udoc = await user.getById(ddoc._id, this.user._id);
|
||||
canManage[ddoc._id] = udoc.hasPerm(PERM.PERM_EDIT_DOMAIN)
|
||||
|| udoc.hasPriv(PRIV.PRIV_MANAGE_ALL_DOMAIN);
|
||||
}
|
||||
this.response.template = 'home_domain.html';
|
||||
this.response.body = { ddocs, dudict, canManage };
|
||||
}
|
||||
}
|
||||
|
||||
class HomeDomainCreateHandler extends Handler {
|
||||
async get() {
|
||||
this.response.body = 'home_domain_create.html';
|
||||
}
|
||||
|
||||
@param('id', Types.String)
|
||||
@param('name', Types.String, isTitle)
|
||||
@param('bulletin', Types.String, isContent)
|
||||
@param('gravatar', Types.String, isEmail, true)
|
||||
async post(_: string, id: string, name: string, bulletin: string, gravatar: string) {
|
||||
gravatar = gravatar || this.user.gravatar || this.user.mail || 'guest@hydro.local';
|
||||
const domainId = await domain.add(id, this.user._id, name, bulletin);
|
||||
await domain.edit(domainId, { gravatar });
|
||||
this.response.redirect = this.url('domain_manage', { domainId });
|
||||
this.response.body = { domainId };
|
||||
}
|
||||
}
|
||||
|
||||
class HomeMessagesHandler extends Handler {
|
||||
async get() {
|
||||
// TODO(iceboy): projection, pagination.
|
||||
@@ -324,6 +362,8 @@ async function apply() {
|
||||
Route('home_security', '/home/security', HomeSecurityHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Route('user_changemail_with_code', '/home/changeMail/:code', UserChangemailWithCodeHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Route('home_settings', '/home/settings/:category', HomeSettingsHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Route('home_domain', '/home/domain', HomeDomainHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Route('home_domain_create', '/home/domain/create', HomeDomainCreateHandler, PRIV.PRIV_CREATE_DOMAIN);
|
||||
Route('home_messages', '/home/messages', HomeMessagesHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Route('home_file', '/home/file', HomeFileHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Connection('home_messages_conn', '/home/messages-conn', HomeMessagesConnectionHandler, PRIV.PRIV_USER_PROFILE);
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as record from '../model/record';
|
||||
import * as problem from '../model/problem';
|
||||
import * as builtin from '../model/builtin';
|
||||
import * as contest from '../model/contest';
|
||||
import * as user from '../model/user';
|
||||
import * as domain from '../model/domain';
|
||||
import * as task from '../model/task';
|
||||
import * as bus from '../service/bus';
|
||||
import {
|
||||
@@ -29,7 +29,7 @@ async function _postJudge(rdoc) {
|
||||
if (accept && !rdoc.rejudged) {
|
||||
tasks.push(
|
||||
problem.inc(rdoc.domainId, rdoc.pid, 'nAccept', 1),
|
||||
user.incDomain(rdoc.domainId, rdoc.uid, 'nAccept', 1),
|
||||
domain.incUserInDomain(rdoc.domainId, rdoc.uid, 'nAccept', 1),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import * as file from '../model/file';
|
||||
import * as problem from '../model/problem';
|
||||
import * as record from '../model/record';
|
||||
import * as domain from '../model/domain';
|
||||
import * as user from '../model/user';
|
||||
import * as solution from '../model/solution';
|
||||
import * as system from '../model/system';
|
||||
@@ -219,7 +220,7 @@ class ProblemSubmitHandler extends ProblemDetailHandler {
|
||||
const rid = await record.add(domainId, {
|
||||
uid: this.user._id, lang, code, pid: this.pdoc.docId,
|
||||
}, true);
|
||||
await user.incDomain(domainId, this.user._id, 'nSubmit');
|
||||
await domain.incUserInDomain(domainId, this.user._id, 'nSubmit');
|
||||
this.response.body = { rid };
|
||||
this.response.redirect = this.url('record_detail', { rid });
|
||||
}
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ String.prototype.rawformat = function rawFormat(object) {
|
||||
};
|
||||
|
||||
String.prototype.translate = function translate(...languages: string[]) {
|
||||
if (languages.length == 0) languages = ['zh_CN'];
|
||||
if (languages.length === 0) languages = ['zh_CN'];
|
||||
for (const language of languages) {
|
||||
if (locales[language]) {
|
||||
if (locales[language][this] !== undefined) return locales[language][this];
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -9,7 +9,7 @@ import { STATUS, PRIV } from '../model/builtin';
|
||||
export const description = 'Delete a user';
|
||||
|
||||
const collDocument = db.collection('document');
|
||||
const collStatus = db.collection('document.status');
|
||||
const collDomainUser = db.collection('domain.user');
|
||||
const collRecord = db.collection('record');
|
||||
|
||||
const $unset = {
|
||||
@@ -75,7 +75,7 @@ export async function run({
|
||||
}) {
|
||||
await deleteRecord(uid);
|
||||
await deleteDiscussion(uid);
|
||||
await collStatus.deleteMany({ uid, docType: document.TYPE_DOMAIN_USER });
|
||||
await collDomainUser.deleteMany({ uid });
|
||||
const uname = String.random(32);
|
||||
await user.setById(uid, {
|
||||
uname,
|
||||
|
||||
+1
-37
@@ -1,5 +1,4 @@
|
||||
import { PRIV } from '../model/builtin';
|
||||
import * as system from '../model/system';
|
||||
import * as user from '../model/user';
|
||||
import * as domain from '../model/domain';
|
||||
import pwhash from '../lib/hash.hydro';
|
||||
@@ -7,42 +6,7 @@ import pwhash from '../lib/hash.hydro';
|
||||
export const description = 'Install';
|
||||
|
||||
export async function run({ username = '', password = '' } = {}) {
|
||||
const def = {
|
||||
PROBLEM_PER_PAGE: 100,
|
||||
RECORD_PER_PAGE: 100,
|
||||
SOLUTION_PER_PAGE: 20,
|
||||
CONTEST_PER_PAGE: 20,
|
||||
TRAINING_PER_PAGE: 10,
|
||||
DISCUSSION_PER_PAGE: 50,
|
||||
REPLY_PER_PAGE: 50,
|
||||
HOMEWORK_ON_MAIN: 5,
|
||||
CONTESTS_ON_MAIN: 5,
|
||||
TRAININGS_ON_MAIN: 5,
|
||||
DISCUSSIONS_ON_MAIN: 20,
|
||||
'smtp.host': '',
|
||||
'smtp.port': 465,
|
||||
'smtp.from': '',
|
||||
'smtp.user': '',
|
||||
'smtp.pass': '',
|
||||
'smtp.secure': false,
|
||||
'db.ver': 1,
|
||||
'server.port': 8888,
|
||||
'session.keys': ['Hydro'],
|
||||
'session.secure': false,
|
||||
'session.saved_expire_seconds': 3600 * 24,
|
||||
'session.unsaved_expire_seconds': 600,
|
||||
changemail_token_expire_seconds: 3600 * 24,
|
||||
registration_token_expire_seconds: 600,
|
||||
};
|
||||
const tasks = [];
|
||||
for (const key in def) {
|
||||
tasks.push(system.get(key).then((value) => {
|
||||
if (!value) return system.set(key, def[key]);
|
||||
return Promise.resolve();
|
||||
}));
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
await domain.add('system', 0, 'Hydro', true);
|
||||
await domain.add('system', 0, 'Hydro', 'Hydro System');
|
||||
if (username && password) {
|
||||
const udoc = await user.getById('system', -1);
|
||||
if (!udoc) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
import * as domain from '../model/domain';
|
||||
import * as contest from '../model/contest';
|
||||
import * as user from '../model/user';
|
||||
import rating from '../lib/rating';
|
||||
import { STATUS } from '../model/builtin';
|
||||
|
||||
@@ -27,7 +26,7 @@ export async function run({ domainId, isSub = false }, report) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
await user.setMultiInDomain(domainId, {}, { rating: 1500 });
|
||||
await domain.setMultiUserInDomain(domainId, {}, { rating: 1500 });
|
||||
const contests = await contest.getMulti(domainId, { rated: true }).sort('endAt', -1).toArray();
|
||||
await report({ message: `Found ${contests.length} contests in ${domainId}` });
|
||||
const udict = {};
|
||||
@@ -60,7 +59,7 @@ export async function run({ domainId, isSub = false }, report) {
|
||||
}
|
||||
const tasks = [];
|
||||
for (const uid in udict) {
|
||||
tasks.push(user.setInDomain(domainId, parseInt(uid, 10), { rating: udict[uid] }));
|
||||
tasks.push(domain.setUserInDomain(domainId, parseInt(uid, 10), { rating: udict[uid] }));
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
return true;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydrooj",
|
||||
"version": "2.7.4",
|
||||
"version": "2.7.5",
|
||||
"main": "hydro/loader.ts",
|
||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||
"author": "masnn",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{% block manage_content %}
|
||||
<script>
|
||||
var Context = {
|
||||
'socketUrl': "/manage/check-conn?token={{ handler.csrfToken }}"
|
||||
'socketUrl': "/manage/check-conn?token={{ handler.UIContext.token }}"
|
||||
};
|
||||
</script>
|
||||
<div class="section">
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{% block content %}
|
||||
<script>
|
||||
var Context = {
|
||||
'socketUrl': "/record-detail-conn?rid={{ rdoc._id }}&token={{ handler.csrfToken }}"
|
||||
'socketUrl': "/record-detail-conn?rid={{ rdoc._id }}&token={{ handler.UIContext.token }}"
|
||||
};
|
||||
</script>
|
||||
<div class="row">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% block content %}
|
||||
<script>
|
||||
var Context = {
|
||||
'socketUrl': "/record-conn?token={{ handler.csrfToken }}",
|
||||
'socketUrl': "/record-conn?token={{ handler.UIContext.token }}",
|
||||
'rids': [
|
||||
{% for rdoc in rdocs %}"{{ rdoc._id.toString() }}",{% endfor %}
|
||||
]
|
||||
|
||||
Reference in new issue
Block a user