Ghost/ghost/data-generator/lib/tables/email-recipients.js
Sam Lord c72dcd629f Fixed balance of email recipient data in data generator
no issue

Previously the number of opened emails was being generated incorrectly as the number of delivered emails was being reported too high.

Also, the faker date function occasionally fails for dates which are
too close together so this switches to manually generating a date
between the two.
2023-02-21 23:50:02 +00:00

105 lines
4.0 KiB
JavaScript

const TableImporter = require('./base');
const {faker} = require('@faker-js/faker');
const generateEvents = require('../utils/event-generator');
const dateToDatabaseString = require('../utils/database-date');
const emailStatus = {
delivered: Symbol(),
opened: Symbol(),
failed: Symbol(),
none: Symbol()
};
class EmailRecipientsImporter extends TableImporter {
static table = 'email_recipients';
constructor(knex, {emailBatches, members, membersSubscribeEvents}) {
super(EmailRecipientsImporter.table, knex);
this.emailBatches = emailBatches;
this.members = members;
this.membersSubscribeEvents = membersSubscribeEvents;
}
setImportOptions({model}) {
this.model = model;
this.batch = this.emailBatches.find(batch => batch.email_id === model.id);
// Shallow clone members list so we can shuffle and modify it
const earliestOpenTime = new Date(this.batch.updated_at);
const latestOpenTime = new Date(this.batch.updated_at);
latestOpenTime.setDate(latestOpenTime.getDate() + 14);
const currentTime = new Date();
this.membersList = this.membersSubscribeEvents
.filter(entry => entry.newsletter_id === this.model.newsletter_id)
.filter(entry => new Date(entry.created_at) < earliestOpenTime)
.map(memberSubscribeEvent => memberSubscribeEvent.member_id);
this.events = this.membersList.length > 0 ? generateEvents({
shape: 'ease-out',
trend: 'negative',
total: this.membersList.length,
startTime: earliestOpenTime,
endTime: currentTime < latestOpenTime ? currentTime : latestOpenTime
}) : [];
this.emailMeta = {
emailCount: this.model.email_count,
// delievered and not opened
deliveredCount: this.model.delivered_count - this.model.opened_count,
openedCount: this.model.opened_count,
failedCount: this.model.failed_count
};
}
generate() {
if (this.emailMeta.emailCount <= 0) {
return;
}
this.emailMeta.emailCount -= 1;
const timestamp = this.events.shift();
if (!timestamp) {
return;
}
const memberIdIndex = faker.datatype.number({
min: 0,
max: this.membersList.length - 1
});
const [memberId] = this.membersList.splice(memberIdIndex, 1);
const member = this.members.find(m => m.id === memberId);
let status = emailStatus.none;
if (this.emailMeta.failedCount > 0) {
status = emailStatus.failed;
this.emailMeta.failedCount -= 1;
} else if (this.emailMeta.openedCount > 0) {
status = emailStatus.opened;
this.emailMeta.openedCount -= 1;
} else if (this.emailMeta.deliveredCount > 0) {
status = emailStatus.delivered;
this.emailMeta.deliveredCount -= 1;
}
let deliveredTime;
if (status === emailStatus.opened) {
const startDate = new Date(this.batch.updated_at).valueOf();
const endDate = timestamp.valueOf();
deliveredTime = new Date(startDate + (Math.random() * (endDate - startDate)));
}
return {
id: faker.database.mongodbObjectId(),
email_id: this.model.id,
batch_id: this.batch.id,
member_id: member.id,
processed_at: this.batch.updated_at,
delivered_at: status === emailStatus.opened ? dateToDatabaseString(deliveredTime) : status === emailStatus.delivered ? dateToDatabaseString(timestamp) : null,
opened_at: status === emailStatus.opened ? dateToDatabaseString(timestamp) : null,
failed_at: status === emailStatus.failed ? dateToDatabaseString(timestamp) : null,
member_uuid: member.uuid,
member_email: member.email,
member_name: member.name
};
}
}
module.exports = EmailRecipientsImporter;