Merge branch 'push_fix' into 'develop'

Fixes for push notifications

Closes #235

See merge request pleroma/pleroma-fe!433
このコミットが含まれているのは:
HJ 2018-12-25 11:33:00 +00:00
コミット 0ad837846a
5個のファイルの変更74行の追加30行の削除

ファイルの表示

@ -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) {
if (user && vapidPublicKey && permission && webPushNotification) {
return store.dispatch('registerPushNotifications') return store.dispatch('registerPushNotifications')
} else if (isUserConfigMutation && !webPushNotification) {
return store.dispatch('unregisterPushNotifications')
}
} }
}) })
} }

ファイルの表示

@ -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,

ファイルの表示

@ -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'))

ファイルの表示

@ -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) => {
.then((response) => {
if (!response.ok) throw new Error('Bad status code from server.') if (!response.ok) throw new Error('Bad status code from server.')
return response.json() return response.json()
}) }).then((responseData) => {
.then((responseData) => {
if (!responseData.id) throw new Error('Bad response from server.') if (!responseData.id) throw new Error('Bad response from server.')
return responseData 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}`))
}
}

ファイルの表示

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