mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-02-04 16:16:55 +00:00
/api/category, /api/directory, /api/file 아래의 대부분의 Endpoint들을 tRPC로 마이그레이션
This commit is contained in:
@@ -1,133 +0,0 @@
|
||||
import { error } from "@sveltejs/kit";
|
||||
import {
|
||||
registerCategory,
|
||||
getAllCategoriesByParent,
|
||||
getCategory,
|
||||
setCategoryEncName,
|
||||
unregisterCategory,
|
||||
type CategoryId,
|
||||
type NewCategory,
|
||||
} from "$lib/server/db/category";
|
||||
import { IntegrityError } from "$lib/server/db/error";
|
||||
import {
|
||||
getAllFilesByCategory,
|
||||
getFile,
|
||||
addFileToCategory,
|
||||
removeFileFromCategory,
|
||||
} from "$lib/server/db/file";
|
||||
import type { Ciphertext } from "$lib/server/db/schema";
|
||||
|
||||
export const getCategoryInformation = async (userId: number, categoryId: CategoryId) => {
|
||||
const category = categoryId !== "root" ? await getCategory(userId, categoryId) : undefined;
|
||||
if (category === null) {
|
||||
error(404, "Invalid category id");
|
||||
}
|
||||
|
||||
const categories = await getAllCategoriesByParent(userId, categoryId);
|
||||
return {
|
||||
metadata: category && {
|
||||
parentId: category.parentId ?? ("root" as const),
|
||||
mekVersion: category.mekVersion,
|
||||
encDek: category.encDek,
|
||||
dekVersion: category.dekVersion,
|
||||
encName: category.encName,
|
||||
},
|
||||
categories: categories.map(({ id }) => id),
|
||||
};
|
||||
};
|
||||
|
||||
export const deleteCategory = async (userId: number, categoryId: number) => {
|
||||
try {
|
||||
await unregisterCategory(userId, categoryId);
|
||||
} catch (e) {
|
||||
if (e instanceof IntegrityError && e.message === "Category not found") {
|
||||
error(404, "Invalid category id");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export const addCategoryFile = async (userId: number, categoryId: number, fileId: number) => {
|
||||
const category = await getCategory(userId, categoryId);
|
||||
const file = await getFile(userId, fileId);
|
||||
if (!category) {
|
||||
error(404, "Invalid category id");
|
||||
} else if (!file) {
|
||||
error(404, "Invalid file id");
|
||||
}
|
||||
|
||||
try {
|
||||
await addFileToCategory(fileId, categoryId);
|
||||
} catch (e) {
|
||||
if (e instanceof IntegrityError && e.message === "File already added to category") {
|
||||
error(400, "File already added");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export const getCategoryFiles = async (userId: number, categoryId: number, recurse: boolean) => {
|
||||
const category = await getCategory(userId, categoryId);
|
||||
if (!category) {
|
||||
error(404, "Invalid category id");
|
||||
}
|
||||
|
||||
const files = await getAllFilesByCategory(userId, categoryId, recurse);
|
||||
return { files };
|
||||
};
|
||||
|
||||
export const removeCategoryFile = async (userId: number, categoryId: number, fileId: number) => {
|
||||
const category = await getCategory(userId, categoryId);
|
||||
const file = await getFile(userId, fileId);
|
||||
if (!category) {
|
||||
error(404, "Invalid category id");
|
||||
} else if (!file) {
|
||||
error(404, "Invalid file id");
|
||||
}
|
||||
|
||||
try {
|
||||
await removeFileFromCategory(fileId, categoryId);
|
||||
} catch (e) {
|
||||
if (e instanceof IntegrityError && e.message === "File not found in category") {
|
||||
error(400, "File not added");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export const renameCategory = async (
|
||||
userId: number,
|
||||
categoryId: number,
|
||||
dekVersion: Date,
|
||||
newEncName: Ciphertext,
|
||||
) => {
|
||||
try {
|
||||
await setCategoryEncName(userId, categoryId, dekVersion, newEncName);
|
||||
} catch (e) {
|
||||
if (e instanceof IntegrityError) {
|
||||
if (e.message === "Category not found") {
|
||||
error(404, "Invalid category id");
|
||||
} else if (e.message === "Invalid DEK version") {
|
||||
error(400, "Invalid DEK version");
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export const createCategory = async (params: NewCategory) => {
|
||||
const oneMinuteAgo = new Date(Date.now() - 60 * 1000);
|
||||
const oneMinuteLater = new Date(Date.now() + 60 * 1000);
|
||||
if (params.dekVersion <= oneMinuteAgo || params.dekVersion >= oneMinuteLater) {
|
||||
error(400, "Invalid DEK version");
|
||||
}
|
||||
|
||||
try {
|
||||
await registerCategory(params);
|
||||
} catch (e) {
|
||||
if (e instanceof IntegrityError && e.message === "Inactive MEK version") {
|
||||
error(400, "Inactive MEK version");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
@@ -1,96 +0,0 @@
|
||||
import { error } from "@sveltejs/kit";
|
||||
import { unlink } from "fs/promises";
|
||||
import { IntegrityError } from "$lib/server/db/error";
|
||||
import {
|
||||
registerDirectory,
|
||||
getAllDirectoriesByParent,
|
||||
getDirectory,
|
||||
setDirectoryEncName,
|
||||
unregisterDirectory,
|
||||
getAllFilesByParent,
|
||||
type DirectoryId,
|
||||
type NewDirectory,
|
||||
} from "$lib/server/db/file";
|
||||
import type { Ciphertext } from "$lib/server/db/schema";
|
||||
|
||||
export const getDirectoryInformation = async (userId: number, directoryId: DirectoryId) => {
|
||||
const directory = directoryId !== "root" ? await getDirectory(userId, directoryId) : undefined;
|
||||
if (directory === null) {
|
||||
error(404, "Invalid directory id");
|
||||
}
|
||||
|
||||
const directories = await getAllDirectoriesByParent(userId, directoryId);
|
||||
const files = await getAllFilesByParent(userId, directoryId);
|
||||
return {
|
||||
metadata: directory && {
|
||||
parentId: directory.parentId ?? ("root" as const),
|
||||
mekVersion: directory.mekVersion,
|
||||
encDek: directory.encDek,
|
||||
dekVersion: directory.dekVersion,
|
||||
encName: directory.encName,
|
||||
},
|
||||
directories: directories.map(({ id }) => id),
|
||||
files: files.map(({ id }) => id),
|
||||
};
|
||||
};
|
||||
|
||||
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, thumbnailPath }) => {
|
||||
safeUnlink(path); // Intended
|
||||
safeUnlink(thumbnailPath); // Intended
|
||||
return id;
|
||||
}),
|
||||
};
|
||||
} catch (e) {
|
||||
if (e instanceof IntegrityError && e.message === "Directory not found") {
|
||||
error(404, "Invalid directory id");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export const renameDirectory = async (
|
||||
userId: number,
|
||||
directoryId: number,
|
||||
dekVersion: Date,
|
||||
newEncName: Ciphertext,
|
||||
) => {
|
||||
try {
|
||||
await setDirectoryEncName(userId, directoryId, dekVersion, newEncName);
|
||||
} catch (e) {
|
||||
if (e instanceof IntegrityError) {
|
||||
if (e.message === "Directory not found") {
|
||||
error(404, "Invalid directory id");
|
||||
} else if (e.message === "Invalid DEK version") {
|
||||
error(400, "Invalid DEK version");
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export const createDirectory = async (params: NewDirectory) => {
|
||||
const oneMinuteAgo = new Date(Date.now() - 60 * 1000);
|
||||
const oneMinuteLater = new Date(Date.now() + 60 * 1000);
|
||||
if (params.dekVersion <= oneMinuteAgo || params.dekVersion >= oneMinuteLater) {
|
||||
error(400, "Invalid DEK version");
|
||||
}
|
||||
|
||||
try {
|
||||
await registerDirectory(params);
|
||||
} catch (e) {
|
||||
if (e instanceof IntegrityError && e.message === "Inactive MEK version") {
|
||||
error(400, "Invalid MEK version");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
@@ -1,72 +1,17 @@
|
||||
import { error } from "@sveltejs/kit";
|
||||
import { createHash } from "crypto";
|
||||
import { createReadStream, createWriteStream } from "fs";
|
||||
import { mkdir, stat, unlink } from "fs/promises";
|
||||
import { mkdir, stat } from "fs/promises";
|
||||
import { dirname } from "path";
|
||||
import { Readable } from "stream";
|
||||
import { pipeline } from "stream/promises";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { IntegrityError } from "$lib/server/db/error";
|
||||
import {
|
||||
registerFile,
|
||||
getAllFileIds,
|
||||
getAllFileIdsByContentHmac,
|
||||
getFile,
|
||||
setFileEncName,
|
||||
unregisterFile,
|
||||
getAllFileCategories,
|
||||
type NewFile,
|
||||
} from "$lib/server/db/file";
|
||||
import {
|
||||
updateFileThumbnail,
|
||||
getFileThumbnail,
|
||||
getMissingFileThumbnails,
|
||||
} from "$lib/server/db/media";
|
||||
import type { Ciphertext } from "$lib/server/db/schema";
|
||||
import { FileRepo, MediaRepo, IntegrityError } from "$lib/server/db";
|
||||
import env from "$lib/server/loadenv";
|
||||
|
||||
export const getFileInformation = async (userId: number, fileId: number) => {
|
||||
const file = await getFile(userId, fileId);
|
||||
if (!file) {
|
||||
error(404, "Invalid file id");
|
||||
}
|
||||
|
||||
const categories = await getAllFileCategories(fileId);
|
||||
return {
|
||||
parentId: file.parentId ?? ("root" as const),
|
||||
mekVersion: file.mekVersion,
|
||||
encDek: file.encDek,
|
||||
dekVersion: file.dekVersion,
|
||||
contentType: file.contentType,
|
||||
encContentIv: file.encContentIv,
|
||||
encName: file.encName,
|
||||
encCreatedAt: file.encCreatedAt,
|
||||
encLastModifiedAt: file.encLastModifiedAt,
|
||||
categories: categories.map(({ id }) => id),
|
||||
};
|
||||
};
|
||||
|
||||
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, 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");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
import { safeUnlink } from "$lib/server/modules/filesystem";
|
||||
|
||||
export const getFileStream = async (userId: number, fileId: number) => {
|
||||
const file = await getFile(userId, fileId);
|
||||
const file = await FileRepo.getFile(userId, fileId);
|
||||
if (!file) {
|
||||
error(404, "Invalid file id");
|
||||
}
|
||||
@@ -78,37 +23,8 @@ export const getFileStream = async (userId: number, fileId: number) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const renameFile = async (
|
||||
userId: number,
|
||||
fileId: number,
|
||||
dekVersion: Date,
|
||||
newEncName: Ciphertext,
|
||||
) => {
|
||||
try {
|
||||
await setFileEncName(userId, fileId, dekVersion, newEncName);
|
||||
} catch (e) {
|
||||
if (e instanceof IntegrityError) {
|
||||
if (e.message === "File not found") {
|
||||
error(404, "Invalid file id");
|
||||
} else if (e.message === "Invalid DEK version") {
|
||||
error(400, "Invalid DEK version");
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export const getFileThumbnailInformation = async (userId: number, fileId: number) => {
|
||||
const thumbnail = await getFileThumbnail(userId, fileId);
|
||||
if (!thumbnail) {
|
||||
error(404, "File or its thumbnail not found");
|
||||
}
|
||||
|
||||
return { updatedAt: thumbnail.updatedAt, encContentIv: thumbnail.encContentIv };
|
||||
};
|
||||
|
||||
export const getFileThumbnailStream = async (userId: number, fileId: number) => {
|
||||
const thumbnail = await getFileThumbnail(userId, fileId);
|
||||
const thumbnail = await MediaRepo.getFileThumbnail(userId, fileId);
|
||||
if (!thumbnail) {
|
||||
error(404, "File or its thumbnail not found");
|
||||
}
|
||||
@@ -133,7 +49,13 @@ export const uploadFileThumbnail = async (
|
||||
try {
|
||||
await pipeline(encContentStream, createWriteStream(path, { flags: "wx", mode: 0o600 }));
|
||||
|
||||
const oldPath = await updateFileThumbnail(userId, fileId, dekVersion, path, encContentIv);
|
||||
const oldPath = await MediaRepo.updateFileThumbnail(
|
||||
userId,
|
||||
fileId,
|
||||
dekVersion,
|
||||
path,
|
||||
encContentIv,
|
||||
);
|
||||
safeUnlink(oldPath); // Intended
|
||||
} catch (e) {
|
||||
await safeUnlink(path);
|
||||
@@ -149,27 +71,8 @@ export const uploadFileThumbnail = async (
|
||||
}
|
||||
};
|
||||
|
||||
export const getFileList = async (userId: number) => {
|
||||
const fileIds = await getAllFileIds(userId);
|
||||
return { files: fileIds };
|
||||
};
|
||||
|
||||
export const scanDuplicateFiles = async (
|
||||
userId: number,
|
||||
hskVersion: number,
|
||||
contentHmac: string,
|
||||
) => {
|
||||
const fileIds = await getAllFileIdsByContentHmac(userId, hskVersion, contentHmac);
|
||||
return { files: fileIds };
|
||||
};
|
||||
|
||||
export const scanMissingFileThumbnails = async (userId: number) => {
|
||||
const fileIds = await getMissingFileThumbnails(userId);
|
||||
return { files: fileIds };
|
||||
};
|
||||
|
||||
export const uploadFile = async (
|
||||
params: Omit<NewFile, "path" | "encContentHash">,
|
||||
params: Omit<FileRepo.NewFile, "path" | "encContentHash">,
|
||||
encContentStream: Readable,
|
||||
encContentHash: Promise<string>,
|
||||
) => {
|
||||
@@ -201,7 +104,7 @@ export const uploadFile = async (
|
||||
throw new Error("Invalid checksum");
|
||||
}
|
||||
|
||||
const { id: fileId } = await registerFile({
|
||||
const { id: fileId } = await FileRepo.registerFile({
|
||||
...params,
|
||||
path,
|
||||
encContentHash: hash,
|
||||
|
||||
Reference in New Issue
Block a user