pushpad 1.4.0 → 1.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a4c81351920b86c10b9926e94eb2aca07a9da9b87ddb3f9d4725459a0993e9c
4
- data.tar.gz: 657f63d05bcabe69c8a197199ab516452d893450ad221b33a07b28162eb7d9be
3
+ metadata.gz: 79880c6abcf0f8ecda48ad0df65bb07ee440660f58fb5fd60d898ceb162d5263
4
+ data.tar.gz: aa148bdaf14910ea7041867163d3f524682be1e54533d6153c790326961c7edc
5
5
  SHA512:
6
- metadata.gz: 6a1e76b5ebfc31b43af6ff17d394c3f4bc88b41f359ab42359e018e5a213bda46c93ca830b3ec663b6b04d915244eda457463305ded412eb56fc448b50cac332
7
- data.tar.gz: cebbc1b3610953a2064549998acc12348e9bd33c69ef97d20bbfb5f6bdcc4d7c94357cc0296dd4584ec68cb4ac8b3cb883cfa0cd774bff842dc326c1c760abd6
6
+ metadata.gz: 8e0b08f9dc1b48b61fc4fc12f8a0a6a22872de66d4e61736792a5548b2f4795b36e5f9275589cfd8d717baf86278908b0833305bbb6fd1ab8fac75150a47d177
7
+ data.tar.gz: '08d16dc17ec9b9a5e2454f254fde072880c2eb50f84b298b882362d36c9b40dc8957b75fcb8935b5e045279c76a1da7de4fbaea685d8e9dedfed365d2993f093'
@@ -10,9 +10,9 @@ jobs:
10
10
  strategy:
11
11
  fail-fast: false
12
12
  matrix:
13
- ruby-version: ['3.0', '3.1', '3.2', '3.3']
13
+ ruby-version: ['3.0', '3.1', '3.2', '3.3', '3.4']
14
14
  steps:
15
- - uses: actions/checkout@v3
15
+ - uses: actions/checkout@v5
16
16
  - name: Set up Ruby
17
17
  uses: ruby/setup-ruby@v1
