node-facebook-messenger-api 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.jshintrc ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "node": true,
3
+ "esversion": 6
4
+ }
package/README.md ADDED
@@ -0,0 +1,180 @@
1
+ # Simple Node.js Facebook Messenger API #
2
+
3
+ [![bitHound Overall Score](https://www.bithound.io/github/perusworld/node-facebook-messenger-api/badges/score.svg)](https://www.bithound.io/github/perusworld/node-facebook-messenger-api)
4
+ [![bitHound Dependencies](https://www.bithound.io/github/perusworld/node-facebook-messenger-api/badges/dependencies.svg)](https://www.bithound.io/github/perusworld/node-facebook-messenger-api/master/dependencies/npm)
5
+ [![bitHound Code](https://www.bithound.io/github/perusworld/node-facebook-messenger-api/badges/code.svg)](https://www.bithound.io/github/perusworld/node-facebook-messenger-api)
6
+
7
+ Based on the [Messenger Platform Sample](https://github.com/fbsamples/messenger-platform-samples)
8
+
9
+ ## Install ##
10
+ ```bash
11
+ npm install github:perusworld/node-facebook-messenger-api --save
12
+ ```
13
+
14
+
15
+
16
+ ## Usage ##
17
+ See [Setup](https://developers.facebook.com/docs/messenger-platform/guides/setup) for more details about setting up the bot/page.
18
+
19
+ ## Detailed Walkthrough/Example (messenger bot on heroku) ##
20
+ [Quickly write a facebook messenger bot using nodejs and host it on heroku](https://steemit.com/chatbot/@perusworld/quickly-write-a-facebook-messenger-bot-using-nodejs-and-host-it-on-heroku)
21
+
22
+
23
+ ### Get User Profile - [User Profile API](https://developers.facebook.com/docs/messenger-platform/user-profile) ##
24
+ ```javascript
25
+ var messengerapi = require('node-facebook-messenger-api').messenger();
26
+ var messenger = new messengerapi.Messenger({
27
+ appId:"",
28
+ pageId: "",
29
+ analyticsLogLevel: "",
30
+ appSecret: "",
31
+ pageAccessToken: "",
32
+ validationToken: ""
33
+ });
34
+
35
+ var pageScopedUserID = "...";
36
+
37
+ messenger.getUserProfile(pageScopedUserID, (err, resp) => {
38
+ if (err) {
39
+ console.error(recipientId, "Sorry, looks like the backend is down :-(");
40
+ } else {
41
+ console.log(JSON.parse(resp));
42
+ }
43
+ });
44
+ ```
45
+
46
+ ### Send Generic Template Message - [Generic Template](https://developers.facebook.com/docs/messenger-platform/send-api-reference/generic-template) ###
47
+ ```javascript
48
+ messenger.sendGenericMessage(pageScopeUserID, [{
49
+ title: "Welcome to Peter\'s Hats",
50
+ image_url: "https://petersfancybrownhats.com/company_image.png",
51
+ subtitle: "We\'ve got the right hat for everyone.",
52
+ default_action: {
53
+ type: "web_url",
54
+ url: "https://peterssendreceiveapp.ngrok.io/view?item=103",
55
+ messenger_extensions: true,
56
+ webview_height_ratio: "tall",
57
+ fallback_url: "https://peterssendreceiveapp.ngrok.io/"
58
+ },
59
+ buttons: [{
60
+ type: "web_url",
61
+ url: "https://petersfancybrownhats.com",
62
+ title: "View Website"
63
+ }, {
64
+ type: "postback",
65
+ title: "Start Chatting",
66
+ payload: "DEVELOPER_DEFINED_PAYLOAD"
67
+ }]
68
+ }]);
69
+ ```
70
+
71
+ ### Using Webhook Handler to receive Facebook Messenger Events - [Webhook Reference](https://developers.facebook.com/docs/messenger-platform/webhook-reference) ###
72
+ The example folder contains a sample app
73
+ ```bash
74
+ npm install
75
+ cd example
76
+ export MESSENGER_ANALYTICS_LOG_LEVEL = "2";
77
+ export MESSENGER_APP_ID = "--yours--";
78
+ export MESSENGER_PAGE_ID = "--yours--";
79
+ export MESSENGER_APP_SECRET="--yours--"
80
+ export MESSENGER_VALIDATION_TOKEN="--yours--"
81
+ export MESSENGER_PAGE_ACCESS_TOKEN="--yours--"
82
+ node server
83
+ ```
84
+ Or use this in your existing code
85
+ ```javascript
86
+ const
87
+ express = require('express');
88
+
89
+ var ignores = ['/some-url/to-ignore'];
90
+ var verifySignature = true;
91
+
92
+ var messengerapi = require('node-facebook-messenger-api').messenger();
93
+ var messenger = new messengerapi.Messenger({});
94
+ var webhookHandler = require('node-facebook-messenger-api').webhookHandler()(messenger, {
95
+ receivedAuthentication : function(event) {
96
+ console.log('receivedAuthentication', event);
97
+ },
98
+ handleMessage : function(event) {
99
+ console.log('handleMessage', event);
100
+ messenger.sendTextMessage(event.sender.id, JSON.stringify(event));
101
+ },
102
+ receivedDeliveryConfirmation : function(event) {
103
+ console.log('receivedDeliveryConfirmation', event);
104
+ },
105
+ receivedPostback : function(event) {
106
+ console.log('receivedPostback', event);
107
+ },
108
+ receivedMessageRead : function(event) {
109
+ console.log('receivedMessageRead', event);
110
+ },
111
+ doLinking : function(event) {
112
+ console.log('doLinking', event);
113
+ },
114
+ doUnlinking : function(event) {
115
+ console.log('doUnlinking', event);
116
+ }
117
+ },verifySignature, ignores, express.Router());
118
+
119
+ var app = express();
120
+ app.set('port', process.env.PORT || 3000);
121
+ app.use(express.static('public'));
122
+
123
+ app.use('/fb', webhookHandler);
124
+ app.listen(app.get('port'), function () {
125
+ console.log('Node app is running in http mode on port', app.get('port'));
126
+ });
127
+ ```
128
+ #### Analytics Events ####
129
+ You can now send analytics events through the following API (See [App Events with Bots for Messenger - Logging Custom Events](https://developers.facebook.com/docs/app-events/bots-for-messenger#logging-custom-events) and [App Events API](https://developers.facebook.com/docs/marketing-api/app-event-api/v2.9) for more details about the event types)
130
+
131
+ For performace reasons if you would like to throttle the events that you would like to send/track, you can use the env variable
132
+ ```bash
133
+ export MESSENGER_ANALYTICS_LOG_LEVEL = "2";
134
+ ```
135
+ to control the log levels. Set that to
136
+
137
+ Level | Value | Description |
138
+ --- | --- | --- |
139
+ None | 99 | Don't send any analytics events |
140
+ Critical | 2 | Send only critical analytics events |
141
+ Verbose | 1 | Send all analytics events |
142
+
143
+ The asynchronous callback from the *analyticsEvent* call would be either
144
+ ```json
145
+ {
146
+ "success": true
147
+ }
148
+ ```
149
+ if the event was successfully accepted or
150
+ ```json
151
+ {
152
+ "skip": true
153
+ }
154
+ ```
155
+ if the event was skipped due lower log levels
156
+
157
+ - Custom Event
158
+ ```javascript
159
+ messenger.analyticsEvent(messengerapi.ANALYTICS_LEVEL_VERBOSE, event.sender.id, () => {
160
+ return messenger.buildAnalyticsEvent("fb_mobile_verbose_event");
161
+ }, (err, resp) => {
162
+ messenger.sendTextMessage(event.sender.id, JSON.stringify(err ? err : resp));
163
+ });
164
+ ```
165
+
166
+ - Standard Purchase Event
167
+ ```javascript
168
+ messenger.analyticsEvent(messengerapi.ANALYTICS_LEVEL_CRITICAL, event.sender.id, () => {
169
+ return messenger.buildAnalyticsEvent("fb_mobile_purchase", { _valueToSum: 9.99, fb_currency: 'USD' });
170
+ }, (err, resp) => {
171
+ messenger.sendTextMessage(event.sender.id, JSON.stringify(err ? err : resp));
172
+ });
173
+ ```
174
+ - Standard Add Cart Event Using quickAnalytics
175
+ ```javascript
176
+ messenger.quickAnalytics(messengerapi.ANALYTICS_LEVEL_CRITICAL, event.sender.id, "fb_mobile_add_to_cart", {
177
+ fb_content_type: 'blah blah blah', fb_content_id: '123456789', _valueToSum: 9.99, fb_currency: 'USD'
178
+ });
179
+ ```
180
+
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+
3
+ const async = require('async'),
4
+ crypto = require('crypto'),
5
+ error = require('debug')('error'),
6
+ debug = require('debug')('fb-accountlink');
7
+
8
+ function AccountLinkHandler(config) {
9
+ this.conf = config;
10
+ if (!this.conf.userIdField) {
11
+ this.conf.userIdField = 'userid';
12
+ }
13
+ }
14
+
15
+ AccountLinkHandler.prototype.getFbLinking = function (authCode, callback) {
16
+ this.conf.linkModel.getById(authCode, callback)
17
+ };
18
+
19
+ AccountLinkHandler.prototype.removeFbLinking = function (linking, callback) {
20
+ this.conf.linkModel.delete({
21
+ _id: linking._id
22
+ }, callback);
23
+ };
24
+
25
+ AccountLinkHandler.prototype.getFbUser = function (linking, callback) {
26
+ this.conf.userModel.getById(linking[this.conf.userIdField], callback);
27
+ };
28
+
29
+ AccountLinkHandler.prototype.addFbUser = function (linking, authCode, handler, callback) {
30
+ var obj = {
31
+ _id: linking[this.conf.userIdField],
32
+ authCode: authCode
33
+ };
34
+ if (handler) {
35
+ handler.updateFbUser(obj, linking);
36
+ }
37
+ this.conf.userModel.add(obj, callback);
38
+ };
39
+
40
+ AccountLinkHandler.prototype.updateFbUser = function (user, authCode, callback) {
41
+ user.authCode = authCode;
42
+ this.conf.userModel.update(user, callback);
43
+ };
44
+
45
+ AccountLinkHandler.prototype.removeFbUser = function (mapping, callback) {
46
+ this.conf.userModel.delete({
47
+ _id: mapping[this.conf.userIdField]
48
+ }, callback)
49
+ };
50
+
51
+ AccountLinkHandler.prototype.getFbUserMapping = function (senderID, callback) {
52
+ this.conf.mappingModel.getById(senderID, callback);
53
+ };
54
+
55
+ AccountLinkHandler.prototype.addFbUserMapping = function (senderID, recipientID, linking, status, callback) {
56
+ var obj = {
57
+ _id: senderID,
58
+ pageId: recipientID,
59
+ status: status
60
+ };
61
+ obj[this.conf.userIdField] = linking[this.conf.userIdField];
62
+ this.conf.mappingModel.add(obj, callback)
63
+ };
64
+
65
+ AccountLinkHandler.prototype.updateFbUserMapping = function (mapping, recipientID, linking, status, callback) {
66
+ mapping.status = status;
67
+ mapping.pageId = recipientID;
68
+ this.conf.mappingModel.update(mapping, callback)
69
+ };
70
+
71
+ AccountLinkHandler.prototype.updateFbUserMappingStatus = function (mapping, status, callback) {
72
+ mapping.status = status;
73
+ this.conf.mappingModel.update(mapping, callback)
74
+ };
75
+
76
+ //TODO: Transation commit/rollback
77
+ AccountLinkHandler.prototype.doLinking = function (event, callback, handler) {
78
+ var senderID = event.sender.id;
79
+ var recipientID = event.recipient.id;
80
+ var status = event.account_linking.status;
81
+ var authCode = event.account_linking.authorization_code;
82
+
83
+ var ctx = {};
84
+ var ptr = this;
85
+ async.waterfall([
86
+ function (callback) {
87
+ ptr.getFbLinking(authCode, callback)
88
+ },
89
+ function (linking, callback) {
90
+ if (null == linking) {
91
+ callback("No linking found", null);
92
+ } else {
93
+ ctx.linking = linking;
94
+ ptr.getFbUser(ctx.linking, callback);
95
+ }
96
+ },
97
+ function (user, callback) {
98
+ if (null == user) {
99
+ ptr.addFbUser(ctx.linking, authCode, handler, callback);
100
+ } else {
101
+ ptr.updateFbUser(user, authCode, callback)
102
+ }
103
+ },
104
+ function (user, callback) {
105
+ if (null == user) {
106
+ callback("No user found", null);
107
+ } else {
108
+ ctx.user = user;
109
+ ptr.getFbUserMapping(senderID, callback);
110
+ }
111
+ },
112
+ function (mapping, callback) {
113
+ if (null == mapping) {
114
+ ptr.addFbUserMapping(senderID, recipientID, ctx.linking, status, callback)
115
+ } else {
116
+ ptr.updateFbUserMapping(mapping, recipientID, ctx.linking, status, callback)
117
+ }
118
+ },
119
+ function (mapping, callback) {
120
+ if (null == mapping) {
121
+ callback("No mapping found", null);
122
+ } else {
123
+ ptr.removeFbLinking(ctx.linking, callback);
124
+ }
125
+ },
126
+ ], function (err, deleted) {
127
+ if (err || !deleted) {
128
+ error('failed to process account linking for', senderID, recipientID, authCode, err);
129
+ callback('failed to process account linking', null);
130
+ } else {
131
+ debug('successfully setup account linking for', senderID, recipientID, authCode);
132
+ callback(null, senderID);
133
+ }
134
+ });
135
+ };
136
+
137
+ AccountLinkHandler.prototype.doUnlinking = function (event, callback) {
138
+ var senderID = event.sender.id;
139
+ var recipientID = event.recipient.id;
140
+ var status = event.account_linking.status;
141
+
142
+ var ptr = this;
143
+ var ctx = {};
144
+ async.waterfall([
145
+ function (callback) {
146
+ ptr.getFbUserMapping(senderID, callback);
147
+ },
148
+ function (mapping, callback) {
149
+ if (null == mapping) {
150
+ callback({
151
+ mapping: false
152
+ }, null);
153
+ } else {
154
+ ctx.mapping = mapping;
155
+ ptr.updateFbUserMappingStatus(mapping, status, callback);
156
+ }
157
+ },
158
+ function (mapping, callback) {
159
+ if (null == mapping) {
160
+ callback("No mapping found", null);
161
+ } else {
162
+ ptr.removeFbUser(ctx.mapping, callback);
163
+ }
164
+ }
165
+ ], function (err, deleted) {
166
+ if (err || !deleted) {
167
+ error('failed to process account unlinking for', senderID, recipientID, err);
168
+ callback('failed to process account unlinking', null);
169
+ } else {
170
+ debug('successfully unlinked account for', senderID, recipientID);
171
+ callback(null, senderID);
172
+ }
173
+ });
174
+ };
175
+
176
+ module.exports.AccountLinkHandler = AccountLinkHandler;
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <head>
3
+ <title>Example Facebook Messenger WebHook Handler</title>
4
+ </head>
5
+ <body>
6
+ <h1>Example Facebook Messenger WebHook Handler</h1>
7
+ </body>
8
+ </html>
@@ -0,0 +1,87 @@
1
+ 'use strict';
2
+
3
+ const
4
+ express = require('express');
5
+
6
+ var ignores = ['/some-url/to-ignore'];
7
+ var verifySignature = true;
8
+
9
+ var messengerapi = require('../node-facebook-messenger-api').messenger();
10
+ var messenger = new messengerapi.Messenger({});
11
+ var webhookHandler = require('../node-facebook-messenger-api').webhookHandler()(messenger, {
12
+ receivedAuthentication: function (event) {
13
+ console.log('receivedAuthentication', event);
14
+ },
15
+ handleMessage: function (event) {
16
+ console.log('handleMessage', event);
17
+ if (event.message && event.message.text) {
18
+ switch (event.message.text) {
19
+ case 'profile':
20
+ messenger.getUserProfile(event.sender.id, (err, resp) => {
21
+ messenger.sendTextMessage(event.sender.id, JSON.stringify(err ? err : resp));
22
+ });
23
+ break;
24
+ case 'anverb':
25
+ messenger.analyticsEvent(messengerapi.ANALYTICS_LEVEL_VERBOSE, event.sender.id, () => {
26
+ return messenger.buildAnalyticsEvent("fb_mobile_verbose_event");
27
+ }, (err, resp) => {
28
+ messenger.sendTextMessage(event.sender.id, JSON.stringify(err ? err : resp));
29
+ });
30
+ break;
31
+ case 'ancrit':
32
+ messenger.analyticsEvent(messengerapi.ANALYTICS_LEVEL_CRITICAL, event.sender.id, () => {
33
+ return messenger.buildAnalyticsEvent("fb_mobile_critical_event");
34
+ }, (err, resp) => {
35
+ messenger.sendTextMessage(event.sender.id, JSON.stringify(err ? err : resp));
36
+ });
37
+ break;
38
+ case 'anusd':
39
+ messenger.analyticsEvent(messengerapi.ANALYTICS_LEVEL_CRITICAL, event.sender.id, () => {
40
+ return messenger.buildAnalyticsEvent("fb_mobile_purchase", { _valueToSum: 9.99, fb_currency: 'USD' });
41
+ }, (err, resp) => {
42
+ messenger.sendTextMessage(event.sender.id, JSON.stringify(err ? err : resp));
43
+ });
44
+ break;
45
+ case 'anquick':
46
+ messenger.quickAnalytics(messengerapi.ANALYTICS_LEVEL_CRITICAL, event.sender.id, "quick_analytics");
47
+ break;
48
+ case 'anitem':
49
+ messenger.quickAnalytics(messengerapi.ANALYTICS_LEVEL_CRITICAL, event.sender.id, "fb_mobile_add_to_cart", {
50
+ fb_content_type: 'blah blah blah', fb_content_id: '123456789', _valueToSum: 9.99, fb_currency: 'USD'
51
+ });
52
+ break;
53
+ default:
54
+ messenger.sendTextMessage(event.sender.id, JSON.stringify(event));
55
+ break;
56
+ }
57
+ } else {
58
+ messenger.sendTextMessage(event.sender.id, JSON.stringify(event));
59
+ }
60
+ },
61
+ receivedDeliveryConfirmation: function (event) {
62
+ console.log('receivedDeliveryConfirmation', event);
63
+ },
64
+ receivedPostback: function (event) {
65
+ console.log('receivedPostback', event);
66
+ },
67
+ receivedMessageRead: function (event) {
68
+ console.log('receivedMessageRead', event);
69
+ },
70
+ doLinking: function (event) {
71
+ console.log('doLinking', event);
72
+ },
73
+ doUnlinking: function (event) {
74
+ console.log('doUnlinking', event);
75
+ }
76
+ }, verifySignature, ignores, express.Router());
77
+
78
+ var app = express();
79
+ app.set('port', process.env.PORT || 3000);
80
+ app.use(express.static('public'));
81
+
82
+ app.use('/fb', webhookHandler);
83
+ app.listen(app.get('port'), function () {
84
+ console.log('Node app is running in http mode on port', app.get('port'));
85
+ });
86
+
87
+