From b3376501d7a36348aae98d7d360bbd000c7ee552 Mon Sep 17 00:00:00 2001 From: riku6460 <17585784+riku6460@users.noreply.github.com> Date: Sun, 18 Aug 2024 06:26:21 +0900 Subject: [PATCH] =?UTF-8?q?fix(backend):=20=E3=82=AF=E3=83=AA=E3=83=83?= =?UTF-8?q?=E3=83=97=E5=91=A8=E3=82=8A=E3=81=AE=E4=B8=8D=E5=85=B7=E5=90=88?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20(MisskeyIO#709)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/core/ClipService.ts | 18 ++++-- .../backend/src/core/UserSuspendService.ts | 64 ++++++++++++++++++- 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/packages/backend/src/core/ClipService.ts b/packages/backend/src/core/ClipService.ts index b69ca8362..df3de63e8 100644 --- a/packages/backend/src/core/ClipService.ts +++ b/packages/backend/src/core/ClipService.ts @@ -134,6 +134,10 @@ export class ClipService { throw new ClipService.NoSuchClipError(); } + if (await this.clipNotesRepository.existsBy({ clipId, noteId })) { + throw new ClipService.AlreadyAddedError(); + } + const policies = await this.roleService.getUserPolicies(me.id); const currentClipCount = await this.clipsRepository.countBy({ @@ -143,6 +147,13 @@ export class ClipService { throw new ClipService.ClipLimitExceededError(); } + const currentNoteCount = await this.clipNotesRepository.countBy({ + clipId: clip.id, + }); + if (currentNoteCount >= policies.noteEachClipsLimit) { + throw new ClipService.TooManyClipNotesError(); + } + const currentNoteCounts = await this.clipNotesRepository .createQueryBuilder('cn') .select('COUNT(*)') @@ -154,13 +165,6 @@ export class ClipService { throw new ClipService.ClipNotesLimitExceededError(); } - const currentNoteCount = await this.clipNotesRepository.countBy({ - clipId: clip.id, - }); - if (currentNoteCount >= policies.noteEachClipsLimit) { - throw new ClipService.TooManyClipNotesError(); - } - try { await this.clipNotesRepository.insert({ id: this.idService.gen(), diff --git a/packages/backend/src/core/UserSuspendService.ts b/packages/backend/src/core/UserSuspendService.ts index f9cf38684..677db309d 100644 --- a/packages/backend/src/core/UserSuspendService.ts +++ b/packages/backend/src/core/UserSuspendService.ts @@ -9,7 +9,16 @@ import { bindThis } from '@/decorators.js'; import { DI } from '@/di-symbols.js'; import type Logger from '@/logger.js'; import type { MiUser } from '@/models/User.js'; -import type { FollowingsRepository, FollowRequestsRepository } from '@/models/_.js'; +import type { + AntennasRepository, + ClipNotesRepository, + ClipsRepository, + FollowingsRepository, + FollowRequestsRepository, + UserListMembershipsRepository, + UserListsRepository, + WebhooksRepository, +} from '@/models/_.js'; import { QueueService } from '@/core/QueueService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; @@ -30,6 +39,24 @@ export class UserSuspendService { @Inject(DI.followRequestsRepository) private followRequestsRepository: FollowRequestsRepository, + @Inject(DI.antennasRepository) + private antennasRepository: AntennasRepository, + + @Inject(DI.webhooksRepository) + private webhooksRepository: WebhooksRepository, + + @Inject(DI.userListsRepository) + private userListsRepository: UserListsRepository, + + @Inject(DI.clipsRepository) + private clipsRepository: ClipsRepository, + + @Inject(DI.clipNotesRepository) + private clipNotesRepository: ClipNotesRepository, + + @Inject(DI.userListMembershipsRepository) + private userListMembershipsRepository: UserListMembershipsRepository, + private queueService: QueueService, private globalEventService: GlobalEventService, private apRendererService: ApRendererService, @@ -45,10 +72,41 @@ export class UserSuspendService { this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: true }); - await Promise.all([ + const promises: Promise[] = []; + + let cursor = ''; + while (true) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition, no-constant-condition + const clipNotes = await this.clipNotesRepository.createQueryBuilder('c') + .select('c.id') + .innerJoin('c.note', 'n') + .where('n.userId = :userId', { userId: user.id }) + .andWhere('c.id > :cursor', { cursor }) + .orderBy('c.id', 'ASC') + .limit(500) + .getRawMany<{ id: string }>(); + + if (clipNotes.length === 0) break; + + cursor = clipNotes.at(-1)?.id ?? ''; + + promises.push(this.clipNotesRepository.createQueryBuilder() + .delete() + .where('id IN (:...ids)', { ids: clipNotes.map((clipNote) => clipNote.id) }) + .execute()); + } + + await Promise.allSettled([ this.followRequestsRepository.delete({ followeeId: user.id }), this.followRequestsRepository.delete({ followerId: user.id }), - ]).catch(() => null); + + this.antennasRepository.delete({ userId: user.id }), + this.webhooksRepository.delete({ userId: user.id }), + this.userListsRepository.delete({ userId: user.id }), + this.clipsRepository.delete({ userId: user.id }), + + ...promises, + this.userListMembershipsRepository.delete({ userId: user.id }), + ]); if (this.userEntityService.isLocalUser(user)) { // 知り得る全SharedInboxにDelete配信