Merge branch 'push_fix' into 'develop'

Fixes for push notifications

Closes #235

See merge request pleroma/pleroma-fe!433
This commit is contained in:
HJ 2018-12-25 11:33:00 +00:00
commit 0ad837846a
5 changed files with 74 additions and 30 deletions

View File

@ -54,24 +54,21 @@ const persistedStateOptions = {
const registerPushNotifications = store => { const registerPushNotifications = store => {
store.subscribe((mutation, state) => { store.subscribe((mutation, state) => {
const vapidPublicKey = state.instance.vapidPublicKey const vapidPublicKey = state.instance.vapidPublicKey
const webPushNotification = state.config.webPushNotifications
const permission = state.interface.notificationPermission === 'granted' const permission = state.interface.notificationPermission === 'granted'
const isUserMutation = mutation.type === 'setCurrentUser'
if (isUserMutation && vapidPublicKey && permission) {
return store.dispatch('registerPushNotifications')
}
const user = state.users.currentUser const user = state.users.currentUser
const isUserMutation = mutation.type === 'setCurrentUser'
const isVapidMutation = mutation.type === 'setInstanceOption' && mutation.payload.name === 'vapidPublicKey' const isVapidMutation = mutation.type === 'setInstanceOption' && mutation.payload.name === 'vapidPublicKey'
if (isVapidMutation && user && permission) {
return store.dispatch('registerPushNotifications')
}
const isPermMutation = mutation.type === 'setNotificationPermission' && mutation.payload === 'granted' const isPermMutation = mutation.type === 'setNotificationPermission' && mutation.payload === 'granted'
const isUserConfigMutation = mutation.type === 'setOption' && mutation.payload.name === 'webPushNotifications'
if (isPermMutation && user && vapidPublicKey) { if (isUserMutation || isVapidMutation || isPermMutation || isUserConfigMutation) {
return store.dispatch('registerPushNotifications') if (user && vapidPublicKey && permission && webPushNotification) {
return store.dispatch('registerPushNotifications')
} else if (isUserConfigMutation && !webPushNotification) {
return store.dispatch('unregisterPushNotifications')
}
} }
}) })
} }

View File

@ -24,7 +24,7 @@ const defaultState = {
likes: true, likes: true,
repeats: true repeats: true
}, },
webPushNotifications: true, webPushNotifications: false,
muteWords: [], muteWords: [],
highlight: {}, highlight: {},
interfaceLanguage: browserLocale, interfaceLanguage: browserLocale,

View File

@ -1,7 +1,7 @@
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import { compact, map, each, merge } from 'lodash' import { compact, map, each, merge } from 'lodash'
import { set } from 'vue' import { set } from 'vue'
import registerPushNotifications from '../services/push/push.js' import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js'
import oauthApi from '../services/new_api/oauth' import oauthApi from '../services/new_api/oauth'
import { humanizeErrors } from './errors' import { humanizeErrors } from './errors'
@ -116,6 +116,11 @@ const users = {
registerPushNotifications(isEnabled, vapidPublicKey, token) registerPushNotifications(isEnabled, vapidPublicKey, token)
}, },
unregisterPushNotifications (store) {
const token = store.state.currentUser.credentials
unregisterPushNotifications(token)
},
addNewStatuses (store, { statuses }) { addNewStatuses (store, { statuses }) {
const users = map(statuses, 'user') const users = map(statuses, 'user')
const retweetedUsers = compact(map(statuses, 'retweeted_status.user')) const retweetedUsers = compact(map(statuses, 'retweeted_status.user'))

View File

@ -14,12 +14,12 @@ function isPushSupported () {
return 'serviceWorker' in navigator && 'PushManager' in window return 'serviceWorker' in navigator && 'PushManager' in window
} }
function registerServiceWorker () { function getOrCreateServiceWorker () {
return runtime.register() return runtime.register()
.catch((err) => console.error('Unable to register service worker.', err)) .catch((err) => console.error('Unable to get or create a service worker.', err))
} }
function subscribe (registration, isEnabled, vapidPublicKey) { function subscribePush (registration, isEnabled, vapidPublicKey) {
if (!isEnabled) return Promise.reject(new Error('Web Push is disabled in config')) if (!isEnabled) return Promise.reject(new Error('Web Push is disabled in config'))
if (!vapidPublicKey) return Promise.reject(new Error('VAPID public key is not found')) if (!vapidPublicKey) return Promise.reject(new Error('VAPID public key is not found'))
@ -30,6 +30,27 @@ function subscribe (registration, isEnabled, vapidPublicKey) {
return registration.pushManager.subscribe(subscribeOptions) return registration.pushManager.subscribe(subscribeOptions)
} }
function unsubscribePush (registration) {
return registration.pushManager.getSubscription()
.then((subscribtion) => {
if (subscribtion === null) { return }
return subscribtion.unsubscribe()
})
}
function deleteSubscriptionFromBackEnd (token) {
return window.fetch('/api/v1/push/subscription/', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
}).then((response) => {
if (!response.ok) throw new Error('Bad status code from server.')
return response
})
}
function sendSubscriptionToBackEnd (subscription, token) { function sendSubscriptionToBackEnd (subscription, token) {
return window.fetch('/api/v1/push/subscription/', { return window.fetch('/api/v1/push/subscription/', {
method: 'POST', method: 'POST',
@ -48,22 +69,42 @@ function sendSubscriptionToBackEnd (subscription, token) {
} }
} }
}) })
}).then((response) => {
if (!response.ok) throw new Error('Bad status code from server.')
return response.json()
}).then((responseData) => {
if (!responseData.id) throw new Error('Bad response from server.')
return responseData
}) })
.then((response) => {
if (!response.ok) throw new Error('Bad status code from server.')
return response.json()
})
.then((responseData) => {
if (!responseData.id) throw new Error('Bad response from server.')
return responseData
})
} }
export default function registerPushNotifications (isEnabled, vapidPublicKey, token) { export function registerPushNotifications (isEnabled, vapidPublicKey, token) {
if (isPushSupported()) { if (isPushSupported()) {
registerServiceWorker() getOrCreateServiceWorker()
.then((registration) => subscribe(registration, isEnabled, vapidPublicKey)) .then((registration) => subscribePush(registration, isEnabled, vapidPublicKey))
.then((subscription) => sendSubscriptionToBackEnd(subscription, token)) .then((subscription) => sendSubscriptionToBackEnd(subscription, token))
.catch((e) => console.warn(`Failed to setup Web Push Notifications: ${e.message}`)) .catch((e) => console.warn(`Failed to setup Web Push Notifications: ${e.message}`))
} }
} }
export function unregisterPushNotifications (token) {
if (isPushSupported()) {
Promise.all([
deleteSubscriptionFromBackEnd(token),
getOrCreateServiceWorker()
.then((registration) => {
return unsubscribePush(registration).then((result) => [registration, result])
})
.then(([registration, unsubResult]) => {
if (!unsubResult) {
console.warn('Push subscription cancellation wasn\'t successful, killing SW anyway...')
}
return registration.unregister().then((result) => {
if (!result) {
console.warn('Failed to kill SW')
}
})
})
]).catch((e) => console.warn(`Failed to disable Web Push Notifications: ${e.message}`))
}
}

View File

@ -16,5 +16,6 @@
"alwaysShowSubjectInput": true, "alwaysShowSubjectInput": true,
"hidePostStats": false, "hidePostStats": false,
"hideUserStats": false, "hideUserStats": false,
"loginMethod": "password" "loginMethod": "password",
"webPushNotifications": false
} }