From acf1b661a22657704927676b101d88176d950123 Mon Sep 17 00:00:00 2001 From: dakkar Date: Mon, 24 Feb 2025 12:09:55 +0000 Subject: [PATCH 1/3] delete scheduled notes when deleting account - fixes #936 --- .../DeleteAccountProcessorService.ts | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/queue/processors/DeleteAccountProcessorService.ts b/packages/backend/src/queue/processors/DeleteAccountProcessorService.ts index 66bed72f18..0c70829132 100644 --- a/packages/backend/src/queue/processors/DeleteAccountProcessorService.ts +++ b/packages/backend/src/queue/processors/DeleteAccountProcessorService.ts @@ -6,7 +6,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { MoreThan } from 'typeorm'; import { DI } from '@/di-symbols.js'; -import type { DriveFilesRepository, NoteReactionsRepository, NotesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; +import type { DriveFilesRepository, NoteReactionsRepository, NotesRepository, UserProfilesRepository, UsersRepository, NoteScheduleRepository, MiNoteSchedule } from '@/models/_.js'; import type Logger from '@/logger.js'; import { DriveService } from '@/core/DriveService.js'; import type { MiDriveFile } from '@/models/DriveFile.js'; @@ -20,6 +20,7 @@ import { ReactionService } from '@/core/ReactionService.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; import type * as Bull from 'bullmq'; import type { DbUserDeleteJobData } from '../types.js'; +import { QueueService } from '@/core/QueueService.js'; @Injectable() export class DeleteAccountProcessorService { @@ -41,6 +42,10 @@ export class DeleteAccountProcessorService { @Inject(DI.noteReactionsRepository) private noteReactionsRepository: NoteReactionsRepository, + @Inject(DI.noteScheduleRepository) + private noteScheduleRepository: NoteScheduleRepository, + + private queueService: QueueService, private driveService: DriveService, private emailService: EmailService, private queueLoggerService: QueueLoggerService, @@ -60,6 +65,22 @@ export class DeleteAccountProcessorService { return; } + { // Delete scheduled notes + const scheduledNotes = await this.noteScheduleRepository.findBy({ + userId: user.id, + }) as MiNoteSchedule[]; + + for (const note of scheduledNotes) { + await this.queueService.ScheduleNotePostQueue.remove(`schedNote:${note.id}`); + } + + await this.noteScheduleRepository.delete({ + userId: user.id, + }); + + this.logger.succ('All scheduled notes deleted'); + } + { // Delete notes let cursor: MiNote['id'] | null = null; From 687cb5b168e3e91177ea700166286c8a39d89c44 Mon Sep 17 00:00:00 2001 From: dakkar Date: Mon, 24 Feb 2025 13:07:23 +0000 Subject: [PATCH 2/3] handle scheduled notes when migrating account - fixes #931 I'm not sure we want the "change ownership of notes if dst is local", though --- locales/index.d.ts | 1 + .../backend/src/core/AccountMoveService.ts | 32 ++++++++++++++++++- sharkey-locales/en-US.yml | 2 +- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index bf49869bf8..cec098e770 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -5904,6 +5904,7 @@ export interface Locale extends ILocale { *  ・Followers from this account will automatically be migrated to the new account *  ・This account will unfollow all users it is currently following *  ・You will be unable to create new notes etc. on this account + *  ・Scheduled notes will be migrated to the new account if it's on this same instance * * While migration of followers is automatic, you must manually prepare some steps to migrate the list of users you are following. To do so, carry out a follows export that you will later import on the new account in the settings menu. The same procedure applies to your lists as well as your muted and blocked users. * diff --git a/packages/backend/src/core/AccountMoveService.ts b/packages/backend/src/core/AccountMoveService.ts index 24d11f29ff..0eb8a76bff 100644 --- a/packages/backend/src/core/AccountMoveService.ts +++ b/packages/backend/src/core/AccountMoveService.ts @@ -9,7 +9,7 @@ import { IsNull, In, MoreThan, Not } from 'typeorm'; import { bindThis } from '@/decorators.js'; import { DI } from '@/di-symbols.js'; import type { MiLocalUser, MiRemoteUser, MiUser } from '@/models/User.js'; -import type { BlockingsRepository, FollowingsRepository, InstancesRepository, MiMeta, MutingsRepository, UserListMembershipsRepository, UsersRepository } from '@/models/_.js'; +import type { BlockingsRepository, FollowingsRepository, InstancesRepository, MiMeta, MutingsRepository, UserListMembershipsRepository, UsersRepository, NoteScheduleRepository, MiNoteSchedule } from '@/models/_.js'; import type { RelationshipJobData, ThinUser } from '@/queue/types.js'; import { IdService } from '@/core/IdService.js'; @@ -49,6 +49,9 @@ export class AccountMoveService { @Inject(DI.instancesRepository) private instancesRepository: InstancesRepository, + @Inject(DI.noteScheduleRepository) + private noteScheduleRepository: NoteScheduleRepository, + private userEntityService: UserEntityService, private idService: IdService, private apPersonService: ApPersonService, @@ -119,6 +122,7 @@ export class AccountMoveService { await Promise.all([ this.copyBlocking(src, dst), this.copyMutings(src, dst), + this.updateScheduledNotes(src, dst), this.updateLists(src, dst), ]); } catch { @@ -201,6 +205,32 @@ export class AccountMoveService { await this.mutingsRepository.insert(arrayToInsert); } + @bindThis + public async updateScheduledNotes(src: ThinUser, dst: MiUser): Promise { + // we're moving to a different local user: change scheduled notes' ownership + if (dst.host === null) { + await this.noteScheduleRepository.update( + { userId: src.id }, + { userId: dst.id }, + ); + + return; + } + + // we're moving to a remote user: delete scheduled notes + const scheduledNotes = await this.noteScheduleRepository.findBy({ + userId: src.id, + }) as MiNoteSchedule[]; + + for (const note of scheduledNotes) { + await this.queueService.ScheduleNotePostQueue.remove(`schedNote:${note.id}`); + } + + await this.noteScheduleRepository.delete({ + userId: src.id, + }); + } + /** * Update lists while moving accounts. * - No removal of the old account from the lists diff --git a/sharkey-locales/en-US.yml b/sharkey-locales/en-US.yml index 6e49b0ba37..157ab4db92 100644 --- a/sharkey-locales/en-US.yml +++ b/sharkey-locales/en-US.yml @@ -206,7 +206,7 @@ _serverSettings: inquiryUrl: "Contact URL" inquiryUrlDescription: "Specify the URL of a web page that contains a contact form or the instance operators' contact information." _accountMigration: - moveAccountDescription: "This will migrate your account to a different one.\n ・Followers from this account will automatically be migrated to the new account\n ・This account will unfollow all users it is currently following\n ・You will be unable to create new notes etc. on this account\n\nWhile migration of followers is automatic, you must manually prepare some steps to migrate the list of users you are following. To do so, carry out a follows export that you will later import on the new account in the settings menu. The same procedure applies to your lists as well as your muted and blocked users.\n\n(This explanation applies to Sharkey v13.12.0 and later. Other ActivityPub software, such as Mastodon, might function differently.)" + moveAccountDescription: "This will migrate your account to a different one.\n ・Followers from this account will automatically be migrated to the new account\n ・This account will unfollow all users it is currently following\n ・You will be unable to create new notes etc. on this account\n ・Scheduled notes will be migrated to the new account if it's on this same instance\n\nWhile migration of followers is automatic, you must manually prepare some steps to migrate the list of users you are following. To do so, carry out a follows export that you will later import on the new account in the settings menu. The same procedure applies to your lists as well as your muted and blocked users.\n\n(This explanation applies to Sharkey v13.12.0 and later. Other ActivityPub software, such as Mastodon, might function differently.)" _achievements: _types: _notes1: From 0fba8dc26ac39d82b5add1756e555070bf18eb52 Mon Sep 17 00:00:00 2001 From: dakkar Date: Sun, 2 Mar 2025 16:51:54 +0000 Subject: [PATCH 3/3] don't move scheduled notes to new account when migrating @Julia confirms it would confuse people more than it helps --- locales/index.d.ts | 1 - packages/backend/src/core/AccountMoveService.ts | 15 ++------------- sharkey-locales/en-US.yml | 2 +- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index cec098e770..bf49869bf8 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -5904,7 +5904,6 @@ export interface Locale extends ILocale { *  ・Followers from this account will automatically be migrated to the new account *  ・This account will unfollow all users it is currently following *  ・You will be unable to create new notes etc. on this account - *  ・Scheduled notes will be migrated to the new account if it's on this same instance * * While migration of followers is automatic, you must manually prepare some steps to migrate the list of users you are following. To do so, carry out a follows export that you will later import on the new account in the settings menu. The same procedure applies to your lists as well as your muted and blocked users. * diff --git a/packages/backend/src/core/AccountMoveService.ts b/packages/backend/src/core/AccountMoveService.ts index 0eb8a76bff..e24fefb4b5 100644 --- a/packages/backend/src/core/AccountMoveService.ts +++ b/packages/backend/src/core/AccountMoveService.ts @@ -122,7 +122,7 @@ export class AccountMoveService { await Promise.all([ this.copyBlocking(src, dst), this.copyMutings(src, dst), - this.updateScheduledNotes(src, dst), + this.deleteScheduledNotes(src), this.updateLists(src, dst), ]); } catch { @@ -206,18 +206,7 @@ export class AccountMoveService { } @bindThis - public async updateScheduledNotes(src: ThinUser, dst: MiUser): Promise { - // we're moving to a different local user: change scheduled notes' ownership - if (dst.host === null) { - await this.noteScheduleRepository.update( - { userId: src.id }, - { userId: dst.id }, - ); - - return; - } - - // we're moving to a remote user: delete scheduled notes + public async deleteScheduledNotes(src: ThinUser): Promise { const scheduledNotes = await this.noteScheduleRepository.findBy({ userId: src.id, }) as MiNoteSchedule[]; diff --git a/sharkey-locales/en-US.yml b/sharkey-locales/en-US.yml index 157ab4db92..6e49b0ba37 100644 --- a/sharkey-locales/en-US.yml +++ b/sharkey-locales/en-US.yml @@ -206,7 +206,7 @@ _serverSettings: inquiryUrl: "Contact URL" inquiryUrlDescription: "Specify the URL of a web page that contains a contact form or the instance operators' contact information." _accountMigration: - moveAccountDescription: "This will migrate your account to a different one.\n ・Followers from this account will automatically be migrated to the new account\n ・This account will unfollow all users it is currently following\n ・You will be unable to create new notes etc. on this account\n ・Scheduled notes will be migrated to the new account if it's on this same instance\n\nWhile migration of followers is automatic, you must manually prepare some steps to migrate the list of users you are following. To do so, carry out a follows export that you will later import on the new account in the settings menu. The same procedure applies to your lists as well as your muted and blocked users.\n\n(This explanation applies to Sharkey v13.12.0 and later. Other ActivityPub software, such as Mastodon, might function differently.)" + moveAccountDescription: "This will migrate your account to a different one.\n ・Followers from this account will automatically be migrated to the new account\n ・This account will unfollow all users it is currently following\n ・You will be unable to create new notes etc. on this account\n\nWhile migration of followers is automatic, you must manually prepare some steps to migrate the list of users you are following. To do so, carry out a follows export that you will later import on the new account in the settings menu. The same procedure applies to your lists as well as your muted and blocked users.\n\n(This explanation applies to Sharkey v13.12.0 and later. Other ActivityPub software, such as Mastodon, might function differently.)" _achievements: _types: _notes1: