twinpush 0.0.2
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 +7 -0
- data/lib/twinpush.rb +159 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/twinpush_spec.rb +475 -0
- metadata +65 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4e5f75a1774fcdbbf792c1e4d982e07cf13d324e0ef3ee113efea24c0c9ae417
|
4
|
+
data.tar.gz: 0776ed72759003f8108506bcd4d9e1645ef12e27a6575d681fc5030a30f4e7f0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8246fe87adbae38faed5bc5d7d8de5bf1b022ec284ef73363bd88de647a2ec4e292074e9742283740928c52c27fa010266c6a83b1dc2b340a5c77a14e8263c65
|
7
|
+
data.tar.gz: b1d5e69a2c9137a795cb107fba7e8e59143bd0a73689c43b7e3f5fc9d699face3514682ffb4a6f46c4c42e468a5af054a40a1c7d6c5c0ce0723a20cedd7d0afe
|
data/lib/twinpush.rb
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'cgi'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class TWINPUSH
|
6
|
+
DEFAULT_TIMEOUT = 30
|
7
|
+
FORMAT = :json
|
8
|
+
BASE_URI = 'https://subdomain.twinpush.com'
|
9
|
+
API_URL = '/api/v2/apps'
|
10
|
+
|
11
|
+
attr_accessor :uri, :app_id, :api_token, :api_token_creator
|
12
|
+
|
13
|
+
# @param [Hash] authentication_keys
|
14
|
+
# @param [Hash] client_options
|
15
|
+
# @param [Integer] timeout
|
16
|
+
def initialize(authentication_keys, client_options = {}, timeout = nil)
|
17
|
+
validate_keys(authentication_keys)
|
18
|
+
authentication_keys.each_pair do |key, value|
|
19
|
+
instance_variable_set("@#{key}", value)
|
20
|
+
self.class.instance_eval { attr_accessor key.to_sym }
|
21
|
+
end
|
22
|
+
@uri = BASE_URI.sub! 'subdomain', @subdomain
|
23
|
+
@client_options = client_options
|
24
|
+
@timeout = timeout | DEFAULT_TIMEOUT
|
25
|
+
end
|
26
|
+
|
27
|
+
#obtains details from a previously created notification
|
28
|
+
def show_notification(notification_id, device_id = nil)
|
29
|
+
path = "#{API_URL}/#{app_id}#{"/devices/#{device_id}" if device_id }/notifications/#{notification_id}"
|
30
|
+
for_uri(uri) do |connection|
|
31
|
+
response = connection.get(path)
|
32
|
+
build_response(response)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
alias show show_notification
|
37
|
+
|
38
|
+
#creates a new notification to be delivered from the platform
|
39
|
+
def create_notification(notification_params)
|
40
|
+
path = "#{API_URL}/#{app_id}/notifications"
|
41
|
+
for_uri(uri) do |connection|
|
42
|
+
response = connection.post(path, notification_params.to_json)
|
43
|
+
build_response(response)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
alias create create_notification
|
48
|
+
|
49
|
+
# obtains delivery statistics for a given notification
|
50
|
+
def report_notification(notification_id)
|
51
|
+
path = "#{API_URL}/#{app_id}/notifications/#{notification_id}/report"
|
52
|
+
for_uri(uri) do |connection|
|
53
|
+
response = connection.get(path)
|
54
|
+
build_response(response)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
alias report report_notification
|
59
|
+
|
60
|
+
#Obtains paginated list of all the deliveries for a given notification.
|
61
|
+
#This is useful to obtain exactly who has been the recipient of the notification and also who has opened it
|
62
|
+
def deliveries_notification(notification_id)
|
63
|
+
path = "#{API_URL}/#{app_id}/notifications/#{notification_id}/deliveries"
|
64
|
+
for_uri(uri) do |connection|
|
65
|
+
response = connection.get(path)
|
66
|
+
build_response(response)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
alias deliveries deliveries_notification
|
71
|
+
|
72
|
+
# Makes a paginated search of the notifications sent to an user through the device alias. It allows filtering by notification tags
|
73
|
+
def inbox(device_id)
|
74
|
+
path = "#{API_URL}/#{app_id}/devices/#{device_id}/inbox"
|
75
|
+
for_uri(uri) do |connection|
|
76
|
+
response = connection.get(path)
|
77
|
+
build_response(response)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
#Obtains a fast summary of the notification inbox associated to the current device alias
|
82
|
+
#It offers the total notification count and the unopened notification count
|
83
|
+
def inbox_summary(device_id)
|
84
|
+
path = "#{API_URL}/#{app_id}/devices/#{device_id}/inbox_summary"
|
85
|
+
for_uri(uri) do |connection|
|
86
|
+
response = connection.get(path)
|
87
|
+
build_response(response)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
#Removes the selected notification from the inbox of the user (or alias) associated to the device
|
92
|
+
def delete_inbox(device_id, notification_id)
|
93
|
+
path = "#{API_URL}/#{app_id}/devices/#{device_id}/notifications/#{notification_id}"
|
94
|
+
for_uri(uri) do |connection|
|
95
|
+
response = connection.delete(path)
|
96
|
+
build_response(response)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# assigns value for a device custom property
|
101
|
+
def set_custom_property(device_id, properties)
|
102
|
+
path = "#{API_URL}/#{app_id}/devices/#{device_id}/set_custom_property"
|
103
|
+
for_uri(uri) do |connection|
|
104
|
+
response = connection.post(path, properties.to_json)
|
105
|
+
build_response(response)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
#Makes a paginated search of the notifications received by a device. It allows filtering by notification tags
|
110
|
+
def search_device_notifications(device_id, params)
|
111
|
+
path = "#{API_URL}/#{app_id}/devices/#{device_id}/search_notifications"
|
112
|
+
for_uri(uri) do |connection|
|
113
|
+
response = connection.post(path, params.to_json)
|
114
|
+
build_response(response)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def validate_keys(authentication_keys)
|
121
|
+
required_params = [:app_id, :subdomain, :api_token, :api_token_creator]
|
122
|
+
(required_params - authentication_keys.keys).each do |params|
|
123
|
+
raise ArgumentError, "Required authentication_key #{params} missing"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def for_uri(uri, extra_headers = {})
|
128
|
+
connection = ::Faraday.new(:url => uri) do |faraday|
|
129
|
+
faraday.adapter Faraday.default_adapter
|
130
|
+
faraday.headers["Content-Type"] = "application/json"
|
131
|
+
faraday.headers["X-TwinPush-REST-API-Key-Creator"] = api_token_creator
|
132
|
+
faraday.headers["X-TwinPush-REST-API-Token"] = api_token
|
133
|
+
extra_headers.each do |key, value|
|
134
|
+
faraday.headers[key] = value
|
135
|
+
end
|
136
|
+
end
|
137
|
+
yield connection
|
138
|
+
end
|
139
|
+
|
140
|
+
def build_response(response)
|
141
|
+
body = response.body || {}
|
142
|
+
response_hash = { body: body, headers: response.headers, status_code: response.status }
|
143
|
+
case response.status
|
144
|
+
when 200
|
145
|
+
response_hash[:response] = 'success'
|
146
|
+
when 403
|
147
|
+
response_hash[:response] = 'API Key Token or Creator API Key Token are not valid or does not match with App ID'
|
148
|
+
when 404
|
149
|
+
response_hash[:response] = 'Application not found for given application_id, device not found for given device_id or delivery not found for given notification and device'
|
150
|
+
when 422
|
151
|
+
response_hash[:response] = 'Some of the parameters given is not valid when trying to create a notification, create a device property or register or update a device'
|
152
|
+
when 500..599
|
153
|
+
response_hash[:response] = 'There was an internal error in the Twinpush server while trying to process the request.'
|
154
|
+
end
|
155
|
+
response_hash
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,475 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TWINPUSH do
|
4
|
+
let(:app_id) { '1a2b3c4d5f' }
|
5
|
+
let(:subdomain) { 'test' }
|
6
|
+
let(:api_token) { '1c5cabc4055e03c64f123d9dbfb4d0e9' }
|
7
|
+
let(:api_token_creator) { '232ddfd56b6a3af1ba89b93c5ffd836d' }
|
8
|
+
let(:authentication_keys) {{app_id: app_id, subdomain: subdomain, api_token: api_token, api_token_creator: api_token_creator}}
|
9
|
+
|
10
|
+
it 'should replace subdomian in uri' do
|
11
|
+
twinpush = TWINPUSH.new(authentication_keys)
|
12
|
+
expect(twinpush.uri).to eq "https://test.googleapis.com/api/v2"
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should raise an error if authentication_keys is not provided' do
|
16
|
+
expect { TWINPUSH.new }.to raise_error(ArgumentError)
|
17
|
+
expect { TWINPUSH.new(app_id: app_id )}.to raise_error(ArgumentError, 'Required authentication_key subdomain missing')
|
18
|
+
expect { TWINPUSH.new(app_id: app_id, subdomain: subdomain )}.to raise_error(ArgumentError, 'Required authentication_key api_token missing')
|
19
|
+
expect { TWINPUSH.new(app_id: app_id, subdomain: subdomain, api_token: api_token)}.to raise_error(ArgumentError, 'Required authentication_key api_token_creator missing')
|
20
|
+
expect { TWINPUSH.new(authentication_keys)}.not_to raise_error(ArgumentError)
|
21
|
+
end
|
22
|
+
|
23
|
+
# describe 'sending notification' do
|
24
|
+
# let(:valid_request_body) do
|
25
|
+
# { registration_ids: registration_ids }
|
26
|
+
# end
|
27
|
+
# let(:valid_request_body_with_string) do
|
28
|
+
# { registration_ids: registration_id }
|
29
|
+
# end
|
30
|
+
# let(:valid_request_headers) do
|
31
|
+
# {
|
32
|
+
# 'Content-Type' => 'application/json',
|
33
|
+
# 'Authorization' => "key=#{api_key}"
|
34
|
+
# }
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# let(:stub_fcm_send_request) do
|
38
|
+
# stub_request(:post, send_url).with(
|
39
|
+
# body: valid_request_body.to_json,
|
40
|
+
# headers: valid_request_headers
|
41
|
+
# ).to_return(
|
42
|
+
# # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
|
43
|
+
# body: '{}',
|
44
|
+
# headers: {},
|
45
|
+
# status: 200
|
46
|
+
# )
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# let(:stub_fcm_send_request_with_string) do
|
50
|
+
# stub_request(:post, send_url).with(
|
51
|
+
# body: valid_request_body_with_string.to_json,
|
52
|
+
# headers: valid_request_headers
|
53
|
+
# ).to_return(
|
54
|
+
# body: '{}',
|
55
|
+
# headers: {},
|
56
|
+
# status: 200
|
57
|
+
# )
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# let(:stub_fcm_send_request_with_basic_auth) do
|
61
|
+
# uri = URI.parse(send_url)
|
62
|
+
# uri.user = 'a'
|
63
|
+
# uri.password = 'b'
|
64
|
+
# stub_request(:post, uri.to_s).to_return(body: '{}', headers: {}, status: 200)
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# before(:each) do
|
68
|
+
# stub_fcm_send_request
|
69
|
+
# stub_fcm_send_request_with_string
|
70
|
+
# stub_fcm_send_request_with_basic_auth
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# it 'should send notification using POST to FCM server' do
|
74
|
+
# fcm = FCM.new(api_key)
|
75
|
+
# fcm.send(registration_ids).should eq(response: 'success', body: '{}', headers: {}, status_code: 200, canonical_ids: [], not_registered_ids: [])
|
76
|
+
# stub_fcm_send_request.should have_been_made.times(1)
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# it 'should send notification using POST to FCM if id provided as string' do
|
80
|
+
# fcm = FCM.new(api_key)
|
81
|
+
# fcm.send(registration_id).should eq(response: 'success', body: '{}', headers: {}, status_code: 200, canonical_ids: [], not_registered_ids: [])
|
82
|
+
# stub_fcm_send_request.should have_been_made.times(1)
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# context 'send notification with data' do
|
86
|
+
# let!(:stub_with_data) do
|
87
|
+
# stub_request(:post, send_url)
|
88
|
+
# .with(body: '{"registration_ids":["42"],"data":{"score":"5x1","time":"15:10"}}',
|
89
|
+
# headers: valid_request_headers)
|
90
|
+
# .to_return(status: 200, body: '', headers: {})
|
91
|
+
# end
|
92
|
+
# before do
|
93
|
+
# end
|
94
|
+
# it 'should send the data in a post request to fcm' do
|
95
|
+
# fcm = FCM.new(api_key)
|
96
|
+
# fcm.send(registration_ids, data: { score: '5x1', time: '15:10' })
|
97
|
+
# stub_with_data.should have_been_requested
|
98
|
+
# end
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# context "sending notification to a topic" do
|
102
|
+
# let!(:stub_with_valid_topic) do
|
103
|
+
# stub_request(:post, send_url)
|
104
|
+
# .with(body: '{"to":"/topics/TopicA","data":{"score":"5x1","time":"15:10"}}',
|
105
|
+
# headers: valid_request_headers)
|
106
|
+
# .to_return(status: 200, body: '', headers: {})
|
107
|
+
# end
|
108
|
+
# let!(:stub_with_invalid_topic) do
|
109
|
+
# stub_request(:post, send_url)
|
110
|
+
# .with(body: '{"condition":"/topics/TopicA$","data":{"score":"5x1","time":"15:10"}}',
|
111
|
+
# headers: valid_request_headers)
|
112
|
+
# .to_return(status: 200, body: '', headers: {})
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# describe "#send_to_topic" do
|
116
|
+
# it 'should send the data in a post request to fcm' do
|
117
|
+
# fcm = FCM.new(api_key)
|
118
|
+
# fcm.send_to_topic(valid_topic, data: { score: '5x1', time: '15:10' })
|
119
|
+
# stub_with_valid_topic.should have_been_requested
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# it 'should not send to invalid topics' do
|
123
|
+
# fcm = FCM.new(api_key)
|
124
|
+
# fcm.send_to_topic(invalid_topic, data: { score: '5x1', time: '15:10' })
|
125
|
+
# stub_with_invalid_topic.should_not have_been_requested
|
126
|
+
# end
|
127
|
+
# end
|
128
|
+
# end
|
129
|
+
#
|
130
|
+
# context "sending notification to a topic condition" do
|
131
|
+
# let!(:stub_with_valid_condition) do
|
132
|
+
# stub_request(:post, send_url)
|
133
|
+
# .with(body: '{"condition":"\'TopicA\' in topics && (\'TopicB\' in topics || \'TopicC\' in topics)","data":{"score":"5x1","time":"15:10"}}',
|
134
|
+
# headers: valid_request_headers)
|
135
|
+
# .to_return(status: 200, body: '', headers: {})
|
136
|
+
# end
|
137
|
+
# let!(:stub_with_invalid_condition) do
|
138
|
+
# stub_request(:post, send_url)
|
139
|
+
# .with(body: '{"condition":"\'TopicA\' in topics and some other text (\'TopicB\' in topics || \'TopicC\' in topics)","data":{"score":"5x1","time":"15:10"}}',
|
140
|
+
# headers: valid_request_headers)
|
141
|
+
# .to_return(status: 200, body: '', headers: {})
|
142
|
+
# end
|
143
|
+
# let!(:stub_with_invalid_condition_topic) do
|
144
|
+
# stub_request(:post, send_url)
|
145
|
+
# .with(body: '{"condition":"\'TopicA$\' in topics","data":{"score":"5x1","time":"15:10"}}',
|
146
|
+
# headers: valid_request_headers)
|
147
|
+
# .to_return(status: 200, body: '', headers: {})
|
148
|
+
# end
|
149
|
+
#
|
150
|
+
# describe "#send_to_topic_condition" do
|
151
|
+
# it 'should send the data in a post request to fcm' do
|
152
|
+
# fcm = FCM.new(api_key)
|
153
|
+
# fcm.send_to_topic_condition(valid_condition, data: { score: '5x1', time: '15:10' })
|
154
|
+
# stub_with_valid_condition.should have_been_requested
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# it 'should not send to invalid conditions' do
|
158
|
+
# fcm = FCM.new(api_key)
|
159
|
+
# fcm.send_to_topic_condition(invalid_condition, data: { score: '5x1', time: '15:10' })
|
160
|
+
# stub_with_invalid_condition.should_not have_been_requested
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
# it 'should not send to invalid topics in a condition' do
|
164
|
+
# fcm = FCM.new(api_key)
|
165
|
+
# fcm.send_to_topic_condition(invalid_condition_topic, data: { score: '5x1', time: '15:10' })
|
166
|
+
# stub_with_invalid_condition_topic.should_not have_been_requested
|
167
|
+
# end
|
168
|
+
# end
|
169
|
+
# end
|
170
|
+
#
|
171
|
+
# context 'when send_notification responds with failure' do
|
172
|
+
# let(:mock_request_attributes) do
|
173
|
+
# {
|
174
|
+
# body: valid_request_body.to_json,
|
175
|
+
# headers: valid_request_headers
|
176
|
+
# }
|
177
|
+
# end
|
178
|
+
#
|
179
|
+
# subject { FCM.new(api_key) }
|
180
|
+
#
|
181
|
+
# context 'on failure code 400' do
|
182
|
+
# before do
|
183
|
+
# stub_request(:post, send_url).with(
|
184
|
+
# mock_request_attributes
|
185
|
+
# ).to_return(
|
186
|
+
# # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
|
187
|
+
# body: '{}',
|
188
|
+
# headers: {},
|
189
|
+
# status: 400
|
190
|
+
# )
|
191
|
+
# end
|
192
|
+
# it 'should not send notification due to 400' do
|
193
|
+
# subject.send(registration_ids).should eq(body: '{}',
|
194
|
+
# headers: {},
|
195
|
+
# response: 'Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields.',
|
196
|
+
# status_code: 400)
|
197
|
+
# end
|
198
|
+
# end
|
199
|
+
#
|
200
|
+
# context 'on failure code 401' do
|
201
|
+
# before do
|
202
|
+
# stub_request(:post, send_url).with(
|
203
|
+
# mock_request_attributes
|
204
|
+
# ).to_return(
|
205
|
+
# # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
|
206
|
+
# body: '{}',
|
207
|
+
# headers: {},
|
208
|
+
# status: 401
|
209
|
+
# )
|
210
|
+
# end
|
211
|
+
#
|
212
|
+
# it 'should not send notification due to 401' do
|
213
|
+
# subject.send(registration_ids).should eq(body: '{}',
|
214
|
+
# headers: {},
|
215
|
+
# response: 'There was an error authenticating the sender account.',
|
216
|
+
# status_code: 401)
|
217
|
+
# end
|
218
|
+
# end
|
219
|
+
#
|
220
|
+
# context 'on failure code 503' do
|
221
|
+
# before do
|
222
|
+
# stub_request(:post, send_url).with(
|
223
|
+
# mock_request_attributes
|
224
|
+
# ).to_return(
|
225
|
+
# # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
|
226
|
+
# body: '{}',
|
227
|
+
# headers: {},
|
228
|
+
# status: 503
|
229
|
+
# )
|
230
|
+
# end
|
231
|
+
#
|
232
|
+
# it 'should not send notification due to 503' do
|
233
|
+
# subject.send(registration_ids).should eq(body: '{}',
|
234
|
+
# headers: {},
|
235
|
+
# response: 'Server is temporarily unavailable.',
|
236
|
+
# status_code: 503)
|
237
|
+
# end
|
238
|
+
# end
|
239
|
+
#
|
240
|
+
# context 'on failure code 5xx' do
|
241
|
+
# before do
|
242
|
+
# stub_request(:post, send_url).with(
|
243
|
+
# mock_request_attributes
|
244
|
+
# ).to_return(
|
245
|
+
# # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
|
246
|
+
# body: '{"body-key" => "Body value"}',
|
247
|
+
# headers: { 'header-key' => 'Header value' },
|
248
|
+
# status: 599
|
249
|
+
# )
|
250
|
+
# end
|
251
|
+
#
|
252
|
+
# it 'should not send notification due to 599' do
|
253
|
+
# subject.send(registration_ids).should eq(body: '{"body-key" => "Body value"}',
|
254
|
+
# headers: { 'header-key' => 'Header value' },
|
255
|
+
# response: 'There was an internal error in the FCM server while trying to process the request.',
|
256
|
+
# status_code: 599)
|
257
|
+
# end
|
258
|
+
# end
|
259
|
+
# end
|
260
|
+
#
|
261
|
+
# context 'when send_notification responds canonical_ids' do
|
262
|
+
# let(:mock_request_attributes) do
|
263
|
+
# {
|
264
|
+
# body: valid_request_body.to_json,
|
265
|
+
# headers: valid_request_headers
|
266
|
+
# }
|
267
|
+
# end
|
268
|
+
#
|
269
|
+
# let(:valid_response_body_with_canonical_ids) do
|
270
|
+
# {
|
271
|
+
# failure: 0, canonical_ids: 1, results: [{ registration_id: '43', message_id: '0:1385025861956342%572c22801bb3' }]
|
272
|
+
# }
|
273
|
+
# end
|
274
|
+
#
|
275
|
+
# subject { FCM.new(api_key) }
|
276
|
+
#
|
277
|
+
# before do
|
278
|
+
# stub_request(:post, send_url).with(
|
279
|
+
# mock_request_attributes
|
280
|
+
# ).to_return(
|
281
|
+
# # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
|
282
|
+
# body: valid_response_body_with_canonical_ids.to_json,
|
283
|
+
# headers: {},
|
284
|
+
# status: 200
|
285
|
+
# )
|
286
|
+
# end
|
287
|
+
#
|
288
|
+
# it 'should contain canonical_ids' do
|
289
|
+
# response = subject.send(registration_ids)
|
290
|
+
#
|
291
|
+
# response.should eq(headers: {},
|
292
|
+
# canonical_ids: [{ old: '42', new: '43' }],
|
293
|
+
# not_registered_ids: [],
|
294
|
+
# status_code: 200,
|
295
|
+
# response: 'success',
|
296
|
+
# body: '{"failure":0,"canonical_ids":1,"results":[{"registration_id":"43","message_id":"0:1385025861956342%572c22801bb3"}]}')
|
297
|
+
# end
|
298
|
+
# end
|
299
|
+
#
|
300
|
+
# context 'when send_notification responds with NotRegistered' do
|
301
|
+
# subject { FCM.new(api_key) }
|
302
|
+
#
|
303
|
+
# let(:mock_request_attributes) do
|
304
|
+
# {
|
305
|
+
# body: valid_request_body.to_json,
|
306
|
+
# headers: valid_request_headers
|
307
|
+
# }
|
308
|
+
# end
|
309
|
+
#
|
310
|
+
# let(:valid_response_body_with_not_registered_ids) do
|
311
|
+
# {
|
312
|
+
# canonical_ids: 0, failure: 1, results: [{ error: 'NotRegistered' }]
|
313
|
+
# }
|
314
|
+
# end
|
315
|
+
#
|
316
|
+
# before do
|
317
|
+
# stub_request(:post, send_url).with(
|
318
|
+
# mock_request_attributes
|
319
|
+
# ).to_return(
|
320
|
+
# body: valid_response_body_with_not_registered_ids.to_json,
|
321
|
+
# headers: {},
|
322
|
+
# status: 200
|
323
|
+
# )
|
324
|
+
# end
|
325
|
+
#
|
326
|
+
# it 'should contain not_registered_ids' do
|
327
|
+
# response = subject.send(registration_ids)
|
328
|
+
# response.should eq(
|
329
|
+
# headers: {},
|
330
|
+
# canonical_ids: [],
|
331
|
+
# not_registered_ids: registration_ids,
|
332
|
+
# status_code: 200,
|
333
|
+
# response: 'success',
|
334
|
+
# body: '{"canonical_ids":0,"failure":1,"results":[{"error":"NotRegistered"}]}'
|
335
|
+
# )
|
336
|
+
# end
|
337
|
+
# end
|
338
|
+
# end
|
339
|
+
#
|
340
|
+
# describe 'sending group notifications' do
|
341
|
+
# # TODO: refactor to should_behave_like
|
342
|
+
# let(:valid_request_headers) do
|
343
|
+
# {
|
344
|
+
# "Authorization" => "key=#{api_key}",
|
345
|
+
# "Content-Type" => 'application/json',
|
346
|
+
# "Project-Id" => project_id
|
347
|
+
# }
|
348
|
+
# end
|
349
|
+
# let(:valid_response_body) do
|
350
|
+
# { notification_key: "APA91bGHXQBB...9QgnYOEURwm0I3lmyqzk2TXQ" }
|
351
|
+
# end
|
352
|
+
#
|
353
|
+
# let(:default_valid_request_body) do
|
354
|
+
# {
|
355
|
+
# registration_ids: registration_ids,
|
356
|
+
# operation: "create",
|
357
|
+
# notification_key_name: key_name
|
358
|
+
# }
|
359
|
+
# end
|
360
|
+
#
|
361
|
+
# subject { FCM.new(api_key) }
|
362
|
+
#
|
363
|
+
# # ref: https://firebase.google.com/docs/cloud-messaging/notifications#managing-device-groups-on-the-app-server
|
364
|
+
# context 'create' do
|
365
|
+
# let(:valid_request_body) do
|
366
|
+
# default_valid_request_body.merge({
|
367
|
+
# operation: "create"
|
368
|
+
# })
|
369
|
+
# end
|
370
|
+
#
|
371
|
+
# let(:mock_request_attributes) do
|
372
|
+
# {
|
373
|
+
# body: valid_request_body.to_json,
|
374
|
+
# headers: valid_request_headers
|
375
|
+
# }
|
376
|
+
# end
|
377
|
+
#
|
378
|
+
# before do
|
379
|
+
# stub_request(:post, group_notification_base_uri).with(
|
380
|
+
# mock_request_attributes
|
381
|
+
# ).to_return(
|
382
|
+
# body: valid_response_body.to_json,
|
383
|
+
# headers: {},
|
384
|
+
# status: 200
|
385
|
+
# )
|
386
|
+
# end
|
387
|
+
#
|
388
|
+
# it 'should send a post request' do
|
389
|
+
# response = subject.create(key_name, project_id, registration_ids)
|
390
|
+
# response.should eq(
|
391
|
+
# headers: {},
|
392
|
+
# status_code: 200,
|
393
|
+
# response: 'success',
|
394
|
+
# body: valid_response_body.to_json
|
395
|
+
# )
|
396
|
+
# end
|
397
|
+
# end # create context
|
398
|
+
#
|
399
|
+
# context 'add' do
|
400
|
+
# let(:valid_request_body) do
|
401
|
+
# default_valid_request_body.merge({
|
402
|
+
# operation: "add",
|
403
|
+
# notification_key: notification_key
|
404
|
+
# })
|
405
|
+
# end
|
406
|
+
#
|
407
|
+
# let(:mock_request_attributes) do
|
408
|
+
# {
|
409
|
+
# body: valid_request_body.to_json,
|
410
|
+
# headers: valid_request_headers
|
411
|
+
# }
|
412
|
+
# end
|
413
|
+
#
|
414
|
+
# before do
|
415
|
+
# stub_request(:post, group_notification_base_uri).with(
|
416
|
+
# mock_request_attributes
|
417
|
+
# ).to_return(
|
418
|
+
# body: valid_response_body.to_json,
|
419
|
+
# headers: {},
|
420
|
+
# status: 200
|
421
|
+
# )
|
422
|
+
# end
|
423
|
+
#
|
424
|
+
# it 'should send a post request' do
|
425
|
+
# response = subject.add(key_name, project_id, notification_key, registration_ids)
|
426
|
+
# response.should eq(
|
427
|
+
# headers: {},
|
428
|
+
# status_code: 200,
|
429
|
+
# response: 'success',
|
430
|
+
# body: valid_response_body.to_json
|
431
|
+
# )
|
432
|
+
# end
|
433
|
+
# end # add context
|
434
|
+
#
|
435
|
+
# context 'remove' do
|
436
|
+
# let(:valid_request_body) do
|
437
|
+
# default_valid_request_body.merge({
|
438
|
+
# operation: "remove",
|
439
|
+
# notification_key: notification_key
|
440
|
+
# })
|
441
|
+
# end
|
442
|
+
#
|
443
|
+
# let(:mock_request_attributes) do
|
444
|
+
# {
|
445
|
+
# body: valid_request_body.to_json,
|
446
|
+
# headers: valid_request_headers
|
447
|
+
# }
|
448
|
+
# end
|
449
|
+
#
|
450
|
+
# before do
|
451
|
+
# stub_request(:post, group_notification_base_uri).with(
|
452
|
+
# mock_request_attributes
|
453
|
+
# ).to_return(
|
454
|
+
# body: valid_response_body.to_json,
|
455
|
+
# headers: {},
|
456
|
+
# status: 200
|
457
|
+
# )
|
458
|
+
# end
|
459
|
+
#
|
460
|
+
# it 'should send a post request' do
|
461
|
+
# response = subject.remove(key_name, project_id, notification_key, registration_ids)
|
462
|
+
# response.should eq(
|
463
|
+
# headers: {},
|
464
|
+
# status_code: 200,
|
465
|
+
# response: 'success',
|
466
|
+
# body: valid_response_body.to_json
|
467
|
+
# )
|
468
|
+
# end
|
469
|
+
# end # remove context
|
470
|
+
# end
|
471
|
+
#
|
472
|
+
# describe 'subscribing to a topic' do
|
473
|
+
# # TODO
|
474
|
+
# end
|
475
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: twinpush
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Amaury González
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-12-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.15.4
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.15.4
|
27
|
+
description: TwinPush gem provides ruby bindings to TwinPush a messaging solution
|
28
|
+
that lets you reliably deliver messages and notifications at no cost to Android,
|
29
|
+
iOS or Web browsers.
|
30
|
+
email:
|
31
|
+
- amaury.muro@gmail.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- lib/twinpush.rb
|
37
|
+
- spec/spec_helper.rb
|
38
|
+
- spec/twinpush_spec.rb
|
39
|
+
homepage: https://github.com/amaurygonzalez/twinpush
|
40
|
+
licenses:
|
41
|
+
- MIT
|
42
|
+
metadata: {}
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: 2.0.0
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project: twinpush
|
59
|
+
rubygems_version: 2.7.6
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: Reliably deliver push notifications through TwinPush API
|
63
|
+
test_files:
|
64
|
+
- spec/spec_helper.rb
|
65
|
+
- spec/twinpush_spec.rb
|