From bb913ee00a68a790a5bcb8c8ffaad0225fdf565e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=BE=E3=81=A3=E3=81=A1=E3=82=83=E3=81=A6=E3=81=83?= =?UTF-8?q?=E3=83=BC=E3=80=82?= <56515516+mattyatea@users.noreply.github.com> Date: Sat, 13 Jul 2024 02:08:56 +0900 Subject: [PATCH] =?UTF-8?q?feat(reaction):=20=E3=83=AD=E3=83=BC=E3=83=AB?= =?UTF-8?q?=E3=81=A7=E3=83=AA=E3=82=A2=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3?= =?UTF-8?q?=E3=81=AE=E5=88=B6=E5=BE=A1=E3=82=92=E3=81=A7=E3=81=8D=E3=82=8B?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=20(MisskeyIO#660)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/index.d.ts | 4 ++++ locales/ja-JP.yml | 1 + packages/backend/src/core/ReactionService.ts | 4 ++-- packages/backend/src/core/RoleService.ts | 3 +++ .../backend/src/models/json-schema/role.ts | 4 ++++ packages/frontend/src/components/MkNote.vue | 10 +++++----- packages/frontend/src/const.ts | 1 + .../frontend/src/pages/admin/roles.editor.vue | 20 +++++++++++++++++++ 8 files changed, 40 insertions(+), 7 deletions(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index 3db165d03..d2ece3ec5 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -6852,6 +6852,10 @@ export interface Locale extends ILocale { * サウンド設定でドライブのファイルを利用 */ "canUseDriveFileInSoundSettings": string; + /** + * リアクションの利用 + */ + "canUseReaction": string; /** * アイコンデコレーションの最大取付個数 */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 4426594d9..2fe1e03ae 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1768,6 +1768,7 @@ _role: canSearchNotes: "ノート検索の利用" canUseTranslator: "翻訳機能の利用" canUseDriveFileInSoundSettings: "サウンド設定でドライブのファイルを利用" + canUseReaction: "リアクションの利用" avatarDecorationLimit: "アイコンデコレーションの最大取付個数" _condition: roleAssignedTo: "マニュアルロールにアサイン済み" diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index e4aa0b983..626914c37 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -116,10 +116,10 @@ export class ReactionService { if (!await this.noteEntityService.isVisibleForMe(note, user.id)) { throw new IdentifiableError('68e9d2d1-48bf-42c2-b90a-b20e09fd3d48', 'Note not accessible for you.'); } + const policies = await this.roleService.getUserPolicies(user.id); let reaction = _reaction ?? FALLBACK; - - if (note.reactionAcceptance === 'likeOnly' || ((note.reactionAcceptance === 'likeOnlyForRemote' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote') && (user.host != null))) { + if (note.reactionAcceptance === 'likeOnly' || !policies.canUseReaction || ((note.reactionAcceptance === 'likeOnlyForRemote' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote') && (user.host != null))) { reaction = '\u2764'; } else if (_reaction) { const custom = reaction.match(isCustomEmojiRegexp); diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 102111fd9..cf188560b 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -53,6 +53,7 @@ export type RolePolicies = { canSearchNotes: boolean; canUseTranslator: boolean; canUseDriveFileInSoundSettings: boolean; + canUseReaction: boolean; canHideAds: boolean; driveCapacityMb: number; alwaysMarkNsfw: boolean; @@ -91,6 +92,7 @@ export const DEFAULT_POLICIES: RolePolicies = { canSearchNotes: false, canUseTranslator: true, canUseDriveFileInSoundSettings: false, + canUseReaction: true, canHideAds: false, driveCapacityMb: 100, alwaysMarkNsfw: false, @@ -402,6 +404,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { canSearchNotes: calc('canSearchNotes', vs => vs.some(v => v === true)), canUseTranslator: calc('canUseTranslator', vs => vs.some(v => v === true)), canUseDriveFileInSoundSettings: calc('canUseDriveFileInSoundSettings', vs => vs.some(v => v === true)), + canUseReaction: calc('canUseReaction', vs => vs.some(v => v === true)), canHideAds: calc('canHideAds', vs => vs.some(v => v === true)), driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)), alwaysMarkNsfw: calc('alwaysMarkNsfw', vs => vs.some(v => v === true)), diff --git a/packages/backend/src/models/json-schema/role.ts b/packages/backend/src/models/json-schema/role.ts index 2963d6659..519e95c47 100644 --- a/packages/backend/src/models/json-schema/role.ts +++ b/packages/backend/src/models/json-schema/role.ts @@ -248,6 +248,10 @@ export const packedRolePoliciesSchema = { type: 'boolean', optional: false, nullable: false, }, + canUseReaction: { + type: 'boolean', + optional: false, nullable: false, + }, canHideAds: { type: 'boolean', optional: false, nullable: false, diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index f17645b46..664d5eb21 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -119,9 +119,9 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -157,6 +157,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { computed, inject, onMounted, ref, shallowRef, Ref, watch, provide } from 'vue'; import * as mfm from 'mfm-js'; import * as Misskey from 'misskey-js'; +import MkButton from './MkButton.vue'; import MkNoteSub from '@/components/MkNoteSub.vue'; import MkNoteHeader from '@/components/MkNoteHeader.vue'; import MkNoteSimple from '@/components/MkNoteSimple.vue'; @@ -165,7 +166,6 @@ import MkReactionsViewerDetails from '@/components/MkReactionsViewer.details.vue import MkMediaList from '@/components/MkMediaList.vue'; import MkCwButton from '@/components/MkCwButton.vue'; import MkPoll from '@/components/MkPoll.vue'; -import MkButton from './MkButton.vue'; import MkUsersTooltip from '@/components/MkUsersTooltip.vue'; import MkUrlPreview from '@/components/MkUrlPreview.vue'; import MkInstanceTicker from '@/components/MkInstanceTicker.vue'; @@ -380,7 +380,7 @@ function reply(viaKeyboard = false): void { function react(viaKeyboard = false): void { pleaseLogin(); showMovedDialog(); - if (appearNote.value.reactionAcceptance === 'likeOnly') { + if (appearNote.value.reactionAcceptance === 'likeOnly' || !$i?.policies.canUseReaction) { sound.playMisskeySfx('reaction'); if (props.mock) { diff --git a/packages/frontend/src/const.ts b/packages/frontend/src/const.ts index 8521e2a0e..4ccc5b411 100644 --- a/packages/frontend/src/const.ts +++ b/packages/frontend/src/const.ts @@ -92,6 +92,7 @@ export const ROLE_POLICIES = [ 'canSearchNotes', 'canUseTranslator', 'canUseDriveFileInSoundSettings', + 'canUseReaction', 'canHideAds', 'driveCapacityMb', 'alwaysMarkNsfw', diff --git a/packages/frontend/src/pages/admin/roles.editor.vue b/packages/frontend/src/pages/admin/roles.editor.vue index d4aa50d9e..6584819fa 100644 --- a/packages/frontend/src/pages/admin/roles.editor.vue +++ b/packages/frontend/src/pages/admin/roles.editor.vue @@ -503,6 +503,26 @@ SPDX-License-Identifier: AGPL-3.0-only + + + +
+ + + + + + + + + +
+
+