Fixed clearing invalid sender_email when changing newsletter sender_reply_to (#19555)

fixes PROD-102

When a newsletter has a sender_email stored in the database that Ghost
is not allowed to send from, we no longer return it as sender_email in
the API. Instead we return it as the sender_reply_to. That way the
expected behaviour is shown correctly in the frontend and the API result
also makes more sense.

In addition to that, when a change is made to a newsletters reply_to
address we'll clear any invalid sender_email values in that newsletter.
That makes sure we can clear the sender_reply_to value instead of
keeping the current fallback to sender_email if that one is stored.

On top of that, this change correclty updates the browse endpoint to use
the newsletter service instead of directly using the model.
This commit is contained in:
Simon Backx 2024-01-23 16:10:11 +01:00 committed by GitHub
parent 94c7d9b21b
commit eb063f7a40
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 1020 additions and 65 deletions

View File

@ -1,4 +1,3 @@
const models = require('../../models');
const allowedIncludes = ['count.posts', 'count.members', 'count.active_members'];
const newslettersService = require('../../services/newsletters');
@ -27,7 +26,7 @@ module.exports = {
},
permissions: true,
query(frame) {
return models.Newsletter.findPage(frame.options);
return newslettersService.browse(frame.options);
}
},

View File

@ -1,4 +1,5 @@
const utils = require('../../../index');
const emailAddressService = require('../../../../../../services/email-address');
module.exports = (model, frame) => {
const jsonModel = model.toJSON(frame.options);
@ -19,6 +20,17 @@ module.exports = (model, frame) => {
};
return serialized;
} else {
if (jsonModel.sender_email && jsonModel.sender_reply_to === 'newsletter') {
// If sender_email is not allowed, we'll return it as the sender_reply_to instead, so we display the current situation correctly in the frontend
// If one of the properties was changed, we need to reset sender_email in case it was not changed but is invalid in the database
// which can happen after a config change (= auto correcting behaviour)
const validated = emailAddressService.service.validate(jsonModel.sender_email, 'from');
if (!validated.allowed) {
jsonModel.sender_reply_to = jsonModel.sender_email;
jsonModel.sender_email = null;
}
}
}
return jsonModel;

View File

