fcm 1.0.3 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/README.md +51 -3
  4. data/fcm.gemspec +2 -2
  5. data/lib/fcm.rb +115 -54
  6. data/spec/fcm_spec.rb +116 -112
  7. metadata +8 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d8fdd71d844f8b1d91cb5766d8eed454a169cc2656bdd23e3f322f668f7bdb5
4
- data.tar.gz: 3b5993317f23cf026391b3dfe894bcc91343489dbf623bfbce884d8bb6d401d1
3
+ metadata.gz: a3378dc24fca1ced3cbda70c31a427261044eaa4b9d0580884e73981a04b1ce3
4
+ data.tar.gz: 6801d93f67ace2faeda17ad8ccf99b363cc6526a99573d8e5938eca7563e78c5
5
5
  SHA512:
6
- metadata.gz: 39012e9f9197305330a3fddc2af38315be9a42ab7233043efa26ae7e6892cd5f7d197cc9eba5fbbeeae0d24fe93958a55a47f9cada23b345e14781d4fd746467
7
- data.tar.gz: fa8d086deaec08496a9d8ca6f31328ec8ececb44d99b55c6512cfc8a58410f5c4add7e65efae1c9820ca4bb1575998a22d41148b0747fdb2f2aa08b9a76bcdff
6
+ metadata.gz: 657dd3db45b913993cbd876a918ed69affaefe076ca649722c0c6c61937978b20337f8677398f735e7ff40ea983193d58c420811a2ed90778bbe8efc00f4f033
7
+ data.tar.gz: 662b4fc1b8b04962f957518ebaf86d68ca92d905a989e6baed51d4705af55b83f30388030da66237fec93b7fe2d66c0fdd3b14132915e75d0dcccccf312eb58d
data/Gemfile CHANGED
@@ -5,3 +5,4 @@ gem 'rake'
5
5
  gem 'rspec'
6
6
  gem 'webmock'
7
7
  gem 'ci_reporter_rspec'
8
+ gem 'googleauth'
data/README.md CHANGED
@@ -19,13 +19,56 @@ gem 'fcm'
19
19
 
20
20
  For Android you will need a device running 2.3 (or newer) that also have the Google Play Store app installed, or an emulator running Android 2.3 with Google APIs. iOS devices are also supported.
21
21
 
22
-
23
22
  A version of supported Ruby, currently:
24
23
  `ruby >= 2.4`
25
24
 
26
-
27
25
  ## Usage
28
26
 
