Created
July 5, 2018 08:14
-
-
Save evalphobia/bd7265217351031ab19a3419e37eaadb to your computer and use it in GitHub Desktop.
To fetch Google Calendar event. (Running on Firebase Functions for Dialogflow)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Action { | |
constructor(req, res){ | |
this.request = req; | |
this.response = res; | |
this.requestSource = (req.body.originalRequest) ? req.body.originalRequest.source : undefined; | |
this.app = new DialogflowApp({req, res}); | |
console.log('api-v2') | |
} | |
sendResponse(text) { | |
const googleAssistantRequest = 'google'; | |
if (this.requestSource === googleAssistantRequest) { | |
this._sendGoogleResponse(text) | |
return | |
} | |
this._sendResponse(text) | |
} | |
_sendResponse(text) { | |
if (typeof text === 'string') { | |
let responseJson = {}; | |
responseJson.speech = text; // spoken response | |
responseJson.displayText = text; // displayed response | |
this.response.json(responseJson); // Send response to Dialogflow | |
return | |
} | |
let responseJson = {}; | |
responseJson.speech = text.speech || text.displayText; | |
responseJson.displayText = text.displayText || text.speech; | |
this.response.json(responseJson); // Send response to Dialogflow | |
} | |
_sendGoogleResponse(text) { | |
if (typeof text === 'string') { | |
this.app.ask(text); | |
return | |
} | |
// If speech or displayText is defined use it to respond | |
let googleResponse = this.app.buildRichResponse().addSimpleResponse({ | |
speech: text.speech || text.displayText, | |
displayText: text.displayText || text.speech | |
}); | |
this.app.ask(googleResponse); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const google = require('googleapis'); | |
// CalendarAction for fetch calendar event from Google Calendar. | |
class CalendarAction extends Action { | |
get CLIENT_ID(){ return '000000000000-foobar.apps.googleusercontent.com' } | |
get CLIENT_SECRET(){ return '<secret>' } | |
get REDIRECT_URL(){ return 'https://example.firebaseapp.com/__/auth/handler' } | |
get REFRESH_TOKEN(){ return '<secret>' } | |
constructor(req, res){ | |
super(req, res) | |
const oauth2Client = new google.auth.OAuth2(this.CLIENT_ID, this.CLIENT_SECRET, this.REDIRECT_URL); | |
oauth2Client.credentials = { | |
refresh_token: this.REFRESH_TOKEN, | |
}; | |
this.oauth2Client = oauth2Client; | |
this.locale = 'ja-JP' | |
this.timeZone = 'Asia/Tokyo' | |
} | |
doWhere(params) { | |
const fn = (err, resp) => {this.listCalendar(err, resp)} | |
this._do(params, fn) | |
} | |
_do(params, callback) { | |
this.oauth2Client.refreshAccessToken( (err, resp) => { | |
if (err) { | |
console.log('actionCalendar: token error=', err); | |
this.sendResponse('actionCalendar: token error'); | |
return | |
} | |
const calendar = google.calendar('v3'); | |
const requestParams = this._createParams(params) | |
calendar.events.list(requestParams, (err, resp) => { callback(err, resp) }); | |
}) | |
} | |
_createParams(params) { | |
let email = params['people-mail'] || params['email'] | |
return { | |
auth: this.oauth2Client, | |
calendarId: email, | |
timeMin: (new Date()).toISOString(), | |
maxResults: 10, | |
singleEvents: true, | |
orderBy: 'startTime' | |
} | |
} | |
listCalendar(err, resp) { | |
console.log('exec listCalendar') | |
if (err) { | |
console.log('actionCalendar: list error=', err); | |
this.sendResponse('actionCalendar: list error'); | |
return | |
} | |
const result = this._getCalendarEvent(resp.items) | |
console.log('result=', result) | |
if (!result) { | |
this.sendResponse('今はその辺にいそうです'); | |
return | |
} | |
this.sendResponse(this._createMessage(result)); | |
} | |
_getCalendarEvent(items) { | |
let now = new Date().getTime(); | |
let result = { | |
currentList: [], | |
current: undefined, | |
next: undefined, | |
prev: undefined, | |
hasEvent: false, | |
allDay: undefined, | |
hasAllDay: false, | |
} | |
for (var i = 0, max = items.length; i < max; i++) { | |
let item = items[i] | |
// 未承認 | |
if (item.status != 'confirmed') {continue;} | |
if (!item.start) {continue;} | |
console.log(`%%% summary=${item.summary}, start=${this._getLocalTime(item.start.dateTime)}, end=${this._getLocalTime(item.end.dateTime)} %%%`) | |
if (item.start.date && !item.start.dateTime) { | |
let startTime = new Date(item.start.date).getTime() | |
let endTime = new Date(item.end.date).getTime() | |
if (now < startTime) continue; | |
if (now > endTime) continue; | |
result.allDay = item; | |
result.hasAllDay = true | |
continue; | |
} | |
let startTime = new Date(item.start.dateTime).getTime() | |
let endTime = new Date(item.end.dateTime).getTime() | |
if (now > startTime && now < endTime) { | |
result.currentList.push(item) | |
result.hasEvent = true | |
continue | |
} | |
// 30分以内に終了したイベントを取得 | |
if (now > startTime && now < (endTime + 60*30*1000)) { | |
result.prev = item | |
result.hasEvent = true | |
continue; | |
} | |
// 30分以内に始まるイベントを取得 | |
if (now < endTime && now > (startTime - 60*30*1000)) { | |
result.next = item | |
result.hasEvent = true | |
continue; | |
} | |
} | |
// 重複イベントの処理 | |
if (result.currentList.length == 1) { | |
result.current = result.currentList[0] | |
} else if (result.currentList.length > 1) { | |
result.prev = result.currentList[result.currentList.length - 2] | |
result.current = result.currentList[result.currentList.length - 1] | |
} | |
if (result.current || result.next || result.prev || result.allDay) { | |
return result | |
} | |
return false | |
} | |
_createMessage(result) { | |
var msg = []; | |
if (result.prev) { | |
msg.push(this._createSentence('前', result.prev)) | |
} | |
if (result.current) { | |
msg.push(this._createSentence('今', result.current)) | |
} | |
if (result.next) { | |
msg.push(this._createSentence('次', result.next)) | |
} | |
// 終日イベントは、(1)「通常イベントが無い場合」、または(2)「全日イベントに場所がある場合」のみ使用 | |
if (result.hasAllDay) { | |
if (result.allDay.location || !result.hasEvent) { | |
msg.push(this._createSentence('終日', result.allDay)) | |
} | |
} | |
return msg.join("\n") | |
} | |
_createSentence(title, item) { | |
if (!item.location) { | |
item.location = 'どこか' | |
} | |
return `【${title}】 | ${item.location}で${item.summary}してそうです (${this._getLocalTime(item.start.dateTime)} - ${this._getLocalTime(item.end.dateTime)})` | |
} | |
_getLocalTime(str) { | |
return new Date(str).toLocaleTimeString(this.locale, {timeZone: this.timeZone}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Golang Slack RTM Bot ver: