mirror of
https://github.com/nodemailer/wildduck.git
synced 2025-10-07 20:40:30 +08:00
added api docs for filters
This commit is contained in:
parent
6a56201b78
commit
9dd052e18c
6 changed files with 619 additions and 263 deletions
16
README.md
16
README.md
|
@ -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
|
@ -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"
}
});
|
||||
|
|
|
@ -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"
}
}
|
||||
|
|
|
@ -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(() => {
|
||||
|
|
Loading…
Add table
Reference in a new issue