27
+ ## HTTP v1 API
28
+
29
+ To migrate to HTTP v1 see: https://firebase.google.com/docs/cloud-messaging/migrate-v1
30
+
31
+ ```ruby
32
+ fcm = FCM.new(
33
+ API_TOKEN,
34
+ GOOGLE_APPLICATION_CREDENTIALS_PATH,
35
+ FIREBASE_PROJECT_ID
36
+ )
37
+ message = {
38
+ 'topic': "89023", # OR token if you want to send to a specific device
39
+ # 'token': "000iddqd",
40
+ 'data': {
41
+ payload: {
42
+ data: {
43
+ id: 1
44
+ }
45
+ }.to_json
46
+ },
47
+ 'notification': {
48
+ title: notification.title_th,
49
+ body: notification.body_th,
50
+ },
51
+ 'android': {},
52
+ 'apns': {
53
+ payload: {
54
+ aps: {
55
+ sound: "default",
56
+ category: "#{Time.zone.now.to_i}"
57
+ }
58
+ }
59
+ },
60
+ 'fcm_options': {
61
+ analytics_label: 'Label'
62
+ }
63
+ }
64
+
65
+ fcm.send_v1(message)
66
+ ```
67
+
68
+ ## HTTP Legacy Version
69
+
70
+ To migrate to HTTP v1 see: https://firebase.google.com/docs/cloud-messaging/migrate-v1
71
+
29
72
  For your server to send a message to one or more devices, you must first initialise a new `FCM` class with your Firebase Cloud Messaging server key, and then call the `send` method on this and give it 1 or more (up to 1000) registration tokens as an array of strings. You can also optionally send further [HTTP message parameters](https://firebase.google.com/docs/cloud-messaging/http-server-ref) like `data` or `time_to_live` etc. as a hash via the second optional argument to `send`.
30
73
 
31
74
  Example sending notifications:
@@ -166,6 +209,11 @@ You can find a guide to implement an Android Client app to receive notifications
166
209
  The guide to set up an iOS app to get notifications is here: [Setting up a FCM Client App on iOS](https://firebase.google.com/docs/cloud-messaging/ios/client).
167
210
 
168
211
  ## ChangeLog
212
+
213
+ ### 1.0.3
214
+
215
+ - Fix overly strict faraday depenecy
216
+
169
217
  ### 1.0.2
170
218
 
171
219
  - Bug fix: retrieve notification key" params: https://github.com/spacialdb/fcm/commit/b328a75c11d779a06d0ceda83527e26aa0495774
@@ -202,7 +250,7 @@ Update version in `fcm.gemspec` with `VERSION` and update `README.md` `## Change
202
250
 
203
251
  ```bash
204
252
  # set the version
205
- # VERSION="1.0.3"
253
+ # VERSION="1.0.4"
206
254
  gem build fcm.gemspec
207
255
  git tag -a v${VERSION} -m "Releasing version v${VERSION}"
208
256
  git push origin --tags
data/fcm.gemspec CHANGED
@@ -3,10 +3,10 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "fcm"
6
- s.version = "1.0.3"
6
+ s.version = "1.0.5"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Kashif Rasul", "Shoaib Burq"]
9
- s.email = ["kashif@spacialdb.com", "shoaib@spacialdb.com"]
9
+ s.email = ["kashif@decision-labs.com", "shoaib@decision-labs.com"]
10
10
  s.homepage = "https://github.com/spacialdb/fcm"
11
11
  s.summary = %q{Reliably deliver messages and notifications via FCM}
12
12
  s.description = %q{fcm provides ruby bindings to Firebase Cloud Messaging (FCM) a cross-platform messaging solution that lets you reliably deliver messages and notifications at no cost to Android, iOS or Web browsers.}
data/lib/fcm.rb CHANGED
@@ -1,24 +1,71 @@
1
- require 'faraday'
2
- require 'cgi'
3
- require 'json'
1
+ require "faraday"
2
+ require "cgi"
3
+ require "json"
4
+ require "googleauth"
4
5
 
5
6
  class FCM
6
- BASE_URI = 'https://fcm.googleapis.com'
7
+ BASE_URI = "https://fcm.googleapis.com"
8
+ BASE_URI_V1 = "https://fcm.googleapis.com/v1/projects/"
7
9
  DEFAULT_TIMEOUT = 30
8
10
  FORMAT = :json
9
11
 
10
12
  # constants
11
- GROUP_NOTIFICATION_BASE_URI = 'https://android.googleapis.com'
12
- INSTANCE_ID_API = 'https://iid.googleapis.com'
13
+ GROUP_NOTIFICATION_BASE_URI = "https://android.googleapis.com"
14
+ INSTANCE_ID_API = "https://iid.googleapis.com"
13
15
  TOPIC_REGEX = /[a-zA-Z0-9\-_.~%]+/
14
16
 
15
- attr_accessor :timeout, :api_key
17
+ attr_accessor :timeout, :api_key, :json_key_path, :project_base_uri
16
18
 
17
- def initialize(api_key, client_options = {})
19
+ def initialize(api_key, json_key_path = "", project_name = "", client_options = {})
18
20
  @api_key = api_key
19
21
  @client_options = client_options
22
+ @json_key_path = json_key_path
23
+ @project_base_uri = BASE_URI_V1 + project_name.to_s
20
24
  end
21
25
 
26
+ # See https://firebase.google.com/docs/cloud-messaging/send-message
27
+ # {
28
+ # "token": "4sdsx",
29
+ # "notification": {
30
+ # "title": "Breaking News",
31
+ # "body": "New news story available."
32
+ # },
33
+ # "data": {
34
+ # "story_id": "story_12345"
35
+ # },
36
+ # "android": {
37
+ # "notification": {
38
+ # "click_action": "TOP_STORY_ACTIVITY",
39
+ # "body": "Check out the Top Story"
40
+ # }
41
+ # },
42
+ # "apns": {
43
+ # "payload": {
44
+ # "aps": {
45
+ # "category" : "NEW_MESSAGE_CATEGORY"
46
+ # }
47
+ # }
48
+ # }
49
+ # }
50
+ # fcm = FCM.new(api_key, json_key_path, project_name)
51
+ # fcm.send(
52
+ # { "token": "4sdsx",, "to" : "notification": {}.. }
53
+ # )
54
+ def send_notification_v1(message)
55
+ return if @project_base_uri.empty?
56
+
57
+ post_body = { 'message': message }
58
+
59
+ response = Faraday.post("#{@project_base_uri}/messages:send") do |req|
60
+ req.headers["Content-Type"] = "application/json"
61
+ req.headers["Authorization"] = "Bearer #{jwt_token}"
62
+ req.body = post_body.to_json
63
+ end
64
+ build_response(response)
65
+ end
66
+
67
+ alias send_v1 send_notification_v1
68
+
22
69
  # See https://developers.google.com/cloud-messaging/http for more details.
23
70
  # { "notification": {
24
71
  # "title": "Portugal vs. Denmark",
@@ -35,68 +82,72 @@ class FCM
35
82
  post_body = build_post_body(registration_ids, options)
36
83
 
37
84
  for_uri(BASE_URI) do |connection|
38
- response = connection.post('/fcm/send', post_body.to_json)
85
+ response = connection.post("/fcm/send", post_body.to_json)
39
86
  build_response(response, registration_ids)
40
87
  end
41
88
  end
89
+
42
90
  alias send send_notification
43
91
 
44
92
  def create_notification_key(key_name, project_id, registration_ids = [])
45
- post_body = build_post_body(registration_ids, operation: 'create',
46
- notification_key_name: key_name)
93
+ post_body = build_post_body(registration_ids, operation: "create",
94
+ notification_key_name: key_name)
47
95
 
48
96
  extra_headers = {
49
- 'project_id' => project_id
97
+ "project_id" => project_id,
50
98
  }
51
99
 
52
100
  for_uri(GROUP_NOTIFICATION_BASE_URI, extra_headers) do |connection|
53
- response = connection.post('/gcm/notification', post_body.to_json)
101
+ response = connection.post("/gcm/notification", post_body.to_json)
54
102
  build_response(response)
55
103
  end
56
104
  end
105
+
57
106
  alias create create_notification_key
58
107
 
59
108
  def add_registration_ids(key_name, project_id, notification_key, registration_ids)
60
- post_body = build_post_body(registration_ids, operation: 'add',
61
- notification_key_name: key_name,
62
- notification_key: notification_key)
109
+ post_body = build_post_body(registration_ids, operation: "add",
110
+ notification_key_name: key_name,
111
+ notification_key: notification_key)
63
112
 
64
113
  extra_headers = {
65
- 'project_id' => project_id
114
+ "project_id" => project_id,
66
115
  }
67
116
 
68
117
  for_uri(GROUP_NOTIFICATION_BASE_URI, extra_headers) do |connection|
69
- response = connection.post('/gcm/notification', post_body.to_json)
118
+ response = connection.post("/gcm/notification", post_body.to_json)
70
119
  build_response(response)
71
120
  end
72
121
  end
122
+
73
123
  alias add add_registration_ids
74
124
 
75
125
  def remove_registration_ids(key_name, project_id, notification_key, registration_ids)
76
- post_body = build_post_body(registration_ids, operation: 'remove',
77
- notification_key_name: key_name,
78
- notification_key: notification_key)
126
+ post_body = build_post_body(registration_ids, operation: "remove",
127
+ notification_key_name: key_name,
128
+ notification_key: notification_key)
79
129
 
80
130
  extra_headers = {
81
- 'project_id' => project_id
131
+ "project_id" => project_id,
82
132
  }
83
133
 
84
134
  for_uri(GROUP_NOTIFICATION_BASE_URI, extra_headers) do |connection|
85
- response = connection.post('/gcm/notification', post_body.to_json)
135
+ response = connection.post("/gcm/notification", post_body.to_json)
86
136
  build_response(response)
87
137
  end
88
138
  end
139
+
89
140
  alias remove remove_registration_ids
90
141
 
91
142
  def recover_notification_key(key_name, project_id)
92
- params = {notification_key_name: key_name}
93
-
143
+ params = { notification_key_name: key_name }
144
+
94
145
  extra_headers = {
95
- 'project_id' => project_id
146
+ "project_id" => project_id,
96
147
  }
97
148
 
98
149
  for_uri(GROUP_NOTIFICATION_BASE_URI, extra_headers) do |connection|
99
- response = connection.get('/gcm/notification', params)
150
+ response = connection.get("/gcm/notification", params)
100
151
  build_response(response)
101
152
  end
102
153
  end
@@ -114,11 +165,11 @@ class FCM
114
165
  end
115
166
 
116
167
  def batch_topic_subscription(topic, registration_ids)
117
- manage_topics_relationship(topic, registration_ids, 'Add')
168
+ manage_topics_relationship(topic, registration_ids, "Add")
118
169
  end
119
170
 
120
171
  def batch_topic_unsubscription(topic, registration_ids)
121
- manage_topics_relationship(topic, registration_ids, 'Remove')
172
+ manage_topics_relationship(topic, registration_ids, "Remove")
122
173
  end
123
174
 
124
175
  def manage_topics_relationship(topic, registration_ids, action)
@@ -132,35 +183,35 @@ class FCM
132
183
 
133
184
  def send_to_topic(topic, options = {})
134
185
  if topic.gsub(TOPIC_REGEX, "").length == 0
135
- send_with_notification_key('/topics/' + topic, options)
186
+ send_with_notification_key("/topics/" + topic, options)
136
187
  end
137
188
  end
138
189
 
139
- def get_instance_id_info iid_token, options={}
190
+ def get_instance_id_info(iid_token, options = {})
140
191
  params = {
141
- query: options
192
+ query: options,
142
193
  }
143
-
194
+
144
195
  for_uri(INSTANCE_ID_API) do |connection|
145
- response = connection.get('/iid/info/'+iid_token, params)
196
+ response = connection.get("/iid/info/" + iid_token, params)
146
197
  build_response(response)
147
198
  end
148
199
  end
149
200
 
150
- def subscribe_instance_id_to_topic iid_token, topic_name
201
+ def subscribe_instance_id_to_topic(iid_token, topic_name)
151
202
  batch_subscribe_instance_ids_to_topic([iid_token], topic_name)
152
203
  end
153
204
 
154
- def unsubscribe_instance_id_from_topic iid_token, topic_name
205
+ def unsubscribe_instance_id_from_topic(iid_token, topic_name)
155
206
  batch_unsubscribe_instance_ids_from_topic([iid_token], topic_name)
156
207
  end
157
208
 
158
- def batch_subscribe_instance_ids_to_topic instance_ids, topic_name
159
- manage_topics_relationship(topic_name, instance_ids, 'Add')
209
+ def batch_subscribe_instance_ids_to_topic(instance_ids, topic_name)
210
+ manage_topics_relationship(topic_name, instance_ids, "Add")
160
211
  end
161
212
 
162
- def batch_unsubscribe_instance_ids_from_topic instance_ids, topic_name
163
- manage_topics_relationship(topic_name, instance_ids, 'Remove')
213
+ def batch_unsubscribe_instance_ids_from_topic(instance_ids, topic_name)
214
+ manage_topics_relationship(topic_name, instance_ids, "Remove")
164
215
  end
165
216
 
166
217
  def send_to_topic_condition(condition, options = {})
@@ -174,7 +225,7 @@ class FCM
174
225
 
175
226
  def for_uri(uri, extra_headers = {})
176
227
  connection = ::Faraday.new(:url => uri) do |faraday|
177
- faraday.adapter Faraday.default_adapter
228
+ faraday.adapter Faraday.default_adapter
178
229
  faraday.headers["Content-Type"] = "application/json"
179
230
  faraday.headers["Authorization"] = "key=#{api_key}"
180
231
  extra_headers.each do |key, value|
@@ -194,18 +245,18 @@ class FCM
194
245
  response_hash = { body: body, headers: response.headers, status_code: response.status }
195
246
  case response.status
196
247
  when 200
197
- response_hash[:response] = 'success'
248
+ response_hash[:response] = "success"
198
249
  body = JSON.parse(body) unless body.empty?
199
250
  response_hash[:canonical_ids] = build_canonical_ids(body, registration_ids) unless registration_ids.empty?
200
251
  response_hash[:not_registered_ids] = build_not_registered_ids(body, registration_ids) unless registration_ids.empty?
201
252
  when 400
202
- response_hash[:response] = 'Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields.'
253
+ response_hash[:response] = "Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields."
203
254
  when 401
204
- response_hash[:response] = 'There was an error authenticating the sender account.'
255
+ response_hash[:response] = "There was an error authenticating the sender account."
205
256
  when 503
206
- response_hash[:response] = 'Server is temporarily unavailable.'
257
+ response_hash[:response] = "Server is temporarily unavailable."
207
258
  when 500..599
208
- response_hash[:response] = 'There was an internal error in the FCM server while trying to process the request.'
259
+ response_hash[:response] = "There was an internal error in the FCM server while trying to process the request."
209
260
  end
210
261
  response_hash
211
262
  end
@@ -213,9 +264,9 @@ class FCM
213
264
  def build_canonical_ids(body, registration_ids)
214
265
  canonical_ids = []
215
266
  unless body.empty?
216
- if body['canonical_ids'] > 0
217
- body['results'].each_with_index do |result, index|
218
- canonical_ids << { old: registration_ids[index], new: result['registration_id'] } if has_canonical_id?(result)
267
+ if body["canonical_ids"] > 0
268
+ body["results"].each_with_index do |result, index|
269
+ canonical_ids << { old: registration_ids[index], new: result["registration_id"] } if has_canonical_id?(result)
219
270
  end
220
271
  end
221
272
  end
@@ -225,8 +276,8 @@ class FCM
225
276
  def build_not_registered_ids(body, registration_id)
226
277
  not_registered_ids = []
227
278
  unless body.empty?
228
- if body['failure'] > 0
229
- body['results'].each_with_index do |result, index|
279
+ if body["failure"] > 0
280
+ body["results"].each_with_index do |result, index|
230
281
  not_registered_ids << registration_id[index] if is_not_registered?(result)
231
282
  end
232
283
  end
@@ -236,17 +287,17 @@ class FCM
236
287
 
237
288
  def execute_notification(body)
238
289
  for_uri(BASE_URI) do |connection|
239
- response = connection.post('/fcm/send', body.to_json)
290
+ response = connection.post("/fcm/send", body.to_json)
240
291
  build_response(response)
241
292
  end
242
293
  end
243
294
 
244
295
  def has_canonical_id?(result)
245
- !result['registration_id'].nil?
296
+ !result["registration_id"].nil?
246
297
  end
247
298
 
248
299
  def is_not_registered?(result)
249
- result['error'] == 'NotRegistered'
300
+ result["error"] == "NotRegistered"
250
301
  end
251
302
 
252
303
  def validate_condition?(condition)
@@ -265,4 +316,14 @@ class FCM
265
316
  topics = condition.scan(/(?:^|\S|\s)'([^']*?)'(?:$|\S|\s)/).flatten
266
317
  topics.all? { |topic| topic.gsub(TOPIC_REGEX, "").length == 0 }
267
318
  end
319
+
320
+ def jwt_token
321
+ scope = "https://www.googleapis.com/auth/firebase.messaging"
322
+ authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
323
+ json_key_io: File.open(@json_key_path),
324
+ scope: scope,
325
+ )
326
+ token = authorizer.fetch_access_token!
327
+ token["access_token"]
328
+ end
268
329
  end
