Skip to content

Commit

Permalink
feat(api-mailboxes): Mailboxes API endpoints added to automatic API d…
Browse files Browse the repository at this point in the history
…ocs generation ZMS-114 (#602)

* added List Mailboxes for a User endpoint to API generation

* Request Mailbox information endpoint added to API generation

* Update Mailbox information endpoint added to API generation

* added Delete a Mailbox endpoint to API generation. Add example to Request Mailbox information API endpoint

* fix mailbox path param in Request Mailbox information

* GetMailboxesResult retention should be not required, fix accidental typo
  • Loading branch information
NickOvt authored Jan 12, 2024
1 parent 5721047 commit 76d0e8f
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 31 deletions.
182 changes: 151 additions & 31 deletions lib/api/mailboxes.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const util = require('util');
const { sessSchema, sessIPSchema, booleanSchema } = require('../schemas');
const { userId, mailboxId } = require('../schemas/request/general-schemas');
const { successRes } = require('../schemas/response/general-schemas');
const { GetMailboxesResult } = require('../schemas/response/mailboxes-schemas');

module.exports = (db, server, mailboxHandler) => {
const getMailboxCounter = util.promisify(tools.getMailboxCounter);
Expand All @@ -17,18 +18,50 @@ module.exports = (db, server, mailboxHandler) => {
const createMailbox = mailboxHandler.createAsync.bind(mailboxHandler);

server.get(
'/users/:user/mailboxes',
{
path: '/users/:user/mailboxes',
tags: ['Mailboxes'],
summary: 'List Mailboxes for a User',
validationObjs: {
requestBody: {},
pathParams: {
user: userId
},
queryParams: {
specialUse: booleanSchema.default(false).description('Should the response include only folders with specialUse flag set.'),
showHidden: booleanSchema.default(false).description('Hidden folders are not included in the listing by default.'),
counters: booleanSchema
.default(false)
.description('Should the response include counters (total + unseen). Counters come with some overhead.'),
sizes: booleanSchema
.default(false)
.description(
'Should the response include mailbox size in bytes. Size numbers come with a lot of overhead as an aggregated query is ran.'
),
sess: sessSchema,
ip: sessIPSchema
},

response: {
200: {
description: 'Success',
model: Joi.object({
success: successRes,
results: Joi.array().items(GetMailboxesResult).description('List of user mailboxes').required()
})
}
}
}
},
tools.responseWrapper(async (req, res) => {
res.charSet('utf-8');

const schema = Joi.object().keys({
user: Joi.string().hex().lowercase().length(24).required(),
specialUse: booleanSchema.default(false),
showHidden: booleanSchema.default(false),
counters: booleanSchema.default(false),
sizes: booleanSchema.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, {
Expand Down Expand Up @@ -329,15 +362,56 @@ module.exports = (db, server, mailboxHandler) => {
);

server.get(
'/users/:user/mailboxes/:mailbox',
{
path: '/users/:user/mailboxes/:mailbox',
summary: 'Request Mailbox information',
tags: ['Mailboxes'],
validationObjs: {
requestBody: {},
queryParams: {
path: Joi.string()
.regex(/\/{2,}|\/$/, { invert: true })
.description('If mailbox is specified as `resolve` in the path then use this param as mailbox path instead of the given mailbox id.'),
sess: sessSchema,
ip: sessIPSchema
},
pathParams: {
user: userId,
mailbox: mailboxId.allow('resolve')
},
response: {
200: {
description: 'Success',
model: Joi.object({
success: successRes,
id: mailboxId,
name: Joi.string().required().description('Name for the mailbox (unicode string)'),
path: Joi.string()
.required()
.description('Full path of the mailbox, folders are separated by slashes, ends with the mailbox name (unicode string)'),
specialUse: Joi.string()
.required()
.example('\\Draft')
.description('Either special use identifier or null. One of Drafts, Junk, Sent or Trash'),
modifyIndex: Joi.number().required().description('Modification sequence number. Incremented on every change in the mailbox.'),
subscribed: booleanSchema.required().description('Mailbox subscription status. IMAP clients may unsubscribe from a folder.'),
hidden: booleanSchema.required().description('Is the folder hidden or not'),
total: Joi.number().required().description('How many messages are stored in this mailbox'),
unseen: Joi.number().required().description('How many unseen messages are stored in this mailbox')
})
}
}
}
},
tools.responseWrapper(async (req, res) => {
res.charSet('utf-8');

const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs;

const schema = Joi.object({
user: Joi.string().hex().lowercase().length(24).required(),
mailbox: Joi.string().hex().lowercase().length(24).allow('resolve').required(),
path: Joi.string().regex(/\/{2,}|\/$/, { invert: true }),
sess: sessSchema,
ip: sessIPSchema
...pathParams,
...requestBody,
...queryParams
});

const result = schema.validate(req.params, {
Expand Down Expand Up @@ -457,19 +531,47 @@ module.exports = (db, server, mailboxHandler) => {
);

server.put(
'/users/:user/mailboxes/:mailbox',
{
path: '/users/:user/mailboxes/:mailbox',
summary: 'Update Mailbox information',
tags: ['Mailboxes'],
validationObjs: {
requestBody: {
path: Joi.string()
.regex(/\/{2,}|\/$/, { invert: true })
.description('Full path of the mailbox, use this to rename an existing Mailbox'),
retention: Joi.number()
.empty('')
.min(0)
.description(
'Retention policy for the Mailbox (in ms). Changing retention value only affects messages added to this folder after the change'
),
subscribed: booleanSchema.description('Change Mailbox subscription state'),
hidden: booleanSchema.description('Is the folder hidden or not. Hidden folders can not be opened in IMAP.'),
sess: sessSchema,
ip: sessIPSchema
},
pathParams: { user: userId, mailbox: mailboxId },
queryParams: {},
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(),
path: Joi.string().regex(/\/{2,}|\/$/, { invert: true }),
retention: Joi.number().empty('').min(0),
subscribed: booleanSchema,
hidden: booleanSchema,
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, {
Expand Down Expand Up @@ -521,15 +623,33 @@ module.exports = (db, server, mailboxHandler) => {
);

server.del(
'/users/:user/mailboxes/:mailbox',
{
path: '/users/:user/mailboxes/:mailbox',
summary: 'Delete a Mailbox',
tags: ['Mailboxes'],
validationObjs: {
requestBody: { user: userId, mailbox: mailboxId },
queryParams: { sess: sessSchema, ip: sessIPSchema },
pathParams: {},
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(),
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, {
Expand Down
25 changes: 25 additions & 0 deletions lib/schemas/response/mailboxes-schemas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';

const Joi = require('joi');
const { mailboxId } = require('../request/general-schemas');
const { booleanSchema } = require('../../schemas');

const GetMailboxesResult = Joi.object({
id: mailboxId,
name: Joi.string().required().description('Name for the mailbox (unicode string)'),
path: Joi.string().required().description('Full path of the mailbox, folders are separated by slashes, ends with the mailbox name (unicode string)'),
specialUse: Joi.string().required().description('Either special use identifier or null. One of Drafts, Junk, Sent or Trash'),
modifyIndex: Joi.number().required().description('Modification sequence number. Incremented on every change in the mailbox.'),
subscribed: booleanSchema.required().description('Mailbox subscription status. IMAP clients may unsubscribe from a folder.'),
retention: Joi.number().description(
'Default retention policy for this mailbox (in ms). If set then messages added to this maibox will be automatically deleted after retention time.'
),
hidden: booleanSchema.required().description('Is the folder hidden or not'),
total: Joi.number().required().description('How many messages are stored in this mailbox'),
unseen: Joi.number().required().description('How many unseen messages are stored in this mailbox'),
size: Joi.number().description('Total size of mailbox in bytes.')
});

module.exports = {
GetMailboxesResult
};

0 comments on commit 76d0e8f

Please sign in to comment.