stealth-facebook 0.12.0 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c5f352636c999182ab5ab0059b65ac878f233c921639c886d969140f4218092a
4
- data.tar.gz: fe85dd2fd4fc0093f46b1bc922b3ff152fcf71dd2552ed9972f4531827ef8a29
3
+ metadata.gz: 2eae4e1dafe5f39e579df40a4d45f3c5d52761e3b5afe00a958018448a8bcaed
4
+ data.tar.gz: 8a83fbff458909bf1cb6beb18bc6a8f2879256e5bac5bd611a28bd7cf47b489a
5
5
  SHA512:
6
- metadata.gz: d0c9dee3070ec9efa473ab1aff1cf6596278e0fdb2adfdf8957eb0f061773df92208197a249505b9176e69a3819ba8751c7fbd4062abf958261209631c00a560
7
- data.tar.gz: 962575b7130ccff7d0e10c8870b5a7caf3c2b2a4d60e1d719541e4136eef3a69bb90f50607c0935da8dd63ae1fcb9cd3bdb17beda05764bdd685ac8ef120d471
6
+ metadata.gz: fa9b3453020fc70539bd4996bb257adf859ddd98770569f8804392a20cd9fe3147f582ca893485fff4c728ee191528a95dab5016a1b5e53a5394eb6f8152e21d
7
+ data.tar.gz: c3caf9325353e5deb40288e515c1df2464679ff6e8b711b700d3fe91859e3892e5a2f68ff54a1415fa3756f145acc475f7c8901815e0a61332a1ed0578eb4f87
data/Gemfile CHANGED
@@ -1,2 +1,5 @@
1
1
  source 'https://rubygems.org'
2
+
3
+ gem 'stealth', '>= 2.0.0.beta'
4
+
2
5
  gemspec
@@ -1,116 +1,98 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stealth-facebook (0.11.2)
5
- faraday (~> 0.13)
6
- stealth (< 2.0)
4
+ stealth-facebook (0.22.0)
5
+ http (~> 4.4)
6
+ stealth (>= 2.0.0.beta)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- actionpack (5.2.1)
12
- actionview (= 5.2.1)
13
- activesupport (= 5.2.1)
14
- rack (~> 2.0)
15
- rack-test (>= 0.6.3)
16
- rails-dom-testing (~> 2.0)
17
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
18
- actionview (5.2.1)
19
- activesupport (= 5.2.1)
20
- builder (~> 3.1)
21
- erubi (~> 1.4)
22
- rails-dom-testing (~> 2.0)
23
- rails-html-sanitizer (~> 1.0, >= 1.0.3)
24
- activemodel (5.2.1)
25
- activesupport (= 5.2.1)
26
- activerecord (5.2.1)
27
- activemodel (= 5.2.1)
28
- activesupport (= 5.2.1)
29
- arel (>= 9.0)
30
- activesupport (5.2.1)
11
+ activesupport (6.0.3.3)
31
12
  concurrent-ruby (~> 1.0, >= 1.0.2)
32
13
  i18n (>= 0.7, < 2)
33
14
  minitest (~> 5.1)
34
15
  tzinfo (~> 1.1)
35
- arel (9.0.0)
36
- builder (3.2.3)
37
- concurrent-ruby (1.0.5)
38
- connection_pool (2.2.2)
39
- crass (1.0.4)
40
- diff-lcs (1.3)
41
- erubi (1.7.1)
42
- faraday (0.15.3)
43
- multipart-post (>= 1.2, < 3)
44
- i18n (1.1.1)
16
+ zeitwerk (~> 2.2, >= 2.2.2)
17
+ addressable (2.7.0)
18
+ public_suffix (>= 2.0.2, < 5.0)
19
+ concurrent-ruby (1.1.7)
20
+ connection_pool (2.2.3)
21
+ diff-lcs (1.4.4)
22
+ domain_name (0.5.20190701)
23
+ unf (>= 0.0.5, < 1.0.0)
24
+ ffi (1.13.1)
25
+ ffi-compiler (1.0.1)
26
+ ffi (>= 1.0.0)
27
+ rake
28
+ http (4.4.1)
29
+ addressable (~> 2.3)
30
+ http-cookie (~> 1.0)
31
+ http-form_data (~> 2.2)
32
+ http-parser (~> 1.2.0)
33
+ http-cookie (1.0.3)
34
+ domain_name (~> 0.5)
35
+ http-form_data (2.3.0)
36
+ http-parser (1.2.1)
37
+ ffi-compiler (>= 1.0, < 2.0)
38
+ i18n (1.8.5)
45
39
  concurrent-ruby (~> 1.0)
