From d1df2ad132f77db8638e5cbef1da92422667e499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Klocek?= Date: Mon, 30 Sep 2024 11:04:55 +0200 Subject: [PATCH] [keyserver] Remove holders in thread deleters Summary: Address [[ https://linear.app/comm/issue/ENG-9354/delete-holders-when-deleting-thread | ENG-9354 ]]. Before calling `DELETE FROM uploads`, we need to select the `extra` column first and remove blob holders if present in the column JSON. Depends on D13512 Test Plan: Enabled blob-hosted avatars for thin threads. Created a thread and set image avatar. Then deleted the thread. Looked into blob service logs to see that a blob was uploaded, then its holder was removed Reviewers: tomek, ashoat Reviewed By: ashoat Differential Revision: https://phab.comm.dev/D13513 --- keyserver/src/deleters/thread-deleters.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/keyserver/src/deleters/thread-deleters.js b/keyserver/src/deleters/thread-deleters.js index d1e8db6197..5d5a5f3a5c 100644 --- a/keyserver/src/deleters/thread-deleters.js +++ b/keyserver/src/deleters/thread-deleters.js @@ -18,7 +18,9 @@ import { import { fetchThreadPermissionsBlob } from '../fetchers/thread-permission-fetchers.js'; import { fetchUpdateInfoForThreadDeletion } from '../fetchers/update-fetchers.js'; import { rescindPushNotifs } from '../push/rescind.js'; +import { removeBlobHolders } from '../services/blob.js'; import type { Viewer } from '../session/viewer.js'; +import { blobHoldersFromUploadRows } from '../uploads/media-utils.js'; type DeleteThreadOptions = Partial<{ +ignorePermissions: boolean, @@ -60,6 +62,8 @@ async function deleteThread( // thread-permission-updaters should be used for descendant threads. const threadIDs = await fetchContainedThreadIDs(threadID); + await fetchAndDeleteThreadBlobHolders(threadIDs); + const [{ threadInfos: serverThreadInfos }] = await Promise.all([ fetchServerThreadInfos({ threadIDs: new Set(threadIDs) }), rescindPushNotifs( @@ -89,6 +93,19 @@ async function deleteThread( return { updatesResult: { newUpdates: viewerUpdates } }; } +async function fetchAndDeleteThreadBlobHolders( + threadIDs: $ReadOnlyArray, +): Promise { + const query = SQL` + SELECT extra + FROM uploads + WHERE container IN (${threadIDs}) + `; + const [rows] = await dbQuery(query); + const blobHolders = blobHoldersFromUploadRows(rows); + await removeBlobHolders(blobHolders); +} + function deleteThreadsFromDB( threadIDs: $ReadOnlyArray, ): Promise { @@ -144,7 +161,9 @@ async function deleteInaccessibleThreads(): Promise { if (threadIDs.size === 0) { return; } - await deleteThreadsFromDB([...threadIDs]); + const containerIDs = [...threadIDs]; + await fetchAndDeleteThreadBlobHolders(containerIDs); + await deleteThreadsFromDB(containerIDs); } export { deleteThread, deleteInaccessibleThreads };