Added member last seen update on link click (#15459)

fixes https://github.com/TryGhost/Team/issues/1952

Adds a new MemberLinkClickEvent event that is fired when a member clicks a link. This code has been added to the `linkClickRepository` because that is the only place that has access to the member model (and the event requires the id and current last seen at value). The LastSeenAtUpdater listens for this event and updates the timestamp if required.
This commit is contained in:
Simon Backx 2022-09-23 10:34:33 +02:00 committed by GitHub
parent 225a046bb8
commit 1290477d71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 8 deletions

View File

@ -2,24 +2,34 @@ const {LinkClick} = require('@tryghost/link-tracking');
const ObjectID = require('bson-objectid').default;
module.exports = class LinkClickRepository {
/** @type {Object} */
#MemberLinkClickEventModel;
/** @type {Object} */
#MemberLinkClickEvent;
/** @type {object} */
#Member;
/** @type {object} */
#DomainEvents;
/**
* @param {object} deps
* @param {object} deps.MemberLinkClickEvent Bookshelf Model
* @param {object} deps.MemberLinkClickEventModel Bookshelf Model
* @param {object} deps.Member Bookshelf Model
* @param {object} deps.MemberLinkClickEvent Event
* @param {object} deps.DomainEvents
*/
constructor(deps) {
this.#MemberLinkClickEvent = deps.MemberLinkClickEvent;
this.#MemberLinkClickEventModel = deps.MemberLinkClickEventModel;
this.#Member = deps.Member;
this.#MemberLinkClickEvent = deps.MemberLinkClickEvent;
this.#DomainEvents = deps.DomainEvents;
}
async getAll(options) {
const collection = await this.#MemberLinkClickEvent.findAll(options);
const collection = await this.#MemberLinkClickEventModel.findAll(options);
const result = [];
@ -45,12 +55,15 @@ module.exports = class LinkClickRepository {
return;
}
const model = await this.#MemberLinkClickEvent.add({
const model = await this.#MemberLinkClickEventModel.add({
// Only store the parthname (no support for variable query strings)
link_id: linkClick.link_id.toHexString(),
member_id: member.id
}, {});
linkClick.event_id = ObjectID.createFromHexString(model.id);
// Dispatch event
this.#DomainEvents.dispatch(this.#MemberLinkClickEvent.create({memberId: member.id, memberLastSeenAt: member.get('last_seen_at'), linkId: linkClick.link_id.toHexString()}, new Date()));
}
};

View File

@ -16,6 +16,9 @@ class LinkTrackingServiceWrapper {
// Wire up all the dependencies
const models = require('../../models');
const {MemberLinkClickEvent} = require('@tryghost/member-events');
const DomainEvents = require('@tryghost/domain-events');
const {LinkTrackingService} = require('@tryghost/link-tracking');
const postLinkRepository = new PostLinkRepository({
@ -24,8 +27,10 @@ class LinkTrackingServiceWrapper {
});
const linkClickRepository = new LinkClickRepository({
MemberLinkClickEvent: models.MemberLinkClickEvent,
Member: models.Member
MemberLinkClickEventModel: models.MemberLinkClickEvent,
Member: models.Member,
MemberLinkClickEvent: MemberLinkClickEvent,
DomainEvents
});
// Expose the service

View File

@ -9,5 +9,6 @@ module.exports = {
MemberPageViewEvent: require('./lib/MemberPageViewEvent'),
SubscriptionCreatedEvent: require('./lib/SubscriptionCreatedEvent'),
MemberCommentEvent: require('./lib/MemberCommentEvent'),
SubscriptionCancelledEvent: require('./lib/SubscriptionCancelledEvent')
SubscriptionCancelledEvent: require('./lib/SubscriptionCancelledEvent'),
MemberLinkClickEvent: require('./lib/MemberLinkClickEvent')
};

View File

@ -0,0 +1,28 @@
/**
* @typedef {object} MemberLinkClickEventData
* @prop {string} memberId
* @prop {string} memberLastSeenAt
* @prop {string} linkId
*/
/**
* Server-side event firing on page views (page, post, tags...)
*/
module.exports = class MemberLinkClickEvent {
/**
* @param {MemberLinkClickEventData} data
* @param {Date} timestamp
*/
constructor(data, timestamp) {
this.data = data;
this.timestamp = timestamp;
}
/**
* @param {MemberLinkClickEventData} data
* @param {Date} [timestamp]
*/
static create(data, timestamp) {
return new MemberLinkClickEvent(data, timestamp || new Date);
}
};

View File

@ -1,4 +1,4 @@
const {MemberPageViewEvent, MemberCommentEvent} = require('@tryghost/member-events');
const {MemberPageViewEvent, MemberCommentEvent, MemberLinkClickEvent} = require('@tryghost/member-events');
const moment = require('moment-timezone');
const {IncorrectUsageError} = require('@tryghost/errors');
@ -35,6 +35,10 @@ class LastSeenAtUpdater {
await this.updateLastSeenAt(event.data.memberId, event.data.memberLastSeenAt, event.timestamp);
});
domainEvents.subscribe(MemberLinkClickEvent, async (event) => {
await this.updateLastSeenAt(event.data.memberId, event.data.memberLastSeenAt, event.timestamp);
});
domainEvents.subscribe(MemberCommentEvent, async (event) => {
await this.updateLastCommentedAt(event.data.memberId, event.timestamp);
});