data/spec/fcm_spec.rb CHANGED
@@ -1,12 +1,12 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
3
  describe FCM do
4
4
  let(:send_url) { "#{FCM::BASE_URI}/fcm/send" }
5
5
  let(:group_notification_base_uri) { "#{FCM::GROUP_NOTIFICATION_BASE_URI}/gcm/notification" }
6
- let(:api_key) { 'AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA' }
7
- let(:registration_id) { '42' }
8
- let(:registration_ids) { ['42'] }
9
- let(:key_name) { 'appUser-Chris' }
6
+ let(:api_key) { "AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA" }
7
+ let(:registration_id) { "42" }
8
+ let(:registration_ids) { ["42"] }
9
+ let(:key_name) { "appUser-Chris" }
10
10
  let(:project_id) { "123456789" } # https://developers.google.com/cloud-messaging/gcm#senderid
11
11
  let(:notification_key) { "APA91bGHXQBB...9QgnYOEURwm0I3lmyqzk2TXQ" }
12
12
  let(:valid_topic) { "TopicA" }
@@ -15,15 +15,19 @@ describe FCM do
15
15
  let(:invalid_condition) { "'TopicA' in topics and some other text ('TopicB' in topics || 'TopicC' in topics)" }
16
16
  let(:invalid_condition_topic) { "'TopicA$' in topics" }
