1+ const _ = require ( 'lodash' ) ;
12const fs = require ( 'fs' ) ;
23const path = require ( 'path' ) ;
3- const lodash = require ( 'lodash' ) ;
44const restify = require ( 'restify' ) ;
55const rp = require ( 'request-promise' ) ;
66
@@ -158,7 +158,7 @@ class BotStack {
158158 return async function ( req , res , next ) { // eslint-disable-line func-names, no-unused-vars
159159 res . end ( ) ;
160160 /* eslint-disable no-restricted-syntax, no-continue, no-await-in-loop */
161- for ( const msg of lodash . get ( req . body , 'messages' , [ ] ) ) {
161+ for ( const msg of _ . get ( req . body , 'messages' , [ ] ) ) {
162162 // message schema
163163 // https://docs.smooch.io/rest/?javascript#schema44
164164 if ( msg . role !== 'appUser' ) {
@@ -168,8 +168,8 @@ class BotStack {
168168 module : 'botstack:smoochWebhook' ,
169169 message : msg
170170 } ) ;
171- const text = lodash . get ( msg , 'text' ) ;
172- const authorID = lodash . get ( msg , 'authorId' ) ;
171+ const text = _ . get ( msg , 'text' ) ;
172+ const authorID = _ . get ( msg , 'authorId' ) ;
173173 let apiAiResponse = null ;
174174 let result = null ;
175175 try {
@@ -224,12 +224,20 @@ class BotStack {
224224 return async function ( req , res , next ) { // eslint-disable-line no-unused-vars
225225 res . end ( ) ;
226226 await self . _syncFbMessageToBackChat ( req ) ; // eslint-disable-line no-underscore-dangle
227- const entries = req . body . entry ;
227+ const entries = _ . get ( req , ' body.entry' , [ ] ) ;
228228 for ( const entry of entries ) {
229- const messages = entry . messaging ;
229+ const messages = _ . get ( entry , ' messaging' , [ ] ) ;
230230 for ( const message of messages ) {
231- const senderID = message . sender . id ;
232- const isEcho = ! ! lodash . get ( message , 'message.is_echo' ) ;
231+ // The sender object is not included for messaging_optins events triggered by the checkbox plugin.
232+ // https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messaging_optins
233+ let isMessagingOptins = false ;
234+ let recipientUserRef = null ;
235+ const senderID = _ . get ( message , 'sender.id' ) ;
236+ if ( ( ! senderID ) && ( _ . has ( message , 'optin.user_ref' ) ) ) {
237+ isMessagingOptins = true ;
238+ recipientUserRef = _ . get ( message , 'optin.user_ref' ) ;
239+ }
240+ const isEcho = ! ! _ . get ( message , 'message.is_echo' ) ;
233241 if ( isEcho ) {
234242 continue ; // eslint-disable-line no-continue
235243 }
@@ -239,17 +247,18 @@ class BotStack {
239247 } ) ;
240248 const isNewSession = await sessionStore . checkExists ( senderID ) ;
241249 const isPostbackMessage = ! ! message . postback ;
242- const isQuickReplyPayload = ! ! lodash . get ( message , 'message.quick_reply.payload' ) ;
243- const isTextMessage = ! ! ( ! isQuickReplyPayload && lodash . get ( message , 'message.text' ) ) ;
244- const isGeoLocationMessage = ! ! lodash . get ( message , 'message.attachments[0].payload.coordinates' ) ;
250+ const isQuickReplyPayload = ! ! _ . get ( message , 'message.quick_reply.payload' ) ;
251+ const isTextMessage = ! ! ( ! isQuickReplyPayload && _ . get ( message , 'message.text' ) ) ;
252+ const isGeoLocationMessage = ! ! _ . get ( message , 'message.attachments[0].payload.coordinates' ) ;
245253 log . debug ( 'Detect kind of message' , {
246254 module : 'botstack:webhookPost' ,
247255 senderID,
248256 isNewSession,
249257 isPostbackMessage,
250258 isQuickReplyPayload,
251259 isTextMessage,
252- isGeoLocationMessage
260+ isGeoLocationMessage,
261+ isMessagingOptins
253262 } ) ;
254263 await sessionStore . set ( senderID ) ;
255264 if ( isQuickReplyPayload ) {
@@ -268,6 +277,8 @@ class BotStack {
268277 } else {
269278 await self . postbackMessage ( message , senderID ) ;
270279 }
280+ } else if ( isMessagingOptins ) {
281+ await self . messagingOptins ( message , recipientUserRef ) ;
271282 } else {
272283 await self . fallback ( message , senderID ) ;
273284 }
@@ -346,7 +357,7 @@ class BotStack {
346357 }
347358
348359 async quickReplyPayload ( message , senderID ) {
349- const text = lodash . get ( message , 'message.quick_reply.payload' ) ;
360+ const text = _ . get ( message , 'message.quick_reply.payload' ) ;
350361 this . log . debug ( 'Process quick reply payload' , {
351362 module : 'botstack: quickReplyPayload' ,
352363 senderId : senderID ,
@@ -389,6 +400,55 @@ class BotStack {
389400 } ) ;
390401 }
391402
403+ async messagingOptins ( message , recipientUserRef ) {
404+ // on first request we have:
405+ // {
406+ // "recipient":{
407+ // "id":"<PAGE_ID>"
408+ // },
409+ // "timestamp":<UNIX_TIMESTAMP>,
410+ // "optin":{
411+ // "ref":"<PASS_THROUGH_PARAM>",
412+ // "user_ref":"<UNIQUE_REF_PARAM>"
413+ // }
414+ // }
415+
416+ // next send message to user using user_ref param
417+ // curl -X POST -H "Content-Type: application/json" -d '{
418+ // "recipient": {
419+ // "user_ref":"<UNIQUE_REF_PARAM>"
420+ // },
421+ // "message": {
422+ // "text":"hello, world!"
423+ // }
424+ // }' "https://graph.facebook.com/v2.6/me/messages?access_token=<PAGE_ACCESS_TOKEN>"
425+
426+ // after got result:
427+ // {
428+ // "message_id": "mid.1456970487936:c34767dfe57ee6e339"
429+ // }
430+
431+ // let's save this user_ref for future use...
432+ //
433+ this . log . debug ( 'Process message opt-in payload' , {
434+ module : 'botstack:messagingOptins' ,
435+ recipientUserRef
436+ } ) ;
437+ if ( BotStackCheck ( 'messagingOptins' ) ) {
438+ BotStackEvents . emit ( 'messagingOptins' , {
439+ recipientUserRef,
440+ message
441+ } ) ;
442+ return ;
443+ }
444+ this . log . debug ( 'Sending to Dialogflow' , {
445+ module : 'botstack:messagingOptins' ,
446+ recipientUserRef,
447+ message
448+ } ) ;
449+ await fb . reply ( fb . textMessage ( 'Hello!' ) , recipientUserRef , { params : { use_user_ref : true } } ) ;
450+ }
451+
392452 startServer ( ) {
393453 const port = process . env . PORT || 1337 ;
394454 const self = this ;
0 commit comments