fixing sum' file logic flaws & device UI stuff stuff
This commit is contained in:
@@ -214,46 +214,59 @@ export class FileController {
|
||||
attributes: { "app.user.id": userId },
|
||||
fn: () =>
|
||||
this.fileRepo
|
||||
.listReferencedObjectKeysForUser(fctx, userId)
|
||||
.andThen((referencedKeys) => {
|
||||
const referencedSet = new Set(referencedKeys);
|
||||
return ResultAsync.combine([
|
||||
this.storageRepo.listObjectKeys(
|
||||
fctx,
|
||||
`uploads/${userId}/`,
|
||||
),
|
||||
this.storageRepo.listObjectKeys(
|
||||
fctx,
|
||||
`thumbnails/${userId}/`,
|
||||
),
|
||||
]).andThen(([uploadKeys, thumbnailKeys]) => {
|
||||
const existingStorageKeys = [
|
||||
...new Set([...uploadKeys, ...thumbnailKeys]),
|
||||
];
|
||||
.listMobileMediaReferencedObjectKeysForUser(fctx, userId)
|
||||
.andThen((referencedKeys) =>
|
||||
this.fileRepo
|
||||
.listMobileMediaDanglingFileIdsForUser(fctx, userId)
|
||||
.andThen((danglingFileIds) => {
|
||||
const referencedSet = new Set(referencedKeys);
|
||||
return ResultAsync.combine([
|
||||
this.storageRepo.listObjectKeys(
|
||||
fctx,
|
||||
`uploads/${userId}/`,
|
||||
),
|
||||
this.storageRepo.listObjectKeys(
|
||||
fctx,
|
||||
`thumbnails/${userId}/`,
|
||||
),
|
||||
]).andThen(([uploadKeys, thumbnailKeys]) => {
|
||||
const existingStorageKeys = [
|
||||
...new Set([...uploadKeys, ...thumbnailKeys]),
|
||||
];
|
||||
|
||||
const danglingKeys = existingStorageKeys.filter(
|
||||
(key) => !referencedSet.has(key),
|
||||
);
|
||||
const danglingKeys = existingStorageKeys.filter(
|
||||
(key) => !referencedSet.has(key),
|
||||
);
|
||||
|
||||
if (danglingKeys.length === 0) {
|
||||
return okAsync({
|
||||
scanned: existingStorageKeys.length,
|
||||
referenced: referencedKeys.length,
|
||||
dangling: 0,
|
||||
deleted: 0,
|
||||
const deleteStorage =
|
||||
danglingKeys.length > 0
|
||||
? this.storageRepo.deleteFiles(
|
||||
fctx,
|
||||
danglingKeys,
|
||||
)
|
||||
: okAsync(true);
|
||||
|
||||
return deleteStorage.andThen(() => {
|
||||
const deleteRows =
|
||||
danglingFileIds.length > 0
|
||||
? this.fileRepo.deleteFiles(
|
||||
fctx,
|
||||
danglingFileIds,
|
||||
userId,
|
||||
)
|
||||
: okAsync(true);
|
||||
|
||||
return deleteRows.map(() => ({
|
||||
scanned: existingStorageKeys.length,
|
||||
referenced: referencedKeys.length,
|
||||
dangling: danglingKeys.length,
|
||||
deleted: danglingKeys.length,
|
||||
deletedRows: danglingFileIds.length,
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return this.storageRepo
|
||||
.deleteFiles(fctx, danglingKeys)
|
||||
.map(() => ({
|
||||
scanned: existingStorageKeys.length,
|
||||
referenced: referencedKeys.length,
|
||||
dangling: danglingKeys.length,
|
||||
deleted: danglingKeys.length,
|
||||
}));
|
||||
});
|
||||
}),
|
||||
}),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
} from "@pkg/db";
|
||||
import { ResultAsync, errAsync, okAsync } from "neverthrow";
|
||||
import { FlowExecCtx } from "@core/flow.execution.context";
|
||||
import { file, fileAccess } from "@pkg/db/schema";
|
||||
import { file, fileAccess, mobileDevice, mobileMediaAsset } from "@pkg/db/schema";
|
||||
import { type Err } from "@pkg/result";
|
||||
import { fileErrors } from "./errors";
|
||||
import { logDomainEvent } from "@pkg/logger";
|
||||
@@ -381,7 +381,7 @@ export class FileRepository {
|
||||
});
|
||||
}
|
||||
|
||||
listReferencedObjectKeysForUser(
|
||||
listMobileMediaReferencedObjectKeysForUser(
|
||||
fctx: FlowExecCtx,
|
||||
userId: string,
|
||||
): ResultAsync<string[], Err> {
|
||||
@@ -391,8 +391,13 @@ export class FileRepository {
|
||||
objectKey: file.objectKey,
|
||||
metadata: file.metadata,
|
||||
})
|
||||
.from(file)
|
||||
.where(eq(file.userId, userId)),
|
||||
.from(mobileMediaAsset)
|
||||
.innerJoin(file, eq(mobileMediaAsset.fileId, file.id))
|
||||
.innerJoin(
|
||||
mobileDevice,
|
||||
eq(mobileMediaAsset.deviceId, mobileDevice.id),
|
||||
)
|
||||
.where(eq(mobileDevice.ownerUserId, userId)),
|
||||
(error) =>
|
||||
fileErrors.getFilesFailed(
|
||||
fctx,
|
||||
@@ -422,6 +427,35 @@ export class FileRepository {
|
||||
});
|
||||
}
|
||||
|
||||
listMobileMediaDanglingFileIdsForUser(
|
||||
fctx: FlowExecCtx,
|
||||
userId: string,
|
||||
): ResultAsync<string[], Err> {
|
||||
return ResultAsync.fromPromise(
|
||||
this.db
|
||||
.select({ id: file.id })
|
||||
.from(file)
|
||||
.where(
|
||||
and(
|
||||
eq(file.userId, userId),
|
||||
sql`NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM ${mobileMediaAsset}
|
||||
INNER JOIN ${mobileDevice}
|
||||
ON ${mobileMediaAsset.deviceId} = ${mobileDevice.id}
|
||||
WHERE ${mobileMediaAsset.fileId} = ${file.id}
|
||||
AND ${mobileDevice.ownerUserId} = ${userId}
|
||||
)`,
|
||||
),
|
||||
),
|
||||
(error) =>
|
||||
fileErrors.getFilesFailed(
|
||||
fctx,
|
||||
error instanceof Error ? error.message : String(error),
|
||||
),
|
||||
).map((rows) => rows.map((row) => row.id));
|
||||
}
|
||||
|
||||
updateFileStatus(
|
||||
fctx: FlowExecCtx,
|
||||
fileId: string,
|
||||
|
||||
Reference in New Issue
Block a user