diff --git a/keyserver/src/deleters/thread-deleters.js b/keyserver/src/deleters/thread-deleters.js --- a/keyserver/src/deleters/thread-deleters.js +++ b/keyserver/src/deleters/thread-deleters.js @@ -18,7 +18,9 @@ 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 @@ // 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 @@ 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 @@ if (threadIDs.size === 0) { return; } - await deleteThreadsFromDB([...threadIDs]); + const containerIDs = [...threadIDs]; + await fetchAndDeleteThreadBlobHolders(containerIDs); + await deleteThreadsFromDB(containerIDs); } export { deleteThread, deleteInaccessibleThreads };