diff --git a/README.md b/README.md index 3da11a298..543454e3d 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,8 @@ Hydro 用户群:1085853538 - import-qduoj: 修复 spj=null - core: 修复文件复制 - core: 支持存储并显示提交记录重测历史 +- core: 新的加域逻辑 +- ui: UserSelect.Multi: 支持批量粘贴用户名 ### Breaking API Changes @@ -144,6 +146,7 @@ Hydro 用户群:1085853538 - core: 移除 global.Hydro.ui.template - core: 移除 global.Hydro.lib - core: 移除 String.prototype.translate (使用 app.i18n.translate) +- core: 升级至 Mongo Driver 6 ## Hydro 4.19.0 / UI 4.57.0 diff --git a/packages/hydrooj/locales/ko.yaml b/packages/hydrooj/locales/ko.yaml index d161b258e..c2b01ebe4 100644 --- a/packages/hydrooj/locales/ko.yaml +++ b/packages/hydrooj/locales/ko.yaml @@ -688,7 +688,6 @@ The role to assign when user joining the domain.: 사용자가 그룹에 참여 The uploaded file is too long.: 업로드한 파일이 너무 깁니다. The user is already a member of the domain.: 이미 그룹에 속한 사용자입니다. The user is too lazy to leave something here...: 설명이 없습니다... (´・ω・`) -Their account will not be deleted and they will be with the default role.: 계정은 삭제되지 않을 것이고, default 역할을 가질 것입니다. There are no contests...: 대회 없음 There is no homework so far ╰(*°▽°*)╯: 과제 없음 ╰(*°▽°*)╯ This contest is not live.: 대회가 실시간이 아닙니다. @@ -810,6 +809,7 @@ You cannot visit this domain.: 이 그룹을 방문할 수 없습니다. You don't have the required permission ({0}) in this domain.: 그룹 권한이 없습니다. ({0})。 You don't have the required privilege.: 권한이 없습니다. You don't own any domain and don't have privilege to create domain.: 그룹을 만들 권한이 없습니다. +You have been kicked from domain {0} by {1}.: 당신은 {1}에 의해 {0}에서 추방되었습니다. You have not submitted any solutions for this problem: 아직 답안을 제출하지 않았습니다. You have permission to create problems for this domain.: 이 그룹에서 문제를 만들기 위한 권한이 있습니다. You have uncompleted domain creation operation. You can click "Continue" to finish the creation.: 그룹 생성이 끝나지 않았습니다. "계속"을 눌러 생성을 완료하십시오. diff --git a/packages/hydrooj/locales/zh.yaml b/packages/hydrooj/locales/zh.yaml index 525a629f2..97a579d76 100644 --- a/packages/hydrooj/locales/zh.yaml +++ b/packages/hydrooj/locales/zh.yaml @@ -792,7 +792,6 @@ The role to assign when user joining the domain.: 用户加入此域时分配的 The uploaded file is too long.: 上传的文件太长。 The user is already a member of the domain.: 该用户已是域的成员。 The user is too lazy to leave something here...: 该用户太懒,这里啥也没写 (´・ω・`) -Their account will not be deleted and they will be with the default role.: 他们的账号不会被删除,并且之后将以 default 角色访问。 theme: 主题 There are no contests...: 没有比赛… There is no homework so far ╰(*°▽°*)╯: 目前还没有作业 ╰(*°▽°*)╯ @@ -934,6 +933,7 @@ You cannot visit this domain.: 您不能访问此域。 You don't have the required permission ({0}) in this domain.: 您在该域中无相应权限 ({0})。 You don't have the required privilege.: 您没有相应的特权。 You don't own any domain and don't have privilege to create domain.: 您不拥有任何域也没有创建域的特权。 +You have been kicked from domain {0} by {1}.: 您已被 {1} 从域 {0} 中移除。 You have not submitted any solutions for this problem: 您在该题下没有递交过任何解答 You have permission to create problems for this domain.: 您有权限为此域创建题目。 You have uncompleted domain creation operation. You can click "Continue" to finish the creation.: 您有未完成的创建域操作。您可以点击“继续”来完成创建。 diff --git a/packages/hydrooj/locales/zh_TW.yaml b/packages/hydrooj/locales/zh_TW.yaml index 2cbe7f943..e16a4dedb 100644 --- a/packages/hydrooj/locales/zh_TW.yaml +++ b/packages/hydrooj/locales/zh_TW.yaml @@ -463,7 +463,6 @@ Technical Information: 技術資訊 Temporary session: 臨時會話 Text: 文字 The homework's deadline is due but in extension. You can still submit for this problem but your score will be penalized.: 功課已經截止,但處於延期時間内。您此時遞交的題目無法獲得全部分數。 -Their account will not be deleted and they will be with the default role.: 他們的賬號不會被刪除,並且之後將以 default 角色訪問。 There are no contests...: 沒有比賽… There is no homework so far ╰(*°▽°*)╯: 目前沒有功課 ╰(*°▽°*)╯ This contest is not live.: 比賽沒有開始。 @@ -551,6 +550,7 @@ You cannot submit for this problem because the homework's deadline is due.: 功 You don't have the required permission ({0}) in this domain.: 您在該域中無相應許可權 ({0})。 You don't have the required privilege.: 您沒有相應的特權。 You don't own any domain and don't have privilege to create domain.: 您不擁有任何域也沒有創建域的特權。 +You have been kicked from domain {0} by {1}.: 您已被 {1} 從域 {0} 中移除。 You have not submitted any solutions for this problem: 您在該題下沒有遞交過任何解答 You have permission to create problems for this domain.: 您有許可權為此域創建題目。 You haven't attended this contest yet.: 您還沒有參加本次比賽。 diff --git a/packages/hydrooj/src/handler/domain.ts b/packages/hydrooj/src/handler/domain.ts index 80f195765..52a398e93 100644 --- a/packages/hydrooj/src/handler/domain.ts +++ b/packages/hydrooj/src/handler/domain.ts @@ -11,6 +11,7 @@ import avatar from '../lib/avatar'; import { PERM, PERMS_BY_FAMILY, PRIV } from '../model/builtin'; import * as discussion from '../model/discussion'; import domain from '../model/domain'; +import MessageModel from '../model/message'; import * as oplog from '../model/oplog'; import { DOMAIN_SETTINGS, DOMAIN_SETTINGS_BY_KEY } from '../model/setting'; import * as system from '../model/system'; @@ -163,11 +164,15 @@ class DomainUserHandler extends ManageHandler { }; } + @param('uids', Types.NumericArray) + async post({ }, uids: number[]) { + if (uids.includes(this.domain.owner)) throw new ForbiddenError(); + } + @requireSudo - @post('uid', Types.Int) - @post('role', Types.Role) - async postSetUser(domainId: string, uid: number, role: string) { - if (uid === this.domain.owner) throw new ForbiddenError(); + @param('uids', Types.NumericArray) + @param('role', Types.Role) + async postSetUsers(domainId: string, uid: number[], role: string) { await Promise.all([ domain.setUserRole(domainId, uid, role), oplog.log(this, 'domain.setRole', { uid, role }), @@ -176,14 +181,20 @@ class DomainUserHandler extends ManageHandler { } @requireSudo - @param('uid', Types.NumericArray) - @param('role', Types.Role) - async postSetUsers(domainId: string, uid: number[], role: string) { - if (uid.includes(this.domain.owner)) throw new ForbiddenError(); + @param('uids', Types.NumericArray) + async postKick({ domainId }, uids: number[]) { + const original = await domain.getMultiUserInDomain(domainId, { uid: { $in: uids } }).toArray(); + const needUpdate = uids.filter((uid) => original.find((i) => i.uid === uid)?.join); + if (!needUpdate.length) return; await Promise.all([ - domain.setUserRole(domainId, uid, role), - oplog.log(this, 'domain.setRole', { uid, role }), + domain.setJoin(domainId, needUpdate.length > 1 ? needUpdate : needUpdate[0], false), + oplog.log(this, 'domain.kick', { uids: needUpdate }), ]); + const msg = JSON.stringify({ + message: 'You have been kicked from domain {0} by {1}.', + params: [this.domain.name, this.user.uname], + }); + await Promise.all(needUpdate.map((i) => MessageModel.send(1, i, msg, MessageModel.FLAG_RICHTEXT | MessageModel.FLAG_UNREAD))); this.back(); } } diff --git a/packages/hydrooj/src/handler/home.ts b/packages/hydrooj/src/handler/home.ts index 3b58113dd..3253e361c 100644 --- a/packages/hydrooj/src/handler/home.ts +++ b/packages/hydrooj/src/handler/home.ts @@ -488,7 +488,7 @@ class HomeDomainHandler extends Handler { } else { for (const ddoc of ddocs) { // eslint-disable-next-line no-await-in-loop - const udoc = (await user.getById(ddoc._id, this.user._id))!; + const udoc = await user.getById(ddoc._id, this.user._id); canManage[ddoc._id] = udoc.hasPerm(PERM.PERM_EDIT_DOMAIN); role[ddoc._id] = udoc.role; } @@ -504,6 +504,12 @@ class HomeDomainHandler extends Handler { else user.setById(this.user._id, { pinnedDomains: this.user.pinnedDomains.filter((i) => i !== id) }); this.back({ star }); } + + @param('id', Types.String) + async postLeave({ }, id: string) { + await domain.setJoin(id, this.user._id, false); + this.back(); + } } class HomeDomainCreateHandler extends Handler { diff --git a/packages/hydrooj/src/model/domain.ts b/packages/hydrooj/src/model/domain.ts index c40c60b78..39fedd717 100644 --- a/packages/hydrooj/src/model/domain.ts +++ b/packages/hydrooj/src/model/domain.ts @@ -135,7 +135,7 @@ class DomainModel { @ArgMethod static async setUserRole(domainId: string, uid: MaybeArray, role: string, autojoin = false) { const update = { $set: { role, ...(autojoin ? { join: true } : {}) } }; - if (!(uid instanceof Array)) { + if (!(Array.isArray(uid))) { const res = await collUser.findOneAndUpdate( { domainId, uid }, update, @@ -152,6 +152,15 @@ class DomainModel { return await collUser.updateMany({ domainId, uid: { $in: uid } }, update, { upsert: true }); } + static async setJoin(domainId: string, uid: MaybeArray, join: boolean) { + if (!(Array.isArray(uid))) { + await DomainModel.updateUserInDomain(domainId, uid, { $set: { join } }); + return; + } + await collUser.updateMany({ domainId, uid: { $in: uid } }, { $set: { join } }); + deleteUserCache(domainId); + } + static async getRoles(domainId: string, count?: boolean): Promise; static async getRoles(domain: DomainDoc, count?: boolean): Promise; @ArgMethod diff --git a/packages/ui-default/locales/ko.yaml b/packages/ui-default/locales/ko.yaml index 44f8693c0..186fb1651 100644 --- a/packages/ui-default/locales/ko.yaml +++ b/packages/ui-default/locales/ko.yaml @@ -680,6 +680,7 @@ Terms of Service: 이용 약관 Test data comes from: Testdata 출처 Testdata Config: Testdata 설정 Text: 본문 +Leave: 나가기 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.: 잘못된 초대 코드 @@ -688,7 +689,7 @@ The role to assign when user joining the domain.: 사용자가 그룹에 참여 The uploaded file is too long.: 업로드한 파일이 너무 깁니다. The user is already a member of the domain.: 이미 그룹에 속한 사용자입니다. The user is too lazy to leave something here...: 설명이 없습니다... (´・ω・`) -Their account will not be deleted and they will be with the default role.: 계정은 삭제되지 않을 것이고, default 역할을 가질 것입니다. +Their account will not be deleted and they will be with the guest role until they re-join the domain.: 계정은 삭제되지 않을 것이고, guest 역할을 가질 것입니다. 그룹에 다시 참여할 때까지 말이죠. There are no contests...: 대회 없음 There is no homework so far ╰(*°▽°*)╯: 과제 없음 ╰(*°▽°*)╯ This contest is not live.: 대회가 실시간이 아닙니다. diff --git a/packages/ui-default/locales/zh.yaml b/packages/ui-default/locales/zh.yaml index f92c2a57e..995fb2860 100644 --- a/packages/ui-default/locales/zh.yaml +++ b/packages/ui-default/locales/zh.yaml @@ -512,6 +512,7 @@ LaTeX Expressions: LaTeX 表达式 Learn More: 了解更多 Leave blank to use numeric pid.: 留空来使用数字题号。 Leave empty for default: 留空以使用默认 +Leave: 离开 Ledo: 乐多 Legacy mode: 兼容模式 Light: 亮色 @@ -916,7 +917,7 @@ The scoreboard was frozen with {0} minutes remaining at {1} - submissions in the The uploaded file is too long.: 上传的文件太长。 The user is already a member of the domain.: 该用户已是域的成员。 The user is too lazy to leave something here...: 该用户太懒,这里啥也没写 (´・ω・`) -Their account will not be deleted and they will be with the default role.: 他们的账号不会被删除,并且之后将以 default 角色访问。 +Their account will not be deleted and they will be with the guest role until they re-join the domain.: 他们的账号不会被删除,并且之后将以 guest 角色访问,直到他们重新加入域。 Theme: 主题 There are no contests...: 没有比赛… There is no homework so far ╰(*°▽°*)╯: 目前还没有作业 ╰(*°▽°*)╯ diff --git a/packages/ui-default/locales/zh_TW.yaml b/packages/ui-default/locales/zh_TW.yaml index 1c04a70c4..4cb4a89d6 100644 --- a/packages/ui-default/locales/zh_TW.yaml +++ b/packages/ui-default/locales/zh_TW.yaml @@ -238,6 +238,7 @@ Last Submit At: 最後遞交於 Last Update At: 最後活動時間 LaTeX Expressions: LaTeX 表示式 Learn More: 瞭解更多 +Leave: 離開 Links: 連結 List View: 列表視圖 Live: 正在進行 @@ -462,7 +463,7 @@ Technical Information: 技術資訊 Temporary session: 臨時會話 Text: 文字 The homework's deadline is due but in extension. You can still submit for this problem but your score will be penalized.: 功課已經截止,但處於延期時間内。您此時遞交的題目無法獲得全部分數。 -Their account will not be deleted and they will be with the default role.: 他們的賬號不會被刪除,並且之後將以 default 角色訪問。 +Their account will not be deleted and they will be with the guest role until they re-join the domain.: 他們的賬號不會被刪除,並且之後將以 guest 角色訪問,直到他們重新加入域。 There are no contests...: 沒有比賽… There is no homework so far ╰(*°▽°*)╯: 目前沒有功課 ╰(*°▽°*)╯ This contest is not live.: 比賽沒有開始。 diff --git a/packages/ui-default/pages/domain_user.page.js b/packages/ui-default/pages/domain_user.page.js index 71884486a..11c804548 100644 --- a/packages/ui-default/pages/domain_user.page.js +++ b/packages/ui-default/pages/domain_user.page.js @@ -60,8 +60,8 @@ const page = new NamedPage('domain_user', () => { const role = addUserDialog.$dom.find('[name="role"]').val(); try { await request.post('', { - operation: 'set_user', - uid: user._id, + operation: 'set_users', + uids: [user._id], role, }); window.location.reload(); @@ -91,15 +91,14 @@ const page = new NamedPage('domain_user', () => { $body: tpl`

