facebook-messenger 1.0.0 → 1.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.
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
@@ -1,8 +1,8 @@
1
1
  module Facebook
2
2
  module Messenger
3
3
  module Incoming
4
- # The Message echo class represents an
5
- # incoming Facebook Messenger message
4
+ # The Message echo class represents an incoming Facebook Messenger message
5
+ # @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/message-echoes
6
6
  class MessageEcho < Message
7
7
  end
8
8
  end
@@ -0,0 +1,13 @@
1
+ module Facebook
2
+ module Messenger
3
+ module Incoming
4
+ # The Message request class represents an
5
+ # incoming Facebook Messenger message request accepted by the user
6
+ class MessageRequest < Message
7
+ def accept?
8
+ @messaging['message_request'] == 'accept'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,16 +1,33 @@
1
1
  module Facebook
2
2
  module Messenger
3
3
  module Incoming
4
+ #
4
5
  # The Optin class represents an incoming Facebook Messenger optin,
5
6
  # which occurs when a user engages by using the Send-to-Messenger Plugin.
6
7
  #
7
- # https://developers.facebook.com/docs/messenger-platform/plugin-reference
8
+ # @see https://developers.facebook.com/docs/messenger-platform/plugin-reference
9
+ #
8
10
  class Optin
9
11
  include Facebook::Messenger::Incoming::Common
10
12
 
13
+ #
14
+ # Function returns 'data-ref' attribute that was defined
15
+ # with the entry point.
16
+ #
17
+ # @return [String] data-ref attribute.
18
+ #
11
19
  def ref
12
20
  @messaging['optin']['ref']
13
21
  end
22
+
23
+ #
24
+ # Function returns 'user_ref' attribute defined in checkbox plugin.
25
+ #
26
+ # @return [String] user-ref attribute.
27
+ #
28
+ def user_ref
29
+ @messaging['optin']['user_ref']
30
+ end
14
31
  end
15
32
  end
16
33
  end
@@ -0,0 +1,49 @@
1
+ module Facebook
2
+ module Messenger
3
+ module Incoming
4
+ # The Payment class represents a successful purchase using the Buy Button
5
+ #
6
+ # https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/payment
7
+ class Payment
8
+ include Facebook::Messenger::Incoming::Common
9
+
10
+ # The payment portion of the payload.
11
+ class Payment
12
+ def initialize(payment)
13
+ @payment = payment
14
+ end
15
+
16
+ # Return String containing developer defined payload.
17
+ def payload
18
+ @payment['payload']
19
+ end
20
+
21
+ # Return hash containing the requested information from user when they
22
+ # click buy button.
23
+ def user_info
24
+ @payment['requested_user_info']
25
+ end
26
+
27
+ # Return hash containing the payment credential information.
28
+ def payment_credential
29
+ @payment['payment_credential']
30
+ end
31
+
32
+ # Return hash containing the information about amount of purchase.
33
+ def amount
34
+ @payment['amount']
35
+ end
36
+
37
+ # Return string containing option_id of selected shipping option.
38
+ def shipping_option_id
39
+ @payment['shipping_option_id']
40
+ end
41
+ end
42
+
43
+ def payment
44
+ @payment ||= Payment.new(@messaging['payment'])
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,21 @@
1
+ module Facebook
2
+ module Messenger
3
+ module Incoming
4
+ # The PolicyEnforcement class represents an incoming webhook response from
5
+ # Facebook when they are notifying your app of a policy violation
6
+ #
7
+ # https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messaging_policy_enforcement
8
+ class PolicyEnforcement
9
+ include Facebook::Messenger::Incoming::Common
10
+
11
+ def action
12
+ @messaging['policy_enforcement']['action']
13
+ end
14
+
15
+ def reason
16
+ @messaging['policy_enforcement']['reason']
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,14 +1,18 @@
1
1
  module Facebook
2
2
  module Messenger
3
3
  module Incoming
4
- # The Postback class represents an incoming Facebook Messenger postback.
4
+ # The Postback class represents an incoming Facebook Messenger
5
+ # postback events.
6
+ # @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messaging_postbacks
5
7
  class Postback
6
8
  include Facebook::Messenger::Incoming::Common
7
9
 
10
+ # Return String of developer defined payload.
8
11
  def payload
9
12
  @messaging['postback']['payload']
10
13
  end
11
14
 
15
+ # Return hash containing the referral information of user.
12
16
  def referral
13
17
  return if @messaging['postback']['referral'].nil?
14
18
  @referral ||= Referral::Referral.new(
@@ -2,13 +2,16 @@ module Facebook
2
2
  module Messenger
3
3
  module Incoming
4
4
  # The Read class represents the user reading a delivered message.
5
+ # @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/message-reads
5
6
  class Read
6
7
  include Facebook::Messenger::Incoming::Common
7
8
 
9
+ # Return time object when message is read by user.
8
10
  def at
9
11
  Time.at(@messaging['read']['watermark'] / 1000)
10
12
  end
11
13
 
14
+ # Return Integer defining the sequence number of message.
12
15
  def seq
13
16
  @messaging['read']['seq']
14
17
  end
@@ -1,9 +1,9 @@
1
1
  module Facebook
2
2
  module Messenger
3
3
  module Incoming
4
- # The Referral class represents an incoming Facebook Messenger referral.
4
+ # Referral class represents an incoming Facebook Messenger referral event.
5
5
  #
6
- # https://developers.facebook.com/docs/messenger-platform/referral-params
6
+ # @see https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messaging_referrals
7
7
  class Referral
8
8
  include Facebook::Messenger::Incoming::Common
9
9
 
@@ -13,14 +13,17 @@ module Facebook
13
13
  @referral = referral
14
14
  end
15
15
 
16
+ # Return String of ref data set in referrer.
16
17
  def ref
17
18
  @referral['ref']
18
19
  end
19
20
 
21
+ # Return String of referral source.
20
22
  def source
21
23
  @referral['source']
22
24
  end
23
25
 
26
+ # Return String of referral type.
24
27
  def type
25
28
  @referral['type']
26
29
  end
@@ -2,18 +2,31 @@ require 'httparty'
2
2
 
3
3
  module Facebook
4
4
  module Messenger
5
- # This module handles changing messenger profile (menu, start & greeting).
6
5
  #
7
- # https://developers.facebook.com/docs/messenger-platform/messenger-profile
6
+ # This module provide functionality to manage the messenger profile.
7
+ # @see https://developers.facebook.com/docs/messenger-platform/messenger-profile
8
+ #
8
9
  module Profile
9
10
  include HTTParty
10
11
 
11
- base_uri 'https://graph.facebook.com/v2.6/me'
12
+ # Define base_uri for HTTParty.
13
+ base_uri 'https://graph.facebook.com/v2.9/me'
12
14
 
13
15
  format :json
14
16
 
15
17
  module_function
16
18
 
19
+ #
20
+ # Set the messenger profile.
21
+ #
22
+ # @raise [Facebook::Messenger::Profile::Error] if there is any error
23
+ # in response.
24
+ #
25
+ # @param [Hash] settings Hash defining the profile settings.
26
+ # @param [String] access_token Access token of facebook page.
27
+ #
28
+ # @return [Boolean] If profile is successfully set, return true.
29
+ #
17
30
  def set(settings, access_token:)
18
31
  response = post '/messenger_profile', body: settings.to_json, query: {
19
32
  access_token: access_token
@@ -24,6 +37,17 @@ module Facebook
24
37
  true
25
38
  end
26
39
 
40
+ #
41
+ # Unset the messenger profile.
42
+ #
43
+ # @raise [Facebook::Messenger::Profile::Error] if there is any error
44
+ # in response.
45
+ #
46
+ # @param [Hash] settings Hash defining the profile settings.
47
+ # @param [String] access_token Access token of facebook page.
48
+ #
49
+ # @return [Boolean] If profile is successfully removed, return true.
50
+ #
27
51
  def unset(settings, access_token:)
28
52
  response = delete '/messenger_profile', body: settings.to_json, query: {
29
53
  access_token: access_token
@@ -34,10 +58,23 @@ module Facebook
34
58
  true
35
59
  end
36
60
 
61
+ #
62
+ # Function raise error if response has error key.
63
+ #
64
+ # @raise [Facebook::Messenger::Profile::Error] if error is present
65
+ # in response.
66
+ #
67
+ # @param [Hash] response Response hash from facebook.
68
+ #
37
69
  def raise_errors(response)
38
70
  raise Error, response['error'] if response.key? 'error'
39
71
  end
40
72
 
73
+ #
74
+ # Default HTTParty options.
75
+ #
76
+ # @return [Hash] Default HTTParty options.
77
+ #
41
78
  def default_options
42
79
  super.merge(
43
80
  headers: {
@@ -46,6 +83,9 @@ module Facebook
46
83
  )
47
84
  end
48
85
 
86
+ #
87
+ # Class Error provides errors related to profile subscriptions.
88
+ #
49
89
  class Error < Facebook::Messenger::FacebookError; end
50
90
  end
51
91
  end
@@ -12,13 +12,16 @@ module Facebook
12
12
  some time, check your app's secret token.
13
13
  HEREDOC
14
14
 
15
+ #
15
16
  # This module holds the server that processes incoming messages from the
16
17
  # Facebook Messenger Platform.
18
+ #
17
19
  class Server
18
20
  def self.call(env)
19
21
  new.call(env)
20
22
  end
21
23
 
24
+ # Rack handler for request.
22
25
  def call(env)
23
26
  @request = Rack::Request.new(env)
24
27
  @response = Rack::Response.new
@@ -34,8 +37,14 @@ module Facebook
34
37
  @response.finish
35
38
  end
36
39
 
40
+ # @private
37
41
  private
38
42
 
43
+ #
44
+ # Function validates the verification request which is sent by Facebook
45
+ # to validate the entered endpoint.
46
+ # @see https://developers.facebook.com/docs/graph-api/webhooks#callback
47
+ #
39
48
  def verify
40
49
  if valid_verify_token?(@request.params['hub.verify_token'])
41
50
  @response.write @request.params['hub.challenge']
@@ -44,6 +53,10 @@ module Facebook
44
53
  end
45
54
  end
46
55
 
56
+ #
57
+ # Function handles the webhook events.
58
+ # @raise BadRequestError if the request is tampered.
59
+ #
47
60
  def receive
48
61
  check_integrity
49
62
 
@@ -52,12 +65,16 @@ module Facebook
52
65
  respond_with_error(error)
53
66
  end
54
67
 
68
+ #
55
69
  # Check the integrity of the request.
70
+ # @see https://developers.facebook.com/docs/messenger-platform/webhook#security
56
71
  #
57
- # Raises BadRequestError if the request has been tampered with.
72
+ # @raise BadRequestError if the request has been tampered with.
58
73
  #
59
- # Returns nothing.
60
74
  def check_integrity
75
+ # If app secret is not found in environment, return.
76
+ # So for the security purpose always add provision in
77
+ # configuration provider to return app secret.
61
78
  return unless app_secret_for(parsed_body['entry'][0]['id'])
62
79
 
63
80
  unless signature.start_with?('sha1='.freeze)
@@ -75,17 +92,21 @@ module Facebook
75
92
  @request.env['HTTP_X_HUB_SIGNATURE'.freeze].to_s
76
93
  end
77
94
 
95
+ #
78
96
  # Verify that the signature given in the X-Hub-Signature header matches
79
97
  # that of the body.
80
98
  #
81
- # Returns a Boolean.
99
+ # @return [Boolean] true if request is valid else false.
100
+ #
82
101
  def valid_signature?
83
102
  Rack::Utils.secure_compare(signature, signature_for(body))
84
103
  end
85
104
 
105
+ #
86
106
  # Sign the given string.
87
107
  #
88
- # Returns a String describing its signature.
108
+ # @return [String] A string describing its signature.
109
+ #
89
110
  def signature_for(string)
90
111
  format('sha1=%s'.freeze, generate_hmac(string))
91
112
  end
@@ -115,13 +136,23 @@ module Facebook
115
136
  @body ||= @request.body.read
116
137
  end
117
138
 
139
+ #
118
140
  # Returns a Hash describing the parsed request body.
141
+ # @raise JSON::ParserError if body hash is not valid.
142
+ #
143
+ # @return [JSON] Parsed body hash.
144
+ #
119
145
  def parsed_body
120
146
  @parsed_body ||= JSON.parse(body)
121
147
  rescue JSON::ParserError
122
148
  raise BadRequestError, 'Error parsing request body format'
123
149
  end
124
150
 
151
+ #
152
+ # Function hand over the webhook event to handlers.
153
+ #
154
+ # @param [Hash] events Parsed body hash in webhook event.
155
+ #
125
156
  def trigger(events)
126
157
  # Facebook may batch several items in the 'entry' array during
127
158
  # periods of high load.
@@ -137,6 +168,11 @@ module Facebook
137
168
  end
138
169
  end
139
170
 
171
+ #
172
+ # If received request is tampered, sent 400 code in response.
173
+ #
174
+ # @param [Object] error Error object.
175
+ #
140
176
  def respond_with_error(error)
141
177
  @response.status = 400
142
178
  @response.write(error.message)
@@ -0,0 +1,36 @@
1
+ require_relative 'server'
2
+
3
+ module Facebook
4
+ module Messenger
5
+ # Server rescuing all errors sending the backtrace back to the chat
6
+ # FOR DEVELOPPING PURPOSE
7
+ class ServerNoError < Server
8
+ SCREAMING_FACE = "\xF0\x9F\x98\xB1".freeze
9
+ MAX_MESSAGE_LENGTH = 639
10
+
11
+ def call(env)
12
+ super
13
+ rescue Exception => e # rubocop:disable Lint/RescueException
14
+ send(SCREAMING_FACE)
15
+ send(e.inspect)
16
+ send(e.backtrace.join("\n")[0..MAX_MESSAGE_LENGTH - 3] + '...')
17
+
18
+ @response.status = 200
19
+ @response.finish
20
+ end
21
+
22
+ private
23
+
24
+ def sender
25
+ parsed_body['entry'][0]['messaging'][0]['sender']
26
+ end
27
+
28
+ def send(text)
29
+ Bot.deliver({
30
+ recipient: sender,
31
+ message: { text: text }
32
+ }, access_token: ENV['ACCESS_TOKEN'])
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,16 +2,31 @@ require 'httparty'
2
2
 
3
3
  module Facebook
4
4
  module Messenger
5
- # This module handles subscribing and unsubscribing Applications to Pages.
5
+ #
6
+ # Module Subscriptions handles subscribing and unsubscribing Applications
7
+ # to Pages.
8
+ #
6
9
  module Subscriptions
7
10
  include HTTParty
8
11
 
9
- base_uri 'https://graph.facebook.com/v2.6/me'
12
+ base_uri 'https://graph.facebook.com/v2.9/me'
10
13
 
11
14
  format :json
12
15
 
13
16
  module_function
14
17
 
18
+ #
19
+ # Function subscribe the facebook app to page.
20
+ # @see https://developers.facebook.com/docs/graph-api/reference/page/subscribed_apps
21
+ #
22
+ # @raise [Facebook::Messenger::Subscriptions::Error] if there is any error
23
+ # in the response of subscribed_apps request.
24
+ #
25
+ # @param [String] access_token Access token of page to which bot has
26
+ # to subscribe.
27
+ #
28
+ # @return [Boolean] TRUE
29
+ #
15
30
  def subscribe(access_token:)
16
31
  response = post '/subscribed_apps', query: {
17
32
  access_token: access_token
@@ -22,6 +37,18 @@ module Facebook
22
37
  true
23
38
  end
24
39
 
40
+ #
41
+ # Function unsubscribe the app from facebook page.
42
+ # @see https://developers.facebook.com/docs/graph-api/reference/page/subscribed_apps
43
+ #
44
+ # @raise [Facebook::Messenger::Subscriptions::Error] if there is any error
45
+ # in the response of subscribed_apps request.
46
+ #
47
+ # @param [String] access_token Access token of page from which app has
48
+ # to unsubscribe.
49
+ #
50
+ # @return [Boolean] TRUE
51
+ #
25
52
  def unsubscribe(access_token:)
26
53
  response = delete '/subscribed_apps', query: {
27
54
  access_token: access_token
@@ -32,10 +59,23 @@ module Facebook
32
59
  true
33
60
  end
34
61
 
62
+ #
63
+ # If there is any error in response, raise error.
64
+ #
65
+ # @raise [Facebook::Messenger::Subscriptions::Error] If there is error
66
+ # in response.
67
+ #
68
+ # @param [Hash] response Response from facebook.
69
+ #
70
+ # @return Raise the error.
71
+ #
35
72
  def raise_errors(response)
36
73
  raise Error, response['error'] if response.key? 'error'
37
74
  end
38
75
 
76
+ #
77
+ # Class Error provides errors related to subscriptions.
78
+ #
39
79
  class Error < Facebook::Messenger::FacebookError; end
40
80
  end
41
81
  end