From 8e9af88a62960207d68f28fb71cd540be7a66fd5 Mon Sep 17 00:00:00 2001 From: NickOvt Date: Thu, 2 May 2024 09:55:36 +0300 Subject: [PATCH] fix(api-storage): Added all storage endpoints to API docs generation ZMS-149 (#675) * Added upload file api endpoint to api docs generaiton * added list stored files api endpoint to api docs generation * Added delete a File api endpoint to api docs generation * added Download file api endpoint to api docs generation --- lib/api/storage.js | 196 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 163 insertions(+), 33 deletions(-) diff --git a/lib/api/storage.js b/lib/api/storage.js index 5a50bf3c..32d7e76c 100644 --- a/lib/api/storage.js +++ b/lib/api/storage.js @@ -6,26 +6,58 @@ const ObjectId = require('mongodb').ObjectId; const tools = require('../tools'); const roles = require('../roles'); const consts = require('../consts'); -const { nextPageCursorSchema, previousPageCursorSchema, pageNrSchema, sessSchema, sessIPSchema } = require('../schemas'); +const { nextPageCursorSchema, previousPageCursorSchema, pageNrSchema, sessSchema, sessIPSchema, booleanSchema } = require('../schemas'); +const { userId } = require('../schemas/request/general-schemas'); +const { successRes, totalRes, pageRes, previousCursorRes, nextCursorRes } = require('../schemas/response/general-schemas'); module.exports = (db, server, storageHandler) => { server.post( - '/users/:user/storage', + { + path: '/users/:user/storage', + tags: ['Storage'], + summary: 'Upload file', + description: 'This method allows to upload an attachment to be linked from a draft', + validationObjs: { + requestBody: { + filename: Joi.string().empty('').max(255).description('Name of the file'), + contentType: Joi.string().empty('').max(255).description('MIME type of the file. Is detected from the file name by default'), + encoding: Joi.string() + .empty('') + .valid('base64') + .description( + 'Encoding of the file content. Useful if you want to upload the file in base64 encoded format. Valid options "base64", "hex", "utf8"' + ), + + content: Joi.binary().max(consts.MAX_ALLOWED_MESSAGE_SIZE).empty('').required().description('File content in binary'), + cid: Joi.string().empty('').max(255).description('content ID'), + + sess: sessSchema, + ip: sessIPSchema + }, + queryParams: {}, + pathParams: { + user: userId + }, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes, + id: Joi.string().required().description('File ID') + }) + } + } + } + }, tools.responseWrapper(async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - user: Joi.string().hex().lowercase().length(24).required(), + const { requestBody, queryParams, pathParams } = req.route.spec.validationObjs; - filename: Joi.string().empty('').max(255), - contentType: Joi.string().empty('').max(255), - encoding: Joi.string().empty('').valid('base64'), - - content: Joi.binary().max(consts.MAX_ALLOWED_MESSAGE_SIZE).empty('').required(), - cid: Joi.string().empty('').max(255), - - sess: sessSchema, - ip: sessIPSchema + const schema = Joi.object({ + ...requestBody, + ...queryParams, + ...pathParams }); if (!req.params.content && req.body && (Buffer.isBuffer(req.body) || typeof req.body === 'string')) { @@ -92,19 +124,69 @@ module.exports = (db, server, storageHandler) => { ); server.get( - '/users/:user/storage', + { + path: '/users/:user/storage', + tags: ['Storage'], + summary: 'List stored files', + validationObjs: { + requestBody: {}, + queryParams: { + query: Joi.string().trim().empty('').max(255).description('partial match of a filename'), + limit: Joi.number().default(20).min(1).max(250).description('How many records to return'), + next: nextPageCursorSchema, + previous: previousPageCursorSchema, + page: pageNrSchema, + sess: sessSchema, + ip: sessIPSchema + }, + pathParams: { + user: userId + }, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes, + total: totalRes, + page: pageRes, + previousCursor: previousCursorRes, + nextCursor: nextCursorRes, + results: Joi.array() + .items( + Joi.object({ + id: Joi.string().required().description('File ID'), + filename: Joi.alternatives() + .try(Joi.string().required(), booleanSchema.required()) + .required() + .description('Filename. False if none'), + contentType: Joi.alternatives() + .try(Joi.string().required(), booleanSchema.required()) + .required() + .description('Content-Type of the file. False if none'), + cid: Joi.string().description('Content ID'), + size: Joi.number().required().description('File size'), + created: Joi.date().required().description('Created datestring'), + md5: Joi.string().description('md5 hash').required() + }) + .required() + .$_setFlag('objectName', 'GetFilesResult') + ) + .required() + .description('File listing') + }) + } + } + } + }, tools.responseWrapper(async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - user: Joi.string().hex().lowercase().length(24).required(), - query: Joi.string().trim().empty('').max(255), - limit: Joi.number().default(20).min(1).max(250), - next: nextPageCursorSchema, - previous: previousPageCursorSchema, - page: pageNrSchema, - sess: sessSchema, - ip: sessIPSchema + const { requestBody, queryParams, pathParams } = req.route.spec.validationObjs; + + const schema = Joi.object({ + ...requestBody, + ...queryParams, + ...pathParams }); const result = schema.validate(req.params, { @@ -227,15 +309,39 @@ module.exports = (db, server, storageHandler) => { ); server.del( - '/users/:user/storage/:file', + { + path: '/users/:user/storage/:file', + tags: ['Storage'], + summary: 'Delete a File', + validationObjs: { + requestBody: {}, + queryParams: { + sess: sessSchema, + ip: sessIPSchema + }, + pathParams: { + user: userId, + file: Joi.string().hex().lowercase().length(24).required().description('ID of the File') + }, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes + }) + } + } + } + }, tools.responseWrapper(async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - user: Joi.string().hex().lowercase().length(24).required(), - file: Joi.string().hex().lowercase().length(24).required(), - sess: sessSchema, - ip: sessIPSchema + const { requestBody, queryParams, pathParams } = req.route.spec.validationObjs; + + const schema = Joi.object({ + ...requestBody, + ...queryParams, + ...pathParams }); const result = schema.validate(req.params, { @@ -271,11 +377,35 @@ module.exports = (db, server, storageHandler) => { ); server.get( - { name: 'storagefile', path: '/users/:user/storage/:file' }, + { + name: 'storagefile', + path: '/users/:user/storage/:file', + tags: ['Storage'], + summary: 'Download File', + description: 'This method returns stored file contents in binary form', + responseType: 'application/octet-stream', + validationObjs: { + requestBody: {}, + queryParams: {}, + pathParams: { + user: userId, + file: Joi.string().hex().lowercase().length(24).required().description('ID of the File') + }, + response: { + 200: { + description: 'Success', + model: Joi.binary() + } + } + } + }, tools.responseWrapper(async (req, res) => { - const schema = Joi.object().keys({ - user: Joi.string().hex().lowercase().length(24).required(), - file: Joi.string().hex().lowercase().length(24).required() + const { requestBody, queryParams, pathParams } = req.route.spec.validationObjs; + + const schema = Joi.object({ + ...requestBody, + ...queryParams, + ...pathParams }); const result = schema.validate(req.params, {