fix: push subscriptions per instance (#1277)

* fix: push subscriptions per instance

fixes #1274

* fixup

* add notice about one push notification per instance at a time
This commit is contained in:
Nolan Lawson 2019-06-19 23:00:27 -07:00 committed by GitHub
parent 51e7f703d3
commit 6980083ed0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 54 additions and 16 deletions

View File

@ -14,7 +14,9 @@ const {
currentInstance,
instanceThemes,
disableCustomScrollbars,
enableGrayscale
enableGrayscale,
pushSubscription,
loggedInInstancesInOrder
} = storeLite.get()
const theme = (instanceThemes && instanceThemes[currentInstance]) || DEFAULT_THEME
@ -65,3 +67,18 @@ if (/iP(?:hone|ad|od)/.test(navigator.userAgent) &&
IntersectionObserver.toString().includes('[native code]'))) {
document.head.removeChild(document.getElementById('theManifest'))
}
if (pushSubscription) {
// Fix a bug in Pinafore <=v1.9.0 if we only have one instance we're logged in to
// (https://github.com/nolanlawson/pinafore/issues/1274)
if (loggedInInstancesInOrder && loggedInInstancesInOrder.length === 1) {
storeLite.set({
pushSubscriptions: {
[currentInstance]: pushSubscription
}
})
}
storeLite.set({
pushSubscription: null
})
}

View File

@ -5,10 +5,10 @@ import { urlBase64ToUint8Array } from '../_utils/base64'
const dummyApplicationServerKey = 'BImgAz4cF_yvNFp8uoBJCaGpCX4d0atNIFMHfBvAAXCyrnn9IMAFQ10DW_ZvBCzGeR4fZI5FnEi2JVcRE-L88jY='
export async function updatePushSubscriptionForInstance (instanceName) {
const { loggedInInstances, pushSubscription } = store.get()
const { loggedInInstances, currentPushSubscription } = store.get()
const accessToken = loggedInInstances[instanceName].access_token
if (pushSubscription === null) {
if (currentPushSubscription === null) {
return
}
@ -16,7 +16,7 @@ export async function updatePushSubscriptionForInstance (instanceName) {
const subscription = await registration.pushManager.getSubscription()
if (subscription === null) {
store.set({ pushSubscription: null })
store.setInstanceData(instanceName, 'pushSubscriptions', null)
store.save()
return
}
@ -28,16 +28,16 @@ export async function updatePushSubscriptionForInstance (instanceName) {
if (btoa(urlBase64ToUint8Array(backendSubscription.server_key).buffer) !== btoa(subscription.options.applicationServerKey)) {
await subscription.unsubscribe()
await deleteSubscription(instanceName, accessToken)
await updateAlerts(instanceName, pushSubscription.alerts)
await updateAlerts(instanceName, currentPushSubscription.alerts)
} else {
store.set({ pushSubscription: backendSubscription })
store.setInstanceData(instanceName, 'pushSubscriptions', backendSubscription)
store.save()
}
} catch (e) {
// TODO: Better way to detect 404
if (e.message.startsWith('404:')) {
await subscription.unsubscribe()
store.set({ pushSubscription: null })
store.setInstanceData(instanceName, 'pushSubscriptions', null)
store.save()
}
}
@ -73,16 +73,16 @@ export async function updateAlerts (instanceName, alerts) {
backendSubscription = await postSubscription(instanceName, accessToken, subscription, alerts)
store.set({ pushSubscription: backendSubscription })
store.setInstanceData(instanceName, 'pushSubscriptions', backendSubscription)
store.save()
} else {
try {
const backendSubscription = await putSubscription(instanceName, accessToken, alerts)
store.set({ pushSubscription: backendSubscription })
store.setInstanceData(instanceName, 'pushSubscriptions', backendSubscription)
store.save()
} catch (e) {
const backendSubscription = await postSubscription(instanceName, accessToken, subscription, alerts)
store.set({ pushSubscription: backendSubscription })
store.setInstanceData(instanceName, 'pushSubscriptions', backendSubscription)
store.save()
}
}

View File

@ -1,8 +1,10 @@
<div class="push-notifications">
{#if pushNotificationsSupport === false}
<p>Your browser doesn't support push notifications.</p>
<p>Your browser doesn't support push notifications.</p>
{:elseif $notificationPermission === "denied"}
<p role="alert">You have denied permission to show notifications.</p>
<p role="alert">You have denied permission to show notifications.</p>
{:elseif $loggedInInstancesInOrder.length > 1}
<p>Note that you can only have push notifications for one instance at a time.</p>
{/if}
<form id="push-notification-settings"
disabled="{!pushNotificationsSupport}"
@ -51,7 +53,7 @@
await updatePushSubscriptionForInstance(instanceName)
const { form } = this.refs
const { pushSubscription } = this.store.get()
const pushSubscription = this.store.getInstanceData(instanceName, 'pushSubscriptions')
for (let { key } of options) {
form.elements[key].checked = get(pushSubscription, ['alerts', key])

View File

@ -15,6 +15,7 @@ export function instanceComputations (store) {
computeForInstance(store, 'currentStatusModifications', 'statusModifications', null)
computeForInstance(store, 'currentCustomEmoji', 'customEmoji', [])
computeForInstance(store, 'currentComposeData', 'composeData', {})
computeForInstance(store, 'currentPushSubscription', 'pushSubscriptions', null)
store.compute(
'isUserLoggedIn',

View File

@ -36,4 +36,15 @@ export function instanceMixins (Store) {
instanceSettings[instanceName][settingName] = value
this.set({ instanceSettings })
}
Store.prototype.setInstanceData = function (instanceName, key, value) {
let instanceData = this.get()[key] || {}
instanceData[instanceName] = value
this.set({ [key]: instanceData })
}
Store.prototype.getInstanceData = function (instanceName, key) {
let instanceData = this.get()[key] || {}
return instanceData[instanceName]
}
}

View File

@ -32,7 +32,7 @@ const persistedState = {
neverMarkMediaAsSensitive: false,
omitEmojiInDisplayNames: undefined,
pinnedPages: {},
pushSubscription: null,
pushSubscriptions: {},
reduceMotion:
!process.browser ||
window.matchMedia('(prefers-reduced-motion: reduce)').matches,

View File

@ -1,5 +1,4 @@
// "lite" version of the store used in the inline script. Purely read-only,
// does not implement non-LocalStorage store features.
// "lite" version of the store used in the inline script.
import { safeParse } from './safeParse'
import { testHasLocalStorageOnce } from '../_utils/testStorage'
@ -16,5 +15,13 @@ export const storeLite = {
return obj[prop]
}
})
},
set (obj) {
if (hasLocalStorage) {
for (let [key, value] of Object.entries(obj)) {
localStorage.setItem(`store_${key}`, JSON.stringify(value))
}
}
}
}