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
@@ -1,8 +1,8 @@
|
|
1
1
|
module Facebook
|
2
2
|
module Messenger
|
3
3
|
module Incoming
|
4
|
-
# The Message echo class represents an
|
5
|
-
#
|
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
|
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
|
-
#
|
4
|
+
# Referral class represents an incoming Facebook Messenger referral event.
|
5
5
|
#
|
6
|
-
# https://developers.facebook.com/docs/messenger-platform/
|
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
|
-
#
|
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
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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.
|
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
|