diff --git a/plugin-server/src/worker/ingestion/hooks.ts b/plugin-server/src/worker/ingestion/hooks.ts index 42f932029f095..15f1ec69bda22 100644 --- a/plugin-server/src/worker/ingestion/hooks.ts +++ b/plugin-server/src/worker/ingestion/hooks.ts @@ -100,9 +100,24 @@ export const PERSON_DEFAULT_DISPLAY_NAME_PROPERTIES = [ 'UserName', ] -export function getPersonLink(event: PostIngestionEvent, siteUrl: string): string { - return `${siteUrl}/person/${encodeURIComponent(event.distinctId)}` +function getProjectUrl(team: Team, siteUrl: string): string { + return `${siteUrl}/project/${team.id}` } + +function getPersonLink(team: Team, siteUrl: string, event: PostIngestionEvent): string { + return `${getProjectUrl(team, siteUrl)}/person/${encodeURIComponent(event.distinctId)}` +} + +function getActionLink(team: Team, siteUrl: string, action: Action): string { + return `${getProjectUrl(team, siteUrl)}/action/${action.id}` +} + +function getEventLink(team: Team, siteUrl: string, event: PostIngestionEvent): string { + return `${getProjectUrl(team, siteUrl)}/events/${encodeURIComponent(event.eventUuid)}/${encodeURIComponent( + event.timestamp + )}` +} + export function getPersonDetails( event: PostIngestionEvent, siteUrl: string, @@ -119,25 +134,25 @@ export function getPersonDetails( const display: string | undefined = (customIdentifier || event.distinctId)?.trim() - return toWebhookLink(display, getPersonLink(event, siteUrl), webhookType) + return toWebhookLink(display, getPersonLink(team, siteUrl, event), webhookType) } -export function getActionLink(action: Action, siteUrl: string): string { - return `${siteUrl}/action/${action.id}` -} -export function getActionDetails(action: Action, siteUrl: string, webhookType: WebhookType): [string, string] { - return toWebhookLink(action.name, getActionLink(action, siteUrl), webhookType) +export function getActionDetails( + team: Team, + action: Action, + siteUrl: string, + webhookType: WebhookType +): [string, string] { + return toWebhookLink(action.name, getActionLink(team, siteUrl, action), webhookType) } -export function getEventLink(event: PostIngestionEvent, siteUrl: string): string { - return `${siteUrl}/events/${encodeURIComponent(event.eventUuid)}/${encodeURIComponent(event.timestamp)}` -} export function getEventDetails( + team: Team, event: PostIngestionEvent, siteUrl: string, webhookType: WebhookType ): [string, string] { - return toWebhookLink(event.event, getEventLink(event, siteUrl), webhookType) + return toWebhookLink(event.event, getEventLink(team, siteUrl, event), webhookType) } const TOKENS_REGEX_BRACKETS_EXCLUDED = /(?<=(? 2) { const property = event.person_properties ? getPropertyValueByPath(event.person_properties, tokenParts.slice(2)) @@ -187,15 +202,15 @@ export function getValueOfToken( } } else if (tokenParts[0] === 'action') { if (tokenParts[1] === 'name') { - ;[text, markdown] = getActionDetails(action, siteUrl, webhookType) + ;[text, markdown] = getActionDetails(team, action, siteUrl, webhookType) } else if (tokenParts[1] === 'link') { - markdown = text = webhookEscape(getActionLink(action, siteUrl), webhookType) + markdown = text = webhookEscape(getActionLink(team, siteUrl, action), webhookType) } } else if (tokenParts[0] === 'event') { if (tokenParts.length === 1) { - ;[text, markdown] = getEventDetails(event, siteUrl, webhookType) + ;[text, markdown] = getEventDetails(team, event, siteUrl, webhookType) } else if (tokenParts[1] === 'link') { - markdown = text = webhookEscape(getEventLink(event, siteUrl), webhookType) + markdown = text = webhookEscape(getEventLink(team, siteUrl, event), webhookType) } else if (tokenParts[1] === 'uuid') { markdown = text = webhookEscape(event.eventUuid, webhookType) } else if (tokenParts[1] === 'name') { @@ -245,7 +260,7 @@ export function getFormattedMessage( messageText = format(tokenizedMessage, ...values) messageMarkdown = format(tokenizedMessage, ...markdownValues) } catch (error) { - const [actionName, actionMarkdown] = getActionDetails(action, siteUrl, webhookType) + const [actionName, actionMarkdown] = getActionDetails(team, action, siteUrl, webhookType) messageText = `⚠ Error: There are one or more formatting errors in the message template for action "${actionName}".` messageMarkdown = `*⚠ Error: There are one or more formatting errors in the message template for action "${actionMarkdown}".*` } diff --git a/plugin-server/tests/worker/ingestion/event-pipeline/event-pipeline-integration.test.ts b/plugin-server/tests/worker/ingestion/event-pipeline/event-pipeline-integration.test.ts index 10aba7b024bf6..ddca28ffe0117 100644 --- a/plugin-server/tests/worker/ingestion/event-pipeline/event-pipeline-integration.test.ts +++ b/plugin-server/tests/worker/ingestion/event-pipeline/event-pipeline-integration.test.ts @@ -159,7 +159,7 @@ describe('Event Pipeline integration test', () => { await ingestEvent(event) const expectedPayload = { - text: '[Test Action](https://example.com/action/69) was triggered by [abc](https://example.com/person/abc)', + text: '[Test Action](https://example.com/project/2/action/69) was triggered by [abc](https://example.com/project/2/person/abc)', } expect(fetch).toHaveBeenCalledWith('https://webhook.example.com/', { diff --git a/plugin-server/tests/worker/ingestion/hooks.test.ts b/plugin-server/tests/worker/ingestion/hooks.test.ts index 16ade8c8a31da..6c45c06e0d77c 100644 --- a/plugin-server/tests/worker/ingestion/hooks.test.ts +++ b/plugin-server/tests/worker/ingestion/hooks.test.ts @@ -17,6 +17,7 @@ import { import { Hook } from './../../../src/types' describe('hooks', () => { + const team = { id: 123, person_display_name_properties: null } as Team beforeEach(() => { process.env.NODE_ENV = 'test' }) @@ -46,7 +47,6 @@ describe('hooks', () => { distinctId: 'WALL-E', person_properties: { email: 'test@posthog.com' }, } as unknown as PostIngestionEvent - const team = { person_display_name_properties: null } as Team test('Slack', () => { const [userDetails, userDetailsMarkdown] = getPersonDetails( @@ -57,7 +57,7 @@ describe('hooks', () => { ) expect(userDetails).toBe('test@posthog.com') - expect(userDetailsMarkdown).toBe('') + expect(userDetailsMarkdown).toBe('') }) test('Teams', () => { @@ -69,7 +69,7 @@ describe('hooks', () => { ) expect(userDetails).toBe('test@posthog.com') - expect(userDetailsMarkdown).toBe('[test@posthog.com](http://localhost:8000/person/WALL-E)') + expect(userDetailsMarkdown).toBe('[test@posthog.com](http://localhost:8000/project/123/person/WALL-E)') }) }) @@ -78,24 +78,26 @@ describe('hooks', () => { test('Slack', () => { const [actionDetails, actionDetailsMarkdown] = getActionDetails( + team, action, 'http://localhost:8000', WebhookType.Slack ) expect(actionDetails).toBe('action1') - expect(actionDetailsMarkdown).toBe('') + expect(actionDetailsMarkdown).toBe('') }) test('Teams', () => { const [actionDetails, actionDetailsMarkdown] = getActionDetails( + team, action, 'http://localhost:8000', WebhookType.Other ) expect(actionDetails).toBe('action1') - expect(actionDetailsMarkdown).toBe('[action1](http://localhost:8000/action/1)') + expect(actionDetailsMarkdown).toBe('[action1](http://localhost:8000/project/123/action/1)') }) }) @@ -129,7 +131,6 @@ describe('hooks', () => { person_properties: { enjoys_broccoli_on_pizza: false }, timestamp: '2021-10-31T00:44:00.000Z', } as unknown as PostIngestionEvent - const team = { person_display_name_properties: null } as Team test('event', () => { const tokenUserName = ['event'] @@ -144,7 +145,9 @@ describe('hooks', () => { ) expect(text).toBe('$pageview') - expect(markdown).toBe('[$pageview](http://localhost:8000/events/123/2021-10-31T00%3A44%3A00.000Z)') + expect(markdown).toBe( + '[$pageview](http://localhost:8000/project/123/events/123/2021-10-31T00%3A44%3A00.000Z)' + ) }) test('event UUID', () => { @@ -224,7 +227,7 @@ describe('hooks', () => { ) expect(text).toBe('WALL-E') - expect(markdown).toBe('[WALL-E](http://localhost:8000/person/WALL-E)') + expect(markdown).toBe('[WALL-E](http://localhost:8000/project/123/person/WALL-E)') }) test('person with email', () => { @@ -240,7 +243,7 @@ describe('hooks', () => { ) expect(text).toBe('wall-e@buynlarge.com') - expect(markdown).toBe('[wall-e@buynlarge.com](http://localhost:8000/person/WALL-E)') + expect(markdown).toBe('[wall-e@buynlarge.com](http://localhost:8000/project/123/person/WALL-E)') }) test('person with custom name property, team-level setting ', () => { @@ -264,7 +267,7 @@ describe('hooks', () => { ) expect(text).toBe('Brzęczyszczykiewicz') - expect(markdown).toBe('[Brzęczyszczykiewicz](http://localhost:8000/person/fd)') + expect(markdown).toBe('[Brzęczyszczykiewicz](http://localhost:8000/project/123/person/fd)') }) test('person prop', () => { @@ -340,7 +343,7 @@ describe('hooks', () => { ) expect(text).toBe('WALL-E') - expect(markdown).toBe('[WALL-E](http://localhost:8000/person/WALL-E)') + expect(markdown).toBe('[WALL-E](http://localhost:8000/project/123/person/WALL-E)') }) test('user prop (actually event prop)', () => { @@ -387,7 +390,7 @@ describe('hooks', () => { expect(text).toBe('text><new link') expect(markdown).toBe( - '' + '' ) }) @@ -403,7 +406,7 @@ describe('hooks', () => { expect(text).toBe('text\\]\\(yes\\!\\), \\[new link') expect(markdown).toBe( - '[text\\]\\(yes\\!\\), \\[new link](http://localhost:8000/events/\\*\\*\\)/2021-10-31T00%3A44%3A00.000Z)' + '[text\\]\\(yes\\!\\), \\[new link](http://localhost:8000/project/123/events/\\*\\*\\)/2021-10-31T00%3A44%3A00.000Z)' ) }) }) @@ -413,7 +416,6 @@ describe('hooks', () => { distinctId: '2', properties: { $browser: 'Chrome', page_title: 'Pricing', 'with space': 'yes sir' }, } as unknown as PostIngestionEvent - const team = { person_display_name_properties: null } as Team test('custom format', () => { const action = { @@ -431,7 +433,7 @@ describe('hooks', () => { ) expect(text).toBe('2 from Chrome on Pricing page with undefined, yes sir') expect(markdown).toBe( - ' from Chrome on Pricing page with undefined, yes sir' + ' from Chrome on Pricing page with undefined, yes sir' ) }) @@ -450,7 +452,7 @@ describe('hooks', () => { WebhookType.Slack ) expect(text).toBe('2 did thing from browser undefined') - expect(markdown).toBe(' did thing from browser undefined') + expect(markdown).toBe(' did thing from browser undefined') }) }) @@ -462,7 +464,6 @@ describe('hooks', () => { name: 'action1', // slack_message_format: '[user.name] did thing from browser [user.brauzer]', } as Action - const team = { person_display_name_properties: null } as Team beforeEach(() => { hook = {