From 88ca0c14efb1cf71204135c3ee7b9a9189ff5910 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Sat, 9 Mar 2024 14:50:17 -0800 Subject: [PATCH 1/4] Add noteAutoDelete form to privacy page --- locales/en-US.yml | 1 + .../src/pages/settings/privacy.autodelete.vue | 66 +++++++++++++++++++ .../frontend/src/pages/settings/privacy.vue | 10 +++ 3 files changed, 77 insertions(+) create mode 100644 packages/frontend/src/pages/settings/privacy.autodelete.vue diff --git a/locales/en-US.yml b/locales/en-US.yml index dfe066af99..1583286ada 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -99,6 +99,7 @@ serverIsDead: "This server is not responding. Please wait for a while and try ag youShouldUpgradeClient: "To view this page, please refresh to update your client." enterListName: "Enter a name for the list" privacy: "Privacy" +autoDeleteNotes: "Self-destructing notes" makeFollowManuallyApprove: "Follow requests require approval" defaultNoteVisibility: "Default visibility" follow: "Follow" diff --git a/packages/frontend/src/pages/settings/privacy.autodelete.vue b/packages/frontend/src/pages/settings/privacy.autodelete.vue new file mode 100644 index 0000000000..ebe58c5de8 --- /dev/null +++ b/packages/frontend/src/pages/settings/privacy.autodelete.vue @@ -0,0 +1,66 @@ + + + diff --git a/packages/frontend/src/pages/settings/privacy.vue b/packages/frontend/src/pages/settings/privacy.vue index 86cf5ab241..36f3319871 100644 --- a/packages/frontend/src/pages/settings/privacy.vue +++ b/packages/frontend/src/pages/settings/privacy.vue @@ -68,6 +68,15 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.keepCw }} + + +
+ + + + +
+
@@ -82,6 +91,7 @@ import { defaultStore } from '@/store.js'; import { i18n } from '@/i18n.js'; import { signinRequired } from '@/account.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; +import XAutoDelete from './privacy.autodelete.vue'; const $i = signinRequired(); From 87c6a36823c0c9405431a9945931284523eab793 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Tue, 12 Mar 2024 17:12:30 -0700 Subject: [PATCH 2/4] 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 103813acf2..a29e6412a7 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 d7316e19e3..593e1d4b2f 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 76b6d7fb05..d8f39dd5c4 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 0000000000..818250b36e --- /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'); + } +} From 949907beb3a326916157a578cc79b9a53e85ffd8 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Tue, 12 Mar 2024 17:58:03 -0700 Subject: [PATCH 3/4] Fix indentation --- .../queue/processors/AutoDeleteNotesProcessorService.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/queue/processors/AutoDeleteNotesProcessorService.ts b/packages/backend/src/queue/processors/AutoDeleteNotesProcessorService.ts index 818250b36e..24a3fba1a0 100644 --- a/packages/backend/src/queue/processors/AutoDeleteNotesProcessorService.ts +++ b/packages/backend/src/queue/processors/AutoDeleteNotesProcessorService.ts @@ -60,11 +60,11 @@ export class AutoDeleteNotesProcessorService { .getMany(); for (const note of notes) { - if (pinnedNoteIds.includes(note.id)) { - continue; - } + if (pinnedNoteIds.includes(note.id)) { + continue; + } - await this.noteDeleteService.delete(user, note); + await this.noteDeleteService.delete(user, note); } } From bef78535c940a2e9ed2d9f7dfac39fc4a956c9e4 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Tue, 12 Mar 2024 18:21:15 -0700 Subject: [PATCH 4/4] saving work --- .../src/queue/processors/AutoDeleteNotesProcessorService.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/backend/src/queue/processors/AutoDeleteNotesProcessorService.ts b/packages/backend/src/queue/processors/AutoDeleteNotesProcessorService.ts index 24a3fba1a0..b44676e665 100644 --- a/packages/backend/src/queue/processors/AutoDeleteNotesProcessorService.ts +++ b/packages/backend/src/queue/processors/AutoDeleteNotesProcessorService.ts @@ -57,6 +57,7 @@ export class AutoDeleteNotesProcessorService { const notes = await this.notesRepository.createQueryBuilder('note') .where('note."userId" = :userId', { userId: user.user.id }) .andWhere('note.id < :untilId', { untilId }) + .andWhere('note.id NOT IN (SELECT "noteId" FROM note_favorite WHERE "userId" = :userId)'); .getMany(); for (const note of notes) {