From 9dd3ed0e65d4d5905c05a021346a46ece5a8fdf6 Mon Sep 17 00:00:00 2001 From: Louis Laureys Date: Mon, 19 Oct 2020 00:33:24 +0200 Subject: [PATCH 1/2] Fix error when partially upding a filter --- lib/api/filters.js | 236 +++++++++++++++++++++++---------------------- 1 file changed, 120 insertions(+), 116 deletions(-) diff --git a/lib/api/filters.js b/lib/api/filters.js index e7803270..ddddb5c9 100644 --- a/lib/api/filters.js +++ b/lib/api/filters.js @@ -774,7 +774,7 @@ module.exports = (db, server) => { * @apiParam {String} user Users unique ID. * @apiParam {String} filter Filters unique ID. * @apiParam {String} [name] Name of the Filter - * @apiParam {Object} query Rules that a message must match + * @apiParam {Object} [query] Rules that a message must match * @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) @@ -782,7 +782,7 @@ module.exports = (db, server) => { * @apiParam {String} [query.text] Fulltext search against message text * @apiParam {Boolean} [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 {Object} action Action to take with a matching message + * @apiParam {Object} [action] Action to take with a matching message * @apiParam {Boolean} [action.seen] If true then mark matching messages as Seen * @apiParam {Boolean} [action.flag] If true then mark matching messages as Flagged * @apiParam {Boolean} [action.delete] If true then do not store matching messages @@ -906,129 +906,133 @@ module.exports = (db, server) => { hasChanges = true; } - ['from', 'to', 'subject', 'listId'].forEach(key => { - if (result.value.query[key]) { - $set['query.headers.' + key] = result.value.query[key].replace(/\s+/g, ' '); - hasChanges = true; - } else if (key in req.params.query) { - // delete empty values - $unset['query.headers.' + key] = true; - hasChanges = true; - } - }); - - if (result.value.query.text) { - $set['query.text'] = result.value.query.text.replace(/\s+/g, ' '); - hasChanges = true; - } else if ('text' in req.params.query) { - $unset['query.text'] = true; - hasChanges = true; - } - - if (typeof result.value.query.ha === 'boolean') { - $set['query.ha'] = result.value.query.ha; - hasChanges = true; - } else if ('ha' in req.params.query) { - $unset['query.ha'] = true; - hasChanges = true; - } - - if (result.value.query.size) { - $set['query.size'] = result.value.query.size; - hasChanges = true; - } else if ('size' in req.params.query) { - $unset['query.size'] = true; - hasChanges = true; - } - - ['seen', 'flag', 'delete', 'spam'].forEach(key => { - if (typeof result.value.action[key] === 'boolean') { - $set['action.' + key] = result.value.action[key]; - hasChanges = true; - } else if (key in req.params.action) { - $unset['action.' + key] = true; - hasChanges = true; - } - }); - - let targets = result.value.action.targets; - - if (targets) { - for (let i = 0, len = targets.length; i < len; i++) { - let target = targets[i]; - if (!/^smtps?:/i.test(target) && !/^https?:/i.test(target) && target.indexOf('@') >= 0) { - // email - targets[i] = { - id: new ObjectID(), - type: 'mail', - value: target - }; - } else if (/^smtps?:/i.test(target)) { - targets[i] = { - id: new ObjectID(), - type: 'relay', - value: target - }; - } else if (/^https?:/i.test(target)) { - targets[i] = { - id: new ObjectID(), - type: 'http', - value: target - }; - } else { - res.json({ - error: 'Unknown target type "' + target + '"', - code: 'InputValidationError' - }); - return next(); - } - } - - $set['action.targets'] = targets; - hasChanges = true; - } else if ('targets' in req.params.action) { - $unset['action.targets'] = true; - hasChanges = true; - } - - if (result.value.action) { - if (!result.value.action.mailbox) { - if ('mailbox' in req.params.action) { - // clear target mailbox - $unset['action.mailbox'] = true; + if (req.params.query) { + ['from', 'to', 'subject', 'listId'].forEach(key => { + if (result.value.query[key]) { + $set['query.headers.' + key] = result.value.query[key].replace(/\s+/g, ' '); + hasChanges = true; + } else if (key in req.params.query) { + // delete empty values + $unset['query.headers.' + key] = true; hasChanges = true; } - } else { - let mailboxData; - try { - mailboxData = await db.database.collection('mailboxes').findOne({ - _id: new ObjectID(result.value.action.mailbox), - user - }); - } catch (err) { - res.json({ - error: 'MongoDB Error: ' + err.message, - code: 'InternalDatabaseError' - }); - return next(); - } + }); - if (!mailboxData) { - res.json({ - error: 'This mailbox does not exist', - code: 'NoSuchMailbox' - }); - return next(); - } - - $set['action.mailbox'] = mailboxData._id; + if (result.value.query.text) { + $set['query.text'] = result.value.query.text.replace(/\s+/g, ' '); hasChanges = true; + } else if ('text' in req.params.query) { + $unset['query.text'] = true; + hasChanges = true; + } + + if (typeof result.value.query.ha === 'boolean') { + $set['query.ha'] = result.value.query.ha; + hasChanges = true; + } else if ('ha' in req.params.query) { + $unset['query.ha'] = true; + hasChanges = true; + } + + if (result.value.query.size) { + $set['query.size'] = result.value.query.size; + hasChanges = true; + } else if ('size' in req.params.query) { + $unset['query.size'] = true; + hasChanges = true; + } + } + + if (req.params.action) { + ['seen', 'flag', 'delete', 'spam'].forEach(key => { + if (typeof result.value.action[key] === 'boolean') { + $set['action.' + key] = result.value.action[key]; + hasChanges = true; + } else if (key in req.params.action) { + $unset['action.' + key] = true; + hasChanges = true; + } + }); + + let targets = result.value.action.targets; + + if (targets) { + for (let i = 0, len = targets.length; i < len; i++) { + let target = targets[i]; + if (!/^smtps?:/i.test(target) && !/^https?:/i.test(target) && target.indexOf('@') >= 0) { + // email + targets[i] = { + id: new ObjectID(), + type: 'mail', + value: target + }; + } else if (/^smtps?:/i.test(target)) { + targets[i] = { + id: new ObjectID(), + type: 'relay', + value: target + }; + } else if (/^https?:/i.test(target)) { + targets[i] = { + id: new ObjectID(), + type: 'http', + value: target + }; + } else { + res.json({ + error: 'Unknown target type "' + target + '"', + code: 'InputValidationError' + }); + return next(); + } + } + + $set['action.targets'] = targets; + hasChanges = true; + } else if ('targets' in req.params.action) { + $unset['action.targets'] = true; + hasChanges = true; + } + + if (result.value.action) { + if (!result.value.action.mailbox) { + if ('mailbox' in req.params.action) { + // clear target mailbox + $unset['action.mailbox'] = true; + hasChanges = true; + } + } else { + let mailboxData; + try { + mailboxData = await db.database.collection('mailboxes').findOne({ + _id: new ObjectID(result.value.action.mailbox), + user + }); + } catch (err) { + res.json({ + error: 'MongoDB Error: ' + err.message, + code: 'InternalDatabaseError' + }); + return next(); + } + + if (!mailboxData) { + res.json({ + error: 'This mailbox does not exist', + code: 'NoSuchMailbox' + }); + return next(); + } + + $set['action.mailbox'] = mailboxData._id; + hasChanges = true; + } } } if (!hasChanges) { res.json({ - error: 'No changes' + success: true }); return next(); } From a4ef1c1df2d71af37e5ef461b9e3a081d5c2d77c Mon Sep 17 00:00:00 2001 From: Louis Laureys Date: Mon, 19 Oct 2020 00:36:15 +0200 Subject: [PATCH 2/2] Generate docs --- docs/api/api_data.js | 4 ++-- docs/api/api_data.json | 4 ++-- docs/api/api_project.js | 2 +- docs/api/api_project.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/api/api_data.js b/docs/api/api_data.js index d7518d0d..e4402afa 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -6893,7 +6893,7 @@ define({ "api": [ { "group": "Parameter", "type": "Object", - "optional": false, + "optional": true, "field": "query", "description": "

Rules that a message must match

" }, @@ -6949,7 +6949,7 @@ define({ "api": [ { "group": "Parameter", "type": "Object", - "optional": false, + "optional": true, "field": "action", "description": "

Action to take with a matching message

" }, diff --git a/docs/api/api_data.json b/docs/api/api_data.json index 4a8bc63a..237a4461 100644 --- a/docs/api/api_data.json +++ b/docs/api/api_data.json @@ -6893,7 +6893,7 @@ { "group": "Parameter", "type": "Object", - "optional": false, + "optional": true, "field": "query", "description": "

Rules that a message must match

" }, @@ -6949,7 +6949,7 @@ { "group": "Parameter", "type": "Object", - "optional": false, + "optional": true, "field": "action", "description": "

Action to take with a matching message

" }, diff --git a/docs/api/api_project.js b/docs/api/api_project.js index 83f6c19c..82b42ee6 100644 --- a/docs/api/api_project.js +++ b/docs/api/api_project.js @@ -9,7 +9,7 @@ define({ "apidoc": "0.3.0", "generator": { "name": "apidoc", - "time": "2020-10-09T08:07:57.934Z", + "time": "2020-10-18T22:35:35.009Z", "url": "https://apidocjs.com", "version": "0.25.0" } diff --git a/docs/api/api_project.json b/docs/api/api_project.json index 92975583..9677ebe0 100644 --- a/docs/api/api_project.json +++ b/docs/api/api_project.json @@ -9,7 +9,7 @@ "apidoc": "0.3.0", "generator": { "name": "apidoc", - "time": "2020-10-09T08:07:57.934Z", + "time": "2020-10-18T22:35:35.009Z", "url": "https://apidocjs.com", "version": "0.25.0" }