Невозможно сделать вызовы APEX Webservice из Dialogflow Intent Handler - PullRequest
0 голосов
/ 20 марта 2020

У меня есть приложение Express (размещенное на Heroku), которое я использую для обработки намерений из Dialogflow и выполнения вызовов в классы веб-сервиса APEX REST (для получения данных из Salesforce), а затем отображаю результаты в Google Assistant.

Для аутентификации я пытаюсь реализовать OAuth, и поэтому я создал Connected App на Salesforce. В Google Actions в разделе «Связывание аккаунтов» я упомянул «URL-адрес авторизации» как Express URL-адрес приложения (что-то вроде https://testBot.herokuapp.com/authorization) и «Идентификатор клиента, выданный вашими действиями в Google» в качестве ключа потребителя от Salesforce. Подключенное приложение и, наконец, «Секрет клиента» в качестве секрета пользователя Salesforce Connected App. Кроме того, мой токен URL похож на https://testBot.herokuapp.com/token.

На Express Я создал маршруты, сначала обработав запрос на авторизацию (чтобы получить код авторизации), а затем во-вторых, на маршруте обратного вызова (это URL-адрес обратного вызова в приложении Salesforce Connected), как упоминалось в Реализация привязки учетной записи OAuth Я перенаправлен на redirect_uri (в форме https://oauth-redirect.googleusercontent.com/r/MY_PROJECT_ID) с код авторизации и состояние в качестве параметров. Вот как выглядит URI https://oauth-redirect.googleusercontent.com/r/MY_PROJECT_ID?code=AUTHORIZATION_CODE&state=STATE_STRING. Теперь на 3-м маршруте (https://testBot.herokuapp.com/token) лог c записывается для обмена кодом авторизации на токен доступа и токен refre sh. Обратите внимание, что конечная точка обмена токенами отвечает на запросы POST.

Теперь, согласно официальной документации, Google хранит токен доступа и токен refre sh для пользователя. Итак, это означает, что объект Conversation или conv должен содержать значения токена доступа, однако, когда я пытаюсь получить доступ к нему и затем вызывать его в веб-сервис APEX, я мог видеть, что conv.user.accessToken дает неопределенное значение, и, следовательно, вызов также не удалось ( ошибка: INVALID_SESSION_ID: сеанс истек или недействителен ) даже после успешной аутентификации.

У меня вопрос, почему я не получаю токен доступа от CONV и если это ожидается (я неправильно читаю документацию), как я должен получить токен доступа?

Вот код express:

const express = require('express');
const bodyParser = require('body-parser');
const jsforce = require('jsforce');
const { dialogflow } = require('actions-on-google');
const {
  SimpleResponse,
  BasicCard,
  SignIn,
  Image,
  Suggestions,
  Button
} = require('actions-on-google');

var options;
var timeOut = 3600;

var port = process.env.PORT || 3000;
var conn = {};

const expApp = express().use(bodyParser.json());
expApp.use(bodyParser.urlencoded());
//app instance
const app = dialogflow({
  debug: true
});

const oauth2 = new jsforce.OAuth2({
    clientId: process.env.SALESFORCE_CONSUMER_KEY,
    clientSecret: process.env.SALESFORCE_CONSUMER_SECRET,
    redirectUri: 'https://testbot.herokuapp.com/callback'
});

expApp.get('/authorize', function(req, res) {
    var queryParams = req.query;
    console.log('this is the first request: '+req);
    res.redirect(oauth2.getAuthorizationUrl({ state: queryParams.state }));

});

expApp.get('/callback', function(req,res) {
    var queryParams = req.query;
    console.log('Request came for access callback');
    console.log('Query params in callback uri is ', req.query);
    let redirectUri = `${process.env.GOOGLE_REDIRECT_URI}?code=${queryParams.code}&state=${queryParams.state}`;
    console.log('Google redirecturi is ', redirectUri);
    res.redirect(redirectUri);
});


expApp.post('/token', function(req, res) {
    console.log('Request came for accesstoken');

    console.log('query params are-->', req.body);
    console.log('req query-->', req.query);

    res.setHeader('Content-Type', 'application/json');
    if (req.body.client_id != process.env.SALESFORCE_CONSUMER_KEY) {
        console.log('Invalid Client ID');
        return res.status(400).send('Invalid Client ID');
    }
    if (req.body.client_secret != process.env.SALESFORCE_CONSUMER_SECRET) {
        console.log('Invalid Client Ksecret');
        return res.status(400).send('Invalid Client ID');
    }
    if (req.body.grant_type) {
        if (req.body.grant_type == 'authorization_code') {
            console.log('Fetching token from salesforce');
            oauth2.requestToken(req.body.code, (err, tokenResponse) => {
                if (err) {
                    console.log(err.message);
                    return res.status(400).json({ "error": "invalid_grant" });
                }
                console.log('Token respons: ',tokenResponse);

                var googleToken = {
                    token_type: tokenResponse.token_type,
                    access_token: tokenResponse.access_token,
                    refresh_token: tokenResponse.refresh_token,
                    expires_in: timeOut
                };
                console.log('Token response for auth code', googleToken);

                res.status(200).json(googleToken);

            });
        } 
        else if (req.body.grant_type == 'refresh_token') {
            console.log('Fetching refresh token from salesforce');
            oauth2.refreshToken(req.body.refresh_token, (err, tokenResponse) => {
                if (err) {
                    console.log(err.message);
                    return res.status(400).json({ "error": "invalid_grant" });
                }
                console.log('Token response in refresh token: ',tokenResponse);
                var googleToken = { token_type: tokenResponse.token_type, access_token: tokenResponse.access_token, expires_in: timeOut };

                console.log('Token response for auth code', googleToken);

                res.status(200).json(googleToken);
            });
        }
    } else {
        res.send('Invalid parameter');
    }
});

var createTask = function(oppName,taskSubject,taskPriority,conFName,conn){
    return new Promise((resolve,reject)=>{
        conn.apex.get("/createTask?oppName="+oppName+"&taskSubject="+taskSubject+"&taskPriority="+taskPriority+"&contactFirstName="+conFName,function(err, res){
            if (err) {
                console.log('error is --> ',err);
                reject(err);
            }
            else{
                console.log('res is --> ',res);
                resolve(res);
            }
        });
    });
};

app.intent('Default Welcome Intent', (conv) => {

    console.log('Request came for account link flow start');    
        if(!conv.user.accessToken){
            conv.ask(new SignIn());
        }
        else{
            conv.ask('You are already signed in ');
        }

});

app.intent('Get SignIn Info', (conv, params, signin) => {    
    console.log('Sign in info Intent');    
    console.log('Sign in content-->',signin);       
    if (signin.status === 'OK') {         
        conv.ask('Hola, thanks for signing in! What do you want to do next?')       ;
    } 
    else {         
        conv.ask('Something went wrong in the sign in process');       
    }     
}); 

app.intent('Create Task on Opportunity', (conv, {oppName,taskSubject,taskPriority,contactFirstName} ) => {
    console.log('conv: ',conv);
    //this logs undefined
    console.log('Access token from conv inside intent: ',conv.user.accessToken);
    const opName = conv.parameters['oppName'];
    const tskSbj = conv.parameters['taskSubject'];
    const tskPr = conv.parameters['taskPriority'];
    const conFName = conv.parameters['contactFirstName'];
    console.log('Instance URL as stored in heroku process variable: ',process.env.INSTANCE_URL);
    conn = new jsforce.Connection({
      instanceUrl : process.env.INSTANCE_URL,
      accessToken : conv.user.accessToken
    });
    return createTask(opName,tskSbj,tskPr,conFName,conn).then((resp) => {
        conv.ask(new SimpleResponse({
            speech:resp,
            text:resp,
        }));
    });
});

expApp.get('/', function (req, res) {
    res.send('Hello World!');
});
expApp.listen(port, function () {
    expApp.post('/fulfillment', app);
    console.log('Example app listening on port !');
});

1 Ответ

0 голосов
/ 21 марта 2020

Итак, во время регистрации разговора. Пользователь понял, что conv.user.access.token правильный, а не conv.user.accessToken. Следовательно, теперь экземпляр подключения будет выглядеть так:

conn = new jsforce.Connection({
  instanceUrl : process.env.INSTANCE_URL,
  accessToken : conv.user.acces.token
});

Теперь запрос на получение веб-службы apex действительно отправляет ожидаемый ответ!

...