fcm 1.0.1 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/Gemfile +1 -0
- data/README.md +70 -16
- data/fcm.gemspec +4 -3
- data/lib/fcm.rb +115 -58
- data/spec/fcm_spec.rb +131 -108
- metadata +21 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 48d3208b5ed6d6f6428d43cc5fbe2d9181e84c1c4a8b28a6947657308bac989d
|
4
|
+
data.tar.gz: d808e663adaf6b963db7eadffab53ff3f9421af9a25aa5de652677b4259d7610
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cdd5cb73c5740dfddb78aef4e1c432121e44908cf09d5c285b13ab10ab79f6a653ca0f09eaa85ff43a532cc3f3e678cd8fa14fb6c327b5a7b32217ff61d45ce
|
7
|
+
data.tar.gz: af7a744e9e9c02a0ba64075788bcb71da12689007ee9fcdaa7d0d0c42968ea0b0f22e972f562b5b11f30d77a3b200d4e0d1ede3ca48b40325a4032e84abb3e26
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Firebase Cloud Messaging (FCM) for Android and iOS
|
2
2
|
|
3
|
-
[](http://badge.fury.io/rb/fcm) [](http://badge.fury.io/rb/fcm) [](http://travis-ci.org/decision-labs/fcm)
|
4
4
|
|
5
5
|
The FCM gem lets your ruby backend send notifications to Android and iOS devices via [
|
6
6
|
Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/).
|
@@ -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
|
-
A version of supported Ruby, currently:
|
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:
|
@@ -34,14 +77,10 @@ Example sending notifications:
|
|
34
77
|
require 'fcm'
|
35
78
|
|
36
79
|
fcm = FCM.new("my_server_key")
|
37
|
-
# you can set option parameters in here
|
38
|
-
# - all options are pass to HTTParty method arguments
|
39
|
-
# - ref: https://github.com/jnunemaker/httparty/blob/master/lib/httparty.rb#L29-L60
|
40
|
-
# fcm = FCM.new("my_server_key", timeout: 3)
|
41
80
|
|
42
81
|
registration_ids= ["12", "13"] # an array of one or more client registration tokens
|
43
82
|
|
44
|
-
# See https://firebase.google.com/docs/
|
83
|
+
# See https://firebase.google.com/docs/cloud-messaging/http-server-ref for all available options.
|
45
84
|
options = { "notification": {
|
46
85
|
"title": "Portugal vs. Denmark",
|
47
86
|
"body": "5 to 1"
|
@@ -101,14 +140,14 @@ FCM [topic messaging](https://firebase.google.com/docs/cloud-messaging/topic-mes
|
|
101
140
|
|
102
141
|
```ruby
|
103
142
|
response = fcm.send_with_notification_key("/topics/yourTopic",
|
104
|
-
|
143
|
+
notification: {body: "This is a FCM Topic Message!"})
|
105
144
|
```
|
106
145
|
|
107
146
|
Or you can use the helper:
|
108
147
|
|
109
148
|
```ruby
|
110
149
|
response = fcm.send_to_topic("yourTopic",
|
111
|
-
|
150
|
+
notification: {body: "This is a FCM Topic Message!"})
|
112
151
|
```
|
113
152
|
|
114
153
|
### Sending to Multiple Topics
|
@@ -137,8 +176,8 @@ The `send_to_topic_condition` method within this library allows you to specicy a
|
|
137
176
|
```ruby
|
138
177
|
response = fcm.send_to_topic_condition(
|
139
178
|
"'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)",
|
140
|
-
|
141
|
-
|
179
|
+
notification: {
|
180
|
+
body: "This is an FCM Topic Message sent to a condition!"
|
142
181
|
}
|
143
182
|
)
|
144
183
|
```
|
@@ -171,6 +210,14 @@ The guide to set up an iOS app to get notifications is here: [Setting up a FCM C
|
|
171
210
|
|
172
211
|
## ChangeLog
|
173
212
|
|
213
|
+
### 1.0.3
|
214
|
+
|
215
|
+
- Fix overly strict faraday depenecy
|
216
|
+
|
217
|
+
### 1.0.2
|
218
|
+
|
219
|
+
- Bug fix: retrieve notification key" params: https://github.com/spacialdb/fcm/commit/b328a75c11d779a06d0ceda83527e26aa0495774
|
220
|
+
|
174
221
|
### 1.0.0
|
175
222
|
|
176
223
|
- Bumped supported ruby to `>= 2.4`
|
@@ -197,8 +244,15 @@ The guide to set up an iOS app to get notifications is here: [Setting up a FCM C
|
|
197
244
|
|
198
245
|
- [Contributors](https://github.com/spacialdb/fcm/contributors)
|
199
246
|
|
200
|
-
##
|
247
|
+
## Cutting a release
|
201
248
|
|
202
|
-
|
249
|
+
Update version in `fcm.gemspec` with `VERSION` and update `README.md` `## ChangeLog` section.
|
203
250
|
|
204
|
-
|
251
|
+
```bash
|
252
|
+
# set the version
|
253
|
+
# VERSION="1.0.4"
|
254
|
+
gem build fcm.gemspec
|
255
|
+
git tag -a v${VERSION} -m "Releasing version v${VERSION}"
|
256
|
+
git push origin --tags
|
257
|
+
gem push fcm-${VERSION}.gem
|
258
|
+
```
|
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.
|
6
|
+
s.version = "1.0.6"
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
8
|
s.authors = ["Kashif Rasul", "Shoaib Burq"]
|
9
|
-
s.email = ["kashif@
|
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.}
|
@@ -19,5 +19,6 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
|
-
s.add_runtime_dependency('faraday', '~> 1
|
22
|
+
s.add_runtime_dependency('faraday', '~> 1')
|
23
|
+
s.add_runtime_dependency('googleauth', '~> 1')
|
23
24
|
end
|
data/lib/fcm.rb
CHANGED
@@ -1,24 +1,71 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "faraday"
|
2
|
+
require "cgi"
|
3
|
+
require "json"
|
4
|
+
require "googleauth"
|
4
5
|
|
5
6
|
class FCM
|
6
|
-
BASE_URI =
|
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 =
|
12
|
-
INSTANCE_ID_API =
|
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,72 +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(
|
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:
|
46
|
-
|
93
|
+
post_body = build_post_body(registration_ids, operation: "create",
|
94
|
+
notification_key_name: key_name)
|
47
95
|
|
48
96
|
extra_headers = {
|
49
|
-
|
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(
|
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:
|
61
|
-
|
62
|
-
|
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
|
-
|
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(
|
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:
|
77
|
-
|
78
|
-
|
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
|
-
|
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(
|
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 = {
|
93
|
-
|
94
|
-
notification_key_name: key_name
|
95
|
-
}
|
96
|
-
}
|
97
|
-
|
143
|
+
params = { notification_key_name: key_name }
|
144
|
+
|
98
145
|
extra_headers = {
|
99
|
-
|
146
|
+
"project_id" => project_id,
|
100
147
|
}
|
101
148
|
|
102
149
|
for_uri(GROUP_NOTIFICATION_BASE_URI, extra_headers) do |connection|
|
103
|
-
response = connection.get(
|
150
|
+
response = connection.get("/gcm/notification", params)
|
104
151
|
build_response(response)
|
105
152
|
end
|
106
153
|
end
|
@@ -118,11 +165,11 @@ class FCM
|
|
118
165
|
end
|
119
166
|
|
120
167
|
def batch_topic_subscription(topic, registration_ids)
|
121
|
-
manage_topics_relationship(topic, registration_ids,
|
168
|
+
manage_topics_relationship(topic, registration_ids, "Add")
|
122
169
|
end
|
123
170
|
|
124
171
|
def batch_topic_unsubscription(topic, registration_ids)
|
125
|
-
manage_topics_relationship(topic, registration_ids,
|
172
|
+
manage_topics_relationship(topic, registration_ids, "Remove")
|
126
173
|
end
|
127
174
|
|
128
175
|
def manage_topics_relationship(topic, registration_ids, action)
|
@@ -136,35 +183,35 @@ class FCM
|
|
136
183
|
|
137
184
|
def send_to_topic(topic, options = {})
|
138
185
|
if topic.gsub(TOPIC_REGEX, "").length == 0
|
139
|
-
send_with_notification_key(
|
186
|
+
send_with_notification_key("/topics/" + topic, options)
|
140
187
|
end
|
141
188
|
end
|
142
189
|
|
143
|
-
def get_instance_id_info
|
190
|
+
def get_instance_id_info(iid_token, options = {})
|
144
191
|
params = {
|
145
|
-
query: options
|
192
|
+
query: options,
|
146
193
|
}
|
147
|
-
|
194
|
+
|
148
195
|
for_uri(INSTANCE_ID_API) do |connection|
|
149
|
-
response = connection.get(
|
196
|
+
response = connection.get("/iid/info/" + iid_token, params)
|
150
197
|
build_response(response)
|
151
198
|
end
|
152
199
|
end
|
153
200
|
|
154
|
-
def subscribe_instance_id_to_topic
|
201
|
+
def subscribe_instance_id_to_topic(iid_token, topic_name)
|
155
202
|
batch_subscribe_instance_ids_to_topic([iid_token], topic_name)
|
156
203
|
end
|
157
204
|
|
158
|
-
def unsubscribe_instance_id_from_topic
|
205
|
+
def unsubscribe_instance_id_from_topic(iid_token, topic_name)
|
159
206
|
batch_unsubscribe_instance_ids_from_topic([iid_token], topic_name)
|
160
207
|
end
|
161
208
|
|
162
|
-
def batch_subscribe_instance_ids_to_topic
|
163
|
-
manage_topics_relationship(topic_name, instance_ids,
|
209
|
+
def batch_subscribe_instance_ids_to_topic(instance_ids, topic_name)
|
210
|
+
manage_topics_relationship(topic_name, instance_ids, "Add")
|
164
211
|
end
|
165
212
|
|
166
|
-
def batch_unsubscribe_instance_ids_from_topic
|
167
|
-
manage_topics_relationship(topic_name, instance_ids,
|
213
|
+
def batch_unsubscribe_instance_ids_from_topic(instance_ids, topic_name)
|
214
|
+
manage_topics_relationship(topic_name, instance_ids, "Remove")
|
168
215
|
end
|
169
216
|
|
170
217
|
def send_to_topic_condition(condition, options = {})
|
@@ -178,7 +225,7 @@ class FCM
|
|
178
225
|
|
179
226
|
def for_uri(uri, extra_headers = {})
|
180
227
|
connection = ::Faraday.new(:url => uri) do |faraday|
|
181
|
-
faraday.adapter
|
228
|
+
faraday.adapter Faraday.default_adapter
|
182
229
|
faraday.headers["Content-Type"] = "application/json"
|
183
230
|
faraday.headers["Authorization"] = "key=#{api_key}"
|
184
231
|
extra_headers.each do |key, value|
|
@@ -198,18 +245,18 @@ class FCM
|
|
198
245
|
response_hash = { body: body, headers: response.headers, status_code: response.status }
|
199
246
|
case response.status
|
200
247
|
when 200
|
201
|
-
response_hash[:response] =
|
248
|
+
response_hash[:response] = "success"
|
202
249
|
body = JSON.parse(body) unless body.empty?
|
203
250
|
response_hash[:canonical_ids] = build_canonical_ids(body, registration_ids) unless registration_ids.empty?
|
204
251
|
response_hash[:not_registered_ids] = build_not_registered_ids(body, registration_ids) unless registration_ids.empty?
|
205
252
|
when 400
|
206
|
-
response_hash[:response] =
|
253
|
+
response_hash[:response] = "Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields."
|
207
254
|
when 401
|
208
|
-
response_hash[:response] =
|
255
|
+
response_hash[:response] = "There was an error authenticating the sender account."
|
209
256
|
when 503
|
210
|
-
response_hash[:response] =
|
257
|
+
response_hash[:response] = "Server is temporarily unavailable."
|
211
258
|
when 500..599
|
212
|
-
response_hash[:response] =
|
259
|
+
response_hash[:response] = "There was an internal error in the FCM server while trying to process the request."
|
213
260
|
end
|
214
261
|
response_hash
|
215
262
|
end
|
@@ -217,9 +264,9 @@ class FCM
|
|
217
264
|
def build_canonical_ids(body, registration_ids)
|
218
265
|
canonical_ids = []
|
219
266
|
unless body.empty?
|
220
|
-
if body[
|
221
|
-
body[
|
222
|
-
canonical_ids << { old: registration_ids[index], new: 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)
|
223
270
|
end
|
224
271
|
end
|
225
272
|
end
|
@@ -229,8 +276,8 @@ class FCM
|
|
229
276
|
def build_not_registered_ids(body, registration_id)
|
230
277
|
not_registered_ids = []
|
231
278
|
unless body.empty?
|
232
|
-
if body[
|
233
|
-
body[
|
279
|
+
if body["failure"] > 0
|
280
|
+
body["results"].each_with_index do |result, index|
|
234
281
|
not_registered_ids << registration_id[index] if is_not_registered?(result)
|
235
282
|
end
|
236
283
|
end
|
@@ -240,17 +287,17 @@ class FCM
|
|
240
287
|
|
241
288
|
def execute_notification(body)
|
242
289
|
for_uri(BASE_URI) do |connection|
|
243
|
-
response = connection.post(
|
290
|
+
response = connection.post("/fcm/send", body.to_json)
|
244
291
|
build_response(response)
|
245
292
|
end
|
246
293
|
end
|
247
294
|
|
248
295
|
def has_canonical_id?(result)
|
249
|
-
!result[
|
296
|
+
!result["registration_id"].nil?
|
250
297
|
end
|
251
298
|
|
252
299
|
def is_not_registered?(result)
|
253
|
-
result[
|
300
|
+
result["error"] == "NotRegistered"
|
254
301
|
end
|
255
302
|
|
256
303
|
def validate_condition?(condition)
|
@@ -269,4 +316,14 @@ class FCM
|
|
269
316
|
topics = condition.scan(/(?:^|\S|\s)'([^']*?)'(?:$|\S|\s)/).flatten
|
270
317
|
topics.all? { |topic| topic.gsub(TOPIC_REGEX, "").length == 0 }
|
271
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
|
272
329
|
end
|
data/spec/fcm_spec.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
require
|
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) {
|
7
|
-
let(:registration_id) {
|
8
|
-
let(:registration_ids) { [
|
9
|
-
let(:key_name) {
|
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
|
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
|
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
|
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
|
-
|
36
|
-
|
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 =
|
66
|
-
uri.password =
|
67
|
-
stub_request(:post, uri.to_s).to_return(body:
|
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
|
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:
|
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
|
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:
|
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
|
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:
|
97
|
+
.to_return(status: 200, body: "", headers: {})
|
94
98
|
end
|
95
99
|
before do
|
96
100
|
end
|
97
|
-
it
|
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:
|
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:
|
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:
|
119
|
+
.to_return(status: 200, body: "", headers: {})
|
116
120
|
end
|
117
121
|
|
118
122
|
describe "#send_to_topic" do
|
119
|
-
it
|
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:
|
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
|
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:
|
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:
|
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:
|
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:
|
154
|
+
.to_return(status: 200, body: "", headers: {})
|
151
155
|
end
|
152
156
|
|
153
157
|
describe "#send_to_topic_condition" do
|
154
|
-
it
|
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:
|
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
|
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:
|
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
|
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:
|
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
|
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
|
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
|
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:
|
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
|
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
|
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:
|
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
|
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
|
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:
|
242
|
+
response: "Server is temporarily unavailable.",
|
239
243
|
status_code: 503)
|
240
244
|
end
|
241
245
|
end
|
242
246
|
|
243
|
-
context
|
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: {
|
251
|
-
status: 599
|
254
|
+
headers: { "header-key" => "Header value" },
|
255
|
+
status: 599,
|
252
256
|
)
|
253
257
|
end
|
254
258
|
|
255
|
-
it
|
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: {
|
258
|
-
response:
|
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
|
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:
|
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
|
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:
|
299
|
+
canonical_ids: [{ old: "42", new: "43" }],
|
296
300
|
not_registered_ids: [],
|
297
301
|
status_code: 200,
|
298
|
-
response:
|
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
|
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:
|
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
|
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:
|
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
|
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" =>
|
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
|
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
|
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:
|
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
|
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
|
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:
|
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
|
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,23 +460,42 @@ 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
|
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:
|
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
|
473
477
|
end
|
474
478
|
|
475
|
-
describe
|
479
|
+
describe "#recover_notification_key" do
|
480
|
+
it "sends a 'retrieve notification key' request" do
|
481
|
+
uri = "#{FCM::GROUP_NOTIFICATION_BASE_URI}/gcm/notification"
|
482
|
+
endpoint = stub_request(:get, uri).with(
|
483
|
+
headers: {
|
484
|
+
"Content-Type" => "application/json",
|
485
|
+
"Authorization" => "key=TEST_SERVER_KEY",
|
486
|
+
"project_id" => "TEST_PROJECT_ID",
|
487
|
+
},
|
488
|
+
query: { notification_key_name: "TEST_KEY_NAME" },
|
489
|
+
)
|
490
|
+
client = FCM.new("TEST_SERVER_KEY")
|
491
|
+
|
492
|
+
client.recover_notification_key("TEST_KEY_NAME", "TEST_PROJECT_ID")
|
493
|
+
|
494
|
+
expect(endpoint).to have_been_requested
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
describe "subscribing to a topic" do
|
476
499
|
# TODO
|
477
500
|
end
|
478
501
|
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: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kashif Rasul
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-11-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: faraday
|
@@ -17,20 +17,34 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: 1
|
20
|
+
version: '1'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: 1
|
27
|
+
version: '1'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: googleauth
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1'
|
28
42
|
description: fcm provides ruby bindings to Firebase Cloud Messaging (FCM) a cross-platform
|
29
43
|
messaging solution that lets you reliably deliver messages and notifications at
|
30
44
|
no cost to Android, iOS or Web browsers.
|
31
45
|
email:
|
32
|
-
- kashif@
|
33
|
-
- shoaib@
|
46
|
+
- kashif@decision-labs.com
|
47
|
+
- shoaib@decision-labs.com
|
34
48
|
executables: []
|
35
49
|
extensions: []
|
36
50
|
extra_rdoc_files: []
|
@@ -65,7 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
79
|
- !ruby/object:Gem::Version
|
66
80
|
version: '0'
|
67
81
|
requirements: []
|
68
|
-
rubygems_version: 3.1
|
82
|
+
rubygems_version: 3.0.3.1
|
69
83
|
signing_key:
|
70
84
|
specification_version: 4
|
71
85
|
summary: Reliably deliver messages and notifications via FCM
|