diff --git a/lib/api/messages.js b/lib/api/messages.js index ad0e2105..6d32cdd7 100644 --- a/lib/api/messages.js +++ b/lib/api/messages.js @@ -154,24 +154,12 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti const putMessageHandler = async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - user: Joi.string().hex().lowercase().length(24).required(), - mailbox: Joi.string().hex().lowercase().length(24).required(), - moveTo: Joi.string().hex().lowercase().length(24), + const { requestBody, queryParams, pathParams } = req.route.spec.validationObjs; - message: Joi.string() - .regex(/^\d+(,\d+)*$|^\d+:(\d+|\*)$/i) - .required(), - - seen: booleanSchema, - deleted: booleanSchema, - flagged: booleanSchema, - draft: booleanSchema, - expires: Joi.alternatives().try(Joi.date(), booleanSchema.allow(false)), - metaData: metaDataSchema.label('metaData'), - - sess: sessSchema, - ip: sessIPSchema + const schema = Joi.object({ + ...requestBody, + ...queryParams, + ...pathParams }); const result = schema.validate(req.params, { @@ -1694,20 +1682,139 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti }) ); - server.put('/users/:user/mailboxes/:mailbox/messages/:message', tools.responseWrapper(putMessageHandler)); - server.put('/users/:user/mailboxes/:mailbox/messages', tools.responseWrapper(putMessageHandler)); + server.put( + { + path: '/users/:user/mailboxes/:mailbox/messages/:message', + tags: ['Messages'], + summary: 'Update message information with path param', + description: 'This method updates message flags and also allows to move messages to a different mailbox', + validationObjs: { + requestBody: { + moveTo: Joi.string().hex().lowercase().length(24).description('ID of the target Mailbox if you want to move messages'), + + seen: booleanSchema.description('State of the \\Seen flag'), + deleted: booleanSchema.description('State of the \\Deleted flag'), + flagged: booleanSchema.description('State of the \\Flagged flag'), + draft: booleanSchema.description('State of the \\Draft flag'), + expires: Joi.alternatives() + .try(Joi.date(), booleanSchema.allow(false)) + .description('Either expiration date or false to turn off autoexpiration'), + metaData: metaDataSchema.label('metaData').description('Optional metadata, must be an object or JSON formatted string'), + + sess: sessSchema, + ip: sessIPSchema + }, + queryParams: {}, + pathParams: { + user: userId, + mailbox: mailboxId, + message: Joi.string() + .regex(/^\d+(,\d+)*$|^\d+:(\d+|\*)$/i) + .required() + .description( + 'Message ID. Either singular or comma separated number (1,2,3) or colon separated range (3:15), or a range from UID to end (3:*)' + ) + }, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes, + id: Joi.array() + .items(Joi.object({})) + .description( + 'If messages were moved then lists new ID values. Array entry is an array with first element pointing to old ID and second to new ID' + ), + mailbox: Joi.string().description('MoveTo mailbox address'), + updated: Joi.number().description('If messages were not moved, then indicates the number of updated messages') + }) + } + } + } + }, + tools.responseWrapper(putMessageHandler) + ); + server.put( + { + path: '/users/:user/mailboxes/:mailbox/messages', + tags: ['Messages'], + summary: 'Update Message information', + description: 'This method updates message flags and also allows to move messages to a different mailbox', + validationObjs: { + requestBody: { + message: Joi.string() + .regex(/^\d+(,\d+)*$|^\d+:(\d+|\*)$/i) + .required() + .description( + 'Message ID. Either singular or comma separated number (1,2,3) or colon separated range (3:15), or a range from UID to end (3:*)' + ), + moveTo: Joi.string().hex().lowercase().length(24).description('ID of the target Mailbox if you want to move messages'), + + seen: booleanSchema.description('State of the \\Seen flag'), + deleted: booleanSchema.description('State of the \\Deleted flag'), + flagged: booleanSchema.description('State of the \\Flagged flag'), + draft: booleanSchema.description('State of the \\Draft flag'), + expires: Joi.alternatives() + .try(Joi.date(), booleanSchema.allow(false)) + .description('Either expiration date or false to turn off autoexpiration'), + metaData: metaDataSchema.label('metaData').description('Optional metadata, must be an object or JSON formatted string'), + + sess: sessSchema, + ip: sessIPSchema + }, + queryParams: {}, + pathParams: { + user: userId, + mailbox: mailboxId + }, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes, + id: Joi.array() + .items(Joi.object({})) + .description( + 'If messages were moved then lists new ID values. Array entry is an array with first element pointing to old ID and second to new ID' + ), + mailbox: Joi.string().description('MoveTo mailbox address'), + updated: Joi.number().description('If messages were not moved, then indicates the number of updated messages') + }) + } + } + } + }, + tools.responseWrapper(putMessageHandler) + ); server.del( - '/users/:user/mailboxes/:mailbox/messages/:message', + { + path: '/users/:user/mailboxes/:mailbox/messages/:message', + tags: ['Messages'], + summary: 'Delete a Message', + validationObjs: { + requestBody: {}, + queryParams: { + sess: sessSchema, + ip: sessIPSchema + }, + pathParams: { + user: userId, + mailbox: mailboxId, + message: messageId + }, + 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(), - mailbox: Joi.string().hex().lowercase().length(24).required(), - message: Joi.number().min(1).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, { @@ -1775,18 +1882,44 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti ); server.del( - '/users/:user/mailboxes/:mailbox/messages', + { + path: '/users/:user/mailboxes/:mailbox/messages', + tags: ['Messages'], + summary: 'Delete all Messages from a Mailbox', + validationObjs: { + requestBody: {}, + queryParams: { + async: booleanSchema.default(false).description('Schedule deletion task'), + + skipArchive: booleanSchema.default(false).description('Skip archived messages'), + sess: sessSchema, + ip: sessIPSchema + }, + pathParams: { + user: userId, + mailbox: mailboxId + }, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes, + deleted: Joi.number().required().description('Indicates the count of deleted messages'), + errors: Joi.number().required().description('Indicate the count of errors during the delete') + }) + } + } + } + }, tools.responseWrapper(async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - user: Joi.string().hex().lowercase().length(24).required(), - mailbox: Joi.string().hex().lowercase().length(24).required(), - async: booleanSchema.default(false), + const { requestBody, queryParams, pathParams } = req.route.spec.validationObjs; - skipArchive: booleanSchema.default(false), - sess: sessSchema, - ip: sessIPSchema + const schema = Joi.object({ + ...requestBody, + ...queryParams, + ...pathParams }); const result = schema.validate(req.params, { @@ -1977,13 +2110,16 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti 200: { description: 'Success', model: Joi.object({ - success: Joi.boolean().description('Indicates successful response'), + success: successRes, message: Joi.object({ - id: Joi.number(), - malbox: Joi.string(), - size: Joi.number() - }).description('Message information'), - previousDeleted: Joi.boolean().description('Set if replacing a previous message was requested') + id: Joi.number().required().description('Message ID in mailbox'), + malbox: Joi.string().required().description('Mailbox ID the message was stored into'), + size: Joi.number().required().description('Size of the RFC822 formatted email') + }) + .required() + .description('Message information'), + previousDeleted: booleanSchema.description('Set if replacing a previous message was requested'), + previousDeleteError: Joi.string().description('Previus delete error message') }) } } @@ -2366,14 +2502,14 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti 200: { description: 'Success', model: Joi.object({ - success: Joi.boolean().description('Indicates successful response'), + success: successRes, queueId: Joi.string().description('Message ID in outbound queue'), forwarded: Joi.array() .items( Joi.object({ - seq: Joi.string(), - type: Joi.string(), - value: Joi.string() + seq: Joi.string().required().description('Sequence ID'), + type: Joi.string().required().description('Target type'), + value: Joi.string().required().description('Target address') }).$_setFlag('objectName', 'Forwarded') ) .description('Information about forwarding targets') @@ -2573,12 +2709,12 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti 200: { description: 'Success', model: Joi.object({ - success: booleanSchema.description('Indicates successful response').required(), + success: successRes, queueId: Joi.string().description('Message ID in outbound queue').required(), message: Joi.object({ id: Joi.number().description('Message ID in mailbox').required(), mailbox: Joi.string().description('Mailbox ID the message was stored into').required(), - size: Joi.number().description('Size of the RFC822 formatted email') + size: Joi.number().required().description('Size of the RFC822 formatted email') }) .description('Message information') .$_setFlag('objectName', 'Message') @@ -2938,15 +3074,40 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti ); server.del( - '/users/:user/outbound/:queueId', + { + path: '/users/:user/outbound/:queueId', + tags: ['Messages'], + summary: 'Delete an Outbound Message', + description: 'You can delete outbound emails that are still in queue. Queue ID can be found from the `outbound` property of a stored email.', + validationObjs: { + requestBody: {}, + queryParams: { + sess: sessSchema, + ip: sessIPSchema + }, + pathParams: { + user: userId, + queueId: Joi.string().hex().lowercase().min(18).max(24).required().description('Outbound queue ID of the message') + }, + 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(), - queueId: Joi.string().hex().lowercase().min(18).max(24).required(), - sess: sessSchema, - ip: sessIPSchema + const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs; + + const schema = Joi.object({ + ...pathParams, + ...queryParams, + ...requestBody }); const result = schema.validate(req.params, {