diff --git a/CHANGELOG.md b/CHANGELOG.md index 79c581d3fc..c903e51dba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,9 @@ ### Server - Fix: nodeinfoにenableMcaptchaとenableTurnstileが無いのを修正 - +- Fix: 破損した通知をクライアントに送信しないように + * 通知欄が無限にリロードされる問題が改善する可能性があります + ## 2024.2.0 ### Note diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index 824f0b7fda..48ea782893 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -67,24 +67,41 @@ export class NotificationEntityService implements OnModuleInit { packedNotes: Map>; packedUsers: Map>; }, - ): Promise|null> { + ): Promise | null> { const notification = src; if (options.checkValidNotifier !== false && !(await this.#isValidNotifier(notification, meId))) return null; - const noteIfNeed = NOTE_REQUIRED_NOTIFICATION_TYPES.has(notification.type) && 'noteId' in notification ? ( + const needsNote = NOTE_REQUIRED_NOTIFICATION_TYPES.has(notification.type) && 'noteId' in notification; + const noteIfNeed = needsNote ? ( hint?.packedNotes != null ? hint.packedNotes.get(notification.noteId) : this.noteEntityService.pack(notification.noteId, { id: meId }, { detail: true, }) ) : undefined; - const userIfNeed = 'notifierId' in notification ? ( + // if the note has been deleted, don't show this notification + if (needsNote && !noteIfNeed) { + return null; + } + + const needsUser = 'notifierId' in notification; + const userIfNeed = needsUser ? ( hint?.packedUsers != null ? hint.packedUsers.get(notification.notifierId) : this.userEntityService.pack(notification.notifierId, { id: meId }) ) : undefined; - const role = notification.type === 'roleAssigned' ? await this.roleEntityService.pack(notification.roleId) : undefined; + // if the user has been deleted, don't show this notification + if (needsUser && !userIfNeed) { + return null; + } + + const needsRole = notification.type === 'roleAssigned'; + const role = needsRole ? await this.roleEntityService.pack(notification.roleId) : undefined; + // if the role has been deleted, don't show this notification + if (needsRole && !role) { + return null; + } return await awaitAll({ id: notification.id, @@ -167,26 +184,37 @@ export class NotificationEntityService implements OnModuleInit { packedNotes: Map>; packedUsers: Map>; }, - ): Promise|null> { + ): Promise | null> { const notification = src; if ( options.checkValidNotifier !== false && !(await this.#isValidNotifier(notification, meId))) return null; - const noteIfNeed = NOTE_REQUIRED_GROUPED_NOTIFICATION_TYPES.has(notification.type) && 'noteId' in notification ? ( + const needsNote = NOTE_REQUIRED_GROUPED_NOTIFICATION_TYPES.has(notification.type) && 'noteId' in notification; + const noteIfNeed = needsNote ? ( hint?.packedNotes != null ? hint.packedNotes.get(notification.noteId) : this.noteEntityService.pack(notification.noteId, { id: meId }, { detail: true, }) ) : undefined; - const userIfNeed = 'notifierId' in notification ? ( + // if the note has been deleted, don't show this notification + if (needsNote && !noteIfNeed) { + return null; + } + + const needsUser = 'notifierId' in notification; + const userIfNeed = needsUser ? ( hint?.packedUsers != null ? hint.packedUsers.get(notification.notifierId) : this.userEntityService.pack(notification.notifierId, { id: meId }) ) : undefined; + // if the user has been deleted, don't show this notification + if (needsUser && !userIfNeed) { + return null; + } if (notification.type === 'reaction:grouped') { - const reactions = await Promise.all(notification.reactions.map(async reaction => { + const reactions = (await Promise.all(notification.reactions.map(async reaction => { const user = hint?.packedUsers != null ? hint.packedUsers.get(reaction.userId)! : await this.userEntityService.pack(reaction.userId, { id: meId }); @@ -194,7 +222,12 @@ export class NotificationEntityService implements OnModuleInit { user, reaction: reaction.reaction, }; - })); + }))).filter(r => r.user); + // if all users have been deleted, don't show this notification + if (!reactions.length) { + return null; + } + return await awaitAll({ id: notification.id, createdAt: new Date(notification.createdAt).toISOString(), @@ -203,14 +236,19 @@ export class NotificationEntityService implements OnModuleInit { reactions, }); } else if (notification.type === 'renote:grouped') { - const users = await Promise.all(notification.userIds.map(userId => { + const users = (await Promise.all(notification.userIds.map(userId => { const packedUser = hint?.packedUsers != null ? hint.packedUsers.get(userId) : null; if (packedUser) { return packedUser; } return this.userEntityService.pack(userId, { id: meId }); - })); + }))).filter(u => u); + // if all users have been deleted, don't show this notification + if (!users.length) { + return null; + } + return await awaitAll({ id: notification.id, createdAt: new Date(notification.createdAt).toISOString(), @@ -220,7 +258,12 @@ export class NotificationEntityService implements OnModuleInit { }); } - const role = notification.type === 'roleAssigned' ? await this.roleEntityService.pack(notification.roleId) : undefined; + const needsRole = notification.type === 'roleAssigned'; + const role = needsRole ? await this.roleEntityService.pack(notification.roleId) : undefined; + // if the role has been deleted, don't show this notification + if (needsRole && !role) { + return null; + } return await awaitAll({ id: notification.id,