pezza_action_push_web 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +299 -0
- data/Rakefile +8 -0
- data/app/assets/javascripts/action_push_web.js +424 -0
- data/app/assets/javascripts/components/action_push_web.js +7 -0
- data/app/assets/javascripts/components/denied.js +24 -0
- data/app/assets/javascripts/components/granted.js +86 -0
- data/app/assets/javascripts/components/request.js +55 -0
- data/app/assets/stylesheets/action_push_web/application.css +15 -0
- data/app/controllers/action_push_web/subscriptions_controller.rb +19 -0
- data/app/helpers/action_push_web/application_helper.rb +22 -0
- data/app/jobs/action_push_web/notification_job.rb +48 -0
- data/app/models/action_push_web/subscription.rb +13 -0
- data/db/migrate/20250907213606_create_action_push_web_subscriptions.rb +13 -0
- data/lib/action_push_web/engine.rb +36 -0
- data/lib/action_push_web/errors.rb +8 -0
- data/lib/action_push_web/notification.rb +63 -0
- data/lib/action_push_web/payload_encryption.rb +86 -0
- data/lib/action_push_web/pool.rb +46 -0
- data/lib/action_push_web/pusher.rb +85 -0
- data/lib/action_push_web/subscription_notification.rb +13 -0
- data/lib/action_push_web/vapid_key.rb +38 -0
- data/lib/action_push_web/vapid_key_generator.rb +19 -0
- data/lib/action_push_web/version.rb +3 -0
- data/lib/action_push_web.rb +37 -0
- data/lib/generators/action_push_web/install/install_generator.rb +51 -0
- data/lib/generators/action_push_web/install/templates/app/jobs/application_push_web_notification_job.rb.tt +7 -0
- data/lib/generators/action_push_web/install/templates/app/models/application_push_subscription.rb.tt +4 -0
- data/lib/generators/action_push_web/install/templates/app/models/application_push_web_notification.rb.tt +12 -0
- data/lib/generators/action_push_web/install/templates/app/views/pwa/service-worker.js +30 -0
- data/lib/generators/action_push_web/install/templates/config/push.yml.tt +22 -0
- data/lib/pezza_action_push_web.rb +4 -0
- data/lib/tasks/action_push_web_tasks.rake +4 -0
- metadata +160 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6b803e5c0eef3a7959489bf3949295a1b0e18ea5d2a9948f4e5a72a50278ce7c
|
4
|
+
data.tar.gz: ceb797d01a9e63505b31a7e1caf0eea9b3fbd79082562c392a2a46405755e225
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e1a7b5f5b15cd74247f32cd3d5101bdae3ef36e49acfadafce656fdafacce379dc907faf7f6bf7031965a555e338cedfd8705ca42c93bb2e9768868d9b6b8b6c
|
7
|
+
data.tar.gz: cafbcc9aecefd513b408d246626d2e6f553bb01968b38345dd8030e1105376d75fa0460faac25e886469b66a9174176ade363c81809675513b63543118cfaf3a
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright Nick Pezza
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,299 @@
|
|
1
|
+
# ActionPushWeb
|
2
|
+
|
3
|
+
Action Push Web is a Rails push notification gem for the web and PWAs.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```bash
|
8
|
+
1. bundle add action_push_web
|
9
|
+
2. bin/rails g action_push_web:install
|
10
|
+
4. bin/rails db:migrate
|
11
|
+
```
|
12
|
+
|
13
|
+
This will install the gem and run the necessary migrations to set up the database.
|
14
|
+
|
15
|
+
The install generator will also output a generated public and private key that
|
16
|
+
you'll want to add to your credentitals.
|
17
|
+
|
18
|
+
## Configuration
|
19
|
+
|
20
|
+
The installation will create:
|
21
|
+
|
22
|
+
- `app/models/application_push_web_notification.rb`
|
23
|
+
- `app/jobs/application_push_web_notification_job.rb`
|
24
|
+
- `app/models/application_push_subscription.rb`
|
25
|
+
- `config/push.yml`
|
26
|
+
- `app/views/pwa/service_worker.js`
|
27
|
+
- mount the subscriptions controllers
|
28
|
+
- import action_push_web.js in your application.js
|
29
|
+
- Add `<%= action_push_web_key_tag %>` to the <head> of your application's layout if it can find it. Otherwise, you'll need to add it manually.
|
30
|
+
|
31
|
+
|
32
|
+
`app/models/application_push_web_notification.rb`:
|
33
|
+
```ruby
|
34
|
+
class ApplicationPushWebNotification < ActionPushWeb::Notification
|
35
|
+
# Set a custom job queue_name
|
36
|
+
queue_as :realtime
|
37
|
+
|
38
|
+
# Controls whether push notifications are enabled (default: !Rails.env.test?)
|
39
|
+
self.enabled = Rails.env.production?
|
40
|
+
|
41
|
+
# Define a custom callback to modify or abort the notification before it is sent
|
42
|
+
before_delivery do |notification|
|
43
|
+
throw :abort if Notification.find(notification.context[:notification_id]).expired?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
Used to create and send push notifications. You can customize it by subclassing or
|
49
|
+
you can change the application defaults by editing it directly.
|
50
|
+
|
51
|
+
`app/jobs/application_push_web_notification_job.rb`:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class ApplicationPushWebNotificationJob < ActionPushWeb::NotificationJob
|
55
|
+
# Enable logging job arguments (default: false)
|
56
|
+
self.log_arguments = true
|
57
|
+
|
58
|
+
# Report job retries via the `Rails.error` reporter (default: false)
|
59
|
+
self.report_job_retries = true
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
Job class that processes the push notifications. You can customize it by editing it
|
64
|
+
directly in your application.
|
65
|
+
|
66
|
+
`app/models/application_push_subscription.rb`:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
class ApplicationPushSubscription < ActionPushWeb::Subscription
|
70
|
+
# Customize TokenError handling (default: destroy!)
|
71
|
+
# rescue_from (ActionPushWeb::TokenError) { Rails.logger.error("Subscription #{id} token is invalid") }
|
72
|
+
end
|
73
|
+
```
|
74
|
+
|
75
|
+
This represents a push notification subscription. You can customize it by editing it directly in your application.
|
76
|
+
|
77
|
+
`config/push.yml`:
|
78
|
+
|
79
|
+
```yaml
|
80
|
+
shared:
|
81
|
+
web:
|
82
|
+
public_key: <%= Rails.application.credentials.action_push_web.public_key %>
|
83
|
+
private_key: <%= Rails.application.credentials.action_push_web.private_key %>
|
84
|
+
|
85
|
+
# Change the request timeout (default: 30).
|
86
|
+
# request_timeout: 60
|
87
|
+
|
88
|
+
# Change the ttl (default: 2419200).
|
89
|
+
# ttl: 60
|
90
|
+
|
91
|
+
# Change the expiration (default: 43200).
|
92
|
+
# expiration: 60
|
93
|
+
|
94
|
+
# Change the subject (default: mailto:sender@example.com).
|
95
|
+
# expiration: mailto:support@my-domain.com
|
96
|
+
|
97
|
+
# Change the urgency (default: normal). You also choose to set this at the notification level.
|
98
|
+
# urgency: high
|
99
|
+
```
|
100
|
+
|
101
|
+
This file contains the configuration for the push notification services you want to use.
|
102
|
+
The push notification requires a web key with a public and private key.
|
103
|
+
If you're configuring more than one app, see the section [Configuring multiple apps](#configuring-multiple-apps) below.
|
104
|
+
|
105
|
+
### Configuring multiple apps
|
106
|
+
|
107
|
+
You can send push notifications to multiple apps using different notification classes.
|
108
|
+
Each notification class need to inherit from `ApplicationPushWebNotification` and set `self.application`, to a key set in `push.yml`
|
109
|
+
for each supported platform. You can also (optionally) set a shared `application` option in `push.yml`.
|
110
|
+
This acts as the base configuration for that platform, and its values will be merged (and overridden) with the matching app-specific configuration.
|
111
|
+
|
112
|
+
In the example below we are configuring two apps: `calendar` and `email` using respectively the
|
113
|
+
`CalendarPushNotification` and `EmailPushNotification` notification classes.
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
class CalendarPushNotification < ApplicationPushWebNotification
|
117
|
+
self.application = "calendar"
|
118
|
+
|
119
|
+
# Custom notification logic for calendar app
|
120
|
+
end
|
121
|
+
|
122
|
+
class EmailPushNotification < ApplicationPushWebNotification
|
123
|
+
self.application = "email"
|
124
|
+
|
125
|
+
# Custom notification logic for email app
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
```yaml
|
130
|
+
shared:
|
131
|
+
web:
|
132
|
+
# Base configuration for web platform
|
133
|
+
# This will be merged with the app-specific configuration
|
134
|
+
application:
|
135
|
+
request_timeout: 60
|
136
|
+
|
137
|
+
calendar:
|
138
|
+
public_key: <%%= Rails.application.credentials.action_push_web.calendar.public_key %>
|
139
|
+
private_key: <%%= Rails.application.credentials.action_push_web.calendar.private_key %>
|
140
|
+
|
141
|
+
email:
|
142
|
+
public_key: <%%= Rails.application.credentials.action_push_web.email.public_key %>
|
143
|
+
private_key: <%%= Rails.application.credentials.action_push_web.email.private_key %>
|
144
|
+
```
|
145
|
+
|
146
|
+
## Usage
|
147
|
+
|
148
|
+
### Create and send a notification asynchronously to a subscription
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
subscription = ApplicationPushSubscription.create! \
|
152
|
+
user_agent: "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Mobile/15E148 Safari/604.1",
|
153
|
+
auth_key: "foStsVKvFCvKS1KJF4OaDS",
|
154
|
+
p256dh_key: "8YZosOgeQYI1lXr6Enahllf56j0VvEynIIm0q37k19QdbclLPNbACud8XSgS1b04TNAFlwyS1niwMx9LoLp8Hsx",
|
155
|
+
endpoint: "https://web.push.apple.com/2UtCfdxa01DJYCW0R7qnA9u4JqYnYo5CHSlR0b95JnMhAW1Zy32ZN9BTLY8KLXogMU3EMuYDWNgdUcX8OaNEZCQOhFp7zeo8US2ZvKYdvGxAjx1ELZH9e3yXHEYlco6vKLfsgOCZxabp63rt80voC5n9i6IzAvMgWmcwz5INfBd"
|
156
|
+
|
157
|
+
notification = ApplicationPushWebNotification.new \
|
158
|
+
title: "Hello world!",
|
159
|
+
body: "Welcome to Action Push Web",
|
160
|
+
path: "/welcome"
|
161
|
+
|
162
|
+
notification.deliver_later_to(subscription)
|
163
|
+
```
|
164
|
+
|
165
|
+
`deliver_later_to` supports also an array of devices:
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
notification.deliver_later_to([ subscription1, subscription2 ])
|
169
|
+
```
|
170
|
+
|
171
|
+
A notification can also be delivered synchronously using `deliver_to`:
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
notification.deliver_to(subscription)
|
175
|
+
```
|
176
|
+
|
177
|
+
It is recommended to send notifications asynchronously using `deliver_later_to`.
|
178
|
+
This ensures error handling and retry logic are in place, and avoids blocking your application's execution.
|
179
|
+
|
180
|
+
### Linking a Subscription to a Record
|
181
|
+
|
182
|
+
A Subscription can be associated with any record in your application via the `owner` polymorphic association:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
user = User.find_by_email_address("pezza@hey.com")
|
186
|
+
|
187
|
+
ApplicationPushSubscription.create! \
|
188
|
+
user_agent: "Mozilla/5.0 (iPhone; CPU iPhone OS 18_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Mobile/15E148 Safari/604.1",
|
189
|
+
auth_key: "foStsVKvFCvKS1KJF4OaDS",
|
190
|
+
p256dh_key: "8YZosOgeQYI1lXr6Enahllf56j0VvEynIIm0q37k19QdbclLPNbACud8XSgS1b04TNAFlwyS1niwMx9LoLp8Hsx",
|
191
|
+
endpoint: "https://web.push.apple.com/2UtCfdxa01DJYCW0R7qnA9u4JqYnYo5CHSlR0b95JnMhAW1Zy32ZN9BTLY8KLXogMU3EMuYDWNgdUcX8OaNEZCQOhFp7zeo8US2ZvKYdvGxAjx1ELZH9e3yXHEYlco6vKLfsgOCZxabp63rt80voC5n9i6IzAvMgWmcwz5INfBd",
|
192
|
+
owner: user
|
193
|
+
```
|
194
|
+
|
195
|
+
### `before_delivery` callback
|
196
|
+
|
197
|
+
You can specify Active Record like callbacks for the `delivery` method. For example, you can modify
|
198
|
+
or cancel the notification by specifying a custom `before_delivery` block. The callback has access
|
199
|
+
to the `notification` object. You can also pass additional context data to the notification
|
200
|
+
by adding extra arguments to the notification constructor:
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
class CalendarPushNotification < ApplicationPushWebNotification
|
204
|
+
before_delivery do |notification|
|
205
|
+
throw :abort if Calendar.find(notification.context[:calendar_id]).expired?
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
notification = CalendarPushNotification
|
210
|
+
.new(title: "Upcoming event", path: "/events/1", calendar_id: 123)
|
211
|
+
|
212
|
+
notification.deliver_later_to(subscription)
|
213
|
+
```
|
214
|
+
|
215
|
+
### Using a custom Subscription model
|
216
|
+
|
217
|
+
If using the default `ApplicationPushSubscription` model does not fit your needs, you can create a custom
|
218
|
+
subscription model, as long as:
|
219
|
+
|
220
|
+
1. It can be serialized and deserialized by `ActiveJob`.
|
221
|
+
2. It responds to the `endpoint`, `auth_key` and `p256dh_key` methods.
|
222
|
+
3. It implements a `push` method like this:
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
class CustomSubscription
|
226
|
+
# Your custom device attributes and methods...
|
227
|
+
|
228
|
+
def push(notification)
|
229
|
+
ActionPushWeb.push \
|
230
|
+
ActionPushWeb::SubscriptionNotification.new(notification:, subscription: self)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
```
|
234
|
+
|
235
|
+
On the frontend, there are 3 custom HTML elements that can be accessed via helpers.
|
236
|
+
|
237
|
+
The first is when the user has not yet granted permission to send notifications.
|
238
|
+
|
239
|
+
You can use what ever HTML you want inside these components. Once the user either grants or denies
|
240
|
+
permission the component will hide itself.
|
241
|
+
|
242
|
+
```erb
|
243
|
+
<%= ask_for_web_notifications do %>
|
244
|
+
<div class="text-blue">Request permission</div>
|
245
|
+
<% end %>
|
246
|
+
```
|
247
|
+
|
248
|
+
If a user denies permission to send notifications:
|
249
|
+
|
250
|
+
```erb
|
251
|
+
<%= when_web_notifications_disabled do %>
|
252
|
+
<div class="text-red">Notifications aren’t allowed</div>
|
253
|
+
<% end %>
|
254
|
+
```
|
255
|
+
|
256
|
+
And if a user grants permission to send notifications.
|
257
|
+
It accepts an `href` attribute to be passed to the helper that points to a create
|
258
|
+
action that handles creating a push subscription. By default it points to the
|
259
|
+
controller included in ActionPushWeb, `action_push_web.subscriptions_path`. It
|
260
|
+
also accepts a `service_worker_url` attribute that points to the service worker.
|
261
|
+
By default it points to `pwa_service_worker_path(format: :js)`
|
262
|
+
|
263
|
+
```erb
|
264
|
+
<%= when_web_notifications_allowed href: action_push_web.subscriptions_path, class: "text-green" do %>
|
265
|
+
Notifications are allowed
|
266
|
+
<% end %>
|
267
|
+
```
|
268
|
+
|
269
|
+
You can alternatively create a custom controller that handles creating a push subscription:
|
270
|
+
|
271
|
+
```ruby
|
272
|
+
class PushSubscriptionsController < ActionPushWeb::SubscriptionsController
|
273
|
+
private
|
274
|
+
def push_subscription_params
|
275
|
+
super.merge(owner: Current.user)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
```
|
279
|
+
|
280
|
+
```erb
|
281
|
+
<%= ask_for_web_notifications(href: push_subscriptions_path) do %>
|
282
|
+
<div class="text-blue">Request permission</div>
|
283
|
+
<% end %>
|
284
|
+
```
|
285
|
+
|
286
|
+
## `ActionPushWeb::Notification` attributes
|
287
|
+
|
288
|
+
| Name | Description
|
289
|
+
|------------------|------------
|
290
|
+
| :title | The title of the notification.
|
291
|
+
| :body | The body of the notification.
|
292
|
+
| :badge | The badge number to display on the app icon.
|
293
|
+
| :path | The path to open when the user taps on the notification.
|
294
|
+
| :icon_path | The path to the icon to display in the notification.
|
295
|
+
| :urgency | The urgency of the notification. (very-low \| low \| normal \| high)
|
296
|
+
| ** | Any additional attributes passed to the constructor will be merged in the `context` hash.
|
297
|
+
|
298
|
+
## License
|
299
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|