fcm 0.0.2 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (8) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +4 -2
  4. data/README.md +95 -29
  5. data/fcm.gemspec +2 -3
  6. data/lib/fcm.rb +93 -17
  7. data/spec/fcm_spec.rb +100 -0
  8. metadata +10 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 54f66db484403cdfb990353ebf8c52553de4beb9
4
- data.tar.gz: 77bdb6784ce6688ee0f3cc468ecf3ab1e7ccd2b4
3
+ metadata.gz: 0d92dc29d8a781ef45a9e3cd113fe834a3a41b63
4
+ data.tar.gz: e3413daa3b418bfbc0631ffdf79f653950599f25
5
5
  SHA512:
6
- metadata.gz: a97f8d1a9d24f436a928f288b302828022bb542529435a155d4758cd014ff19bfd5ce295e746597717d2b45e3e8d6523a97a1336e87555e734c492d31b6252bf
7
- data.tar.gz: dc3ea1cf7d433759648a27e579000616f1fd322bf0d477dd5d67fc39ca7483dc2d12d870856585161d809df3d641c3482f0380af0168b69d1003312a71a30e83
6
+ metadata.gz: 994687542f81b3d11b403d71dde8097a1990445c66249922215da103cff7737d44ee30d99537676cf2695f5606d2837cbb45cfdf59aed2b8c7649290450bf9a1
7
+ data.tar.gz: 1516e659f3c1d7180a77ac177e0f79e4f45d9d471d0f22434533657de07d9de4c29855baf66dcbee003cf9c3b1ac6976ac8a543ca9e75a07b1d9fd04297dfb59
data/.gitignore CHANGED
@@ -48,3 +48,4 @@ specifications
48
48
  Gemfile.lock
49
49
  .rvmrc
50
50
  spec/reports
51
+ *.gem
data/.travis.yml CHANGED
@@ -2,5 +2,7 @@ language: ruby
2
2
  rvm:
3
3
  - 2.0.0
4
4
  - 2.1.10
