facebook-messenger 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +151 -10
- data/lib/facebook/messenger.rb +3 -0
- data/lib/facebook/messenger/bot.rb +43 -10
- 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/configuration.rb +3 -1
- data/lib/facebook/messenger/configuration/providers/base.rb +4 -2
- data/lib/facebook/messenger/configuration/providers/environment.rb +6 -1
- data/lib/facebook/messenger/error.rb +14 -1
- data/lib/facebook/messenger/incoming.rb +31 -6
- data/lib/facebook/messenger/incoming/account_linking.rb +6 -0
- data/lib/facebook/messenger/incoming/common.rb +75 -1
- data/lib/facebook/messenger/incoming/delivery.rb +1 -0
- data/lib/facebook/messenger/incoming/message.rb +86 -1
- data/lib/facebook/messenger/incoming/message_echo.rb +2 -2
- data/lib/facebook/messenger/incoming/message_request.rb +13 -0
- data/lib/facebook/messenger/incoming/optin.rb +18 -1
- 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 +5 -1
- data/lib/facebook/messenger/incoming/read.rb +3 -0
- data/lib/facebook/messenger/incoming/referral.rb +5 -2
- data/lib/facebook/messenger/profile.rb +43 -3
- data/lib/facebook/messenger/server.rb +40 -4
- data/lib/facebook/messenger/server_no_error.rb +36 -0
- data/lib/facebook/messenger/subscriptions.rb +42 -2
- data/lib/facebook/messenger/version.rb +3 -1
- metadata +12 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4eb152a59edb50fe9a410f715d347c58a1ecee2e
|
4
|
+
data.tar.gz: 0832b222a0ce2e352c191dd4797760d5b5f1871e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a47da0222b108ffb19ffc5e28f730474deb7ebe1ee0fb32ec6e00ca66fa6a69550ef8221f4277da77241d2d38b31744b40a3dc22fea4dec03b9e14f0dbc2519f
|
7
|
+
data.tar.gz: 2e5ddec2fc4ea8dfd22d77de20dd364121cbe4def6b06f707d7917e9f73ec57dc83a455b6b762ade18b5551583a57a128e3335ea71634555514858ff763dad4a
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
[![Dependency Status](https://img.shields.io/gemnasium/hyperoslo/facebook-messenger.svg?style=flat)](https://gemnasium.com/hyperoslo/facebook-messenger)
|
9
9
|
[![Code Climate](https://img.shields.io/codeclimate/github/hyperoslo/facebook-messenger.svg?style=flat)](https://codeclimate.com/github/hyperoslo/facebook-messenger)
|
10
10
|
[![Coverage Status](https://img.shields.io/coveralls/hyperoslo/facebook-messenger.svg?style=flat)](https://coveralls.io/r/hyperoslo/facebook-messenger)
|
11
|
-
[![
|
11
|
+
[![Documentation Coverage](http://inch-ci.org/github/jgorset/facebook-messenger.svg?branch=master)](http://inch-ci.org/github/jgorset/facebook-messenger)
|
12
12
|
|
13
13
|
## Installation
|
14
14
|
|
@@ -47,7 +47,8 @@ Bot.deliver({
|
|
47
47
|
},
|
48
48
|
message: {
|
49
49
|
text: 'Human?'
|
50
|
-
}
|
50
|
+
},
|
51
|
+
message_type: Facebook::Messenger::Bot::MessagingType::UPDATE
|
51
52
|
}, access_token: ENV['ACCESS_TOKEN'])
|
52
53
|
```
|
53
54
|
|
@@ -171,10 +172,21 @@ Bot.on :message_echo do |message_echo|
|
|
171
172
|
message_echo.text # => 'Hello, bot!'
|
172
173
|
message_echo.attachments # => [ { 'type' => 'image', 'payload' => { 'url' => 'https://www.example.com/1.jpg' } } ]
|
173
174
|
|
174
|
-
# Log or store in your storage method of choice
|
175
|
+
# Log or store in your storage method of choice (skynet, obviously)
|
175
176
|
end
|
176
177
|
```
|
177
178
|
|
179
|
+
##### Record accepted message requests
|
180
|
+
|
181
|
+
You can keep track of message requests accepted by the human:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
Bot.on :message_request do |message_request|
|
185
|
+
message_request.accept? # => true
|
186
|
+
|
187
|
+
# Log or store in your storage method of choice (skynet, obviously)
|
188
|
+
end
|
189
|
+
```
|
178
190
|
|
179
191
|
#### Send to Facebook
|
180
192
|
|
@@ -266,7 +278,7 @@ Facebook::Messenger::Profile.set({
|
|
266
278
|
type: 'nested',
|
267
279
|
call_to_actions: [
|
268
280
|
{
|
269
|
-
title: 'What
|
281
|
+
title: 'What is a chatbot?',
|
270
282
|
type: 'postback',
|
271
283
|
payload: 'EXTERMINATE'
|
272
284
|
},
|
@@ -298,6 +310,53 @@ Facebook::Messenger::Profile.set({
|
|
298
310
|
}, access_token: ENV['ACCESS_TOKEN'])
|
299
311
|
```
|
300
312
|
|
313
|
+
|
314
|
+
#### Handle a Facebook Policy Violation
|
315
|
+
|
316
|
+
See Facebook's documentation on [Messaging Policy Enforcement](https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messaging_policy_enforcement)
|
317
|
+
|
318
|
+
```ruby
|
319
|
+
Bot.on :'policy_enforcement' do |referral|
|
320
|
+
referral.action # => 'block'
|
321
|
+
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."
|
322
|
+
end
|
323
|
+
```
|
324
|
+
#### messaging_type
|
325
|
+
##### Sending Messages
|
326
|
+
See Facebook's documentation on [Sending Messages](https://developers.facebook.com/docs/messenger-platform/send-messages#standard_messaging)
|
327
|
+
|
328
|
+
As of May 7th 2018 all messages are required to include a messaging_type
|
329
|
+
|
330
|
+
```ruby
|
331
|
+
Bot.deliver({
|
332
|
+
recipient: {
|
333
|
+
id: '45123'
|
334
|
+
},
|
335
|
+
message: {
|
336
|
+
text: 'Human?'
|
337
|
+
},
|
338
|
+
message_type: Facebook::Messenger::Bot::MessagingType::UPDATE
|
339
|
+
}, access_token: ENV['ACCESS_TOKEN'])
|
340
|
+
```
|
341
|
+
|
342
|
+
##### MESSAGE_TAG
|
343
|
+
See Facebook's documentation on [Message Tags](https://developers.facebook.com/docs/messenger-platform/send-messages/message-tags)
|
344
|
+
|
345
|
+
When sending a message with messaging_type: MESSAGE_TAG (Facebook::Messenger::Bot::MessagingType::MESSAGE_TAG) you must ensure you add a tag: parameter
|
346
|
+
|
347
|
+
```ruby
|
348
|
+
Bot.deliver({
|
349
|
+
recipient: {
|
350
|
+
id: '45123'
|
351
|
+
},
|
352
|
+
message: {
|
353
|
+
text: 'Human?'
|
354
|
+
},
|
355
|
+
message_type: Facebook::Messenger::Bot::MessagingType::MESSAGE_TAG
|
356
|
+
tag: Facebook::Messenger::Bot::Tag::NON_PROMOTIONAL_SUBSCRIPTION
|
357
|
+
}, access_token: ENV['ACCESS_TOKEN'])
|
358
|
+
```
|
359
|
+
|
301
360
|
## Configuration
|
302
361
|
|
303
362
|
### Create an Application on Facebook
|
@@ -324,16 +383,36 @@ to keep track of access tokens, app secrets and verify tokens for each of them:
|
|
324
383
|
|
325
384
|
```ruby
|
326
385
|
class ExampleProvider < Facebook::Messenger::Configuration::Providers::Base
|
386
|
+
# Verify that the given verify token is valid.
|
387
|
+
#
|
388
|
+
# verify_token - A String describing the application's verify token.
|
389
|
+
#
|
390
|
+
# Returns a Boolean representing whether the verify token is valid.
|
327
391
|
def valid_verify_token?(verify_token)
|
328
392
|
bot.exists?(verify_token: verify_token)
|
329
393
|
end
|
330
394
|
|
395
|
+
# Find the right application secret.
|
396
|
+
#
|
397
|
+
# page_id - An Integer describing a Facebook Page ID.
|
398
|
+
#
|
399
|
+
# Returns a String describing the application secret.
|
331
400
|
def app_secret_for(page_id)
|
332
401
|
bot.find_by(page_id: page_id).app_secret
|
333
402
|
end
|
334
403
|
|
335
|
-
|
336
|
-
|
404
|
+
# Find the right access token.
|
405
|
+
#
|
406
|
+
# recipient - A Hash describing the `recipient` attribute of the message coming
|
407
|
+
# from Facebook.
|
408
|
+
#
|
409
|
+
# Note: The naming of "recipient" can throw you off, but think of it from the
|
410
|
+
# perspective of the message: The "recipient" is the page that receives the
|
411
|
+
# message.
|
412
|
+
#
|
413
|
+
# Returns a String describing an access token.
|
414
|
+
def access_token_for(recipient)
|
415
|
+
bot.find_by(page_id: recipient['id']).access_token
|
337
416
|
end
|
338
417
|
|
339
418
|
private
|
@@ -375,6 +454,8 @@ require 'facebook/messenger'
|
|
375
454
|
require_relative 'bot'
|
376
455
|
|
377
456
|
run Facebook::Messenger::Server
|
457
|
+
|
458
|
+
# or Facebook::Messenger::ServerNoError for dev
|
378
459
|
```
|
379
460
|
|
380
461
|
```
|
@@ -437,9 +518,64 @@ config.paths.add File.join('app', 'bot'), glob: File.join('**', '*.rb')
|
|
437
518
|
config.autoload_paths += Dir[Rails.root.join('app', 'bot', '*')]
|
438
519
|
```
|
439
520
|
|
521
|
+
|
522
|
+
### Test it...
|
523
|
+
|
524
|
+
##### ...locally
|
440
525
|
To test your locally running bot, you can use [ngrok]. This will create a secure
|
441
526
|
tunnel to localhost so that Facebook can reach the webhook.
|
442
527
|
|
528
|
+
##### ... with RSpec
|
529
|
+
|
530
|
+
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.
|
531
|
+
|
532
|
+
In this case, subscribing to Messenger events has been extracted into a `Listener` class.
|
533
|
+
```ruby
|
534
|
+
# app/bot/listener.rb
|
535
|
+
require 'facebook/messenger'
|
536
|
+
|
537
|
+
include Facebook::Messenger
|
538
|
+
|
539
|
+
class Listener
|
540
|
+
Facebook::Messenger::Subscriptions.subscribe(access_token: ENV["FB_ACCESS_TOKEN"])
|
541
|
+
|
542
|
+
Bot.on :message do |message|
|
543
|
+
Bot.deliver({
|
544
|
+
recipient: message.sender,
|
545
|
+
message: {
|
546
|
+
text: 'Uploading your message to skynet.'
|
547
|
+
}
|
548
|
+
}, access_token: ENV['FB_ACCESS_TOKEN'])
|
549
|
+
end
|
550
|
+
end
|
551
|
+
```
|
552
|
+
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.
|
553
|
+
```ruby
|
554
|
+
require 'rails_helper'
|
555
|
+
|
556
|
+
RSpec.describe Listener do
|
557
|
+
FakeMessage = Struct.new(:sender, :recipient, :timestamp, :message)
|
558
|
+
|
559
|
+
describe 'Bot#on(message)' do
|
560
|
+
it 'responds with a message' do
|
561
|
+
expect(Bot).to receive(:deliver)
|
562
|
+
Bot.trigger(:message, fake_message)
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
private
|
567
|
+
|
568
|
+
def fake_message
|
569
|
+
sender = {"id"=>"1234"}
|
570
|
+
recipient = {"id"=>"5678"}
|
571
|
+
timestamp = 1528049653543
|
572
|
+
message = {"text"=>"Hello, world"}
|
573
|
+
FakeMessage.new(sender, recipient, timestamp, message)
|
574
|
+
end
|
575
|
+
end
|
576
|
+
```
|
577
|
+
|
578
|
+
|
443
579
|
## Development
|
444
580
|
|
445
581
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run
|
@@ -467,11 +603,16 @@ support bots with, well, Facebook Messenger.
|
|
467
603
|
|
468
604
|
* [Botamp](https://botamp.com) is the all-in-one solution for Marketing Automation via messaging apps.
|
469
605
|
|
470
|
-
##
|
606
|
+
## I love you
|
607
|
+
|
608
|
+
Johannes Gorset made this. You should [tweet me](http://twitter.com/jgorset) if you can't get it
|
609
|
+
to work. In fact, you should tweet me anyway.
|
610
|
+
|
611
|
+
## I love Schibsted
|
471
612
|
|
472
|
-
[
|
473
|
-
|
474
|
-
|
613
|
+
I work at [Schibsted Products & Technology](https://github.com/schibsted) with a bunch of awesome folks
|
614
|
+
who are every bit as passionate about building things as I am. If you're using Facebook Messenger,
|
615
|
+
you should probably join us.
|
475
616
|
|
476
617
|
[Hyper]: https://github.com/hyperoslo
|
477
618
|
[tweet us]: http://twitter.com/hyperoslo
|
data/lib/facebook/messenger.rb
CHANGED
@@ -4,6 +4,7 @@ require 'facebook/messenger/subscriptions'
|
|
4
4
|
require 'facebook/messenger/profile'
|
5
5
|
require 'facebook/messenger/bot'
|
6
6
|
require 'facebook/messenger/server'
|
7
|
+
require 'facebook/messenger/server_no_error'
|
7
8
|
require 'facebook/messenger/configuration'
|
8
9
|
require 'facebook/messenger/incoming'
|
9
10
|
|
@@ -22,6 +23,8 @@ module Facebook
|
|
22
23
|
@config = config
|
23
24
|
end
|
24
25
|
|
26
|
+
# Set the default configuration provider.
|
27
|
+
# Developer can set different configuration provider.
|
25
28
|
configure do |config|
|
26
29
|
config.provider = Configuration::Providers::Environment.new
|
27
30
|
end
|
@@ -1,14 +1,20 @@
|
|
1
1
|
require 'facebook/messenger/bot/error_parser'
|
2
2
|
require 'facebook/messenger/bot/exceptions'
|
3
|
+
require 'facebook/messenger/bot/message_type'
|
3
4
|
|
4
5
|
module Facebook
|
5
6
|
module Messenger
|
6
|
-
#
|
7
|
+
#
|
8
|
+
# Module Bot provides functionality to sends and receives messages.
|
9
|
+
#
|
7
10
|
module Bot
|
8
11
|
include HTTParty
|
9
12
|
|
10
|
-
base_uri
|
13
|
+
# Define base_uri for HTTParty.
|
14
|
+
base_uri 'https://graph.facebook.com/v2.9/me'
|
11
15
|
|
16
|
+
#
|
17
|
+
# @return [Array] Array containing the supported webhook events.
|
12
18
|
EVENTS = %i[
|
13
19
|
message
|
14
20
|
delivery
|
@@ -18,14 +24,19 @@ module Facebook
|
|
18
24
|
account_linking
|
19
25
|
referral
|
20
26
|
message_echo
|
27
|
+
payment
|
28
|
+
policy_enforcement
|
21
29
|
].freeze
|
22
30
|
|
23
31
|
class << self
|
24
32
|
# Deliver a message with the given payload.
|
33
|
+
# @see https://developers.facebook.com/docs/messenger-platform/send-api-reference#request
|
25
34
|
#
|
26
|
-
#
|
35
|
+
# @raise [Facebook::Messenger::Bot::SendError] if there is any error
|
36
|
+
# in response while sending message.
|
27
37
|
#
|
28
|
-
#
|
38
|
+
# @param [Hash] message A Hash describing the recipient and the message.
|
39
|
+
# @param [String] access_token Access token.
|
29
40
|
#
|
30
41
|
# Returns a String describing the message ID if the message was sent,
|
31
42
|
# or raises an exception if it was not.
|
@@ -44,8 +55,12 @@ module Facebook
|
|
44
55
|
|
45
56
|
# Register a hook for the given event.
|
46
57
|
#
|
47
|
-
#
|
48
|
-
#
|
58
|
+
# @raise [ArgumentError] if received event is not registered.
|
59
|
+
#
|
60
|
+
# @param [String] event A String describing a Messenger event.
|
61
|
+
# @param [Block] block A code block to run upon the event.
|
62
|
+
#
|
63
|
+
# @return Save event and its block in hooks.
|
49
64
|
def on(event, &block)
|
50
65
|
unless EVENTS.include? event
|
51
66
|
raise ArgumentError,
|
@@ -58,9 +73,12 @@ module Facebook
|
|
58
73
|
|
59
74
|
# Receive a given message from Messenger.
|
60
75
|
#
|
61
|
-
#
|
76
|
+
# @see https://developers.facebook.com/docs/messenger-platform/webhook-reference
|
77
|
+
#
|
78
|
+
# @param [Hash] payload A Hash describing the message.
|
79
|
+
#
|
80
|
+
# @return pass event and object of callback class to trigger function.
|
62
81
|
#
|
63
|
-
# * https://developers.facebook.com/docs/messenger-platform/webhook-reference
|
64
82
|
def receive(payload)
|
65
83
|
callback = Facebook::Messenger::Incoming.parse(payload)
|
66
84
|
event = Facebook::Messenger::Incoming::EVENTS.invert[callback.class]
|
@@ -68,26 +86,41 @@ module Facebook
|
|
68
86
|
end
|
69
87
|
|
70
88
|
# Trigger the hook for the given event.
|
89
|
+
# Fetch callback for event from hooks and call it.
|
71
90
|
#
|
72
|
-
#
|
73
|
-
#
|
91
|
+
# @raise [KeyError] if hook is not registered for event
|
92
|
+
#
|
93
|
+
# @param [String] event A String describing a Messenger event.
|
94
|
+
# @param [Object] args Arguments to pass to the hook.
|
74
95
|
def trigger(event, *args)
|
75
96
|
hooks.fetch(event).call(*args)
|
76
97
|
rescue KeyError
|
77
98
|
$stderr.puts "Ignoring #{event} (no hook registered)"
|
78
99
|
end
|
79
100
|
|
101
|
+
#
|
80
102
|
# Return a Hash of hooks.
|
103
|
+
#
|
104
|
+
# @return [Hash] Hash of hooks.
|
105
|
+
#
|
81
106
|
def hooks
|
82
107
|
@hooks ||= {}
|
83
108
|
end
|
84
109
|
|
110
|
+
#
|
85
111
|
# Deregister all hooks.
|
112
|
+
#
|
113
|
+
# @return [Hash] Assign empty hash to hooks and return it.
|
114
|
+
#
|
86
115
|
def unhook
|
87
116
|
@hooks = {}
|
88
117
|
end
|
89
118
|
|
119
|
+
#
|
90
120
|
# Default HTTParty options.
|
121
|
+
#
|
122
|
+
# @return [Hash] Default HTTParty options.
|
123
|
+
#
|
91
124
|
def default_options
|
92
125
|
super.merge(
|
93
126
|
read_timeout: 300,
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Facebook
|
2
|
+
module Messenger
|
3
|
+
module Bot
|
4
|
+
# Supported message types
|
5
|
+
module MessageType
|
6
|
+
RESPONSE = 'RESPONSE'.freeze
|
7
|
+
UPDATE = 'UPDATE'.freeze
|
8
|
+
MESSAGE_TAG = 'MESSAGE_TAG'.freeze
|
9
|
+
NON_PROMOTIONAL_SUBSCRIPTION = 'NON_PROMOTIONAL_SUBSCRIPTION'.freeze
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Facebook
|
2
|
+
module Messenger
|
3
|
+
module Bot
|
4
|
+
# Supported tags.
|
5
|
+
# Note: A tag is required when sending messages with the
|
6
|
+
# message type `MESSAGE_TAG`.
|
7
|
+
module Tag
|
8
|
+
COMMUNITY_ALERT = 'COMMUNITY_ALERT'.freeze
|
9
|
+
CONFIRMED_EVENT_REMINDER = 'CONFIRMED_EVENT_REMINDER'.freeze
|
10
|
+
NON_PROMOTIONAL_SUBSCRIPTION = 'NON_PROMOTIONAL_SUBSCRIPTION'.freeze
|
11
|
+
PAIRING_UPDATE = 'PAIRING_UPDATE'.freeze
|
12
|
+
APPLICATION_UPDATE = 'APPLICATION_UPDATE'.freeze
|
13
|
+
ACCOUNT_UPDATE = 'ACCOUNT_UPDATE'.freeze
|
14
|
+
PAYMENT_UPDATE = 'PAYMENT_UPDATE'.freeze
|
15
|
+
PERSONAL_FINANCE_UPDATE = 'PERSONAL_FINANCE_UPDATE'.freeze
|
16
|
+
SHIPPING_UPDATE = 'SHIPPING_UPDATE'.freeze
|
17
|
+
RESERVATION_UPDATE = 'RESERVATION_UPDATE'.freeze
|
18
|
+
ISSUE_RESOLUTION = 'ISSUE_RESOLUTION'.freeze
|
19
|
+
APPOINTMENT_UPDATE = 'APPOINTMENT_UPDATE'.freeze
|
20
|
+
GAME_EVENT = 'GAME_EVENT'.freeze
|
21
|
+
TRANSPORTATION_UPDATE = 'TRANSPORTATION_UPDATE'.freeze
|
22
|
+
FEATURE_FUNCTIONALITY_UPDATE = 'FEATURE_FUNCTIONALITY_UPDATE'.freeze
|
23
|
+
TICKET_UPDATE = 'TICKET_UPDATE'.freeze
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|