17
17
 
18
- it 'should raise an error if the api key is not provided' do
18
+ it "should raise an error if the api key is not provided" do
19
19
  expect { FCM.new }.to raise_error(ArgumentError)
20
20
  end
21
21
 
22
- it 'should raise error if time_to_live is given' do
22
+ it "should raise error if time_to_live is given" do
23
23
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#ttl
24
24
  end
25
25
 
26
- describe 'sending notification' do
26
+ describe "#send_v1" do
27
+ pending "should send message"
28
+ end
29
+
30
+ describe "sending notification" do
27
31
  let(:valid_request_body) do
28
32
  { registration_ids: registration_ids }
29
33
  end
@@ -32,39 +36,39 @@ describe FCM do
32
36
  end
33
37
  let(:valid_request_headers) do
34
38
  {
35
- 'Content-Type' => 'application/json',
36
- 'Authorization' => "key=#{api_key}"
39
+ "Content-Type" => "application/json",
40
+ "Authorization" => "key=#{api_key}",
37
41
  }
38
42
  end
39
43
 
40
44
  let(:stub_fcm_send_request) do
41
45
  stub_request(:post, send_url).with(
42
46
  body: valid_request_body.to_json,
43
- headers: valid_request_headers
47
+ headers: valid_request_headers,
44
48
  ).to_return(
45
49
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
46
- body: '{}',
50
+ body: "{}",
47
51
  headers: {},
48
- status: 200
52
+ status: 200,
49
53
  )
