From 91762bb8cad7b390b5b1004fa99dadc7d05496ab Mon Sep 17 00:00:00 2001 From: Namekuji Date: Sat, 2 Sep 2023 06:04:50 -0400 Subject: [PATCH] delete associated notes on account deletion --- .../src/queue/processors/db/delete-account.ts | 133 +++++++++++++++--- 1 file changed, 112 insertions(+), 21 deletions(-) diff --git a/packages/backend/src/queue/processors/db/delete-account.ts b/packages/backend/src/queue/processors/db/delete-account.ts index c8d47e7f6d..1ce1302559 100644 --- a/packages/backend/src/queue/processors/db/delete-account.ts +++ b/packages/backend/src/queue/processors/db/delete-account.ts @@ -1,6 +1,20 @@ import type Bull from "bull"; import { queueLogger } from "../../logger.js"; -import { DriveFiles, Notes, UserProfiles, Users } from "@/models/index.js"; +import { + ChannelNotePinings, + ClipNotes, + DriveFiles, + MutedNotes, + NoteFavorites, + NoteUnreads, + NoteWatchings, + Notes, + PromoNotes, + PromoReads, + UserNotePinings, + UserProfiles, + Users, +} from "@/models/index.js"; import type { DbUserDeleteJobData } from "@/queue/types.js"; import type { Note } from "@/models/entities/note.js"; import type { DriveFile } from "@/models/entities/drive-file.js"; @@ -8,8 +22,14 @@ import { MoreThan } from "typeorm"; import { deleteFileSync } from "@/services/drive/delete-file.js"; import { sendEmail } from "@/services/send-email.js"; import meilisearch from "@/db/meilisearch.js"; -import { acctToUserIdCache, userByIdCache, userDenormalizedCache } from "@/services/user-cache.js"; -import config from "@/config/index.js"; +import { userByIdCache, userDenormalizedCache } from "@/services/user-cache.js"; +import { + parseHomeTimeline, + parseScyllaNote, + prepared, + scyllaClient, +} from "@/db/scylla.js"; +import type { Client } from "cassandra-driver"; const logger = queueLogger.createSubLogger("delete-account"); @@ -25,30 +45,101 @@ export async function deleteAccount( // Delete notes let cursor: Note["id"] | null = null; - while (true) { - const notes = (await Notes.find({ - where: { - userId: user.id, - ...(cursor ? { id: MoreThan(cursor) } : {}), + if (scyllaClient) { + scyllaClient.eachRow( + prepared.note.select.byUserId, + [user.id], + { prepare: true }, + (_, row) => { + const client = scyllaClient as Client; + const note = parseScyllaNote(row); + const noteDeleteParams = [ + note.createdAt, + note.createdAt, + note.userId, + note.userHost ?? "local", + note.visibility, + ] as [Date, Date, string, string, string]; + client.execute(prepared.note.delete, noteDeleteParams, { + prepare: true, + }); + client.eachRow( + prepared.homeTimeline.select.byId, + [note.id], + { + prepare: true, + }, + (_, row) => { + const timeline = parseHomeTimeline(row); + client.execute( + prepared.homeTimeline.delete, + [ + timeline.feedUserId, + timeline.createdAtDate, + timeline.createdAt, + timeline.userId, + ], + { prepare: true }, + ); + }, + ); + if (meilisearch) { + meilisearch.deleteNotes([note]); + } + ChannelNotePinings.delete({ + noteId: note.id, + }); + ClipNotes.delete({ + noteId: note.id, + }); + MutedNotes.delete({ + noteId: note.id, + }); + NoteFavorites.delete({ + noteId: note.id, + }); + NoteUnreads.delete({ + noteId: note.id, + }); + NoteWatchings.delete({ + noteId: note.id, + }); + PromoNotes.delete({ + noteId: note.id, + }); + PromoReads.delete({ + noteId: note.id, + }); + UserNotePinings.delete({ + noteId: note.id, + }); }, - take: 10, - order: { - id: 1, - }, - })) as Note[]; + ); + } else { + while (true) { + const notes = (await Notes.find({ + where: { + userId: user.id, + ...(cursor ? { id: MoreThan(cursor) } : {}), + }, + take: 10, + order: { + id: 1, + }, + })) as Note[]; - if (notes.length === 0) { - break; - } + if (notes.length === 0) { + break; + } - cursor = notes[notes.length - 1].id; + cursor = notes[notes.length - 1].id; - await Notes.delete(notes.map((note) => note.id)); - if (meilisearch) { - await meilisearch.deleteNotes(notes); + await Notes.delete(notes.map((note) => note.id)); + if (meilisearch) { + await meilisearch.deleteNotes(notes); + } } } - logger.succ("All of notes deleted"); }