From ea81c998a781a764dc05ea585e5d36550674df3f Mon Sep 17 00:00:00 2001 From: Sander Bruens Date: Thu, 22 Feb 2024 10:45:29 -0500 Subject: [PATCH] feat(sentry_webhook): update Salesforce record IDs for new contact form (#1510) * chore(sentry_webhook): update Salesforce record IDs for new contact form * Add new `accessKeySource` and `build`. * Add new fields `subject` and `isUpdatedForm`. * Change `type` field to new `role` field. * Normalize `cloudProvider` value based on allowed picklist values. * Update tests. --- .../post_sentry_event_to_salesforce.spec.ts | 20 ++-- .../post_sentry_event_to_salesforce.ts | 94 ++++++++++++++++--- 2 files changed, 93 insertions(+), 21 deletions(-) diff --git a/src/sentry_webhook/post_sentry_event_to_salesforce.spec.ts b/src/sentry_webhook/post_sentry_event_to_salesforce.spec.ts index 008ae031..bfb9c138 100644 --- a/src/sentry_webhook/post_sentry_event_to_salesforce.spec.ts +++ b/src/sentry_webhook/post_sentry_event_to_salesforce.spec.ts @@ -57,7 +57,7 @@ describe('postSentryEventToSalesforce', () => { '&email=foo%40bar.com' + '&00N0b00000BqOA4=' + '&description=my%20message' + - '&type=Outline%20client' + '&00N5a00000DXxmr=I%20am%20using%20the%20Outline%20client%20application%20on%20my%20mobile%20or%20desktop%20device' ); expect(mockRequest.end).toHaveBeenCalled(); }); @@ -81,7 +81,7 @@ describe('postSentryEventToSalesforce', () => { '&email=foo%40bar.com' + '&00N3F000002Rqhq=' + '&description=my%20message' + - '&type=Outline%20client' + '&UNKNOWN=I%20am%20using%20the%20Outline%20client%20application%20on%20my%20mobile%20or%20desktop%20device' ); expect(mockRequest.end).toHaveBeenCalled(); }); @@ -91,9 +91,12 @@ describe('postSentryEventToSalesforce', () => { user: {email: 'foo@bar.com'}, message: 'my message', tags: [ - ['category', 'test category'], + ['category', 'no-server'], + ['subject', 'test subject'], ['os.name', 'Mac OS X'], ['sentry:release', 'test version'], + ['build.number', '0.0.0-debug'], + ['accessKeySource', 'test source'], ['unknown:tag', 'foo'], ], }; @@ -107,10 +110,13 @@ describe('postSentryEventToSalesforce', () => { '&email=foo%40bar.com' + '&00N0b00000BqOA4=' + '&description=my%20message' + - '&type=Outline%20client' + - '&00N0b00000BqOA2=test%20category' + - '&00N0b00000BqOfW=macOs' + - '&00N0b00000BqOfR=test%20version' + '&00N5a00000DXxmr=I%20am%20using%20the%20Outline%20client%20application%20on%20my%20mobile%20or%20desktop%20device' + + '&00N5a00000DXy19=I%20need%20an%20access%20key' + + '&subject=test%20subject' + + '&00N5a00000DXxmo=MacOS' + + '&00N5a00000DXxmq=test%20version' + + '&00N5a00000DXy64=0.0.0-debug' + + '&00N5a00000DXxms=test%20source' ); expect(mockRequest.end).toHaveBeenCalled(); }); diff --git a/src/sentry_webhook/post_sentry_event_to_salesforce.ts b/src/sentry_webhook/post_sentry_event_to_salesforce.ts index 45883043..83f8e52d 100644 --- a/src/sentry_webhook/post_sentry_event_to_salesforce.ts +++ b/src/sentry_webhook/post_sentry_event_to_salesforce.ts @@ -20,13 +20,17 @@ interface SalesforceFormFields { orgId: string; recordType: string; email: string; + subject: string; description: string; - category: string; + issue: string; + accessKeySource: string; cloudProvider: string; sentryEventUrl: string; os: string; version: string; - type: string; + build: string; + role: string; + isUpdatedForm: string; } // Defines the Salesforce form values. @@ -42,25 +46,33 @@ const SALESFORCE_FORM_FIELDS_DEV: SalesforceFormFields = { orgId: 'orgid', recordType: 'recordType', email: 'email', + subject: 'subject', description: 'description', - category: '00N3F000002Rqho', + issue: '00N3F000002Rqho', + accessKeySource: '00N75000000wYiY', cloudProvider: '00N3F000002Rqhs', sentryEventUrl: '00N3F000002Rqhq', os: '00N3F000002cLcN', version: '00N3F000002cLcI', - type: 'type', + build: '00N75000000wmdC', + role: 'UNKNOWN', + isUpdatedForm: '00N75000000wmd7', }; const SALESFORCE_FORM_FIELDS_PROD: SalesforceFormFields = { orgId: 'orgid', recordType: 'recordType', email: 'email', + subject: 'subject', description: 'description', - category: '00N0b00000BqOA2', - cloudProvider: '00N0b00000BqOA7', + issue: '00N5a00000DXy19', + accessKeySource: '00N5a00000DXxms', + cloudProvider: '00N5a00000DXxmn', sentryEventUrl: '00N0b00000BqOA4', - os: '00N0b00000BqOfW', - version: '00N0b00000BqOfR', - type: 'type', + os: '00N5a00000DXxmo', + version: '00N5a00000DXxmq', + build: '00N5a00000DXy64', + role: '00N5a00000DXxmr', + isUpdatedForm: '00N5a00000DXy5a', }; const SALESFORCE_FORM_VALUES_DEV: SalesforceFormValues = { orgId: '00D750000004dFg', @@ -71,6 +83,22 @@ const SALESFORCE_FORM_VALUES_PROD: SalesforceFormValues = { recordType: '0120b0000006e8i', }; +const ISSUE_TYPE_TO_PICKLIST_VALUE: {[key: string]: string} = { + 'cannot-add-server': 'I am having trouble adding a server using my access key', + connection: 'I am having trouble connecting to my Outline VPN server', + general: 'General feedback & suggestions', + managing: 'I need assistance managing my Outline VPN server or helping others connect to it', + 'no-server': 'I need an access key', + performance: 'My internet access is slow while connected to my Outline VPN server', +}; + +const CLOUD_PROVIDER_TO_PICKLIST_VALUE: {[key: string]: string} = { + aws: 'Amazon Web Services', + digitalocean: 'DigitalOcean', + gcloud: 'Google Cloud', + other: 'Other', +}; + // Returns whether a Sentry event should be sent to Salesforce by checking that it contains an // email address. export function shouldPostEventToSalesforce(event: SentryEvent): boolean { @@ -138,14 +166,34 @@ function getSalesforceFormData( form.push(encodeFormData(formFields.email, email)); form.push(encodeFormData(formFields.sentryEventUrl, getSentryEventUrl(project, event.event_id))); form.push(encodeFormData(formFields.description, event.message)); - form.push(encodeFormData(formFields.type, isClient ? 'Outline client' : 'Outline manager')); + form.push( + encodeFormData( + formFields.role, + isClient + ? 'I am using the Outline client application on my mobile or desktop device' + : 'I am an Outline server manager' + ) + ); if (event.tags) { const tags = new Map(event.tags); - form.push(encodeFormData(formFields.category, tags.get('category'))); + form.push(encodeFormData(formFields.issue, toIssuePicklistValue(tags.get('category')))); + form.push(encodeFormData(formFields.subject, tags.get('subject'))); form.push(encodeFormData(formFields.os, toOSPicklistValue(tags.get('os.name')))); form.push(encodeFormData(formFields.version, tags.get('sentry:release'))); - if (!isClient) { - form.push(encodeFormData(formFields.cloudProvider, tags.get('cloudProvider'))); + form.push(encodeFormData(formFields.build, tags.get('build.number'))); + const formVersion = Number(tags.get('formVersion') ?? 1); + if (formVersion === 2) { + form.push(encodeFormData(formFields.isUpdatedForm, 'true')); + } + if (isClient) { + form.push(encodeFormData(formFields.accessKeySource, tags.get('accessKeySource'))); + } else { + form.push( + encodeFormData( + formFields.cloudProvider, + toCloudProviderPicklistValue(tags.get('cloudProvider')) + ) + ); } } return form.join('&'); @@ -169,11 +217,29 @@ function toOSPicklistValue(value: string | undefined): string | undefined { return 'Windows'; } if (normalizedValue.includes('mac')) { - return 'macOs'; + return 'MacOS'; } return 'Linux'; } +// Returns a picklist value that is allowed by SalesForce for the issue record. +function toIssuePicklistValue(value: string | undefined): string | undefined { + if (!value) { + console.warn('No issue type found'); + return undefined; + } + return ISSUE_TYPE_TO_PICKLIST_VALUE[value]; +} + +// Returns a picklist value that is allowed by SalesForce for the cloud provider record. +function toCloudProviderPicklistValue(value: string | undefined): string | undefined { + if (!value) { + console.warn('No cloud provider found'); + return undefined; + } + return CLOUD_PROVIDER_TO_PICKLIST_VALUE[value]; +} + function encodeFormData(field: string, value?: string) { return `${encodeURIComponent(field)}=${encodeURIComponent(value || '')}`; }