diff --git a/packages/hydrooj/src/handler/domain.ts b/packages/hydrooj/src/handler/domain.ts index 398349c48..b36c6711c 100644 --- a/packages/hydrooj/src/handler/domain.ts +++ b/packages/hydrooj/src/handler/domain.ts @@ -101,24 +101,68 @@ class DomainUserHandler extends ManageHandler { @requireSudo @param('format', Types.Range(['default', 'raw']), true) async get({ domainId }, format = 'default') { - const rudocs = {}; const [dudocs, roles] = await Promise.all([ - domain.getMultiUserInDomain(domainId, { - $and: [ - { role: { $nin: ['default', 'guest'] } }, - { role: { $ne: null } }, - ], - }).toArray(), + domain.collUser.aggregate([ + { + $match: { + $or: [{ + join: true, + }, { + role: { + $nin: ['default', 'guest'], + $ne: null, + }, + }], + domainId, + }, + }, + { + $lookup: { + from: 'user', + let: { uid: '$uid' }, + pipeline: [ + { + $match: { + $expr: { $eq: ['$_id', '$$uid'] }, + priv: { $bitsAllSet: PRIV.PRIV_USER_PROFILE }, + }, + }, + { + $project: { + _id: 1, + uname: 1, + avatar: 1, + }, + }, + ], + as: 'user', + }, + }, + { $unwind: '$user' }, + { + $project: { + user: 1, + role: 1, + join: 1, + displayName: this.user.hasPerm(PERM.PERM_VIEW_DISPLAYNAME), + }, + }, + ]).toArray(), domain.getRoles(domainId), ]); - // TODO: switch to getListForRender for better performance - const udict = await user.getList(domainId, dudocs.map((dudoc) => dudoc.uid)); - const users = dudocs.filter((dudoc) => udict[dudoc.uid].priv & PRIV.PRIV_USER_PROFILE); - const joined = Object.fromEntries(dudocs.map((dudoc) => [dudoc.uid, dudoc.join])); + const users = dudocs.map((dudoc) => { + const u = { + ...dudoc, + ...dudoc.user, + }; + delete u.user; + return u; + }); + const rudocs = {}; for (const role of roles) rudocs[role._id] = users.filter((udoc) => udoc.role === role._id); this.response.template = format === 'raw' ? 'domain_user_raw.html' : 'domain_user.html'; this.response.body = { - roles, rudocs, domain: this.domain, joined, + roles, rudocs, domain: this.domain, }; } @@ -286,7 +330,7 @@ class DomainJoinHandler extends Handler { ]); const assignedRole = this.user.hasPriv(PRIV.PRIV_MANAGE_ALL_DOMAIN) ? 'root' - : dudoc?.role; + : dudoc?.role || 'default'; if (dudoc?.join) throw new DomainJoinAlreadyMemberError(target, this.user._id); const r = await domain.getRoles(ddoc); const roles = r.map((role) => role._id); diff --git a/packages/hydrooj/src/model/domain.ts b/packages/hydrooj/src/model/domain.ts index 67558a397..48c493c2b 100644 --- a/packages/hydrooj/src/model/domain.ts +++ b/packages/hydrooj/src/model/domain.ts @@ -59,7 +59,7 @@ class DomainModel { }; await bus.parallel('domain/create', ddoc); await coll.insertOne(ddoc); - await DomainModel.setUserRole(domainId, owner, 'root'); + await DomainModel.setUserRole(domainId, owner, 'root', true); return domainId; } @@ -133,9 +133,10 @@ class DomainModel { } @ArgMethod - static async setUserRole(domainId: string, uid: MaybeArray, role: string) { + static async setUserRole(domainId: string, uid: MaybeArray, role: string, autojoin = false) { + const update = { $set: { role, ...(autojoin ? { join: true } : {}) } }; if (!(uid instanceof Array)) { - const res = await collUser.findOneAndUpdate({ domainId, uid }, { $set: { role } }, { upsert: true, returnDocument: 'after' }); + const res = await collUser.findOneAndUpdate({ domainId, uid }, update, { upsert: true, returnDocument: 'after' }); const udoc = await UserModel.getById(domainId, uid); deleteUserCache(udoc); return res; @@ -144,7 +145,7 @@ class DomainModel { .project<{ _id: number, mail: string, uname: string }>({ mail: 1, uname: 1 }) .toArray(); for (const udoc of affected) deleteUserCache(udoc); - return await collUser.updateMany({ domainId, uid: { $in: uid } }, { $set: { role } }, { upsert: true }); + return await collUser.updateMany({ domainId, uid: { $in: uid } }, update, { upsert: true }); } static async getRoles(domainId: string, count?: boolean): Promise; diff --git a/packages/hydrooj/src/upgrade.ts b/packages/hydrooj/src/upgrade.ts index 1812010d2..efbe5a0a9 100644 --- a/packages/hydrooj/src/upgrade.ts +++ b/packages/hydrooj/src/upgrade.ts @@ -707,7 +707,7 @@ export const coreScripts: MigrationScript[] = [ async function _91_92() { await domain.collUser.updateMany({}, { $set: { join: true } }); await domain.coll.updateMany( - { _join: { $or: [{ $exists: false }, { $eq: null }] } }, + { $or: [{ _join: { $exists: false } }, { _join: { $eq: null } }] }, { $set: { _join: { method: domain.JOIN_METHOD_ALL, role: 'default', expire: null }, _migratedJoin: true } }, ); const domainUser = await domain.coll.find({ domainId: 'system', join: true }, onPrimary) diff --git a/packages/ui-default/locales/zh.yaml b/packages/ui-default/locales/zh.yaml index 6d8d5fb9b..f92c2a57e 100644 --- a/packages/ui-default/locales/zh.yaml +++ b/packages/ui-default/locales/zh.yaml @@ -906,6 +906,7 @@ Testdata: 测试数据 Text: 文本 The 'default' role applies to ALL REGISTERED USER.: default 角色作用于所有已注册用户 The contest is a flexible time contest. You need to complete the contest within a specified time after you attended.: 本场比赛采用灵活时间模式,你需要在参加后的指定时间内完成比赛。 +The domain owner: 域所有者: The homework's deadline is due but in extension. You can still submit for this problem but your score will be penalized.: 作业已超过截止时间,但仍在延期时间内。您递交题目将无法获得全部分数。 The invitation code to enter to successfully join the domain. You can only use letters and numbers in the code and it should not be longer than 64 characters.: 加入此域的邀请码。您只能使用字母和数字,并且不能长于 64 个字符。 The invitation code you provided is invalid.: 您提供的邀请码无效。 @@ -1057,6 +1058,7 @@ Write Your Comment: 发表您的评论 Write Your Solution: 发表您的题解 Year: 年 You are currently in legacy mode. Some additional features will be unavailable. We strongly recommend switching to standard mode on a modern browser.: 您当前处于兼容模式。某些功能在此模式下不可用。我们强烈建议在现代浏览器上切换为标准模式以获得更好的体验。 +You are invited to join {0}: '您被邀请加入 {0}' You are not allowed to join the domain. The link is either invalid or expired.: 您无法加入该域,链接无效或已过期。 You can also upload your avatar to Gravatar and it will be automatically updated here.: 你也可以将头像上传到 Gravatar,本站的头像将自动更新。 You can create your own training plans and share them with others.: 您可以创建您自己的训练计划并且与他人分享。 diff --git a/packages/ui-default/templates/domain_user.html b/packages/ui-default/templates/domain_user.html index 9db169d0a..090cff332 100644 --- a/packages/ui-default/templates/domain_user.html +++ b/packages/ui-default/templates/domain_user.html @@ -82,7 +82,9 @@ {%- for udoc in udocs -%} {% set is_disabled=(rudoc._id == handler.user._id) %} - [{{udoc._id}}]{{ user.render_inline(udoc, avatar=false, badge=false) }}    + [{{udoc._id}}]{{ user.render_inline(udoc, avatar=false, badge=false) }}{% if not udoc.join %} + ({{ _('Not joined yet') }}) + {% endif %}    {%- endfor -%} {{ role }} @@ -101,7 +103,7 @@ {{ user.render_inline(rudoc, badge=false) }} - {% if not joined[rudoc._id] %}({{ _('Not joined yet') }}){% endif %} + {% if not rudoc.join %}({{ _('Not joined yet') }}){% endif %} {{ form.select({ diff --git a/packages/ui-default/templates/partials/problem_sidebar_normal.html b/packages/ui-default/templates/partials/problem_sidebar_normal.html index e0841e9e5..1d733a708 100644 --- a/packages/ui-default/templates/partials/problem_sidebar_normal.html +++ b/packages/ui-default/templates/partials/problem_sidebar_normal.html @@ -21,6 +21,7 @@ {% else %} + {% endif %} {% endif %}