Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {faker} from '@faker-js/faker';
import errors from '@tryghost/errors';
import type {Knex} from 'knex';
import {TableImporter} from './table-importer';
import * as databaseDate from '../utils/database-date';
import {fromDatabaseDate, toDatabaseDate} from '../../../lib/db-date';
import {DEFAULT_EMAIL_DESIGN_SETTING_SLUG} from '../../../services/member-welcome-emails/constants';

type AutomationAction = {
Expand Down Expand Up @@ -66,13 +66,13 @@ export class AutomationActionRevisionsImporter extends TableImporter<AutomationA
throw new errors.IncorrectUsageError({message: 'Cannot generate automation action revision without an action'});
}

const createdAt = databaseDate.parse(this.#action.created_at);
const createdAt = fromDatabaseDate(this.#action.created_at);
createdAt.setSeconds(createdAt.getSeconds() + this.#revisionIndex);
this.#revisionIndex += 1;

const common = {
id: this.fastFakeObjectId(),
created_at: databaseDate.dateToDatabaseString(createdAt),
created_at: toDatabaseDate(createdAt),
action_id: this.#action.id,
email_sent_count: null,
email_opened_count: null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {faker} from '@faker-js/faker';
import errors from '@tryghost/errors';
import type {Knex} from 'knex';
import {TableImporter} from './table-importer';
import * as databaseDate from '../utils/database-date';
import {toDatabaseDate} from '../../../lib/db-date';
import {randomDateBetween} from '../utils/random';

type Automation = {
id: string;
Expand Down Expand Up @@ -50,17 +50,14 @@ export class AutomationActionsImporter extends TableImporter<AutomationAction, A
throw new errors.IncorrectUsageError({message: 'Cannot generate automation action without an automation'});
}

const createdAt = faker.date.between({
from: databaseDate.parse(this.#automation.created_at),
to: new Date()
});
const createdAt = randomDateBetween(this.#automation.created_at, new Date());
const type = this.#actionIndex % 2 === 0 ? 'wait' : 'send_email';
this.#actionIndex += 1;

return {
id: this.fastFakeObjectId(),
created_at: databaseDate.dateToDatabaseString(createdAt),
updated_at: databaseDate.dateToDatabaseString(createdAt),
created_at: toDatabaseDate(createdAt),
updated_at: toDatabaseDate(createdAt),
deleted_at: null,
automation_id: this.#automation.id,
type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import errors from '@tryghost/errors';
import {clamp} from 'lodash';
import type {Knex} from 'knex';
import {TableImporter} from './table-importer';
import * as databaseDate from '../utils/database-date';
import {fromDatabaseDate, toDatabaseDate} from '../../../lib/db-date';

type AutomationRun = {
id: string;
Expand Down Expand Up @@ -113,13 +113,13 @@ export class AutomationRunStepsImporter extends TableImporter<AutomationRunStep>
const requestedStepCount = clamp(Math.floor(stepsPerRun) + extraStep, 1, actionCount);
const runStepCount = fullPathGeneratedForAutomation.has(run.automation_id) ? requestedStepCount : actionCount;
fullPathGeneratedForAutomation.add(run.automation_id);
const runCreatedAt = databaseDate.parse(run.created_at);
const runCreatedAt = fromDatabaseDate(run.created_at);
const lastStepStatus = faker.helpers.arrayElement(['pending', 'finished', 'failed'] as const);

for (let index = 0; index < runStepCount; index += 1) {
const createdAt = new Date(runCreatedAt);
createdAt.setHours(createdAt.getHours() + index);
const createdAtString = databaseDate.dateToDatabaseString(createdAt);
const createdAtString = toDatabaseDate(createdAt);
const status = index === runStepCount - 1 ? lastStepStatus : 'finished';
const isTerminal = status !== 'pending';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import assert from 'node:assert/strict';
import type {Knex} from 'knex';
import {TableImporter} from './table-importer';
import {parseEmailAddress} from '@tryghost/parse-email-address';
import * as databaseDate from '../utils/database-date';
import {fromDatabaseDate, toDatabaseDate} from '../../../lib/db-date';
import {randomDateBetween} from '../utils/random';

type Automation = {
id: string;
Expand Down Expand Up @@ -73,19 +74,16 @@ export class AutomationRunsImporter extends TableImporter<AutomationRun, Automat
}

const member = faker.helpers.arrayElement(this.#members);
const automationCreatedAt = databaseDate.parse(this.#automation.created_at);
const memberCreatedAt = databaseDate.parse(member.created_at);
const createdAt = faker.date.between({
from: new Date(Math.max(automationCreatedAt.valueOf(), memberCreatedAt.valueOf())),
to: new Date()
});
const automationCreatedAt = fromDatabaseDate(this.#automation.created_at);
const memberCreatedAt = fromDatabaseDate(member.created_at);
const createdAt = randomDateBetween(new Date(Math.max(automationCreatedAt.valueOf(), memberCreatedAt.valueOf())), new Date());

assertExampleEmailDomain(member.email);

return {
id: this.fastFakeObjectId(),
created_at: databaseDate.dateToDatabaseString(createdAt),
updated_at: databaseDate.dateToDatabaseString(createdAt),
created_at: toDatabaseDate(createdAt),
updated_at: toDatabaseDate(createdAt),
automation_id: this.#automation.id,
member_id: member.id,
member_email: member.email
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {Knex} from 'knex';
import {TableImporter} from './table-importer';
// @ts-expect-error This module currently lacks type definitions.
import {blogStartDate} from '../utils/blog-info';
import * as databaseDate from '../utils/database-date';
import {toDatabaseDate} from '../../../lib/db-date';
import {MEMBER_WELCOME_EMAIL_SLUGS} from '../../../services/member-welcome-emails/constants';

type Automation = {
Expand Down Expand Up @@ -52,8 +52,8 @@ export class AutomationsImporter extends TableImporter<Automation> {
status: faker.helpers.arrayElement(['active', 'inactive']),
name,
slug,
created_at: databaseDate.dateToDatabaseString(createdAt),
updated_at: databaseDate.dateToDatabaseString(createdAt)
created_at: toDatabaseDate(createdAt),
updated_at: toDatabaseDate(createdAt)
};
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const {TableImporter} = require('./table-importer');
const {faker} = require('@faker-js/faker');
const {luck} = require('../utils/random');
const databaseDate = require('../utils/database-date');
const {luck, randomDateBetween} = require('../utils/random');
const {toDatabaseDate} = require('../../../lib/db-date');

class CommentReportsImporter extends TableImporter {
static table = 'comment_reports';
Expand Down Expand Up @@ -49,16 +49,16 @@ class CommentReportsImporter extends TableImporter {
return null;
}

const reportTime = databaseDate.randomBetween(this.model.created_at, new Date());
const reportTime = randomDateBetween(this.model.created_at, new Date());

const reporter = this.possibleReporters[faker.number.int(this.possibleReporters.length - 1)];

return {
id: this.fastFakeObjectId(),
comment_id: this.model.id,
member_id: reporter.id,
created_at: databaseDate.dateToDatabaseString(reportTime),
updated_at: databaseDate.dateToDatabaseString(reportTime)
created_at: toDatabaseDate(reportTime),
updated_at: toDatabaseDate(reportTime)
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const {faker} = require('@faker-js/faker');
const {TableImporter} = require('./table-importer');
const {luck} = require('../utils/random');
const generateEvents = require('../utils/event-generator');
const databaseDate = require('../utils/database-date');
const {fromDatabaseDate, toDatabaseDate} = require('../../../lib/db-date');

class CommentsImporter extends TableImporter {
static table = 'comments';
Expand All @@ -24,7 +24,7 @@ class CommentsImporter extends TableImporter {

setReferencedModel(model) {
this.model = model;
const publishedAt = databaseDate.parse(model.published_at);
const publishedAt = fromDatabaseDate(model.published_at);

this.commentIds = []; // Store [id, parent_id, timestamp] tuples for reply-to-reply

Expand All @@ -37,7 +37,7 @@ class CommentsImporter extends TableImporter {
endTime: new Date()
}).sort((a, b) => a.getTime() - b.getTime()); // Sort chronologically so replies always come after their targets

this.possibleMembers = this.members.filter(member => databaseDate.parse(member.created_at) < publishedAt);
this.possibleMembers = this.members.filter(member => fromDatabaseDate(member.created_at) < publishedAt);
}

generate() {
Expand Down Expand Up @@ -97,8 +97,8 @@ class CommentsImporter extends TableImporter {
parent_id: parentId,
in_reply_to_id: inReplyToId,
status: 'published',
created_at: databaseDate.dateToDatabaseString(timestamp),
updated_at: databaseDate.dateToDatabaseString(timestamp),
created_at: toDatabaseDate(timestamp),
updated_at: toDatabaseDate(timestamp),
html: `<p>${faker.lorem.sentence().replace(/[&<>"']/g, c => `&#${c.charCodeAt(0)};`)}</p>`
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const {TableImporter} = require('./table-importer');
const {faker} = require('@faker-js/faker');
const databaseDate = require('../utils/database-date');
const {randomDateBetween} = require('../utils/random');
const {fromDatabaseDate, toDatabaseDate} = require('../../../lib/db-date');

class EmailBatchesImporter extends TableImporter {
static table = 'email_batches';
Expand All @@ -21,8 +22,8 @@ class EmailBatchesImporter extends TableImporter {
}

generate() {
const emailSentDate = databaseDate.parse(this.model.created_at);
const latestUpdatedDate = databaseDate.parse(this.model.created_at);
const emailSentDate = fromDatabaseDate(this.model.created_at);
const latestUpdatedDate = new Date(emailSentDate);
latestUpdatedDate.setHours(latestUpdatedDate.getHours() + 1);

return {
Expand All @@ -31,7 +32,7 @@ class EmailBatchesImporter extends TableImporter {
mailgun_message_id: `${new Date().toISOString().split('.')[0].replace(/[^0-9]/g, '')}.${faker.string.hexadecimal({length: 16, prefix: '', casing: 'lower'})}@m.example.com`,
status: 'submitted', // TODO: introduce failures
created_at: this.model.created_at,
updated_at: databaseDate.dateToDatabaseString(databaseDate.randomBetween(emailSentDate, latestUpdatedDate))
updated_at: toDatabaseDate(randomDateBetween(emailSentDate, latestUpdatedDate))
};
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const {TableImporter} = require('./table-importer');
const {faker} = require('@faker-js/faker');
const generateEvents = require('../utils/event-generator');
const databaseDate = require('../utils/database-date');
const {randomDateBetween} = require('../utils/random');
const {fromDatabaseDate, toDatabaseDate} = require('../../../lib/db-date');
const debug = require('@tryghost/debug')('EmailRecipientsImporter');

const emailStatus = {
Expand Down Expand Up @@ -109,11 +110,7 @@ class EmailRecipientsImporter extends TableImporter {
this.membersSubscribeEventsCreatedAtsByNewsletterId.set(memberSubscribeEvent.newsletter_id, []);
}

if (!(memberSubscribeEvent.created_at instanceof Date)) {
// SQLite fix
memberSubscribeEvent.created_at = databaseDate.parse(memberSubscribeEvent.created_at);
}
this.membersSubscribeEventsCreatedAtsByNewsletterId.get(memberSubscribeEvent.newsletter_id).push(memberSubscribeEvent.created_at.getTime());
this.membersSubscribeEventsCreatedAtsByNewsletterId.get(memberSubscribeEvent.newsletter_id).push(fromDatabaseDate(memberSubscribeEvent.created_at).getTime());
}

await this.importForEach(this.emailBatches, quantity ? quantity / emails.length : 1000);
Expand All @@ -123,15 +120,12 @@ class EmailRecipientsImporter extends TableImporter {
this.batch = model;
this.model = this.emails.get(this.batch.email_id);
this.batchIndex = this.batch.index;

// Shallow clone members list so we can shuffle and modify it
const earliestOpenTime = databaseDate.parse(this.batch.updated_at);
const latestOpenTime = databaseDate.parse(this.batch.updated_at);
latestOpenTime.setDate(latestOpenTime.getDate() + 14);
this.batchUpdatedAt = fromDatabaseDate(this.batch.updated_at);
this.batchProcessedAt = toDatabaseDate(this.batchUpdatedAt);

// Get all members that were subscribed to this newsletter BEFORE the batch was sent
// We use binary search to speed up it up
const lastIndex = findFirstHigherIndex(this.membersSubscribeEventsCreatedAtsByNewsletterId.get(this.model.newsletter_id), earliestOpenTime);
const lastIndex = findFirstHigherIndex(this.membersSubscribeEventsCreatedAtsByNewsletterId.get(this.model.newsletter_id), this.batchUpdatedAt);

this.membersList = this.membersSubscribeEventsByNewsletterId.get(this.model.newsletter_id).slice(0, Math.max(0, lastIndex - 1))
.slice(this.batchIndex * 1000, (this.batchIndex + 1) * 1000)
Expand Down Expand Up @@ -164,7 +158,7 @@ class EmailRecipientsImporter extends TableImporter {
}

// The events are generated for a different time, so we need to move them to the batch time
timestamp = new Date(timestamp.getTime() - this.eventStartTimeUsed.getTime() + databaseDate.parse(this.batch.updated_at).getTime());
timestamp = new Date(timestamp.getTime() - this.eventStartTimeUsed.getTime() + this.batchUpdatedAt.getTime());

if (timestamp > new Date()) {
timestamp = new Date();
Expand All @@ -187,9 +181,7 @@ class EmailRecipientsImporter extends TableImporter {

let deliveredTime;
if (status === emailStatus.opened) {
const startDate = databaseDate.parse(this.batch.updated_at);
const endDate = timestamp;
deliveredTime = databaseDate.randomBetween(startDate, endDate);
deliveredTime = randomDateBetween(this.batchUpdatedAt, timestamp);
}

return {
Expand All @@ -198,10 +190,10 @@ class EmailRecipientsImporter extends TableImporter {
email_id: this.model.id,
batch_id: this.batch.id,
member_id: member.id,
processed_at: databaseDate.dateToDatabaseString(this.batch.updated_at),
delivered_at: status === emailStatus.opened ? databaseDate.dateToDatabaseString(deliveredTime) : status === emailStatus.delivered ? databaseDate.dateToDatabaseString(timestamp) : null,
opened_at: status === emailStatus.opened ? databaseDate.dateToDatabaseString(timestamp) : null,
failed_at: status === emailStatus.failed ? databaseDate.dateToDatabaseString(timestamp) : null,
processed_at: this.batchProcessedAt,
delivered_at: status === emailStatus.opened ? toDatabaseDate(deliveredTime) : status === emailStatus.delivered ? toDatabaseDate(timestamp) : null,
opened_at: status === emailStatus.opened ? toDatabaseDate(timestamp) : null,
failed_at: status === emailStatus.failed ? toDatabaseDate(timestamp) : null,
member_uuid: member.uuid,
member_email: member.email,
member_name: member.name
Expand Down
12 changes: 6 additions & 6 deletions ghost/core/core/server/data/seeders/importers/emails-importer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const {TableImporter} = require('./table-importer');
const {faker} = require('@faker-js/faker');
const generateEvents = require('../utils/event-generator');
const {luck} = require('../utils/random');
const databaseDate = require('../utils/database-date');
const {fromDatabaseDate, toDatabaseDate} = require('../../../lib/db-date');

class EmailsImporter extends TableImporter {
static table = 'emails';
Expand Down Expand Up @@ -42,7 +42,7 @@ class EmailsImporter extends TableImporter {
: this.newsletters[1];
}

const publishedAt = databaseDate.parse(this.model.published_at);
const publishedAt = fromDatabaseDate(this.model.published_at);
const timestamp = luck(60)
? publishedAt
: generateEvents({
Expand All @@ -55,7 +55,7 @@ class EmailsImporter extends TableImporter {

const recipientCount = this.membersSubscribeEvents
.filter(entry => entry.newsletter_id === newsletter.id)
.filter(entry => databaseDate.parse(entry.created_at) < timestamp).length;
.filter(entry => fromDatabaseDate(entry.created_at) < timestamp).length;
const deliveredCount = Math.ceil(recipientCount * faker.number.float({
max: 1,
min: 0.9,
Expand Down Expand Up @@ -87,10 +87,10 @@ class EmailsImporter extends TableImporter {
track_opens: true,
track_clicks: true,
feedback_enabled: true,
submitted_at: databaseDate.dateToDatabaseString(timestamp),
submitted_at: toDatabaseDate(timestamp),
newsletter_id: newsletter.id,
created_at: databaseDate.dateToDatabaseString(timestamp),
updated_at: databaseDate.dateToDatabaseString(timestamp)
created_at: toDatabaseDate(timestamp),
updated_at: toDatabaseDate(timestamp)
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const {TableImporter} = require('./table-importer');
const {faker} = require('@faker-js/faker');
const {slugify} = require('@tryghost/string');
const {blogStartDate} = require('../utils/blog-info');
const databaseDate = require('../utils/database-date');
const {toDatabaseDate} = require('../../../lib/db-date');

class LabelsImporter extends TableImporter {
static table = 'labels';
Expand Down Expand Up @@ -30,8 +30,8 @@ class LabelsImporter extends TableImporter {
id: this.fastFakeObjectId(),
name: name,
slug: `${slugify(name)}`,
created_at: databaseDate.dateToDatabaseString(blogStartDate),
updated_at: databaseDate.dateToDatabaseString(blogStartDate)
created_at: toDatabaseDate(blogStartDate),
updated_at: toDatabaseDate(blogStartDate)
};
}
}
Expand Down
Loading
Loading