diff options
| author | Marie <github@yuugi.dev> | 2024-11-03 17:59:50 +0100 |
|---|---|---|
| committer | Marie <github@yuugi.dev> | 2024-12-09 05:32:51 +0100 |
| commit | fc9d777dc3161b40c5c62bb65cb03e2c7d8f4380 (patch) | |
| tree | af42af2f205816cb3b833747d2df35935c5f9c92 /packages/backend | |
| parent | chore: remove leftover log (diff) | |
| download | sharkey-fc9d777dc3161b40c5c62bb65cb03e2c7d8f4380.tar.gz sharkey-fc9d777dc3161b40c5c62bb65cb03e2c7d8f4380.tar.bz2 sharkey-fc9d777dc3161b40c5c62bb65cb03e2c7d8f4380.zip | |
upd: add notification for failures, add reasons for failure, apply suggestions
Diffstat (limited to 'packages/backend')
7 files changed, 72 insertions, 19 deletions
diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index bbaf0cb7c8..27b8231854 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -20,7 +20,7 @@ import type { OnModuleInit } from '@nestjs/common'; import type { UserEntityService } from './UserEntityService.js'; import type { NoteEntityService } from './NoteEntityService.js'; -const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'renote:grouped', 'quote', 'reaction', 'reaction:grouped', 'pollEnded', 'edited'] as (typeof groupedNotificationTypes[number])[]); +const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'renote:grouped', 'quote', 'reaction', 'reaction:grouped', 'pollEnded', 'edited', 'scheduledNoteFailed'] as (typeof groupedNotificationTypes[number])[]); @Injectable() export class NotificationEntityService implements OnModuleInit { @@ -169,6 +169,9 @@ export class NotificationEntityService implements OnModuleInit { exportedEntity: notification.exportedEntity, fileId: notification.fileId, } : {}), + ...(notification.type === 'scheduledNoteFailed' ? { + reason: notification.reason, + } : {}), ...(notification.type === 'app' ? { body: notification.customBody, header: notification.customHeader, diff --git a/packages/backend/src/models/NoteSchedule.ts b/packages/backend/src/models/NoteSchedule.ts index 97ffe32ffa..dde0af6ad7 100644 --- a/packages/backend/src/models/NoteSchedule.ts +++ b/packages/backend/src/models/NoteSchedule.ts @@ -18,8 +18,6 @@ type MinimumUser = { }; export type MiScheduleNoteType={ - /** Date.toISOString() */ - createdAt: string; visibility: 'public' | 'home' | 'followers' | 'specified'; visibleUsers: MinimumUser[]; channel?: MiChannel['id']; diff --git a/packages/backend/src/models/Notification.ts b/packages/backend/src/models/Notification.ts index c4f046c565..5003e02d96 100644 --- a/packages/backend/src/models/Notification.ts +++ b/packages/backend/src/models/Notification.ts @@ -122,6 +122,11 @@ export type MiNotification = { createdAt: string; notifierId: MiUser['id']; noteId: MiNote['id']; +} | { + type: 'scheduledNoteFailed'; + id: string; + createdAt: string; + reason: string; }; export type MiGroupedNotification = MiNotification | { diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts index 990e8957cf..69bd9531ec 100644 --- a/packages/backend/src/models/json-schema/notification.ts +++ b/packages/backend/src/models/json-schema/notification.ts @@ -376,6 +376,20 @@ export const packedNotificationSchema = { type: { type: 'string', optional: false, nullable: false, + enum: ['scheduledNoteFailed'], + }, + reason: { + type: 'string', + optional: false, nullable: false, + }, + }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, enum: ['reaction:grouped'], }, note: { diff --git a/packages/backend/src/queue/processors/ScheduleNotePostProcessorService.ts b/packages/backend/src/queue/processors/ScheduleNotePostProcessorService.ts index 62d527953d..59e23b865e 100644 --- a/packages/backend/src/queue/processors/ScheduleNotePostProcessorService.ts +++ b/packages/backend/src/queue/processors/ScheduleNotePostProcessorService.ts @@ -9,6 +9,7 @@ import { bindThis } from '@/decorators.js'; import { NoteCreateService } from '@/core/NoteCreateService.js'; import type { ChannelsRepository, DriveFilesRepository, MiDriveFile, NoteScheduleRepository, NotesRepository, UsersRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; +import { NotificationService } from '@/core/NotificationService.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; import type * as Bull from 'bullmq'; import type { ScheduleNotePostJobData } from '../types.js'; @@ -32,6 +33,7 @@ export class ScheduleNotePostProcessorService { private noteCreateService: NoteCreateService, private queueLoggerService: QueueLoggerService, + private notificationService: NotificationService, ) { this.logger = this.queueLoggerService.logger.createSubLogger('schedule-note-post'); } @@ -50,8 +52,9 @@ export class ScheduleNotePostProcessorService { const renote = note.reply ? await this.notesRepository.findOneBy({ id: note.renote }) : undefined; const channel = note.channel ? await this.channelsRepository.findOneBy({ id: note.channel, isArchived: false }) : undefined; let files: MiDriveFile[] = []; - const fileIds = note.files ?? null; - if (fileIds != null && fileIds.length > 0 && me) { + const fileIds = note.files; + + if (fileIds.length > 0 && me) { files = await this.driveFilesRepository.createQueryBuilder('file') .where('file.userId = :userId AND file.id IN (:...fileIds)', { userId: me.id, @@ -61,22 +64,52 @@ export class ScheduleNotePostProcessorService { .setParameters({ fileIds }) .getMany(); } - if ( - !data.userId || - !me || - (note.reply && !reply) || - (note.renote && !renote) || - (note.channel && !channel) || - (note.files.length !== files.length) - ) { - //キューに積んだときは有った物が消滅してたら予約投稿をキャンセルする - this.logger.warn('cancel schedule note'); + + if (!data.userId || !me) { + this.logger.warn('Schedule Note Failed Reason: User Not Found'); + await this.noteScheduleRepository.remove(data); + return; + } + + if (note.files.length !== files.length) { + this.logger.warn('Schedule Note Failed Reason: files are missing in the user\'s drive'); + this.notificationService.createNotification(me.id, 'scheduledNoteFailed', { + reason: 'Some attached files on your scheduled note no longer exist', + }); + await this.noteScheduleRepository.remove(data); + return; + } + + if (note.reply && !reply) { + this.logger.warn('Schedule Note Failed Reason: parent note to reply does not exist'); + this.notificationService.createNotification(me.id, 'scheduledNoteFailed', { + reason: 'Replied to note on your scheduled note no longer exists', + }); await this.noteScheduleRepository.remove(data); return; } + + if (note.renote && !renote) { + this.logger.warn('Schedule Note Failed Reason: attached quote note no longer exists'); + this.notificationService.createNotification(me.id, 'scheduledNoteFailed', { + reason: 'A quoted note from one of your scheduled notes no longer exists', + }); + await this.noteScheduleRepository.remove(data); + return; + } + + if (note.channel && !channel) { + this.logger.warn('Schedule Note Failed Reason: Channel does not exist'); + this.notificationService.createNotification(me.id, 'scheduledNoteFailed', { + reason: 'An attached channel on your scheduled note no longer exists', + }); + await this.noteScheduleRepository.remove(data); + return; + } + await this.noteCreateService.create(me, { ...note, - createdAt: new Date(note.createdAt), //typeORMのjsonbで何故かstringにされるから戻す + createdAt: new Date(), files, poll: note.poll ? { choices: note.poll.choices, diff --git a/packages/backend/src/server/api/endpoints/notes/schedule/create.ts b/packages/backend/src/server/api/endpoints/notes/schedule/create.ts index c22c29ae31..b8ae3f44a3 100644 --- a/packages/backend/src/server/api/endpoints/notes/schedule/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/schedule/create.ts @@ -292,7 +292,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- // Check blocking if (reply.userId !== me.id) { - const blockExist = await this.blockingsRepository.exist({ + const blockExist = await this.blockingsRepository.exists({ where: { blockerId: reply.userId, blockeeId: me.id, @@ -324,8 +324,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- } else { throw new ApiError(meta.errors.cannotCreateAlreadyExpiredSchedule); } - const note:MiScheduleNoteType = { - createdAt: new Date(ps.scheduleNote.scheduledAt!).toISOString(), + const note: MiScheduleNoteType = { files: files.map(f => f.id), poll: ps.poll ? { choices: ps.poll.choices, diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index 2aa4f279ea..7930129002 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -35,6 +35,7 @@ export const notificationTypes = [ 'roleAssigned', 'achievementEarned', 'exportCompleted', + 'scheduledNoteFailed', 'app', 'test', ] as const; |