feat(whatsapp.gblib): Switch from Whatsapp channel which bot to talk to with the same number.
This commit is contained in:
		
							parent
							
								
									b2da413f0f
								
							
						
					
					
						commit
						cb3d241fbc
					
				
					 7 changed files with 147 additions and 31 deletions
				
			
		| 
						 | 
				
			
			@ -37,7 +37,7 @@
 | 
			
		|||
'use strict';
 | 
			
		||||
 | 
			
		||||
const crypto = require('crypto');
 | 
			
		||||
const emptyDir = require('empty-dir');
 | 
			
		||||
const rimraf = require('rimraf');
 | 
			
		||||
import { WaterfallDialog } from 'botbuilder-dialogs';
 | 
			
		||||
import { GBMinInstance, IGBDialog } from 'botlib';
 | 
			
		||||
import urlJoin = require('url-join');
 | 
			
		||||
| 
						 | 
				
			
			@ -83,8 +83,7 @@ export class AdminDialog extends IGBDialog {
 | 
			
		|||
      await s.downloadFolder(localFolder, siteName, folderName,
 | 
			
		||||
        GBConfigService.get('CLOUD_USERNAME'), GBConfigService.get('CLOUD_PASSWORD'))
 | 
			
		||||
      await deployer.deployPackage(min, localFolder);
 | 
			
		||||
      await emptyDir(localFolder);
 | 
			
		||||
 | 
			
		||||
      rimraf.sync(localFolder);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										70
									
								
								packages/core.gbapp/dialogs/SwitchBot.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								packages/core.gbapp/dialogs/SwitchBot.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
/*****************************************************************************\
 | 
			
		||||
|                                               ( )_  _                       |
 | 
			
		||||
|    _ _    _ __   _ _    __    ___ ___     _ _ | ,_)(_)  ___   ___     _     |
 | 
			
		||||
|   ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| |  | |/',__)/' _ `\ /'_`\   |
 | 
			
		||||
|   | (_) )| |  ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) )  |
 | 
			
		||||
|   | ,__/'(_)  `\__,_)`\__  |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/'  |
 | 
			
		||||
|   | |                ( )_) |                                                |
 | 
			
		||||
|   (_)                 \___/'                                                |
 | 
			
		||||
|                                                                             |
 | 
			
		||||
| General Bots Copyright (c) Pragmatismo.io. All rights reserved.             |
 | 
			
		||||
| Licensed under the AGPL-3.0.                                                |
 | 
			
		||||
|                                                                             |
 | 
			
		||||
| According to our dual licensing model, this program can be used either      |
 | 
			
		||||
| under the terms of the GNU Affero General Public License, version 3,        |
 | 
			
		||||
| or under a proprietary license.                                             |
 | 
			
		||||
|                                                                             |
 | 
			
		||||
| The texts of the GNU Affero General Public License with an additional       |
 | 
			
		||||
| permission and of our proprietary license can be found at and               |
 | 
			
		||||
| in the LICENSE file you have received along with this program.              |
 | 
			
		||||
|                                                                             |
 | 
			
		||||
| This program is distributed in the hope that it will be useful,             |
 | 
			
		||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of              |
 | 
			
		||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                |
 | 
			
		||||
| GNU Affero General Public License for more details.                         |
 | 
			
		||||
|                                                                             |
 | 
			
		||||
| "General Bots" is a registered trademark of Pragmatismo.io.                 |
 | 
			
		||||
| The licensing of the program under the AGPLv3 does not imply a              |
 | 
			
		||||
| trademark license. Therefore any rights, title and interest in              |
 | 
			
		||||
| our trademarks remain entirely with us.                                     |
 | 
			
		||||
|                                                                             |
 | 
			
		||||
\*****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @fileoverview General Bots server core.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
import { BotAdapter } from 'botbuilder';
 | 
			
		||||
import { WaterfallDialog } from 'botbuilder-dialogs';
 | 
			
		||||
import { GBMinInstance, IGBDialog } from 'botlib';
 | 
			
		||||
import { Messages } from '../strings';
 | 
			
		||||
import { SecService } from '../../security.gblib/services/SecService';
 | 
			
		||||
/**
 | 
			
		||||
 * Dialog for the bot explains about itself.
 | 
			
		||||
 */
 | 
			
		||||
export class SwitchBotDialog extends IGBDialog {
 | 
			
		||||
  /**
 | 
			
		||||
   * Setup dialogs flows and define services call.
 | 
			
		||||
   *
 | 
			
		||||
   * @param bot The bot adapter.
 | 
			
		||||
   * @param min The minimal bot instance data.
 | 
			
		||||
   */
 | 
			
		||||
  public static setup(bot: BotAdapter, min: GBMinInstance) {
 | 
			
		||||
    min.dialogs.add(new WaterfallDialog('/bot', [
 | 
			
		||||
 | 
			
		||||
      async step => {
 | 
			
		||||
        const locale = step.context.activity.locale;
 | 
			
		||||
        await step.context.sendActivity(`${min.instance.description}`);
 | 
			
		||||
        return await step.prompt('textPrompt', "Qual seria o código de ativação?");
 | 
			
		||||
      },
 | 
			
		||||
      async step => {
 | 
			
		||||
        let sec = new SecService();
 | 
			
		||||
        let from = step.context.activity.from.id;
 | 
			
		||||
        await sec.updateCurrentBotId(min.instance.instanceId, from, step.result);
 | 
			
		||||
        return await step.next();
 | 
			
		||||
      }
 | 
			
		||||
    ]));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +41,7 @@ import { Sequelize } from 'sequelize-typescript';
 | 
			
		|||
import { WelcomeDialog } from './dialogs/WelcomeDialog';
 | 
			
		||||
import { WhoAmIDialog } from './dialogs/WhoAmIDialog';
 | 
			
		||||
import { GuaribasChannel, GuaribasException, GuaribasInstance, GuaribasPackage } from './models/GBModel';
 | 
			
		||||
import { SwitchBotDialog } from './dialogs/SwitchBot';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Package for core.gbapp.
 | 
			
		||||
| 
						 | 
				
			
			@ -68,5 +69,6 @@ export class GBCorePackage implements IGBPackage {
 | 
			
		|||
  public loadBot(min: GBMinInstance): void {
 | 
			
		||||
    WelcomeDialog.setup(min.bot, min);
 | 
			
		||||
    WhoAmIDialog.setup(min.bot, min);
 | 
			
		||||
    SwitchBotDialog.setup(min.bot, min);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,6 +97,10 @@ export class GBConversationalService implements IGBConversationalService {
 | 
			
		|||
 | 
			
		||||
  public async routeNLP(step: GBDialogStep, min: GBMinInstance, text: string): Promise<boolean> {
 | 
			
		||||
 | 
			
		||||
    if (min.instance.nlpAppId === null){
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const model = new LuisRecognizer({
 | 
			
		||||
      applicationId: min.instance.nlpAppId,
 | 
			
		||||
      endpointKey: min.instance.nlpKey,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -68,6 +68,7 @@ import { Messages } from '../strings';
 | 
			
		|||
import { GBAdminPackage } from './../../admin.gbapp/index';
 | 
			
		||||
import { GBConfigService } from './GBConfigService';
 | 
			
		||||
import { GBDeployer } from './GBDeployer';
 | 
			
		||||
import { SecService } from '../../security.gblib/services/SecService';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Minimal service layer for a bot.
 | 
			
		||||
| 
						 | 
				
			
			@ -127,11 +128,11 @@ export class GBMinService {
 | 
			
		|||
    }
 | 
			
		||||
    const url = '/webhooks/whatsapp';
 | 
			
		||||
    GBServer.globals.server.post(url, async (req, res) => {
 | 
			
		||||
    const text = req.body.messages[0].body;
 | 
			
		||||
    const from = req.body.messages[0].author.split('@')[0];
 | 
			
		||||
    const fromName = req.body.messages[0].senderName;
 | 
			
		||||
 | 
			
		||||
      let botId = 'subway-prd';
 | 
			
		||||
      const from = req.body.messages[0].chatId.split('@')[0];
 | 
			
		||||
      
 | 
			
		||||
      let sec = new SecService();
 | 
			
		||||
      let user = await sec.getUserFromPhone(from);
 | 
			
		||||
      let botId = user.currentBotId;
 | 
			
		||||
      const min = GBServer.globals.minInstances.filter(p => p.botId === botId)[0];
 | 
			
		||||
      (min as any).whatsAppDirectLine.received(req, res);
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -408,6 +409,8 @@ export class GBMinService {
 | 
			
		|||
 | 
			
		||||
        const user = await min.userProfile.get(context, {});
 | 
			
		||||
 | 
			
		||||
        // First time processing.
 | 
			
		||||
 | 
			
		||||
        if (!user.loaded) {
 | 
			
		||||
          await min.conversationalService.sendEvent(step, 'loadInstance', {
 | 
			
		||||
            instanceId: instance.instanceId,
 | 
			
		||||
| 
						 | 
				
			
			@ -419,6 +422,12 @@ export class GBMinService {
 | 
			
		|||
          user.subjects = [];
 | 
			
		||||
          user.cb = undefined;
 | 
			
		||||
          await min.userProfile.set(step.context, user);
 | 
			
		||||
 | 
			
		||||
          let sec = new SecService();
 | 
			
		||||
          const member = context.activity.membersAdded[0];
 | 
			
		||||
 | 
			
		||||
          await sec.ensureUser(instance.instanceId, member.id,
 | 
			
		||||
             min.botId, member.id, "", "web", member.name, member.id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        GBLog.info(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,6 +81,9 @@ export class GuaribasUser extends Model<GuaribasUser> {
 | 
			
		|||
  @Column
 | 
			
		||||
  phone: string
 | 
			
		||||
 | 
			
		||||
  @Column
 | 
			
		||||
  currentBotId: string
 | 
			
		||||
 | 
			
		||||
  @Column(DataType.TEXT)
 | 
			
		||||
  @Column
 | 
			
		||||
  conversationReference: string
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,34 +37,36 @@ export class SecService extends GBService {
 | 
			
		|||
  public async ensureUser(
 | 
			
		||||
    instanceId: number,
 | 
			
		||||
    userSystemId: string,
 | 
			
		||||
    currentBotId: string,
 | 
			
		||||
    userName: string,
 | 
			
		||||
    address: string,
 | 
			
		||||
    channelName: string,
 | 
			
		||||
    displayName: string
 | 
			
		||||
    displayName: string,
 | 
			
		||||
    phone: string
 | 
			
		||||
  ): Promise<GuaribasUser> {
 | 
			
		||||
    return new Promise<GuaribasUser>((resolve, reject) => {
 | 
			
		||||
      GuaribasUser.findOne({
 | 
			
		||||
        attributes: ['instanceId', 'internalAddress'],
 | 
			
		||||
        where: {
 | 
			
		||||
          instanceId: instanceId,
 | 
			
		||||
          userSystemId: userSystemId
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
        .then(user => {
 | 
			
		||||
          if (!user) {
 | 
			
		||||
            user = GuaribasUser.build();
 | 
			
		||||
          }
 | 
			
		||||
          user.userSystemId = userSystemId;
 | 
			
		||||
          user.userName = userName;
 | 
			
		||||
          user.displayName = displayName;
 | 
			
		||||
          user.internalAddress = address;
 | 
			
		||||
          user.email = userName;
 | 
			
		||||
          user.defaultChannel = channelName;
 | 
			
		||||
          user.save();
 | 
			
		||||
          resolve(user);
 | 
			
		||||
        })
 | 
			
		||||
        .error(reject);
 | 
			
		||||
    let user = await GuaribasUser.findOne({
 | 
			
		||||
      
 | 
			
		||||
      where: {
 | 
			
		||||
        instanceId: instanceId,
 | 
			
		||||
        userSystemId: userSystemId
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (!user) {
 | 
			
		||||
      user = GuaribasUser.build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    user.instanceId = instanceId;
 | 
			
		||||
    user.userSystemId = userSystemId;
 | 
			
		||||
    user.currentBotId = currentBotId;
 | 
			
		||||
    user.userName = userName;
 | 
			
		||||
    user.displayName = displayName;
 | 
			
		||||
    user.internalAddress = address;
 | 
			
		||||
    user.email = userName;
 | 
			
		||||
    user.phone = phone;
 | 
			
		||||
    user.defaultChannel = channelName;
 | 
			
		||||
    user.save();
 | 
			
		||||
    return user;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
| 
						 | 
				
			
			@ -88,4 +90,31 @@ export class SecService extends GBService {
 | 
			
		|||
    await user.save();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async updateCurrentBotId(
 | 
			
		||||
    instanceId: number,
 | 
			
		||||
    userSystemId: string,
 | 
			
		||||
    currentBotId: string
 | 
			
		||||
  ): Promise<GuaribasUser> {
 | 
			
		||||
    let user = await GuaribasUser.findOne({
 | 
			
		||||
      where: {
 | 
			
		||||
        instanceId: instanceId,
 | 
			
		||||
        userSystemId: userSystemId
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    user.currentBotId = currentBotId;
 | 
			
		||||
    await user.save();
 | 
			
		||||
    return user;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async getUserFromPhone(
 | 
			
		||||
    phone: string
 | 
			
		||||
  ): Promise<GuaribasUser> {
 | 
			
		||||
    return await GuaribasUser.findOne({
 | 
			
		||||
      where: {
 | 
			
		||||
        phone: phone
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue