diff --git a/lib/api/users.js b/lib/api/users.js index c1b7d065..4609ec2b 100644 --- a/lib/api/users.js +++ b/lib/api/users.js @@ -2208,15 +2208,54 @@ module.exports = (db, server, userHandler, settingsHandler) => { ); server.del( - '/users/:user', + { + path: '/users/:user', + summary: 'Delete a User', + description: + 'This method deletes user and address entries from DB and schedules a background task to delete messages. You can call this method several times even if the user has already been deleted, in case there are still some pending messages.', + tags: ['Users'], + validationObjs: { + requestBody: {}, + queryParams: { + deleteAfter: Joi.date() + .empty('') + .allow(false) + .default(false) + .description( + 'Delete user entry from registry but keep all user data until provided date. User account is fully recoverable up to that date.' + ), + sess: sessSchema, + ip: sessIPSchema + }, + pathParams: { + user: userId + }, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes, + code: Joi.string().example('TaskScheduled').description('Task code. Should be TaskScheduled'), + user: Joi.string().description('User ID'), + addresses: Joi.object({ + deleted: Joi.number().description('Number of deleted addresses') + }), + deleteAfter: Joi.date().description('Delete after date'), + task: Joi.string().description('Task ID') + }) + } + } + } + }, tools.responseWrapper(async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - user: Joi.string().hex().lowercase().length(24).required(), - deleteAfter: Joi.date().empty('').allow(false).default(false), - sess: sessSchema, - ip: sessIPSchema + const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs; + + const schema = Joi.object({ + ...pathParams, + ...requestBody, + ...queryParams }); const result = schema.validate(req.params, { @@ -2262,14 +2301,44 @@ module.exports = (db, server, userHandler, settingsHandler) => { ); server.get( - '/users/:user/restore', + { + path: '/users/:user/restore', + summary: 'Return recovery info for a deleted user', + tags: ['Users'], + validationObjs: { + requestBody: {}, + queryParams: { + sess: sessSchema, + ip: sessIPSchema + }, + pathParams: { + user: userId + }, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes, + user: Joi.string().description('ID of the deleted User').required(), + username: Joi.string().description('Username of the User').required(), + storageUsed: Joi.number().description('Calculated quota usage for the user').required(), + tags: Joi.array().items(Joi.string()).description('List of tags associated with the User').required(), + deleted: Joi.date().description('Datestring of the time the user was deleted').required(), + recoverableAddresses: Joi.array().items(Joi.string()).description('List of email addresses that can be restored').required() + }) + } + } + } + }, tools.responseWrapper(async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - user: Joi.string().hex().lowercase().length(24).required(), - sess: sessSchema, - ip: sessIPSchema + const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs; + + const schema = Joi.object({ + ...pathParams, + ...requestBody, + ...queryParams }); const result = schema.validate(req.params, { @@ -2318,14 +2387,47 @@ module.exports = (db, server, userHandler, settingsHandler) => { ); server.post( - '/users/:user/restore', + { + path: '/users/:user/restore', + summary: 'Cancel user deletion task', + description: + 'Use this endpoint to cancel a timed deletion task scheduled by DELETE /user/{id}. If user data is not yet deleted then the account is fully recovered, except any email addresses that might have been already recycled', + tags: ['Users'], + validationObjs: { + requestBody: { + sess: sessSchema, + ip: sessIPSchema + }, + queryParams: {}, + pathParams: { + user: userId + }, + response: { + 200: { + description: 'Success', + model: Joi.object({ + success: successRes, + code: Joi.string().required().description('Task status code'), + user: Joi.string().description('User ID'), + task: Joi.string().description('Existing task id'), + addresses: Joi.object({ + recovered: Joi.number().description('Number of recovered addresses'), + main: Joi.string().description('Main address') + }) + }) + } + } + } + }, tools.responseWrapper(async (req, res) => { res.charSet('utf-8'); - const schema = Joi.object().keys({ - user: Joi.string().hex().lowercase().length(24).required(), - sess: sessSchema, - ip: sessIPSchema + const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs; + + const schema = Joi.object({ + ...pathParams, + ...requestBody, + ...queryParams }); const result = schema.validate(req.params, {