@ -92,7 +92,7 @@ class NewslettersService {
* @public
* @param {Object} options data (id, uuid, slug...)
* @param {Object} [options] options
* @returns {Promise<object>} JSONified Newsletter models
* @returns {Promise<object>}
*/
async read(data, options = {}) {
const newsletter = await this.NewsletterModel.findOne(data, options);
@ -108,11 +108,14 @@ class NewslettersService {
/**
* @public
* @param {Object} [options] options
* @returns {Promise<object>} JSONified Newsletter models
* @returns {Promise<object>}
*/
async browse(options = {}) {
let newsletters = await this.NewsletterModel.findAll(options);
return await this.NewsletterModel.findPage(options);
}
async getAll(options = {}) {
const newsletters = await this.NewsletterModel.findAll(options);
return newsletters.toJSON();
}
@ -298,6 +301,10 @@ class NewslettersService {
}
if (validated.verificationEmailRequired) {
if (type === 'replyTo' && email === newsletter.get('sender_email')) {
// This is some custom behaviour that allows swapping sender_email to sender_reply_to without requiring validation again
continue;
}
delete cleanedAttrs[property];
emailsToVerify.push({email, property});
}
@ -311,6 +318,18 @@ class NewslettersService {
}
}
// If one of the properties was changed, we need to reset sender_email in case it was not changed but is invalid in the database
// which can happen after a config change (= auto correcting behaviour)
const didChangeReplyTo = newsletter && attrs.sender_reply_to !== undefined && newsletter.get('sender_reply_to') !== attrs.sender_reply_to;
const didChangeSenderEmail = newsletter && (attrs.sender_email !== undefined && newsletter.get('sender_email') !== attrs.sender_email);
if (didChangeReplyTo && !didChangeSenderEmail && newsletter.get('sender_email')) {
const validated = this.emailAddressService.service.validate(newsletter.get('sender_email'), 'from');
if (!validated.allowed) {
logging.info(`Resetting sender_email for newsletter ${newsletter.id} because it became invalid`);
cleanedAttrs.sender_email = null;
}
}
return {cleanedAttrs, emailsToVerify};
}

View File

@ -2884,6 +2884,183 @@ Object {
}
`;
exports[`Newsletters API Managed email with custom sending domain Auto correcting invalid domains Browse returns sender_email as sender_reply_to in case we cannot send from sender_email and sender_reply_to is set to newsletter 1: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "5375",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email with custom sending domain Auto correcting invalid domains Does not reset sender_email when editing the newsletter (not the reply-to address) 1: [body] 1`] = `
Object {
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "notvalid@acme.com",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "daily-newsletter",
"sort_order": 1,
"status": "active",
"subscribe_on_signup": false,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
}
`;
exports[`Newsletters API Managed email with custom sending domain Auto correcting invalid domains Does not reset sender_email when editing the newsletter (not the reply-to address) 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "924",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-cache-invalidate": "/*",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email with custom sending domain Auto correcting invalid domains Read returns sender_email as sender_reply_to in case we cannot send from sender_email and sender_reply_to is set to newsletter 1: [body] 1`] = `
Object {
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "notvalid@acme.com",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "daily-newsletter",
"sort_order": 1,
"status": "active",
"subscribe_on_signup": false,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
}
`;
exports[`Newsletters API Managed email with custom sending domain Auto correcting invalid domains Read returns sender_email as sender_reply_to in case we cannot send from sender_email and sender_reply_to is set to newsletter 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "924",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email with custom sending domain Auto correcting invalid domains Resets sender_email when editing the newsletter reply_to address 1: [body] 1`] = `
Object {
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "support",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "daily-newsletter",
"sort_order": 1,
"status": "active",
"subscribe_on_signup": false,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
}
`;
exports[`Newsletters API Managed email with custom sending domain Auto correcting invalid domains Resets sender_email when editing the newsletter reply_to address 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "914",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-cache-invalidate": "/*",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email with custom sending domain Can clear sender_email 1: [body] 1`] = `
Object {
"newsletters": Array [
@ -2897,10 +3074,10 @@ Object {
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "anything@sendingdomain.com",
"sender_reply_to": "newsletter",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
@ -2929,7 +3106,7 @@ exports[`Newsletters API Managed email with custom sending domain Can clear send
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "923",
"content-length": "917",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -2952,10 +3129,10 @@ Object {
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "default@email.com",
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "anything@sendingdomain.com",
"sender_reply_to": "existing@acme.com",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
@ -2984,7 +3161,7 @@ exports[`Newsletters API Managed email with custom sending domain Can keep sende
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "938",
"content-length": "924",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -3012,8 +3189,8 @@ Object {
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "default@email.com",
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "newsletter",
"show_badge": true,
@ -3044,7 +3221,7 @@ exports[`Newsletters API Managed email with custom sending domain Can set newsle
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "977",
"content-length": "972",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -3326,8 +3503,8 @@ Object {
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "default@email.com",
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "anything@sendingdomain.com",
"show_badge": true,
@ -3358,7 +3535,7 @@ exports[`Newsletters API Managed email with custom sending domain Can set newsle
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "938",
"content-length": "933",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -3381,8 +3558,8 @@ Object {
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "default@email.com",
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "support",
"show_badge": true,
@ -3413,7 +3590,7 @@ exports[`Newsletters API Managed email with custom sending domain Can set newsle
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "919",
"content-length": "914",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -3436,8 +3613,8 @@ Object {
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "default@email.com",
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "newsletter",
"show_badge": true,
@ -3468,7 +3645,7 @@ exports[`Newsletters API Managed email with custom sending domain Can set newsle
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "922",
"content-length": "917",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -3491,10 +3668,10 @@ Object {
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"name": "My changed newsletter name",
"sender_email": "anything@sendingdomain.com",
"sender_name": "Jamie",
"sender_reply_to": "anything@sendingdomain.com",
"sender_reply_to": "newsletter",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
@ -3523,7 +3700,7 @@ exports[`Newsletters API Managed email with custom sending domain Can set sender
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "947",
"content-length": "941",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -3657,6 +3834,467 @@ Object {
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Browse returns sender_email as sender_reply_to in case we cannot send from sender_email and sender_reply_to is set to newsletter 1: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "5365",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Can switch sender_email to sender_reply_to without validation 1: [body] 1`] = `
Object {
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "notvalid@acme.com",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "daily-newsletter",
"sort_order": 1,
"status": "active",
"subscribe_on_signup": false,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Can switch sender_email to sender_reply_to without validation 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "914",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-cache-invalidate": "/*",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Does not reset sender_email when editing the newsletter (not the reply-to address) 1: [body] 1`] = `
Object {
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "notvalid@acme.com",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "daily-newsletter",
"sort_order": 1,
"status": "active",
"subscribe_on_signup": false,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Does not reset sender_email when editing the newsletter (not the reply-to address) 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "924",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-cache-invalidate": "/*",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Does not reset sender_email when editing the newsletter address (not the reply-to address) 1: [body] 1`] = `
Object {
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "newsletter",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "daily-newsletter",
"sort_order": 1,
"status": "active",
"subscribe_on_signup": false,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Does not reset sender_email when editing the newsletter address (not the reply-to address) 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "917",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-cache-invalidate": "/*",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Read returns sender_email as sender_reply_to in case we cannot send from sender_email and sender_reply_to is set to newsletter 1: [body] 1`] = `
Object {
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "notvalid@acme.com",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "daily-newsletter",
"sort_order": 1,
"status": "active",
"subscribe_on_signup": false,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Read returns sender_email as sender_reply_to in case we cannot send from sender_email and sender_reply_to is set to newsletter 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "914",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Resets sender_email when editing the newsletter reply_to address 1: [body] 1`] = `
Object {
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "support",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "daily-newsletter",
"sort_order": 1,
"status": "active",
"subscribe_on_signup": false,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Resets sender_email when editing the newsletter reply_to address 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "904",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-cache-invalidate": "/*",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Resets sender_email when editing the newsletter reply_to address in combination with keeping sender email 1: [body] 1`] = `
Object {
"meta": Object {
"sent_email_verification": Array [
"sender_reply_to",
],
},
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "newsletter",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "daily-newsletter",
"sort_order": 1,
"status": "active",
"subscribe_on_signup": false,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Resets sender_email when editing the newsletter reply_to address in combination with keeping sender email 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "962",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-cache-invalidate": "/*",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Resets sender_email when editing the newsletter reply_to address in combination with resetting sender email 1: [body] 1`] = `
Object {
"meta": Object {
"sent_email_verification": Array [
"sender_reply_to",
],
},
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "newsletter",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "daily-newsletter",
"sort_order": 1,
"status": "active",
"subscribe_on_signup": false,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Resets sender_email when editing the newsletter reply_to address in combination with resetting sender email 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "962",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-cache-invalidate": "/*",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Returns sender_email as sender_reply_to in case we cannot send from sender_email and sender_reply_to is set to newsletter 1: [body] 1`] = `
Object {
"newsletters": Array [
Object {
"background_color": "light",
"body_font_category": "serif",
"border_color": null,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": null,
"feedback_enabled": false,
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "notvalid@acme.com",
"sender_name": "Jamie",
"sender_reply_to": "newsletter",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
"show_header_icon": true,
"show_header_name": true,
"show_header_title": true,
"show_latest_posts": false,
"show_post_title_section": true,
"show_subscription_details": false,
"slug": "daily-newsletter",
"sort_order": 1,
"status": "active",
"subscribe_on_signup": false,
"title_alignment": "center",
"title_color": null,
"title_font_category": "serif",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "members",
},
],
}
`;
exports[`Newsletters API Managed email without custom sending domain Auto correcting invalid domains Returns sender_email as sender_reply_to in case we cannot send from sender_email and sender_reply_to is set to newsletter 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "922",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`Newsletters API Managed email without custom sending domain Can clear sender_email 1: [body] 1`] = `
Object {
"newsletters": Array [
@ -3726,9 +4364,9 @@ Object {
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "jamie@example.com",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "newsletter",
"sender_reply_to": "existing@acme.com",
"show_badge": true,
"show_comment_cta": true,
"show_feature_image": true,
@ -3757,7 +4395,7 @@ exports[`Newsletters API Managed email without custom sending domain Can keep se
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "922",
"content-length": "914",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -3896,7 +4534,7 @@ Object {
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "jamie@example.com",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "newsletter",
"show_badge": true,
@ -3927,7 +4565,7 @@ exports[`Newsletters API Managed email without custom sending domain Can set new
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "977",
"content-length": "962",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -4155,7 +4793,7 @@ Object {
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "jamie@example.com",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "support",
"show_badge": true,
@ -4186,7 +4824,7 @@ exports[`Newsletters API Managed email without custom sending domain Can set new
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "919",
"content-length": "904",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -4210,7 +4848,7 @@ Object {
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "jamie@example.com",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "newsletter",
"show_badge": true,
@ -4241,7 +4879,7 @@ exports[`Newsletters API Managed email without custom sending domain Can set new
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "922",
"content-length": "907",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -4265,7 +4903,7 @@ Object {
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "jamie@example.com",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "default@email.com",
"show_badge": true,
@ -4296,7 +4934,7 @@ exports[`Newsletters API Managed email without custom sending domain Can set new
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "929",
"content-length": "914",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -4498,7 +5136,7 @@ Object {
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"name": "My changed newsletter name",
"sender_email": "hello@acme.com",
"sender_name": "Jamie",
"sender_reply_to": "hello@acme.com",
@ -4530,7 +5168,7 @@ exports[`Newsletters API Self hoster without managed email Can change sender_ema
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "923",
"content-length": "933",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -4553,7 +5191,7 @@ Object {
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "hello@acme.com",
@ -4585,7 +5223,7 @@ exports[`Newsletters API Self hoster without managed email Can clear sender_emai
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "911",
"content-length": "921",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -4663,8 +5301,8 @@ Object {
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "anything@sendingdomain.com",
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "hello@acme.com",
"show_badge": true,
@ -4695,7 +5333,7 @@ exports[`Newsletters API Self hoster without managed email Can set newsletter re
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "935",
"content-length": "921",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -4718,8 +5356,8 @@ Object {
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "anything@sendingdomain.com",
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "support",
"show_badge": true,
@ -4750,7 +5388,7 @@ exports[`Newsletters API Self hoster without managed email Can set newsletter re
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "928",
"content-length": "914",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -4773,8 +5411,8 @@ Object {
"footer_content": null,
"header_image": "http://127.0.0.1:2369/content/images/2022/05/test.jpg",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"name": "Daily newsletter",
"sender_email": "anything@sendingdomain.com",
"name": "My changed newsletter name",
"sender_email": null,
"sender_name": "Jamie",
"sender_reply_to": "newsletter",
"show_badge": true,
@ -4805,7 +5443,7 @@ exports[`Newsletters API Self hoster without managed email Can set newsletter re
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "931",
"content-length": "917",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,

View File

@ -14,6 +14,16 @@ const assertMemberRelationCount = async (newsletterId, expectedCount) => {
assert.equal(relations.length, expectedCount);
};
// Change directly in database, to test edge cases
async function editNewsletter(id, changes) {
await dbUtils.knex('newsletters').where({id}).update(changes);
}
// Get directly from the database
async function getNewsletter(id) {
return (await dbUtils.knex('newsletters').where({id}))[0];
}
const newsletterSnapshot = {
id: anyObjectId,
uuid: anyUuid,
@ -868,6 +878,175 @@ describe('Newsletters API', function () {
configUtils.set('mail:from', 'default@email.com');
});
describe('Auto correcting invalid domains', function () {
const id = fixtureManager.get('newsletters', 0).id;
beforeEach(async function () {
// Invalid situation in the database)
await editNewsletter(id, {
sender_email: 'notvalid@acme.com',
sender_reply_to: 'newsletter'
});
});
after(async function () {
// Reset
await editNewsletter(id, {
sender_email: null,
sender_reply_to: 'newsletter'
});
});
it('Read returns sender_email as sender_reply_to in case we cannot send from sender_email and sender_reply_to is set to newsletter', async function () {
const {body} = await agent.get(`newsletters/${id}`)
.expectStatus(200)
.matchBodySnapshot({
newsletters: [newsletterSnapshot]
})
.matchHeaderSnapshot({
'content-version': anyContentVersion,
etag: anyEtag
});
// Do a manual check to make sure we don't accidentally change snapshots
assert.equal(body.newsletters[0].sender_email, null);
assert.equal(body.newsletters[0].sender_reply_to, 'notvalid@acme.com');
});
it('Browse returns sender_email as sender_reply_to in case we cannot send from sender_email and sender_reply_to is set to newsletter', async function () {
const {body} = await agent.get(`newsletters`)
.expectStatus(200)
.matchHeaderSnapshot({
'content-version': anyContentVersion,
etag: anyEtag
});
const newsletter = body.newsletters.find(n => n.id === id);
// Do a manual check to make sure we don't accidentally change snapshots
assert.equal(newsletter.sender_email, null);
assert.equal(newsletter.sender_reply_to, 'notvalid@acme.com');
});
it('Resets sender_email when editing the newsletter reply_to address', async function () {
await agent.put(`newsletters/${id}`)
.body({
newsletters: [{
sender_reply_to: 'support'
}]
})
.expectStatus(200)
.matchBodySnapshot({
newsletters: [newsletterSnapshot]
})
.matchHeaderSnapshot({
'content-version': anyContentVersion,
etag: anyEtag
});
const newsletter = await getNewsletter(id);
// Do a manual check to make sure we don't accidentally change snapshots
assert.equal(newsletter.sender_email, null);
assert.equal(newsletter.sender_reply_to, 'support');
});
it('Resets sender_email when editing the newsletter reply_to address in combination with resetting sender email', async function () {
await agent.put(`newsletters/${id}`)
.body({
newsletters: [{
sender_email: null,
sender_reply_to: 'something@allowed.com'
}]
})
.expectStatus(200)
.matchBodySnapshot({
newsletters: [newsletterSnapshot]
})
.matchHeaderSnapshot({
'content-version': anyContentVersion,
etag: anyEtag
});
const newsletter = await getNewsletter(id);
// Do a manual check to make sure we don't accidentally change snapshots
assert.equal(newsletter.sender_email, null);
assert.equal(newsletter.sender_reply_to, 'newsletter'); // required validation
});
it('Resets sender_email when editing the newsletter reply_to address in combination with keeping sender email', async function () {
await agent.put(`newsletters/${id}`)
.body({
newsletters: [{
sender_email: 'notvalid@acme.com',
sender_reply_to: 'something@allowed.com'
}]
})
.expectStatus(200)
.matchBodySnapshot({
newsletters: [newsletterSnapshot]
})
.matchHeaderSnapshot({
'content-version': anyContentVersion,
etag: anyEtag
});
const newsletter = await getNewsletter(id);
// Do a manual check to make sure we don't accidentally change snapshots
assert.equal(newsletter.sender_email, null);
assert.equal(newsletter.sender_reply_to, 'newsletter'); // required validation
});
it('Can switch sender_email to sender_reply_to without validation', async function () {
// The frontend will try to do this because it gets the mapped values from the API
await agent.put(`newsletters/${id}`)
.body({
newsletters: [{
sender_email: null,
sender_reply_to: 'notvalid@acme.com'
}]
})
.expectStatus(200)
.matchBodySnapshot({
newsletters: [newsletterSnapshot]
})
.matchHeaderSnapshot({
'content-version': anyContentVersion,
etag: anyEtag
});
const newsletter = await getNewsletter(id);
// Do a manual check to make sure we don't accidentally change snapshots
assert.equal(newsletter.sender_email, null);
assert.equal(newsletter.sender_reply_to, 'notvalid@acme.com'); // did not require validation
});
it('Does not reset sender_email when editing the newsletter (not the reply-to address)', async function () {
await agent.put(`newsletters/${id}`)
.body({
newsletters: [{
name: 'My changed newsletter name'
}]
})
.expectStatus(200)
.matchBodySnapshot({
newsletters: [newsletterSnapshot]
})
.matchHeaderSnapshot({
'content-version': anyContentVersion,
etag: anyEtag
});
const newsletter = await getNewsletter(id);
assert.equal(newsletter.name, 'My changed newsletter name');
assert.equal(newsletter.sender_email, 'notvalid@acme.com');
assert.equal(newsletter.sender_reply_to, 'newsletter');
});
});
it('Can set newsletter reply-to to newsletter or support', async function () {
const id = fixtureManager.get('newsletters', 0).id;
@ -1061,6 +1240,12 @@ describe('Newsletters API', function () {
it('Can keep sender_email', async function () {
const id = fixtureManager.get('newsletters', 0).id;
// Invalid situation in the database)
await editNewsletter(id, {
sender_email: 'existing@acme.com',
sender_reply_to: 'newsletter'
});
const before = await models.Newsletter.findOne({id});
assert(before.get('sender_email'), 'This test requires a non empty sender_email');
@ -1147,6 +1332,102 @@ describe('Newsletters API', function () {
configUtils.set('hostSettings:managedEmail:sendingDomain', 'sendingdomain.com');
});
describe('Auto correcting invalid domains', function () {
const id = fixtureManager.get('newsletters', 0).id;
beforeEach(async function () {
// Invalid situation in the database)
await editNewsletter(id, {
sender_email: 'notvalid@acme.com',
sender_reply_to: 'newsletter'
});
});
after(async function () {
// Reset
await editNewsletter(id, {
sender_email: null,
sender_reply_to: 'newsletter'
});
});
it('Read returns sender_email as sender_reply_to in case we cannot send from sender_email and sender_reply_to is set to newsletter', async function () {
const {body} = await agent.get(`newsletters/${id}`)
.expectStatus(200)
.matchBodySnapshot({
newsletters: [newsletterSnapshot]
})
.matchHeaderSnapshot({
'content-version': anyContentVersion,
etag: anyEtag
});
// Do a manual check to make sure we don't accidentally change snapshots
assert.equal(body.newsletters[0].sender_email, null);
assert.equal(body.newsletters[0].sender_reply_to, 'notvalid@acme.com');
});
it('Browse returns sender_email as sender_reply_to in case we cannot send from sender_email and sender_reply_to is set to newsletter', async function () {
const {body} = await agent.get(`newsletters`)
.expectStatus(200)
.matchHeaderSnapshot({
'content-version': anyContentVersion,
etag: anyEtag
});
const newsletter = body.newsletters.find(n => n.id === id);
// Do a manual check to make sure we don't accidentally change snapshots
assert.equal(newsletter.sender_email, null);
assert.equal(newsletter.sender_reply_to, 'notvalid@acme.com');
});
it('Resets sender_email when editing the newsletter reply_to address', async function () {
await agent.put(`newsletters/${id}`)
.body({
newsletters: [{
sender_reply_to: 'support'
}]
})
.expectStatus(200)
.matchBodySnapshot({
newsletters: [newsletterSnapshot]
})
.matchHeaderSnapshot({
'content-version': anyContentVersion,
etag: anyEtag
});
const newsletter = await getNewsletter(id);
// Do a manual check to make sure we don't accidentally change snapshots
assert.equal(newsletter.sender_email, null);
assert.equal(newsletter.sender_reply_to, 'support');
});
it('Does not reset sender_email when editing the newsletter (not the reply-to address)', async function () {
await agent.put(`newsletters/${id}`)
.body({
newsletters: [{
name: 'My changed newsletter name'
}]
})
.expectStatus(200)
.matchBodySnapshot({
newsletters: [newsletterSnapshot]
})
.matchHeaderSnapshot({
'content-version': anyContentVersion,
etag: anyEtag
});
const newsletter = await getNewsletter(id);
assert.equal(newsletter.name, 'My changed newsletter name');
assert.equal(newsletter.sender_email, 'notvalid@acme.com');
assert.equal(newsletter.sender_reply_to, 'newsletter');
});
});
it('Can set newsletter reply-to to newsletter or support', async function () {
const id = fixtureManager.get('newsletters', 0).id;
@ -1333,6 +1614,12 @@ describe('Newsletters API', function () {
it('Can keep sender_email', async function () {
const id = fixtureManager.get('newsletters', 0).id;
// Invalid situation in the database)
await editNewsletter(id, {
sender_email: 'existing@acme.com',
sender_reply_to: 'newsletter'
});
const before = await models.Newsletter.findOne({id});
assert(before.get('sender_email'), 'This test requires a non empty sender_email');

View File

@ -219,7 +219,9 @@ describe('Unit: utils/serializers/output/mappers', function () {
const newsletter = createJsonModel(testUtils.DataGenerator.forKnex.createNewsletter({
name: 'Full newsletter',
slug: 'full-newsletter'
slug: 'full-newsletter',
sender_email: null,
sender_reply_to: 'newsletter'
}));
const mapped = mappers.newsletters(newsletter, frame);

View File

@ -102,14 +102,12 @@ describe('NewslettersService', function () {
// @TODO replace this with a specific function for fetching all available newsletters
describe('browse', function () {
it('lists all newsletters by calling findAll and toJSON', async function () {
const toJSONStub = sinon.stub();
const findAllStub = sinon.stub(models.Newsletter, 'findAll').returns({toJSON: toJSONStub});
it('lists all newsletters by calling findPage', async function () {
const findAllStub = sinon.stub(models.Newsletter, 'findPage').returns({data: []});
await newsletterService.browse({});
sinon.assert.calledOnce(findAllStub);
sinon.assert.calledOnce(toJSONStub);
});
});

View File

@ -487,10 +487,10 @@ module.exports = class RouterController {
if (requestedNewsletters && requestedNewsletters.length > 0 && requestedNewsletters.every(newsletter => newsletter.name !== undefined)) {
const newsletterNames = requestedNewsletters.map(newsletter => newsletter.name);
const newsletterNamesFilter = newsletterNames.map(newsletter => `'${newsletter.replace(/("|')/g, '\\$1')}'`);
const newsletters = await this._newslettersService.browse({
const newsletters = (await this._newslettersService.getAll({
filter: `name:[${newsletterNamesFilter}]`,
columns: ['id','name','status']
});
}));
if (newsletters.length !== newsletterNames.length) { //check for invalid newsletters
const validNewsletters = newsletters.map(newsletter => newsletter.name);

View File

@ -401,7 +401,7 @@ module.exports = class MemberRepository {
// By default subscribe to all active auto opt-in newsletters with members visibility
//TODO: Will mostly need to be updated later for paid-only newsletters
browseOptions.filter = 'status:active+subscribe_on_signup:true+visibility:members';
const newsletters = await this._newslettersService.browse(browseOptions);
const newsletters = await this._newslettersService.getAll(browseOptions);
return newsletters || [];
}

View File

@ -146,10 +146,10 @@ describe('RouterController', function () {
const newsletterNames = newsletters.map(newsletter => newsletter.name);
const newsletterNamesFilter = newsletterNames.map(newsletter => `'${newsletter.replace(/("|')/g, '\\$1')}'`);
const newslettersServiceStub = {
browse: sinon.stub()
getAll: sinon.stub()
};
newslettersServiceStub.browse
newslettersServiceStub.getAll
.withArgs({
filter: `name:[${newsletterNamesFilter}]`,
columns: ['id','name','status']
@ -181,10 +181,10 @@ describe('RouterController', function () {
];
const newslettersServiceStub = {
browse: sinon.stub()
getAll: sinon.stub()
};
newslettersServiceStub.browse
newslettersServiceStub.getAll
.withArgs({
filter: `name:['${INVALID_NEWSLETTER_NAME}']`,
columns: ['id','name','status']
@ -221,10 +221,10 @@ describe('RouterController', function () {
const newsletterNames = newsletters.map(newsletter => `'${newsletter.name}'`);
const newslettersServiceStub = {
browse: sinon.stub()
getAll: sinon.stub()
};
newslettersServiceStub.browse
newslettersServiceStub.getAll
.withArgs({
filter: `name:[${newsletterNames}]`,
columns: ['id', 'name','status']