diff --git a/locales/index.d.ts b/locales/index.d.ts index 303f5df9c5..6a9d9f294e 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -12092,6 +12092,10 @@ export interface Locale extends ILocale { * {name} said something in a muted thread */ "userSaysSomethingInMutedThread": ParameterizedString<"name">; + /** + * {name} has been silenced by {host} staff + */ + "silencedUserSaysSomething": ParameterizedString<"name" | "host">; /** * {name} is flagged: "{cw}" */ diff --git a/packages/backend/src/core/WebhookTestService.ts b/packages/backend/src/core/WebhookTestService.ts index 96b06ac0c2..5fabe2052d 100644 --- a/packages/backend/src/core/WebhookTestService.ts +++ b/packages/backend/src/core/WebhookTestService.ts @@ -409,6 +409,7 @@ export class WebhookTestService { isMutingNote: false, isFavorited: false, isRenoted: false, + isSilenced: false, visibility: note.visibility, mentions: note.mentions, visibleUserIds: note.visibleUserIds, diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index 3d329684ea..9df6e909a6 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -642,13 +642,26 @@ export class NoteEntityService implements OnModuleInit { .getExists() : false), ]); + const packedUser = packedUsers?.get(note.userId) ?? this.userEntityService.pack(note.user ?? note.userId, me); + const isSilenced = Promise.resolve(packedUser).then(async u => { + if (!u.isSilenced && !u.instance?.isSilenced) return false; + if (note.userId === meId) return false; + + if (meId) { + const followings = opts._hint_?.userFollowings ?? await this.cacheService.userFollowingsCache.fetch(meId); + if (followings.has(note.userId)) return false; + } + + return true; + }); + const packed: Packed<'Note'> = await awaitAll({ id: note.id, threadId, createdAt: this.idService.parse(note.id).date.toISOString(), updatedAt: note.updatedAt ? note.updatedAt.toISOString() : undefined, userId: note.userId, - user: packedUsers?.get(note.userId) ?? this.userEntityService.pack(note.user ?? note.userId, me), + user: packedUser, text: text, cw: note.cw, mandatoryCW: note.mandatoryCW, @@ -689,6 +702,7 @@ export class NoteEntityService implements OnModuleInit { isMutingNote: mutedNotes.has(note.id), isFavorited, isRenoted, + isSilenced, ...(meId && Object.keys(reactions).length > 0 ? { myReaction: this.populateMyReaction({ diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts index 6d3b9fe15e..5ebea6c740 100644 --- a/packages/backend/src/models/json-schema/note.ts +++ b/packages/backend/src/models/json-schema/note.ts @@ -193,6 +193,10 @@ export const packedNoteSchema = { type: 'boolean', optional: false, nullable: false, }, + isSilenced: { + type: 'boolean', + optional: false, nullable: false, + }, emojis: { type: 'object', optional: true, nullable: false, diff --git a/packages/frontend/src/components/SkMutedNote.vue b/packages/frontend/src/components/SkMutedNote.vue index 05a1273238..fac948a987 100644 --- a/packages/frontend/src/components/SkMutedNote.vue +++ b/packages/frontend/src/components/SkMutedNote.vue @@ -47,6 +47,16 @@ Displays a placeholder for a muted note. + + + + + +