50
54
  end
51
55
 
52
56
  let(:stub_fcm_send_request_with_string) do
53
57
  stub_request(:post, send_url).with(
54
58
  body: valid_request_body_with_string.to_json,
55
- headers: valid_request_headers
59
+ headers: valid_request_headers,
56
60
  ).to_return(
57
- body: '{}',
61
+ body: "{}",
58
62
  headers: {},
59
- status: 200
63
+ status: 200,
60
64
  )
61
65
  end
62
66
 
63
67
  let(:stub_fcm_send_request_with_basic_auth) do
64
68
  uri = URI.parse(send_url)
65
- uri.user = 'a'
66
- uri.password = 'b'
67
- stub_request(:post, uri.to_s).to_return(body: '{}', headers: {}, status: 200)
69
+ uri.user = "a"
70
+ uri.password = "b"
71
+ stub_request(:post, uri.to_s).to_return(body: "{}", headers: {}, status: 200)
68
72
  end
69
73
 
70
74
  before(:each) do
@@ -73,30 +77,30 @@ describe FCM do
73
77
  stub_fcm_send_request_with_basic_auth
74
78
  end
75
79
 
76
- it 'should send notification using POST to FCM server' do
80
+ it "should send notification using POST to FCM server" do
77
81
  fcm = FCM.new(api_key)
78
- fcm.send(registration_ids).should eq(response: 'success', body: '{}', headers: {}, status_code: 200, canonical_ids: [], not_registered_ids: [])
82
+ fcm.send(registration_ids).should eq(response: "success", body: "{}", headers: {}, status_code: 200, canonical_ids: [], not_registered_ids: [])
79
83
  stub_fcm_send_request.should have_been_made.times(1)
80
84
  end
81
85
 
82
- it 'should send notification using POST to FCM if id provided as string' do
86
+ it "should send notification using POST to FCM if id provided as string" do
83
87
  fcm = FCM.new(api_key)
84
- fcm.send(registration_id).should eq(response: 'success', body: '{}', headers: {}, status_code: 200, canonical_ids: [], not_registered_ids: [])
88
+ fcm.send(registration_id).should eq(response: "success", body: "{}", headers: {}, status_code: 200, canonical_ids: [], not_registered_ids: [])
85
89
  stub_fcm_send_request.should have_been_made.times(1)
86
90
  end
87
91
 
88
- context 'send notification with data' do
92
+ context "send notification with data" do
89
93
  let!(:stub_with_data) do
90
94
  stub_request(:post, send_url)
91
95
  .with(body: '{"registration_ids":["42"],"data":{"score":"5x1","time":"15:10"}}',
92
96
  headers: valid_request_headers)
93
- .to_return(status: 200, body: '', headers: {})
97
+ .to_return(status: 200, body: "", headers: {})
94
98
  end
95
99
  before do
96
100
  end
97
- it 'should send the data in a post request to fcm' do
101
+ it "should send the data in a post request to fcm" do
98
102
  fcm = FCM.new(api_key)
99
- fcm.send(registration_ids, data: { score: '5x1', time: '15:10' })
103
+ fcm.send(registration_ids, data: { score: "5x1", time: "15:10" })
100
104
  stub_with_data.should have_been_requested
101
105
  end
102
106
  end
@@ -106,25 +110,25 @@ describe FCM do
106
110
  stub_request(:post, send_url)
107
111
  .with(body: '{"to":"/topics/TopicA","data":{"score":"5x1","time":"15:10"}}',
108
112
  headers: valid_request_headers)
109
- .to_return(status: 200, body: '', headers: {})
113
+ .to_return(status: 200, body: "", headers: {})
110
114
  end
111
115
  let!(:stub_with_invalid_topic) do
112
116
  stub_request(:post, send_url)
113
117
  .with(body: '{"condition":"/topics/TopicA$","data":{"score":"5x1","time":"15:10"}}',
114
118
  headers: valid_request_headers)
115
- .to_return(status: 200, body: '', headers: {})
119
+ .to_return(status: 200, body: "", headers: {})
116
120
  end
117
121
 
118
122
  describe "#send_to_topic" do
119
- it 'should send the data in a post request to fcm' do
123
+ it "should send the data in a post request to fcm" do
120
124
  fcm = FCM.new(api_key)
121
- fcm.send_to_topic(valid_topic, data: { score: '5x1', time: '15:10' })
125
+ fcm.send_to_topic(valid_topic, data: { score: "5x1", time: "15:10" })
122
126
  stub_with_valid_topic.should have_been_requested
123
127
  end
124
128
 
125
- it 'should not send to invalid topics' do
129
+ it "should not send to invalid topics" do
126
130
  fcm = FCM.new(api_key)
127
- fcm.send_to_topic(invalid_topic, data: { score: '5x1', time: '15:10' })
131
+ fcm.send_to_topic(invalid_topic, data: { score: "5x1", time: "15:10" })
128
132
  stub_with_invalid_topic.should_not have_been_requested
129
133
  end
130
134
  end
@@ -135,143 +139,143 @@ describe FCM do
135
139
  stub_request(:post, send_url)
136
140
  .with(body: '{"condition":"\'TopicA\' in topics && (\'TopicB\' in topics || \'TopicC\' in topics)","data":{"score":"5x1","time":"15:10"}}',
137
141
  headers: valid_request_headers)
