mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
Added flag to disable lastSeenAt updater for member link clicks (#21802)
ref https://linear.app/ghost/issue/ENG-1814 This provides a way for us, if needed, to disable the least important piece of the member click event cascade.
This commit is contained in:
parent
4c13f188ce
commit
3da2a9f64e
4 changed files with 100 additions and 11 deletions
|
@ -3,6 +3,7 @@ const DomainEvents = require('@tryghost/domain-events');
|
|||
const events = require('../../lib/common/events');
|
||||
const settingsCache = require('../../../shared/settings-cache');
|
||||
const members = require('../members');
|
||||
const config = require('../../../shared/config');
|
||||
|
||||
class MembersEventsServiceWrapper {
|
||||
init() {
|
||||
|
@ -43,7 +44,8 @@ class MembersEventsServiceWrapper {
|
|||
},
|
||||
db,
|
||||
events,
|
||||
lastSeenAtCache: this.lastSeenAtCache
|
||||
lastSeenAtCache: this.lastSeenAtCache,
|
||||
config
|
||||
});
|
||||
|
||||
// Subscribe to domain events
|
||||
|
|
|
@ -193,7 +193,8 @@
|
|||
"enableStripePromoCodes": false,
|
||||
"emailAnalytics": true,
|
||||
"backgroundJobs": {
|
||||
"emailAnalytics": true
|
||||
"emailAnalytics": true,
|
||||
"clickTrackingLastSeenAtUpdater": true
|
||||
},
|
||||
"portal": {
|
||||
"url": "https://cdn.jsdelivr.net/ghost/portal@~{version}/umd/portal.min.js",
|
||||
|
|
|
@ -18,6 +18,7 @@ class LastSeenAtUpdater {
|
|||
* @param {any} deps.db Database connection
|
||||
* @param {any} deps.events The event emitter
|
||||
* @param {any} deps.lastSeenAtCache An instance of the last seen at cache
|
||||
* @param {any} deps.config Ghost config for click tracking
|
||||
*/
|
||||
constructor({
|
||||
services: {
|
||||
|
@ -26,7 +27,8 @@ class LastSeenAtUpdater {
|
|||
getMembersApi,
|
||||
db,
|
||||
events,
|
||||
lastSeenAtCache
|
||||
lastSeenAtCache,
|
||||
config
|
||||
}) {
|
||||
if (!getMembersApi) {
|
||||
throw new IncorrectUsageError({message: 'Missing option getMembersApi'});
|
||||
|
@ -37,6 +39,7 @@ class LastSeenAtUpdater {
|
|||
this._db = db;
|
||||
this._events = events;
|
||||
this._lastSeenAtCache = lastSeenAtCache || new LastSeenAtCache({services: {settingsCache}});
|
||||
this._config = config;
|
||||
}
|
||||
/**
|
||||
* Subscribe to events of this domainEvents service
|
||||
|
@ -52,14 +55,18 @@ class LastSeenAtUpdater {
|
|||
}
|
||||
});
|
||||
|
||||
domainEvents.subscribe(MemberLinkClickEvent, async (event) => {
|
||||
try {
|
||||
await this.cachedUpdateLastSeenAt(event.data.memberId, event.data.memberLastSeenAt, event.timestamp);
|
||||
} catch (err) {
|
||||
logging.error(`Error in LastSeenAtUpdater.MemberLinkClickEvent listener for member ${event.data.memberId}`);
|
||||
logging.error(err);
|
||||
}
|
||||
});
|
||||
// Only disable if explicitly set to false in config
|
||||
const shouldUpdateForClickTracking = !this._config || this._config.get('backgroundJobs:clickTrackingLastSeenAtUpdater') !== false;
|
||||
if (shouldUpdateForClickTracking) {
|
||||
domainEvents.subscribe(MemberLinkClickEvent, async (event) => {
|
||||
try {
|
||||
await this.cachedUpdateLastSeenAt(event.data.memberId, event.data.memberLastSeenAt, event.timestamp);
|
||||
} catch (err) {
|
||||
logging.error(`Error in LastSeenAtUpdater.MemberLinkClickEvent listener for member ${event.data.memberId}`);
|
||||
logging.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
domainEvents.subscribe(MemberCommentEvent, async (event) => {
|
||||
try {
|
||||
|
|
|
@ -285,6 +285,85 @@ describe('LastSeenAtUpdater', function () {
|
|||
await DomainEvents.allSettled();
|
||||
assert(spy.notCalled, 'The LastSeenAtUpdater should never fire on MemberSubscribeEvent events.');
|
||||
});
|
||||
|
||||
describe('Disable via config', function () {
|
||||
it('MemberLinkClickEvent should not be fired when disabled', async function () {
|
||||
const now = moment.utc('2022-02-28T18:00:00Z');
|
||||
const previousLastSeen = moment.utc('2022-02-27T22:59:00Z').toDate();
|
||||
const stub = sinon.stub().resolves();
|
||||
const settingsCache = sinon.stub();
|
||||
settingsCache.returns('Europe/Brussels'); // Default return for other settings
|
||||
const configStub = sinon.stub();
|
||||
configStub.withArgs('backgroundJobs:clickTrackingLastSeenAtUpdater').returns(false);
|
||||
|
||||
const updater = new LastSeenAtUpdater({
|
||||
services: {
|
||||
settingsCache: {
|
||||
get: settingsCache
|
||||
}
|
||||
},
|
||||
config: {
|
||||
get: configStub
|
||||
},
|
||||
getMembersApi() {
|
||||
return {
|
||||
members: {
|
||||
update: stub,
|
||||
get: () => {
|
||||
return {
|
||||
id: '1',
|
||||
get: () => {
|
||||
return previousLastSeen;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
events
|
||||
});
|
||||
updater.subscribe(DomainEvents);
|
||||
sinon.stub(updater, 'updateLastSeenAt');
|
||||
DomainEvents.dispatch(MemberLinkClickEvent.create({memberId: '1', memberLastSeenAt: previousLastSeen, url: '/'}, now.toDate()));
|
||||
assert(updater.updateLastSeenAt.notCalled, 'The LastSeenAtUpdater should not attempt a member update when disabled');
|
||||
});
|
||||
|
||||
it('MemberLinkClickEvent should be fired when enabled/empty', async function () {
|
||||
const now = moment.utc('2022-02-28T18:00:00Z');
|
||||
const previousLastSeen = moment.utc('2022-02-27T22:59:00Z').toDate();
|
||||
const stub = sinon.stub().resolves();
|
||||
const settingsCache = sinon.stub();
|
||||
settingsCache.returns('Europe/Brussels'); // Default return for other settings
|
||||
|
||||
const updater = new LastSeenAtUpdater({
|
||||
services: {
|
||||
settingsCache: {
|
||||
get: settingsCache
|
||||
}
|
||||
},
|
||||
getMembersApi() {
|
||||
return {
|
||||
members: {
|
||||
update: stub,
|
||||
get: () => {
|
||||
return {
|
||||
id: '1',
|
||||
get: () => {
|
||||
return previousLastSeen;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
events
|
||||
});
|
||||
updater.subscribe(DomainEvents);
|
||||
sinon.stub(updater, 'updateLastSeenAt');
|
||||
DomainEvents.dispatch(MemberLinkClickEvent.create({memberId: '1', memberLastSeenAt: previousLastSeen, url: '/'}, now.toDate()));
|
||||
assert(updater.updateLastSeenAt.calledOnce, 'The LastSeenAtUpdater should attempt a member update when not disabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateLastSeenAt', function () {
|
||||
|
|
Loading…
Add table
Reference in a new issue