Merge branch 'push-notifications-fix' into 'develop'

Web Push fixes

See merge request soapbox-pub/soapbox-fe!881
features-override
Alex Gleason 2021-11-18 21:35:28 +00:00
commit 4c331387df
5 zmienionych plików z 37 dodań i 23 usunięć

Wyświetl plik

@ -2,6 +2,7 @@ import { decode as decodeBase64 } from '../../utils/base64';
import { pushNotificationsSetting } from '../../settings'; import { pushNotificationsSetting } from '../../settings';
import { setBrowserSupport, setSubscription, clearSubscription } from './setter'; import { setBrowserSupport, setSubscription, clearSubscription } from './setter';
import { createPushSubsription, updatePushSubscription } from 'soapbox/actions/push_subscriptions'; import { createPushSubsription, updatePushSubscription } from 'soapbox/actions/push_subscriptions';
import { getVapidKey } from 'soapbox/utils/auth';
// Taken from https://www.npmjs.com/package/web-push // Taken from https://www.npmjs.com/package/web-push
const urlBase64ToUint8Array = (base64String) => { const urlBase64ToUint8Array = (base64String) => {
@ -13,11 +14,6 @@ const urlBase64ToUint8Array = (base64String) => {
return decodeBase64(base64); return decodeBase64(base64);
}; };
const getVapidKey = getState => {
const state = getState();
return state.getIn(['auth', 'app', 'vapid_key']) || state.getIn(['instance', 'pleroma', 'vapid_public_key']);
};
const getRegistration = () => navigator.serviceWorker.ready; const getRegistration = () => navigator.serviceWorker.ready;
const getPushSubscription = (registration) => const getPushSubscription = (registration) =>
@ -27,7 +23,7 @@ const getPushSubscription = (registration) =>
const subscribe = (registration, getState) => const subscribe = (registration, getState) =>
registration.pushManager.subscribe({ registration.pushManager.subscribe({
userVisibleOnly: true, userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(getVapidKey(getState)), applicationServerKey: urlBase64ToUint8Array(getVapidKey(getState())),
}); });
const unsubscribe = ({ registration, subscription }) => const unsubscribe = ({ registration, subscription }) =>
@ -35,7 +31,8 @@ const unsubscribe = ({ registration, subscription }) =>
const sendSubscriptionToBackend = (subscription, me) => { const sendSubscriptionToBackend = (subscription, me) => {
return (dispatch, getState) => { return (dispatch, getState) => {
const params = { subscription }; const alerts = getState().getIn(['push_notifications', 'alerts']).toJS();
const params = { subscription, data: { alerts } };
if (me) { if (me) {
const data = pushNotificationsSetting.get(me); const data = pushNotificationsSetting.get(me);
@ -54,7 +51,7 @@ const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager'
export function register() { export function register() {
return (dispatch, getState) => { return (dispatch, getState) => {
const me = getState().get('me'); const me = getState().get('me');
const vapidKey = getVapidKey(getState); const vapidKey = getVapidKey(getState());
dispatch(setBrowserSupport(supportsPushNotifications)); dispatch(setBrowserSupport(supportsPushNotifications));
@ -105,6 +102,7 @@ export function register() {
} }
}) })
.catch(error => { .catch(error => {
console.error(error);
if (error.code === 20 && error.name === 'AbortError') { if (error.code === 20 && error.name === 'AbortError') {
console.warn('Your browser supports Web Push Notifications, but does not seem to implement the VAPID protocol.'); console.warn('Your browser supports Web Push Notifications, but does not seem to implement the VAPID protocol.');
} else if (error.code === 5 && error.name === 'InvalidCharacterError') { } else if (error.code === 5 && error.name === 'InvalidCharacterError') {

Wyświetl plik

@ -44,6 +44,7 @@ import { getFeatures } from 'soapbox/utils/features';
import { fetchCustomEmojis } from 'soapbox/actions/custom_emojis'; import { fetchCustomEmojis } from 'soapbox/actions/custom_emojis';
import ThumbNavigation from 'soapbox/components/thumb_navigation'; import ThumbNavigation from 'soapbox/components/thumb_navigation';
import { getSoapboxConfig } from 'soapbox/actions/soapbox'; import { getSoapboxConfig } from 'soapbox/actions/soapbox';
import { getVapidKey } from 'soapbox/utils/auth';
import { import {
Status, Status,
@ -135,6 +136,7 @@ const mapStateToProps = state => {
const account = state.getIn(['accounts', me]); const account = state.getIn(['accounts', me]);
const instance = state.get('instance'); const instance = state.get('instance');
const soapbox = getSoapboxConfig(state); const soapbox = getSoapboxConfig(state);
const vapidKey = getVapidKey(state);
return { return {
dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null, dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null,
@ -144,6 +146,7 @@ const mapStateToProps = state => {
account, account,
features: getFeatures(instance), features: getFeatures(instance),
soapbox, soapbox,
vapidKey,
}; };
}; };
@ -357,6 +360,7 @@ class UI extends React.PureComponent {
account: PropTypes.object, account: PropTypes.object,
features: PropTypes.object.isRequired, features: PropTypes.object.isRequired,
soapbox: ImmutablePropTypes.map.isRequired, soapbox: ImmutablePropTypes.map.isRequired,
vapidKey: PropTypes.string,
}; };
state = { state = {
@ -466,7 +470,7 @@ class UI extends React.PureComponent {
}); });
componentDidMount() { componentDidMount() {
const { account, features, dispatch } = this.props; const { account, features, vapidKey, dispatch } = this.props;
if (!account) return; if (!account) return;
window.addEventListener('resize', this.handleResize, { passive: true }); window.addEventListener('resize', this.handleResize, { passive: true });
@ -515,17 +519,24 @@ class UI extends React.PureComponent {
dispatch(fetchCustomEmojis()); dispatch(fetchCustomEmojis());
this.connectStreaming(); this.connectStreaming();
dispatch(registerPushNotifications());
if (vapidKey) {
dispatch(registerPushNotifications());
}
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
this.connectStreaming(); this.connectStreaming();
const { dispatch, account, features } = this.props; const { dispatch, account, features, vapidKey } = this.props;
if (features.chats && account && !prevProps.features.chats) { if (features.chats && account && !prevProps.features.chats) {
dispatch(fetchChats()); dispatch(fetchChats());
} }
if (vapidKey && !prevProps.vapidKey) {
dispatch(registerPushNotifications());
}
} }
componentWillUnmount() { componentWillUnmount() {

Wyświetl plik

@ -6,12 +6,12 @@ describe('push_notifications reducer', () => {
expect(reducer(undefined, {})).toEqual(ImmutableMap({ expect(reducer(undefined, {})).toEqual(ImmutableMap({
subscription: null, subscription: null,
alerts: new ImmutableMap({ alerts: new ImmutableMap({
follow: false, follow: true,
follow_request: false, follow_request: true,
favourite: false, favourite: true,
reblog: false, reblog: true,
mention: false, mention: true,
poll: false, poll: true,
}), }),
isSubscribed: false, isSubscribed: false,
browserSupport: false, browserSupport: false,

Wyświetl plik

@ -4,12 +4,12 @@ import { Map as ImmutableMap } from 'immutable';
const initialState = ImmutableMap({ const initialState = ImmutableMap({
subscription: null, subscription: null,
alerts: new ImmutableMap({ alerts: new ImmutableMap({
follow: false, follow: true,
follow_request: false, follow_request: true,
favourite: false, favourite: true,
reblog: false, reblog: true,
mention: false, mention: true,
poll: false, poll: true,
}), }),
isSubscribed: false, isSubscribed: false,
browserSupport: false, browserSupport: false,

Wyświetl plik

@ -57,3 +57,8 @@ export const getAuthUserUrl = state => {
me, me,
]).find(isURL); ]).find(isURL);
}; };
/** Get the VAPID public key. */
export const getVapidKey = state => {
return state.getIn(['auth', 'app', 'vapid_key']) || state.getIn(['instance', 'pleroma', 'vapid_public_key']);
};