138
- .to_return(status: 200, body: '', headers: {})
142
+ .to_return(status: 200, body: "", headers: {})
139
143
  end
140
144
  let!(:stub_with_invalid_condition) do
141
145
  stub_request(:post, send_url)
142
146
  .with(body: '{"condition":"\'TopicA\' in topics and some other text (\'TopicB\' in topics || \'TopicC\' in topics)","data":{"score":"5x1","time":"15:10"}}',
143
147
  headers: valid_request_headers)
144
- .to_return(status: 200, body: '', headers: {})
148
+ .to_return(status: 200, body: "", headers: {})
145
149
  end
146
150
  let!(:stub_with_invalid_condition_topic) do
147
151
  stub_request(:post, send_url)
148
152
  .with(body: '{"condition":"\'TopicA$\' in topics","data":{"score":"5x1","time":"15:10"}}',
149
153
  headers: valid_request_headers)
150
- .to_return(status: 200, body: '', headers: {})
154
+ .to_return(status: 200, body: "", headers: {})
151
155
  end
152
156
 
153
157
  describe "#send_to_topic_condition" do
154
- it 'should send the data in a post request to fcm' do
158
+ it "should send the data in a post request to fcm" do
155
159
  fcm = FCM.new(api_key)
156
- fcm.send_to_topic_condition(valid_condition, data: { score: '5x1', time: '15:10' })
160
+ fcm.send_to_topic_condition(valid_condition, data: { score: "5x1", time: "15:10" })
157
161
  stub_with_valid_condition.should have_been_requested
158
162
  end
159
163
 
160
- it 'should not send to invalid conditions' do
164
+ it "should not send to invalid conditions" do
161
165
  fcm = FCM.new(api_key)
162
- fcm.send_to_topic_condition(invalid_condition, data: { score: '5x1', time: '15:10' })
166
+ fcm.send_to_topic_condition(invalid_condition, data: { score: "5x1", time: "15:10" })
163
167
  stub_with_invalid_condition.should_not have_been_requested
164
168
  end
165
169
 
166
- it 'should not send to invalid topics in a condition' do
170
+ it "should not send to invalid topics in a condition" do
167
171
  fcm = FCM.new(api_key)
168
- fcm.send_to_topic_condition(invalid_condition_topic, data: { score: '5x1', time: '15:10' })
172
+ fcm.send_to_topic_condition(invalid_condition_topic, data: { score: "5x1", time: "15:10" })
169
173
  stub_with_invalid_condition_topic.should_not have_been_requested
170
174
  end
171
175
  end
172
176
  end
173
177
 
174
- context 'when send_notification responds with failure' do
178
+ context "when send_notification responds with failure" do
175
179
  let(:mock_request_attributes) do
176
180
  {
177
181
  body: valid_request_body.to_json,
178
- headers: valid_request_headers
182
+ headers: valid_request_headers,
179
183
  }
180
184
  end
181
185
 
182
186
  subject { FCM.new(api_key) }
183
187
 
184
- context 'on failure code 400' do
188
+ context "on failure code 400" do
185
189
  before do
186
190
  stub_request(:post, send_url).with(
187
191
  mock_request_attributes
188
192
  ).to_return(
189
193
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
190
- body: '{}',
194
+ body: "{}",
191
195
  headers: {},
192
- status: 400
196
+ status: 400,
193
197
  )
194
198
  end
