mirror of
https://github.com/nodemailer/wildduck.git
synced 2025-10-09 13:29:47 +08:00
update
This commit is contained in:
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
|
@ -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"
}
});
|
||||||
|
|
|
@ -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"
}
}
|
||||||
|
|
|
@ -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
|
* @api {get} /users/:user/mailboxes/:mailbox/messages List messages in a Mailbox
|
||||||
* @apiName GetMessages
|
* @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
|
* @apiName PutMessage
|
||||||
* @apiGroup Messages
|
* @apiGroup Messages
|
||||||
* @apiDescription This method updates message flags and also allows to move messages to a different mailbox
|
* @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
|
* @apiError error Description of the error
|
||||||
*
|
*
|
||||||
* @apiExample {curl} Mark messages as unseen:
|
* @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' \
|
* -H 'Content-type: application/json' \
|
||||||
* -d '{
|
* -d '{
|
||||||
|
* "message": "1,2,3",
|
||||||
* "seen": false
|
* "seen": false
|
||||||
* }'
|
* }'
|
||||||
*
|
*
|
||||||
|
@ -1735,173 +1901,8 @@ module.exports = (db, server, messageHandler) => {
|
||||||
* "error": "Database error"
|
* "error": "Database error"
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
server.put(
|
server.put('/users/:user/mailboxes/:mailbox/messages/:message', tools.asyncifyJson(putMessageHandler));
|
||||||
'/users/:user/mailboxes/:mailbox/messages/:message',
|
server.put('/users/:user/mailboxes/:mailbox/messages', tools.asyncifyJson(putMessageHandler));
|
||||||
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();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {delete} /users/:user/mailboxes/:mailbox/messages/:message Delete a Message
|
* @api {delete} /users/:user/mailboxes/:mailbox/messages/:message Delete a Message
|
||||||
|
|
Loading…
Add table
Reference in a new issue