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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +151 -10
  3. data/lib/facebook/messenger.rb +3 -0
  4. data/lib/facebook/messenger/bot.rb +43 -10
  5. data/lib/facebook/messenger/bot/message_type.rb +13 -0
  6. data/lib/facebook/messenger/bot/messaging_type.rb +12 -0
  7. data/lib/facebook/messenger/bot/tag.rb +27 -0
  8. data/lib/facebook/messenger/configuration.rb +3 -1
  9. data/lib/facebook/messenger/configuration/providers/base.rb +4 -2
  10. data/lib/facebook/messenger/configuration/providers/environment.rb +6 -1
  11. data/lib/facebook/messenger/error.rb +14 -1
  12. data/lib/facebook/messenger/incoming.rb +31 -6
  13. data/lib/facebook/messenger/incoming/account_linking.rb +6 -0
  14. data/lib/facebook/messenger/incoming/common.rb +75 -1
  15. data/lib/facebook/messenger/incoming/delivery.rb +1 -0
  16. data/lib/facebook/messenger/incoming/message.rb +86 -1
  17. data/lib/facebook/messenger/incoming/message_echo.rb +2 -2
  18. data/lib/facebook/messenger/incoming/message_request.rb +13 -0
  19. data/lib/facebook/messenger/incoming/optin.rb +18 -1
  20. data/lib/facebook/messenger/incoming/payment.rb +49 -0
  21. data/lib/facebook/messenger/incoming/policy_enforcement.rb +21 -0
  22. data/lib/facebook/messenger/incoming/postback.rb +5 -1
  23. data/lib/facebook/messenger/incoming/read.rb +3 -0
  24. data/lib/facebook/messenger/incoming/referral.rb +5 -2
  25. data/lib/facebook/messenger/profile.rb +43 -3
  26. data/lib/facebook/messenger/server.rb +40 -4
  27. data/lib/facebook/messenger/server_no_error.rb +36 -0
  28. data/lib/facebook/messenger/subscriptions.rb +42 -2
  29. data/lib/facebook/messenger/version.rb +3 -1
  30. metadata +12 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d44d493f7a90af8ada14c7bdcece0b54fa033abf
4
- data.tar.gz: 5299267b035cda79e916beb6752fc736c9ec9853
3
+ metadata.gz: 4eb152a59edb50fe9a410f715d347c58a1ecee2e
4
+ data.tar.gz: 0832b222a0ce2e352c191dd4797760d5b5f1871e
5
5
  SHA512:
6
- metadata.gz: 5707bbee02a68b2bf370d841d8644c7b6bdd2acadbcc93083c0c76743d337e1aad126c731a2374a92b064e233a4bd8e1f02df7d1f958700ea81c084b04ccff63
7
- data.tar.gz: 4db0e0fcd018f909478a98162275bbc91691a81ac1c40106ecec4eb0c2f4e276b16c1598713e6fbfcbadb580b212f2fa85266f1e66e4ca551749b7b6a9244909
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
- [![Join the chat at https://gitter.im/hyperoslo/facebook-messenger](https://badges.gitter.im/hyperoslo/facebook-messenger.svg)](https://gitter.im/hyperoslo/facebook-messenger?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
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's a chatbot?',
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
- def access_token_for(page_id)
336
- bot.find_by(page_id: page_id).access_token
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
- ## Hyper loves you
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
- [Hyper] made this. We're a bunch of folks who love building things. You should
473
- [tweet us] if you can't get it to work. In fact, you should tweet us anyway.
474
- If you're using Facebook Messenger, we probably want to [hire you].
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
@@ -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
- # The Bot module sends and receives messages.
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 'https://graph.facebook.com/v2.6/me'
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
- # message - A Hash describing the recipient and the message*.
35
+ # @raise [Facebook::Messenger::Bot::SendError] if there is any error
36
+ # in response while sending message.
27
37
  #
28
- # * https://developers.facebook.com/docs/messenger-platform/send-api-reference#request
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
- # event - A String describing a Messenger event.
48
- # block - A code block to run upon the event.
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
- # payload - A Hash describing the message.
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
- # event - A String describing a Messenger event.
73
- # args - Arguments to pass to the hook.
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,12 @@
1
+ module Facebook
2
+ module Messenger
3
+ module Bot
4
+ # Supported message types
5
+ module MessagingType
6
+ RESPONSE = 'RESPONSE'.freeze
7
+ UPDATE = 'UPDATE'.freeze
8
+ MESSAGE_TAG = 'MESSAGE_TAG'.freeze
9
+ end
10
+ end
11
+ end
12
+ 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
@@ -2,7 +2,9 @@ require 'facebook/messenger/configuration/providers'
2
2
 
3
3
  module Facebook
4
4
  module Messenger
5
- # This module holds the configuration.
5
+ #
6
+ # Class Configuration holds the configuration for bot.
7
+ #
6
8
  class Configuration
7
9
  attr_accessor :provider
8
10
  end