195
- it 'should not send notification due to 400' do
196
- subject.send(registration_ids).should eq(body: '{}',
199
+ it "should not send notification due to 400" do
200
+ subject.send(registration_ids).should eq(body: "{}",
197
201
  headers: {},
198
- response: 'Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields.',
202
+ response: "Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields.",
199
203
  status_code: 400)
200
204
  end
201
205
  end
202
206
 
203
- context 'on failure code 401' do
207
+ context "on failure code 401" do
204
208
  before do
205
209
  stub_request(:post, send_url).with(
206
210
  mock_request_attributes
207
211
  ).to_return(
208
212
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
209
- body: '{}',
213
+ body: "{}",
210
214
  headers: {},
211
- status: 401
215
+ status: 401,
212
216
  )
213
217
  end
214
218
 
215
- it 'should not send notification due to 401' do
216
- subject.send(registration_ids).should eq(body: '{}',
219
+ it "should not send notification due to 401" do
220
+ subject.send(registration_ids).should eq(body: "{}",
217
221
  headers: {},
218
- response: 'There was an error authenticating the sender account.',
222
+ response: "There was an error authenticating the sender account.",
219
223
  status_code: 401)
220
224
  end
221
225
  end
222
226
 
223
- context 'on failure code 503' do
227
+ context "on failure code 503" do
224
228
  before do
225
229
  stub_request(:post, send_url).with(
226
230
  mock_request_attributes
227
231
  ).to_return(
228
232
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
229
- body: '{}',
233
+ body: "{}",
230
234
  headers: {},
231
- status: 503
235
+ status: 503,
232
236
  )
233
237
  end
234
238
 
235
- it 'should not send notification due to 503' do
236
- subject.send(registration_ids).should eq(body: '{}',
239
+ it "should not send notification due to 503" do
240
+ subject.send(registration_ids).should eq(body: "{}",
237
241
  headers: {},
238
- response: 'Server is temporarily unavailable.',
242
+ response: "Server is temporarily unavailable.",
239
243
  status_code: 503)
240
244
  end
241
245
  end
242
246
 
243
- context 'on failure code 5xx' do
247
+ context "on failure code 5xx" do
244
248
  before do
245
249
  stub_request(:post, send_url).with(
246
250
  mock_request_attributes
247
251
  ).to_return(
248
252
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
249
253
  body: '{"body-key" => "Body value"}',
250
- headers: { 'header-key' => 'Header value' },
251
- status: 599
254
+ headers: { "header-key" => "Header value" },
255
+ status: 599,
252
256
  )
253
257
  end
254
258
 
255
- it 'should not send notification due to 599' do
259
+ it "should not send notification due to 599" do
256
260
  subject.send(registration_ids).should eq(body: '{"body-key" => "Body value"}',
257
- headers: { 'header-key' => 'Header value' },
258
- response: 'There was an internal error in the FCM server while trying to process the request.',
261
+ headers: { "header-key" => "Header value" },
262
+ response: "There was an internal error in the FCM server while trying to process the request.",
259
263
  status_code: 599)
260
264
  end
261
265
  end
262
266
  end
263
267
 
264
- context 'when send_notification responds canonical_ids' do
268
+ context "when send_notification responds canonical_ids" do
265
269
  let(:mock_request_attributes) do
266
270
  {
267
271
  body: valid_request_body.to_json,
268
- headers: valid_request_headers
272
+ headers: valid_request_headers,
269
273
  }
270
274
  end
271
275
 
272
276
  let(:valid_response_body_with_canonical_ids) do
273
277
  {
274
- failure: 0, canonical_ids: 1, results: [{ registration_id: '43', message_id: '0:1385025861956342%572c22801bb3' }]
278
+ failure: 0, canonical_ids: 1, results: [{ registration_id: "43", message_id: "0:1385025861956342%572c22801bb3" }],
275
279
  }
276
280
  end
277
281
 
@@ -284,35 +288,35 @@ describe FCM do
284
288
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
285
289
  body: valid_response_body_with_canonical_ids.to_json,
286
290
  headers: {},
287
- status: 200
291
+ status: 200,
288
292
  )
289
293
  end
290
294
 
291
- it 'should contain canonical_ids' do
295
+ it "should contain canonical_ids" do
292
296
  response = subject.send(registration_ids)
293
297
 
294
298
  response.should eq(headers: {},
295
- canonical_ids: [{ old: '42', new: '43' }],
299
+ canonical_ids: [{ old: "42", new: "43" }],
296
300
  not_registered_ids: [],
297
301
  status_code: 200,
298
- response: 'success',
302
+ response: "success",
299
303
  body: '{"failure":0,"canonical_ids":1,"results":[{"registration_id":"43","message_id":"0:1385025861956342%572c22801bb3"}]}')
300
304
  end
301
305
  end
302
306
 
303
- context 'when send_notification responds with NotRegistered' do
307
+ context "when send_notification responds with NotRegistered" do
304
308
  subject { FCM.new(api_key) }
305
309
 
306
310
  let(:mock_request_attributes) do
307
311
  {
308
312
  body: valid_request_body.to_json,
309
- headers: valid_request_headers
313
+ headers: valid_request_headers,
310
314
  }
311
315
  end
312
316
 
313
317
  let(:valid_response_body_with_not_registered_ids) do
314
318
  {
315
- canonical_ids: 0, failure: 1, results: [{ error: 'NotRegistered' }]
319
+ canonical_ids: 0, failure: 1, results: [{ error: "NotRegistered" }],
316
320
  }
317
321
  end
318
322
 
@@ -322,31 +326,31 @@ describe FCM do
322
326
  ).to_return(
323
327
  body: valid_response_body_with_not_registered_ids.to_json,
324
328
  headers: {},
325
- status: 200
329
+ status: 200,
326
330
  )
327
331
  end
328
332
 
329
- it 'should contain not_registered_ids' do
333
+ it "should contain not_registered_ids" do
330
334
  response = subject.send(registration_ids)
331
335
  response.should eq(
332
336
  headers: {},
333
337
  canonical_ids: [],
334
338
  not_registered_ids: registration_ids,
335
339
  status_code: 200,
336
- response: 'success',
337
- body: '{"canonical_ids":0,"failure":1,"results":[{"error":"NotRegistered"}]}'
340
+ response: "success",
341
+ body: '{"canonical_ids":0,"failure":1,"results":[{"error":"NotRegistered"}]}',
338
342
  )
339
343
  end
340
344
  end
341
345
  end
342
346
 
343
- describe 'sending group notifications' do
347
+ describe "sending group notifications" do
344
348
  # TODO: refactor to should_behave_like
345
349
  let(:valid_request_headers) do
346
350
  {
347
351
  "Authorization" => "key=#{api_key}",
348
- "Content-Type" => 'application/json',
349
- "Project-Id" => project_id
352
+ "Content-Type" => "application/json",
353
+ "Project-Id" => project_id,
350
354
  }
351
355
  end
352
356
  let(:valid_response_body) do
@@ -357,24 +361,24 @@ describe FCM do
357
361
  {
358
362
  registration_ids: registration_ids,
359
363
  operation: "create",
360
- notification_key_name: key_name
364
+ notification_key_name: key_name,
361
365
  }
362
366
  end
363
367
 
364
368
  subject { FCM.new(api_key) }
365
369
 
366
370
  # ref: https://firebase.google.com/docs/cloud-messaging/notifications#managing-device-groups-on-the-app-server
367
- context 'create' do
371
+ context "create" do
368
372
  let(:valid_request_body) do
369
373
  default_valid_request_body.merge({
370
- operation: "create"
374
+ operation: "create",
371
375
  })
372
376
  end
373
377
 
374
378
  let(:mock_request_attributes) do
375
379
  {
376
380
  body: valid_request_body.to_json,
377
- headers: valid_request_headers
381
+ headers: valid_request_headers,
378
382
  }
379
383
  end
380
384
 
@@ -384,33 +388,33 @@ describe FCM do
384
388
  ).to_return(
385
389
  body: valid_response_body.to_json,
386
390
  headers: {},
387
- status: 200
391
+ status: 200,
388
392
  )
