From a9912534fecaf7d885ddcae71d8db931d80e670b Mon Sep 17 00:00:00 2001 From: kabo2468 <28654659+kabo2468@users.noreply.github.com> Date: Tue, 27 Feb 2024 02:51:17 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E3=83=AD=E3=83=BC=E3=83=AB=E3=81=AB?= =?UTF-8?q?=E3=82=88=E3=82=8B=E3=83=A1=E3=83=B3=E3=82=B7=E3=83=A7=E3=83=B3?= =?UTF-8?q?=E3=80=81=E3=83=AA=E3=83=97=E3=83=A9=E3=82=A4=E3=80=81=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E3=81=AE=E5=88=B6=E9=99=90=20(MisskeyIO#478)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/en-US.yml | 1 + locales/index.d.ts | 4 ++++ locales/ja-JP.yml | 1 + .../backend/src/core/NoteCreateService.ts | 15 +++++++++++++- packages/backend/src/core/RoleService.ts | 3 +++ .../src/core/entities/UserEntityService.ts | 2 +- .../server/api/endpoints/admin/show-user.ts | 2 +- packages/frontend/src/const.ts | 3 ++- .../frontend/src/pages/admin/roles.editor.vue | 20 +++++++++++++++++++ packages/frontend/src/pages/admin/roles.vue | 8 ++++++++ 10 files changed, 55 insertions(+), 4 deletions(-) diff --git a/locales/en-US.yml b/locales/en-US.yml index 67d7dd8a8..26cf271a5 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1664,6 +1664,7 @@ _role: gtlAvailable: "Can view the global timeline" ltlAvailable: "Can view the local timeline" canPublicNote: "Can send public notes" + canInitiateConversation: "Can mention, reply or quote" canCreateContent: "Can create contents" canUpdateContent: "Can edit contents" canDeleteContent: "Can delete contents" diff --git a/locales/index.d.ts b/locales/index.d.ts index ff6b22aaa..bb7a00ede 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -6558,6 +6558,10 @@ export interface Locale extends ILocale { * パブリック投稿の許可 */ "canPublicNote": string; + /** + * メンション、リプライ、引用の許可 + */ + "canInitiateConversation": string; /** * コンテンツの作成 */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 2766d0a91..31a4567ff 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1697,6 +1697,7 @@ _role: gtlAvailable: "グローバルタイムラインの閲覧" ltlAvailable: "ローカルタイムラインの閲覧" canPublicNote: "パブリック投稿の許可" + canInitiateConversation: "メンション、リプライ、引用の許可" canCreateContent: "コンテンツの作成" canUpdateContent: "コンテンツの編集" canDeleteContent: "コンテンツの削除" diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index b77534466..6e442451b 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -259,13 +259,14 @@ export class NoteCreateService implements OnApplicationShutdown { if (data.channel != null) data.localOnly = true; const meta = await this.metaService.fetch(); + const policies = await this.roleService.getUserPolicies(user.id); if (data.visibility === 'public' && data.channel == null) { const sensitiveWords = meta.sensitiveWords; if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', sensitiveWords)) { data.visibility = 'home'; this.logger.warn('Visibility changed to home because sensitive words are included', { user: user.id, note: data }); - } else if ((await this.roleService.getUserPolicies(user.id)).canPublicNote === false) { + } else if (policies.canPublicNote === false) { data.visibility = 'home'; } } @@ -379,6 +380,18 @@ export class NoteCreateService implements OnApplicationShutdown { } } + if (policies.canInitiateConversation === false) { + if ( + mentionedUsers.some(u => u.id !== user.id) + || (data.reply && data.reply.replyUserId !== user.id) + || (data.visibility === 'specified' && data.visibleUsers?.some(u => u.id !== user.id)) + || (this.isQuote(data) && data.renote.userId !== user.id) + ) { + this.logger.error('Request rejected because user has no permission to initiate conversation', { user: user.id, note: data }); + throw new IdentifiableError('332dd91b-6a00-430a-ac39-620cf60ad34b', 'Notes including mentions, replies, or renotes are not allowed.'); + } + } + tags = tags.filter(tag => Array.from(tag).length <= 128).splice(0, 32); if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) { diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 6c3582fbd..d8797040f 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -36,6 +36,7 @@ export type RolePolicies = { gtlAvailable: boolean; ltlAvailable: boolean; canPublicNote: boolean; + canInitiateConversation: boolean; canCreateContent: boolean; canUpdateContent: boolean; canDeleteContent: boolean; @@ -69,6 +70,7 @@ export const DEFAULT_POLICIES: RolePolicies = { gtlAvailable: true, ltlAvailable: true, canPublicNote: true, + canInitiateConversation: true, canCreateContent: true, canUpdateContent: true, canDeleteContent: true, @@ -338,6 +340,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { 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)), + canInitiateConversation: calc('canInitiateConversation', vs => vs.some(v => v === true)), canCreateContent: calc('canCreateContent', vs => vs.some(v => v === true)), canUpdateContent: calc('canUpdateContent', vs => vs.some(v => v === true)), canDeleteContent: calc('canDeleteContent', vs => vs.some(v => v === true)), diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index e081f3b7a..ed83676a2 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -393,7 +393,7 @@ export class UserEntityService implements OnModuleInit { bannerBlurhash: user.bannerBlurhash, isLocked: user.isLocked, isSilenced: !policies?.canPublicNote, - isLimited: !(policies?.canCreateContent && policies.canUpdateContent && policies.canDeleteContent), + isLimited: !(policies?.canCreateContent && policies.canUpdateContent && policies.canDeleteContent && policies.canInitiateConversation), isSuspended: user.isSuspended, description: profile!.description, location: profile!.location, diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index 02797476b..b9cc7a555 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -212,7 +212,7 @@ export default class extends Endpoint { // eslint- const policies = await this.roleService.getUserPolicies(user.id); const isModerator = await this.roleService.isModerator(user); - const isLimited = !(policies.canCreateContent && policies.canUpdateContent && policies.canDeleteContent); + const isLimited = !(policies.canCreateContent && policies.canUpdateContent && policies.canDeleteContent && policies.canInitiateConversation); const isSilenced = !policies.canPublicNote; const _me = await this.usersRepository.findOneByOrFail({ id: me.id }); diff --git a/packages/frontend/src/const.ts b/packages/frontend/src/const.ts index 5d517ad9c..02674ef88 100644 --- a/packages/frontend/src/const.ts +++ b/packages/frontend/src/const.ts @@ -75,6 +75,7 @@ export const ROLE_POLICIES = [ 'gtlAvailable', 'ltlAvailable', 'canPublicNote', + 'canInitiateConversation', 'canCreateContent', 'canUpdateContent', 'canDeleteContent', @@ -131,7 +132,7 @@ export const MFM_PARAMS: Record = { position: ['x=', 'y='], fg: ['color='], bg: ['color='], - border: ['width=', 'style=', 'color=', 'radius=', 'noclip'], + border: ['width=', 'style=', 'color=', 'radius=', 'noclip'], font: ['serif', 'monospace', 'cursive', 'fantasy', 'emoji', 'math'], blur: [], rainbow: ['speed=', 'delay='], diff --git a/packages/frontend/src/pages/admin/roles.editor.vue b/packages/frontend/src/pages/admin/roles.editor.vue index b4052fe33..8ee1958fc 100644 --- a/packages/frontend/src/pages/admin/roles.editor.vue +++ b/packages/frontend/src/pages/admin/roles.editor.vue @@ -160,6 +160,26 @@ SPDX-License-Identifier: AGPL-3.0-only + + + +
+ + + + + + + + + +
+
+