5
- - 2.2.5
6
- - 2.3.1
5
+ - 2.2.10
6
+ - 2.3.8
7
+ - 2.4.5
8
+ - 2.5.3
data/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # Firebase Cloud Messaging (FCM) for Android and iOS
2
+
2
3
  [![Gem Version](https://badge.fury.io/rb/fcm.svg)](http://badge.fury.io/rb/fcm) [![Build Status](https://secure.travis-ci.org/spacialdb/fcm.png?branch=master)](http://travis-ci.org/spacialdb/fcm)
3
4
 
4
5
  The FCM gem lets your ruby backend send notifications to Android and iOS devices via [
5
6
  Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/).
6
7
 
7
- ##Installation
8
+ ## Installation
8
9
 
9
10
  $ gem install fcm
10
11
 
@@ -14,53 +15,63 @@ or in your `Gemfile` just include it:
14
15
  gem 'fcm'
15
16
  ```
16
17
 
17
- ##Requirements
18
+ ## Requirements
18
19
 
19
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.
20
21
 
21
22
  One of the following, tested Ruby versions:
22
23
 
23
- * `2.0.0`
24
- * `2.1.9`
25
- * `2.2.5`
26
- * `2.3.1`
24
+ - `2.0.0`
25
+ - `2.1.9`
26
+ - `2.2.5`
27
+ - `2.3.1`
27
28
 
28
- ##Usage
29
+ ## Usage
29
30
 
30
- For your server to send a message to one or more devices, you must first initialise a new `FCM` class with your Firebase server Api 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`.
31
+ 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`.
31
32
 
32
33
  Example sending notifications:
33
34
 
34
35
  ```ruby
35
36
  require 'fcm'
36
37
 
37
- fcm = FCM.new("my_api_key")
38
+ fcm = FCM.new("my_server_key")
38
39
  # you can set option parameters in here
39
40
  # - all options are pass to HTTParty method arguments
40
41
  # - ref: https://github.com/jnunemaker/httparty/blob/master/lib/httparty.rb#L29-L60
41
- # fcm = FCM.new("my_api_key", timeout: 3)
42
+ # fcm = FCM.new("my_server_key", timeout: 3)
42
43
 
43
44
  registration_ids= ["12", "13"] # an array of one or more client registration tokens
44
- options = {data: {score: "123"}, collapse_key: "updated_score"}
45
+
46
+ # See https://developers.google.com/cloud-messaging/http for all available options.
47
+ options = { "notification": {
48
+ "title": "Portugal vs. Denmark",
49
+ "text": "5 to 1"
50
+ },
51
+ "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
52
+ }
45
53
  response = fcm.send(registration_ids, options)
46
54
  ```
47
55
 
48
- Currently `response` is just a hash containing the response `body`, `headers` and `status`. Check [here](https://firebase.google.com/docs/cloud-messaging/server#response) to see how to interpret the responses.
56
+ Currently `response` is just a hash containing the response `body`, `headers` and `status_code`. Check [here](https://firebase.google.com/docs/cloud-messaging/server#response) to see how to interpret the responses.
49
57
 
50
58
  ## Device Group Messaging
51
59
 
52
60
  With [device group messaging](https://firebase.google.com/docs/cloud-messaging/notifications), you can send a single message to multiple instance of an app running on devices belonging to a group. Typically, "group" refers a set of different devices that belong to a single user. However, a group could also represent a set of devices where the app instance functions in a highly correlated manner. To use this feature, you will first need an initialised `FCM` class.
53
61
 
54
62
  ### Generate a Notification Key for device group
55
- Then you will need a notification key which you can create for a particular `key_name` which needs to be uniquely named per app in case you have multiple apps for the same `project_id`. This ensures that notifications only go to the intended target app. The `create` method will do this and return the token `notification_key`, that represents the device group, in the response:
63
+
64
+ Then you will need a notification key which you can create for a particular `key_name` which needs to be uniquely named per app in case you have multiple apps for the same `project_id`. This ensures that notifications only go to the intended target app. The `create` method will do this and return the token `notification_key`, that represents the device group, in the response:
56
65
 
57
66
  ```ruby
58
- response = fcm.create(key_name: "appUser-Chris",
67
+ params = {key_name: "appUser-Chris",
59
68
  project_id: "my_project_id",
60
- registration_ids: ["4", "8", "15", "16", "23", "42"])
69
+ registration_ids: ["4", "8", "15", "16", "23", "42"]}
70
+ response = fcm.create(*params.values)
61
71
  ```
62
72
 
63
73
  ### Send to Notification Key
74
+
64
75
  Now you can send a message to a particular `notification_key` via the `send_with_notification_key` method. This allows the server to send a single [data](https://firebase.google.com/docs/cloud-messaging/concept-options#data_messages) payload or/and [notification](https://firebase.google.com/docs/cloud-messaging/concept-options#notifications) payload to multiple app instances (typically on multiple devices) owned by a single user (instead of sending to some registration tokens). Note: the maximum number of members allowed for a `notification_key` is 20.
65
76
 
66
77
  ```ruby
@@ -74,31 +85,85 @@ response = fcm.send_with_notification_key("notification_key",
74
85
  You can also add/remove registration Tokens to/from a particular `notification_key` of some `project_id`. For example:
75
86
 
76
87
  ```ruby
77
- response = fcm.add(key_name: "appUser-Chris",
88
+ params = { key_name: "appUser-Chris",
78
89
  project_id: "my_project_id",
79
90
  notification_key:"appUser-Chris-key",
80
- registration_ids:["7", "3"])
91
+ registration_ids:["7", "3"] }
92
+ response = fcm.add(*params.values)
81
93
 
82
- response = fcm.remove(key_name: "appUser-Chris",
94
+ params = { key_name: "appUser-Chris",
83
95
  project_id: "my_project_id",
84
96
  notification_key:"appUser-Chris-key",
85
- registration_ids:["8", "15"])
97
+ registration_ids:["8", "15"] }
98
+ response = fcm.remove(*params.values)
86
99
  ```
87
100
 
88
101
  ## Send Messages to Topics
89
102
 
90
- FCM [topic messaging](https://firebase.google.com/docs/cloud-messaging/topic-messaging) allows your app server to send a message to multiple devices that have opted in to a particular topic. Based on the publish/subscribe model, topic messaging supports unlimited subscriptions per app. Sending to a topic is very similar to sending to an individual device or to a user group, in the sense that you can use the `fcm.send_with_notification_key()` method where the `noticiation_key` matches the regular expression `"/topics/[a-zA-Z0-9-_.~%]+"`:
103
+ FCM [topic messaging](https://firebase.google.com/docs/cloud-messaging/topic-messaging) allows your app server to send a message to multiple devices that have opted in to a particular topic. Based on the publish/subscribe model, topic messaging supports unlimited subscriptions per app. Sending to a topic is very similar to sending to an individual device or to a user group, in the sense that you can use the `fcm.send_with_notification_key()` method where the `notification_key` matches the regular expression `"/topics/[a-zA-Z0-9-_.~%]+"`:
91
104
 
92
105
  ```ruby
93
106
  response = fcm.send_with_notification_key("/topics/yourTopic",
94
- data: {message: "This is a FCM Topic Message!")
107
+ data: {message: "This is a FCM Topic Message!"})
95
108
  ```
96
109
 
97
110
  Or you can use the helper:
98
111
 
99
112
  ```ruby
100
113
  response = fcm.send_to_topic("yourTopic",
101
- data: {message: "This is a FCM Topic Message!")
114
+ data: {message: "This is a FCM Topic Message!"})
115
+ ```
116
+
117
+ ### Sending to Multiple Topics
118
+
119
+ To send to combinations of multiple topics, the FCM [docs](https://firebase.google.com/docs/cloud-messaging/send-message#send_messages_to_topics_2) require that you set a **condition** key (instead of the `to:` key) to a boolean condition that specifies the target topics. For example, to send messages to devices that subscribed to _TopicA_ and either _TopicB_ or _TopicC_:
120
+
121
+ ```
122
+ 'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)
123
+ ```
124
+
125
+ FCM first evaluates any conditions in parentheses, and then evaluates the expression from left to right. In the above expression, a user subscribed to any single topic does not receive the message. Likewise, a user who does not subscribe to TopicA does not receive the message. These combinations do receive it:
126
+
127
+ - TopicA and TopicB
128
+ - TopicA and TopicC
129
+
130
+ You can include up to five topics in your conditional expression, and parentheses are supported. Supported operators: `&&`, `||`, `!`. Note the usage for !:
131
+
132
+ ```
133
+ !('TopicA' in topics)
134
+ ```
135
+
136
+ With this expression, any app instances that are not subscribed to TopicA, including app instances that are not subscribed to any topic, receive the message.
137
+
138
+ The `send_to_topic_condition` method within this library allows you to specicy a condition of multiple topics to which to send to the data payload.
139
+
140
+ ```ruby
141
+ response = fcm.send_to_topic_condition(
142
+ "'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)",
143
+ data: {
144
+ message: "This is an FCM Topic Message sent to a condition!"
145
+ }
146
+ )
147
+ ```
148
+
149
+ ## Subscribe the client app to a topic
150
+
151
+ Given a registration token and a topic name, you can add the token to the topic using the [Google Instance ID server API](https://developers.google.com/instance-id/reference/server).
152
+
153
+ ```ruby
154
+ topic = "YourTopic"
155
+ registration_id= "12" # a client registration tokens
156
+ response = fcm.topic_subscription(topic, registration_id)
157
+ ```
158
+
159
+ Or you can manage relationship maps for multiple app instances [Google Instance ID server API. Manage relationship](https://developers.google.com/instance-id/reference/server#manage_relationship_maps_for_multiple_app_instances)
160
+
161
+ ```ruby
162
+ topic = "YourTopic"
163
+ registration_ids= ["4", "8", "15", "16", "23", "42"] # an array of one or more client registration tokens
164
+ response = fcm.batch_topic_subscription(topic, registration_ids)
165
+ # or unsubscription
166
+ response = fcm.batch_topic_unsubscription(topic, registration_ids)
102
167
  ```
103
168
 
104
169
  ## Mobile Clients
@@ -111,22 +176,23 @@ The guide to set up an iOS app to get notifications is here: [Setting up a FCM C
111
176
 
112
177
  ### 0.0.2
113
178
 
114
- * Fixed group messaging url.
115
- * Added API to `recover_notification_key`.
179
+ - Fixed group messaging url.
180
+ - Added API to `recover_notification_key`.
116
181
 
117
182
  ### 0.0.1
118
183
 
119
- * Initial version.
184
+ - Initial version.
120
185
 
121
- ##MIT License
186
+ ## MIT License
122
187
 
123
- * Copyright (c) 2016 Kashif Rasul and Shoaib Burq. See LICENSE.txt for details.
188
+ - Copyright (c) 2016 Kashif Rasul and Shoaib Burq. See LICENSE.txt for details.
124
189
 
125
- ##Many thanks to all the contributors
190
+ ## Many thanks to all the contributors
126
191
 
127
- * [Contributors](https://github.com/spacialdb/fcm/contributors)
192
+ - [Contributors](https://github.com/spacialdb/fcm/contributors)
128
193
 
129
194
  ## Donations
195
+
130
196
  We accept tips through [Gratipay](https://gratipay.com/spacialdb/).
131
197
 
132
198
  [![Gratipay](https://img.shields.io/gratipay/spacialdb.svg)](https://www.gittip.com/spacialdb/)
data/fcm.gemspec CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "fcm"
6
- s.version = "0.0.2"
6
+ s.version = "0.0.6"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Kashif Rasul", "Shoaib Burq"]
9
9
  s.email = ["kashif@spacialdb.com", "shoaib@spacialdb.com"]
@@ -21,6 +21,5 @@ Gem::Specification.new do |s|
21
21
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
22
  s.require_paths = ["lib"]
23
23
 
24
- s.add_dependency('httparty')
25
- s.add_dependency('json')
24
+ s.add_runtime_dependency('httparty', '~> 0.10', '>= 0.10.0')
26
25
  end
data/lib/fcm.rb CHANGED
@@ -10,6 +10,8 @@ class FCM
10
10
 
11
11
  # constants
12
12
  GROUP_NOTIFICATION_BASE_URI = 'https://android.googleapis.com/gcm'
13
+ INSTANCE_ID_API = 'https://iid.googleapis.com/iid/v1'
14
+ TOPIC_REGEX = /[a-zA-Z0-9\-_.~%]+/
13
15
 
14
16
  attr_accessor :timeout, :api_key
15
17
 
@@ -18,18 +20,18 @@ class FCM
18
20
  @client_options = client_options
19
21
  end
20
22
 
21
- # {
22
- # "collapse_key": "score_update",
23
- # "time_to_live": 108,
24
- # "delay_while_idle": true,
25
- # "registration_ids": ["4", "8", "15", "16", "23", "42"],
26
- # "data" : {
27
- # "score": "5x1",
28
- # "time": "15:10"
29
- # }
23
+ # See https://developers.google.com/cloud-messaging/http for more details.
24
+ # { "notification": {
25
+ # "title": "Portugal vs. Denmark",
26
+ # "text": "5 to 1"
27
+ # },
28
+ # "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
30
29
  # }
31
30
  # fcm = FCM.new("API_KEY")
32
- # fcm.send(registration_ids: ["4sdsx", "8sdsd"], {data: {score: "5x1"}})
31
+ # fcm.send(
32
+ # ["4sdsx", "8sdsd"], # registration_ids
33
+ # { "notification": { "title": "Portugal vs. Denmark", "text": "5 to 1" }, "to" : "bk3RNwTe3HdFQ3P1..." }
34
+ # )
33
35
  def send_notification(registration_ids, options = {})
34
36
  post_body = build_post_body(registration_ids, options)
35
37
 
@@ -129,32 +131,75 @@ class FCM
129
131
  response = nil
130
132
 
131
133
  for_uri(GROUP_NOTIFICATION_BASE_URI) do
132
- response = self.class.post('/notification', params.merge(@client_options))
134
+ response = self.class.get('/notification', params.merge(@client_options))
133
135
  end
134
136
  build_response(response)
135
137
  end
136
138
 
137
139
  def send_with_notification_key(notification_key, options = {})
138
140
  body = { to: notification_key }.merge(options)
141
+ execute_notification(body)
142
+ end
139
143
 
144
+ def topic_subscription(topic, registration_id)
140
145
  params = {
141
- body: body.to_json,
142
146
  headers: {
143
- 'Authorization' => "key=#{@api_key}",
144
- 'Content-Type' => 'application/json'
147
+ 'Authorization' => "key=#{@api_key}",
148
+ 'Content-Type' => 'application/json'
145
149
  }
146
150
  }
147
151
 
148
- response = self.class.post('/send', params.merge(@client_options))
152
+ response = nil
153
+
154
+ for_uri(INSTANCE_ID_API) do
155
+ response = self.class.post("/#{registration_id}/rel/topics/#{topic}", params)
156
+ end
157
+
158
+ build_response(response)
159
+ end
160
+
161
+ def batch_topic_subscription(topic, registration_ids)
162
+ manage_topics_relationship(topic, registration_ids, 'Add')
163
+ end
164
+
165
+ def batch_topic_unsubscription(topic, registration_ids)
166
+ manage_topics_relationship(topic, registration_ids, 'Remove')
167
+ end
168
+
169
+ def manage_topics_relationship(topic, registration_ids, action)
170
+ body = { to: "/topics/#{topic}", registration_tokens: registration_ids }
171
+ params = {
172
+ body: body.to_json,
173
+ headers: {
174
+ 'Authorization' => "key=#{@api_key}",
175
+ 'Content-Type' => 'application/json'
176
+ }
177
+ }
178
+
179
+ response = nil
180
+
181
+ for_uri(INSTANCE_ID_API) do
182
+ response = self.class.post("/:batch#{action}", params)
183
+ end
184
+
149
185
  build_response(response)
150
186
  end
151
187
 
188
+
189
+
152
190
  def send_to_topic(topic, options = {})
153
- if topic =~ /[a-zA-Z0-9\-_.~%]+/
191
+ if topic.gsub(TOPIC_REGEX, "").length == 0
154
192
  send_with_notification_key('/topics/' + topic, options)
155
193
  end
156
194
  end
157
195
 
196
+ def send_to_topic_condition(condition, options = {})
197
+ if validate_condition?(condition)
198
+ body = { condition: condition }.merge(options)
199
+ execute_notification(body)
200
+ end
201
+ end
202
+
158
203
  private
159
204
 
160
205
  def for_uri(uri)
@@ -165,7 +210,8 @@ class FCM
165
210
  end
166
211
 
167
212
  def build_post_body(registration_ids, options = {})
168
- { registration_ids: registration_ids }.merge(options)
213
+ ids = registration_ids.is_a?(String) ? [registration_ids] : registration_ids
214
+ { registration_ids: ids }.merge(options)
169
215
  end
170
216
 
171
217
  def build_response(response, registration_ids = [])
@@ -213,6 +259,19 @@ class FCM
213
259
  not_registered_ids
214
260
  end
215
261
 
262
+ def execute_notification(body)
263
+ params = {
264
+ body: body.to_json,
265
+ headers: {
266
+ 'Authorization' => "key=#{@api_key}",
267
+ 'Content-Type' => 'application/json'
268
+ }
269
+ }
270
+
271
+ response = self.class.post('/send', params.merge(@client_options))
272
+ build_response(response)
273
+ end
274
+
216
275
  def has_canonical_id?(result)
217
276
  !result['registration_id'].nil?
218
277
  end
@@ -220,4 +279,21 @@ class FCM
220
279
  def is_not_registered?(result)
221
280
  result['error'] == 'NotRegistered'
222
281
  end
282
+
283
+ def validate_condition?(condition)
284
+ validate_condition_format?(condition) && validate_condition_topics?(condition)
285
+ end
286
+
287
+ def validate_condition_format?(condition)
288
+ bad_characters = condition.gsub(
289
+ /(topics|in|\s|\(|\)|(&&)|[!]|(\|\|)|'([a-zA-Z0-9\-_.~%]+)')/,
290
+ ""
291
+ )
292
+ bad_characters.length == 0
293
+ end
294
+
295
+ def validate_condition_topics?(condition)
296
+ topics = condition.scan(/(?:^|\S|\s)'([^']*?)'(?:$|\S|\s)/).flatten
297
+ topics.all? { |topic| topic.gsub(TOPIC_REGEX, "").length == 0 }
298
+ end
223
299
  end
data/spec/fcm_spec.rb CHANGED
@@ -4,10 +4,16 @@ describe FCM do
4
4
  let(:send_url) { "#{FCM.base_uri}/send" }
5
5
  let(:group_notification_base_uri) { "https://android.googleapis.com/gcm/notification" }
6
6
  let(:api_key) { 'AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA' }
7
+ let(:registration_id) { '42' }
7
8
  let(:registration_ids) { ['42'] }
8
9
  let(:key_name) { 'appUser-Chris' }
9
10
  let(:project_id) { "123456789" } # https://developers.google.com/cloud-messaging/gcm#senderid
10
11
  let(:notification_key) { "APA91bGHXQBB...9QgnYOEURwm0I3lmyqzk2TXQ" }
12
+ let(:valid_topic) { "TopicA" }
13
+ let(:invalid_topic) { "TopicA$" }
14
+ let(:valid_condition) { "'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)" }
15
+ let(:invalid_condition) { "'TopicA' in topics and some other text ('TopicB' in topics || 'TopicC' in topics)" }
16
+ let(:invalid_condition_topic) { "'TopicA$' in topics" }
11
17
 
12
18
  it 'should raise an error if the api key is not provided' do
13
19
  expect { FCM.new }.to raise_error(ArgumentError)
@@ -21,6 +27,9 @@ describe FCM do
21
27
  let(:valid_request_body) do
22
28
  { registration_ids: registration_ids }
23
29
  end
30
+ let(:valid_request_body_with_string) do
31
+ { registration_ids: registration_id }
32
+ end
24
33
  let(:valid_request_headers) do
25
34
  {
26
35
  'Content-Type' => 'application/json',
@@ -40,6 +49,17 @@ describe FCM do
40
49
  )
41
50
  end
42
51
 
52
+ let(:stub_fcm_send_request_with_string) do
53
+ stub_request(:post, send_url).with(
54
+ body: valid_request_body_with_string.to_json,
55
+ headers: valid_request_headers
56
+ ).to_return(
57
+ body: '{}',
58
+ headers: {},
59
+ status: 200
60
+ )
61
+ end
62
+
43
63
  let(:stub_fcm_send_request_with_basic_auth) do
44
64
  uri = URI.parse(send_url)
45
65
  uri.user = 'a'
@@ -49,6 +69,7 @@ describe FCM do
49
69
 
50
70
  before(:each) do
51
71
  stub_fcm_send_request
72
+ stub_fcm_send_request_with_string
52
73
  stub_fcm_send_request_with_basic_auth
53
74
  end
54
75
 
@@ -58,6 +79,12 @@ describe FCM do
58
79
  stub_fcm_send_request.should have_been_made.times(1)
59
80
  end
60
81
 
82
+ it 'should send notification using POST to FCM if id provided as string' do
83
+ fcm = FCM.new(api_key)
84
+ fcm.send(registration_id).should eq(response: 'success', body: '{}', headers: {}, status_code: 200, canonical_ids: [], not_registered_ids: [])
85
+ stub_fcm_send_request.should have_been_made.times(1)
86
+ end
87
+
61
88
  context 'send notification with data' do
62
89
  let!(:stub_with_data) do
63
90
  stub_request(:post, send_url)
@@ -74,6 +101,76 @@ describe FCM do
74
101
  end
75
102
  end
76
103
 
104
+ context "sending notification to a topic" do
105
+ let!(:stub_with_valid_topic) do
106
+ stub_request(:post, send_url)
107
+ .with(body: '{"to":"/topics/TopicA","data":{"score":"5x1","time":"15:10"}}',
108
+ headers: valid_request_headers)
109
+ .to_return(status: 200, body: '', headers: {})
110
+ end
111
+ let!(:stub_with_invalid_topic) do
112
+ stub_request(:post, send_url)
113
+ .with(body: '{"condition":"/topics/TopicA$","data":{"score":"5x1","time":"15:10"}}',
114
+ headers: valid_request_headers)
115
+ .to_return(status: 200, body: '', headers: {})
116
+ end
117
+
118
+ describe "#send_to_topic" do
119
+ it 'should send the data in a post request to fcm' do
120
+ fcm = FCM.new(api_key)
121
+ fcm.send_to_topic(valid_topic, data: { score: '5x1', time: '15:10' })
122
+ stub_with_valid_topic.should have_been_requested
123
+ end
124
+
125
+ it 'should not send to invalid topics' do
126
+ fcm = FCM.new(api_key)
127
+ fcm.send_to_topic(invalid_topic, data: { score: '5x1', time: '15:10' })
128
+ stub_with_invalid_topic.should_not have_been_requested
129
+ end
130
+ end
131
+ end
132
+
133
+ context "sending notification to a topic condition" do
134
+ let!(:stub_with_valid_condition) do
135
+ stub_request(:post, send_url)
136
+ .with(body: '{"condition":"\'TopicA\' in topics && (\'TopicB\' in topics || \'TopicC\' in topics)","data":{"score":"5x1","time":"15:10"}}',
137
+ headers: valid_request_headers)
138
+ .to_return(status: 200, body: '', headers: {})
139
+ end
140
+ let!(:stub_with_invalid_condition) do
141
+ stub_request(:post, send_url)
142
+ .with(body: '{"condition":"\'TopicA\' in topics and some other text (\'TopicB\' in topics || \'TopicC\' in topics)","data":{"score":"5x1","time":"15:10"}}',
143
+ headers: valid_request_headers)
144
+ .to_return(status: 200, body: '', headers: {})
145
+ end
146
+ let!(:stub_with_invalid_condition_topic) do
147
+ stub_request(:post, send_url)
148
+ .with(body: '{"condition":"\'TopicA$\' in topics","data":{"score":"5x1","time":"15:10"}}',
149
+ headers: valid_request_headers)
150
+ .to_return(status: 200, body: '', headers: {})
151
+ end
152
+
153
+ describe "#send_to_topic_condition" do
154
+ it 'should send the data in a post request to fcm' do
155
+ fcm = FCM.new(api_key)
156
+ fcm.send_to_topic_condition(valid_condition, data: { score: '5x1', time: '15:10' })
157
+ stub_with_valid_condition.should have_been_requested
158
+ end
159
+
160
+ it 'should not send to invalid conditions' do
161
+ fcm = FCM.new(api_key)
162
+ fcm.send_to_topic_condition(invalid_condition, data: { score: '5x1', time: '15:10' })
163
+ stub_with_invalid_condition.should_not have_been_requested
164
+ end
165
+
166
+ it 'should not send to invalid topics in a condition' do
167
+ fcm = FCM.new(api_key)
168
+ fcm.send_to_topic_condition(invalid_condition_topic, data: { score: '5x1', time: '15:10' })
169
+ stub_with_invalid_condition_topic.should_not have_been_requested
170
+ end
171
+ end
172
+ end
173
+
77
174
  context 'when send_notification responds with failure' do
78
175
  let(:mock_request_attributes) do
79
176
  {
@@ -373,6 +470,9 @@ describe FCM do
373
470
  )
374
471
  end
375
472
  end # remove context
473
+ end
376
474
 
475
+ describe 'subscribing to a topic' do
476
+ # TODO
377
477
  end
378
478
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fcm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kashif Rasul
@@ -9,36 +9,28 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-08-04 00:00:00.000000000 Z
12
+ date: 2018-11-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ">="
18
+ - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '0'
21
- type: :runtime
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
20
+ version: '0.10'
25
21
  - - ">="
26
22
  - !ruby/object:Gem::Version
27
- version: '0'
28
- - !ruby/object:Gem::Dependency
29
- name: json
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: '0'
23
+ version: 0.10.0
35
24
  type: :runtime
36
25
  prerelease: false
37
26
  version_requirements: !ruby/object:Gem::Requirement
38
27
  requirements:
28
+ - - "~>"
29
+ - !ruby/object:Gem::Version
30
+ version: '0.10'
39
31
  - - ">="
40
32
  - !ruby/object:Gem::Version
41
- version: '0'
33
+ version: 0.10.0
42
34
  description: fcm provides ruby bindings to Firebase Cloud Messaging (FCM) a cross-platform
43
35
  messaging solution that lets you reliably deliver messages and notifications at
44
36
  no cost to Android, iOS or Web browsers.
@@ -80,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
72
  version: '0'
81
73
  requirements: []
82
74
  rubyforge_project: fcm
83
- rubygems_version: 2.6.6
75
+ rubygems_version: 2.6.13
84
76
  signing_key:
85
77
  specification_version: 4
86
78
  summary: Reliably deliver messages and notifications via FCM