From 1472c1567c791a8200f678b11c8523a6147dc9d3 Mon Sep 17 00:00:00 2001 From: undefined Date: Mon, 29 Mar 2021 01:57:13 +0800 Subject: [PATCH] core: bug fix fix #68 fix #70 fix #71 --- packages/hydrooj/package.json | 2 +- packages/hydrooj/src/handler/domain.ts | 13 +++++++-- packages/hydrooj/src/handler/home.ts | 2 +- packages/hydrooj/src/model/builtin.ts | 2 +- packages/hydrooj/src/model/domain.ts | 40 +++++++++++++++++--------- packages/hydrooj/src/model/setting.ts | 2 +- packages/hydrooj/src/service/server.ts | 1 - packages/hydrooj/src/upgrade.ts | 9 +++++- 8 files changed, 48 insertions(+), 23 deletions(-) diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index a9f1a522c..4de8f5eb1 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.20.44", + "version": "2.20.45", "bin": "bin/hydrooj.js", "main": "dist/loader.js", "typings": "dist/loader.d.ts", diff --git a/packages/hydrooj/src/handler/domain.ts b/packages/hydrooj/src/handler/domain.ts index 165a5b1a0..641f53b01 100644 --- a/packages/hydrooj/src/handler/domain.ts +++ b/packages/hydrooj/src/handler/domain.ts @@ -104,7 +104,7 @@ class DomainUserHandler extends ManageHandler { const [dudocs, roles] = await Promise.all([ domain.getMultiUserInDomain(domainId, { $and: [ - { role: { $ne: 'default' } }, + { role: { $nin: ['default', 'guest'] } }, { role: { $ne: null } }, ], }).toArray(), @@ -115,7 +115,7 @@ class DomainUserHandler extends ManageHandler { for (const role of roles) rudocs[role._id] = []; for (const dudoc of dudocs) { const ud = udict[dudoc.uid]; - rudocs[ud.role].push(ud); + rudocs[ud.role || 'default'].push(ud); } const rolesSelect = roles.map((role) => [role._id, role._id]); const path = [ @@ -135,6 +135,13 @@ class DomainUserHandler extends ManageHandler { await domain.setUserRole(domainId, uid, role); this.back(); } + + @param('uid', Types.Array) + @param('role', Types.String) + async postSetUsers(domainId: string, uid: number[], role: string) { + await domain.setUserRole(domainId, uid, role); + this.back(); + } } class DomainPermissionHandler extends ManageHandler { @@ -170,7 +177,7 @@ class DomainPermissionHandler extends ManageHandler { class DomainRoleHandler extends ManageHandler { async get({ domainId }) { - const roles = await domain.getRoles(domainId); + const roles = await domain.getRoles(domainId, true); const path = [ ['Hydro', 'homepage'], ['domain', null], diff --git a/packages/hydrooj/src/handler/home.ts b/packages/hydrooj/src/handler/home.ts index 9621e51cc..c355c02e1 100644 --- a/packages/hydrooj/src/handler/home.ts +++ b/packages/hydrooj/src/handler/home.ts @@ -296,7 +296,7 @@ class HomeDomainCreateHandler extends Handler { 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 }); - await domain.setUserRole(domainId, this.user._id, 'admin'); + await domain.setUserRole(domainId, this.user._id, 'root'); this.response.redirect = this.url('domain_dashboard', { domainId }); this.response.body = { domainId }; } diff --git a/packages/hydrooj/src/model/builtin.ts b/packages/hydrooj/src/model/builtin.ts index ace0e028c..51523b7de 100644 --- a/packages/hydrooj/src/model/builtin.ts +++ b/packages/hydrooj/src/model/builtin.ts @@ -304,7 +304,7 @@ export const BUILTIN_USERS: Udoc[] = [ export const BUILTIN_ROLES = { guest: PERM.PERM_BASIC, default: PERM.PERM_DEFAULT, - admin: PERM.PERM_ADMIN, + root: PERM.PERM_ALL, }; export const DEFAULT_NODES = { diff --git a/packages/hydrooj/src/model/domain.ts b/packages/hydrooj/src/model/domain.ts index cab21644f..cf84581cf 100644 --- a/packages/hydrooj/src/model/domain.ts +++ b/packages/hydrooj/src/model/domain.ts @@ -3,7 +3,7 @@ import { FilterQuery } from 'mongodb'; import { BUILTIN_ROLES, PRIV } from './builtin'; import { DomainDoc } from '../interface'; import { ArgMethod } from '../utils'; -import { NumberKeys } from '../typeutils'; +import { MaybeArray, NumberKeys } from '../typeutils'; import * as bus from '../service/bus'; import db from '../service/db'; @@ -52,6 +52,7 @@ class DomainModel { }; await bus.serial('domain/create', ddoc); await coll.insertOne(ddoc); + await DomainModel.setUserRole(domainId, owner, 'root'); return domainId; } @@ -104,15 +105,23 @@ class DomainModel { return r; } - @ArgMethod - static setUserRole(domainId: string, uid: number, role: string) { - return collUser.updateOne({ uid, domainId }, { $set: { role } }, { upsert: true }); + static async countUser(domainId: string, role?: string) { + if (role) return await collUser.find({ domainId, role }).count(); + return await collUser.find({ domainId }).count(); } - static async getRoles(domainId: string): Promise; - static async getRoles(domain: DomainDoc): Promise; @ArgMethod - static async getRoles(arg: string | DomainDoc) { + static setUserRole(domainId: string, uid: MaybeArray, role: string) { + if (!(uid instanceof Array)) { + return collUser.updateOne({ domainId, uid }, { $set: { role } }, { upsert: true }); + } + return collUser.updateMany({ domainId, uid: { $in: uid } }, { $set: { role } }, { upsert: true }); + } + + static async getRoles(domainId: string, count?: boolean): Promise; + static async getRoles(domain: DomainDoc, count?: boolean): Promise; + @ArgMethod + static async getRoles(arg: string | DomainDoc, count: boolean = false) { let ddoc: DomainDoc; if (typeof arg === 'string') ddoc = await DomainModel.get(arg); else ddoc = arg; @@ -127,6 +136,14 @@ class DomainModel { roles.push({ _id: role, perm: BUILTIN_ROLES[role] }); } } + if (count) { + for (const role of roles) { + if (!['default', 'guest'].includes(role._id)) { + // eslint-disable-next-line no-await-in-loop + role.count = await DomainModel.countUser(ddoc._id, role._id); + } + } + } return roles; } @@ -157,10 +174,9 @@ class DomainModel { 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'; + if (udoc.priv & PRIV.PRIV_MANAGE_ALL_DOMAIN) dudoc.role = 'root'; 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]; @@ -190,17 +206,13 @@ class DomainModel { @ArgMethod static async getDictUserByDomainId(uid: number) { - const [dudocs, ddocs] = await Promise.all([ - collUser.find({ uid }).toArray(), - coll.find({ owner: uid }).toArray(), - ]); + const dudocs = await collUser.find({ 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; } diff --git a/packages/hydrooj/src/model/setting.ts b/packages/hydrooj/src/model/setting.ts index fd8175457..8d0791cd4 100644 --- a/packages/hydrooj/src/model/setting.ts +++ b/packages/hydrooj/src/model/setting.ts @@ -205,7 +205,7 @@ bus.once('app/started', async () => { bus.on('system/setting', (args) => { if (!args.lang?.texts) return; - SETTINGS_BY_KEY['codeLang'].range = args.lang.texts; + SETTINGS_BY_KEY['codeLang'].range = yaml.load(args.lang.texts) as any; }); global.Hydro.model.setting = { diff --git a/packages/hydrooj/src/service/server.ts b/packages/hydrooj/src/service/server.ts index f14699716..4227f4418 100644 --- a/packages/hydrooj/src/service/server.ts +++ b/packages/hydrooj/src/service/server.ts @@ -29,7 +29,6 @@ import { CsrfTokenError, InvalidOperationError, MethodNotAllowedError, NotFoundError, HydroError, } from '../error'; -import hash from '../lib/hash.hydro'; import * as misc from '../lib/misc'; import user from '../model/user'; import domain from '../model/domain'; diff --git a/packages/hydrooj/src/upgrade.ts b/packages/hydrooj/src/upgrade.ts index 6bdf99e52..ba2b1d568 100644 --- a/packages/hydrooj/src/upgrade.ts +++ b/packages/hydrooj/src/upgrade.ts @@ -21,7 +21,7 @@ const logger = new Logger('upgrade'); type UpgradeScript = () => Promise; async function iterateAllDomain(cb: (ddoc: DomainDoc, current?: number, total?: number) => Promise) { - const ddocs = await domain.getMulti().project({ _id: 1 }).toArray(); + const ddocs = await domain.getMulti().project({ _id: 1, owner: 1 }).toArray(); for (const i in ddocs) await cb(ddocs[i], +i, ddocs.length); } @@ -220,6 +220,13 @@ const scripts: UpgradeScript[] = [ }); return true; }, + // Set domain owner perm + async function _13_14() { + const _FRESH_INSTALL_IGNORE = 1; + await iterateAllDomain((ddoc) => domain.setUserRole(ddoc._id, ddoc.owner, 'root')); + await db.collection('domain.user').updateMany({ role: 'admin' }, { $set: { role: 'root' } }); + return true; + }, ]; export = scripts;