This commit is contained in:
Andris Reinman 2018-09-10 10:46:19 +03:00
parent c811e9bd9f
commit 0bc00fcbc7
5 changed files with 174 additions and 173 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
define({ "name": "wildduck", "version": "1.0.0", "description": "WildDuck API docs", "title": "WildDuck API", "url": "https://api.wildduck.email", "sampleUrl": false, "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2018-09-07T07:55:56.519Z", "url": "http://apidocjs.com", "version": "0.17.6" } });
define({ "name": "wildduck", "version": "1.0.0", "description": "WildDuck API docs", "title": "WildDuck API", "url": "https://api.wildduck.email", "sampleUrl": false, "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2018-09-10T07:46:13.698Z", "url": "http://apidocjs.com", "version": "0.17.6" } });

View file

@ -1 +1 @@
{ "name": "wildduck", "version": "1.0.0", "description": "WildDuck API docs", "title": "WildDuck API", "url": "https://api.wildduck.email", "sampleUrl": false, "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2018-09-07T07:55:56.519Z", "url": "http://apidocjs.com", "version": "0.17.6" } }
{ "name": "wildduck", "version": "1.0.0", "description": "WildDuck API docs", "title": "WildDuck API", "url": "https://api.wildduck.email", "sampleUrl": false, "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2018-09-10T07:46:13.698Z", "url": "http://apidocjs.com", "version": "0.17.6" } }

View file

