added api docs for filters

This commit is contained in:
Andris Reinman 2017-11-27 15:56:49 +02:00
parent 6a56201b78
commit 9dd052e18c
6 changed files with 619 additions and 263 deletions

View file

@ -88,7 +88,7 @@ node server.js --config=/etc/wildduck.toml
### Step 4\. Create an user account
See [API Docs](https://github.com/nodemailer/wildduck/wiki/API-Docs#add-a-new-user) for details about creating new user accounts
See [API Docs](https://api.wildduck.email/#api-Users-PostUser) for details about creating new user accounts
### Step 5\. Use an IMAP/POP3 client to log in
@ -107,15 +107,15 @@ Any IMAP or POP3 client will do. Use the credentials from step 4\. to log in.
Users, mailboxes and messages can be managed with HTTP requests against Wild Duck API
### [API Docs](https://github.com/nodemailer/wildduck/wiki/API-Docs)
**[API Docs](https://api.wildduck.email/)**
# FAQ
### Does it work?
Yes, it does. You can run the server and get working IMAP and POP3 servers for mail store, LMTP server for pushing messages to the mail store and HTTP API
server to create new users. All handled by Node.js, MongoDB and Redis, no additional dependencies needed. Provided services can be disabled and enabled one by
one so, for example you could process just IMAP in one host and LMTP in another.
Yes, it does. You can run the server and get working IMAP and POP3 servers for mail store, LMTP server for pushing messages to the mail store and
[HTTP API](https://api.wildduck.email/) server to create new users. All handled by Node.js, MongoDB and Redis, no additional dependencies needed. Provided
services can be disabled and enabled one by one so, for example you could process just IMAP in one host and LMTP in another.
### How is security implemented in Wild Duck?
@ -134,8 +134,8 @@ Read about Wild Duck security implementation from the [Wiki](https://github.com/
5. **Works on any OS including Windows.** At least if you get MongoDB and Redis running first.
6. Focus on **internationalization**, ie. supporting email addresses with non-ascii characters
7. **Deduplication of attachments.** If the same attachment is referenced by different messages then only a single copy of the attachment is stored.
8. Access messages both using **IMAP and HTTP API**. The latter serves parsed data, so no need to fetch RFC822 messages and parse out html, plaintext content or
attachments. It is super easy to create a webmail interface on top of this.
8. Access messages both using **IMAP and [HTTP API](https://api.wildduck.email/)**. The latter serves parsed data, so no need to fetch RFC822 messages and parse
out html, plaintext content or attachments. It is super easy to create a webmail interface on top of this.
9. Built in **address labels**: _username+label@example.com_ is delivered to _username@example.com_
10. Dots in usernames and addresses are informational only. username@example.com is the same as user.name@example.com
11. **HTTP Event Source** to push modifications in user email account to browser for super snappy webmail clients
@ -250,7 +250,7 @@ If a messages is deleted by a client this message gets marked as Seen and moved
Wild Duck has built-in message filtering in LMTP server. This is somewhat similar to Sieve even though the filters are not scripts.
Filters can be managed via the [Wild Duck API](https://github.com/nodemailer/wildduck/wiki/API-Docs).
Filters can be managed via the [Wild Duck API](https://api.wildduck.email/#api-Filters).
## IMAP Protocol Differences

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": "http://localhost:8080", "sampleUrl": false, "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2017-11-27T12:20:35.334Z", "url": "http://apidocjs.com", "version": "0.17.6" } });
define({ "name": "wildduck", "version": "1.0.0", "description": "WildDuck API docs", "title": "WildDuck API", "url": "http://localhost:8080", "sampleUrl": false, "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2017-11-27T13:55:26.682Z", "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": "http://localhost:8080", "sampleUrl": false, "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2017-11-27T12:20:35.334Z", "url": "http://apidocjs.com", "version": "0.17.6" } }
{ "name": "wildduck", "version": "1.0.0", "description": "WildDuck API docs", "title": "WildDuck API", "url": "http://localhost:8080", "sampleUrl": false, "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2017-11-27T13:55:26.682Z", "url": "http://apidocjs.com", "version": "0.17.6" } }

View file

@ -5,11 +5,69 @@ const ObjectID = require('mongodb').ObjectID;
const urllib = require('url');
module.exports = (db, server) => {
/**
* @api {get} /users/:user/filters List Filters for an User
* @apiName GetFilters
* @apiGroup Filters
* @apiHeader {String} X-Access-Token Optional access token if authentication is enabled
* @apiHeaderExample {json} Header-Example:
* {
* "X-Access-Token": "59fc66a03e54454869460e45"
* }
*
* @apiParam {String} user Users unique ID
*
* @apiSuccess {Boolean} success Indicates successful response
* @apiSuccess {Object[]} results Filter description
* @apiSuccess {String} results.id Filter ID
* @apiSuccess {String} results.name Name for the filter
* @apiSuccess {String} results.created Datestring of the time the filter was created
* @apiSuccess {Array[]} results.query A list of query descriptions
* @apiSuccess {Array[]} results.action A list of action descriptions
*
* @apiError error Description of the error
*
* @apiExample {curl} Example usage:
* curl -i http://localhost:8080/users/5a1bda70bfbd1442cd96c6f0/filters
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true,
* "results": [
* {
* "id": "5a1c0ee490a34c67e266931c",
* "query": [
* [
* "from",
* "(Mäger)"
* ]
* ],
* "action": [
* [
* "mark as read"
* ]
* ],
* "created": "2017-11-27T13:11:00.835Z"
* }
* ]
* }
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 200 OK
* {
* "error": "This user does not exist"
* }
*/
server.get('/users/:user/filters', (req, res, next) => {
res.charSet('utf-8');
const schema = Joi.object().keys({
user: Joi.string().hex().lowercase().length(24).required()
user: Joi.string()
.hex()
.lowercase()
.length(24)
.required()
});
const result = Joi.validate(req.params, schema, {
@ -26,92 +84,155 @@ module.exports = (db, server) => {
let user = new ObjectID(result.value.user);
db.users.collection('users').findOne({
_id: user
}, {
fields: {
address: true
}
}, (err, userData) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!userData) {
res.json({
error: 'This user does not exist'
});
return next();
}
db.database
.collection('mailboxes')
.find({
user
})
.project({ _id: 1, path: 1 })
.sort({ _id: 1 })
.toArray((err, mailboxes) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!mailboxes) {
mailboxes = [];
}
db.database
.collection('filters')
.find({
user
})
.sort({
_id: 1
})
.toArray((err, filters) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!filters) {
filters = [];
}
db.users.collection('users').findOne(
{
_id: user
},
{
fields: {
address: true
}
},
(err, userData) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!userData) {
res.json({
error: 'This user does not exist'
});
return next();
}
db.database
.collection('mailboxes')
.find({
user
})
.project({ _id: 1, path: 1 })
.sort({ _id: 1 })
.toArray((err, mailboxes) => {
if (err) {
res.json({
success: true,
results: filters.map(filter => {
let descriptions = getFilterStrings(filter, mailboxes);
return {
id: filter._id,
name: filter.name,
query: descriptions.query,
action: descriptions.action,
created: filter.created
};
})
error: 'MongoDB Error: ' + err.message
});
return next();
});
});
});
}
if (!mailboxes) {
mailboxes = [];
}
db.database
.collection('filters')
.find({
user
})
.sort({
_id: 1
})
.toArray((err, filters) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!filters) {
filters = [];
}
res.json({
success: true,
results: filters.map(filter => {
let descriptions = getFilterStrings(filter, mailboxes);
return {
id: filter._id,
name: filter.name,
query: descriptions.query,
action: descriptions.action,
created: filter.created
};
})
});
return next();
});
});
}
);
});
/**
* @api {get} /users/:user/filters/:filter Request Filter information
* @apiName GetFilter
* @apiGroup Filters
* @apiHeader {String} X-Access-Token Optional access token if authentication is enabled
* @apiHeaderExample {json} Header-Example:
* {
* "X-Access-Token": "59fc66a03e54454869460e45"
* }
*
* @apiParam {String} user Users unique ID.
* @apiParam {String} filter Filters unique ID.
*
* @apiSuccess {Boolean} success Indicates successful response
* @apiSuccess {String} id ID for the Filter
* @apiSuccess {String} name Name of the Filter
* @apiSuccess {String} query_from Partial match for the From: header (case insensitive)
* @apiSuccess {String} query_to Partial match for the To:/Cc: headers (case insensitive)
* @apiSuccess {String} query_subject Partial match for the Subject: header (case insensitive)
* @apiSuccess {String} query_text Fulltext search against message text
* @apiSuccess {Bolean} query_ha Does a message have to have an attachment or not
* @apiSuccess {Number} query_size Message size in bytes. If the value is a positive number then message needs to be larger, if negative then message needs to be smaller than abs(size) value
* @apiSuccess {Bolean} action_seen If true then mark matching messages as Seen
* @apiSuccess {Bolean} action_flag If true then mark matching messages as Flagged
* @apiSuccess {Bolean} action_delete If true then do not store matching messages
* @apiSuccess {Bolean} action_spam If true then store matching messags to Junk Mail folder
* @apiSuccess {String} action_mailbox Mailbox ID to store matching messages to
* @apiSuccess {String} action_forward An email address where matching messages should be forwarded to
* @apiSuccess {String} action_targetUrl An URL where matching messages should be POSTed to
*
* @apiError error Description of the error
*
* @apiExample {curl} Example usage:
* curl -i http://localhost:8080/users/59fc66a03e54454869460e45/filters/5a1c0ee490a34c67e266931c
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true,
* "id": "5a1c0ee490a34c67e266931c",
* "created": "2017-11-27T13:11:00.835Z",
* "query_from": "Mäger",
* "action_seen": true
* }
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 200 OK
* {
* "error": "This filter does not exist"
* }
*/
server.get('/users/:user/filters/:filter', (req, res, next) => {
res.charSet('utf-8');
const schema = Joi.object().keys({
user: Joi.string().hex().lowercase().length(24).required(),
filter: Joi.string().hex().lowercase().length(24).required()
user: Joi.string()
.hex()
.lowercase()
.length(24)
.required(),
filter: Joi.string()
.hex()
.lowercase()
.length(24)
.required()
});
const result = Joi.validate(req.params, schema, {
@ -129,76 +250,119 @@ module.exports = (db, server) => {
let user = new ObjectID(result.value.user);
let filter = new ObjectID(result.value.filter);
db.database.collection('filters').findOne({
_id: filter,
user
}, (err, filterData) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!filterData) {
res.json({
error: 'This filter does not exist'
});
return next();
}
db.database
.collection('mailboxes')
.find({
user
})
.project({ _id: 1, path: 1 })
.sort({ _id: 1 })
.toArray((err, mailboxes) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!mailboxes) {
mailboxes = [];
}
let result = {
success: true,
id: filterData._id,
name: filterData.name,
created: filterData.created
};
Object.keys((filterData.query && filterData.query.headers) || {}).forEach(key => {
result['query_' + key] = filterData.query.headers[key];
db.database.collection('filters').findOne(
{
_id: filter,
user
},
(err, filterData) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
Object.keys(filterData.query || {}).forEach(key => {
if (key !== 'headers') {
result['query_' + key] = filterData.query[key];
}
});
Object.keys(filterData.action || {}).forEach(key => {
result['action_' + key] = filterData.action[key];
});
res.json(result);
return next();
});
});
}
if (!filterData) {
res.json({
error: 'This filter does not exist'
});
return next();
}
db.database
.collection('mailboxes')
.find({
user
})
.project({ _id: 1, path: 1 })
.sort({ _id: 1 })
.toArray((err, mailboxes) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!mailboxes) {
mailboxes = [];
}
let result = {
success: true,
id: filterData._id,
name: filterData.name,
created: filterData.created
};
Object.keys((filterData.query && filterData.query.headers) || {}).forEach(key => {
result['query_' + key] = filterData.query.headers[key];
});
Object.keys(filterData.query || {}).forEach(key => {
if (key !== 'headers') {
result['query_' + key] = filterData.query[key];
}
});
Object.keys(filterData.action || {}).forEach(key => {
result['action_' + key] = filterData.action[key];
});
res.json(result);
return next();
});
}
);
});
/**
* @api {delete} /users/:user/filters/:filter Delete a Filter
* @apiName DeleteFilter
* @apiGroup Filters
* @apiHeader {String} X-Access-Token Optional access token if authentication is enabled
* @apiHeaderExample {json} Header-Example:
* {
* "X-Access-Token": "59fc66a03e54454869460e45"
* }
*
* @apiParam {String} user Users unique ID
* @apiParam {String} filter Filters unique ID
*
* @apiSuccess {Boolean} success Indicates successful response
*
* @apiError error Description of the error
*
* @apiExample {curl} Example usage:
* curl -i -XDELETE http://localhost:8080/users/59fc66a03e54454869460e45/filters/5a1c0ee490a34c67e266931c
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true
* }
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 200 OK
* {
* "error": "This filter does not exist"
* }
*/
server.del('/users/:user/filters/:filter', (req, res, next) => {
res.charSet('utf-8');
const schema = Joi.object().keys({
user: Joi.string().hex().lowercase().length(24).required(),
filter: Joi.string().hex().lowercase().length(24).required()
user: Joi.string()
.hex()
.lowercase()
.length(24)
.required(),
filter: Joi.string()
.hex()
.lowercase()
.length(24)
.required()
});
const result = Joi.validate(req.params, schema, {
@ -216,54 +380,144 @@ module.exports = (db, server) => {
let user = new ObjectID(result.value.user);
let filter = new ObjectID(result.value.filter);
db.database.collection('filters').deleteOne({
_id: filter,
user
}, (err, r) => {
if (err) {
db.database.collection('filters').deleteOne(
{
_id: filter,
user
},
(err, r) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!r.deletedCount) {
res.status(404);
res.json({
error: 'Filter was not found'
});
return next();
}
res.json({
error: 'MongoDB Error: ' + err.message
success: true
});
return next();
}
if (!r.deletedCount) {
res.status(404);
res.json({
error: 'Filter was not found'
});
return next();
}
res.json({
success: true
});
return next();
});
);
});
/**
* @api {post} /users/:user/filters Create new Filter
* @apiName PostFilter
* @apiGroup Filters
* @apiHeader {String} X-Access-Token Optional access token if authentication is enabled
* @apiHeaderExample {json} Header-Example:
* {
* "X-Access-Token": "59fc66a03e54454869460e45"
* }
*
* @apiParam {String} user Users unique ID.
* @apiParam {String} [name] Name of the Filter
* @apiParam {String} [query_from] Partial match for the From: header (case insensitive)
* @apiParam {String} [query_to] Partial match for the To:/Cc: headers (case insensitive)
* @apiParam {String} [query_subject] Partial match for the Subject: header (case insensitive)
* @apiParam {String} [query_text] Fulltext search against message text
* @apiParam {Bolean} [query_ha] Does a message have to have an attachment or not
* @apiParam {Number} [query_size] Message size in bytes. If the value is a positive number then message needs to be larger, if negative then message needs to be smaller than abs(size) value
* @apiParam {Bolean} [action_seen] If true then mark matching messages as Seen
* @apiParam {Bolean} [action_flag] If true then mark matching messages as Flagged
* @apiParam {Bolean} [action_delete] If true then do not store matching messages
* @apiParam {Bolean} [action_spam] If true then store matching messags to Junk Mail folder
* @apiParam {String} [action_mailbox] Mailbox ID to store matching messages to
* @apiParam {String} [action_forward] An email address where matching messages should be forwarded to
* @apiParam {String} [action_targetUrl] An URL where matching messages should be POSTed to
*
* @apiSuccess {Boolean} success Indicates successful response
* @apiSuccess {String} id ID for the created Filter
*
* @apiError error Description of the error
*
* @apiExample {curl} Example usage:
* curl -i -XPOST http://localhost:8080/users/5a1bda70bfbd1442cd96c6f0/filters \
* -H 'Content-type: application/json' \
* -d '{
* "query_from": "Mäger",
* "action_seen": true
* }'
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true,
* "id": "5a1c0ee490a34c67e266931c"
* }
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 200 OK
* {
* "error": "Empty filter query"
* }
*/
server.post('/users/:user/filters', (req, res, next) => {
res.charSet('utf-8');
const schema = Joi.object().keys({
user: Joi.string().hex().lowercase().length(24).required(),
user: Joi.string()
.hex()
.lowercase()
.length(24)
.required(),
name: Joi.string().trim().max(255).empty(''),
name: Joi.string()
.trim()
.max(255)
.empty(''),
query_from: Joi.string().trim().max(255).empty(''),
query_to: Joi.string().trim().max(255).empty(''),
query_subject: Joi.string().trim().max(255).empty(''),
query_text: Joi.string().trim().max(255).empty(''),
query_ha: Joi.boolean().truthy(['Y', 'true', 'yes', 1]).empty(''),
query_from: Joi.string()
.trim()
.max(255)
.empty(''),
query_to: Joi.string()
.trim()
.max(255)
.empty(''),
query_subject: Joi.string()
.trim()
.max(255)
.empty(''),
query_text: Joi.string()
.trim()
.max(255)
.empty(''),
query_ha: Joi.boolean()
.truthy(['Y', 'true', 'yes', 1])
.empty(''),
query_size: Joi.number().empty(''),
action_seen: Joi.boolean().truthy(['Y', 'true', 'yes', 1]).empty(''),
action_flag: Joi.boolean().truthy(['Y', 'true', 'yes', 1]).empty(''),
action_delete: Joi.boolean().truthy(['Y', 'true', 'yes', 1]).empty(''),
action_spam: Joi.boolean().truthy(['Y', 'true', 'yes', 1]).empty(''),
action_seen: Joi.boolean()
.truthy(['Y', 'true', 'yes', 1])
.empty(''),
action_flag: Joi.boolean()
.truthy(['Y', 'true', 'yes', 1])
.empty(''),
action_delete: Joi.boolean()
.truthy(['Y', 'true', 'yes', 1])
.empty(''),
action_spam: Joi.boolean()
.truthy(['Y', 'true', 'yes', 1])
.empty(''),
action_mailbox: Joi.string().hex().lowercase().length(24).empty(''),
action_forward: Joi.string().email().empty(''),
action_mailbox: Joi.string()
.hex()
.lowercase()
.length(24)
.empty(''),
action_forward: Joi.string()
.email()
.empty(''),
action_targetUrl: Joi.string()
.uri({
scheme: ['http', 'https'],
@ -343,26 +597,29 @@ module.exports = (db, server) => {
if (!result.value.action_mailbox) {
return done();
}
db.database.collection('mailboxes').findOne({
_id: new ObjectID(result.value.action_mailbox),
user
}, (err, mailboxData) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
db.database.collection('mailboxes').findOne(
{
_id: new ObjectID(result.value.action_mailbox),
user
},
(err, mailboxData) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!mailboxData) {
res.json({
error: 'This mailbox does not exist'
});
return next();
}
filterData.action.mailbox = mailboxData._id;
hasAction = true;
done();
}
if (!mailboxData) {
res.json({
error: 'This mailbox does not exist'
});
return next();
}
filterData.action.mailbox = mailboxData._id;
hasAction = true;
done();
});
);
};
checkFilterMailbox(() => {
@ -380,67 +637,163 @@ module.exports = (db, server) => {
return next();
}
db.users.collection('users').findOne({
_id: user
}, {
fields: {
address: true
}
}, (err, userData) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!userData) {
res.json({
error: 'This user does not exist'
});
return next();
}
db.database.collection('filters').insertOne(filterData, (err, r) => {
db.users.collection('users').findOne(
{
_id: user
},
{
fields: {
address: true
}
},
(err, userData) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!userData) {
res.json({
error: 'This user does not exist'
});
return next();
}
res.json({
success: !!r.insertedCount,
id: filterData._id
db.database.collection('filters').insertOne(filterData, (err, r) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
res.json({
success: !!r.insertedCount,
id: filterData._id
});
return next();
});
return next();
});
});
}
);
});
});
/**
* @api {put} /users/:user/filters/:filter Update Filter information
* @apiName PutFilter
* @apiGroup Filters
* @apiDescription This method updates Filter data. To unset a value, use empty strings
* @apiHeader {String} X-Access-Token Optional access token if authentication is enabled
* @apiHeaderExample {json} Header-Example:
* {
* "X-Access-Token": "59fc66a03e54454869460e45"
* }
*
* @apiParam {String} user Users unique ID.
* @apiParam {String} filter Filters unique ID.
* @apiParam {String} [name] Name of the Filter
* @apiParam {String} [query_from] Partial match for the From: header (case insensitive)
* @apiParam {String} [query_to] Partial match for the To:/Cc: headers (case insensitive)
* @apiParam {String} [query_subject] Partial match for the Subject: header (case insensitive)
* @apiParam {String} [query_text] Fulltext search against message text
* @apiParam {Bolean} [query_ha] Does a message have to have an attachment or not
* @apiParam {Number} [query_size] Message size in bytes. If the value is a positive number then message needs to be larger, if negative then message needs to be smaller than abs(size) value
* @apiParam {Bolean} [action_seen] If true then mark matching messages as Seen
* @apiParam {Bolean} [action_flag] If true then mark matching messages as Flagged
* @apiParam {Bolean} [action_delete] If true then do not store matching messages
* @apiParam {Bolean} [action_spam] If true then store matching messags to Junk Mail folder
* @apiParam {String} [action_mailbox] Mailbox ID to store matching messages to
* @apiParam {String} [action_forward] An email address where matching messages should be forwarded to
* @apiParam {String} [action_targetUrl] An URL where matching messages should be POSTed to
*
* @apiSuccess {Boolean} success Indicates successful response
* @apiSuccess {String} id ID for the created Filter
*
* @apiError error Description of the error
*
* @apiExample {curl} Example usage:
* curl -i -XPUT http://localhost:8080/users/59fc66a03e54454869460e45/filters/5a1c0ee490a34c67e266931c \
* -H 'Content-type: application/json' \
* -d '{
* "action_seen": "",
* "action_flag": true
* }'
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true
* }
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 200 OK
* {
* "error": "Empty filter query"
* }
*/
server.put('/users/:user/filters/:filter', (req, res, next) => {
res.charSet('utf-8');
const schema = Joi.object().keys({
user: Joi.string().hex().lowercase().length(24).required(),
filter: Joi.string().hex().lowercase().length(24).required(),
user: Joi.string()
.hex()
.lowercase()
.length(24)
.required(),
filter: Joi.string()
.hex()
.lowercase()
.length(24)
.required(),
name: Joi.string().trim().max(255).empty(''),
name: Joi.string()
.trim()
.max(255)
.empty(''),
query_from: Joi.string().trim().max(255).empty(''),
query_to: Joi.string().trim().max(255).empty(''),
query_subject: Joi.string().trim().max(255).empty(''),
query_text: Joi.string().trim().max(255).empty(''),
query_ha: Joi.boolean().truthy(['Y', 'true', 'yes', 1]).empty(''),
query_from: Joi.string()
.trim()
.max(255)
.empty(''),
query_to: Joi.string()
.trim()
.max(255)
.empty(''),
query_subject: Joi.string()
.trim()
.max(255)
.empty(''),
query_text: Joi.string()
.trim()
.max(255)
.empty(''),
query_ha: Joi.boolean()
.truthy(['Y', 'true', 'yes', 1])
.empty(''),
query_size: Joi.number().empty(''),
action_seen: Joi.boolean().truthy(['Y', 'true', 'yes', 1]).empty(''),
action_flag: Joi.boolean().truthy(['Y', 'true', 'yes', 1]).empty(''),
action_delete: Joi.boolean().truthy(['Y', 'true', 'yes', 1]).empty(''),
action_spam: Joi.boolean().truthy(['Y', 'true', 'yes', 1]).empty(''),
action_seen: Joi.boolean()
.truthy(['Y', 'true', 'yes', 1])
.empty(''),
action_flag: Joi.boolean()
.truthy(['Y', 'true', 'yes', 1])
.empty(''),
action_delete: Joi.boolean()
.truthy(['Y', 'true', 'yes', 1])
.empty(''),
action_spam: Joi.boolean()
.truthy(['Y', 'true', 'yes', 1])
.empty(''),
action_mailbox: Joi.string().hex().lowercase().length(24).empty(''),
action_forward: Joi.string().email().empty(''),
action_mailbox: Joi.string()
.hex()
.lowercase()
.length(24)
.empty(''),
action_forward: Joi.string()
.email()
.empty(''),
action_targetUrl: Joi.string()
.uri({
scheme: ['http', 'https'],
@ -537,26 +890,29 @@ module.exports = (db, server) => {
}
return done();
}
db.database.collection('mailboxes').findOne({
_id: new ObjectID(result.value.action_mailbox),
user
}, (err, mailboxData) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
db.database.collection('mailboxes').findOne(
{
_id: new ObjectID(result.value.action_mailbox),
user
},
(err, mailboxData) => {
if (err) {
res.json({
error: 'MongoDB Error: ' + err.message
});
return next();
}
if (!mailboxData) {
res.json({
error: 'This mailbox does not exist'
});
return next();
}
$set['action.mailbox'] = mailboxData._id;
hasAction = true;
done();
}
if (!mailboxData) {
res.json({
error: 'This mailbox does not exist'
});
return next();
}
$set['action.mailbox'] = mailboxData._id;
hasAction = true;
done();
});
);
};
checkFilterMailbox(() => {