From 87c6a36823c0c9405431a9945931284523eab793 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Tue, 12 Mar 2024 17:12:30 -0700 Subject: [PATCH] saving work --- packages/backend/src/core/QueueService.ts | 6 ++ .../backend/src/queue/QueueProcessorModule.ts | 2 + .../src/queue/QueueProcessorService.ts | 3 + .../AutoDeleteNotesProcessorService.ts | 73 +++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 packages/backend/src/queue/processors/AutoDeleteNotesProcessorService.ts diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index 103813acf..a29e6412a 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -69,6 +69,12 @@ export class QueueService { repeat: { pattern: '*/5 * * * *' }, removeOnComplete: true, }); + + this.systemQueue.add('autoDeleteNotes', { + }, { + repeat: { pattern: '*/1 * * * *' }, + removeOnComplete: true, + }); } @bindThis diff --git a/packages/backend/src/queue/QueueProcessorModule.ts b/packages/backend/src/queue/QueueProcessorModule.ts index d7316e19e..593e1d4b2 100644 --- a/packages/backend/src/queue/QueueProcessorModule.ts +++ b/packages/backend/src/queue/QueueProcessorModule.ts @@ -13,6 +13,7 @@ import { EndedPollNotificationProcessorService } from './processors/EndedPollNot import { InboxProcessorService } from './processors/InboxProcessorService.js'; import { WebhookDeliverProcessorService } from './processors/WebhookDeliverProcessorService.js'; import { CheckExpiredMutingsProcessorService } from './processors/CheckExpiredMutingsProcessorService.js'; +import { AutoDeleteNotesProcessorService } from './processors/AutoDeleteNotesProcessorService.js'; import { CleanChartsProcessorService } from './processors/CleanChartsProcessorService.js'; import { CleanProcessorService } from './processors/CleanProcessorService.js'; import { CleanRemoteFilesProcessorService } from './processors/CleanRemoteFilesProcessorService.js'; @@ -52,6 +53,7 @@ import { RelationshipProcessorService } from './processors/RelationshipProcessor ResyncChartsProcessorService, CleanChartsProcessorService, CheckExpiredMutingsProcessorService, + AutoDeleteNotesProcessorService, CleanProcessorService, DeleteDriveFilesProcessorService, ExportAccountDataProcessorService, diff --git a/packages/backend/src/queue/QueueProcessorService.ts b/packages/backend/src/queue/QueueProcessorService.ts index 76b6d7fb0..d8f39dd5c 100644 --- a/packages/backend/src/queue/QueueProcessorService.ts +++ b/packages/backend/src/queue/QueueProcessorService.ts @@ -38,6 +38,7 @@ import { TickChartsProcessorService } from './processors/TickChartsProcessorServ import { ResyncChartsProcessorService } from './processors/ResyncChartsProcessorService.js'; import { CleanChartsProcessorService } from './processors/CleanChartsProcessorService.js'; import { CheckExpiredMutingsProcessorService } from './processors/CheckExpiredMutingsProcessorService.js'; +import { AutoDeleteNotesProcessorService } from './processors/AutoDeleteNotesProcessorService.js'; import { CleanProcessorService } from './processors/CleanProcessorService.js'; import { AggregateRetentionProcessorService } from './processors/AggregateRetentionProcessorService.js'; import { QueueLoggerService } from './QueueLoggerService.js'; @@ -118,6 +119,7 @@ export class QueueProcessorService implements OnApplicationShutdown { private cleanChartsProcessorService: CleanChartsProcessorService, private aggregateRetentionProcessorService: AggregateRetentionProcessorService, private checkExpiredMutingsProcessorService: CheckExpiredMutingsProcessorService, + private autoDeleteNotesProcessorService: AutoDeleteNotesProcessorService, private cleanProcessorService: CleanProcessorService, ) { this.logger = this.queueLoggerService.logger; @@ -146,6 +148,7 @@ export class QueueProcessorService implements OnApplicationShutdown { case 'cleanCharts': return this.cleanChartsProcessorService.process(); case 'aggregateRetention': return this.aggregateRetentionProcessorService.process(); case 'checkExpiredMutings': return this.checkExpiredMutingsProcessorService.process(); + case 'autoDeleteNotes': return this.autoDeleteNotesProcessorService.process(); case 'clean': return this.cleanProcessorService.process(); default: throw new Error(`unrecognized job type ${job.name} for system`); } diff --git a/packages/backend/src/queue/processors/AutoDeleteNotesProcessorService.ts b/packages/backend/src/queue/processors/AutoDeleteNotesProcessorService.ts new file mode 100644 index 000000000..818250b36 --- /dev/null +++ b/packages/backend/src/queue/processors/AutoDeleteNotesProcessorService.ts @@ -0,0 +1,73 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { In } from 'typeorm'; +import { DI } from '@/di-symbols.js'; +import type { UserProfilesRepository, NotesRepository } from '@/models/_.js'; +import type Logger from '@/logger.js'; +import { bindThis } from '@/decorators.js'; +import { NoteDeleteService } from '@/core/NoteDeleteService.js'; +import { IdService } from '@/core/IdService.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; + +@Injectable() +export class AutoDeleteNotesProcessorService { + private logger: Logger; + + constructor( + @Inject(DI.userProfilesRepository) + private userProfilesRepository: UserProfilesRepository, + @Inject(DI.notesRepository) + private notesRepository: NotesRepository, + @Inject(DI.userNotePiningsRepository) + private userNotePiningsRepository: UserNotePiningsRepository, + + private idService: IdService, + private noteDeleteService: NoteDeleteService, + private queueLoggerService: QueueLoggerService, + ) { + this.logger = this.queueLoggerService.logger.createSubLogger('auto-delete-notes'); + } + + @bindThis + public async process(): Promise { + this.logger.info('Auto deleting old notes...'); + + const users = await this.userProfilesRepository.createQueryBuilder('user_profile') + .innerJoinAndSelect('user_profile.user', 'user') + .where('user.host IS NULL') + .andWhere('user_profile.autoDeleteNotes') + .getMany(); + + for (const user of users) { + this.logger.info(`Deleting old notes of user @${user.user.username} (id ${user.user.id})`); + const untilTime = Date.now() - (user.autoDeleteNotesMinutes * 1000 * 60); + const untilId = this.idService.gen(untilTime); + + const pins = await this.userNotePiningsRepository.createQueryBuilder('user_note_pining') + .where('"userId" = :userId', { userId: user.user.id }) + .getMany(); + + const pinnedNoteIds = pins.map((p) => p.noteId); + + const notes = await this.notesRepository.createQueryBuilder('note') + .where('note."userId" = :userId', { userId: user.user.id }) + .andWhere('note.id < :untilId', { untilId }) + .getMany(); + + for (const note of notes) { + if (pinnedNoteIds.includes(note.id)) { + continue; + } + + await this.noteDeleteService.delete(user, note); + } + } + + this.logger.succ('Done with note auto-delete'); + } +}