broke up db functions more, more validation

This commit is contained in:
subnub
2024-10-11 16:46:32 -04:00
parent 1a41e31f53
commit 25ae8a0119
13 changed files with 231 additions and 51 deletions
+1 -2
View File
@@ -34,7 +34,7 @@ class FolderController {
try {
const userID = req.user._id;
const name = req.body.name;
const parent = req.body.parent;
const parent = req.body.parent || "/";
const folder = await folderService.createFolder(userID, name, parent);
@@ -56,7 +56,6 @@ class FolderController {
try {
const userID = req.user._id;
const folderID = req.body.id;
const parentList = req.body.parentList;
await chunkService.deleteFolder(userID, folderID);
+10
View File
@@ -301,6 +301,16 @@ class DbUtil {
{ new: true }
);
};
// DELETE
deleteFile = async (fileID: string, userID: string) => {
const result = await File.deleteOne({
_id: new ObjectId(fileID),
"metadata.owner": userID,
});
return result;
};
}
export default DbUtil;
+30 -1
View File
@@ -76,6 +76,8 @@ class DbUtil {
query.name = new RegExp(search, "i");
}
query.trashed = null;
const result = await Folder.find(query).sort({ createdAt: -1 });
return result;
@@ -209,10 +211,37 @@ class DbUtil {
owner: string;
}) => {
const folder = new Folder(folderData);
await await folder.save();
await folder.save();
return folder;
};
// DELETE
deleteFolder = async (folderID: string, userID: string) => {
const result = await Folder.deleteOne({
_id: new ObjectId(folderID),
owner: userID,
});
return result;
};
deleteFoldersByParentList = async (
parentList: (string | ObjectId)[],
userID: string
) => {
const result = await Folder.deleteMany({
owner: userID,
parentList: { $all: parentList },
});
return result;
};
deleteFoldersByOwner = async (userID: string) => {
const result = await Folder.deleteMany({ owner: userID });
return result;
};
}
export default DbUtil;
+28
View File
@@ -0,0 +1,28 @@
import Thumbnail from "../../models/thumbnail-model";
import { ObjectId } from "mongodb";
class ThumbnailDB {
constructor() {}
// READ
getThumbnailInfo = async (userID: string, thumbnailID: string) => {
const thumbnail = await Thumbnail.findOne({
_id: new ObjectId(thumbnailID),
owner: userID,
});
return thumbnail;
};
// DELETE
removeThumbnail = async (userID: string, thumbnailID: ObjectId) => {
const result = await Thumbnail.deleteOne({
_id: thumbnailID,
owner: userID,
});
return result;
};
}
export default ThumbnailDB;
+15
View File
@@ -0,0 +1,15 @@
import { ObjectId } from "mongodb";
import User from "../../models/user-model";
// READ
class UserDB {
constructor() {}
getUserInfo = async (userID: string) => {
const user = await User.findOne({ _id: new ObjectId(userID) });
return user;
};
}
export default UserDB;
+49 -7
View File
@@ -2,8 +2,15 @@ import { Router } from "express";
import auth from "../middleware/auth";
import FolderController from "../controllers/folder-controller";
import {
createFolderValidationRules,
deleteFolderValidationRules,
getFolderInfoValidationRules,
getFolderListValidationRules,
moveFolderListValidationRules,
moveFolderValidationRules,
renameFolderValidationRules,
restoreFolderValidationRules,
trashFolderValidationRules,
} from "../middleware/folders/folder-middleware";
const folderController = new FolderController();
@@ -18,7 +25,12 @@ router.get(
folderController.getInfo
);
router.get("/folder-service/list", auth, folderController.getFolderList);
router.get(
"/folder-service/list",
auth,
getFolderListValidationRules,
folderController.getFolderList
);
router.get(
"/folder-service/move-folder-list",
@@ -29,22 +41,52 @@ router.get(
// PATCH
router.patch("/folder-service/rename", auth, folderController.renameFolder);
router.patch(
"/folder-service/rename",
auth,
renameFolderValidationRules,
folderController.renameFolder
);
router.patch("/folder-service/move", auth, folderController.moveFolder);
router.patch(
"/folder-service/move",
auth,
moveFolderValidationRules,
folderController.moveFolder
);
router.patch("/folder-service/trash", auth, folderController.trashFolder);
router.patch(
"/folder-service/trash",
auth,
trashFolderValidationRules,
folderController.trashFolder
);
router.patch("/folder-service/restore", auth, folderController.restoreFolder);
router.patch(
"/folder-service/restore",
auth,
restoreFolderValidationRules,
folderController.restoreFolder
);
// DELETE
router.delete("/folder-service/remove", auth, folderController.deleteFolder);
router.delete(
"/folder-service/remove",
auth,
deleteFolderValidationRules,
folderController.deleteFolder
);
router.delete("/folder-service/remove-all", auth, folderController.deleteAll);
// POST
router.post("/folder-service/create", auth, folderController.createFolder);
router.post(
"/folder-service/create",
auth,
createFolderValidationRules,
folderController.createFolder
);
export default router;
@@ -2,6 +2,8 @@ import { body, param, query, validationResult } from "express-validator";
import { Request, Response, NextFunction } from "express";
import { middlewareValidationFunction } from "../utils/middleware-utils";
// GET
export const moveFolderListValidationRules = [
query("parent").optional().isString().withMessage("Parent must be a string"),
query("search").optional().isString().withMessage("Search must be a string"),
@@ -13,9 +15,52 @@ export const getFolderInfoValidationRules = [
middlewareValidationFunction,
];
const getFolderListValidationRules = [
export const getFolderListValidationRules = [
query("search").optional().isString().withMessage("Search must be a string"),
query("parent").optional().isString().withMessage("Parent must be a string"),
query("sortBy").optional().isString().withMessage("Sort By must be a string"),
query("type").optional().isString().withMessage("Type must be a string"),
query("trashMode")
.optional()
.isBoolean()
.withMessage("Trash Mode must be a boolean"),
middlewareValidationFunction,
];
// PATCH
export const renameFolderValidationRules = [
body("id").isString().withMessage("ID must be a string"),
body("title").isString().withMessage("Title must be a string"),
middlewareValidationFunction,
];
export const moveFolderValidationRules = [
body("parentID").isString().withMessage("Parent must be a string"),
body("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const trashFolderValidationRules = [
body("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
export const restoreFolderValidationRules = [
body("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
// DELETE
export const deleteFolderValidationRules = [
body("id").isString().withMessage("ID must be a string"),
middlewareValidationFunction,
];
// POST
export const createFolderValidationRules = [
body("name").isString().withMessage("Name must be a string"),
body("parent").optional().isString().withMessage("Parent must be a string"),
middlewareValidationFunction,
];
@@ -76,7 +76,7 @@ class S3Actions implements IStorageActions {
s3Storage.upload({ Bucket: bucket, Body: stream, Key: randomID }, (err) => {
if (err) {
console.log("Amazon upload err", err);
console.log("S3 upload err", err);
pass.emit("error", err);
}
});
+39 -34
View File
@@ -6,27 +6,24 @@ import crypto from "crypto";
import getBusboyData from "./utils/getBusboyData";
import videoChecker from "../../utils/videoChecker";
import uuid from "uuid";
import File, {
FileInterface,
FileMetadateInterface,
} from "../../models/file-model";
import { FileInterface, FileMetadateInterface } from "../../models/file-model";
import FileDB from "../../db/mongoDB/fileDB";
import FolderDB from "../../db/mongoDB/folderDB";
import Thumbnail, { ThumbnailInterface } from "../../models/thumbnail-model";
import User from "../../models/user-model";
import env from "../../enviroment/env";
import fixStartChunkLength from "./utils/fixStartChunkLength";
import Folder, { FolderInterface } from "../../models/folder-model";
import { FolderInterface } from "../../models/folder-model";
import ForbiddenError from "../../utils/ForbiddenError";
import { ObjectId } from "mongodb";
import { S3Actions } from "./actions/S3-actions";
import { FilesystemActions } from "./actions/file-system-actions";
import { createGenericParams } from "./utils/storageHelper";
import { check } from "express-validator";
import { Readable } from "stream";
import ThumbnailDB from "../../db/mongoDB/thumbnailDB";
import UserDB from "../../db/mongoDB/userDB";
const fileDB = new FileDB();
const folderDB = new FolderDB();
const thumbnailDB = new ThumbnailDB();
const userDB = new UserDB();
const storageActions =
env.dbType === "s3" ? new S3Actions() : new FilesystemActions();
@@ -162,13 +159,12 @@ class StorageService {
if (!password) throw new ForbiddenError("Invalid Encryption Key");
const thumbnail = (await Thumbnail.findById(
new ObjectId(id)
)) as ThumbnailInterface;
const thumbnail = await thumbnailDB.getThumbnailInfo(
user._id.toString(),
id
);
if (thumbnail.owner !== user._id.toString()) {
throw new ForbiddenError("Thumbnail Unauthorized Error");
}
if (!thumbnail) throw new NotFoundError("Thumbnail Not Found");
const iv = thumbnail.IV;
@@ -305,7 +301,9 @@ class StorageService {
await fileDB.removeOneTimePublicLink(fileID);
}
const user = (await User.findById(file.metadata.owner)) as UserInterface;
const user = await userDB.getUserInfo(file.metadata.owner);
if (!user) throw new NotFoundError("User Not Found");
const password = user.getEncryptionKey();
@@ -364,9 +362,12 @@ class StorageService {
if (!file) throw new NotFoundError("Delete File Not Found Error");
if (file.metadata.thumbnailID) {
const thumbnail = (await Thumbnail.findById(
const thumbnail = await thumbnailDB.getThumbnailInfo(
userID,
file.metadata.thumbnailID
)) as ThumbnailInterface;
);
if (!thumbnail) throw new NotFoundError("Thumbnail Not Found");
const removeChunksParams = createGenericParams({
filePath: thumbnail.path,
@@ -375,7 +376,7 @@ class StorageService {
await storageActions.removeChunks(removeChunksParams);
await Thumbnail.deleteOne({ _id: file.metadata.thumbnailID });
await thumbnailDB.removeThumbnail(userID, thumbnail._id);
}
const removeChunksParams = createGenericParams({
@@ -384,7 +385,7 @@ class StorageService {
});
await storageActions.removeChunks(removeChunksParams);
await File.deleteOne({ _id: file._id });
await fileDB.deleteFile(fileID, userID);
};
deleteFolder = async (userID: string, folderID: string) => {
@@ -394,11 +395,8 @@ class StorageService {
const parentList = [...folder.parentList, folder._id];
await Folder.deleteMany({
owner: userID,
parentList: { $all: parentList },
});
await Folder.deleteMany({ owner: userID, _id: folderID });
await folderDB.deleteFoldersByParentList(parentList, userID);
await folderDB.deleteFolder(folderID, userID);
const fileList = await fileDB.getFileListByIncludedParent(
userID,
@@ -412,9 +410,12 @@ class StorageService {
try {
if (currentFile.metadata.thumbnailID) {
const thumbnail = (await Thumbnail.findById(
const thumbnail = await thumbnailDB.getThumbnailInfo(
userID,
currentFile.metadata.thumbnailID
)) as ThumbnailInterface;
);
if (!thumbnail) throw new NotFoundError("Thumbnail Not Found");
const removeChunksParams = createGenericParams({
filePath: thumbnail.path,
@@ -423,7 +424,7 @@ class StorageService {
await storageActions.removeChunks(removeChunksParams);
await Thumbnail.deleteOne({ _id: currentFile.metadata.thumbnailID });
await thumbnailDB.removeThumbnail(userID, thumbnail._id);
}
const removeChunksParams = createGenericParams({
@@ -432,7 +433,7 @@ class StorageService {
});
await storageActions.removeChunks(removeChunksParams);
await File.deleteOne({ _id: currentFile._id });
await fileDB.deleteFile(currentFile._id.toString(), userID);
} catch (e) {
console.log(
"Could not delete file",
@@ -444,7 +445,7 @@ class StorageService {
};
deleteAll = async (userID: string) => {
await Folder.deleteMany({ owner: userID });
await folderDB.deleteFoldersByOwner(userID);
const fileList = await fileDB.getFileListByOwner(userID);
@@ -456,9 +457,13 @@ class StorageService {
try {
if (currentFile.metadata.thumbnailID) {
const thumbnail = (await Thumbnail.findById(
const thumbnail = await thumbnailDB.getThumbnailInfo(
userID,
currentFile.metadata.thumbnailID
)) as ThumbnailInterface;
);
if (!thumbnail) throw new NotFoundError("Thumbnail Not Found");
const removeChunksParams = createGenericParams({
filePath: thumbnail.path,
Key: thumbnail.s3ID,
@@ -466,7 +471,7 @@ class StorageService {
await storageActions.removeChunks(removeChunksParams);
await Thumbnail.deleteOne({ _id: currentFile.metadata.thumbnailID });
await thumbnailDB.removeThumbnail(userID, thumbnail._id);
}
const removeChunksParams = createGenericParams({
@@ -475,7 +480,7 @@ class StorageService {
});
await storageActions.removeChunks(removeChunksParams);
await File.deleteOne({ _id: currentFile._id });
await fileDB.deleteFile(currentFile._id.toString(), userID);
} catch (e) {
console.log(
"Could Not Remove File",
@@ -20,7 +20,7 @@ const folderDB = new FolderDB();
class FolderService {
createFolder = async (userID: string, name: string, parent: string) => {
const newFolderParentList = [];
if (parent && parent !== "/") {
if (parent !== "/") {
const parentFolder = await folderDB.getFolderInfo(parent, userID);
if (!parentFolder) throw new Error("Parent not found");
@@ -230,6 +230,7 @@ const ContextMenu: React.FC<ContextMenuProps> = memo((props) => {
const reloadItems = () => {
invalidateFilesCache();
invalidateQuickFilesCache();
invalidateFoldersCache();
dispatch(resetSelected());
};
+4 -2
View File
@@ -14,7 +14,7 @@ import HomeIconOutline from "../../icons/HomeIconOutline";
const LeftSection = () => {
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const leftSectionOpen = useAppSelector((state) => state.leftSection.drawOpen);
const { isHome, isTrash, isMedia, isSettings } = useUtils();
const { isHome, isHomeFolder, isTrash, isMedia, isSettings } = useUtils();
const dispatch = useAppDispatch();
const navigate = useNavigate();
const addNewDisabled = useRef(false);
@@ -100,7 +100,9 @@ const LeftSection = () => {
<div
className={classNames(
"pl-2 mr-5 py-2 hover:bg-white-hover rounded-md cursor-pointer animate flex flex-row items-center w-full",
isHome ? "text-primary bg-white-hover" : "text-gray-primary"
isHome || isHomeFolder
? "text-primary bg-white-hover"
: "text-gray-primary"
)}
onClick={goHome}
>
+5 -1
View File
@@ -27,7 +27,11 @@ export const useUtils = () => {
return location.pathname === "/settings";
}, [location.pathname]);
return { isHome, isTrash, isMedia, isSettings };
const isHomeFolder = useMemo(() => {
return location.pathname.includes("/folder/");
}, [location.pathname]);
return { isHome, isTrash, isMedia, isSettings, isHomeFolder };
};
export const useClickOutOfBounds = (