${i18n('Confirm removing the selected users?')}

-

${i18n('Their account will not be deleted and they will be with the default role.')}

+

${i18n('Their account will not be deleted and they will be with the guest role until they re-join the domain.')}

`, }).open(); if (action !== 'yes') return; try { await request.post('', { - operation: 'set_users', - uid: selectedUsers, - role: 'default', + operation: 'kick', + uids: selectedUsers, }); Notification.success(i18n('Selected users have been removed from the domain.')); await delay(2000); @@ -122,7 +121,7 @@ const page = new NamedPage('domain_user', () => { try { await request.post('', { operation: 'set_users', - uid: selectedUsers, + uids: selectedUsers, role, }); Notification.success(i18n('Role has been updated to {0} for selected users.', role)); @@ -138,8 +137,8 @@ const page = new NamedPage('domain_user', () => { const role = $(ev.currentTarget).val(); try { await request.post('', { - operation: 'set_user', - uid: row.attr('data-uid'), + operation: 'set_users', + uids: [row.attr('data-uid')], role, }); Notification.success(i18n('Role has been updated to {0}.', role)); diff --git a/packages/ui-default/pages/home_domain.page.styl b/packages/ui-default/pages/home_domain.page.styl index fa69b807c..a50fd3c37 100644 --- a/packages/ui-default/pages/home_domain.page.styl +++ b/packages/ui-default/pages/home_domain.page.styl @@ -11,7 +11,7 @@ border-left: 1px solid $table-border-color .col--action - width: rem(135px) + width: rem(200px) +mobile() .col--icon, .col--role diff --git a/packages/ui-default/templates/home_domain.html b/packages/ui-default/templates/home_domain.html index 81e9609bc..329f4be30 100644 --- a/packages/ui-default/templates/home_domain.html +++ b/packages/ui-default/templates/home_domain.html @@ -44,6 +44,11 @@ {% if canManage[ddoc['_id']] %} · {{ _('Manage') }} {% endif %} + ·
+ + + +
{%- endfor -%}