audiobookshelf/client/store/user.js
Igor Serebryany 63f1df4015
don't save proxy user's tokens in localstorage
we still want those tokens, we will use them in the mobile app. but we
don't want them client side, otherwise proxy users remain logged in. we
centralize the logic around storing the token, and turn `setUser` into
an action vs a mutation
2023-10-06 16:31:01 -07:00

173 lines
5.8 KiB
JavaScript

export const state = () => ({
user: null,
settings: {
orderBy: 'media.metadata.title',
orderDesc: false,
filterBy: 'all',
playbackRate: 1,
bookshelfCoverSize: 120,
collapseSeries: false,
collapseBookSeries: false,
useChapterTrack: false,
seriesSortBy: 'name',
seriesSortDesc: false,
seriesFilterBy: 'all'
}
})
export const getters = {
getIsRoot: (state) => state.user && state.user.type === 'root',
getIsAdminOrUp: (state) => state.user && (state.user.type === 'admin' || state.user.type === 'root'),
getToken: (state) => {
return state.user?.token || null
},
getUserMediaProgress: (state) => (libraryItemId, episodeId = null) => {
if (!state.user.mediaProgress) return null
return state.user.mediaProgress.find(li => {
if (episodeId && li.episodeId !== episodeId) return false
return li.libraryItemId == libraryItemId
})
},
getUserBookmarksForItem: (state) => (libraryItemId) => {
if (!state.user.bookmarks) return []
return state.user.bookmarks.filter(bm => bm.libraryItemId === libraryItemId)
},
getUserSetting: (state) => (key) => {
return state.settings?.[key] || null
},
getUserCanUpdate: (state) => {
return !!state.user?.permissions?.update
},
getUserCanDelete: (state) => {
return !!state.user?.permissions?.delete
},
getUserCanDownload: (state) => {
return !!state.user?.permissions?.download
},
getUserCanUpload: (state) => {
return !!state.user?.permissions?.upload
},
getUserCanAccessAllLibraries: (state) => {
return !!state.user?.permissions?.accessAllLibraries
},
getLibrariesAccessible: (state, getters) => {
if (!state.user) return []
if (getters.getUserCanAccessAllLibraries) return []
return state.user.librariesAccessible || []
},
getCanAccessLibrary: (state, getters) => (libraryId) => {
if (!state.user) return false
if (getters.getUserCanAccessAllLibraries) return true
return getters.getLibrariesAccessible.includes(libraryId)
},
getIsSeriesRemovedFromContinueListening: (state) => (seriesId) => {
if (!state.user || !state.user.seriesHideFromContinueListening || !state.user.seriesHideFromContinueListening.length) return false
return state.user.seriesHideFromContinueListening.includes(seriesId)
}
}
export const actions = {
// When changing libraries make sure sort and filter is still valid
checkUpdateLibrarySortFilter({ state, dispatch, commit }, mediaType) {
const settingsUpdate = {}
if (mediaType == 'podcast') {
if (state.settings.orderBy == 'media.metadata.authorName' || state.settings.orderBy == 'media.metadata.authorNameLF') {
settingsUpdate.orderBy = 'media.metadata.author'
}
if (state.settings.orderBy == 'media.duration') {
settingsUpdate.orderBy = 'media.numTracks'
}
if (state.settings.orderBy == 'media.metadata.publishedYear') {
settingsUpdate.orderBy = 'media.metadata.title'
}
const invalidFilters = ['series', 'authors', 'narrators', 'publishers', 'languages', 'progress', 'issues', 'ebooks', 'abridged']
const filterByFirstPart = (state.settings.filterBy || '').split('.').shift()
if (invalidFilters.includes(filterByFirstPart)) {
settingsUpdate.filterBy = 'all'
}
} else {
if (state.settings.orderBy == 'media.metadata.author') {
settingsUpdate.orderBy = 'media.metadata.authorName'
}
if (state.settings.orderBy == 'media.numTracks') {
settingsUpdate.orderBy = 'media.duration'
}
}
if (Object.keys(settingsUpdate).length) {
dispatch('updateUserSettings', settingsUpdate)
}
},
updateUserSettings({ state, commit }, payload) {
if (!payload) return false
let hasChanges = false
const existingSettings = { ...state.settings }
for (const key in existingSettings) {
if (payload[key] !== undefined && existingSettings[key] !== payload[key]) {
hasChanges = true
existingSettings[key] = payload[key]
}
}
if (hasChanges) {
commit('setSettings', existingSettings)
this.$eventBus.$emit('user-settings', state.settings)
}
},
loadUserSettings({ state, commit }) {
// Load settings from local storage
try {
let userSettingsFromLocal = localStorage.getItem('userSettings')
if (userSettingsFromLocal) {
userSettingsFromLocal = JSON.parse(userSettingsFromLocal)
const userSettings = { ...state.settings }
for (const key in userSettings) {
if (userSettingsFromLocal[key] !== undefined) {
userSettings[key] = userSettingsFromLocal[key]
}
}
commit('setSettings', userSettings)
this.$eventBus.$emit('user-settings', state.settings)
}
} catch (error) {
console.error('Failed to load userSettings from local storage', error)
}
},
setUser({ commit }, user) {
commit('setUser', user)
commit('setUserToken', user ? user.token : null)
},
}
export const mutations = {
setUser(state, user) {
state.user = user
},
setUserToken(state, token) {
if (!token) {
localStorage.removeItem('token')
} else if (state.user && state.user.isFromProxy) {
localStorage.removeItem('token')
} else {
state.user.token = token
localStorage.setItem('token', token)
}
},
updateMediaProgress(state, { id, data }) {
if (!state.user) return
if (!data) {
state.user.mediaProgress = state.user.mediaProgress.filter(lip => lip.id != id)
} else {
var indexOf = state.user.mediaProgress.findIndex(lip => lip.id == id)
if (indexOf >= 0) {
state.user.mediaProgress.splice(indexOf, 1, data)
} else {
state.user.mediaProgress.push(data)
}
}
},
setSettings(state, settings) {
if (!settings) return
localStorage.setItem('userSettings', JSON.stringify(settings))
state.settings = settings
}
}