Я пытаюсь создать чат-бот помощника Google Calendar с выполнением Dialogflow, размещенным в GCP, с использованием клиентских библиотек node.js, dialogflow-fillment и googleapis. У меня проблема с созданием метода аутентификации с использованием идентификатора клиента OAuth. Идея состоит в том, что когда пользователь добавляет бота в Google Chat, бот должен приветствовать его / ее и запрашивать у пользователя разрешение на определенные области (в данном случае для создания событий в Google Calendar). Что мне сейчас удалось сделать, так это отправить пользователю ссылку, по которой он увидит области, утвердит их, и будет сгенерирован код, но затем этот код должен быть передан обратно в функцию, чтобы получить токен и установить учетные данные.
ссылка отправлена пользователю
сгенерированный код
код, переданный пользователю
Есть ли способ автоматически получить этот код и аутентифицировать пользователя?
Мой код выглядит так (он немного запутан из-за всех проведенных мною тестов):
const {google} = require('googleapis');
const {WebhookClient} = require('dialogflow-fulfillment');
const credentials = {"installed":{"client_id":"618408396856-vrd3it4s4nk19tlo7qrnbb51a9f8bq6t.apps.googleusercontent.com","project_id":"pg-xc-n-app-577847","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"d_qDDlFVBtllcotgn2xvc00N","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}};
//setting authentication details
const SCOPES = [
'https://www.googleapis.com/auth/calendar.events',
'https://www.googleapis.com/auth/spreadsheets'
];
const {client_secret, client_id, redirect_uris} = credentials.installed;
const authentication = new google.auth.OAuth2(
client_id,
client_secret,
redirect_uris[0]
);
const url = authentication.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
});
const calendarId = 'primary';
const calendar = google.calendar('v3');
process.env.DEBUG = 'dialogflow:*'; // enables lib debugging statements
exports.meetingRoomFulfillment = function meetingRoomFulfillment(req, res) {
const agent = new WebhookClient({ request: req, response: res });
console.log(`Intent ${((req.body.queryResult || {}).intent || {}).displayName}`);
console.log(`Dialogflow Request body`, JSON.stringify(req.body));
if (req.body.queryResult === undefined || req.body.queryResult.intent === undefined || req.body.queryResult.intent.displayName === undefined) {
console.log(`Missing intent so cancelling fulfillment`);
res.send({});
return;
}
function authenticate(agent){
agent.add(`To authenticate this app please visit the following url: ${url}`);
}
function authenticationCode(agent){
const code = agent.parameters.authenticationCode;
console.log('The code: ' + code);
authentication.getToken(code, (err, token) => {
if (err) return console.error('Error retrieving access token', err);
authentication.setCredentials(token);
retrievedToken = token;
console.log(retrievedToken);
});
agent.add('Successfully authenticated!');
}
function makeAppointment (agent) {
const dateTimeStart = new Date(agent.parameters.date.split('T')[0] + 'T' + agent.parameters.time.split('T')[1]);
const dateTimeEnd = new Date(new Date(dateTimeStart).setHours(dateTimeStart.getHours() + 1));
const appointmentTimeString = dateTimeStart.toLocaleString();
const eventDescription = agent.parameters.text;
// Check the availibility of the time, and make an appointment if there is time on the calendar
return createCalendarEvent(dateTimeStart, dateTimeEnd, eventDescription).then(() => {
agent.add(`Ok, let me see if we can fit you in. ${appointmentTimeString} is fine!. I am creating an event called: ${eventDescription}`);
}).catch(() => {
agent.add(`I'm sorry, there are no slots available for this period.`);
});
}
let intentMap = new Map();
intentMap.set('authenticate', authenticate);
intentMap.set('authentication code', authenticationCode);
intentMap.set('Make Appointment', makeAppointment);
agent.handleRequest(intentMap);
}
function createCalendarEvent (dateTimeStart, dateTimeEnd, eventDescription) {
return new Promise((resolve, reject) => {
calendar.events.list({
auth: authentication,
calendarId: calendarId,
timeMin: dateTimeStart.toISOString(),
timeMax: dateTimeEnd.toISOString()
}, (err, calendarResponse) => {
// Check if there is a event already in the calendar
if (err || calendarResponse.data.items.length > 0) {
reject(err || new Error('Requested time conflicts with another appointment'));
console.log(err);
} else {
// Create event for the requested time period
calendar.events.insert({
auth: authentication,
calendarId: calendarId,
resource: {
summary: eventDescription,
start: {dateTime: dateTimeStart},
end: {dateTime: dateTimeEnd}
}
}, (err, event) => {
err ? reject(err) : resolve(event);
console.log(err);
}
);
}
});
});
}