diff --git a/backend/controllers/file-controller.ts b/backend/controllers/file-controller.ts index 61d18a5..f0afac4 100644 --- a/backend/controllers/file-controller.ts +++ b/backend/controllers/file-controller.ts @@ -235,12 +235,15 @@ class FileController { handleFinish(filename, metadata); }); } catch (e: unknown) { - if (e instanceof Error) { - console.log("\nUploading File Error File Route:", e.message); - } if (!responseSent) { res.writeHead(500, { Connection: "close" }); - res.end(); + if (e instanceof Error) { + console.log("\nUploading File Error File Route:", e.message); + res.end(e.message); + } else { + console.log("\nUploading File Error File Route:", e); + res.end("Server error uploading file"); + } } } }; @@ -510,6 +513,10 @@ class FileController { const accessTokenStreamVideo = req.accessTokenStreamVideo!; + if (!accessTokenStreamVideo) { + throw new NotAuthorizedError("No Access Token"); + } + await User.updateOne( { _id: userID }, { $pull: { tempTokens: { token: accessTokenStreamVideo } } } @@ -674,7 +681,7 @@ class FileController { try { const userID = req.user._id; - let searchQuery = req.query.search || ""; + const searchQuery = req.query.search as string; const trashMode = req.query.trashMode === "true"; const mediaMode = req.query.mediaMode === "true"; diff --git a/backend/db/mongoDB/fileDB.ts b/backend/db/mongoDB/fileDB.ts index 4424795..039c9c6 100644 --- a/backend/db/mongoDB/fileDB.ts +++ b/backend/db/mongoDB/fileDB.ts @@ -118,11 +118,20 @@ class DbUtil { const queryObj = createQuery(queryData); - const fileList = await File.find(queryObj) - .sort(formattedSortBy) - .limit(limit); + if (sortBy.includes("alp_")) { + const fileList = await File.find(queryObj) + .collation({ locale: "en", strength: 2 }) + .sort(formattedSortBy) + .limit(limit); - return fileList; + return fileList; + } else { + const fileList = await File.find(queryObj) + .sort(formattedSortBy) + .limit(limit); + + return fileList; + } }; removeTempToken = async (user: UserInterface, tempToken: string) => { diff --git a/backend/express-routers/file-router.ts b/backend/express-routers/file-router.ts index 9cd8035..9deffa8 100644 --- a/backend/express-routers/file-router.ts +++ b/backend/express-routers/file-router.ts @@ -8,6 +8,7 @@ import { getListValidationRules, getPublicDownloadValidationRules, getQuickListValidationRules, + getSuggestedListValidationRules, getThumbnailValidationRules, } from "../middleware/files/files-middleware"; @@ -91,6 +92,7 @@ router.get( router.get( "/file-service/suggested-list", auth, + getSuggestedListValidationRules, fileController.getSuggestedList ); diff --git a/backend/middleware/files/files-middleware.ts b/backend/middleware/files/files-middleware.ts index 95fa58f..7c7733f 100644 --- a/backend/middleware/files/files-middleware.ts +++ b/backend/middleware/files/files-middleware.ts @@ -51,3 +51,20 @@ export const moveFileValidationRules = [ query("parentID").isString().withMessage("Parent must be a string"), middlewareValidationFunction, ]; + +export const getSuggestedListValidationRules = [ + query("search") + .optional() + .isString() + .isLength({ min: 1, max: 255 }) + .withMessage("Search must be a string"), + query("trashMode") + .optional() + .isBoolean() + .withMessage("Trash Mode must be a boolean"), + query("mediaMode") + .optional() + .isBoolean() + .withMessage("Media Mode must be a boolean"), + middlewareValidationFunction, +]; diff --git a/backend/models/file-model.ts b/backend/models/file-model.ts index b4f2a8b..31be254 100644 --- a/backend/models/file-model.ts +++ b/backend/models/file-model.ts @@ -86,6 +86,72 @@ export interface FileInterface metadata: FileMetadateInterface; } +fileSchema.index( + { "metadata.owner": 1, "metadata.parent": 1, filename: 1 }, + { background: true } +); + +fileSchema.index( + { "metadata.owner": 1, "metadata.parent": 1, uploadDate: 1 }, + { background: true } +); + +fileSchema.index( + { "metadata.owner": 1, "metadata.parent": 1, filename: 1 }, + { background: true } +); + +fileSchema.index( + { "metadata.owner": 1, "metadata.parent": 1, uploadDate: 1 }, + { collation: { locale: "en", strength: 2 }, background: true } +); + +fileSchema.index( + { "metadata.owner": 1, "metadata.parent": 1, filename: 1 }, + { collation: { locale: "en", strength: 2 }, background: true } +); + +fileSchema.index({ "metadata.owner": 1 }, { background: true }); + +fileSchema.index({ "metadata.parent": 1 }, { background: true }); + +fileSchema.index({ uploadDate: 1 }, { background: true }); + +fileSchema.index({ "metadata.trashed": 1 }, { background: true }); + +fileSchema.index({ "metadata.hasThumbnail": 1 }, { background: true }); + +fileSchema.index( + { filename: 1 }, + { collation: { locale: "en", strength: 2 }, background: true } +); + +fileSchema.index( + { "metadata.parent": 1 }, + { collation: { locale: "en", strength: 2 }, background: true } +); + +fileSchema.index( + { "metadata.owner": 1 }, + { collation: { locale: "en", strength: 2 }, background: true } +); + +// fileSchema.index( +// { filename: 1 }, +// { collation: { locale: "en", strength: 2 }, background: true } +// ); +// fileSchema.index( +// { filename: -1 }, +// { collation: { locale: "en", strength: 2 }, background: true } +// ); +// fileSchema.index({ uploadDate: 1 }, { background: true }); +// fileSchema.index({ uploadDate: -1 }, { background: true }); +// fileSchema.index({ "metadata.parent": 1 }, { background: true }); +// fileSchema.index({ "metadata.owner": 1 }, { background: true }); +// fileSchema.index({ "metadata.isVideo": 1 }, { background: true }); +// fileSchema.index({ "metadata.hasThumbnail": 1 }, { background: true }); +// fileSchema.index({ "metadata.trashed": 1 }, { background: true }); + const File = mongoose.model("fs.files", fileSchema); export default File; diff --git a/backend/models/folder-model.ts b/backend/models/folder-model.ts index 52dd002..58624c9 100644 --- a/backend/models/folder-model.ts +++ b/backend/models/folder-model.ts @@ -42,6 +42,14 @@ export interface FolderInterface trashed: boolean | null; } +folderSchema.index({ owner: 1, parent: 1, name: 1 }, { background: true }); +folderSchema.index({ owner: 1, parent: 1, createdAt: 1 }, { background: true }); +folderSchema.index({ createdAt: 1 }, { background: true }); +folderSchema.index({ owner: 1 }, { background: true }); +folderSchema.index({ trashed: 1 }, { background: true }); +folderSchema.index({ parent: 1 }, { background: true }); +folderSchema.index({ name: 1 }, { background: true }); + const Folder = mongoose.model("Folder", folderSchema); export default Folder; diff --git a/backend/models/thumbnail-model.ts b/backend/models/thumbnail-model.ts index 71fb8d7..ac92448 100644 --- a/backend/models/thumbnail-model.ts +++ b/backend/models/thumbnail-model.ts @@ -42,6 +42,8 @@ export interface ThumbnailInterface extends Document { updatedAt: Date; } +thumbnailSchema.index({ owner: 1 }); + const Thumbnail = mongoose.model( "Thumbnail", thumbnailSchema diff --git a/backend/server/server.ts b/backend/server/server.ts index 91af2cf..d2c871c 100755 --- a/backend/server/server.ts +++ b/backend/server/server.ts @@ -36,7 +36,7 @@ if (process.env.SSL === "true") { server = http.createServer(app); -require("../db/mongoose"); +require("../db/connections/mongoose"); app.use(cookieParser(env.passwordCookie)); app.use(helmet()); diff --git a/backend/services/chunk-service/chunk-service.ts b/backend/services/chunk-service/chunk-service.ts index 8549655..a696a0e 100644 --- a/backend/services/chunk-service/chunk-service.ts +++ b/backend/services/chunk-service/chunk-service.ts @@ -6,7 +6,10 @@ import crypto from "crypto"; import getBusboyData from "./utils/getBusboyData"; import videoChecker from "../../utils/videoChecker"; import uuid from "uuid"; -import File, { FileInterface } from "../../models/file-model"; +import File, { + 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"; @@ -19,6 +22,8 @@ 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"; const fileDB = new FileDB(); const folderDB = new FolderDB(); @@ -44,11 +49,39 @@ class StorageService { const filename = fileInfo.filename; const parent = formData.get("parent") || "/"; - const size = formData.get("size") || ""; - let hasThumbnail = false; - let thumbnailID = ""; + const size = +formData.get("size"); + const hasThumbnail = false; + const thumbnailID = ""; const isVideo = videoChecker(filename); + const errors = []; + + if (!filename || filename.length === 0 || filename.length > 255) { + errors.push({ + msg: "Filename is required and length must be greater than 0 and less than 255", + param: "filename", + }); + } + + if (!file) { + errors.push({ msg: "File is required", param: "file" }); + } + + // @prettier-ignore + if (!(file instanceof Readable)) { + errors.push({ msg: "File must be a readable stream", param: "file" }); + } + + if (!size || size < 0) { + errors.push({ msg: "Size must be a positive integer", param: "size" }); + } + + if (errors.length > 0) { + throw new Error( + `Invalid request parameters ${errors.map((e) => e.msg).join(", ")}` + ); + } + const parentList = []; if (parent !== "/") { @@ -65,7 +98,7 @@ class StorageService { const randomFilenameID = uuid.v4(); const metadata = { - owner: user._id, + owner: user._id.toString(), parent, parentList: parentList.toString(), hasThumbnail, @@ -73,7 +106,7 @@ class StorageService { isVideo, size, IV: initVect, - } as any; + } as FileMetadateInterface; if (env.dbType === "fs") { metadata.filePath = env.fsDirectory + randomFilenameID; diff --git a/backend/utils/ForbiddenError.ts b/backend/utils/ForbiddenError.ts index 1cc5dd6..28b8c05 100644 --- a/backend/utils/ForbiddenError.ts +++ b/backend/utils/ForbiddenError.ts @@ -1,12 +1,13 @@ class ForbiddenError extends Error { + code: number; + isCustomError: boolean; - code: number; - - constructor(args: any) { - super(args); + constructor(args: any) { + super(args); - this.code = 403; - } + this.code = 403; + this.isCustomError = true; + } } -export default ForbiddenError; \ No newline at end of file +export default ForbiddenError; diff --git a/backend/utils/InternalServerError.ts b/backend/utils/InternalServerError.ts index 89e1441..0ff000f 100644 --- a/backend/utils/InternalServerError.ts +++ b/backend/utils/InternalServerError.ts @@ -1,12 +1,13 @@ class InternalServerError extends Error { + code: number; + isCustomError: boolean; - code: number; - - constructor(args: any) { - super(args); + constructor(args: any) { + super(args); - this.code = 500; - } + this.code = 500; + this.isCustomError = true; + } } -export default InternalServerError; \ No newline at end of file +export default InternalServerError; diff --git a/backend/utils/NotAuthorizedError.ts b/backend/utils/NotAuthorizedError.ts index d35791e..c756e8b 100644 --- a/backend/utils/NotAuthorizedError.ts +++ b/backend/utils/NotAuthorizedError.ts @@ -1,12 +1,13 @@ class NotAuthorizedError extends Error { + code: number; + isCustomError: boolean; - code: number; - - constructor(args: any) { - super(args); + constructor(args: any) { + super(args); - this.code = 401; - } + this.code = 401; + this.isCustomError = true; + } } -export default NotAuthorizedError; \ No newline at end of file +export default NotAuthorizedError; diff --git a/backend/utils/NotEmailVerifiedError.ts b/backend/utils/NotEmailVerifiedError.ts index 4ee10f0..8c33281 100644 --- a/backend/utils/NotEmailVerifiedError.ts +++ b/backend/utils/NotEmailVerifiedError.ts @@ -1,12 +1,13 @@ class NotEmailVerifiedError extends Error { + code: number; + isCustomError: boolean; - code: number; - - constructor(args: any) { - super(args); + constructor(args: any) { + super(args); - this.code = 404; - } + this.code = 404; + this.isCustomError = true; + } } -export default NotEmailVerifiedError; \ No newline at end of file +export default NotEmailVerifiedError; diff --git a/backend/utils/NotFoundError.ts b/backend/utils/NotFoundError.ts index 4715120..af86e09 100644 --- a/backend/utils/NotFoundError.ts +++ b/backend/utils/NotFoundError.ts @@ -1,12 +1,13 @@ class NotFoundError extends Error { + code: number; + isCustomError: boolean; - code: number; - - constructor(args: any) { - super(args); + constructor(args: any) { + super(args); - this.code = 404; - } + this.code = 404; + this.isCustomError = true; + } } -export default NotFoundError; \ No newline at end of file +export default NotFoundError; diff --git a/backend/utils/NotValidDataError.ts b/backend/utils/NotValidDataError.ts index b17991b..01601bf 100644 --- a/backend/utils/NotValidDataError.ts +++ b/backend/utils/NotValidDataError.ts @@ -1,12 +1,13 @@ class NotValidDataError extends Error { + code: number; + isCustomError: boolean; - code: number; - - constructor(args: any) { - super(args); + constructor(args: any) { + super(args); - this.code = 403; - } + this.code = 403; + this.isCustomError = true; + } } -export default NotValidDataError; \ No newline at end of file +export default NotValidDataError; diff --git a/nodemon.json b/nodemon.json index 2f7d144..3906e53 100644 --- a/nodemon.json +++ b/nodemon.json @@ -2,5 +2,5 @@ "watch": ["dist/"], "ignore": ["src", "node_modules"], "ext": "js,json", - "exec": "node dist/server/serverStart.js" + "exec": "node dist/server/server-start.js" } diff --git a/package.json b/package.json index 7d5123e..0244bf6 100755 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "test": "NODE_ENV=test env-cmd -f ./config/test.env jest --config=jest.config.json --runInBand", "start:dev": "NODE_ENV=development node dist/server/serverStart.js", "start:debug": "NODE_ENV=development node --inspect dist/server/serverStart.js", - "start": "cross-env NODE_ENV=production node dist/server/serverStart.js", + "start": "cross-env NODE_ENV=production node dist/server/server-start.js", "create-indexes-database": "node serverUtils/createIndexes.js", "increase-node-memory": "export NODE_OPTIONS=--max_old_space_size=8000", "create-indexes-database:dev": "node serverUtils/createIndexes.js", @@ -34,7 +34,7 @@ "vite-test": "vite", "dev-test": "concurrently \"vite\" \"nodemon server.js\"", "dev-hot": "concurrently \"vite\" \"tsc -w -p ./backend/tsconfig.json\" \"npm run dev:backend\"", - "dev:backend": "nodemon dist/server/serverStart.js", + "dev:backend": "nodemon dist/server/server-start.js", "vite-build": "vite build", "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'" }, diff --git a/src/components/DownloadPage/DownloadPage.tsx b/src/components/DownloadPage/DownloadPage.tsx index 3e1744d..23d51c1 100644 --- a/src/components/DownloadPage/DownloadPage.tsx +++ b/src/components/DownloadPage/DownloadPage.tsx @@ -42,7 +42,7 @@ const PublicDownloadPage = () => { return (
- +
); } @@ -121,7 +121,7 @@ const PublicDownloadPage = () => { - + ); }; diff --git a/src/components/Homepage/Homepage.tsx b/src/components/Homepage/Homepage.tsx index bfab51b..41c3024 100644 --- a/src/components/Homepage/Homepage.tsx +++ b/src/components/Homepage/Homepage.tsx @@ -19,7 +19,7 @@ const Homepage = () => { - + ); }; diff --git a/src/components/LoginPage/LoginPage.tsx b/src/components/LoginPage/LoginPage.tsx index 070c68f..91e3116 100755 --- a/src/components/LoginPage/LoginPage.tsx +++ b/src/components/LoginPage/LoginPage.tsx @@ -249,7 +249,7 @@ const LoginPage = () => { - + ); };