mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
core&ui: implement domain leave and kick
This commit is contained in:
13 files changed
+64
-28
No files matched your search
@@ -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
|
||||
|
||||
|
||||
@@ -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.: 그룹 생성이 끝나지 않았습니다. "계속"을 눌러 생성을 완료하십시오.
|
||||
|
||||
@@ -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.: 您有未完成的创建域操作。您可以点击“继续”来完成创建。
|
||||
|
||||
@@ -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.: 您還沒有參加本次比賽。
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -135,7 +135,7 @@ class DomainModel {
|
||||
@ArgMethod
|
||||
static async setUserRole(domainId: string, uid: MaybeArray<number>, 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<number>, 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<any[]>;
|
||||
static async getRoles(domain: DomainDoc, count?: boolean): Promise<any[]>;
|
||||
@ArgMethod
|
||||
|
||||
@@ -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.: 대회가 실시간이 아닙니다.
|
||||
|
||||
@@ -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 ╰(*°▽°*)╯: 目前还没有作业 ╰(*°▽°*)╯
|
||||
|
||||
@@ -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.: 比賽沒有開始。
|
||||
|
||||
@@ -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`
|
||||
<div class="typo">
|
||||
<p>${i18n('Confirm removing the selected users?')}</p>
|
||||
<p>${i18n('Their account will not be deleted and they will be with the default role.')}</p>
|
||||
<p>${i18n('Their account will not be deleted and they will be with the guest role until they re-join the domain.')}</p>
|
||||
</div>`,
|
||||
}).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));
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
border-left: 1px solid $table-border-color
|
||||
|
||||
.col--action
|
||||
width: rem(135px)
|
||||
width: rem(200px)
|
||||
|
||||
+mobile()
|
||||
.col--icon, .col--role
|
||||
|
||||
@@ -44,6 +44,11 @@
|
||||
{% if canManage[ddoc['_id']] %}
|
||||
· <a class="typo-a" href="{{ url('domain_dashboard', domainId=ddoc['_id']) }}">{{ _('Manage') }}</a>
|
||||
{% endif %}
|
||||
· <form class="form--inline" method="post">
|
||||
<input type="hidden" name="operation" value="leave">
|
||||
<input type="hidden" name="id" value="{{ ddoc['_id'] }}">
|
||||
<button class="typo-a" type="submit">{{ _('Leave') }}</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{%- endfor -%}
|
||||
|
||||
Reference in new issue
Block a user