From 13c5184c8b616d9ad0841733062de3af882d3ae9 Mon Sep 17 00:00:00 2001 From: dblythy Date: Fri, 25 Dec 2020 12:55:13 +1100 Subject: [PATCH 1/8] initial --- spec/CloudCode.spec.js | 14 ++++++++++++++ src/cloud-code/Parse.Cloud.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index 9b95bbf8b0..d25a634bf7 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -3167,4 +3167,18 @@ describe('afterLogin hook', () => { const query = new Parse.Query(TestObject); await query.find({ context: { a: 'a' } }); }); + it('can send email via Parse.Cloud', async done => { + const emailAdapter = { + sendMail: mailData => { + expect(mailData).toBeDefined(); + expect(mailData.to).toBe('test'); + done(); + }, + }; + await reconfigureServer({ + emailAdapter: emailAdapter, + }); + const mailData = { to: 'test' }; + await Parse.Cloud.sendMail(mailData); + }); }); diff --git a/src/cloud-code/Parse.Cloud.js b/src/cloud-code/Parse.Cloud.js index c04c48205e..9564122d30 100644 --- a/src/cloud-code/Parse.Cloud.js +++ b/src/cloud-code/Parse.Cloud.js @@ -1,5 +1,6 @@ import { Parse } from 'parse/node'; import * as triggers from '../triggers'; +const Config = require('../Config'); function isParseObjectConstructor(object) { return typeof object === 'function' && Object.prototype.hasOwnProperty.call(object, 'className'); @@ -528,6 +529,34 @@ ParseCloud.beforeConnect = function (handler, validationHandler) { ); }; +/** + * Sends email through your mail adapter + * + * **Available in Cloud Code only.** + * + * **Requires a mail adapter to be set** + * + * ``` + * Parse.Cloud.sendMail(data); + *``` + * + * @method sendMail + * @name Parse.Cloud.sendMail + * @param {Any} data The object of the mail data that you'd like to send + */ +ParseCloud.sendMail = function (data) { + const config = Config.get(Parse.applicationId) || {}; + const emailAdapter = config.emailAdapter; + if (!emailAdapter) { + throw 'You cannot send mail without an email adapter'; + } + const sendMail = emailAdapter.sendMail; + if (!sendMail || typeof sendMail !== 'function') { + throw 'This adapter does not support sendMail'; + } + return sendMail(data); +}; + /** * Registers a before live query subscription function. * From 985c8f4bda42b0b9045f57077489fabe65840b9f Mon Sep 17 00:00:00 2001 From: dblythy Date: Fri, 25 Dec 2020 19:21:13 +1100 Subject: [PATCH 2/8] more tests --- spec/CloudCode.spec.js | 8 ++++++++ src/cloud-code/Parse.Cloud.js | 8 ++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index d25a634bf7..6e7654d184 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -3181,4 +3181,12 @@ describe('afterLogin hook', () => { const mailData = { to: 'test' }; await Parse.Cloud.sendMail(mailData); }); + it('cannot send email without adapter', async () => { + try { + await Parse.Cloud.sendMail({}); + fail('Should have failed to send emails.'); + } catch (e) { + expect(e).toBe('You cannot send mail without an email adapter'); + } + }); }); diff --git a/src/cloud-code/Parse.Cloud.js b/src/cloud-code/Parse.Cloud.js index 9564122d30..8fc8025c57 100644 --- a/src/cloud-code/Parse.Cloud.js +++ b/src/cloud-code/Parse.Cloud.js @@ -546,15 +546,11 @@ ParseCloud.beforeConnect = function (handler, validationHandler) { */ ParseCloud.sendMail = function (data) { const config = Config.get(Parse.applicationId) || {}; - const emailAdapter = config.emailAdapter; + const emailAdapter = config.userController.adapter; if (!emailAdapter) { throw 'You cannot send mail without an email adapter'; } - const sendMail = emailAdapter.sendMail; - if (!sendMail || typeof sendMail !== 'function') { - throw 'This adapter does not support sendMail'; - } - return sendMail(data); + return emailAdapter.sendMail(data); }; /** From 6d2dee9e9201b513fadab8f75b5ea15459b21882 Mon Sep 17 00:00:00 2001 From: dblythy Date: Fri, 25 Dec 2020 19:29:45 +1100 Subject: [PATCH 3/8] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71df536115..c0723510fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ __BREAKING CHANGES:__ ___ - IMPROVE: Optimize queries on classes with pointer permissions. [#7061](https://github.com/parse-community/parse-server/pull/7061). Thanks to [Pedro Diaz](https://github.com/pdiaz) - FIX: request.context for afterFind triggers. [#7078](https://github.com/parse-community/parse-server/pull/7078). Thanks to [dblythy](https://github.com/dblythy) +- NEW: sendMail via Parse.Cloud.sendMail({...}). [#7089](https://github.com/parse-community/parse-server/pull/7089). Thanks to [dblythy](https://github.com/dblythy) ### 4.5.0 [Full Changelog](https://github.com/parse-community/parse-server/compare/4.4.0...4.5.0) From 4286cf744e30f665c09f4fb460774b82f1c1137d Mon Sep 17 00:00:00 2001 From: dblythy Date: Fri, 25 Dec 2020 23:50:38 +1100 Subject: [PATCH 4/8] review --- CHANGELOG.md | 2 +- spec/CloudCode.spec.js | 8 +++++++- src/cloud-code/Parse.Cloud.js | 16 ++++++++++------ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0723510fc..6cab892532 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ __BREAKING CHANGES:__ ___ - IMPROVE: Optimize queries on classes with pointer permissions. [#7061](https://github.com/parse-community/parse-server/pull/7061). Thanks to [Pedro Diaz](https://github.com/pdiaz) - FIX: request.context for afterFind triggers. [#7078](https://github.com/parse-community/parse-server/pull/7078). Thanks to [dblythy](https://github.com/dblythy) -- NEW: sendMail via Parse.Cloud.sendMail({...}). [#7089](https://github.com/parse-community/parse-server/pull/7089). Thanks to [dblythy](https://github.com/dblythy) +- NEW: Added convenience method Parse.Cloud.sendMail(...) to send email via mail adapter in Cloud Code. [#7089](https://github.com/parse-community/parse-server/pull/7089). Thanks to [dblythy](https://github.com/dblythy) ### 4.5.0 [Full Changelog](https://github.com/parse-community/parse-server/compare/4.4.0...4.5.0) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index 6e7654d184..e72a37f036 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -3167,6 +3167,9 @@ describe('afterLogin hook', () => { const query = new Parse.Query(TestObject); await query.find({ context: { a: 'a' } }); }); +}); + +describe('sendMail', () => { it('can send email via Parse.Cloud', async done => { const emailAdapter = { sendMail: mailData => { @@ -3181,12 +3184,15 @@ describe('afterLogin hook', () => { const mailData = { to: 'test' }; await Parse.Cloud.sendMail(mailData); }); + it('cannot send email without adapter', async () => { try { await Parse.Cloud.sendMail({}); fail('Should have failed to send emails.'); } catch (e) { - expect(e).toBe('You cannot send mail without an email adapter'); + expect(e).toBe( + 'Failed to send email because no mail adapter is configured for Parse Server.' + ); } }); }); diff --git a/src/cloud-code/Parse.Cloud.js b/src/cloud-code/Parse.Cloud.js index 8fc8025c57..5f5837e310 100644 --- a/src/cloud-code/Parse.Cloud.js +++ b/src/cloud-code/Parse.Cloud.js @@ -530,25 +530,29 @@ ParseCloud.beforeConnect = function (handler, validationHandler) { }; /** - * Sends email through your mail adapter + * Sends an email through the Parse Server mail adapter. * * **Available in Cloud Code only.** - * - * **Requires a mail adapter to be set** + * **Requires a mail adapter to be configured for Parse Server.** * * ``` - * Parse.Cloud.sendMail(data); + * Parse.Cloud.sendMail({ + * from: 'Example ', + * to: 'contact@example.com', + * subject: 'Test email.', + * text: 'This email is a test' + * }); *``` * * @method sendMail * @name Parse.Cloud.sendMail - * @param {Any} data The object of the mail data that you'd like to send + * @param {Object} data The object of the mail data to send */ ParseCloud.sendMail = function (data) { const config = Config.get(Parse.applicationId) || {}; const emailAdapter = config.userController.adapter; if (!emailAdapter) { - throw 'You cannot send mail without an email adapter'; + throw 'Failed to send email because no mail adapter is configured for Parse Server.'; } return emailAdapter.sendMail(data); }; From 2c2d4ce5d1d63cf11ea0efef560b42c773dd0f76 Mon Sep 17 00:00:00 2001 From: dblythy Date: Sat, 26 Dec 2020 00:11:01 +1100 Subject: [PATCH 5/8] log on error --- spec/CloudCode.spec.js | 14 ++++++-------- src/cloud-code/Parse.Cloud.js | 8 +++++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index e72a37f036..c3d0776167 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -3186,13 +3186,11 @@ describe('sendMail', () => { }); it('cannot send email without adapter', async () => { - try { - await Parse.Cloud.sendMail({}); - fail('Should have failed to send emails.'); - } catch (e) { - expect(e).toBe( - 'Failed to send email because no mail adapter is configured for Parse Server.' - ); - } + const logger = require('../lib/logger').logger; + spyOn(logger, 'warn').and.callFake(() => {}); + await Parse.Cloud.sendMail({}); + expect(logger.warn).toHaveBeenCalledWith( + 'Failed to send email because no mail adapter is configured for Parse Server.' + ); }); }); diff --git a/src/cloud-code/Parse.Cloud.js b/src/cloud-code/Parse.Cloud.js index 5f5837e310..2d2aef113d 100644 --- a/src/cloud-code/Parse.Cloud.js +++ b/src/cloud-code/Parse.Cloud.js @@ -551,10 +551,12 @@ ParseCloud.beforeConnect = function (handler, validationHandler) { ParseCloud.sendMail = function (data) { const config = Config.get(Parse.applicationId) || {}; const emailAdapter = config.userController.adapter; - if (!emailAdapter) { - throw 'Failed to send email because no mail adapter is configured for Parse Server.'; + if (emailAdapter) { + return emailAdapter.sendMail(data); } - return emailAdapter.sendMail(data); + config.loggerController.warn( + 'Failed to send email because no mail adapter is configured for Parse Server.' + ); }; /** From 4bc1987e4b5e659ccef94ee1ee5a662afc35b67c Mon Sep 17 00:00:00 2001 From: dblythy Date: Sat, 26 Dec 2020 13:00:59 +1100 Subject: [PATCH 6/8] change logger to error --- spec/CloudCode.spec.js | 4 ++-- src/cloud-code/Parse.Cloud.js | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index c3d0776167..e276377c4d 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -3187,9 +3187,9 @@ describe('sendMail', () => { it('cannot send email without adapter', async () => { const logger = require('../lib/logger').logger; - spyOn(logger, 'warn').and.callFake(() => {}); + spyOn(logger, 'error').and.callFake(() => {}); await Parse.Cloud.sendMail({}); - expect(logger.warn).toHaveBeenCalledWith( + expect(logger.error).toHaveBeenCalledWith( 'Failed to send email because no mail adapter is configured for Parse Server.' ); }); diff --git a/src/cloud-code/Parse.Cloud.js b/src/cloud-code/Parse.Cloud.js index 2d2aef113d..d658dab047 100644 --- a/src/cloud-code/Parse.Cloud.js +++ b/src/cloud-code/Parse.Cloud.js @@ -551,12 +551,13 @@ ParseCloud.beforeConnect = function (handler, validationHandler) { ParseCloud.sendMail = function (data) { const config = Config.get(Parse.applicationId) || {}; const emailAdapter = config.userController.adapter; - if (emailAdapter) { - return emailAdapter.sendMail(data); + if (!emailAdapter) { + config.loggerController.error( + 'Failed to send email because no mail adapter is configured for Parse Server.' + ); + return; } - config.loggerController.warn( - 'Failed to send email because no mail adapter is configured for Parse Server.' - ); + return emailAdapter.sendMail(data); }; /** From d887e4a107b091a1f9227712c8bf9bafa6d012a5 Mon Sep 17 00:00:00 2001 From: dblythy Date: Sun, 27 Dec 2020 09:35:06 +1100 Subject: [PATCH 7/8] rename --- spec/CloudCode.spec.js | 6 +++--- src/cloud-code/Parse.Cloud.js | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index e276377c4d..7f0fe70aa0 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -3169,7 +3169,7 @@ describe('afterLogin hook', () => { }); }); -describe('sendMail', () => { +describe('sendEmail', () => { it('can send email via Parse.Cloud', async done => { const emailAdapter = { sendMail: mailData => { @@ -3182,13 +3182,13 @@ describe('sendMail', () => { emailAdapter: emailAdapter, }); const mailData = { to: 'test' }; - await Parse.Cloud.sendMail(mailData); + await Parse.Cloud.sendEmail(mailData); }); it('cannot send email without adapter', async () => { const logger = require('../lib/logger').logger; spyOn(logger, 'error').and.callFake(() => {}); - await Parse.Cloud.sendMail({}); + await Parse.Cloud.sendEmail({}); expect(logger.error).toHaveBeenCalledWith( 'Failed to send email because no mail adapter is configured for Parse Server.' ); diff --git a/src/cloud-code/Parse.Cloud.js b/src/cloud-code/Parse.Cloud.js index d658dab047..ebba39fd24 100644 --- a/src/cloud-code/Parse.Cloud.js +++ b/src/cloud-code/Parse.Cloud.js @@ -536,19 +536,19 @@ ParseCloud.beforeConnect = function (handler, validationHandler) { * **Requires a mail adapter to be configured for Parse Server.** * * ``` - * Parse.Cloud.sendMail({ + * Parse.Cloud.sendEmail({ * from: 'Example ', * to: 'contact@example.com', - * subject: 'Test email.', - * text: 'This email is a test' + * subject: 'Test email', + * text: 'This email is a test.' * }); *``` * * @method sendMail - * @name Parse.Cloud.sendMail + * @name Parse.Cloud.sendEmail * @param {Object} data The object of the mail data to send */ -ParseCloud.sendMail = function (data) { +ParseCloud.sendEmail = function (data) { const config = Config.get(Parse.applicationId) || {}; const emailAdapter = config.userController.adapter; if (!emailAdapter) { From 9266a06af8dd4655a2c600511833b01189f1e5e5 Mon Sep 17 00:00:00 2001 From: dblythy Date: Wed, 30 Dec 2020 11:18:57 +1100 Subject: [PATCH 8/8] Update Parse.Cloud.js --- src/cloud-code/Parse.Cloud.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cloud-code/Parse.Cloud.js b/src/cloud-code/Parse.Cloud.js index ebba39fd24..80eead1f31 100644 --- a/src/cloud-code/Parse.Cloud.js +++ b/src/cloud-code/Parse.Cloud.js @@ -544,12 +544,12 @@ ParseCloud.beforeConnect = function (handler, validationHandler) { * }); *``` * - * @method sendMail + * @method sendEmail * @name Parse.Cloud.sendEmail - * @param {Object} data The object of the mail data to send + * @param {Object} data The object of the mail data to send. */ ParseCloud.sendEmail = function (data) { - const config = Config.get(Parse.applicationId) || {}; + const config = Config.get(Parse.applicationId); const emailAdapter = config.userController.adapter; if (!emailAdapter) { config.loggerController.error(