mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-24 19:33:02 +03:00
Added email_recipients
include option to members API read endpoint (#12471)
refs https://github.com/TryGhost/Ghost-Admin/pull/1796 We want to be able to display an email activity timeline in Ghost-Admin for each member. The quickest way to achieve that right now is to provide access to the `email_recipient` data for the member when fetching, this will allow clients to build up a timeline based on the event timestamps included with each email_recipient/email pair. - sets up `email_recipients` relationship in `Member` model - updates members API read endpoint to accept an `email_recipients` include parameter - appends `email_recipients.email` to the `withRelated` array when `email_recipients` is included so that we have data available for email subject and html/plaintext for previews - updates members API output serializer to include the email_recipients object in the output
This commit is contained in:
parent
9586d1ce56
commit
c1d66f0b01
@ -13,6 +13,7 @@ const {i18n} = require('../../lib/common');
|
||||
const db = require('../../data/db');
|
||||
|
||||
const ghostMailer = new GhostMailer();
|
||||
const allowedIncludes = ['email_recipients'];
|
||||
|
||||
module.exports = {
|
||||
docName: 'members',
|
||||
@ -51,15 +52,35 @@ module.exports = {
|
||||
},
|
||||
|
||||
read: {
|
||||
options: [
|
||||
'include'
|
||||
],
|
||||
headers: {},
|
||||
data: [
|
||||
'id',
|
||||
'email'
|
||||
],
|
||||
validation: {},
|
||||
validation: {
|
||||
options: {
|
||||
include: {
|
||||
values: allowedIncludes
|
||||
}
|
||||
}
|
||||
},
|
||||
permissions: true,
|
||||
async query(frame) {
|
||||
frame.options.withRelated = ['labels', 'stripeSubscriptions', 'stripeSubscriptions.customer'];
|
||||
const defaultWithRelated = ['labels', 'stripeSubscriptions', 'stripeSubscriptions.customer'];
|
||||
|
||||
if (!frame.options.withRelated) {
|
||||
frame.options.withRelated = defaultWithRelated;
|
||||
} else {
|
||||
frame.options.withRelated = frame.options.withRelated.concat(defaultWithRelated);
|
||||
}
|
||||
|
||||
if (frame.options.withRelated.includes('email_recipients')) {
|
||||
frame.options.withRelated.push('email_recipients.email');
|
||||
}
|
||||
|
||||
let model = await membersService.api.members.get(frame.data, frame.options);
|
||||
|
||||
if (!model) {
|
||||
|
@ -103,7 +103,8 @@ function serializeMember(member, options) {
|
||||
comped: comped,
|
||||
email_count: json.email_count,
|
||||
email_opened_count: json.email_opened_count,
|
||||
email_open_rate: json.email_open_rate
|
||||
email_open_rate: json.email_open_rate,
|
||||
email_recipients: json.email_recipients
|
||||
};
|
||||
}
|
||||
|
||||
@ -150,6 +151,7 @@ function createSerializer(debugString, serialize) {
|
||||
* @prop {number} email_count
|
||||
* @prop {number} email_opened_count
|
||||
* @prop {number} email_open_rate
|
||||
* @prop {null|SerializedEmailRecipient[]} email_recipients
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -180,6 +182,48 @@ function createSerializer(debugString, serialize) {
|
||||
* @prop {string} plan.currency_symbol
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SerializedEmailRecipient
|
||||
*
|
||||
* @prop {string} id
|
||||
* @prop {string} email_id
|
||||
* @prop {string} batch_id
|
||||
* @prop {string} processed_at
|
||||
* @prop {string} delivered_at
|
||||
* @prop {string} opened_at
|
||||
* @prop {string} failed_at
|
||||
* @prop {string} member_uuid
|
||||
* @prop {string} member_email
|
||||
* @prop {string} member_name
|
||||
* @prop {SerializedEmail[]} email
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SerializedEmail
|
||||
*
|
||||
* @prop {string} id
|
||||
* @prop {string} post_id
|
||||
* @prop {string} uuid
|
||||
* @prop {string} status
|
||||
* @prop {string} recipient_filter
|
||||
* @prop {null|string} error
|
||||
* @prop {string} error_data
|
||||
* @prop {number} email_count
|
||||
* @prop {number} delivered_count
|
||||
* @prop {number} opened_count
|
||||
* @prop {number} failed_count
|
||||
* @prop {string} subject
|
||||
* @prop {string} from
|
||||
* @prop {string} reply_to
|
||||
* @prop {string} html
|
||||
* @prop {string} plaintext
|
||||
* @prop {boolean} track_opens
|
||||
* @prop {string} created_at
|
||||
* @prop {string} created_by
|
||||
* @prop {string} updated_at
|
||||
* @prop {string} updated_by
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} APIConfig
|
||||
* @prop {string} docName
|
||||
|
@ -4,6 +4,12 @@ const EmailRecipient = ghostBookshelf.Model.extend({
|
||||
tableName: 'email_recipients',
|
||||
hasTimestamps: false,
|
||||
|
||||
relationships: ['email'],
|
||||
|
||||
relationshipBelongsTo: {
|
||||
email: 'emails'
|
||||
},
|
||||
|
||||
email() {
|
||||
return this.belongsTo('Email', 'email_id');
|
||||
},
|
||||
|
@ -17,11 +17,12 @@ const Member = ghostBookshelf.Model.extend({
|
||||
};
|
||||
},
|
||||
|
||||
relationships: ['labels', 'stripeCustomers'],
|
||||
relationships: ['labels', 'stripeCustomers', 'email_recipients'],
|
||||
|
||||
relationshipBelongsTo: {
|
||||
labels: 'labels',
|
||||
stripeCustomers: 'members_stripe_customers'
|
||||
stripeCustomers: 'members_stripe_customers',
|
||||
email_recipients: 'email_recipients'
|
||||
},
|
||||
|
||||
labels: function labels() {
|
||||
@ -50,6 +51,10 @@ const Member = ghostBookshelf.Model.extend({
|
||||
);
|
||||
},
|
||||
|
||||
email_recipients() {
|
||||
return this.hasMany('EmailRecipient', 'member_id', 'id');
|
||||
},
|
||||
|
||||
serialize(options) {
|
||||
const defaultSerializedObject = ghostBookshelf.Model.prototype.serialize.call(this, options);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user