From 66c579eb7b61298155dc22fa4e2ba4fcffb015e2 Mon Sep 17 00:00:00 2001 From: Sergio Gutierrez Villalba Date: Tue, 26 Sep 2023 14:08:43 +0200 Subject: [PATCH] feat(folder): check existence EP --- src/app/routes/storage.ts | 27 ++++++++++++++++++++++ src/app/services/folder.js | 46 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/src/app/routes/storage.ts b/src/app/routes/storage.ts index abee64be..58061197 100644 --- a/src/app/routes/storage.ts +++ b/src/app/routes/storage.ts @@ -182,6 +182,32 @@ export class StorageController { }); } + public async checkFolderExistence(req: Request, res: Response): Promise { + const { name, parentId } = req.body; + const { behalfUser: user } = req as any; + + if (Validator.isInvalidString(name)) { + throw createHttpError(400, 'Folder name must be a valid string'); + } + + if (!parentId || parentId <= 0) { + throw createHttpError(400, 'Invalid parent folder id'); + } + + return this.services.Folder.CheckFolderExistence(user, name, parentId) + .then((result: { folder: FolderAttributes, exists: boolean }) => { + if (result.exists) { + res.status(200).json(result); + } else { + res.status(404).send(); + } + }) + .catch((err: Error) => { + this.logger.error(`Error checking folder existence for user ${user.id}: ${err}`); + res.status(500).send(); + }); + } + public async getTree(req: Request, res: Response): Promise { const { user } = req as PassportRequest; const deleted = req.query?.trash === 'true'; @@ -794,6 +820,7 @@ export default (router: Router, service: any) => { controller.createThumbnail.bind(controller) ); router.post('/storage/folder', passportAuth, sharedAdapter, controller.createFolder.bind(controller)); + router.post('/storage/folder/exists', passportAuth, sharedAdapter, controller.checkFolderExistence.bind(controller)); router.get('/storage/tree', passportAuth, controller.getTree.bind(controller)); router.get('/storage/tree/:folderId', passportAuth, controller.getTreeSpecific.bind(controller)); router.delete('/storage/folder/:id', passportAuth, sharedAdapter, controller.deleteFolder.bind(controller)); diff --git a/src/app/services/folder.js b/src/app/services/folder.js index b94f98e5..2f712670 100644 --- a/src/app/services/folder.js +++ b/src/app/services/folder.js @@ -127,6 +127,51 @@ module.exports = (Model, App) => { return folder; }; + const CheckFolderExistence = async (user, folderName, parentFolderId) => { + if (parentFolderId >= 2147483648) { + throw Error('Invalid parent folder'); + } + const isGuest = user.email !== user.bridgeUser; + + if (isGuest) { + const { bridgeUser } = user; + + user = await Model.users.findOne({ + where: { username: bridgeUser }, + }); + } + + const parentFolder = await Model.folder.findOne({ + id: { [Op.eq]: parentFolderId }, + user_id: { [Op.eq]: user.id }, + }); + + if (!parentFolder) { + throw Error('Parent folder is not yours'); + } + + if (folderName === '' || invalidName.test(folderName)) { + throw Error('Invalid folder name'); + } + + // Encrypt folder name, TODO: use versioning for encryption + const cryptoFolderName = App.services.Crypt.encryptName(folderName, parentFolderId); + + const maybeExistentFolder = await Model.folder.findOne({ + where: { + parentId: { [Op.eq]: parentFolderId }, + name: { [Op.eq]: cryptoFolderName }, + deleted: { [Op.eq]: false }, + }, + }); + + if (maybeExistentFolder) { + return { exists: true, folder: maybeExistentFolder }; + } + + return { exists: false, folder: null }; + }; + // Requires stored procedure const DeleteOrphanFolders = async (userId) => { const clear = await App.database.query('CALL clear_orphan_folders_by_user (:userId, :output)', { @@ -772,6 +817,7 @@ module.exports = (Model, App) => { Name: 'Folder', getById, Create, + CheckFolderExistence, Delete, GetChildren, GetTree,