mirror of
https://github.com/kmc7468/arkvault.git
synced 2025-12-16 23:18:48 +00:00
/api/file/[id]/thumbnail, /api/file/[id]/thumbnail/download, /api/file/[id]/thumbnail/upload Endpoint 구현
This commit is contained in:
@@ -327,7 +327,8 @@ export const getAllFilesByCategory = async (
|
||||
.where("user_id", "=", userId)
|
||||
.where("file_id", "is not", null)
|
||||
.$narrowType<{ file_id: NotNull }>()
|
||||
.orderBy(["file_id", "depth"])
|
||||
.orderBy("file_id")
|
||||
.orderBy("depth")
|
||||
.execute();
|
||||
return files.map(({ file_id, depth }) => ({ id: file_id, isRecursive: depth > 0 }));
|
||||
};
|
||||
|
||||
86
src/lib/server/db/media.ts
Normal file
86
src/lib/server/db/media.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import type { NotNull } from "kysely";
|
||||
import { IntegrityError } from "./error";
|
||||
import db from "./kysely";
|
||||
|
||||
interface Thumbnail {
|
||||
id: number;
|
||||
path: string;
|
||||
createdAt: Date;
|
||||
encContentIv: string;
|
||||
}
|
||||
|
||||
interface FileThumbnail extends Thumbnail {
|
||||
fileId: number;
|
||||
}
|
||||
|
||||
export const updateFileThumbnail = async (
|
||||
userId: number,
|
||||
fileId: number,
|
||||
dekVersion: Date,
|
||||
path: string,
|
||||
encContentIv: string,
|
||||
) => {
|
||||
return await db.transaction().execute(async (trx) => {
|
||||
const file = await trx
|
||||
.selectFrom("file")
|
||||
.select("data_encryption_key_version")
|
||||
.where("id", "=", fileId)
|
||||
.where("user_id", "=", userId)
|
||||
.limit(1)
|
||||
.forUpdate()
|
||||
.executeTakeFirst();
|
||||
if (!file) {
|
||||
throw new IntegrityError("File not found");
|
||||
} else if (file.data_encryption_key_version.getTime() !== dekVersion.getTime()) {
|
||||
throw new IntegrityError("Invalid DEK version");
|
||||
}
|
||||
|
||||
const thumbnail = await trx
|
||||
.selectFrom("thumbnail")
|
||||
.select("path as old_path")
|
||||
.where("file_id", "=", fileId)
|
||||
.limit(1)
|
||||
.forUpdate()
|
||||
.executeTakeFirst();
|
||||
const now = new Date();
|
||||
|
||||
await trx
|
||||
.insertInto("thumbnail")
|
||||
.values({
|
||||
file_id: fileId,
|
||||
path,
|
||||
created_at: now,
|
||||
encrypted_content_iv: encContentIv,
|
||||
})
|
||||
.onConflict((oc) =>
|
||||
oc.column("file_id").doUpdateSet({
|
||||
path,
|
||||
created_at: now,
|
||||
encrypted_content_iv: encContentIv,
|
||||
}),
|
||||
)
|
||||
.execute();
|
||||
return thumbnail?.old_path;
|
||||
});
|
||||
};
|
||||
|
||||
export const getFileThumbnail = async (userId: number, fileId: number) => {
|
||||
const thumbnail = await db
|
||||
.selectFrom("thumbnail")
|
||||
.innerJoin("file", "thumbnail.file_id", "file.id")
|
||||
.selectAll("thumbnail")
|
||||
.where("file.id", "=", fileId)
|
||||
.where("file.user_id", "=", userId)
|
||||
.$narrowType<{ file_id: NotNull }>()
|
||||
.limit(1)
|
||||
.executeTakeFirst();
|
||||
return thumbnail
|
||||
? ({
|
||||
id: thumbnail.id,
|
||||
fileId: thumbnail.file_id,
|
||||
path: thumbnail.path,
|
||||
encContentIv: thumbnail.encrypted_content_iv,
|
||||
createdAt: thumbnail.created_at,
|
||||
} satisfies FileThumbnail)
|
||||
: null;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ColumnType, Generated } from "kysely";
|
||||
import type { Generated } from "kysely";
|
||||
|
||||
interface ThumbnailTable {
|
||||
id: Generated<number>;
|
||||
@@ -6,7 +6,7 @@ interface ThumbnailTable {
|
||||
file_id: number | null;
|
||||
category_id: number | null;
|
||||
path: string;
|
||||
created_at: ColumnType<Date, Date, never>;
|
||||
created_at: Date;
|
||||
encrypted_content_iv: string; // Base64
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user