46
- loofah (2.2.3)
47
- crass (~> 1.0.2)
48
- nokogiri (>= 1.5.9)
49
- method_source (0.9.0)
50
- mini_portile2 (2.3.0)
51
- minitest (5.11.3)
52
- multi_json (1.13.1)
53
- multipart-post (2.0.0)
54
- mustermann (1.0.3)
55
- nokogiri (1.8.5)
56
- mini_portile2 (~> 2.3.0)
57
- puma (3.12.0)
58
- rack (2.0.6)
59
- rack-protection (2.0.4)
40
+ minitest (5.14.2)
41
+ multi_json (1.15.0)
42
+ mustermann (1.1.1)
43
+ ruby2_keywords (~> 0.0.1)
44
+ nio4r (2.5.4)
45
+ public_suffix (4.0.6)
46
+ puma (4.3.6)
47
+ nio4r (~> 2.0)
48
+ rack (2.2.3)
49
+ rack-protection (2.1.0)
60
50
  rack
61
51
  rack-test (1.1.0)
62
52
  rack (>= 1.0, < 3)
63
- rails-dom-testing (2.0.3)
64
- activesupport (>= 4.2.0)
65
- nokogiri (>= 1.6)
66
- rails-html-sanitizer (1.0.4)
67
- loofah (~> 2.2, >= 2.2.2)
68
- railties (5.2.1)
69
- actionpack (= 5.2.1)
70
- activesupport (= 5.2.1)
71
- method_source
72
- rake (>= 0.8.7)
73
- thor (>= 0.19.0, < 2.0)
74
- rake (12.3.1)
75
- redis (4.0.2)
76
- rspec (3.8.0)
77
- rspec-core (~> 3.8.0)
78
- rspec-expectations (~> 3.8.0)
79
- rspec-mocks (~> 3.8.0)
80
- rspec-core (3.8.0)
81
- rspec-support (~> 3.8.0)
82
- rspec-expectations (3.8.1)
53
+ rake (13.0.1)
54
+ redis (4.2.2)
55
+ rspec (3.9.0)
56
+ rspec-core (~> 3.9.0)
57
+ rspec-expectations (~> 3.9.0)
58
+ rspec-mocks (~> 3.9.0)
59
+ rspec-core (3.9.2)
60
+ rspec-support (~> 3.9.3)
61
+ rspec-expectations (3.9.2)
83
62
  diff-lcs (>= 1.2.0, < 2.0)
84
- rspec-support (~> 3.8.0)
85
- rspec-mocks (3.8.0)
63
+ rspec-support (~> 3.9.0)
64
+ rspec-mocks (3.9.1)
86
65
  diff-lcs (>= 1.2.0, < 2.0)
87
- rspec-support (~> 3.8.0)
88
- rspec-support (3.8.0)
66
+ rspec-support (~> 3.9.0)
67
+ rspec-support (3.9.3)
89
68
  rspec_junit_formatter (0.4.1)
90
69
  rspec-core (>= 2, < 4, != 2.12.0)
