sforkowany z mirror/soapbox
Merge branch 'push-notifications-fix' into 'develop'
Web Push fixes See merge request soapbox-pub/soapbox-fe!881features-override
commit
4c331387df
|
@ -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') {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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']);
|
||||||
|
};
|
||||||
|
|
Ładowanie…
Reference in New Issue