18
18
  with:
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2016-2022 Pushpad (https://pushpad.xyz)
3
+ Copyright (c) 2016-2025 Pushpad (https://pushpad.xyz)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -350,6 +350,38 @@ project.update(name: 'The New Project Name')
350
350
  project.delete
351
351
  ```
352
352
 
353
+ ## Managing senders
354
+
355
+ Senders are usually created manually from the Pushpad dashboard. However you can also create senders from code.
356
+
357
+ ```ruby
358
+ attributes = {
359
+ # required attributes
360
+ name: "My sender",
361
+
362
+ # optional configurations
363
+ # do not include these fields if you want to generate them automatically
364
+ vapid_private_key: "-----BEGIN EC PRIVATE KEY----- ...",
365
+ vapid_public_key: "-----BEGIN PUBLIC KEY----- ..."
366
+ }
367
+
368
+ sender = Pushpad::Sender.create(attributes)
369
+ ```
370
+
371
+ You can also find, update and delete senders:
372
+
373
+ ```ruby
374
+ Pushpad::Sender.find_all.each do |s|
375
+ puts "Sender #{s.id}: #{s.name}"
376
+ end
377
+
378
+ sender = Pushpad::Sender.find 987
379
+
380
+ sender.update(name: 'The New Sender Name')
381
+
382
+ sender.delete
383
+ ```
384
+
353
385
  ## License
354
386
 
355
387
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -16,10 +16,11 @@ module Pushpad
16
16
  end
17
17
 
18
18
  attr_accessor :body, :title, :target_url, :icon_url, :badge_url, :image_url, :ttl, :require_interaction, :silent, :urgent, :custom_data, :custom_metrics, :actions, :starred, :send_at
19
- attr_reader :id, :created_at, :scheduled_count, :successfully_sent_count, :opened_count
19
+ attr_reader :id, :project_id, :created_at, :scheduled_count, :successfully_sent_count, :opened_count
20
20
 
21
21
  def initialize(options)
22
22
  @id = options[:id]
23
+ @project_id = options[:project_id]
23
24
  @created_at = options[:created_at] && Time.parse(options[:created_at])
24
25
  @scheduled_count = options[:scheduled_count]
25
26
  @successfully_sent_count = options[:successfully_sent_count]
@@ -0,0 +1,90 @@
1
+ module Pushpad
2
+ class Sender
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, :name, :vapid_private_key, :vapid_public_key, :created_at
16
+
17
+ attr_reader *ATTRIBUTES
18
+
19
+ def initialize(options)
20
+ @id = options[:id]
21
+ @name = options[:name]
22
+ @vapid_private_key = options[:vapid_private_key]
23
+ @vapid_public_key = options[:vapid_public_key]
24
+ @created_at = options[:created_at] && Time.parse(options[:created_at])
25
+ end
26
+
27
+ def self.create(attributes)
28
+ endpoint = "https://pushpad.xyz/api/v1/senders"
29
+ response = Request.post(endpoint, attributes.to_json)
30
+
31
+ unless response.code == "201"
32
+ raise CreateError, "Response #{response.code} #{response.message}: #{response.body}"
33
+ end
34
+
35
+ new(JSON.parse(response.body, symbolize_names: true))
36
+ end
37
+
38
+ def self.find(id)
39
+ response = Request.get("https://pushpad.xyz/api/v1/senders/#{id}")
40
+
41
+ unless response.code == "200"
42
+ raise FindError, "Response #{response.code} #{response.message}: #{response.body}"
43
+ end
44
+
45
+ new(JSON.parse(response.body, symbolize_names: true))
46
+ end
47
+
48
+ def self.find_all
49
+ response = Request.get("https://pushpad.xyz/api/v1/senders")
50
+
51
+ unless response.code == "200"
52
+ raise FindError, "Response #{response.code} #{response.message}: #{response.body}"
53
+ end
54
+
55
+ JSON.parse(response.body, symbolize_names: true).map do |attributes|
56
+ new(attributes)
57
+ end
58
+ end
59
+
60
+ def update(attributes)
61
+ raise "You must set id" unless id
62
+
63
+ endpoint = "https://pushpad.xyz/api/v1/senders/#{id}"
64
+ response = Request.patch(endpoint, attributes.to_json)
65
+
66
+ unless response.code == "200"
67
+ raise UpdateError, "Response #{response.code} #{response.message}: #{response.body}"
68
+ end
69
+
70
+ updated = self.class.new(JSON.parse(response.body, symbolize_names: true))
71
+
72
+ ATTRIBUTES.each do |attr|
73
+ self.instance_variable_set("@#{attr}", updated.instance_variable_get("@#{attr}"))
74
+ end
75
+
76
+ self
77
+ end
78
+
79
+ def delete
80
+ raise "You must set id" unless id
81
+
82
+ response = Request.delete("https://pushpad.xyz/api/v1/senders/#{id}")
83
+
84
+ unless response.code == "204"
85
+ raise DeleteError, "Response #{response.code} #{response.message}: #{response.body}"
86
+ end
87
+ end
88
+
89
+ end
90
+ end
@@ -15,10 +15,11 @@ module Pushpad
15
15
  class DeleteError < RuntimeError
16
16
  end
17
17
 
18
- attr_reader :id, :endpoint, :p256dh, :auth, :uid, :tags, :last_click_at, :created_at
18
+ attr_reader :id, :project_id, :endpoint, :p256dh, :auth, :uid, :tags, :last_click_at, :created_at
19
19
 
20
20
  def initialize(options)
21
21
  @id = options[:id]
22
+ @project_id = options[:project_id]
22
23
  @endpoint = options[:endpoint]
23
24
  @p256dh = options[:p256dh]
24
25
  @auth = options[:auth]
@@ -89,7 +90,7 @@ module Pushpad
89
90
  end
90
91
 
91
92
  def update(attributes, options = {})
92
- project_id = options[:project_id] || Pushpad.project_id
93
+ project_id = project_id || options[:project_id] || Pushpad.project_id
93
94
  raise "You must set project_id" unless project_id
94
95
 
95
96
  raise "You must set id" unless id
@@ -109,7 +110,7 @@ module Pushpad
109
110
  end
110
111
 
111
112
  def delete(options = {})
112
- project_id = options[:project_id] || Pushpad.project_id
113
+ project_id = project_id || options[:project_id] || Pushpad.project_id
113
114
  raise "You must set project_id" unless project_id
114
115
 
115
116
  raise "You must set id" unless id
data/lib/pushpad.rb CHANGED
@@ -4,6 +4,7 @@ require "pushpad/request"
4
4
  require "pushpad/notification"
5
5
  require "pushpad/subscription"
6
6
  require "pushpad/project"
7
+ require "pushpad/sender"
7
8
 
8
9
  module Pushpad
9
10
  @@auth_token = nil
data/pushpad.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "pushpad"
3
- spec.version = '1.4.0'
3
+ spec.version = '1.6.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."
@@ -62,6 +62,7 @@ module Pushpad
62
62
  it "returns notification with attributes from json response" do
63
63
  attributes = {
64
64
  id: 5,
65
+ project_id: 123,
65
66
  title: "Foo Bar",
66
67
  body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
67
68
  target_url: "https://example.com",
@@ -118,6 +119,7 @@ module Pushpad
118
119
  it "returns notifications of project with attributes from json response" do
119
120
  attributes = {
120
121
  id: 5,
122
+ project_id: 123,
121
123
  title: "Foo Bar",
122
124
  body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
123
125
  target_url: "https://example.com",
@@ -0,0 +1,199 @@
1
+ require "spec_helper"
2
+
3
+ module Pushpad
4
+ describe Sender do
5
+
6
+ def stub_senders_post(attributes = {})
7
+ stub_request(:post, "https://pushpad.xyz/api/v1/senders").
8
+ with(body: hash_including(attributes)).
9
+ to_return(status: 201, body: attributes.to_json)
10
+ end
11
+
12
+ def stub_failing_senders_post
13
+ stub_request(:post, "https://pushpad.xyz/api/v1/senders").
14
+ to_return(status: 422)
15
+ end
16
+
17
+ def stub_sender_get(attributes)
18
+ stub_request(:get, "https://pushpad.xyz/api/v1/senders/#{attributes[:id]}").
19
+ to_return(status: 200, body: attributes.to_json)
20
+ end
21
+
22
+ def stub_failing_sender_get(attributes)
23
+ stub_request(:get, "https://pushpad.xyz/api/v1/senders/#{attributes[:id]}").
24
+ to_return(status: 404)
25
+ end
26
+
27
+ def stub_senders_get(list)
28
+ stub_request(:get, "https://pushpad.xyz/api/v1/senders").
29
+ to_return(status: 200, body: list.to_json)
30
+ end
31
+
32
+ def stub_failing_senders_get
33
+ stub_request(:get, "https://pushpad.xyz/api/v1/senders").
34
+ to_return(status: 401)
35
+ end
36
+
37
+ def stub_sender_patch(id, attributes)
38
+ stub_request(:patch, "https://pushpad.xyz/api/v1/senders/#{id}").
39
+ with(body: hash_including(attributes)).
40
+ to_return(status: 200, body: attributes.to_json)
41
+ end
42
+
43
+ def stub_failing_sender_patch(id)
44
+ stub_request(:patch, "https://pushpad.xyz/api/v1/senders/#{id}").
45
+ to_return(status: 422)
46
+ end
47
+
48
+ def stub_sender_delete(id)
49
+ stub_request(:delete, "https://pushpad.xyz/api/v1/senders/#{id}").
50
+ to_return(status: 204)
51
+ end
52
+
53
+ def stub_failing_sender_delete(id)
54
+ stub_request(:delete, "https://pushpad.xyz/api/v1/senders/#{id}").
55
+ to_return(status: 403)
56
+ end
57
+
58
+ describe ".create" do
59
+ it "creates a new sender with the given attributes and returns it" do
60
+ attributes = {
61
+ name: "My sender"
62
+ }
63
+ stub = stub_senders_post(attributes)
64
+
65
+ sender = Sender.create(attributes)
66
+ expect(sender).to have_attributes(attributes)
67
+
68
+ expect(stub).to have_been_requested
69
+ end
70
+
71
+ it "fails with CreateError if response status code is not 201" do
72
+ attributes = { name: "" }
73
+ stub_failing_senders_post
74
+
75
+ expect {
76
+ Sender.create(attributes)
77
+ }.to raise_error(Sender::CreateError)
78
+ end
79
+ end
80
+
81
+ describe ".find" do
82
+ it "returns sender with attributes from json response" do
83
+ attributes = {
84
+ id: 182,
85
+ name: "My sender",
86
+ vapid_private_key: "-----BEGIN EC PRIVATE KEY----- ...",
87
+ vapid_public_key: "-----BEGIN PUBLIC KEY----- ...",
88
+ created_at: "2016-07-06T11:28:21.266Z"
89
+ }
90
+ stub_sender_get(attributes)
91
+
92
+ sender = Sender.find(182)
93
+
94
+ attributes.delete(:created_at)
95
+ expect(sender).to have_attributes(attributes)
96
+ expect(sender.created_at.utc.to_s).to eq(Time.utc(2016, 7, 6, 11, 28, 21.266).to_s)
97
+ end
98
+
99
+ it "fails with FindError if response status code is not 200" do
100
+ attributes = { id: 362 }
101
+ stub_failing_sender_get(attributes)
102
+
103
+ expect {
104
+ Sender.find(362)
105
+ }.to raise_error(Sender::FindError)
106
+ end
107
+ end
108
+
109
+ describe ".find_all" do
110
+ it "returns senders with attributes from json response" do
111
+ attributes = {
112
+ id: 182,
113
+ name: "My sender",
114
+ vapid_private_key: "-----BEGIN EC PRIVATE KEY----- ...",
115
+ vapid_public_key: "-----BEGIN PUBLIC KEY----- ...",
116
+ created_at: "2016-07-06T11:28:21.266Z"
117
+ }
118
+ stub_senders_get([attributes])
119
+
120
+ senders = Sender.find_all
121
+
122
+ attributes.delete(:created_at)
123
+ expect(senders[0]).to have_attributes(attributes)
124
+ expect(senders[0].created_at.utc.to_s).to eq(Time.utc(2016, 7, 6, 11, 28, 21.266).to_s)
125
+ end
126
+
127
+ it "fails with FindError if response status code is not 200" do
128
+ stub_failing_senders_get
129
+
130
+ expect {
131
+ Sender.find_all
132
+ }.to raise_error(Sender::FindError)
133
+ end
134
+
135
+ it "works properly when there are no results" do
136
+ stub_senders_get([])
137
+
138
+ senders = Sender.find_all
139
+
140
+ expect(senders).to eq([])
141
+ end
142
+ end
143
+
144
+ describe "#update" do
145
+ it "updates a sender with the given attributes and returns it" do
146
+ attributes = {
147
+ name: "The New Sender Name"
148
+ }
149
+ stub = stub_sender_patch(5, attributes)
150
+
151
+ sender = Sender.new(id: 5)
152
+ sender.update attributes
153
+ expect(sender).to have_attributes(attributes)
154
+
155
+ expect(stub).to have_been_requested
156
+ end
157
+
158
+ it "fails with UpdateError if response status code is not 200" do
159
+ attributes = { name: "" }
160
+ stub_failing_sender_patch(5)
161
+
162
+ sender = Sender.new(id: 5)
163
+
164
+ expect {
165
+ sender.update attributes
166
+ }.to raise_error(Sender::UpdateError)
167
+ end
168
+
169
+ it "fails with helpful error message when id is missing" do
170
+ expect {
171
+ Sender.new(id: nil).update({})
172
+ }.to raise_error(/must set id/)
173
+ end
174
+ end
175
+
176
+ describe "#delete" do
177
+ it "deletes a sender" do
178
+ stub = stub_sender_delete(5)
179
+
180
+ sender = Sender.new(id: 5)
181
+ res = sender.delete
182
+ expect(res).to be_nil
183
+
184
+ expect(stub).to have_been_requested
185
+ end
186
+
187
+ it "fails with DeleteError if response status code is not 204" do
188
+ stub_failing_sender_delete(5)
189
+
190
+ sender = Sender.new(id: 5)
191
+
192
+ expect {
193
+ sender.delete
194
+ }.to raise_error(Sender::DeleteError)
195
+ end
196
+ end
197
+
198
+ end
199
+ end
@@ -164,6 +164,7 @@ module Pushpad
164
164
  it "returns subscription with attributes from json response" do
165
165
  attributes = {
166
166
  id: 5,
167
+ project_id: 123,
167
168
  endpoint: "https://example.com/push/f7Q1Eyf7EyfAb1",
168
169
  p256dh: "BCQVDTlYWdl05lal3lG5SKr3VxTrEWpZErbkxWrzknHrIKFwihDoZpc_2sH6Sh08h-CacUYI-H8gW4jH-uMYZQ4=",
169
170
  auth: "cdKMlhgVeSPzCXZ3V7FtgQ==",
@@ -204,6 +205,7 @@ module Pushpad
204
205
  it "returns subscriptions of project with attributes from json response" do
205
206
  attributes = {
206
207
  id: 1169,
208
+ project_id: 123,
207
209
  endpoint: "https://example.com/push/f7Q1Eyf7EyfAb1",
208
210
  p256dh: "BCQVDTlYWdl05lal3lG5SKr3VxTrEWpZErbkxWrzknHrIKFwihDoZpc_2sH6Sh08h-CacUYI-H8gW4jH-uMYZQ4=",
209
211
  auth: "cdKMlhgVeSPzCXZ3V7FtgQ==",
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.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pushpad
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-21 00:00:00.000000000 Z
11
+ date: 2025-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -56,11 +56,13 @@ files:
56
56
  - lib/pushpad/notification.rb
57
57
  - lib/pushpad/project.rb
58
58
  - lib/pushpad/request.rb
59
+ - lib/pushpad/sender.rb
59
60
  - lib/pushpad/subscription.rb
60
61
  - pushpad.gemspec
61
62
  - spec/pushpad/notification_spec.rb
62
63
  - spec/pushpad/project_spec.rb
63
64
  - spec/pushpad/request_spec.rb
65
+ - spec/pushpad/sender_spec.rb
64
66
  - spec/pushpad/subscription_spec.rb
65
67
  - spec/pushpad_spec.rb
66
68
  - spec/spec_helper.rb
@@ -83,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
85
  - !ruby/object:Gem::Version
84
86
  version: '0'
85
87
  requirements: []
86
- rubygems_version: 3.5.16
88
+ rubygems_version: 3.5.22
87
89
  signing_key:
88
90
  specification_version: 4
89
91
  summary: Web push notifications for Chrome, Firefox, Opera, Edge and Safari using
@@ -92,6 +94,7 @@ test_files:
92
94
  - spec/pushpad/notification_spec.rb
93
95
  - spec/pushpad/project_spec.rb
94
96
  - spec/pushpad/request_spec.rb
97
+ - spec/pushpad/sender_spec.rb
95
98
  - spec/pushpad/subscription_spec.rb
96
99
  - spec/pushpad_spec.rb
97
100
  - spec/spec_helper.rb