From 518b3e2f7315af24d7b106bfdfd40a56c4cd6d8c Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 15 Jan 2023 19:10:39 +0900 Subject: [PATCH 1/7] =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=83=AB=E3=81=AE?= =?UTF-8?q?=E5=90=84=E3=82=AA=E3=83=97=E3=82=B7=E3=83=A7=E3=83=B3=E3=81=AB?= =?UTF-8?q?=E5=84=AA=E5=85=88=E5=BA=A6=E3=82=92=E8=A8=AD=E5=AE=9A=E3=81=A7?= =?UTF-8?q?=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/ja-JP.yml | 5 + packages/backend/src/core/RoleService.ts | 45 ++-- .../src/core/entities/RoleEntityService.ts | 1 + packages/backend/src/models/entities/Role.ts | 1 + .../frontend/src/pages/admin/roles.editor.vue | 222 ++++++++++-------- 5 files changed, 160 insertions(+), 114 deletions(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index a0802dd68c..79856447a0 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -957,6 +957,11 @@ _role: chooseRoleToAssign: "アサインするロールを選択" canEditMembersByModerator: "モデレーターのメンバー編集を許可" descriptionOfCanEditMembersByModerator: "オンにすると、管理者に加えてモデレーターもこのロールへユーザーをアサイン/アサイン解除できるようになります。オフにすると管理者のみが行えます。" + priority: "優先度" + _priority: + low: "低" + middle: "中" + high: "高" _options: gtlAvailable: "グローバルタイムラインの閲覧" ltlAvailable: "ローカルタイムラインの閲覧" diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 9fd612c96e..42b477d9ed 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -203,27 +203,36 @@ export class RoleService implements OnApplicationShutdown { const roles = await this.getUserRoles(userId); - function getOptionValues(option: keyof RoleOptions) { - if (roles.length === 0) return [baseRoleOptions[option]]; - return roles.map(role => (role.options[option] && (role.options[option].useDefault !== true)) ? role.options[option].value : baseRoleOptions[option]); + function calc(name: T, aggregate: (values: RoleOptions[T][]) => RoleOptions[T]) { + if (roles.length === 0) return baseRoleOptions[name]; + + const options = roles.map(role => role.options[name] ?? { priority: 0, useDefault: true }); + + const p2 = options.filter(option => option.priority === 2); + if (p2.length > 0) return aggregate(p2.map(option => option.useDefault ? baseRoleOptions[name] : option.value)); + + const p1 = options.filter(option => option.priority === 1); + if (p1.length > 0) return aggregate(p2.map(option => option.useDefault ? baseRoleOptions[name] : option.value)); + + return aggregate(options.map(option => option.useDefault ? baseRoleOptions[name] : option.value)); } return { - gtlAvailable: getOptionValues('gtlAvailable').some(x => x === true), - ltlAvailable: getOptionValues('ltlAvailable').some(x => x === true), - canPublicNote: getOptionValues('canPublicNote').some(x => x === true), - canInvite: getOptionValues('canInvite').some(x => x === true), - canManageCustomEmojis: getOptionValues('canManageCustomEmojis').some(x => x === true), - driveCapacityMb: Math.max(...getOptionValues('driveCapacityMb')), - pinLimit: Math.max(...getOptionValues('pinLimit')), - antennaLimit: Math.max(...getOptionValues('antennaLimit')), - wordMuteLimit: Math.max(...getOptionValues('wordMuteLimit')), - webhookLimit: Math.max(...getOptionValues('webhookLimit')), - clipLimit: Math.max(...getOptionValues('clipLimit')), - noteEachClipsLimit: Math.max(...getOptionValues('noteEachClipsLimit')), - userListLimit: Math.max(...getOptionValues('userListLimit')), - userEachUserListsLimit: Math.max(...getOptionValues('userEachUserListsLimit')), - rateLimitFactor: Math.max(...getOptionValues('rateLimitFactor')), + gtlAvailable: calc('gtlAvailable', vs => vs.some(v => v === true)), + ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)), + canPublicNote: calc('canPublicNote', vs => vs.some(v => v === true)), + canInvite: calc('canInvite', vs => vs.some(v => v === true)), + canManageCustomEmojis: calc('canManageCustomEmojis', vs => vs.some(v => v === true)), + driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)), + pinLimit: calc('pinLimit', vs => Math.max(...vs)), + antennaLimit: calc('antennaLimit', vs => Math.max(...vs)), + wordMuteLimit: calc('wordMuteLimit', vs => Math.max(...vs)), + webhookLimit: calc('webhookLimit', vs => Math.max(...vs)), + clipLimit: calc('clipLimit', vs => Math.max(...vs)), + noteEachClipsLimit: calc('noteEachClipsLimit', vs => Math.max(...vs)), + userListLimit: calc('userListLimit', vs => Math.max(...vs)), + userEachUserListsLimit: calc('userEachUserListsLimit', vs => Math.max(...vs)), + rateLimitFactor: calc('rateLimitFactor', vs => Math.max(...vs)), }; } diff --git a/packages/backend/src/core/entities/RoleEntityService.ts b/packages/backend/src/core/entities/RoleEntityService.ts index 7db7ed6695..6a14775653 100644 --- a/packages/backend/src/core/entities/RoleEntityService.ts +++ b/packages/backend/src/core/entities/RoleEntityService.ts @@ -44,6 +44,7 @@ export class RoleEntityService { for (const [k, v] of Object.entries(DEFAULT_ROLE)) { if (roleOptions[k] == null) roleOptions[k] = { useDefault: true, + priority: 0, value: v, }; } diff --git a/packages/backend/src/models/entities/Role.ts b/packages/backend/src/models/entities/Role.ts index a18df40d0c..d8d203493b 100644 --- a/packages/backend/src/models/entities/Role.ts +++ b/packages/backend/src/models/entities/Role.ts @@ -138,6 +138,7 @@ export class Role { }) public options: Record; } diff --git a/packages/frontend/src/pages/admin/roles.editor.vue b/packages/frontend/src/pages/admin/roles.editor.vue index bd166c9d48..0f67cec0b2 100644 --- a/packages/frontend/src/pages/admin/roles.editor.vue +++ b/packages/frontend/src/pages/admin/roles.editor.vue @@ -40,189 +40,235 @@
- +
- + - + + + + +
- +
- + - + + + +
- +
- + - + + + +
- +
- + - + + + +
- +
- + - + + + +
- +
- + - + + + +
- +
- + - + + + +
- +
- + - + + + +
- +
- + - + + + +
- +
- + - + + + +
- +
- + - + + + +
- +
- + - + + + +
- +
- + - + + + +
- +
- + - + + + +
- +
- + - + + + +
@@ -245,7 +291,7 @@