Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 92 additions & 11 deletions ghost/core/core/server/api/endpoints/automated-emails.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const _ = require('lodash');
const tpl = require('@tryghost/tpl');
const errors = require('@tryghost/errors');
const models = require('../../models');
Expand All @@ -7,6 +8,32 @@ const messages = {
automatedEmailNotFound: 'Automated email not found.'
};

// NOTE: This file is in a transitionary state. The `automated_emails` database table was split into
// `welcome_email_automations` (automation metadata: status, name, slug) and
// `welcome_email_automated_emails` (email content: subject, lexical, sender fields). This controller
// acts as a facade that joins/splits data between those two models while preserving the original
// `automated_emails` API shape externally.
const AUTOMATION_FIELDS = ['status', 'name', 'slug'];
const EMAIL_FIELDS = ['subject', 'lexical', 'sender_name', 'sender_email', 'sender_reply_to', 'email_design_setting_id'];

function flattenAutomation(automation, email = automation.related('welcomeEmailAutomatedEmail')) {
const result = {
id: automation.id,
status: automation.get('status'),
name: automation.get('name'),
slug: automation.get('slug'),
subject: email.get('subject'),
lexical: email.get('lexical'),
sender_name: email.get('sender_name'),
sender_email: email.get('sender_email'),
sender_reply_to: email.get('sender_reply_to'),
email_design_setting_id: email.get('email_design_setting_id'),
created_at: automation.get('created_at'),
updated_at: automation.get('updated_at')
};
return result;
}

/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'automated_emails',
Expand All @@ -23,8 +50,15 @@ const controller = {
'page'
],
permissions: true,
query(frame) {
return models.AutomatedEmail.findPage(frame.options);
async query(frame) {
const result = await models.WelcomeEmailAutomation.findPage({
...frame.options,
withRelated: ['welcomeEmailAutomatedEmail']
});
return {
...result,
data: result.data.map(automation => flattenAutomation(automation))
};
}
},

Expand All @@ -41,14 +75,17 @@ const controller = {
],
permissions: true,
async query(frame) {
const model = await models.AutomatedEmail.findOne(frame.data, frame.options);
const model = await models.WelcomeEmailAutomation.findOne(frame.data, {
...frame.options,
withRelated: ['welcomeEmailAutomatedEmail']
});
if (!model) {
throw new errors.NotFoundError({
message: tpl(messages.automatedEmailNotFound)
});
}

return model;
return flattenAutomation(model);
}
},

Expand All @@ -60,7 +97,24 @@ const controller = {
permissions: true,
async query(frame) {
const data = frame.data.automated_emails[0];
return models.AutomatedEmail.add(data, frame.options);

const emailData = _.pick(data, EMAIL_FIELDS);
const automationData = _.pick(data, AUTOMATION_FIELDS);

return models.Base.transaction(async (transacting) => {
// Create automation first (emails reference automations via FK)
const automation = await models.WelcomeEmailAutomation.add(automationData, {...frame.options, transacting});
emailData.welcome_email_automation_id = automation.id;
const email = await models.WelcomeEmailAutomatedEmail.add(emailData, {...frame.options, transacting});

// Set the back-reference from automation to its first email
const updatedAutomation = await models.WelcomeEmailAutomation.edit(
{first_welcome_email_automated_email_id: email.id},
{id: automation.id, transacting}
);

return flattenAutomation(updatedAutomation, email);
});
}
},

Expand All @@ -79,16 +133,43 @@ const controller = {
}
},
permissions: true,
// eslint-disable-next-line ghost/ghost-custom/max-api-complexity
async query(frame) {
const data = frame.data.automated_emails[0];
const model = await models.AutomatedEmail.edit(data, frame.options);
if (!model) {
throw new errors.NotFoundError({
message: tpl(messages.automatedEmailNotFound)

const emailData = _.pick(data, EMAIL_FIELDS);
const automationData = _.pick(data, AUTOMATION_FIELDS);

return models.Base.transaction(async (transacting) => {
let automation = await models.WelcomeEmailAutomation.findOne({id: frame.options.id}, {
transacting,
withRelated: ['welcomeEmailAutomatedEmail']
});
}
if (!automation) {
throw new errors.NotFoundError({
message: tpl(messages.automatedEmailNotFound)
});
}

let email = automation.related('welcomeEmailAutomatedEmail');

return model;
if (Object.keys(emailData).length > 0) {
email = await models.WelcomeEmailAutomatedEmail.edit(emailData, {
...frame.options,
transacting,
id: automation.get('first_welcome_email_automated_email_id')
});
}

if (Object.keys(automationData).length > 0) {
automation = await models.WelcomeEmailAutomation.edit(automationData, {
...frame.options,
transacting
});
}

return flattenAutomation(automation, email);
});
}
},

Expand Down
3 changes: 2 additions & 1 deletion ghost/core/core/server/data/exporter/table-lists.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ const BACKUP_TABLES = [
'actions',
'api_keys',
'automated_email_recipients',
'automated_emails',
'welcome_email_automated_emails',
'welcome_email_automations',
'brute',
'donation_payment_events',
'email_design_settings',
Expand Down
Loading
Loading