pushpad 1.2.0 → 1.4.0
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/README.md +90 -0
- data/lib/pushpad/project.rb +95 -0
- data/lib/pushpad/request.rb +6 -0
- data/lib/pushpad/subscription.rb +69 -0
- data/lib/pushpad.rb +1 -0
- data/pushpad.gemspec +1 -1
- data/spec/pushpad/project_spec.rb +211 -0
- data/spec/pushpad/subscription_spec.rb +171 -0
- metadata +10 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a4c81351920b86c10b9926e94eb2aca07a9da9b87ddb3f9d4725459a0993e9c
|
4
|
+
data.tar.gz: 657f63d05bcabe69c8a197199ab516452d893450ad221b33a07b28162eb7d9be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a1e76b5ebfc31b43af6ff17d394c3f4bc88b41f359ab42359e018e5a213bda46c93ca830b3ec663b6b04d915244eda457463305ded412eb56fc448b50cac332
|
7
|
+
data.tar.gz: cebbc1b3610953a2064549998acc12348e9bd33c69ef97d20bbfb5f6bdcc4d7c94357cc0296dd4584ec68cb4ac8b3cb883cfa0cd774bff842dc326c1c760abd6
|
data/README.md
CHANGED
@@ -260,6 +260,96 @@ to get the full list in multiple requests.
|
|
260
260
|
subscriptions = Pushpad::Subscription.find_all(project_id: 5, page: 2)
|
261
261
|
```
|
262
262
|
|
263
|
+
You can also retrieve the data of a specific subscription if you already know its id:
|
264
|
+
|
265
|
+
```ruby
|
266
|
+
Pushpad::Subscription.find 123
|
267
|
+
Pushpad::Subscription.find 123, project_id: 456
|
268
|
+
```
|
269
|
+
|
270
|
+
## Updating push subscription data
|
271
|
+
|
272
|
+
Usually you add data, like user IDs and tags, to the push subscriptions using the [JavaScript SDK](https://pushpad.xyz/docs/javascript_sdk_reference) in the frontend.
|
273
|
+
|
274
|
+
However you can also update the subscription data from your server:
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
Pushpad::Subscription.find_all(uids: ['user1']).each do |subscription|
|
278
|
+
# update the user ID associated to the push subscription
|
279
|
+
subscription.update uid: 'myuser1'
|
280
|
+
|
281
|
+
# update the tags associated to the push subscription
|
282
|
+
tags = subscription.tags
|
283
|
+
tags << 'another_tag'
|
284
|
+
subscription.update tags: tags
|
285
|
+
end
|
286
|
+
```
|
287
|
+
|
288
|
+
## Importing push subscriptions
|
289
|
+
|
290
|
+
If you need to [import](https://pushpad.xyz/docs/import) some existing push subscriptions (from another service to Pushpad, or from your backups) or if you simply need to create some test data, you can use this method:
|
291
|
+
|
292
|
+
```ruby
|
293
|
+
attributes = {
|
294
|
+
endpoint: "https://example.com/push/f7Q1Eyf7EyfAb1",
|
295
|
+
p256dh: "BCQVDTlYWdl05lal3lG5SKr3VxTrEWpZErbkxWrzknHrIKFwihDoZpc_2sH6Sh08h-CacUYI-H8gW4jH-uMYZQ4=",
|
296
|
+
auth: "cdKMlhgVeSPzCXZ3V7FtgQ==",
|
297
|
+
uid: "exampleUid",
|
298
|
+
tags: ["exampleTag1", "exampleTag2"]
|
299
|
+
}
|
300
|
+
|
301
|
+
subscription = Pushpad::Subscription.create(attributes, project_id: 5)
|
302
|
+
```
|
303
|
+
|
304
|
+
Please note that this is not the standard way to collect subscriptions on Pushpad: usually you subscribe the users to the notifications using the [JavaScript SDK](https://pushpad.xyz/docs/javascript_sdk_reference) in the frontend.
|
305
|
+
|
306
|
+
## Deleting push subscriptions
|
307
|
+
|
308
|
+
Usually you unsubscribe a user from push notifications using the [JavaScript SDK](https://pushpad.xyz/docs/javascript_sdk_reference) in the frontend (recommended).
|
309
|
+
|
310
|
+
However you can also delete the subscriptions using this library. Be careful, the subscriptions are permanently deleted!
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
subscription = Pushpad::Subscription.find 123
|
314
|
+
subscription.delete
|
315
|
+
```
|
316
|
+
|
317
|
+
## Managing projects
|
318
|
+
|
319
|
+
Projects are usually created manually from the Pushpad dashboard. However you can also create projects from code if you need advanced automation or if you manage [many different domains](https://pushpad.xyz/docs/multiple_domains).
|
320
|
+
|
321
|
+
```ruby
|
322
|
+
attributes = {
|
323
|
+
# required attributes
|
324
|
+
sender_id: 123,
|
325
|
+
name: "My project",
|
326
|
+
website: "https://example.com",
|
327
|
+
|
328
|
+
# optional configurations
|
329
|
+
icon_url: "https://example.com/icon.png",
|
330
|
+
badge_url: "https://example.com/badge.png",
|
331
|
+
notifications_ttl: 604800,
|
332
|
+
notifications_require_interaction: false,
|
333
|
+
notifications_silent: false
|
334
|
+
}
|
335
|
+
|
336
|
+
project = Pushpad::Project.create(attributes)
|
337
|
+
```
|
338
|
+
|
339
|
+
You can also find, update and delete projects:
|
340
|
+
|
341
|
+
```ruby
|
342
|
+
Pushpad::Project.find_all.each do |p|
|
343
|
+
puts "Project #{p.id}: #{p.name}"
|
344
|
+
end
|
345
|
+
|
346
|
+
project = Pushpad::Project.find 123
|
347
|
+
|
348
|
+
project.update(name: 'The New Project Name')
|
349
|
+
|
350
|
+
project.delete
|
351
|
+
```
|
352
|
+
|
263
353
|
## License
|
264
354
|
|
265
355
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Pushpad
|
2
|
+
class Project
|
3
|
+
class CreateError < RuntimeError
|
4
|
+
end
|
5
|
+
|
6
|
+
class FindError < RuntimeError
|
7
|
+
end
|
8
|
+
|
9
|
+
class UpdateError < RuntimeError
|
10
|
+
end
|
11
|
+
|
12
|
+
class DeleteError < RuntimeError
|
13
|
+
end
|
14
|
+
|
15
|
+
ATTRIBUTES = :id, :sender_id, :name, :website, :icon_url, :badge_url, :notifications_ttl, :notifications_require_interaction, :notifications_silent, :created_at
|
16
|
+
|
17
|
+
attr_reader *ATTRIBUTES
|
18
|
+
|
19
|
+
def initialize(options)
|
20
|
+
@id = options[:id]
|
21
|
+
@sender_id = options[:sender_id]
|
22
|
+
@name = options[:name]
|
23
|
+
@website = options[:website]
|
24
|
+
@icon_url = options[:icon_url]
|
25
|
+
@badge_url = options[:badge_url]
|
26
|
+
@notifications_ttl = options[:notifications_ttl]
|
27
|
+
@notifications_require_interaction = options[:notifications_require_interaction]
|
28
|
+
@notifications_silent = options[:notifications_silent]
|
29
|
+
@created_at = options[:created_at] && Time.parse(options[:created_at])
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.create(attributes)
|
33
|
+
endpoint = "https://pushpad.xyz/api/v1/projects"
|
34
|
+
response = Request.post(endpoint, attributes.to_json)
|
35
|
+
|
36
|
+
unless response.code == "201"
|
37
|
+
raise CreateError, "Response #{response.code} #{response.message}: #{response.body}"
|
38
|
+
end
|
39
|
+
|
40
|
+
new(JSON.parse(response.body, symbolize_names: true))
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.find(id)
|
44
|
+
response = Request.get("https://pushpad.xyz/api/v1/projects/#{id}")
|
45
|
+
|
46
|
+
unless response.code == "200"
|
47
|
+
raise FindError, "Response #{response.code} #{response.message}: #{response.body}"
|
48
|
+
end
|
49
|
+
|
50
|
+
new(JSON.parse(response.body, symbolize_names: true))
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.find_all
|
54
|
+
response = Request.get("https://pushpad.xyz/api/v1/projects")
|
55
|
+
|
56
|
+
unless response.code == "200"
|
57
|
+
raise FindError, "Response #{response.code} #{response.message}: #{response.body}"
|
58
|
+
end
|
59
|
+
|
60
|
+
JSON.parse(response.body, symbolize_names: true).map do |attributes|
|
61
|
+
new(attributes)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def update(attributes)
|
66
|
+
raise "You must set id" unless id
|
67
|
+
|
68
|
+
endpoint = "https://pushpad.xyz/api/v1/projects/#{id}"
|
69
|
+
response = Request.patch(endpoint, attributes.to_json)
|
70
|
+
|
71
|
+
unless response.code == "200"
|
72
|
+
raise UpdateError, "Response #{response.code} #{response.message}: #{response.body}"
|
73
|
+
end
|
74
|
+
|
75
|
+
updated = self.class.new(JSON.parse(response.body, symbolize_names: true))
|
76
|
+
|
77
|
+
ATTRIBUTES.each do |attr|
|
78
|
+
self.instance_variable_set("@#{attr}", updated.instance_variable_get("@#{attr}"))
|
79
|
+
end
|
80
|
+
|
81
|
+
self
|
82
|
+
end
|
83
|
+
|
84
|
+
def delete
|
85
|
+
raise "You must set id" unless id
|
86
|
+
|
87
|
+
response = Request.delete("https://pushpad.xyz/api/v1/projects/#{id}")
|
88
|
+
|
89
|
+
unless response.code == "202"
|
90
|
+
raise DeleteError, "Response #{response.code} #{response.message}: #{response.body}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
data/lib/pushpad/request.rb
CHANGED
@@ -19,6 +19,12 @@ module Pushpad
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
def patch(endpoint, body, options = {})
|
23
|
+
perform(Net::HTTP::Patch, endpoint, options) do |request|
|
24
|
+
request.body = body
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
22
28
|
def delete(endpoint, options = {})
|
23
29
|
perform(Net::HTTP::Delete, endpoint, options)
|
24
30
|
end
|
data/lib/pushpad/subscription.rb
CHANGED
@@ -1,11 +1,20 @@
|
|
1
1
|
module Pushpad
|
2
2
|
class Subscription
|
3
|
+
class CreateError < RuntimeError
|
4
|
+
end
|
5
|
+
|
6
|
+
class UpdateError < RuntimeError
|
7
|
+
end
|
8
|
+
|
3
9
|
class CountError < RuntimeError
|
4
10
|
end
|
5
11
|
|
6
12
|
class FindError < RuntimeError
|
7
13
|
end
|
8
14
|
|
15
|
+
class DeleteError < RuntimeError
|
16
|
+
end
|
17
|
+
|
9
18
|
attr_reader :id, :endpoint, :p256dh, :auth, :uid, :tags, :last_click_at, :created_at
|
10
19
|
|
11
20
|
def initialize(options)
|
@@ -18,6 +27,20 @@ module Pushpad
|
|
18
27
|
@last_click_at = options[:last_click_at] && Time.parse(options[:last_click_at])
|
19
28
|
@created_at = options[:created_at] && Time.parse(options[:created_at])
|
20
29
|
end
|
30
|
+
|
31
|
+
def self.create(attributes, options = {})
|
32
|
+
project_id = options[:project_id] || Pushpad.project_id
|
33
|
+
raise "You must set project_id" unless project_id
|
34
|
+
|
35
|
+
endpoint = "https://pushpad.xyz/api/v1/projects/#{project_id}/subscriptions"
|
36
|
+
response = Request.post(endpoint, attributes.to_json)
|
37
|
+
|
38
|
+
unless response.code == "201"
|
39
|
+
raise CreateError, "Response #{response.code} #{response.message}: #{response.body}"
|
40
|
+
end
|
41
|
+
|
42
|
+
new(JSON.parse(response.body, symbolize_names: true))
|
43
|
+
end
|
21
44
|
|
22
45
|
def self.count(options = {})
|
23
46
|
project_id = options[:project_id] || Pushpad.project_id
|
@@ -33,6 +56,19 @@ module Pushpad
|
|
33
56
|
response["X-Total-Count"].to_i
|
34
57
|
end
|
35
58
|
|
59
|
+
def self.find(id, options = {})
|
60
|
+
project_id = options[:project_id] || Pushpad.project_id
|
61
|
+
raise "You must set project_id" unless project_id
|
62
|
+
|
63
|
+
response = Request.get("https://pushpad.xyz/api/v1/projects/#{project_id}/subscriptions/#{id}")
|
64
|
+
|
65
|
+
unless response.code == "200"
|
66
|
+
raise FindError, "Response #{response.code} #{response.message}: #{response.body}"
|
67
|
+
end
|
68
|
+
|
69
|
+
new(JSON.parse(response.body, symbolize_names: true))
|
70
|
+
end
|
71
|
+
|
36
72
|
def self.find_all(options = {})
|
37
73
|
project_id = options[:project_id] || Pushpad.project_id
|
38
74
|
raise "You must set project_id" unless project_id
|
@@ -51,6 +87,39 @@ module Pushpad
|
|
51
87
|
new(attributes)
|
52
88
|
end
|
53
89
|
end
|
90
|
+
|
91
|
+
def update(attributes, options = {})
|
92
|
+
project_id = options[:project_id] || Pushpad.project_id
|
93
|
+
raise "You must set project_id" unless project_id
|
94
|
+
|
95
|
+
raise "You must set id" unless id
|
96
|
+
|
97
|
+
endpoint = "https://pushpad.xyz/api/v1/projects/#{project_id}/subscriptions/#{id}"
|
98
|
+
response = Request.patch(endpoint, attributes.to_json)
|
99
|
+
|
100
|
+
unless response.code == "200"
|
101
|
+
raise UpdateError, "Response #{response.code} #{response.message}: #{response.body}"
|
102
|
+
end
|
103
|
+
|
104
|
+
attributes = JSON.parse(response.body, symbolize_names: true)
|
105
|
+
@uid = attributes[:uid]
|
106
|
+
@tags = attributes[:tags]
|
107
|
+
|
108
|
+
self
|
109
|
+
end
|
110
|
+
|
111
|
+
def delete(options = {})
|
112
|
+
project_id = options[:project_id] || Pushpad.project_id
|
113
|
+
raise "You must set project_id" unless project_id
|
114
|
+
|
115
|
+
raise "You must set id" unless id
|
116
|
+
|
117
|
+
response = Request.delete("https://pushpad.xyz/api/v1/projects/#{project_id}/subscriptions/#{id}")
|
118
|
+
|
119
|
+
unless response.code == "204"
|
120
|
+
raise DeleteError, "Response #{response.code} #{response.message}: #{response.body}"
|
121
|
+
end
|
122
|
+
end
|
54
123
|
|
55
124
|
private
|
56
125
|
|
data/lib/pushpad.rb
CHANGED
data/pushpad.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "pushpad"
|
3
|
-
spec.version = '1.
|
3
|
+
spec.version = '1.4.0'
|
4
4
|
spec.authors = ["Pushpad"]
|
5
5
|
spec.email = ["support@pushpad.xyz"]
|
6
6
|
spec.summary = "Web push notifications for Chrome, Firefox, Opera, Edge and Safari using Pushpad."
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Pushpad
|
4
|
+
describe Project do
|
5
|
+
|
6
|
+
def stub_projects_post(attributes = {})
|
7
|
+
stub_request(:post, "https://pushpad.xyz/api/v1/projects").
|
8
|
+
with(body: hash_including(attributes)).
|
9
|
+
to_return(status: 201, body: attributes.to_json)
|
10
|
+
end
|
11
|
+
|
12
|
+
def stub_failing_projects_post
|
13
|
+
stub_request(:post, "https://pushpad.xyz/api/v1/projects").
|
14
|
+
to_return(status: 422)
|
15
|
+
end
|
16
|
+
|
17
|
+
def stub_project_get(attributes)
|
18
|
+
stub_request(:get, "https://pushpad.xyz/api/v1/projects/#{attributes[:id]}").
|
19
|
+
to_return(status: 200, body: attributes.to_json)
|
20
|
+
end
|
21
|
+
|
22
|
+
def stub_failing_project_get(attributes)
|
23
|
+
stub_request(:get, "https://pushpad.xyz/api/v1/projects/#{attributes[:id]}").
|
24
|
+
to_return(status: 404)
|
25
|
+
end
|
26
|
+
|
27
|
+
def stub_projects_get(list)
|
28
|
+
stub_request(:get, "https://pushpad.xyz/api/v1/projects").
|
29
|
+
to_return(status: 200, body: list.to_json)
|
30
|
+
end
|
31
|
+
|
32
|
+
def stub_failing_projects_get
|
33
|
+
stub_request(:get, "https://pushpad.xyz/api/v1/projects").
|
34
|
+
to_return(status: 401)
|
35
|
+
end
|
36
|
+
|
37
|
+
def stub_project_patch(id, attributes)
|
38
|
+
stub_request(:patch, "https://pushpad.xyz/api/v1/projects/#{id}").
|
39
|
+
with(body: hash_including(attributes)).
|
40
|
+
to_return(status: 200, body: attributes.to_json)
|
41
|
+
end
|
42
|
+
|
43
|
+
def stub_failing_project_patch(id)
|
44
|
+
stub_request(:patch, "https://pushpad.xyz/api/v1/projects/#{id}").
|
45
|
+
to_return(status: 422)
|
46
|
+
end
|
47
|
+
|
48
|
+
def stub_project_delete(id)
|
49
|
+
stub_request(:delete, "https://pushpad.xyz/api/v1/projects/#{id}").
|
50
|
+
to_return(status: 202)
|
51
|
+
end
|
52
|
+
|
53
|
+
def stub_failing_project_delete(id)
|
54
|
+
stub_request(:delete, "https://pushpad.xyz/api/v1/projects/#{id}").
|
55
|
+
to_return(status: 403)
|
56
|
+
end
|
57
|
+
|
58
|
+
describe ".create" do
|
59
|
+
it "creates a new project with the given attributes and returns it" do
|
60
|
+
attributes = {
|
61
|
+
sender_id: 123,
|
62
|
+
name: "My project",
|
63
|
+
website: "https://example.com"
|
64
|
+
}
|
65
|
+
stub = stub_projects_post(attributes)
|
66
|
+
|
67
|
+
project = Project.create(attributes)
|
68
|
+
expect(project).to have_attributes(attributes)
|
69
|
+
|
70
|
+
expect(stub).to have_been_requested
|
71
|
+
end
|
72
|
+
|
73
|
+
it "fails with CreateError if response status code is not 201" do
|
74
|
+
attributes = { name: "My project" }
|
75
|
+
stub_failing_projects_post
|
76
|
+
|
77
|
+
expect {
|
78
|
+
Project.create(attributes)
|
79
|
+
}.to raise_error(Project::CreateError)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe ".find" do
|
84
|
+
it "returns project with attributes from json response" do
|
85
|
+
attributes = {
|
86
|
+
id: 361,
|
87
|
+
sender_id: 123,
|
88
|
+
name: "Example Project",
|
89
|
+
website: "https://example.com",
|
90
|
+
icon_url: "https://example.com/icon.png",
|
91
|
+
badge_url: "https://example.com/badge.png",
|
92
|
+
notifications_ttl: 604800,
|
93
|
+
notifications_require_interaction: false,
|
94
|
+
notifications_silent: false,
|
95
|
+
created_at: "2016-07-06T10:58:39.143Z"
|
96
|
+
}
|
97
|
+
stub_project_get(attributes)
|
98
|
+
|
99
|
+
project = Project.find(361)
|
100
|
+
|
101
|
+
attributes.delete(:created_at)
|
102
|
+
expect(project).to have_attributes(attributes)
|
103
|
+
expect(project.created_at.utc.to_s).to eq(Time.utc(2016, 7, 6, 10, 58, 39.143).to_s)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "fails with FindError if response status code is not 200" do
|
107
|
+
attributes = { id: 362 }
|
108
|
+
stub_failing_project_get(attributes)
|
109
|
+
|
110
|
+
expect {
|
111
|
+
Project.find(362)
|
112
|
+
}.to raise_error(Project::FindError)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe ".find_all" do
|
117
|
+
it "returns projects with attributes from json response" do
|
118
|
+
attributes = {
|
119
|
+
id: 361,
|
120
|
+
sender_id: 123,
|
121
|
+
name: "Example Project",
|
122
|
+
website: "https://example.com",
|
123
|
+
icon_url: "https://example.com/icon.png",
|
124
|
+
badge_url: "https://example.com/badge.png",
|
125
|
+
notifications_ttl: 604800,
|
126
|
+
notifications_require_interaction: false,
|
127
|
+
notifications_silent: false,
|
128
|
+
created_at: "2016-07-06T10:58:39.143Z"
|
129
|
+
}
|
130
|
+
stub_projects_get([attributes])
|
131
|
+
|
132
|
+
projects = Project.find_all
|
133
|
+
|
134
|
+
attributes.delete(:created_at)
|
135
|
+
expect(projects[0]).to have_attributes(attributes)
|
136
|
+
expect(projects[0].created_at.utc.to_s).to eq(Time.utc(2016, 7, 6, 10, 58, 39.143).to_s)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "fails with FindError if response status code is not 200" do
|
140
|
+
stub_failing_projects_get
|
141
|
+
|
142
|
+
expect {
|
143
|
+
Project.find_all
|
144
|
+
}.to raise_error(Project::FindError)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "works properly when there are no results" do
|
148
|
+
stub_projects_get([])
|
149
|
+
|
150
|
+
projects = Project.find_all
|
151
|
+
|
152
|
+
expect(projects).to eq([])
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "#update" do
|
157
|
+
it "updates a project with the given attributes and returns it" do
|
158
|
+
attributes = {
|
159
|
+
name: "The New Project Name"
|
160
|
+
}
|
161
|
+
stub = stub_project_patch(5, attributes)
|
162
|
+
|
163
|
+
project = Project.new(id: 5)
|
164
|
+
project.update attributes
|
165
|
+
expect(project).to have_attributes(attributes)
|
166
|
+
|
167
|
+
expect(stub).to have_been_requested
|
168
|
+
end
|
169
|
+
|
170
|
+
it "fails with UpdateError if response status code is not 200" do
|
171
|
+
attributes = { name: "" }
|
172
|
+
stub_failing_project_patch(5)
|
173
|
+
|
174
|
+
project = Project.new(id: 5)
|
175
|
+
|
176
|
+
expect {
|
177
|
+
project.update attributes
|
178
|
+
}.to raise_error(Project::UpdateError)
|
179
|
+
end
|
180
|
+
|
181
|
+
it "fails with helpful error message when id is missing" do
|
182
|
+
expect {
|
183
|
+
Project.new(id: nil).update({})
|
184
|
+
}.to raise_error(/must set id/)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe "#delete" do
|
189
|
+
it "deletes a project" do
|
190
|
+
stub = stub_project_delete(5)
|
191
|
+
|
192
|
+
project = Project.new(id: 5)
|
193
|
+
res = project.delete
|
194
|
+
expect(res).to be_nil
|
195
|
+
|
196
|
+
expect(stub).to have_been_requested
|
197
|
+
end
|
198
|
+
|
199
|
+
it "fails with DeleteError if response status code is not 202" do
|
200
|
+
stub_failing_project_delete(5)
|
201
|
+
|
202
|
+
project = Project.new(id: 5)
|
203
|
+
|
204
|
+
expect {
|
205
|
+
project.delete
|
206
|
+
}.to raise_error(Project::DeleteError)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
end
|
@@ -2,6 +2,16 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
module Pushpad
|
4
4
|
describe Subscription do
|
5
|
+
def stub_subscription_get(options)
|
6
|
+
stub_request(:get, "https://pushpad.xyz/api/v1/projects/#{options[:project_id]}/subscriptions/#{options[:id]}").
|
7
|
+
to_return(status: 200, body: options[:attributes].to_json)
|
8
|
+
end
|
9
|
+
|
10
|
+
def stub_failing_subscription_get(options)
|
11
|
+
stub_request(:get, "https://pushpad.xyz/api/v1/projects/#{options[:project_id]}/subscriptions/#{options[:id]}").
|
12
|
+
to_return(status: 404)
|
13
|
+
end
|
14
|
+
|
5
15
|
def stub_subscriptions_head(options)
|
6
16
|
stub_request(:head, "https://pushpad.xyz/api/v1/projects/#{options[:project_id]}/subscriptions").
|
7
17
|
with(query: hash_including(options.fetch(:query, {}))).
|
@@ -24,6 +34,63 @@ module Pushpad
|
|
24
34
|
stub_request(:get, "https://pushpad.xyz/api/v1/projects/#{options[:project_id]}/subscriptions").
|
25
35
|
to_return(status: 403)
|
26
36
|
end
|
37
|
+
|
38
|
+
def stub_subscriptions_post(project_id, attributes = {})
|
39
|
+
stub_request(:post, "https://pushpad.xyz/api/v1/projects/#{project_id}/subscriptions").
|
40
|
+
with(body: hash_including(attributes)).
|
41
|
+
to_return(status: 201, body: attributes.to_json)
|
42
|
+
end
|
43
|
+
|
44
|
+
def stub_failing_subscriptions_post(project_id)
|
45
|
+
stub_request(:post, "https://pushpad.xyz/api/v1/projects/#{project_id}/subscriptions").
|
46
|
+
to_return(status: 403)
|
47
|
+
end
|
48
|
+
|
49
|
+
def stub_subscription_patch(project_id, id, attributes = {})
|
50
|
+
stub_request(:patch, "https://pushpad.xyz/api/v1/projects/#{project_id}/subscriptions/#{id}").
|
51
|
+
with(body: hash_including(attributes)).
|
52
|
+
to_return(status: 200, body: attributes.to_json)
|
53
|
+
end
|
54
|
+
|
55
|
+
def stub_failing_subscription_patch(project_id, id)
|
56
|
+
stub_request(:patch, "https://pushpad.xyz/api/v1/projects/#{project_id}/subscriptions/#{id}").
|
57
|
+
to_return(status: 422)
|
58
|
+
end
|
59
|
+
|
60
|
+
def stub_subscription_delete(project_id, id)
|
61
|
+
stub_request(:delete, "https://pushpad.xyz/api/v1/projects/#{project_id}/subscriptions/#{id}").
|
62
|
+
to_return(status: 204)
|
63
|
+
end
|
64
|
+
|
65
|
+
def stub_failing_subscription_delete(project_id, id)
|
66
|
+
stub_request(:delete, "https://pushpad.xyz/api/v1/projects/#{project_id}/subscriptions/#{id}").
|
67
|
+
to_return(status: 403)
|
68
|
+
end
|
69
|
+
|
70
|
+
describe ".create" do
|
71
|
+
it "creates a new subscription with the given attributes and returns it" do
|
72
|
+
attributes = {
|
73
|
+
endpoint: "https://example.com/push/f7Q1Eyf7EyfAb1",
|
74
|
+
p256dh: "BCQVDTlYWdl05lal3lG5SKr3VxTrEWpZErbkxWrzknHrIKFwihDoZpc_2sH6Sh08h-CacUYI-H8gW4jH-uMYZQ4=",
|
75
|
+
auth: "cdKMlhgVeSPzCXZ3V7FtgQ==",
|
76
|
+
uid: "exampleUid",
|
77
|
+
tags: ["exampleTag1", "exampleTag2"]
|
78
|
+
}
|
79
|
+
stub_subscriptions_post(5, attributes)
|
80
|
+
|
81
|
+
subscription = Subscription.create(attributes, project_id: 5)
|
82
|
+
expect(subscription).to have_attributes(attributes)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "fails with CreateError if response status code is not 201" do
|
86
|
+
attributes = { endpoint: "https://example.com/push/123" }
|
87
|
+
stub_failing_subscriptions_post(5)
|
88
|
+
|
89
|
+
expect {
|
90
|
+
Subscription.create(attributes, project_id: 5)
|
91
|
+
}.to raise_error(Subscription::CreateError)
|
92
|
+
end
|
93
|
+
end
|
27
94
|
|
28
95
|
describe ".count" do
|
29
96
|
it "returns value from X-Total-Count header" do
|
@@ -93,6 +160,46 @@ module Pushpad
|
|
93
160
|
end
|
94
161
|
end
|
95
162
|
|
163
|
+
describe ".find" do
|
164
|
+
it "returns subscription with attributes from json response" do
|
165
|
+
attributes = {
|
166
|
+
id: 5,
|
167
|
+
endpoint: "https://example.com/push/f7Q1Eyf7EyfAb1",
|
168
|
+
p256dh: "BCQVDTlYWdl05lal3lG5SKr3VxTrEWpZErbkxWrzknHrIKFwihDoZpc_2sH6Sh08h-CacUYI-H8gW4jH-uMYZQ4=",
|
169
|
+
auth: "cdKMlhgVeSPzCXZ3V7FtgQ==",
|
170
|
+
uid: "exampleUid",
|
171
|
+
tags: ["exampleTag1", "exampleTag2"],
|
172
|
+
last_click_at: "2023-11-03T10:30:00.000Z",
|
173
|
+
created_at: "2016-09-06T10:47:05.494Z"
|
174
|
+
}
|
175
|
+
stub_subscription_get(id: 5, project_id: 10, attributes: attributes)
|
176
|
+
|
177
|
+
subscription = Subscription.find(5, project_id: 10)
|
178
|
+
|
179
|
+
attributes.delete(:last_click_at)
|
180
|
+
attributes.delete(:created_at)
|
181
|
+
expect(subscription).to have_attributes(attributes)
|
182
|
+
expect(subscription.last_click_at.utc.to_s).to eq(Time.utc(2023, 11, 3, 10, 30, 0.0).to_s)
|
183
|
+
expect(subscription.created_at.utc.to_s).to eq(Time.utc(2016, 9, 6, 10, 47, 5.494).to_s)
|
184
|
+
end
|
185
|
+
|
186
|
+
it "fails with FindError if response status code is not 200" do
|
187
|
+
stub_failing_subscription_get(id: 5, project_id: 10)
|
188
|
+
|
189
|
+
expect {
|
190
|
+
Subscription.find(5, project_id: 10)
|
191
|
+
}.to raise_error(Subscription::FindError)
|
192
|
+
end
|
193
|
+
|
194
|
+
it "fails with helpful error message when project_id is missing" do
|
195
|
+
Pushpad.project_id = nil
|
196
|
+
|
197
|
+
expect {
|
198
|
+
Subscription.find 5
|
199
|
+
}.to raise_error(/must set project_id/)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
96
203
|
describe ".find_all" do
|
97
204
|
it "returns subscriptions of project with attributes from json response" do
|
98
205
|
attributes = {
|
@@ -197,5 +304,69 @@ module Pushpad
|
|
197
304
|
end
|
198
305
|
end
|
199
306
|
|
307
|
+
describe "#update" do
|
308
|
+
it "updates a subscription with the given attributes and returns it" do
|
309
|
+
attributes = {
|
310
|
+
uid: "exampleUid",
|
311
|
+
tags: ["exampleTag1", "exampleTag2"]
|
312
|
+
}
|
313
|
+
stub_subscription_patch(5, 123, attributes)
|
314
|
+
|
315
|
+
subscription = Subscription.new(id: 123)
|
316
|
+
subscription.update attributes, project_id: 5
|
317
|
+
expect(subscription).to have_attributes(attributes)
|
318
|
+
end
|
319
|
+
|
320
|
+
it "fails with UpdateError if response status code is not 200" do
|
321
|
+
attributes = { uid: "exampleUid" }
|
322
|
+
stub_failing_subscription_patch(5, 123)
|
323
|
+
|
324
|
+
subscription = Subscription.new(id: 123)
|
325
|
+
|
326
|
+
expect {
|
327
|
+
subscription.update attributes, project_id: 5
|
328
|
+
}.to raise_error(Subscription::UpdateError)
|
329
|
+
end
|
330
|
+
|
331
|
+
it "fails with helpful error message when project_id is missing" do
|
332
|
+
Pushpad.project_id = nil
|
333
|
+
|
334
|
+
expect {
|
335
|
+
Subscription.new(id: 123).update({})
|
336
|
+
}.to raise_error(/must set project_id/)
|
337
|
+
end
|
338
|
+
|
339
|
+
it "fails with helpful error message when id is missing" do
|
340
|
+
Pushpad.project_id = 5
|
341
|
+
|
342
|
+
expect {
|
343
|
+
Subscription.new(id: nil).update({})
|
344
|
+
}.to raise_error(/must set id/)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
describe "#delete" do
|
349
|
+
it "deletes a subscription" do
|
350
|
+
Pushpad.project_id = 5
|
351
|
+
stub_subscription_delete(5, 123)
|
352
|
+
|
353
|
+
subscription = Subscription.new(id: 123)
|
354
|
+
|
355
|
+
res = subscription.delete
|
356
|
+
expect(res).to be_nil
|
357
|
+
end
|
358
|
+
|
359
|
+
it "fails with DeleteError if response status code is not 204" do
|
360
|
+
Pushpad.project_id = 5
|
361
|
+
stub_failing_subscription_delete(5, 123)
|
362
|
+
|
363
|
+
subscription = Subscription.new(id: 123)
|
364
|
+
|
365
|
+
expect {
|
366
|
+
subscription.delete
|
367
|
+
}.to raise_error(Subscription::DeleteError)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
200
371
|
end
|
201
372
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pushpad
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pushpad
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
description:
|
41
|
+
description:
|
42
42
|
email:
|
43
43
|
- support@pushpad.xyz
|
44
44
|
executables: []
|
@@ -54,10 +54,12 @@ files:
|
|
54
54
|
- Rakefile
|
55
55
|
- lib/pushpad.rb
|
56
56
|
- lib/pushpad/notification.rb
|
57
|
+
- lib/pushpad/project.rb
|
57
58
|
- lib/pushpad/request.rb
|
58
59
|
- lib/pushpad/subscription.rb
|
59
60
|
- pushpad.gemspec
|
60
61
|
- spec/pushpad/notification_spec.rb
|
62
|
+
- spec/pushpad/project_spec.rb
|
61
63
|
- spec/pushpad/request_spec.rb
|
62
64
|
- spec/pushpad/subscription_spec.rb
|
63
65
|
- spec/pushpad_spec.rb
|
@@ -66,7 +68,7 @@ homepage: https://pushpad.xyz
|
|
66
68
|
licenses:
|
67
69
|
- MIT
|
68
70
|
metadata: {}
|
69
|
-
post_install_message:
|
71
|
+
post_install_message:
|
70
72
|
rdoc_options: []
|
71
73
|
require_paths:
|
72
74
|
- lib
|
@@ -81,13 +83,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
81
83
|
- !ruby/object:Gem::Version
|
82
84
|
version: '0'
|
83
85
|
requirements: []
|
84
|
-
rubygems_version: 3.
|
85
|
-
signing_key:
|
86
|
+
rubygems_version: 3.5.16
|
87
|
+
signing_key:
|
86
88
|
specification_version: 4
|
87
89
|
summary: Web push notifications for Chrome, Firefox, Opera, Edge and Safari using
|
88
90
|
Pushpad.
|
89
91
|
test_files:
|
90
92
|
- spec/pushpad/notification_spec.rb
|
93
|
+
- spec/pushpad/project_spec.rb
|
91
94
|
- spec/pushpad/request_spec.rb
|
92
95
|
- spec/pushpad/subscription_spec.rb
|
93
96
|
- spec/pushpad_spec.rb
|