91
- sidekiq (5.2.2)
92
- connection_pool (~> 2.2, >= 2.2.2)
93
- rack-protection (>= 1.5.0)
94
- redis (>= 3.3.5, < 5)
95
- sinatra (2.0.4)
96
- mustermann (~> 1.0)
70
+ ruby2_keywords (0.0.2)
71
+ sidekiq (6.1.2)
72
+ connection_pool (>= 2.2.2)
97
73
  rack (~> 2.0)
98
- rack-protection (= 2.0.4)
74
+ redis (>= 4.2.0)
75
+ sinatra (2.1.0)
76
+ mustermann (~> 1.0)
77
+ rack (~> 2.2)
78
+ rack-protection (= 2.1.0)
99
79
  tilt (~> 2.0)
100
- stealth (1.0.4)
101
- activerecord (~> 5.2)
102
- activesupport (~> 5.2)
80
+ stealth (2.0.0.beta1)
81
+ activesupport (~> 6.0)
103
82
  multi_json (~> 1.12)
104
- puma (~> 3.10)
105
- railties (~> 5.2)
106
- sidekiq (~> 5.0)
83
+ puma (>= 4.2, < 5.0)
84
+ sidekiq (~> 6.0)
107
85
  sinatra (~> 2.0)
108
- thor (~> 0.20)
109
- thor (0.20.0)
86
+ thor (~> 1.0)
87
+ thor (1.0.1)
110
88
  thread_safe (0.3.6)
111
- tilt (2.0.8)
112
- tzinfo (1.2.5)
89
+ tilt (2.0.10)
90
+ tzinfo (1.2.7)
113
91
  thread_safe (~> 0.1)
92
+ unf (0.1.4)
93
+ unf_ext
94
+ unf_ext (0.0.7.7)
95
+ zeitwerk (2.4.0)
114
96
 
115
97
  PLATFORMS
116
98
  ruby
@@ -119,7 +101,8 @@ DEPENDENCIES
119
101
  rack-test (~> 1.1)
120
102
  rspec (~> 3.6)
121
103
  rspec_junit_formatter (~> 0.3)
104
+ stealth (>= 2.0.0.beta)
122
105
  stealth-facebook!
123
106
 
124
107
  BUNDLED WITH
125
- 1.16.3
108
+ 2.1.4
data/LICENSE CHANGED
@@ -1,20 +1,7 @@
1
- Copyright (c) 2017 Mauricio Gomes, Black Ops Bureau
1
+ Copyright (c) 2017-2020 Mauricio Gomes, Mav Automation Ventures Inc.
2
2
 
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
4
 
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13
6
 
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -12,7 +12,26 @@ When configuring your webhooks, you'll want to enable the `messages`, `messaging
12
12
 
13
13
  <img src='fb-config.png' width='875px' alt='Facebook Config Screenshot' />
14
14
 
15
- Make sure you don't enable `message_reads` as that is not yet supported by this gem.
15
+ ### message_reads
16
+
17
+ Beginning with version `0.13.0` of this gem, `message_reads` webhooks are supported. When enabled in your Facebook configuration, they will appear as `current_message.read`. That will return a hash:
18
+
19
+ ```ruby
20
+ {
21
+ watermark: 1458668856253,
22
+ seq: 38
23
+ }
24
+ ```
25
+
26
+ More info about `message_reads` webhooks can be found in the [Facebook Developer docs](https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/message-reads).
27
+
28
+ ### messaging_referrals
29
+
30
+ Facebook separates referral data for users with an existing thread versus those that have initiated a new thread. For the former case, the `messaging_referrals` webhook event is used to send the referral data. For the latter case, the referral payload is sent via the `postback` event.
31
+
32
+ For both scenarios above, this driver will include the referral payload as part of the `current_message`. It can be accessed via `current_message.referral`.
33
+
34
+ More info about `messaging_referrals` webhooks and the different referral payloads can be found in the [Facebook Developer docs](https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messaging_referrals/)
16
35
 
17
36
  ## Configure The Integration
18
37
 
