diff --git a/ghost/core/core/server/services/segment/DomainEventsAnalytics.js b/ghost/core/core/server/services/segment/DomainEventsAnalytics.js index 779a009a61..bff29a2739 100644 --- a/ghost/core/core/server/services/segment/DomainEventsAnalytics.js +++ b/ghost/core/core/server/services/segment/DomainEventsAnalytics.js @@ -1,40 +1,82 @@ -const _ = require('lodash'); -const logging = require('@tryghost/logging'); -const DomainEvents = require('@tryghost/domain-events'); const {MilestoneCreatedEvent} = require('@tryghost/milestones'); +/** + * @typedef {import('@tryghost/logging')} logging + */ + +/** + * @typedef {import('analytics-node')} analytics + */ + +/** + * @typedef {import('../../../shared/sentry')} sentry + */ + +/** + * @typedef {import('@tryghost/domain-events')} DomainEvents + */ + +/** + * @typedef {object} IDomainEventsAnalytics + * @param {analytics} analytics + * @param {logging} logging + * @param {object} trackDefaults + * @param {string} prefix + * @param {sentry} sentry + * @param {DomainEvents} DomainEvents + * @prop {} subscribeToEvents + */ + module.exports = class DomainEventsAnalytics { + /** @type {analytics} */ #analytics; + /** @type {object} */ #trackDefaults; + /** @type {string} */ #prefix; + /** @type {sentry} */ #sentry; + /** @type {logging} */ + #logging; + /** @type {DomainEvents} */ + #DomainEvents; constructor(deps) { this.#analytics = deps.analytics; this.#trackDefaults = deps.trackDefaults; this.#prefix = deps.prefix; this.#sentry = deps.sentry; + this.#logging = deps.logging; + this.#DomainEvents = deps.DomainEvents; } - async #handleMilestoneCreatedEvent(type, event) { - if (type === MilestoneCreatedEvent - && event.data.milestone + /** + * + * @param {object} event + * @param {object} event.data + * @param {object} event.data.milestone + * @param {number} event.data.milestone.value + * @param {string} event.data.milestone.type + * @returns {Promise} + */ + async #handleMilestoneCreatedEvent(event) { + if (event.data.milestone && event.data.milestone.value === 100 ) { const eventName = event.data.milestone.type === 'arr' ? '$100 MRR reached' : '100 members reached'; try { - this.#analytics.track(_.extend(this.#trackDefaults, {}, {event: this.#prefix + eventName})); + this.#analytics.track(Object.assign(this.#trackDefaults, {}, {event: this.#prefix + eventName})); } catch (err) { - logging.error(err); + this.#logging.error(err); this.#sentry.captureException(err); } } } - subscribeToDomainEvents() { - DomainEvents.subscribe(MilestoneCreatedEvent, async (event) => { - await this.#handleMilestoneCreatedEvent(MilestoneCreatedEvent, event); + subscribeToEvents() { + this.#DomainEvents.subscribe(MilestoneCreatedEvent, async (event) => { + await this.#handleMilestoneCreatedEvent(event); }); } }; diff --git a/ghost/core/core/server/services/segment/index.js b/ghost/core/core/server/services/segment/index.js index e9c6a20c71..4ad79ca2da 100644 --- a/ghost/core/core/server/services/segment/index.js +++ b/ghost/core/core/server/services/segment/index.js @@ -1,6 +1,9 @@ const Analytics = require('analytics-node'); const config = require('../../../shared/config'); const sentry = require('../../../shared/sentry'); +const logging = require('@tryghost/logging'); +const DomainEvents = require('@tryghost/domain-events'); +const events = require('../../lib/common/events'); const ModelEventsAnalytics = require('./ModelEventsAnalytics'); const DomainEventsAnalytics = require('./DomainEventsAnalytics'); @@ -14,14 +17,18 @@ module.exports.init = function () { analytics, trackDefaults, prefix, - sentry + sentry, + DomainEvents, + logging }); const modelEventsAnalytics = new ModelEventsAnalytics({ analytics, trackDefaults, prefix, - sentry + sentry, + events, + logging }); // Listen to model events diff --git a/ghost/core/test/unit/server/services/segment/DomainEventsAnalytics.test.js b/ghost/core/test/unit/server/services/segment/DomainEventsAnalytics.test.js index 64e7e176e9..2214b0b4e8 100644 --- a/ghost/core/test/unit/server/services/segment/DomainEventsAnalytics.test.js +++ b/ghost/core/test/unit/server/services/segment/DomainEventsAnalytics.test.js @@ -8,7 +8,6 @@ const DomainEventsAnalytics = require('../../../../../core/server/services/segme // Stubbed dependencies const DomainEvents = require('@tryghost/domain-events'); const {MilestoneCreatedEvent} = require('@tryghost/milestones'); -const logging = require('@tryghost/logging'); describe('DomainEventsAnalytics', function () { describe('Constructor', function () { @@ -18,15 +17,17 @@ describe('DomainEventsAnalytics', function () { }); describe('Domain events analytics service', function () { - let domainAnalytics; + let domainEventsAnalytics; let analyticsStub; let sentryStub; let loggingStub; + let domainEventsStub; beforeEach(function () { analyticsStub = sinon.stub(); sentryStub = sinon.stub(); - loggingStub = sinon.stub(logging, 'error'); + loggingStub = sinon.stub(); + domainEventsStub = sinon.stub(); }); afterEach(function () { @@ -34,9 +35,7 @@ describe('DomainEventsAnalytics', function () { }); it('subscribes to events', async function () { - const domainEventsStub = sinon.stub(DomainEvents, 'subscribe').resolves(); - - domainAnalytics = new DomainEventsAnalytics({ + domainEventsAnalytics = new DomainEventsAnalytics({ analytics: analyticsStub, trackDefaults: { userId: '1234', @@ -45,16 +44,22 @@ describe('DomainEventsAnalytics', function () { prefix: 'Pro: ', sentry: { captureException: sentryStub + }, + DomainEvents: { + subscribe: domainEventsStub + }, + logging: { + error: loggingStub } }); - domainAnalytics.subscribeToDomainEvents(); + domainEventsAnalytics.subscribeToEvents(); assert(domainEventsStub.callCount === 1); assert(loggingStub.callCount === 0); }); it('handles milestone created event for 100 members', async function () { - domainAnalytics = new DomainEventsAnalytics({ + domainEventsAnalytics = new DomainEventsAnalytics({ analytics: { track: analyticsStub }, @@ -65,10 +70,14 @@ describe('DomainEventsAnalytics', function () { prefix: 'Pro: ', sentry: { captureException: sentryStub + }, + DomainEvents, + logging: { + error: loggingStub } }); - domainAnalytics.subscribeToDomainEvents(); + domainEventsAnalytics.subscribeToEvents(); DomainEvents.dispatch(MilestoneCreatedEvent.create({ milestone: { @@ -106,7 +115,7 @@ describe('DomainEventsAnalytics', function () { }); it('handles milestone created event for $100 ARR', async function () { - domainAnalytics = new DomainEventsAnalytics({ + domainEventsAnalytics = new DomainEventsAnalytics({ analytics: { track: analyticsStub }, @@ -117,10 +126,14 @@ describe('DomainEventsAnalytics', function () { prefix: 'Pro: ', sentry: { captureException: sentryStub + }, + DomainEvents, + logging: { + error: loggingStub } }); - domainAnalytics.subscribeToDomainEvents(); + domainEventsAnalytics.subscribeToEvents(); DomainEvents.dispatch(MilestoneCreatedEvent.create({ milestone: { @@ -162,7 +175,7 @@ describe('DomainEventsAnalytics', function () { it('can handle tracking errors', async function () { let error = new Error('Test error'); - domainAnalytics = new DomainEventsAnalytics({ + domainEventsAnalytics = new DomainEventsAnalytics({ analytics: { track: analyticsStub.throws(error) }, @@ -170,10 +183,14 @@ describe('DomainEventsAnalytics', function () { prefix: '', sentry: { captureException: sentryStub + }, + DomainEvents, + logging: { + error: loggingStub } }); - domainAnalytics.subscribeToDomainEvents(); + domainEventsAnalytics.subscribeToEvents(); try { DomainEvents.dispatch(MilestoneCreatedEvent.create({