Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Add Facebook Handover Protocol #978

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4be0b65
:dancers: handle app roles event
ouadie-lahdioui Sep 2, 2017
0281ceb
:scream_cat: add lodash
ouadie-lahdioui Sep 2, 2017
8d66320
:nail_care: handle facebook_standby
ouadie-lahdioui Sep 2, 2017
f529e14
:feet: handle facebook_pass_thread_control
ouadie-lahdioui Sep 2, 2017
3703044
:eyes: handle facebook_take_thread_control
ouadie-lahdioui Sep 2, 2017
2c4fd3c
:see_no_evil: Remove lodash and add a default log message when standb…
ouadie-lahdioui Sep 2, 2017
96eba34
:running: Add handover_protocol and get_secondary_receivers_list method
ouadie-lahdioui Sep 2, 2017
5fc914e
:pouting_cat: add take_thread_control
ouadie-lahdioui Sep 3, 2017
2ca775c
:trollface: Add pass_thread_control
ouadie-lahdioui Sep 3, 2017
953f26b
:sheep: Add documentation
ouadie-lahdioui Sep 3, 2017
86cc29b
Merge branch 'master' into pr-handover
jonchurch Nov 7, 2017
abecf88
fix for messaging pipeline
jonchurch Nov 7, 2017
3dcd8cd
fix typo
jonchurch Nov 7, 2017
90aaa52
typo
jonchurch Nov 7, 2017
9b09e56
testing
jonchurch Nov 7, 2017
1bb30f9
typos
jonchurch Nov 7, 2017
e9f547c
remove debug console.log
jonchurch Nov 7, 2017
22d74f6
test pass_thread_control
jonchurch Nov 8, 2017
cfb012c
try stringify request_body
jonchurch Nov 8, 2017
137c7ab
log error in pass thread
jonchurch Nov 8, 2017
f094da5
add error handling to pass thread
jonchurch Nov 8, 2017
1587905
add debug to threadControl middleware
jonchurch Nov 8, 2017
ff466d3
try to fix handover api on bot
jonchurch Nov 8, 2017
32a2a93
typo
jonchurch Nov 8, 2017
8419f58
fix cb and json parsing for handover api calls
jonchurch Nov 8, 2017
09e7cf5
fix up secondary receivers api call
jonchurch Nov 8, 2017
c7e9daa
work on secondary_receivers api call
jonchurch Nov 8, 2017
fc1baa5
add fields to secondary receiver listing
jonchurch Nov 8, 2017
0e03369
remove fields param from list receiver
jonchurch Nov 8, 2017
d42f1f2
Merge branch 'master' into pr-handover-rebase
jonchurch Nov 11, 2017
afd2136
Merge pull request #1 from jonchurch/pr-handover-rebase
ouadie-lahdioui Nov 11, 2017
b8029ba
Resolve conflict with botkit v0.0.6
ouadie-lahdioui Dec 16, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions docs/readme-facebook.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Table of Contents
* [Silent and No Notifications](#silent-and-no-notifications)
* [Messenger code API](#messenger-code-api)
* [Attachment upload API](#attachment-upload-api)
* [Handover Protocol](#handover-protocol)
* [Running Botkit with an Express server](#use-botkit-for-facebook-messenger-with-an-express-web-server)

## Getting Started
Expand Down Expand Up @@ -85,6 +86,10 @@ Normal messages will be sent to your bot using the `message_received` event. In
| facebook_account_linking | a user has started the account linking
| facebook_optin | a user has clicked the [Send-to-Messenger plugin](https://developers.facebook.com/docs/messenger-platform/implementation#send_to_messenger_plugin)
| facebook_referral | a user has clicked on a [m.me URL with a referral param](https://developers.facebook.com/docs/messenger-platform/referral-params)
| facebook_app_roles | This callback will occur when a page admin changes the role of your application.
| standby | This callback will occur when a message has been sent to your page, but your application is not the current thread owner.
| facebook_receive_thread_control | This callback will occur when thread ownership for a user has been passed to your application.
| facebook_lose_thread_control | This callback will occur when thread ownership for a user has been taken away from your application.

All incoming events will contain the fields `user` and `channel`, both of which represent the Facebook user's ID, and a `timestamp` field.

Expand Down Expand Up @@ -570,6 +575,44 @@ var taggedMessage = {
bot.reply(message, taggedMessage);
```

## Handover Protocol

The Messenger Platform handover protocol enables two or more applications to collaborate on the Messenger Platform for a Page.

View the facebook [documentation](https://developers.facebook.com/docs/messenger-platform/handover-protocol) for more details.

### Secondary Receivers List

Allows the Primary Receiver app to retrieve the list of apps that are Secondary Receivers for a page. Only the app with the Primary Receiver role for the page may use this API.

- To retrieve the list of Secondary Receivers :
```javascript
controller.api.handover.get_secondary_receivers_list('id,name', function (result) {
// result.data = list of Secondary Receivers
});
```

### Take Thread Control

The Primary Receiver app can take control of a specific thread from a Secondary Receiver app :

- To thread control :
```javascript
controller.api.handover.take_thread_control('<RECIPIENT_PSID>', 'String to pass to pass to the secondary receiver', function (result) {
// result = {"success":true}
});
```

### Pass Thread Control

To pass the thread control from your app to another app :

- To pass thread control :
```javascript
controller.api.handover.pass_thread_control('<RECIPIENT_PSID>', '<TARGET_PSID>', 'String to pass to the secondary receiver app', function (result) {
// result = {"success":true}
});
```

## Use BotKit for Facebook Messenger with an Express web server
Instead of the web server generated with setupWebserver(), it is possible to use a different web server to receive webhooks, as well as serving web pages.
Expand Down
127 changes: 117 additions & 10 deletions lib/Facebook.js
Original file line number Diff line number Diff line change
Expand Up @@ -358,11 +358,18 @@ function Facebookbot(configuration) {
// we split these up into multiple message objects for ingestion
if (payload.entry) {
for (var e = 0; e < payload.entry.length; e++) {
if (payload.entry[e].messaging) {
for (var m = 0; m < payload.entry[e].messaging.length; m++) {
facebook_botkit.ingest(bot, payload.entry[e].messaging[m], res);
}
}
if (payload.entry[e].messaging) {
for (var m = 0; m < payload.entry[e].messaging.length; m++) {
facebook_botkit.ingest(bot, payload.entry[e].messaging[m], res);
}
}
if (payload.entry[e].standby) {
for (var s = 0; s < payload.entry[e].standby.length; s++) {
var standby_message = payload.entry[e].standby[s];
standby_message.standby = true;
facebook_botkit.ingest(bot, standby_message, res);
}
}
}
}

Expand Down Expand Up @@ -458,6 +465,26 @@ function Facebookbot(configuration) {

});

/* Facebook Handover Protocol categorize middleware */
facebook_botkit.middleware.categorize.use(function threadControl(bot, message, next) {

if (message.app_roles) {
message.type = 'facebook_app_roles';
}
if (message.standby) {
message.type = 'standby'
}
if (message.pass_thread_control) {
message.type = 'facebook_receive_thread_control'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't be the opposite?
message.pass_thread_control => facebook_lose_thread_control
message.take_thread_control => facebook_receive_thread_control

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass_thread_control callback will occur when thread ownership for a user has been passed to your application, So, in botkit y'll be able to catche that like that :

controller.hears('facebook_receive_thread_control', 'message_received', function(bot, message) { 
 /* your bot has received the thread ownership */
});

However, take_thread_control will occur when thread ownership for a user has been taken away from your application, to catche that :

controller.hears('facebook_lose_thread_control', 'message_received', function(bot, message) { 
 /* thread ownership for a user has been taken away */
});

@t-lopes WDYT ?

}
if (message.take_thread_control) {
message.type = 'facebook_lose_thread_control'
}

next();

});

facebook_botkit.on('webserver_up', function(webserver) {

// Validate that requests come from facebook, and abort on validation errors
Expand Down Expand Up @@ -816,8 +843,90 @@ function Facebookbot(configuration) {
};




var handover = {
get_secondary_receivers_list: function (fields, cb) {
request.get({
url: 'https://' + api_host + '/v2.6/me/secondary_receivers',
qs: {
fields: typeof(fields) == 'string' ? fields : fields.join(','),
access_token: configuration.access_token
},
json: true
}, function (err, res, body) {
if (err) {
facebook_botkit.log('Could not get secondary receivers list');
cb && cb(err);
} else {
if (body.error) {
facebook_botkit.log('ERROR in secondary receivers list: ', body.error.message);
cb && cb(body.error);
} else {
facebook_botkit.debug('Successfully getting secondary receivers list', body);
cb && cb(null, body);
}
}
});
},
take_thread_control: function (recipient, metadata, cb) {
var request_body = {
recipient: {
id: recipient
},
metadata: metadata
};
request.post({
url: 'https://' + api_host + '/v2.6/me/take_thread_control',
qs: {
access_token: configuration.access_token
},
body: request_body,
json: true
}, function (err, res, body) {
if (err) {
facebook_botkit.log('Could not take thread control');
cb && cb(err);
} else {
if (body.error) {
facebook_botkit.log('ERROR in take thread control API call: ', body.error.message);
cb && cb(body.error);
} else {
facebook_botkit.debug('Successfully taken thread control', body);
cb && cb(null, body);
}
}
});
},
pass_thread_control: function (recipient, target, metadata, cb) {
var request_body = {
recipient: {
id: recipient
},
target_app_id: target,
metadata: metadata
};
request.post({
url: 'https://' + api_host + '/v2.6/me/pass_thread_control',
qs: {
access_token: configuration.access_token
},
body: request_body,
json: true
}, function (err, res, body) {
if (err) {
facebook_botkit.log('Could not pass thread control');
cb && cb(err);
} else {
if (body.error) {
facebook_botkit.log('ERROR in pass thread control API call: ', body.error.message);
cb && cb(body.error);
} else {
facebook_botkit.debug('Successfully past thread control', body);
cb && cb(null, body);
}
}
});
}
};


facebook_botkit.api = {
Expand All @@ -827,12 +936,10 @@ function Facebookbot(configuration) {
'attachment_upload': attachment_upload_api,
'nlp': nlp,
'tags': tags,
'handover': handover
};





// Verifies the SHA1 signature of the raw request payload before bodyParser parses it
// Will abort parsing if signature is invalid, and pass a generic error to response
function verifyRequest(req, res, buf, encoding) {
Expand Down