mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-12 21:08:46 +00:00
파일을 삭제할 경우 서버와 클라이언트에 저장된 썸네일을 함께 삭제하도록 개선
This commit is contained in:
@@ -163,16 +163,24 @@ export const unregisterDirectory = async (userId: number, directoryId: number) =
|
||||
.setIsolationLevel("repeatable read") // TODO: Sufficient?
|
||||
.execute(async (trx) => {
|
||||
const unregisterFiles = async (parentId: number) => {
|
||||
return await trx
|
||||
const files = await trx
|
||||
.selectFrom("file")
|
||||
.leftJoin("thumbnail", "file.id", "thumbnail.file_id")
|
||||
.select(["file.id", "file.path", "thumbnail.path as thumbnailPath"])
|
||||
.where("file.parent_id", "=", parentId)
|
||||
.where("file.user_id", "=", userId)
|
||||
.forUpdate("file")
|
||||
.execute();
|
||||
await trx
|
||||
.deleteFrom("file")
|
||||
.where("parent_id", "=", parentId)
|
||||
.where("user_id", "=", userId)
|
||||
.returning(["id", "path"])
|
||||
.execute();
|
||||
return files;
|
||||
};
|
||||
const unregisterDirectoryRecursively = async (
|
||||
directoryId: number,
|
||||
): Promise<{ id: number; path: string }[]> => {
|
||||
): Promise<{ id: number; path: string; thumbnailPath: string | null }[]> => {
|
||||
const files = await unregisterFiles(directoryId);
|
||||
const subDirectories = await trx
|
||||
.selectFrom("directory")
|
||||
@@ -417,16 +425,22 @@ export const setFileEncName = async (
|
||||
};
|
||||
|
||||
export const unregisterFile = async (userId: number, fileId: number) => {
|
||||
const file = await db
|
||||
.deleteFrom("file")
|
||||
.where("id", "=", fileId)
|
||||
.where("user_id", "=", userId)
|
||||
.returning("path")
|
||||
.executeTakeFirst();
|
||||
if (!file) {
|
||||
throw new IntegrityError("File not found");
|
||||
}
|
||||
return { path: file.path };
|
||||
return await db.transaction().execute(async (trx) => {
|
||||
const file = await trx
|
||||
.selectFrom("file")
|
||||
.leftJoin("thumbnail", "file.id", "thumbnail.file_id")
|
||||
.select(["file.path", "thumbnail.path as thumbnailPath"])
|
||||
.where("file.id", "=", fileId)
|
||||
.where("file.user_id", "=", userId)
|
||||
.forUpdate("file")
|
||||
.executeTakeFirst();
|
||||
if (!file) {
|
||||
throw new IntegrityError("File not found");
|
||||
}
|
||||
|
||||
await trx.deleteFrom("file").where("id", "=", fileId).execute();
|
||||
return file;
|
||||
});
|
||||
};
|
||||
|
||||
export const addFileToCategory = async (fileId: number, categoryId: number) => {
|
||||
|
||||
@@ -37,7 +37,7 @@ export const updateFileThumbnail = async (
|
||||
|
||||
const thumbnail = await trx
|
||||
.selectFrom("thumbnail")
|
||||
.select("path as old_path")
|
||||
.select("path as oldPath")
|
||||
.where("file_id", "=", fileId)
|
||||
.limit(1)
|
||||
.forUpdate()
|
||||
@@ -60,7 +60,7 @@ export const updateFileThumbnail = async (
|
||||
}),
|
||||
)
|
||||
.execute();
|
||||
return thumbnail?.old_path;
|
||||
return thumbnail?.oldPath ?? null;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -34,12 +34,19 @@ export const getDirectoryInformation = async (userId: number, directoryId: Direc
|
||||
};
|
||||
};
|
||||
|
||||
const safeUnlink = async (path: string | null) => {
|
||||
if (path) {
|
||||
await unlink(path).catch(console.error);
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteDirectory = async (userId: number, directoryId: number) => {
|
||||
try {
|
||||
const files = await unregisterDirectory(userId, directoryId);
|
||||
return {
|
||||
files: files.map(({ id, path }) => {
|
||||
unlink(path); // Intended
|
||||
files: files.map(({ id, path, thumbnailPath }) => {
|
||||
safeUnlink(path); // Intended
|
||||
safeUnlink(thumbnailPath); // Intended
|
||||
return id;
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -45,10 +45,17 @@ export const getFileInformation = async (userId: number, fileId: number) => {
|
||||
};
|
||||
};
|
||||
|
||||
const safeUnlink = async (path: string | null) => {
|
||||
if (path) {
|
||||
await unlink(path).catch(console.error);
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteFile = async (userId: number, fileId: number) => {
|
||||
try {
|
||||
const { path } = await unregisterFile(userId, fileId);
|
||||
unlink(path); // Intended
|
||||
const { path, thumbnailPath } = await unregisterFile(userId, fileId);
|
||||
safeUnlink(path); // Intended
|
||||
safeUnlink(thumbnailPath); // Intended
|
||||
} catch (e) {
|
||||
if (e instanceof IntegrityError && e.message === "File not found") {
|
||||
error(404, "Invalid file id");
|
||||
@@ -126,9 +133,7 @@ export const uploadFileThumbnail = async (
|
||||
await pipeline(encContentStream, createWriteStream(path, { flags: "wx", mode: 0o600 }));
|
||||
|
||||
const oldPath = await updateFileThumbnail(userId, fileId, dekVersion, path, encContentIv);
|
||||
if (oldPath) {
|
||||
safeUnlink(oldPath); // Intended
|
||||
}
|
||||
safeUnlink(oldPath); // Intended
|
||||
} catch (e) {
|
||||
await safeUnlink(path);
|
||||
|
||||
@@ -157,10 +162,6 @@ export const scanMissingFileThumbnails = async (userId: number) => {
|
||||
return { files: fileIds };
|
||||
};
|
||||
|
||||
const safeUnlink = async (path: string) => {
|
||||
await unlink(path).catch(console.error);
|
||||
};
|
||||
|
||||
export const uploadFile = async (
|
||||
params: Omit<NewFile, "path" | "encContentHash">,
|
||||
encContentStream: Readable,
|
||||
|
||||
@@ -2,7 +2,13 @@ import { getContext, setContext } from "svelte";
|
||||
import { callGetApi, callPostApi } from "$lib/hooks";
|
||||
import { storeHmacSecrets } from "$lib/indexedDB";
|
||||
import { generateDataKey, wrapDataKey, unwrapHmacSecret, encryptString } from "$lib/modules/crypto";
|
||||
import { storeFileCache, deleteFileCache, storeFileThumbnail, uploadFile } from "$lib/modules/file";
|
||||
import {
|
||||
storeFileCache,
|
||||
deleteFileCache,
|
||||
storeFileThumbnail,
|
||||
deleteFileThumbnail,
|
||||
uploadFile,
|
||||
} from "$lib/modules/file";
|
||||
import type {
|
||||
DirectoryRenameRequest,
|
||||
DirectoryCreateRequest,
|
||||
@@ -114,10 +120,12 @@ export const requestEntryDeletion = async (entry: SelectedEntry) => {
|
||||
|
||||
if (entry.type === "directory") {
|
||||
const { deletedFiles }: DirectoryDeleteResponse = await res.json();
|
||||
await Promise.all(deletedFiles.map(deleteFileCache));
|
||||
await Promise.all(
|
||||
deletedFiles.flatMap((fileId) => [deleteFileCache(fileId), deleteFileThumbnail(fileId)]),
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
await deleteFileCache(entry.id);
|
||||
await Promise.all([deleteFileCache(entry.id), deleteFileThumbnail(entry.id)]);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user