2022-09-23 11:34:33 +03:00
|
|
|
const {MemberPageViewEvent, MemberCommentEvent, MemberLinkClickEvent} = require('@tryghost/member-events');
|
2022-03-01 12:28:45 +03:00
|
|
|
const moment = require('moment-timezone');
|
2022-05-02 21:07:30 +03:00
|
|
|
const {IncorrectUsageError} = require('@tryghost/errors');
|
2022-11-29 13:15:19 +03:00
|
|
|
const {EmailOpenedEvent} = require('@tryghost/email-events');
|
2022-02-23 21:13:42 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Listen for `MemberViewEvent` to update the `member.last_seen_at` timestamp
|
|
|
|
*/
|
|
|
|
class LastSeenAtUpdater {
|
|
|
|
/**
|
|
|
|
* Initializes the event subscriber
|
|
|
|
* @param {Object} deps dependencies
|
2022-03-01 12:28:45 +03:00
|
|
|
* @param {Object} deps.services The list of service dependencies
|
|
|
|
* @param {any} deps.services.settingsCache The settings service
|
2022-05-02 21:07:30 +03:00
|
|
|
* @param {() => object} deps.getMembersApi - A function which returns an instance of members-api
|
2022-02-23 21:13:42 +03:00
|
|
|
*/
|
2022-03-01 12:28:45 +03:00
|
|
|
constructor({
|
|
|
|
services: {
|
|
|
|
settingsCache
|
2022-05-02 21:07:30 +03:00
|
|
|
},
|
|
|
|
getMembersApi
|
2022-03-01 12:28:45 +03:00
|
|
|
}) {
|
2022-05-02 21:07:30 +03:00
|
|
|
if (!getMembersApi) {
|
|
|
|
throw new IncorrectUsageError({message: 'Missing option getMembersApi'});
|
|
|
|
}
|
|
|
|
|
|
|
|
this._getMembersApi = getMembersApi;
|
2022-03-01 12:28:45 +03:00
|
|
|
this._settingsCacheService = settingsCache;
|
2022-09-07 17:41:59 +03:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Subscribe to events of this domainEvents service
|
|
|
|
* @param {any} domainEvents The DomainEvents service
|
|
|
|
*/
|
|
|
|
subscribe(domainEvents) {
|
|
|
|
domainEvents.subscribe(MemberPageViewEvent, async (event) => {
|
2022-02-23 21:13:42 +03:00
|
|
|
await this.updateLastSeenAt(event.data.memberId, event.data.memberLastSeenAt, event.timestamp);
|
|
|
|
});
|
2022-07-25 18:35:46 +03:00
|
|
|
|
2022-09-23 11:34:33 +03:00
|
|
|
domainEvents.subscribe(MemberLinkClickEvent, async (event) => {
|
|
|
|
await this.updateLastSeenAt(event.data.memberId, event.data.memberLastSeenAt, event.timestamp);
|
|
|
|
});
|
|
|
|
|
2022-09-07 17:41:59 +03:00
|
|
|
domainEvents.subscribe(MemberCommentEvent, async (event) => {
|
2022-07-25 18:35:46 +03:00
|
|
|
await this.updateLastCommentedAt(event.data.memberId, event.timestamp);
|
|
|
|
});
|
2022-11-29 13:15:19 +03:00
|
|
|
|
|
|
|
domainEvents.subscribe(EmailOpenedEvent, async (event) => {
|
|
|
|
await this.updateLastSeenAtWithoutKnownLastSeen(event.memberId, event.timestamp);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates the member.last_seen_at field if it wasn't updated in the current day yet (in the publication timezone)
|
|
|
|
* Example: current time is 2022-02-28 18:00:00
|
|
|
|
* - memberLastSeenAt is 2022-02-27 23:00:00, timestamp is current time, then `last_seen_at` is set to the current time
|
|
|
|
* - memberLastSeenAt is 2022-02-28 01:00:00, timestamp is current time, then `last_seen_at` isn't changed
|
|
|
|
* @param {string} memberId The id of the member to be udpated
|
|
|
|
* @param {Date} timestamp The event timestamp
|
|
|
|
*/
|
|
|
|
async updateLastSeenAtWithoutKnownLastSeen(memberId, timestamp) {
|
|
|
|
// Fetch manually
|
|
|
|
const membersApi = this._getMembersApi();
|
|
|
|
const member = await membersApi.members.get({id: memberId}, {require: true});
|
|
|
|
const memberLastSeenAt = member.get('last_seen_at');
|
|
|
|
await this.updateLastSeenAt(memberId, memberLastSeenAt, timestamp);
|
2022-02-23 21:13:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-03-01 19:35:02 +03:00
|
|
|
* Updates the member.last_seen_at field if it wasn't updated in the current day yet (in the publication timezone)
|
|
|
|
* Example: current time is 2022-02-28 18:00:00
|
|
|
|
* - memberLastSeenAt is 2022-02-27 23:00:00, timestamp is current time, then `last_seen_at` is set to the current time
|
|
|
|
* - memberLastSeenAt is 2022-02-28 01:00:00, timestamp is current time, then `last_seen_at` isn't changed
|
2022-02-23 21:13:42 +03:00
|
|
|
* @param {string} memberId The id of the member to be udpated
|
2022-11-29 13:15:19 +03:00
|
|
|
* @param {string|null} memberLastSeenAt The previous last_seen_at property value for the current member
|
2022-02-23 21:13:42 +03:00
|
|
|
* @param {Date} timestamp The event timestamp
|
|
|
|
*/
|
|
|
|
async updateLastSeenAt(memberId, memberLastSeenAt, timestamp) {
|
2022-03-01 12:28:45 +03:00
|
|
|
const timezone = this._settingsCacheService.get('timezone');
|
2022-03-01 15:07:37 +03:00
|
|
|
if (memberLastSeenAt === null || moment(moment.utc(timestamp).tz(timezone).startOf('day')).isAfter(memberLastSeenAt)) {
|
2022-11-29 13:15:19 +03:00
|
|
|
const membersApi = this._getMembersApi();
|
2022-05-02 21:07:30 +03:00
|
|
|
await membersApi.members.update({
|
2022-02-28 16:36:58 +03:00
|
|
|
last_seen_at: moment.utc(timestamp).format('YYYY-MM-DD HH:mm:ss')
|
2022-02-23 21:13:42 +03:00
|
|
|
}, {
|
|
|
|
id: memberId
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2022-07-25 18:35:46 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates the member.last_seen_at field if it wasn't updated in the current day yet (in the publication timezone)
|
|
|
|
* Example: current time is 2022-02-28 18:00:00
|
|
|
|
* - memberLastSeenAt is 2022-02-27 23:00:00, timestamp is current time, then `last_seen_at` is set to the current time
|
|
|
|
* - memberLastSeenAt is 2022-02-28 01:00:00, timestamp is current time, then `last_seen_at` isn't changed
|
|
|
|
* @param {string} memberId The id of the member to be udpated
|
|
|
|
* @param {Date} timestamp The event timestamp
|
|
|
|
*/
|
|
|
|
async updateLastCommentedAt(memberId, timestamp) {
|
2022-11-29 13:15:19 +03:00
|
|
|
const membersApi = this._getMembersApi();
|
2022-07-25 18:35:46 +03:00
|
|
|
const member = await membersApi.members.get({id: memberId}, {require: true});
|
|
|
|
const timezone = this._settingsCacheService.get('timezone');
|
|
|
|
|
|
|
|
const memberLastSeenAt = member.get('last_seen_at');
|
|
|
|
const memberLastCommentedAt = member.get('last_commented_at');
|
|
|
|
|
|
|
|
if (memberLastSeenAt === null || moment(moment.utc(timestamp).tz(timezone).startOf('day')).isAfter(memberLastSeenAt) || memberLastCommentedAt === null || moment(moment.utc(timestamp).tz(timezone).startOf('day')).isAfter(memberLastCommentedAt)) {
|
|
|
|
await membersApi.members.update({
|
|
|
|
last_seen_at: moment.utc(timestamp).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
|
last_commented_at: moment.utc(timestamp).format('YYYY-MM-DD HH:mm:ss')
|
|
|
|
}, {
|
|
|
|
id: memberId
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2022-02-23 21:13:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = LastSeenAtUpdater;
|