From a1085807f90ef05029ad7cc8e96e3bc29db631f8 Mon Sep 17 00:00:00 2001 From: Joan Reyero Date: Mon, 13 Feb 2023 18:54:32 +0100 Subject: [PATCH 1/7] Added tracking --- .../eagleEyeContent/eagleEyeContentTrack.ts | 21 +++++++++++ backend/src/api/eagleEyeContent/index.ts | 6 ++++ backend/src/services/eagleEyeActionService.ts | 23 ++++++++++++ .../src/services/eagleEyeSettingsService.ts | 36 +++++++++++++++++++ .../components/list/eagle-eye-result-card.vue | 8 ++++- .../premium/eagle-eye/eagle-eye-service.js | 12 +++++++ 6 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts diff --git a/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts b/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts new file mode 100644 index 0000000000..b267515e18 --- /dev/null +++ b/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts @@ -0,0 +1,21 @@ +import Permissions from '../../security/permissions' +import PermissionChecker from '../../services/user/permissionChecker' +import track from '../../segment/track' + +export default async (req, res) => { + new PermissionChecker(req).validateHas(Permissions.values.eagleEyeContentRead) + track( + 'Eagle Eye post click', + { + url: req.params.postUrl, + platform: req.params.platform, + }, + { ...req }, + ) + + const out = { + Success: true, + } + + await req.responseHandler.success(req, res, out) +} diff --git a/backend/src/api/eagleEyeContent/index.ts b/backend/src/api/eagleEyeContent/index.ts index 7fd10c716c..3a1321ab59 100644 --- a/backend/src/api/eagleEyeContent/index.ts +++ b/backend/src/api/eagleEyeContent/index.ts @@ -15,6 +15,12 @@ export default (app) => { safeWrap(require('./eagleEyeContentUpsert').default), ) + app.post( + `/tenant/:tenantId/eagleEyeContent/track`, + featureFlagMiddleware(FeatureFlag.EAGLE_EYE, 'entities.eagleEye.errors.planLimitExceeded'), + safeWrap(require('./eagleEyeContentTrack').default), + ) + app.get( `/tenant/:tenantId/eagleEyeContent/search`, featureFlagMiddleware(FeatureFlag.EAGLE_EYE, 'entities.eagleEye.errors.planLimitExceeded'), diff --git a/backend/src/services/eagleEyeActionService.ts b/backend/src/services/eagleEyeActionService.ts index 05ad1e0c27..c6c41c06f6 100644 --- a/backend/src/services/eagleEyeActionService.ts +++ b/backend/src/services/eagleEyeActionService.ts @@ -5,6 +5,7 @@ import Error404 from '../errors/Error404' import { EagleEyeAction, EagleEyeActionType } from '../types/eagleEyeTypes' import { IServiceOptions } from './IServiceOptions' import { LoggingBase } from './loggingBase' +import track from '../segment/telemetryTrack' export default class EagleEyeActionService extends LoggingBase { options: IServiceOptions @@ -72,6 +73,17 @@ export default class EagleEyeActionService extends LoggingBase { await SequelizeRepository.commitTransaction(transaction) + track( + `Eagle Eye post ${record.type === EagleEyeActionType.BOOKMARK ? 'bookmark' : 'feedback'}`, + { + type: record.type, + url: content.url, + platform: content.platform, + action: 'create', + }, + { ...this.options }, + ) + return record } catch (error) { await SequelizeRepository.rollbackTransaction(transaction) @@ -96,5 +108,16 @@ export default class EagleEyeActionService extends LoggingBase { if (content.actions.length === 0) { await EagleEyeContentRepository.destroy(contentId, this.options) } + + track( + `Eagle Eye post ${action.type === EagleEyeActionType.BOOKMARK ? 'bookmark' : 'feedback'}`, + { + type: action.type, + url: content.url, + platform: content.platform, + action: 'destroy', + }, + { ...this.options }, + ) } } diff --git a/backend/src/services/eagleEyeSettingsService.ts b/backend/src/services/eagleEyeSettingsService.ts index 7753f2f13d..c3a450ec42 100644 --- a/backend/src/services/eagleEyeSettingsService.ts +++ b/backend/src/services/eagleEyeSettingsService.ts @@ -2,6 +2,7 @@ import lodash from 'lodash' import SequelizeRepository from '../database/repositories/sequelizeRepository' import UserRepository from '../database/repositories/userRepository' import Error400 from '../errors/Error400' +import track from '../segment/telemetryTrack' import { EagleEyeSettings, EagleEyeFeedSettings, @@ -146,6 +147,41 @@ export default class EagleEyeSettingsService extends LoggingBase { await SequelizeRepository.commitTransaction(transaction) + // Track the events in Segment + const settingsOut: EagleEyeSettings = userOut.eagleEyeSettings + + if (data.emailDigestActive) { + track( + 'EagleEye Email Settings Updated', + { + email: settingsOut.emailDigest.email, + frequency: settingsOut.emailDigest.frequency, + time: settingsOut.emailDigest.time, + matchFeedSettings: settingsOut.emailDigest.matchFeedSettings, + platforms: settingsOut.emailDigest.feed.platforms, + publishedDate: settingsOut.emailDigest.feed.publishedDate, + keywords: settingsOut.emailDigest.feed.keywords, + exactKeywords: settingsOut.emailDigest.feed.exactKeywords, + excludeKeywords: settingsOut.emailDigest.feed.excludedKeywords, + }, + { ...this.options }, + ) + } else { + track( + 'EagleEye Settings Updated', + { + onboarded: settingsOut.onboarded, + emailDigestActive: settingsOut.emailDigestActive, + platforms: settingsOut.feed.platforms, + publishedDate: settingsOut.feed.publishedDate, + keywords: settingsOut.feed.keywords, + exactKeywords: settingsOut.feed.exactKeywords, + excludeKeywords: settingsOut.feed.excludedKeywords, + }, + { ...this.options }, + ) + } + return userOut.eagleEyeSettings } catch (error) { await SequelizeRepository.rollbackTransaction(transaction) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue index 8fef282ce8..caafbc80f1 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue @@ -164,6 +164,7 @@ import { formatDateToTimeAgo } from '@/utils/date' import { computed, defineProps } from 'vue' import platformOptions from '@/premium/eagle-eye/constants/eagle-eye-platforms.json' +import { EagleEyeService } from '../../eagle-eye-service' import { withHttp } from '@/utils/string' import { mapActions, @@ -217,12 +218,17 @@ const bookmarkTooltip = computed(() => { }) // Open post in origin url -const onCardClick = (e) => { +const onCardClick = async (e) => { if (!props.result.url || e.target.localName === 'a') { return } window.open(withHttp(props.result.url), '_blank') + + await EagleEyeService.trackClick({ + url: props.result.url, + platform: props.result.platform + }) } // If opposite thumbs up is set, remove before creating the new action diff --git a/frontend/src/premium/eagle-eye/eagle-eye-service.js b/frontend/src/premium/eagle-eye/eagle-eye-service.js index 7582cbfd3c..bbc15f1f7a 100644 --- a/frontend/src/premium/eagle-eye/eagle-eye-service.js +++ b/frontend/src/premium/eagle-eye/eagle-eye-service.js @@ -41,6 +41,18 @@ export class EagleEyeService { return response.data } + static async trackClick({ url, platform }) { + const tenantId = AuthCurrentTenant.get() + const response = await authAxios.post( + `/tenant/${tenantId}/eagleEyeContent/track`, + { + url, + platform + } + ) + return response.data + } + static async addAction({ postId, actionData }) { const tenantId = AuthCurrentTenant.get() From befb3bf15728196b3abf38c8e6bcb34afe35756f Mon Sep 17 00:00:00 2001 From: Joan Reyero Date: Mon, 13 Feb 2023 18:57:39 +0100 Subject: [PATCH 2/7] Comments --- backend/src/services/eagleEyeActionService.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/services/eagleEyeActionService.ts b/backend/src/services/eagleEyeActionService.ts index c6c41c06f6..1c732c3fe9 100644 --- a/backend/src/services/eagleEyeActionService.ts +++ b/backend/src/services/eagleEyeActionService.ts @@ -73,6 +73,7 @@ export default class EagleEyeActionService extends LoggingBase { await SequelizeRepository.commitTransaction(transaction) + // Tracking here so we have access to url and platform track( `Eagle Eye post ${record.type === EagleEyeActionType.BOOKMARK ? 'bookmark' : 'feedback'}`, { @@ -109,6 +110,7 @@ export default class EagleEyeActionService extends LoggingBase { await EagleEyeContentRepository.destroy(contentId, this.options) } + // Tracking here so we have access to url and platform track( `Eagle Eye post ${action.type === EagleEyeActionType.BOOKMARK ? 'bookmark' : 'feedback'}`, { From 4e9658bfdfc8c1b6a7d0cf30807676f9c1070a8e Mon Sep 17 00:00:00 2001 From: Joan Reyero Date: Mon, 13 Feb 2023 19:14:11 +0100 Subject: [PATCH 3/7] Transactions --- backend/src/services/eagleEyeActionService.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/backend/src/services/eagleEyeActionService.ts b/backend/src/services/eagleEyeActionService.ts index 1c732c3fe9..db0ea34883 100644 --- a/backend/src/services/eagleEyeActionService.ts +++ b/backend/src/services/eagleEyeActionService.ts @@ -51,7 +51,10 @@ export default class EagleEyeActionService extends LoggingBase { await EagleEyeActionRepository.removeActionFromContent( EagleEyeActionType.THUMBS_UP, contentId, - this.options, + { + ...this.options, + transaction, + }, ) } else if ( data.type === EagleEyeActionType.THUMBS_UP && @@ -60,16 +63,18 @@ export default class EagleEyeActionService extends LoggingBase { await EagleEyeActionRepository.removeActionFromContent( EagleEyeActionType.THUMBS_DOWN, contentId, - this.options, + { + ...this.options, + transaction, + }, ) } // add new action - const record = await EagleEyeActionRepository.createActionForContent( - data, - contentId, - this.options, - ) + const record = await EagleEyeActionRepository.createActionForContent(data, contentId, { + ...this.options, + transaction, + }) await SequelizeRepository.commitTransaction(transaction) From 3f07939aa3917c3bdff3b133281cdac6603d9eaa Mon Sep 17 00:00:00 2001 From: Joan Reyero Date: Mon, 13 Feb 2023 19:28:14 +0100 Subject: [PATCH 4/7] Fixed tracking? --- .../eagleEyeContent/eagleEyeContentTrack.ts | 4 ++-- backend/src/services/eagleEyeActionService.ts | 24 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts b/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts index b267515e18..4e20baf780 100644 --- a/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts +++ b/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts @@ -7,8 +7,8 @@ export default async (req, res) => { track( 'Eagle Eye post click', { - url: req.params.postUrl, - platform: req.params.platform, + url: req.body.url, + platform: req.body.platform, }, { ...req }, ) diff --git a/backend/src/services/eagleEyeActionService.ts b/backend/src/services/eagleEyeActionService.ts index db0ea34883..cbb8b2edda 100644 --- a/backend/src/services/eagleEyeActionService.ts +++ b/backend/src/services/eagleEyeActionService.ts @@ -28,6 +28,18 @@ export default class EagleEyeActionService extends LoggingBase { throw new Error404(this.options.language, 'errors.eagleEye.contentNotFound') } + // Tracking here so we have access to url and platform + track( + `Eagle Eye post ${data.type === EagleEyeActionType.BOOKMARK ? 'bookmark' : 'feedback'}`, + { + type: data.type, + url: content.url, + platform: content.platform, + action: 'create', + }, + { ...this.options }, + ) + const existingUserActions: EagleEyeAction[] = content.actions.filter( (a) => a.actionById === this.options.currentUser.id, ) @@ -78,18 +90,6 @@ export default class EagleEyeActionService extends LoggingBase { await SequelizeRepository.commitTransaction(transaction) - // Tracking here so we have access to url and platform - track( - `Eagle Eye post ${record.type === EagleEyeActionType.BOOKMARK ? 'bookmark' : 'feedback'}`, - { - type: record.type, - url: content.url, - platform: content.platform, - action: 'create', - }, - { ...this.options }, - ) - return record } catch (error) { await SequelizeRepository.rollbackTransaction(transaction) From 624380ca89f391f5d72339df4117ce9006720616 Mon Sep 17 00:00:00 2001 From: Joan Reyero Date: Mon, 13 Feb 2023 20:12:14 +0100 Subject: [PATCH 5/7] Fixed tracks --- backend/src/services/eagleEyeActionService.ts | 2 +- backend/src/services/eagleEyeSettingsService.ts | 2 +- .../src/services/premium/enrichment/memberEnrichmentService.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/services/eagleEyeActionService.ts b/backend/src/services/eagleEyeActionService.ts index cbb8b2edda..179afeb670 100644 --- a/backend/src/services/eagleEyeActionService.ts +++ b/backend/src/services/eagleEyeActionService.ts @@ -5,7 +5,7 @@ import Error404 from '../errors/Error404' import { EagleEyeAction, EagleEyeActionType } from '../types/eagleEyeTypes' import { IServiceOptions } from './IServiceOptions' import { LoggingBase } from './loggingBase' -import track from '../segment/telemetryTrack' +import track from '../segment/track' export default class EagleEyeActionService extends LoggingBase { options: IServiceOptions diff --git a/backend/src/services/eagleEyeSettingsService.ts b/backend/src/services/eagleEyeSettingsService.ts index c3a450ec42..b4b8b66220 100644 --- a/backend/src/services/eagleEyeSettingsService.ts +++ b/backend/src/services/eagleEyeSettingsService.ts @@ -2,7 +2,7 @@ import lodash from 'lodash' import SequelizeRepository from '../database/repositories/sequelizeRepository' import UserRepository from '../database/repositories/userRepository' import Error400 from '../errors/Error400' -import track from '../segment/telemetryTrack' +import track from '../segment/track' import { EagleEyeSettings, EagleEyeFeedSettings, diff --git a/backend/src/services/premium/enrichment/memberEnrichmentService.ts b/backend/src/services/premium/enrichment/memberEnrichmentService.ts index 93b3075795..3c529eea67 100644 --- a/backend/src/services/premium/enrichment/memberEnrichmentService.ts +++ b/backend/src/services/premium/enrichment/memberEnrichmentService.ts @@ -29,7 +29,7 @@ import RedisPubSubEmitter from '../../../utils/redis/pubSubEmitter' import { createRedisClient } from '../../../utils/redis' import { ApiWebsocketMessage } from '../../../types/mq/apiWebsocketMessage' import MemberEnrichmentCacheRepository from '../../../database/repositories/memberEnrichmentCacheRepository' -import track from '../../../segment/telemetryTrack' +import track from '../../../segment/track' export default class MemberEnrichmentService extends LoggingBase { options: IServiceOptions From 7e32cf3b187bc89ef0f0b0b198caba2778f8587c Mon Sep 17 00:00:00 2001 From: Joan Reyero Date: Mon, 13 Feb 2023 20:24:45 +0100 Subject: [PATCH 6/7] Format --- frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue b/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue index 2a71f20696..81cce7c30e 100644 --- a/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue +++ b/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue @@ -41,7 +41,7 @@ import AppEagleEyeSettings from '@/premium/eagle-eye/components/list/eagle-eye-s import AppEagleEyeList from '@/premium/eagle-eye/components/list/eagle-eye-list.vue' import AppEagleEyeLoadingState from '@/premium/eagle-eye/components/list/eagle-eye-loading-state.vue' import { mapGetters } from '@/shared/vuex/vuex.helpers' -import { computed, onMounted } from 'vue' +import { computed, onMounted } from 'vue' import { useStore } from 'vuex' const { showBanner } = mapGetters('tenant') From a281a535c1bcea03094b502eba58bd7ba7a256af Mon Sep 17 00:00:00 2001 From: Joan Reyero Date: Tue, 14 Feb 2023 10:22:00 +0100 Subject: [PATCH 7/7] Changed naming --- backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts | 2 +- backend/src/services/eagleEyeActionService.ts | 4 ++-- backend/src/services/eagleEyeSettingsService.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts b/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts index 4e20baf780..c3ccdac065 100644 --- a/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts +++ b/backend/src/api/eagleEyeContent/eagleEyeContentTrack.ts @@ -5,7 +5,7 @@ import track from '../../segment/track' export default async (req, res) => { new PermissionChecker(req).validateHas(Permissions.values.eagleEyeContentRead) track( - 'Eagle Eye post click', + 'Eagle Eye post clicked', { url: req.body.url, platform: req.body.platform, diff --git a/backend/src/services/eagleEyeActionService.ts b/backend/src/services/eagleEyeActionService.ts index 179afeb670..79a5bbd956 100644 --- a/backend/src/services/eagleEyeActionService.ts +++ b/backend/src/services/eagleEyeActionService.ts @@ -30,7 +30,7 @@ export default class EagleEyeActionService extends LoggingBase { // Tracking here so we have access to url and platform track( - `Eagle Eye post ${data.type === EagleEyeActionType.BOOKMARK ? 'bookmark' : 'feedback'}`, + `Eagle Eye post ${data.type === EagleEyeActionType.BOOKMARK ? 'bookmarked' : 'voted'}`, { type: data.type, url: content.url, @@ -117,7 +117,7 @@ export default class EagleEyeActionService extends LoggingBase { // Tracking here so we have access to url and platform track( - `Eagle Eye post ${action.type === EagleEyeActionType.BOOKMARK ? 'bookmark' : 'feedback'}`, + `Eagle Eye post ${action.type === EagleEyeActionType.BOOKMARK ? 'bookmarked' : 'voted'}`, { type: action.type, url: content.url, diff --git a/backend/src/services/eagleEyeSettingsService.ts b/backend/src/services/eagleEyeSettingsService.ts index b4b8b66220..211494cf35 100644 --- a/backend/src/services/eagleEyeSettingsService.ts +++ b/backend/src/services/eagleEyeSettingsService.ts @@ -152,7 +152,7 @@ export default class EagleEyeSettingsService extends LoggingBase { if (data.emailDigestActive) { track( - 'EagleEye Email Settings Updated', + 'Eagle Eye email settings updated', { email: settingsOut.emailDigest.email, frequency: settingsOut.emailDigest.frequency, @@ -168,7 +168,7 @@ export default class EagleEyeSettingsService extends LoggingBase { ) } else { track( - 'EagleEye Settings Updated', + 'Eagle Eye settings updated', { onboarded: settingsOut.onboarded, emailDigestActive: settingsOut.emailDigestActive,