Skip to content

Commit 18fe75e

Browse files
committed
send track events to crowd tenant
1 parent 3c00e08 commit 18fe75e

File tree

6 files changed

+139
-0
lines changed

6 files changed

+139
-0
lines changed

backend/config/custom-environment-variables.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,5 +188,11 @@
188188
"auth0": {
189189
"clientId": "CROWD_AUTH0_CLIENT_ID",
190190
"jwks": "CROWD_AUTH0_JWKS"
191+
},
192+
"crowdAnalytics": {
193+
"tenantId": "CROWD_ANALYTICS_TENANT_ID",
194+
"isEnabled": "CROWD_ANALYTICS_IS_ENABLED",
195+
"baseUrl": "CROWD_ANALYTICS_BASE_URL",
196+
"apiToken": "CROWD_ANALYTICS_API_TOKEN"
191197
}
192198
}

backend/src/conf/configTypes.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,10 @@ export interface IOpenSearchConfig {
232232
accessKeyId?: string
233233
secretAccessKey?: string
234234
}
235+
236+
export interface CrowdAnalyticsConfiguration {
237+
isEnabled: string
238+
tenantId: string
239+
baseUrl: string
240+
apiToken: string
241+
}

backend/src/conf/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
IOpenSearchConfig,
3434
Auth0Configuration,
3535
WeeklyEmailsConfiguration,
36+
CrowdAnalyticsConfiguration,
3637
} from './configTypes'
3738

3839
// TODO-kube
@@ -130,3 +131,6 @@ export const INTEGRATION_PROCESSING_CONFIG: IntegrationProcessingConfiguration =
130131

131132
export const WEEKLY_EMAILS_CONFIG: WeeklyEmailsConfiguration =
132133
config.get<WeeklyEmailsConfiguration>('weeklyEmails')
134+
135+
export const CROWD_ANALYTICS_CONFIG: CrowdAnalyticsConfiguration =
136+
config.get<CrowdAnalyticsConfiguration>('crowdAnalytics')

backend/src/database/repositories/tenantRepository.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,22 @@ class TenantRepository {
505505

506506
return platforms
507507
}
508+
509+
static async getTenantInfo(id: string, options: IRepositoryOptions) {
510+
const query = `
511+
select name, plan, "isTrialPlan", "trialEndsAt" from tenants where "tenantId" = :tenantId
512+
`
513+
const parameters: any = {
514+
tenantId: id,
515+
}
516+
517+
const info = await options.database.sequelize.query(query, {
518+
replacements: parameters,
519+
type: QueryTypes.SELECT,
520+
})
521+
522+
return info
523+
}
508524
}
509525

510526
export default TenantRepository
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import axios from 'axios'
2+
import { CROWD_ANALYTICS_CONFIG } from '@/conf'
3+
import UserRepository from '../database/repositories/userRepository'
4+
import TenantRepository from '../database/repositories/tenantRepository'
5+
import SequelizeRepository from '../database/repositories/sequelizeRepository'
6+
7+
const IS_CROWD_ANALYTICS_ENABLED = CROWD_ANALYTICS_CONFIG.isEnabled === 'true'
8+
const CROWD_ANALYTICS_TENANT_ID = CROWD_ANALYTICS_CONFIG.tenantId
9+
const CROWD_ANALYTICS_BASE_URL = CROWD_ANALYTICS_CONFIG.baseUrl
10+
const CROWD_ANALYTICS_TOKEN = CROWD_ANALYTICS_CONFIG.apiToken
11+
12+
// createdAnAccount (boolean)
13+
14+
// email
15+
16+
// firstName
17+
18+
// lastName
19+
20+
// plan
21+
22+
// is_trial
23+
24+
// trialEndsDate
25+
26+
// workspace <> organization
27+
28+
// Workspace → organization attributes
29+
30+
// Name
31+
32+
interface CrowdAnalyticsData {
33+
userId: string
34+
tenantId: string
35+
event: string
36+
timestamp: string
37+
properties: any
38+
}
39+
40+
export default async function addProductData(data: CrowdAnalyticsData) {
41+
if (!IS_CROWD_ANALYTICS_ENABLED) {
42+
return
43+
}
44+
45+
if (!CROWD_ANALYTICS_TENANT_ID) {
46+
return
47+
}
48+
49+
if (!CROWD_ANALYTICS_BASE_URL) {
50+
return
51+
}
52+
53+
if (!CROWD_ANALYTICS_TOKEN) {
54+
return
55+
}
56+
57+
try {
58+
const repositoryOptions = await SequelizeRepository.getDefaultIRepositoryOptions()
59+
60+
const user = await UserRepository.findById(data.userId, repositoryOptions)
61+
62+
const tenant = await TenantRepository.getTenantInfo(data.tenantId, repositoryOptions)
63+
64+
const obj = {
65+
member: {
66+
username: {
67+
'crowd.dev': user.email,
68+
},
69+
emails: [user.email],
70+
displayName: user.fullName,
71+
attributes: {
72+
email: user.email,
73+
createdAnAccount: true,
74+
firstName: user.firstName,
75+
lastName: user.lastName,
76+
plan: tenant.plan,
77+
isTrialPlan: tenant.isTrialPlan,
78+
trialEndsAt: tenant.trialEndsAt,
79+
},
80+
},
81+
type: data.event,
82+
timestamp: data.timestamp,
83+
platform: 'crowd.dev',
84+
sourceId: `${data.userId}-${data.timestamp}-${data.event}`,
85+
}
86+
const endpoint = `${CROWD_ANALYTICS_BASE_URL}/api/tenant/${CROWD_ANALYTICS_TENANT_ID}/activity/with-member`
87+
await axios.post(endpoint, obj, {
88+
headers: {
89+
Authorization: `Bearer ${CROWD_ANALYTICS_TOKEN}`,
90+
},
91+
})
92+
} catch (error) {
93+
// nothing
94+
}
95+
}

backend/src/segment/track.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { getServiceChildLogger } from '@crowd/logging'
22
import { Edition } from '@crowd/types'
33
import { API_CONFIG, IS_TEST_ENV, SEGMENT_CONFIG } from '../conf'
44
import getTenatUser from './trackHelper'
5+
// eslint-disable-next-line import/no-cycle
6+
import addProductData from './addProductDataToCrowdTenant'
57

68
const log = getServiceChildLogger('segment')
79

@@ -35,6 +37,15 @@ export default function identify(
3537

3638
try {
3739
analytics.track(payload)
40+
41+
// send product analytics data to crowd tenant workspace
42+
addProductData({
43+
userId: userIdOut,
44+
tenantId: tenantIdOut,
45+
event,
46+
timestamp,
47+
properties,
48+
})
3849
} catch (error) {
3950
log.error(error, { payload }, 'ERROR: Could not send the following payload to Segment')
4051
}

0 commit comments

Comments
 (0)