mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 05:37:34 +03:00
First pass on adding domainevents to segment service
no issue - In order to listen to `DomainEvents` for `MilestoneCreatedEvents` we need to add a `DomainEvents` listener and handler to the Segment analytics service. - For better readability and to be more consistent with how code is currently written in Ghost, I refactored the service index file and split the two types of event listener into separate classes which is much cleaner and easier to test.
This commit is contained in:
parent
20eaff9e5c
commit
2c4d9e2776
@ -0,0 +1,40 @@
|
||||
const _ = require('lodash');
|
||||
const logging = require('@tryghost/logging');
|
||||
const DomainEvents = require('@tryghost/domain-events');
|
||||
const {MilestoneCreatedEvent} = require('@tryghost/milestones');
|
||||
|
||||
module.exports = class DomainEventsAnalytics {
|
||||
#analytics;
|
||||
#trackDefaults;
|
||||
#prefix;
|
||||
#sentry;
|
||||
|
||||
constructor(deps) {
|
||||
this.#analytics = deps.analytics;
|
||||
this.#trackDefaults = deps.trackDefaults;
|
||||
this.#prefix = deps.prefix;
|
||||
this.#sentry = deps.sentry;
|
||||
}
|
||||
|
||||
async #handleMilestoneCreatedEvent(type, event) {
|
||||
if (type === MilestoneCreatedEvent
|
||||
&& 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}));
|
||||
} catch (err) {
|
||||
logging.error(err);
|
||||
this.#sentry.captureException(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subscribeToDomainEvents() {
|
||||
DomainEvents.subscribe(MilestoneCreatedEvent, async (event) => {
|
||||
await this.#handleMilestoneCreatedEvent(MilestoneCreatedEvent, event);
|
||||
});
|
||||
}
|
||||
};
|
@ -0,0 +1,63 @@
|
||||
const _ = require('lodash');
|
||||
const logging = require('@tryghost/logging');
|
||||
// Listens to model events to layer on analytics - also uses the "fake" theme.uploaded event from the theme API
|
||||
const events = require('../../lib/common/events');
|
||||
|
||||
const TO_TRACK = [
|
||||
{
|
||||
event: 'post.published',
|
||||
name: 'Post Published'
|
||||
},
|
||||
{
|
||||
event: 'page.published',
|
||||
name: 'Page Published'
|
||||
},
|
||||
{
|
||||
event: 'theme.uploaded',
|
||||
name: 'Theme Uploaded',
|
||||
// {keyOnSuppliedEventData: keyOnTrackedEventData}
|
||||
// - used to extract specific properties from event data and give them meaningful names
|
||||
data: {name: 'name'}
|
||||
},
|
||||
{
|
||||
event: 'integration.added',
|
||||
name: 'Custom Integration Added'
|
||||
},
|
||||
{
|
||||
event: 'settings.edited',
|
||||
name: 'Stripe enabled',
|
||||
data: {key: 'key', value: 'value'}
|
||||
}
|
||||
];
|
||||
|
||||
module.exports = class ModelEventsAnalytics {
|
||||
#analytics;
|
||||
#trackDefaults;
|
||||
#prefix;
|
||||
#sentry;
|
||||
#toTrack;
|
||||
|
||||
constructor(deps) {
|
||||
this.#analytics = deps.analytics;
|
||||
this.#trackDefaults = deps.trackDefaults;
|
||||
this.#prefix = deps.prefix;
|
||||
this.#sentry = deps.sentry;
|
||||
this.#toTrack = TO_TRACK;
|
||||
}
|
||||
|
||||
subscribeToModelEvents() {
|
||||
this.#toTrack.forEach(({event, name, data = {}}) => {
|
||||
events.on(event, function (eventData = {}) {
|
||||
// extract desired properties from eventData and rename keys if necessary
|
||||
const mappedData = _.mapValues(data || {}, v => eventData[v]);
|
||||
|
||||
try {
|
||||
this.#analytics.track(_.extend(this.#trackDefaults, mappedData, {event: this.#prefix + name}));
|
||||
} catch (err) {
|
||||
logging.error(err);
|
||||
this.#sentry.captureException(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
@ -1,51 +1,32 @@
|
||||
const _ = require('lodash');
|
||||
const Analytics = require('analytics-node');
|
||||
const logging = require('@tryghost/logging');
|
||||
|
||||
const config = require('../../../shared/config');
|
||||
const sentry = require('../../../shared/sentry');
|
||||
|
||||
// Listens to model events to layer on analytics - also uses the "fake" theme.uploaded event from the theme API
|
||||
const events = require('../../lib/common/events');
|
||||
const ModelEventsAnalytics = require('./ModelEventsAnalytics');
|
||||
const DomainEventsAnalytics = require('./DomainEventsAnalytics');
|
||||
|
||||
module.exports.init = function () {
|
||||
const analytics = new Analytics(config.get('segment:key'));
|
||||
const trackDefaults = config.get('segment:trackDefaults') || {};
|
||||
const prefix = config.get('segment:prefix') || '';
|
||||
|
||||
const toTrack = [
|
||||
{
|
||||
event: 'post.published',
|
||||
name: 'Post Published'
|
||||
},
|
||||
{
|
||||
event: 'page.published',
|
||||
name: 'Page Published'
|
||||
},
|
||||
{
|
||||
event: 'theme.uploaded',
|
||||
name: 'Theme Uploaded',
|
||||
// {keyOnSuppliedEventData: keyOnTrackedEventData}
|
||||
// - used to extract specific properties from event data and give them meaningful names
|
||||
data: {name: 'name'}
|
||||
},
|
||||
{
|
||||
event: 'integration.added',
|
||||
name: 'Custom Integration Added'
|
||||
}
|
||||
];
|
||||
|
||||
_.each(toTrack, function (track) {
|
||||
events.on(track.event, function (eventData = {}) {
|
||||
// extract desired properties from eventData and rename keys if necessary
|
||||
const data = _.mapValues(track.data || {}, v => eventData[v]);
|
||||
|
||||
try {
|
||||
analytics.track(_.extend(trackDefaults, data, {event: prefix + track.name}));
|
||||
} catch (err) {
|
||||
logging.error(err);
|
||||
sentry.captureException(err);
|
||||
}
|
||||
});
|
||||
const subscribeToDomainEvents = new DomainEventsAnalytics({
|
||||
analytics,
|
||||
trackDefaults,
|
||||
prefix,
|
||||
sentry
|
||||
});
|
||||
|
||||
const modelEventsAnalytics = new ModelEventsAnalytics({
|
||||
analytics,
|
||||
trackDefaults,
|
||||
prefix,
|
||||
sentry
|
||||
});
|
||||
|
||||
// Listen to model events
|
||||
modelEventsAnalytics.subscribeToModelEvents();
|
||||
|
||||
// Listen to domain events
|
||||
subscribeToDomainEvents.subscribeToDomainEvents();
|
||||
};
|
||||
|
11
ghost/core/test/unit/server/services/segment/index.test.js
Normal file
11
ghost/core/test/unit/server/services/segment/index.test.js
Normal file
@ -0,0 +1,11 @@
|
||||
const assert = require('assert');
|
||||
|
||||
describe('Segment Analytics Service', function () {
|
||||
let segmentService;
|
||||
|
||||
it('Provides expected public API', async function () {
|
||||
segmentService = require('../../../../../core/server/services/segment');
|
||||
|
||||
assert.ok(segmentService.initAndRun);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user