389
393
  end
390
394
 
391
- it 'should send a post request' do
395
+ it "should send a post request" do
392
396
  response = subject.create(key_name, project_id, registration_ids)
393
397
  response.should eq(
394
398
  headers: {},
395
399
  status_code: 200,
396
- response: 'success',
397
- body: valid_response_body.to_json
400
+ response: "success",
401
+ body: valid_response_body.to_json,
398
402
  )
399
403
  end
400
404
  end # create context
401
405
 
402
- context 'add' do
406
+ context "add" do
403
407
  let(:valid_request_body) do
404
408
  default_valid_request_body.merge({
405
409
  operation: "add",
406
- notification_key: notification_key
410
+ notification_key: notification_key,
407
411
  })
408
412
  end
409
413
 
410
414
  let(:mock_request_attributes) do
411
415
  {
412
416
  body: valid_request_body.to_json,
413
- headers: valid_request_headers
417
+ headers: valid_request_headers,
414
418
  }
415
419
  end
416
420
 
@@ -420,33 +424,33 @@ describe FCM do
420
424
  ).to_return(
421
425
  body: valid_response_body.to_json,
422
426
  headers: {},
423
- status: 200
427
+ status: 200,
424
428
  )
425
429
  end
426
430
 
427
- it 'should send a post request' do
431
+ it "should send a post request" do
428
432
  response = subject.add(key_name, project_id, notification_key, registration_ids)
429
433
  response.should eq(
430
434
  headers: {},
431
435
  status_code: 200,
432
- response: 'success',
433
- body: valid_response_body.to_json
436
+ response: "success",
437
+ body: valid_response_body.to_json,
434
438
  )
435
439
  end
436
440
  end # add context
437
441
 
438
- context 'remove' do
442
+ context "remove" do
439
443
  let(:valid_request_body) do
440
444
  default_valid_request_body.merge({
441
445
  operation: "remove",
442
- notification_key: notification_key
446
+ notification_key: notification_key,
443
447
  })
444
448
  end
445
449
 
446
450
  let(:mock_request_attributes) do
447
451
  {
448
452
  body: valid_request_body.to_json,
449
- headers: valid_request_headers
453
+ headers: valid_request_headers,
450
454
  }
451
455
  end
452
456
 
@@ -456,17 +460,17 @@ describe FCM do
456
460
  ).to_return(
457
461
  body: valid_response_body.to_json,
458
462
  headers: {},
459
- status: 200
463
+ status: 200,
460
464
  )
461
465
  end
462
466
 
463
- it 'should send a post request' do
467
+ it "should send a post request" do
464
468
  response = subject.remove(key_name, project_id, notification_key, registration_ids)
465
469
  response.should eq(
466
470
  headers: {},
467
471
  status_code: 200,
468
- response: 'success',
469
- body: valid_response_body.to_json
472
+ response: "success",
473
+ body: valid_response_body.to_json,
470
474
  )
471
475
  end
472
476
  end # remove context
@@ -477,11 +481,11 @@ describe FCM do
477
481
  uri = "#{FCM::GROUP_NOTIFICATION_BASE_URI}/gcm/notification"
478
482
  endpoint = stub_request(:get, uri).with(
479
483
  headers: {
480
- 'Content-Type' => 'application/json',
481
- 'Authorization' => "key=TEST_SERVER_KEY",
482
- 'project_id' => "TEST_PROJECT_ID"
484
+ "Content-Type" => "application/json",
485
+ "Authorization" => "key=TEST_SERVER_KEY",
486
+ "project_id" => "TEST_PROJECT_ID",
483
487
  },
484
- query: {notification_key_name: "TEST_KEY_NAME"}
488
+ query: { notification_key_name: "TEST_KEY_NAME" },
485
489
  )
486
490
  client = FCM.new("TEST_SERVER_KEY")
487
491
 
@@ -491,7 +495,7 @@ describe FCM do
491
495
  end
492
496
  end
493
497
 
494
- describe 'subscribing to a topic' do
498
+ describe "subscribing to a topic" do
495
499
  # TODO
496
500
  end
497
501
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fcm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kashif Rasul
8
8
  - Shoaib Burq
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-06-03 00:00:00.000000000 Z
12
+ date: 2021-11-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -29,8 +29,8 @@ description: fcm provides ruby bindings to Firebase Cloud Messaging (FCM) a cros
29
29
  messaging solution that lets you reliably deliver messages and notifications at
30
30
  no cost to Android, iOS or Web browsers.
31
31
  email:
32
- - kashif@spacialdb.com
33
- - shoaib@spacialdb.com
32
+ - kashif@decision-labs.com
33
+ - shoaib@decision-labs.com
34
34
  executables: []
35
35
  extensions: []
36
36
  extra_rdoc_files: []
@@ -50,7 +50,7 @@ homepage: https://github.com/spacialdb/fcm
50
50
  licenses:
51
51
  - MIT
52
52
  metadata: {}
53
- post_install_message:
53
+ post_install_message:
54
54
  rdoc_options: []
55
55
  require_paths:
56
56
  - lib
@@ -65,8 +65,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
65
  - !ruby/object:Gem::Version
66
66
  version: '0'
67
67
  requirements: []
68
- rubygems_version: 3.0.3
69
- signing_key:
68
+ rubygems_version: 3.0.3.1
69
+ signing_key:
70
70
  specification_version: 4
71
71
  summary: Reliably deliver messages and notifications via FCM
72
72
  test_files: