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
@@ -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