@ -50,6 +50,171 @@ module.exports = (db, server, messageHandler) => {
});
});
const putMessageHandler = async (req, res, next) => {
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),
message: Joi.string()
.regex(/^\d+(,\d+)*$|^\d+:\d+$/i)
.required(),
seen: Joi.boolean()
.truthy(['Y', 'true', 'yes', 'on', 1])
.falsy(['N', 'false', 'no', 'off', 0, '']),
deleted: Joi.boolean()
.truthy(['Y', 'true', 'yes', 'on', 1])
.falsy(['N', 'false', 'no', 'off', 0, '']),
flagged: Joi.boolean()
.truthy(['Y', 'true', 'yes', 'on', 1])
.falsy(['N', 'false', 'no', 'off', 0, '']),
draft: Joi.boolean()
.truthy(['Y', 'true', 'yes', 'on', 1])
.falsy(['N', 'false', 'no', 'off', 0, '']),
expires: Joi.alternatives().try(
Joi.date(),
Joi.boolean()
.truthy(['Y', 'true', 'yes', 'on', 1])
.falsy(['N', 'false', 'no', 'off', 0, ''])
.allow(false)
),
sess: Joi.string().max(255),
ip: Joi.string().ip({
version: ['ipv4', 'ipv6'],
cidr: 'forbidden'
})
});
const result = Joi.validate(req.params, schema, {
abortEarly: false,
convert: true
});
if (result.error) {
res.json({
error: result.error.message,
code: 'InputValidationError'
});
return next();
}
// permissions check
if (req.user && req.user === result.value.user) {
req.validate(roles.can(req.role).updateOwn('messages'));
} else {
req.validate(roles.can(req.role).updateAny('messages'));
}
let user = new ObjectID(result.value.user);
let mailbox = new ObjectID(result.value.mailbox);
let moveTo = result.value.moveTo ? new ObjectID(result.value.moveTo) : false;
let message = result.value.message;
let messageQuery;
if (/^\d+$/.test(message)) {
messageQuery = Number(message);
} else if (/^\d+(,\d+)*$/.test(message)) {
messageQuery = {
$in: message
.split(',')
.map(uid => Number(uid))
.sort((a, b) => a - b)
};
} else if (/^\d+:\d+$/.test(message)) {
let parts = message
.split(':')
.map(uid => Number(uid))
.sort((a, b) => a - b);
if (parts[0] === parts[1]) {
messageQuery = parts[0];
} else {
messageQuery = {
$gte: parts[0],
$lte: parts[1]
};
}
} else {
res.json({
error: 'Invalid message identifier',
code: 'NoSuchMessage'
});
return next();
}
if (moveTo) {
let info;
try {
let data = await moveMessage({
user,
source: { user, mailbox },
destination: { user, mailbox: moveTo },
updates: result.value,
messageQuery
});
info = data.info;
} catch (err) {
res.json({
error: err.message,
code: err.code
});
return next();
}
if (!info || !info.destinationUid || !info.destinationUid.length) {
res.json({
error: 'Could not move message, check if message exists',
code: 'NoSuchMessage'
});
return next();
}
res.json({
success: true,
mailbox: moveTo,
id: info && info.sourceUid && info.sourceUid.map((uid, i) => [uid, info.destinationUid && info.destinationUid[i]])
});
return next();
}
let updated;
try {
updated = await updateMessage(user, mailbox, messageQuery, result.value);
} catch (err) {
res.json({
error: err.message,
code: err.code
});
return next();
}
if (!updated) {
res.json({
error: 'No message matched query',
code: 'NoSuchMessage'
});
return next();
}
res.json({
success: true,
updated
});
return next();
};
/**
* @api {get} /users/:user/mailboxes/:mailbox/messages List messages in a Mailbox
* @apiName GetMessages
@ -1679,7 +1844,7 @@ module.exports = (db, server, messageHandler) => {
);
/**
* @api {put} /users/:user/mailboxes/:mailbox/messages/:message Update Message information
* @api {put} /users/:user/mailboxes/:mailbox/messages Update Message information
* @apiName PutMessage
* @apiGroup Messages
* @apiDescription This method updates message flags and also allows to move messages to a different mailbox
@ -1705,9 +1870,10 @@ module.exports = (db, server, messageHandler) => {
* @apiError error Description of the error
*
* @apiExample {curl} Mark messages as unseen:
* curl -i -XPUT "http://localhost:8080/users/59fc66a03e54454869460e45/mailboxes/59fc66a03e54454869460e46/messages/1,2,3" \
* curl -i -XPUT "http://localhost:8080/users/59fc66a03e54454869460e45/mailboxes/59fc66a03e54454869460e46/messages" \
* -H 'Content-type: application/json' \
* -d '{
* "message": "1,2,3",
* "seen": false
* }'
*
@ -1735,173 +1901,8 @@ module.exports = (db, server, messageHandler) => {
* "error": "Database error"
* }
*/
server.put(
'/users/:user/mailboxes/:mailbox/messages/:message',
tools.asyncifyJson(async (req, res, next) => {
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),
message: Joi.string()
.regex(/^\d+(,\d+)*$|^\d+:\d+$/i)
.required(),
seen: Joi.boolean()
.truthy(['Y', 'true', 'yes', 'on', 1])
.falsy(['N', 'false', 'no', 'off', 0, '']),
deleted: Joi.boolean()
.truthy(['Y', 'true', 'yes', 'on', 1])
.falsy(['N', 'false', 'no', 'off', 0, '']),
flagged: Joi.boolean()
.truthy(['Y', 'true', 'yes', 'on', 1])
.falsy(['N', 'false', 'no', 'off', 0, '']),
draft: Joi.boolean()
.truthy(['Y', 'true', 'yes', 'on', 1])
.falsy(['N', 'false', 'no', 'off', 0, '']),
expires: Joi.alternatives().try(
Joi.date(),
Joi.boolean()
.truthy(['Y', 'true', 'yes', 'on', 1])
.falsy(['N', 'false', 'no', 'off', 0, ''])
.allow(false)
),
sess: Joi.string().max(255),
ip: Joi.string().ip({
version: ['ipv4', 'ipv6'],
cidr: 'forbidden'
})
});
const result = Joi.validate(req.params, schema, {
abortEarly: false,
convert: true
});
if (result.error) {
res.json({
error: result.error.message,
code: 'InputValidationError'
});
return next();
}
// permissions check
if (req.user && req.user === result.value.user) {
req.validate(roles.can(req.role).updateOwn('messages'));
} else {
req.validate(roles.can(req.role).updateAny('messages'));
}
let user = new ObjectID(result.value.user);
let mailbox = new ObjectID(result.value.mailbox);
let moveTo = result.value.moveTo ? new ObjectID(result.value.moveTo) : false;
let message = result.value.message;
let messageQuery;
if (/^\d+$/.test(message)) {
messageQuery = Number(message);
} else if (/^\d+(,\d+)*$/.test(message)) {
messageQuery = {
$in: message
.split(',')
.map(uid => Number(uid))
.sort((a, b) => a - b)
};
} else if (/^\d+:\d+$/.test(message)) {
let parts = message
.split(':')
.map(uid => Number(uid))
.sort((a, b) => a - b);
if (parts[0] === parts[1]) {
messageQuery = parts[0];
} else {
messageQuery = {
$gte: parts[0],
$lte: parts[1]
};
}
} else {
res.json({
error: 'Invalid message identifier',
code: 'NoSuchMessage'
});
return next();
}
if (moveTo) {
let info;
try {
let data = await moveMessage({
user,
source: { user, mailbox },
destination: { user, mailbox: moveTo },
updates: result.value,
messageQuery
});
info = data.info;
} catch (err) {
res.json({
error: err.message,
code: err.code
});
return next();
}
if (!info || !info.destinationUid || !info.destinationUid.length) {
res.json({
error: 'Could not move message, check if message exists',
code: 'NoSuchMessage'
});
return next();
}
res.json({
success: true,
mailbox: moveTo,
id: info && info.sourceUid && info.sourceUid.map((uid, i) => [uid, info.destinationUid && info.destinationUid[i]])
});
return next();
}
let updated;
try {
updated = await updateMessage(user, mailbox, messageQuery, result.value);
} catch (err) {
res.json({
error: err.message,
code: err.code
});
return next();
}
if (!updated) {
res.json({
error: 'No message matched query',
code: 'NoSuchMessage'
});
return next();
}
res.json({
success: true,
updated
});
return next();
})
);
server.put('/users/:user/mailboxes/:mailbox/messages/:message', tools.asyncifyJson(putMessageHandler));
server.put('/users/:user/mailboxes/:mailbox/messages', tools.asyncifyJson(putMessageHandler));
/**
* @api {delete} /users/:user/mailboxes/:mailbox/messages/:message Delete a Message