Web Push Notifications (#3243)

* feat: Register push subscription

* feat: Notify when mentioned

* feat: Boost, favourite, reply, follow, follow request

* feat: Notification interaction

* feat: Handle change of public key

* feat: Unsubscribe if things go wrong

* feat: Do not send normal notifications if push is enabled

* feat: Focus client if open

* refactor: Move push logic to WebPushSubscription

* feat: Better title and body

* feat: Localize messages

* chore: Fix lint errors

* feat: Settings

* refactor: Lazy load

* fix: Check if push settings exist

* feat: Device-based preferences

* refactor: Simplify logic

* refactor: Pull request feedback

* refactor: Pull request feedback

* refactor: Create /api/web/push_subscriptions endpoint

* feat: Spec PushSubscriptionController

* refactor: WebPushSubscription => Web::PushSubscription

* feat: Spec Web::PushSubscription

* feat: Display first media attachment

* feat: Support direction

* fix: Stuff broken while rebasing

* refactor: Integration with session activations

* refactor: Cleanup

* refactor: Simplify implementation

* feat: Set VAPID keys via environment

* chore: Comments

* fix: Crash when no alerts

* fix: Set VAPID keys in testing environment

* fix: Follow link

* feat: Notification actions

* fix: Delete previous subscription

* chore: Temporary logs

* refactor: Move migration to a later date

* fix: Fetch the correct session activation and misc bugs

* refactor: Move migration to a later date

* fix: Remove follow request (no notifications)

* feat: Send administrator contact to push service

* feat: Set time-to-live

* fix: Do not show sensitive images

* fix: Reducer crash in error handling

* feat: Add badge

* chore: Fix lint error

* fix: Checkbox label overlap

* fix: Check for payload support

* fix: Rename action "type" (crash in latest Chrome)

* feat: Action to expand notification

* fix: Lint errors

* fix: Unescape notification body

* fix: Do not allow boosting if the status is hidden

* feat: Add VAPID keys to the production sample environment

* fix: Strip HTML tags from status

* refactor: Better error messages

* refactor: Handle browser not implementing the VAPID protocol (Samsung Internet)

* fix: Error when target_status is nil

* fix: Handle lack of image

* fix: Delete reference to invalid subscriptions

* feat: Better error handling

* fix: Unescape HTML characters after tags are striped

* refactor: Simpify code

* fix: Modify to work with #4091

* Sort strings alphabetically

* i18n: Updated Polish translation

it annoys me that it's not fully localized :P

* refactor: Use current_session in PushSubscriptionController

* fix: Rebase mistake

* fix: Set cacheName to mastodon

* refactor: Pull request feedback

* refactor: Remove logging statements

* chore(yarn): Fix conflicts with master

* chore(yarn): Copy latest from master

* chore(yarn): Readd offline-plugin

* refactor: Use save! and update!

* refactor: Send notifications async

* fix: Allow retry when push fails

* fix: Save track for failed pushes

* fix: Minify sw.js

* fix: Remove account_id from fabricator
This commit is contained in:
Sorin Davidoi 2017-07-13 22:15:32 +02:00 committed by Eugen Rochko
parent c2753fdfb4
commit 0c7c188c45
42 changed files with 890 additions and 14 deletions

View file

@ -31,6 +31,11 @@ Rails.application.configure do
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Generate random VAPID keys
vapid_key = Webpush.generate_key
config.x.vapid_private_key = vapid_key.private_key
config.x.vapid_public_key = vapid_key.public_key
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false

View file

@ -40,6 +40,11 @@ Rails.application.configure do
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# Generate random VAPID keys
vapid_key = Webpush.generate_key
config.x.vapid_private_key = vapid_key.private_key
config.x.vapid_public_key = vapid_key.public_key
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end

View file

@ -0,0 +1,17 @@
# frozen_string_literal: true
Rails.application.configure do
# You can generate the keys using the following command (first is the private key, second is the public one)
# You should only generate this once per instance. If you later decide to change it, all push subscription will
# be invalidated, requiring the users to access the website again to resubscribe.
#
# ruby -e "require 'webpush'; vapid_key = Webpush.generate_key; puts vapid_key.private_key; puts vapid_key.public_key;"
#
# For more information visit https://rossta.net/blog/using-the-web-push-api-with-vapid.html
if Rails.env.production?
config.x.vapid_private_key = ENV['VAPID_PRIVATE_KEY']
config.x.vapid_public_key = ENV['VAPID_PUBLIC_KEY']
end
end

View file

@ -335,6 +335,21 @@ en:
next: Next
prev: Prev
truncate: "…"
push_notifications:
favourite:
title: "%{name} favourited your status"
follow:
title: "%{name} is now following you"
mention:
action_boost: 'Boost'
action_expand: 'Show more'
action_favourite: 'Favourite'
title: "%{name} mentioned you"
reblog:
title: "%{name} boosted your status"
subscribed:
body: "You can now receive push notifications."
title: "Subscription registered!"
remote_follow:
acct: Enter your username@domain you want to follow from
missing_resource: Could not find the required redirect URL for your account

View file

@ -339,6 +339,21 @@ pl:
next: Następna
prev: Poprzednia
truncate: "…"
push_notifications:
favourite:
title: "%{name} dodał Twój status do ulubionych"
follow:
title: "%{name} zaczął Cię śledzić"
mention:
action_boost: 'Podbij'
action_expand: 'Pokaż więcej'
action_favourite: 'Dodaj do ulubionych'
title: "%{name} wspomniał o Tobie"
reblog:
title: "%{name} podbił Twój status"
subscribed:
body: "Otrzymujesz teraz powiadomienia push."
title: "Zarejestrowano subskrypcję!"
remote_follow:
acct: Podaj swój adres (nazwa@domena), z którego chcesz śledzić
missing_resource: Nie udało się znaleźć adresu przekierowania z Twojej domeny

View file

@ -206,6 +206,11 @@ Rails.application.routes.draw do
namespace :web do
resource :settings, only: [:update]
resources :push_subscriptions, only: [:create] do
member do
put :update
end
end
end
end

View file

@ -5,6 +5,9 @@ const merge = require('webpack-merge');
const CompressionPlugin = require('compression-webpack-plugin');
const sharedConfig = require('./shared.js');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const OfflinePlugin = require('offline-plugin');
const { publicPath } = require('./configuration.js');
const path = require('path');
module.exports = merge(sharedConfig, {
output: { filename: '[name]-[chunkhash].js' },
@ -39,5 +42,16 @@ module.exports = merge(sharedConfig, {
openAnalyzer: false,
logLevel: 'silent', // do not bother Webpacker, who runs with --json and parses stdout
}),
new OfflinePlugin({
publicPath: publicPath, // sw.js must be served from the root to avoid scope issues
caches: { }, // do not cache things, we only use it for push notifications for now
ServiceWorker: {
entry: path.join(__dirname, '../../app/javascript/mastodon/service_worker/entry.js'),
cacheName: 'mastodon',
output: '../sw.js',
publicPath: '/sw.js',
minify: true,
},
}),
],
});