@@ -68,6 +87,8 @@ test:
68
87
 
69
88
  As with all Stealth integrations, integrations can be specified by environment. You'll want to replace `FACEBOOK_VERIFY_TOKEN` and `FACEBOOK_ACCESS_TOKEN` with your respective keys from your Facebook page.
70
89
 
90
+ You may also specify a Facebook Graph API version by setting the ENV var `FACEBOOK_API_VERSION` to API version your bot has been cofnigured to use. If none is specified, this driver will currently default to version `3.2`.
91
+
71
92
  These are the supported setup options:
72
93
 
73
94
  ### greeting
@@ -130,9 +151,9 @@ fb_profile = Stealth::Services::Facebook::Client.fetch_profile(
130
151
 
131
152
  ### Analytics
132
153
 
133
- If you'd like to track custom bot metrics in addition to the ones provided automatically by Facebook Analytics, you can do so in starting in version `0.12.0` of this gem.
154
+ If you'd like to track custom bot metrics in addition to the ones provided automatically by Facebook Analytics, you can do so starting with version `0.12.0` of this gem.
134
155
 
135
- In order to send these metrics, you'll need to add the `app_id` of the bot as well as the `page_id` of the Facebook page (attached to the bot) to `services.yml`:
156
+ In order to send these metrics, you'll need to include the `app_id` of the bot as well as the `page_id` of the Facebook page (attached to the bot) to `services.yml`:
136
157
 
137
158
  ```yaml
138
159
  default: &default
@@ -150,7 +171,7 @@ Then to collect a metric:
150
171
  Stealth::Services::Facebook::Client.track(recipient_id: u.recipient_id, metric: 'name of your metric', value: 2)
151
172
  ```
152
173
 
153
- To specify additional options:
174
+ You can specify additional options:
154
175
 
155
176
  ```ruby
156
177
  Stealth::Services::Facebook::Client.track(recipient_id: u.recipient_id, metric: 'signup', value: 2, options: { 'fb_description' => 'A signup occured.' })
@@ -181,7 +202,7 @@ Text replies can also include suggestions, which will be rendered as quick repli
181
202
  - text: Red
182
203
  ```
183
204
 
184
- Although not as common, text replies can also include buttons:
205
+ Text replies can also include buttons:
185
206
 
186
207
  ```yaml
187
208
  - reply_type: text
@@ -197,7 +218,9 @@ Although not as common, text replies can also include buttons:
197
218
 
198
219
  ### suggestions
199
220
 
200
- Though suggestions are not a reply type on their own, they are frequently used to optimize the accuracy and speed of your bot. In the `text` reply type above, we used simple labels for our suggestions. Facebook supports a few special types of quick replies, however.
221
+ Though suggestions are not a reply type on their own, they are frequently used to optimize the accuracy and speed of your bot. In the `text` reply type above, we used simple labels for our suggestions. Facebook supports a few special types of quick replies, discussed below.
222
+
223
+ Please note that starting with version `0.17.0` of this gem, quick replies return their response via `current_message.message` as well as `current_message.payload`. Please make sure your `route` method in `BotController` handles that accordingly.
201
224
 
202
225
  #### Location
203
226
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.12.0
1
+ 0.22.0
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'faraday'
4
+ require 'http'
5
5
 
6
6
  require 'stealth/services/facebook/message_handler'
7
7
  require 'stealth/services/facebook/reply_handler'
@@ -10,9 +10,13 @@ require 'stealth/services/facebook/setup'
10
10
  module Stealth
11
11
  module Services
12
12
  module Facebook
13
-
14
13
  class Client < Stealth::Services::BaseClient
15
- FB_ENDPOINT = "https://graph.facebook.com/v2.10/me"
14
+
15
+ FB_ENDPOINT = if ENV['FACEBOOK_API_VERSION'].present?
16
+ "https://graph.facebook.com/v#{ENV['FACEBOOK_API_VERSION']}/me"
17
+ else
18
+ "https://graph.facebook.com/v3.2/me"
19
+ end
16
20
 
17
21
  attr_reader :api_endpoint, :reply
18
22
 
@@ -23,9 +27,34 @@ module Stealth
23
27
  end
24
28
 
25
29
  def transmit
26
- headers = { "Content-Type" => "application/json" }
27
- response = Faraday.post(api_endpoint, reply.to_json, headers)
28
- Stealth::Logger.l(topic: "facebook", message: "Transmitting. Response: #{response.status}: #{response.body}")
30
+ res = self
31
+ .class
32
+ .http_client
33
+ .post(api_endpoint, body: MultiJson.dump(reply))
34
+
35
+ if res.status.client_error? # HTTP 4xx error
36
+ # Messenger error sub-codes (https://developers.facebook.com/docs/messenger-platform/reference/send-api/error-codes)
37
+ case res.body
38
+ when /1545041/
39
+ raise Stealth::Errors::UserOptOut
40
+ when /2018108/
41
+ raise Stealth::Errors::UserOptOut
42
+ when /2018028/
43
+ raise Stealth::Errors::InvalidSessionID.new('Cannot message users who are not admins, developers or testers of the app until pages_messaging permission is reviewed and the app is live.')
44
+ end
45
+ end
46
+
47
+ Stealth::Logger.l(
48
+ topic: "facebook",
49
+ message: "Transmitted. Response: #{res.status.code}: #{res.body}"
50
+ )
51
+ end
52
+
53
+ def self.http_client
54
+ headers = {
55
+ 'Content-Type' => 'application/json'
56
+ }
57
+ HTTP.timeout(connect: 15, read: 60).headers(headers)
29
58
  end
30
59
 
31
60
  def self.fetch_profile(recipient_id:, fields: nil)
@@ -44,13 +73,19 @@ module Stealth
44
73
  query: query_hash.to_query
45
74
  )
46
75
 
47
- response = Faraday.get(uri.to_s)
48
- Stealth::Logger.l(topic: "facebook", message: "Requested user profile for #{recipient_id}. Response: #{response.status}: #{response.body}")
76
+ res = http_client.get(uri.to_s)
77
+ Stealth::Logger.l(topic:
78
+ 'facebook',
79
+ message: "Requested user profile for #{recipient_id}. Response: #{res.status.code}: #{res.body}"
80
+ )
49
81
 
50
- if response.status.in?(200..299)
51
- MultiJson.load(response.body)
82
+ if res.status.success?
83
+ MultiJson.load(res.body.to_s)
52
84
  else
53
- raise(Stealth::Errors::ServiceError, "Facebook error #{response.status}: #{response.body}")
85
+ raise(
86
+ Stealth::Errors::ServiceError,
87
+ "Facebook error #{res.status}: #{res.body}"
88
+ )
54
89
  end
55
90
  end
56
91
 
@@ -77,17 +112,23 @@ module Stealth
77
112
  path: "/#{Stealth.config.facebook.app_id}/activities"
78
113
  )
79
114
 
80
- response = Faraday.post(uri.to_s, params)
81
- Stealth::Logger.l(topic: "facebook", message: "Sending custom event for metric: #{metric} and value: #{value}. Response: #{response.status}: #{response.body}")
115
+ res = http_client.post(uri.to_s, body: MultiJson.dump(params))
116
+ Stealth::Logger.l(
117
+ topic: "facebook",
118
+ message: "Sent custom event for metric: #{metric} and value: #{value}. Response: #{res.status}: #{res.body}"
119
+ )
82
120
 
83
- if response.status.in?(200..299)
84
- MultiJson.load(response.body)
121
+ if res.status.success?
122
+ MultiJson.load(res.body.to_s)
85
123
  else
86
- raise(Stealth::Errors::ServiceError, "Facebook error #{response.status}: #{response.body}")
124
+ raise(
125
+ Stealth::Errors::ServiceError,
126
+ "Facebook error #{res.status}: #{res.body}"
127
+ )
87
128
  end
88
129
  end
89
- end
90
130
 
131
+ end
91
132
  end
92
133
  end
93
134
  end
@@ -23,20 +23,21 @@ module Stealth
23
23
  private
24
24
 
25
25
  def fetch_message
26
- if params['message']['quick_reply'].present?
27
- service_message.message = params['message']['quick_reply']['payload']
28
- elsif params['message']['text'].present?
29
- service_message.message = params['message']['text']
26
+ if params.dig('message', 'quick_reply').present?
27
+ service_message.message = params.dig('message', 'text')
28
+ service_message.payload = params.dig('message', 'quick_reply', 'payload')
29
+ elsif params.dig('message', 'text').present?
30
+ service_message.message = params.dig('message', 'text')
30
31
  end
31
32
  end
32
33
 
33
34
  def fetch_location
34
- if params['message']['attachments'].present? && params['message']['attachments'].is_a?(Array)
35
- params['message']['attachments'].each do |attachment|
35
+ if params.dig('message', 'attachments').present? && params.dig('message', 'attachments').is_a?(Array)
36
+ params.dig('message', 'attachments').each do |attachment|
36
37
  next unless attachment['type'] == 'location'
37
38
 
38
- lat = attachment['payload']['coordinates']['lat']
39
- lng = attachment['payload']['coordinates']['long']
39
+ lat = attachment.dig('payload', 'coordinates', 'lat')
40
+ lng = attachment.dig('payload', 'coordinates', 'long')
40
41
 
41
42
  service_message.location = {
42
43
  lat: lat,
@@ -47,11 +48,21 @@ module Stealth
47
48
  end
48
49
 
49
50
  def fetch_attachments
50
- if params['message']['attachments'].present? && params['message']['attachments'].is_a?(Array)
51
- params['message']['attachments'].each do |attachment|
51
+ if params.dig('message', 'attachments').present? && params.dig('message', 'attachments').is_a?(Array)
52
+ params.dig('message', 'attachments').each do |attachment|
53
+ # Seems to be a bug in Messenger, but in attachments of type `fallback`
54
+ # we are seeing the URL come in at the attachment-level rather than
55
+ # nested within the payload as the API specifies:
56
+ # https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/messages
57
+ payload_url = if attachment.dig('payload', 'url').present?
58
+ attachment['payload']['url']
59
+ else
60
+ attachment['url']
61
+ end
62
+
52
63
  service_message.attachments << {
53
64
  type: attachment['type'],
54
- url: attachment['payload']['url']
65
+ url: payload_url
55
66
  }
56
67
  end
57
68
  end
@@ -0,0 +1,49 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+
5
+
6
+ module Stealth
7
+ module Services
8
+ module Facebook
9
+
10
+ class MessageReadsEvent
11
+
12
+ attr_reader :service_message, :params
13
+
14
+ def initialize(service_message:, params:)
15
+ @service_message = service_message
16
+ @params = params
17
+ end
18
+
19
+ def process
20
+ fetch_read
21
+ end
22
+
23
+ private
24
+
25
+ def fetch_read
26
+ service_message.read = { watermark: get_timestamp, seq: params['read']['seq'] }
27
+ end
28
+
29
+ def get_timestamp
30
+ Time.at(params['read']['watermark']/1000).to_datetime
31
+ end
32
+ end
33
+
34
+ module ReadsEvent
35
+ attr_accessor :read
36
+ def initialize(service:)
37
+ @read = {}
38
+ super
39
+ end
40
+ end
41
+
42
+ end
43
+ end
44
+
45
+
46
+ class ServiceMessage
47
+ prepend Services::Facebook::ReadsEvent
48
+ end
49
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Stealth
5
+ module Services
6
+ module Facebook
7
+
8
+ class MessagingReferralEvent
9
+
10
+ attr_reader :service_message, :params
11
+
12
+ def initialize(service_message:, params:)
13
+ @service_message = service_message
14
+ @params = params
15
+ end
16
+
17
+ def process
18
+ fetch_referral
19
+ end
20
+
21
+ private
22
+
23
+ def fetch_referral
24
+ service_message.referral = params['referral']
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -22,11 +22,11 @@ module Stealth
22
22
  private
23
23
 
24
24
  def fetch_payload
25
- service_message.payload = params['postback']['payload']
25
+ service_message.payload = params.dig('postback', 'payload')
26
26
  end
27
27
 
28
28
  def fetch_referral
29
- service_message.referral = params['postback']['referral']
29
+ service_message.referral = params.dig('postback', 'referral')
30
30
  end
31
31
 
32
32
  end
@@ -3,6 +3,8 @@
3
3
 
4
4
  require 'stealth/services/facebook/events/message_event'
5
5
  require 'stealth/services/facebook/events/postback_event'
6
+ require 'stealth/services/facebook/events/message_reads_event'
7
+ require 'stealth/services/facebook/events/messaging_referral_event'
6
8
 
7
9
  module Stealth
8
10
  module Services
@@ -23,7 +25,11 @@ module Stealth
23
25
  else
24
26
  # Queue the request processing so we can respond quickly to FB
25
27
  # and also keep track of this message
26
- Stealth::Services::HandleMessageJob.perform_async('facebook', params, {})
28
+ Stealth::Services::HandleMessageJob.perform_async(
29
+ 'facebook',
30
+ params,
31
+ headers
32
+ )
27
33
 
28
34
  # Relay our acceptance
29
35
  [200, 'OK']
@@ -34,6 +40,7 @@ module Stealth
34
40
  @service_message = ServiceMessage.new(service: 'facebook')
35
41
  @facebook_message = params['entry'].first['messaging'].first
36
42
  service_message.sender_id = get_sender_id
43
+ service_message.target_id = get_target_id
37
44
  service_message.timestamp = get_timestamp
38
45
  process_facebook_event
39
46
 
@@ -58,6 +65,10 @@ module Stealth
58
65
  facebook_message['sender']['id']
59
66
  end
60
67
 
68
+ def get_target_id
69
+ facebook_message['recipient']['id']
70
+ end
71
+
61
72
  def get_timestamp
62
73
  Time.at(facebook_message['timestamp']/1000).to_datetime
63
74
  end
@@ -73,6 +84,16 @@ module Stealth
73
84
  service_message: service_message,
74
85
  params: facebook_message
75
86
  )
87
+ elsif facebook_message['read'].present?
88
+ message_event = Stealth::Services::Facebook::MessageReadsEvent.new(
89
+ service_message: service_message,
90
+ params: facebook_message
91
+ )
92
+ elsif facebook_message['referral'].present?
93
+ message_event = Stealth::Services::Facebook::MessagingReferralEvent.new(
94
+ service_message: service_message,
95
+ params: facebook_message
96
+ )
76
97
  end
77
98
 
78
99
  message_event.process
@@ -363,6 +363,12 @@ module Stealth
363
363
  quick_reply = { "content_type" => "user_phone_number" }
364
364
  when 'email'
365
365
  quick_reply = { "content_type" => "user_email" }
366
+ when 'birthday'
367
+ quick_reply = { "content_type" => "user_birthday" }
368
+ when 'state'
369
+ quick_reply = { "content_type" => "user_state" }
370
+ when 'zip_code'
371
+ quick_reply = { "content_type" => "user_zip_code" }
366
372
  else
367
373
  quick_reply = {
368
374
  "content_type" => "text",
@@ -391,34 +397,38 @@ module Stealth
391
397
  fb_buttons = buttons.collect do |button|
392
398
  case button['type']
393
399
  when 'url'
394
- button = {
400
+ _button = {
395
401
  "type" => "web_url",
396
402
  "url" => button["url"],
397
403
  "title" => button["text"]
398
404
  }
399
405
 
400
406
  if button["webview_height"].present?
401
- button["webview_height_ratio"] = button["webview_height"]
407
+ _button["webview_height_ratio"] = button["webview_height"]
402
408
  end
403
409
 
404
- button
410
+ if button['messenger_extensions'].present?
411
+ _button['messenger_extensions'] = true
412
+ end
413
+
414
+ _button
405
415
 
406
416
  when 'payload'
407
- button = {
417
+ _button = {
408
418
  "type" => "postback",
409
419
  "payload" => button["payload"],
410
420
  "title" => button["text"]
411
421
  }
412
422
 
413
423
  when 'call'
414
- button = {
424
+ _button = {
415
425
  "type" => "phone_number",
416
426
  "payload" => button["phone_number"],
417
427
  "title" => button["text"]
418
428
  }
419
429
 
420
430
  when 'nested'
421
- button = {
431
+ _button = {
422
432
  "type" => "nested",
423
433
  "title" => button["text"],
424
434
  "call_to_actions" => generate_buttons(buttons: button["buttons"])
@@ -428,7 +438,7 @@ module Stealth
428
438
  raise(Stealth::Errors::ServiceImpaired, "Sorry, we don't yet support #{button["type"]} buttons yet!")
429
439
  end
430
440
 
431
- button
441
+ _button
432
442
  end
433
443
 
434
444
  fb_buttons
@@ -12,8 +12,8 @@ Gem::Specification.new do |s|
12
12
  s.author = 'Mauricio Gomes'
13
13
  s.email = 'mauricio@edge14.com'
14
14
 
15
- s.add_dependency 'stealth', '< 2.0'
16
- s.add_dependency 'faraday', '~> 0.13'
15
+ s.add_dependency 'stealth', '>= 2.0.0.beta'
16
+ s.add_dependency 'http', '~> 4.4'
17
17
 
18
18
  s.add_development_dependency 'rspec', '~> 3.6'
19
19
  s.add_development_dependency 'rspec_junit_formatter', '~> 0.3'
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stealth-facebook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mauricio Gomes
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-14 00:00:00.000000000 Z
11
+ date: 2020-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: stealth
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "<"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '2.0'
19
+ version: 2.0.0.beta
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "<"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '2.0'
26
+ version: 2.0.0.beta
27
27
  - !ruby/object:Gem::Dependency
28
- name: faraday
28
+ name: http
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.13'
33
+ version: '4.4'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0.13'
40
+ version: '4.4'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -98,6 +98,8 @@ files:
98
98
  - lib/stealth/facebook.rb
99
99
  - lib/stealth/services/facebook/client.rb
100
100
  - lib/stealth/services/facebook/events/message_event.rb
101
+ - lib/stealth/services/facebook/events/message_reads_event.rb
102
+ - lib/stealth/services/facebook/events/messaging_referral_event.rb
101
103
  - lib/stealth/services/facebook/events/postback_event.rb
102
104
  - lib/stealth/services/facebook/message_handler.rb
103
105
  - lib/stealth/services/facebook/reply_handler.rb
@@ -110,7 +112,7 @@ homepage: https://github.com/hellostealth/stealth-facebook
110
112
  licenses:
111
113
  - MIT
112
114
  metadata: {}
113
- post_install_message:
115
+ post_install_message:
114
116
  rdoc_options: []
115
117
  require_paths:
116
118
  - lib
@@ -125,9 +127,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
127
  - !ruby/object:Gem::Version
126
128
  version: '0'
127
129
  requirements: []
128
- rubyforge_project:
129
- rubygems_version: 2.7.7
130
- signing_key:
130
+ rubygems_version: 3.1.2
131
+ signing_key:
131
132
  specification_version: 4
132
133
  summary: Stealth Facebook Messenger driver
133
134
  test_files: