Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(whatsapp/messenger): improve configuration XP #13389

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 19 additions & 24 deletions integrations/messenger/integration.definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,38 @@ export const INTEGRATION_NAME = 'messenger'

export default new IntegrationDefinition({
name: INTEGRATION_NAME,
version: '2.0.2',
version: '2.1.0',
title: 'Messenger',
description: 'This integration allows your bot to interact with Messenger.',
icon: 'icon.svg',
readme: 'hub.md',
configuration: {
identifier: {
linkTemplateScript: 'linkTemplate.vrl',
required: true,
},
ui: {
useManualConfiguration: {
title: 'Use Manual Configuration',
},
},
schema: z
.object({
useManualConfiguration: z.boolean().optional().describe('Skip oAuth and supply details from a Meta App'),
verifyToken: z.string().optional().describe('Token used for verification when subscribing to webhooks'),
schema: z.object({}),
},
configurations: {
manualApp: {
title: 'Manual Configuration',
description: 'Manual Configuration, use your own Meta app (for advanced use cases only)',
schema: z.object({
verifyToken: z
.string()
.min(1)
.describe(
'Token used for verification when subscribing to webhooks on the Meta app (type any random string)'
),
accessToken: z
.string()
.optional()
.min(1)
.describe('Access Token from a System Account that has permission to the Meta app'),
clientId: z.string().optional(),
clientId: z.string().min(1).describe('Meta app client id'),
clientSecret: z.string().optional().describe('Meta app secret used for webhook signature check'),
pageId: z.string().optional().describe('Id from the Facebook page'),
})
.hidden((formData) => {
const showConfig = !formData?.useManualConfiguration

return {
verifyToken: showConfig,
accessToken: showConfig,
clientId: showConfig,
clientSecret: showConfig,
pageId: showConfig,
}
pageId: z.string().min(1).describe('Id from the Facebook page'),
}),
},
},
identifier: {
extractScript: 'extract.vrl',
Expand Down
2 changes: 1 addition & 1 deletion integrations/messenger/src/misc/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export async function getCredentials(
client: bp.Client,
ctx: bp.Context
): Promise<{ accessToken: string; clientSecret: string; clientId: string }> {
if (ctx.configuration.useManualConfiguration) {
if (ctx.configurationType === 'manualApp') {
return {
accessToken: ctx.configuration.accessToken || '',
clientSecret: ctx.configuration.clientSecret || '',
Expand Down
16 changes: 16 additions & 0 deletions integrations/messenger/src/misc/wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,22 @@ export const handleWizard = async (req: Request, client: bp.Client, ctx: bp.Cont
identifier: pageId,
})

return generateButtonDialog({
title: 'Configuration Complete',
description: `Your configuration is now complete and the selected Facebook page will start answering as this bot, you can open it on Messenger and test it.

Here are some things to verify if you are unable to talk with your bot on Messenger.

- Confirm if are talking with the page that was selected for this bot
- Double check if you published this bot
`,
buttons: [
{ display: 'Okay', type: 'primary', action: 'NAVIGATE', payload: `${req.path}?wizard-step=wrap-up-finish` },
],
})
}

if (wizardStep === 'wrap-up-finish') {
return redirectTo(getInterstitialUrl(true))
}

Expand Down
54 changes: 26 additions & 28 deletions integrations/whatsapp/integration.definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,44 +32,42 @@ export const INTEGRATION_NAME = 'whatsapp'

export default new IntegrationDefinition({
name: INTEGRATION_NAME,
version: '2.0.9',
version: '2.1.0',
title: 'WhatsApp',
description: 'This integration allows your bot to interact with WhatsApp.',
icon: 'icon.svg',
readme: 'hub.md',
configuration: {
identifier: {
linkTemplateScript: 'linkTemplate.vrl',
},
ui: {
phoneNumberId: {
title: 'Default Phone Number ID for starting conversations',
},
useManualConfiguration: {
title: 'Use Manual Configuration',
configurations: {
manualApp: {
title: 'Manual Configuration',
description: 'Manual Configuration, use your own Meta app (for advanced use cases only)',
ui: {
phoneNumberId: {
title: 'Default Phone Number ID for starting conversations',
},
},
},
schema: z
.object({
useManualConfiguration: z.boolean().optional().describe('Skip oAuth and supply details from a Meta App'),
verifyToken: z.string().optional().describe('Token used for verification when subscribing to webhooks'),
schema: z.object({
verifyToken: z
.string()
.min(1)
.describe(
'Token used for verification when subscribing to webhooks on the Meta app (type any random string)'
),
accessToken: z
.string()
.optional()
.min(1)
.describe('Access Token from a System Account that has permission to the Meta app'),
clientSecret: z.string().optional().describe('Meta app secret used for webhook signature check'),
phoneNumberId: z.string().optional().describe('Default Phone used for starting conversations'),
})
.hidden((formData) => {
const showConfig = !formData?.useManualConfiguration

return {
verifyToken: showConfig,
accessToken: showConfig,
clientSecret: showConfig,
phoneNumberId: showConfig,
}
phoneNumberId: z.string().min(1).describe('Default Phone id used for starting conversations'),
}),
},
},
configuration: {
identifier: {
linkTemplateScript: 'linkTemplate.vrl',
required: true,
},
schema: z.object({}),
},
identifier: {
extractScript: 'extract.vrl',
Expand Down
7 changes: 5 additions & 2 deletions integrations/whatsapp/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import * as bp from '.botpress'

const integration = new bp.Integration({
register: async (input) => {
const { useManualConfiguration, accessToken, clientSecret, phoneNumberId, verifyToken } = input.ctx.configuration
const useManualConfiguration = input.ctx.configurationType === 'manualApp'

await identifyBot(input.ctx.botId, {
[INTEGRATION_NAME + 'OauthType']: useManualConfiguration ? 'manual' : 'oauth',
Expand All @@ -33,6 +33,9 @@ const integration = new bp.Integration({
return // nothing more to do if we're not using manual configuration
}

const { accessToken, clientSecret, phoneNumberId, verifyToken } = input.ctx
.configuration as bp.configurations.manualApp.ManualAppConfig

if (accessToken && clientSecret && phoneNumberId && verifyToken) {
// let's check the credentials
const isValidConfiguration = await checkManualConfiguration(accessToken)
Expand Down Expand Up @@ -188,7 +191,7 @@ const integration = new bp.Integration({
const token = query['hub.verify_token']
const challenge = query['hub.challenge']

if (mode === 'subscribe') {
if (mode === 'subscribe' && ctx.configurationType === 'manualApp') {
if (token === ctx.configuration.verifyToken) {
if (!challenge) {
logger.forBot().warn('Returning HTTP 400 as no challenge parameter was received in query string of request')
Expand Down
6 changes: 3 additions & 3 deletions integrations/whatsapp/src/misc/whatsapp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export class MetaOauthClient {
}

export const getAccessToken = async (client: bp.Client, ctx: bp.Context): Promise<string> => {
if (ctx.configuration.useManualConfiguration) {
if (ctx.configurationType === 'manualApp') {
return ctx.configuration.accessToken as string
}

Expand All @@ -147,7 +147,7 @@ export const getAccessToken = async (client: bp.Client, ctx: bp.Context): Promis

export const getSecret = (ctx: bp.Context): string | undefined => {
let value: string | undefined
if (ctx.configuration.useManualConfiguration) {
if (ctx.configurationType === 'manualApp') {
value = ctx.configuration.clientSecret
} else {
value = bp.secrets.CLIENT_SECRET
Expand All @@ -157,7 +157,7 @@ export const getSecret = (ctx: bp.Context): string | undefined => {
}

export const getPhoneNumberId = async (client: bp.Client, ctx: bp.Context) => {
if (ctx.configuration.useManualConfiguration) {
if (ctx.configurationType === 'manualApp') {
return ctx.configuration.phoneNumberId
}

Expand Down
18 changes: 18 additions & 0 deletions integrations/whatsapp/src/misc/wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,24 @@ export const handleWizard = async (req: Request, client: bp.Client, ctx: bp.Cont
await oauthClient.registerNumber(phoneNumberId, accessToken)
await oauthClient.subscribeToWebhooks(wabaId, accessToken)

return generateButtonDialog({
title: 'Configuration Complete',
description: `Your configuration is now complete and the selected WhatsApp number will start answering as this bot, you can add the number to your personal contacts and test it.

Here are some things to verify if you are unable to talk with your bot on WhatsApp.

- Confirm if you added the correct number (With country and area code)
- Double check if you published this bot
- Wait a few hours (3-4) for Meta to process the Setup
- Verify if your display name was not denied by Meta (you will get an email in the Facebook accounts email address)
`,
buttons: [
{ display: 'Okay', type: 'primary', action: 'NAVIGATE', payload: `${req.path}?wizard-step=wrap-up-finish` },
],
})
}

if (wizardStep === 'wrap-up-finish') {
return redirectTo(getInterstitialUrl(true))
}

Expand Down
Loading