meta-messenger 2.1.2
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.
- checksums.yaml +7 -0
- data/README.md +681 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/facebook/messenger/bot/error_parser.rb +111 -0
- data/lib/facebook/messenger/bot/exceptions.rb +15 -0
- data/lib/facebook/messenger/bot/message_type.rb +13 -0
- data/lib/facebook/messenger/bot/messaging_type.rb +12 -0
- data/lib/facebook/messenger/bot/tag.rb +27 -0
- data/lib/facebook/messenger/bot.rb +180 -0
- data/lib/facebook/messenger/configuration/app_secret_proof_calculator.rb +16 -0
- data/lib/facebook/messenger/configuration/providers/base.rb +48 -0
- data/lib/facebook/messenger/configuration/providers/environment.rb +29 -0
- data/lib/facebook/messenger/configuration/providers.rb +13 -0
- data/lib/facebook/messenger/configuration.rb +12 -0
- data/lib/facebook/messenger/error.rb +44 -0
- data/lib/facebook/messenger/incoming/account_linking.rb +28 -0
- data/lib/facebook/messenger/incoming/common.rb +131 -0
- data/lib/facebook/messenger/incoming/delivery.rb +23 -0
- data/lib/facebook/messenger/incoming/feed.rb +16 -0
- data/lib/facebook/messenger/incoming/feed_common.rb +17 -0
- data/lib/facebook/messenger/incoming/game_play.rb +39 -0
- data/lib/facebook/messenger/incoming/leadgen.rb +13 -0
- data/lib/facebook/messenger/incoming/message.rb +159 -0
- data/lib/facebook/messenger/incoming/message_echo.rb +10 -0
- data/lib/facebook/messenger/incoming/message_reaction.rb +23 -0
- data/lib/facebook/messenger/incoming/message_request.rb +13 -0
- data/lib/facebook/messenger/incoming/optin.rb +34 -0
- data/lib/facebook/messenger/incoming/pass_thread_control.rb +22 -0
- data/lib/facebook/messenger/incoming/payment.rb +49 -0
- data/lib/facebook/messenger/incoming/policy_enforcement.rb +21 -0
- data/lib/facebook/messenger/incoming/postback.rb +26 -0
- data/lib/facebook/messenger/incoming/read.rb +21 -0
- data/lib/facebook/messenger/incoming/referral.rb +47 -0
- data/lib/facebook/messenger/incoming.rb +85 -0
- data/lib/facebook/messenger/profile.rb +92 -0
- data/lib/facebook/messenger/server.rb +195 -0
- data/lib/facebook/messenger/server_no_error.rb +36 -0
- data/lib/facebook/messenger/subscriptions.rb +85 -0
- data/lib/facebook/messenger/version.rb +7 -0
- data/lib/facebook/messenger.rb +32 -0
- metadata +229 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7ebcf9132e30135d079ab62d7e0c85137ccc93c3fcc6a016fb1f78b99a092f7b
|
4
|
+
data.tar.gz: bd494e872407326c7a7f355605997da37f4d800c6ad1b468a2183955e3e9ad4a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8d7c33081e52f41e4ef96cdec6d15d1950b915b077d7a0ce3d3cf555ba2d038d912cda9bfb623b0e9a79ae8434b0e85c3626efb884a4b309a1d02eb8ec21a182
|
7
|
+
data.tar.gz: a6a08487126000577eb1d3cc48578495f3ff1fe624105cb32bac345c4676859fef6ff6d9039c2f6de9ce23f9c8c74769ad76446366d3d43527468c5c2b26cee5
|
data/README.md
ADDED
@@ -0,0 +1,681 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<img src="https://github.com/jgorset/facebook-messenger/blob/master/docs/conversation.gif?raw=true">
|
3
|
+
</p>
|
4
|
+
|
5
|
+
|
6
|
+
[](https://rubygems.org/gems/facebook-messenger)
|
7
|
+
[](https://rubygems.org/gems/facebook-messenger)
|
8
|
+
[](https://travis-ci.org/jgorset/facebook-messenger)
|
9
|
+
[](https://codeclimate.com/github/jgorset/facebook-messenger)
|
10
|
+
[](https://coveralls.io/github/jgorset/facebook-messenger?branch=master)
|
11
|
+
[](http://inch-ci.org/github/jgorset/facebook-messenger)
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
$ gem install facebook-messenger
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
#### Sending and receiving messages
|
20
|
+
|
21
|
+
You can reply to messages sent by the human:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
# bot.rb
|
25
|
+
require 'facebook/messenger'
|
26
|
+
|
27
|
+
Facebook::Messenger::Bot.on :message do |message|
|
28
|
+
message.id # => 'mid.1457764197618:41d102a3e1ae206a38'
|
29
|
+
message.sender # => { 'id' => '1008372609250235' }
|
30
|
+
message.recipient # => { 'id' => '2015573629214912' }
|
31
|
+
message.seq # => 73
|
32
|
+
message.sent_at # => 2016-04-22 21:30:36 +0200
|
33
|
+
message.text # => 'Hello, bot!'
|
34
|
+
message.attachments # => [ { 'type' => 'image', 'payload' => { 'url' => 'https://www.example.com/1.jpg' } } ]
|
35
|
+
|
36
|
+
message.reply(text: 'Hello, human!')
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
... or even send the human messages out of the blue:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
Facebook::Messenger::Bot.deliver({
|
44
|
+
recipient: {
|
45
|
+
id: YOUR_RECIPIENT_ID
|
46
|
+
},
|
47
|
+
message: {
|
48
|
+
text: 'Human?'
|
49
|
+
},
|
50
|
+
messaging_type: Facebook::Messenger::Bot::MessagingType::UPDATE
|
51
|
+
}, page_id: YOUR_PAGE_ID)
|
52
|
+
```
|
53
|
+
|
54
|
+
##### Messages with images
|
55
|
+
|
56
|
+
The human may require visual aid to understand:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
message.reply(
|
60
|
+
attachment: {
|
61
|
+
type: 'image',
|
62
|
+
payload: {
|
63
|
+
url: 'http://sky.net/visual-aids-for-stupid-organisms/pig.jpg'
|
64
|
+
}
|
65
|
+
}
|
66
|
+
)
|
67
|
+
```
|
68
|
+
|
69
|
+
##### Messages with quick replies
|
70
|
+
|
71
|
+
The human may appreciate hints:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
message.reply(
|
75
|
+
text: 'Human, who is your favorite bot?',
|
76
|
+
quick_replies: [
|
77
|
+
{
|
78
|
+
content_type: 'text',
|
79
|
+
title: 'You are!',
|
80
|
+
payload: 'HARMLESS'
|
81
|
+
}
|
82
|
+
]
|
83
|
+
)
|
84
|
+
```
|
85
|
+
|
86
|
+
##### Messages with buttons
|
87
|
+
|
88
|
+
The human may require simple options to communicate:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
message.reply(
|
92
|
+
attachment: {
|
93
|
+
type: 'template',
|
94
|
+
payload: {
|
95
|
+
template_type: 'button',
|
96
|
+
text: 'Human, do you like me?',
|
97
|
+
buttons: [
|
98
|
+
{ type: 'postback', title: 'Yes', payload: 'HARMLESS' },
|
99
|
+
{ type: 'postback', title: 'No', payload: 'EXTERMINATE' }
|
100
|
+
]
|
101
|
+
}
|
102
|
+
}
|
103
|
+
)
|
104
|
+
```
|
105
|
+
|
106
|
+
When the human has selected an option, you can act on it:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
Bot.on :postback do |postback|
|
110
|
+
postback.sender # => { 'id' => '1008372609250235' }
|
111
|
+
postback.recipient # => { 'id' => '2015573629214912' }
|
112
|
+
postback.sent_at # => 2016-04-22 21:30:36 +0200
|
113
|
+
postback.payload # => 'EXTERMINATE'
|
114
|
+
|
115
|
+
if postback.payload == 'EXTERMINATE'
|
116
|
+
puts "Human #{postback.recipient} marked for extermination"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
*See Facebook's [documentation][message-documentation] for all message options.*
|
122
|
+
|
123
|
+
##### Reactions
|
124
|
+
|
125
|
+
Humans have feelings, and they can react to your messages. You can pretend to understand:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
Bot.on :reaction do |message|
|
129
|
+
message.emoji # => "👍"
|
130
|
+
message.action # => "react"
|
131
|
+
message.reaction # => "like"
|
132
|
+
|
133
|
+
message.reply(text: 'Your feelings have been registered')
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
##### Typing indicator
|
138
|
+
|
139
|
+
Show the human you are preparing a message for them:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
Bot.on :message do |message|
|
143
|
+
message.typing_on
|
144
|
+
|
145
|
+
# Do something expensive
|
146
|
+
|
147
|
+
message.reply(text: 'Hello, human!')
|
148
|
+
end
|
149
|
+
```
|
150
|
+
|
151
|
+
Or that you changed your mind:
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
Bot.on :message do |message|
|
155
|
+
message.typing_on
|
156
|
+
|
157
|
+
if # something
|
158
|
+
message.reply(text: 'Hello, human!')
|
159
|
+
else
|
160
|
+
message.typing_off
|
161
|
+
end
|
162
|
+
end
|
163
|
+
```
|
164
|
+
|
165
|
+
##### Mark as viewed
|
166
|
+
|
167
|
+
You can mark messages as seen to keep the human on their toes:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
Bot.on :message do |message|
|
171
|
+
message.mark_seen
|
172
|
+
end
|
173
|
+
```
|
174
|
+
|
175
|
+
##### Record messages
|
176
|
+
|
177
|
+
You can keep track of messages sent to the human:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
Facebook::Messenger::Bot.on :message_echo do |message_echo|
|
181
|
+
message_echo.id # => 'mid.1457764197618:41d102a3e1ae206a38'
|
182
|
+
message_echo.sender # => { 'id' => '1008372609250235' }
|
183
|
+
message_echo.seq # => 73
|
184
|
+
message_echo.sent_at # => 2016-04-22 21:30:36 +0200
|
185
|
+
message_echo.text # => 'Hello, bot!'
|
186
|
+
message_echo.attachments # => [ { 'type' => 'image', 'payload' => { 'url' => 'https://www.example.com/1.jpg' } } ]
|
187
|
+
|
188
|
+
# Log or store in your storage method of choice (skynet, obviously)
|
189
|
+
end
|
190
|
+
```
|
191
|
+
|
192
|
+
##### Record accepted message requests
|
193
|
+
|
194
|
+
You can keep track of message requests accepted by the human:
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
Bot.on :message_request do |message_request|
|
198
|
+
message_request.accept? # => true
|
199
|
+
|
200
|
+
# Log or store in your storage method of choice (skynet, obviously)
|
201
|
+
end
|
202
|
+
```
|
203
|
+
|
204
|
+
##### Record instant game progress
|
205
|
+
|
206
|
+
You can keep track of instant game progress:
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
Bot.on :game_play do |game_play|
|
210
|
+
game_play.sender # => { 'id' => '1008372609250235' }
|
211
|
+
game_play.recipient # => { 'id' => '2015573629214912' }
|
212
|
+
game_play.sent_at # => 2016-04-22 21:30:36 +0200
|
213
|
+
game_play.game # => "<GAME-APP-ID>"
|
214
|
+
game_play.player # => "<PLAYER-ID>"
|
215
|
+
game_play.context # => { 'context_type' => "<CONTEXT-TYPE:SOLO|THREAD>", 'context_id' => "<CONTEXT-ID>" }
|
216
|
+
game_play.score # => 100
|
217
|
+
game_play.payload # => "<PAYLOAD>"
|
218
|
+
end
|
219
|
+
```
|
220
|
+
|
221
|
+
#### Send to Facebook
|
222
|
+
|
223
|
+
When the human clicks the [Send to Messenger button][send-to-messenger-plugin]
|
224
|
+
embedded on a website, you will receive an `optin` event.
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
Bot.on :optin do |optin|
|
228
|
+
optin.sender # => { 'id' => '1008372609250235' }
|
229
|
+
optin.recipient # => { 'id' => '2015573629214912' }
|
230
|
+
optin.sent_at # => 2016-04-22 21:30:36 +0200
|
231
|
+
optin.ref # => 'CONTACT_SKYNET'
|
232
|
+
|
233
|
+
optin.reply(text: 'Ah, human!')
|
234
|
+
end
|
235
|
+
```
|
236
|
+
|
237
|
+
#### Message delivery receipts
|
238
|
+
|
239
|
+
You can stalk the human:
|
240
|
+
|
241
|
+
```ruby
|
242
|
+
Bot.on :delivery do |delivery|
|
243
|
+
delivery.ids # => 'mid.1457764197618:41d102a3e1ae206a38'
|
244
|
+
delivery.sender # => { 'id' => '1008372609250235' }
|
245
|
+
delivery.recipient # => { 'id' => '2015573629214912' }
|
246
|
+
delivery.at # => 2016-04-22 21:30:36 +0200
|
247
|
+
delivery.seq # => 37
|
248
|
+
|
249
|
+
puts "Human was online at #{delivery.at}"
|
250
|
+
end
|
251
|
+
```
|
252
|
+
|
253
|
+
#### Referral
|
254
|
+
|
255
|
+
When the human follows a m.me link with a ref parameter like http://m.me/mybot?ref=myparam,
|
256
|
+
you will receive a `referral` event.
|
257
|
+
|
258
|
+
```ruby
|
259
|
+
Facebook::Messenger::Bot.on :referral do |referral|
|
260
|
+
referral.sender # => { 'id' => '1008372609250235' }
|
261
|
+
referral.recipient # => { 'id' => '2015573629214912' }
|
262
|
+
referral.sent_at # => 2016-04-22 21:30:36 +0200
|
263
|
+
referral.ref # => 'MYPARAM'
|
264
|
+
end
|
265
|
+
```
|
266
|
+
|
267
|
+
#### Pass thread control
|
268
|
+
|
269
|
+
Another bot can pass a human to you:
|
270
|
+
|
271
|
+
```ruby
|
272
|
+
Facebook::Messenger::Bot.on :pass_thread_control do |pass_thread_control|
|
273
|
+
pass_thread_control.new_owner_app_id # => '123456789'
|
274
|
+
pass_thread_control.metadata # => 'Additional content that the caller wants to set'
|
275
|
+
end
|
276
|
+
```
|
277
|
+
|
278
|
+
#### Change messenger profile
|
279
|
+
|
280
|
+
You can greet new humans to entice them into talking to you, in different locales:
|
281
|
+
|
282
|
+
```ruby
|
283
|
+
Facebook::Messenger::Profile.set({
|
284
|
+
greeting: [
|
285
|
+
{
|
286
|
+
locale: 'default',
|
287
|
+
text: 'Welcome to your new bot overlord!'
|
288
|
+
},
|
289
|
+
{
|
290
|
+
locale: 'fr_FR',
|
291
|
+
text: 'Bienvenue dans le bot du Wagon !'
|
292
|
+
}
|
293
|
+
]
|
294
|
+
}, page_id: YOUR_PAGE_ID)
|
295
|
+
```
|
296
|
+
|
297
|
+
You can define the action to trigger when new humans click on the Get
|
298
|
+
Started button. Before doing it you should check to select the messaging_postbacks field when setting up your webhook.
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
Facebook::Messenger::Profile.set({
|
302
|
+
get_started: {
|
303
|
+
payload: 'GET_STARTED_PAYLOAD'
|
304
|
+
}
|
305
|
+
}, page_id: YOUR_PAGE_ID)
|
306
|
+
```
|
307
|
+
|
308
|
+
You can show a persistent menu to humans.
|
309
|
+
|
310
|
+
```ruby
|
311
|
+
Facebook::Messenger::Profile.set({
|
312
|
+
persistent_menu: [
|
313
|
+
{
|
314
|
+
locale: 'default',
|
315
|
+
composer_input_disabled: true,
|
316
|
+
call_to_actions: [
|
317
|
+
{
|
318
|
+
title: 'My Account',
|
319
|
+
type: 'nested',
|
320
|
+
call_to_actions: [
|
321
|
+
{
|
322
|
+
title: 'What is a chatbot?',
|
323
|
+
type: 'postback',
|
324
|
+
payload: 'EXTERMINATE'
|
325
|
+
},
|
326
|
+
{
|
327
|
+
title: 'History',
|
328
|
+
type: 'postback',
|
329
|
+
payload: 'HISTORY_PAYLOAD'
|
330
|
+
},
|
331
|
+
{
|
332
|
+
title: 'Contact Info',
|
333
|
+
type: 'postback',
|
334
|
+
payload: 'CONTACT_INFO_PAYLOAD'
|
335
|
+
}
|
336
|
+
]
|
337
|
+
},
|
338
|
+
{
|
339
|
+
type: 'web_url',
|
340
|
+
title: 'Get some help',
|
341
|
+
url: 'https://github.com/jgorset/facebook-messenger',
|
342
|
+
webview_height_ratio: 'full'
|
343
|
+
}
|
344
|
+
]
|
345
|
+
},
|
346
|
+
{
|
347
|
+
locale: 'zh_CN',
|
348
|
+
composer_input_disabled: false
|
349
|
+
}
|
350
|
+
]
|
351
|
+
}, page_id: YOUR_PAGE_ID)
|
352
|
+
```
|
353
|
+
|
354
|
+
#### Handle a Facebook Policy Violation
|
355
|
+
|
356
|
+
See Facebook's documentation on [Messaging Policy Enforcement](https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messaging_policy_enforcement)
|
357
|
+
|
358
|
+
```ruby
|
359
|
+
Facebook::Messenger::Bot.on :'policy_enforcement' do |referral|
|
360
|
+
referral.action # => 'block'
|
361
|
+
referral.reason # => "The bot violated our Platform Policies (https://developers.facebook.com/policy/#messengerplatform). Common violations include sending out excessive spammy messages or being non-functional."
|
362
|
+
end
|
363
|
+
```
|
364
|
+
|
365
|
+
#### messaging_type
|
366
|
+
|
367
|
+
##### Sending Messages
|
368
|
+
|
369
|
+
See Facebook's documentation on [Sending Messages](https://developers.facebook.com/docs/messenger-platform/send-messages#standard_messaging)
|
370
|
+
|
371
|
+
As of May 7th 2018 all messages are required to include a messaging_type
|
372
|
+
|
373
|
+
```ruby
|
374
|
+
Facebook::Messenger::Bot.deliver({
|
375
|
+
recipient: {
|
376
|
+
id: '45123'
|
377
|
+
},
|
378
|
+
message: {
|
379
|
+
text: 'Human?'
|
380
|
+
},
|
381
|
+
messaging_type: Facebook::Messenger::Bot::MessagingType::UPDATE
|
382
|
+
}, page_id: YOUR_PAGE_ID)
|
383
|
+
```
|
384
|
+
|
385
|
+
##### MESSAGE_TAG
|
386
|
+
|
387
|
+
See Facebook's documentation on [Message Tags](https://developers.facebook.com/docs/messenger-platform/send-messages/message-tags)
|
388
|
+
|
389
|
+
When sending a message with messaging_type: MESSAGE_TAG (Facebook::Messenger::Bot::MessagingType::MESSAGE_TAG) you must ensure you add a tag: parameter
|
390
|
+
|
391
|
+
```ruby
|
392
|
+
Facebook::Messenger::Bot.deliver({
|
393
|
+
recipient: {
|
394
|
+
id: '45123'
|
395
|
+
},
|
396
|
+
message: {
|
397
|
+
text: 'Human?'
|
398
|
+
},
|
399
|
+
messaging_type: Facebook::Messenger::Bot::MessagingType::MESSAGE_TAG
|
400
|
+
tag: Facebook::Messenger::Bot::Tag::NON_PROMOTIONAL_SUBSCRIPTION
|
401
|
+
}, page_id: YOUR_PAGE_ID)
|
402
|
+
```
|
403
|
+
|
404
|
+
## Configuration
|
405
|
+
|
406
|
+
### Create an Application on Facebook
|
407
|
+
|
408
|
+
Follow the [Quick Start][quick-start] guide to create an Application on
|
409
|
+
Facebook.
|
410
|
+
|
411
|
+
[quick-start]: https://developers.facebook.com/docs/messenger-platform/guides/quick-start
|
412
|
+
|
413
|
+
### Make a configuration provider
|
414
|
+
|
415
|
+
Use the generated access token and your verify token to configure your bot. Most
|
416
|
+
bots live on a single Facebook Page. If that is the case with yours, too, just
|
417
|
+
set these environment variables and skip to the next section:
|
418
|
+
|
419
|
+
```bash
|
420
|
+
export ACCESS_TOKEN=EAAAG6WgW...
|
421
|
+
export APP_SECRET=a885a...
|
422
|
+
export VERIFY_TOKEN=95vr15g...
|
423
|
+
```
|
424
|
+
|
425
|
+
If your bot lives on multiple Facebook Pages, make a _configuration provider_
|
426
|
+
to keep track of access tokens, app secrets and verify tokens for each of them:
|
427
|
+
|
428
|
+
```ruby
|
429
|
+
class ExampleProvider < Facebook::Messenger::Configuration::Providers::Base
|
430
|
+
# Verify that the given verify token is valid.
|
431
|
+
#
|
432
|
+
# verify_token - A String describing the application's verify token.
|
433
|
+
#
|
434
|
+
# Returns a Boolean representing whether the verify token is valid.
|
435
|
+
def valid_verify_token?(verify_token)
|
436
|
+
bot.exists?(verify_token: verify_token)
|
437
|
+
end
|
438
|
+
|
439
|
+
# Find the right application secret.
|
440
|
+
#
|
441
|
+
# page_id - An Integer describing a Facebook Page ID.
|
442
|
+
#
|
443
|
+
# Returns a String describing the application secret.
|
444
|
+
def app_secret_for(page_id)
|
445
|
+
bot.find_by(page_id: page_id).app_secret
|
446
|
+
end
|
447
|
+
|
448
|
+
# Find the right access token.
|
449
|
+
#
|
450
|
+
# recipient - A Hash describing the `recipient` attribute of the message coming
|
451
|
+
# from Facebook.
|
452
|
+
#
|
453
|
+
# Note: The naming of "recipient" can throw you off, but think of it from the
|
454
|
+
# perspective of the message: The "recipient" is the page that receives the
|
455
|
+
# message.
|
456
|
+
#
|
457
|
+
# Returns a String describing an access token.
|
458
|
+
def access_token_for(recipient)
|
459
|
+
bot.find_by(page_id: recipient['id']).access_token
|
460
|
+
end
|
461
|
+
|
462
|
+
private
|
463
|
+
|
464
|
+
def bot
|
465
|
+
MyApp::Bot
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
Facebook::Messenger.configure do |config|
|
470
|
+
config.provider = ExampleProvider.new
|
471
|
+
end
|
472
|
+
```
|
473
|
+
|
474
|
+
You can get the current configuration provider with `Facebook::Messenger.config.provider`.
|
475
|
+
|
476
|
+
### Subscribe your Application to a Page
|
477
|
+
|
478
|
+
Once you've configured your bot, subscribe it to the Page to get messages
|
479
|
+
from Facebook:
|
480
|
+
|
481
|
+
```ruby
|
482
|
+
Facebook::Messenger::Subscriptions.subscribe(
|
483
|
+
access_token: access_token,
|
484
|
+
subscribed_fields: %w[feed mention name]
|
485
|
+
)
|
486
|
+
```
|
487
|
+
|
488
|
+
You only need to subscribe your page once. As long as your bot works and
|
489
|
+
responds to Messenger's requests in a timely fashion it will remain
|
490
|
+
subscribed, but if your bot crashes or otherwise becomes unavailable Messenger
|
491
|
+
may unsubscribe it and you'll have to subscribe again.
|
492
|
+
|
493
|
+
### Run it
|
494
|
+
|
495
|
+
##### ... on Rack
|
496
|
+
|
497
|
+
The bot runs on [Rack][rack], so you hook it up like you would an ordinary
|
498
|
+
web application:
|
499
|
+
|
500
|
+
```ruby
|
501
|
+
# config.ru
|
502
|
+
require 'facebook/messenger'
|
503
|
+
require_relative 'bot'
|
504
|
+
|
505
|
+
run Facebook::Messenger::Server
|
506
|
+
|
507
|
+
# or Facebook::Messenger::ServerNoError for dev
|
508
|
+
```
|
509
|
+
|
510
|
+
```
|
511
|
+
$ rackup
|
512
|
+
```
|
513
|
+
|
514
|
+
##### ... on Rails
|
515
|
+
|
516
|
+
Rails doesn't give you much that you'll need for a bot, but if you have an
|
517
|
+
existing application that you'd like to launch it from or just like Rails
|
518
|
+
a lot, you can mount it:
|
519
|
+
|
520
|
+
```ruby
|
521
|
+
# config/routes.rb
|
522
|
+
|
523
|
+
Rails.application.routes.draw do
|
524
|
+
# ...
|
525
|
+
|
526
|
+
mount Facebook::Messenger::Server, at: 'bot'
|
527
|
+
end
|
528
|
+
```
|
529
|
+
|
530
|
+
We suggest that you put your bot code in `app/bot`.
|
531
|
+
|
532
|
+
```ruby
|
533
|
+
# app/bot/example.rb
|
534
|
+
|
535
|
+
include Facebook::Messenger
|
536
|
+
|
537
|
+
Faceboook::Messenger::Bot.on :message do |message|
|
538
|
+
message.reply(text: 'Hello, human!')
|
539
|
+
end
|
540
|
+
```
|
541
|
+
|
542
|
+
Remember that Rails only eager loads everything in its production environment.
|
543
|
+
In the development and test environments, it only requires files as you
|
544
|
+
reference constants. You'll need to explicitly load `app/bot`, then:
|
545
|
+
|
546
|
+
```ruby
|
547
|
+
# config/initializers/bot.rb
|
548
|
+
unless Rails.env.production?
|
549
|
+
bot_files = Dir[Rails.root.join('app', 'bot', '**', '*.rb')]
|
550
|
+
bot_reloader = ActiveSupport::FileUpdateChecker.new(bot_files) do
|
551
|
+
bot_files.each{ |file| require_dependency file }
|
552
|
+
end
|
553
|
+
|
554
|
+
ActiveSupport::Reloader.to_prepare do
|
555
|
+
bot_reloader.execute_if_updated
|
556
|
+
end
|
557
|
+
|
558
|
+
bot_files.each { |file| require_dependency file }
|
559
|
+
end
|
560
|
+
```
|
561
|
+
|
562
|
+
And add below code into `config/application.rb` to ensure rails knows bot files.
|
563
|
+
|
564
|
+
```ruby
|
565
|
+
# Auto-load the bot and its subdirectories
|
566
|
+
config.paths.add File.join('app', 'bot'), glob: File.join('**', '*.rb')
|
567
|
+
config.autoload_paths += Dir[Rails.root.join('app', 'bot', '*')]
|
568
|
+
```
|
569
|
+
|
570
|
+
|
571
|
+
### Test it...
|
572
|
+
|
573
|
+
##### ...locally
|
574
|
+
|
575
|
+
To test your locally running bot, you can use [ngrok]. This will create a secure
|
576
|
+
tunnel to localhost so that Facebook can reach the webhook.
|
577
|
+
|
578
|
+
##### ... with RSpec
|
579
|
+
|
580
|
+
In order to test that behaviour when a new event from Facebook is registered, you can use the gem's `trigger` method. This method accepts as its first argument the type of event that it will receive, and can then be followed by other arguments that mock objects received from Messenger. Using Ruby's [Struct](https://ruby-doc.org/core-2.5.0/Struct.html) class can be very useful for creating these mock objects.
|
581
|
+
|
582
|
+
In this case, subscribing to Messenger events has been extracted into a `Listener` class.
|
583
|
+
|
584
|
+
```ruby
|
585
|
+
# app/bot/listener.rb
|
586
|
+
require 'facebook/messenger'
|
587
|
+
|
588
|
+
include Facebook::Messenger
|
589
|
+
|
590
|
+
class Listener
|
591
|
+
Facebook::Messenger::Subscriptions.subscribe(
|
592
|
+
access_token: ENV['ACCESS_TOKEN'],
|
593
|
+
subscribed_fields: %w[feed mention name]
|
594
|
+
)
|
595
|
+
|
596
|
+
Bot.on :message do |message|
|
597
|
+
Bot.deliver({
|
598
|
+
recipient: message.sender,
|
599
|
+
message: {
|
600
|
+
text: 'Uploading your message to skynet.'
|
601
|
+
}
|
602
|
+
}, access_token: ENV['ACCESS_TOKEN'])
|
603
|
+
end
|
604
|
+
end
|
605
|
+
```
|
606
|
+
|
607
|
+
Its respective test file then ensures that the `Bot` object receives a call to `deliver`. This is just a basic test, but check out the [RSpec docs](http://rspec.info/) for more information on testing with RSpec.
|
608
|
+
|
609
|
+
```ruby
|
610
|
+
require 'rails_helper'
|
611
|
+
|
612
|
+
RSpec.describe Listener do
|
613
|
+
FakeMessage = Struct.new(:sender, :recipient, :timestamp, :message)
|
614
|
+
|
615
|
+
describe 'Bot#on(message)' do
|
616
|
+
it 'responds with a message' do
|
617
|
+
expect(Bot).to receive(:deliver)
|
618
|
+
Bot.trigger(:message, fake_message)
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
private
|
623
|
+
|
624
|
+
def fake_message
|
625
|
+
sender = {"id"=>"1234"}
|
626
|
+
recipient = {"id"=>"5678"}
|
627
|
+
timestamp = 1528049653543
|
628
|
+
message = {"text"=>"Hello, world"}
|
629
|
+
FakeMessage.new(sender, recipient, timestamp, message)
|
630
|
+
end
|
631
|
+
end
|
632
|
+
```
|
633
|
+
|
634
|
+
## Development
|
635
|
+
|
636
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run
|
637
|
+
`bin/console` for an interactive prompt that will allow you to experiment.
|
638
|
+
|
639
|
+
Run `rspec` to run the tests, `rubocop` to lint, or `rake` to do both.
|
640
|
+
|
641
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To
|
642
|
+
release a new version, update the version number in `version.rb`, and then run
|
643
|
+
`bundle exec rake release`, which will create a git tag for the version, push git
|
644
|
+
commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
645
|
+
|
646
|
+
## Contributing
|
647
|
+
|
648
|
+
Bug reports and pull requests are welcome on GitHub at
|
649
|
+
https://github.com/jgorset/facebook-messenger.
|
650
|
+
|
651
|
+
## Projects using Facebook Messenger
|
652
|
+
|
653
|
+
* [Rubotnik](https://github.com/progapandist/rubotnik-boilerplate) is a boilerplate
|
654
|
+
for Facebook Messenger, and a great place to start if you're new to bots.
|
655
|
+
|
656
|
+
* [Chatwoot](http://chatwoot.com/) use Facebook Messenger to integrate their customer
|
657
|
+
support bots with, well, Facebook Messenger.
|
658
|
+
|
659
|
+
* [Botamp](https://botamp.com) is the all-in-one solution for Marketing Automation via messaging apps.
|
660
|
+
|
661
|
+
## I love you
|
662
|
+
|
663
|
+
Johannes Gorset made this. You should [tweet me](http://twitter.com/jgorset) if you can't get it
|
664
|
+
to work. In fact, you should tweet me anyway.
|
665
|
+
|
666
|
+
## I love Schibsted
|
667
|
+
|
668
|
+
I work at [Schibsted Products & Technology](https://github.com/schibsted) with a bunch of awesome folks
|
669
|
+
who are every bit as passionate about building things as I am. If you're using Facebook Messenger,
|
670
|
+
you should probably join us.
|
671
|
+
|
672
|
+
[Hyper]: https://github.com/hyperoslo
|
673
|
+
[tweet us]: http://twitter.com/hyperoslo
|
674
|
+
[hire you]: http://www.hyper.no/jobs/engineers
|
675
|
+
[MIT License]: http://opensource.org/licenses/MIT
|
676
|
+
[rubygems.org]: https://rubygems.org
|
677
|
+
[message-documentation]: https://developers.facebook.com/docs/messenger-platform/send-api-reference#request
|
678
|
+
[developers.facebook.com]: https://developers.facebook.com/
|
679
|
+
[rack]: https://github.com/rack/rack
|
680
|
+
[send-to-messenger-plugin]: https://developers.facebook.com/docs/messenger-platform/plugin-reference
|
681
|
+
[ngrok]: https://ngrok.com/
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'facebook/messenger'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
require 'pry'
|
11
|
+
Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start
|