Fetch all user info on startup

This commit is contained in:
wvffle 2022-07-21 23:19:16 +00:00 committed by Georg Krause
parent bd1a92c5f1
commit 4c02478470
10 changed files with 85 additions and 130 deletions

View File

@ -67,6 +67,11 @@ onKeyboardShortcut('h', () => toggleShortcutsModal())
const { width } = useWindowSize() const { width } = useWindowSize()
const showSetInstanceModal = ref(false) const showSetInstanceModal = ref(false)
// Fetch user data on startup
if (store.state.auth.authenticated) {
store.dispatch('auth/fetchUser')
}
</script> </script>
<template> <template>

View File

@ -9,7 +9,6 @@ import SemanticModal from '~/components/semantic/Modal.vue'
import useThemeList from '~/composables/useThemeList' import useThemeList from '~/composables/useThemeList'
import useTheme from '~/composables/useTheme' import useTheme from '~/composables/useTheme'
import axios from 'axios'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { computed, ref, watch, watchEffect, onMounted } from 'vue' import { computed, ref, watch, watchEffect, onMounted } from 'vue'
import { useGettext } from 'vue3-gettext' import { useGettext } from 'vue3-gettext'
@ -94,37 +93,6 @@ const moderationNotifications = computed(() =>
+ store.state.ui.notifications.pendingReviewRequests + store.state.ui.notifications.pendingReviewRequests
) )
onMounted(async () => {
if (store.state.auth.authenticated) {
const [inbox, edits, reports, requests] = await Promise.all([
axios.get('federation/inbox/', { params: { is_read: false } }).catch(() => ({ data: { count: 0 } })),
axios.get('mutations/', { params: { page_size: 1, q: 'is_approved:null' } }).catch(() => ({ data: { count: 0 } })),
axios.get('manage/moderation/reports/', { params: { page_size: 1, q: 'resolved:no' } }).catch(() => ({ data: { count: 0 } })),
axios.get('manage/moderation/requests/', { params: { page_size: 1, q: 'status:pending' } }).catch(() => ({ data: { count: 0 } }))
])
store.commit('ui/incrementNotifications', {
type: 'inbox',
value: inbox.data.count
})
store.commit('ui/incrementNotifications', {
type: 'pendingReviewEdits',
value: edits.data.count
})
store.commit('ui/incrementNotifications', {
type: 'pendingReviewRequests',
value: requests.data.count
})
store.commit('ui/incrementNotifications', {
type: 'pendingReviewReports',
value: reports.data.count
})
}
})
const isProduction = import.meta.env.PROD const isProduction = import.meta.env.PROD
const showUserModal = ref(false) const showUserModal = ref(false)
const showLanguageModal = ref(false) const showLanguageModal = ref(false)

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { BackendError } from '~/types' import type { BackendError } from '~/types'
import type { RouteLocationRaw } from 'vue-router'
import { ref, reactive, computed, onMounted } from 'vue' import { ref, reactive, computed, onMounted } from 'vue'
import { useGettext } from 'vue3-gettext' import { useGettext } from 'vue3-gettext'
@ -8,7 +9,7 @@ import { useStore } from '~/store'
import PasswordInput from '~/components/forms/PasswordInput.vue' import PasswordInput from '~/components/forms/PasswordInput.vue'
interface Props { interface Props {
next?: string next?: RouteLocationRaw
buttonClasses?: string buttonClasses?: string
showSignup?: boolean showSignup?: boolean
} }
@ -42,10 +43,7 @@ const submit = async () => {
try { try {
if (domain === store.getters['instance/domain']) { if (domain === store.getters['instance/domain']) {
await store.dispatch('auth/login', { await store.dispatch('auth/login', { credentials })
credentials,
next: props.next
})
} else { } else {
await store.dispatch('auth/oauthLogin', props.next) await store.dispatch('auth/oauthLogin', props.next)
} }
@ -61,14 +59,6 @@ const submit = async () => {
isLoading.value = false isLoading.value = false
} }
// export default {
// created () {
// if (this.$store.state.auth.authenticated) {
// this.$router.push(this.next)
// }
// },
// }
</script> </script>
<template> <template>

View File

@ -1,6 +1,7 @@
import type { User } from '~/types' import type { User } from '~/types'
import type { Module } from 'vuex' import type { Module } from 'vuex'
import type { RootState } from '~/store/index' import type { RootState } from '~/store/index'
import type { RouteLocationRaw } from 'vue-router'
import axios from 'axios' import axios from 'axios'
import useLogger from '~/composables/useLogger' import useLogger from '~/composables/useLogger'
@ -147,20 +148,12 @@ const store: Module<State, RootState> = {
}, },
actions: { actions: {
// Send a request to the login URL and save the returned JWT // Send a request to the login URL and save the returned JWT
login ({ dispatch }, { next, credentials, onError }) { async login ({ dispatch }, { credentials }) {
const form = useFormData(credentials) const form = useFormData(credentials)
return axios.post('users/login', form).then(() => { await axios.post('users/login', form)
logger.info('Successfully logged in as', credentials.username) logger.info('Successfully logged in as', credentials.username)
dispatch('fetchUser').then(() => { await dispatch('fetchUser')
// Redirect to a specified route
import('~/router').then((router) => {
return router.default.push(next)
})
})
}, response => {
logger.error('Error while logging in', response.data)
onError(response)
})
}, },
async logout ({ commit }) { async logout ({ commit }) {
try { try {
@ -181,36 +174,40 @@ const store: Module<State, RootState> = {
}) })
logger.info('Log out, goodbye!') logger.info('Log out, goodbye!')
}, },
fetchUser ({ dispatch }) {
return new Promise((resolve, reject) => { async fetchNotifications ({ dispatch, state }) {
axios.get('users/me/').then((response) => { return Promise.all([
dispatch('ui/fetchUnreadNotifications', null, { root: true }),
state.availablePermissions.library && dispatch('ui/fetchPendingReviewEdits', null, { root: true }),
state.availablePermissions.moderation && dispatch('ui/fetchPendingReviewReports', null, { root: true }),
state.availablePermissions.moderation && dispatch('ui/fetchPendingReviewRequests', null, { root: true })
])
},
async fetchUser ({ dispatch }) {
try {
const response = await axios.get('users/me/')
logger.info('Successfully fetched user profile') logger.info('Successfully fetched user profile')
dispatch('updateUser', response.data) dispatch('updateUser', response.data)
dispatch('ui/fetchUnreadNotifications', null, { root: true })
if (response.data.permissions.library) { await Promise.all([
dispatch('ui/fetchPendingReviewEdits', null, { root: true }) dispatch('fetchNotifications'),
} dispatch('favorites/fetch', null, { root: true }),
if (response.data.permissions.moderation) { dispatch('playlists/fetchOwn', null, { root: true }),
dispatch('ui/fetchPendingReviewReports', null, { root: true }) dispatch('libraries/fetchFollows', null, { root: true }),
dispatch('ui/fetchPendingReviewRequests', null, { root: true }) dispatch('channels/fetchSubscriptions', null, { root: true }),
}
dispatch('favorites/fetch', null, { root: true })
dispatch('channels/fetchSubscriptions', null, { root: true })
dispatch('libraries/fetchFollows', null, { root: true })
dispatch('moderation/fetchContentFilters', null, { root: true }) dispatch('moderation/fetchContentFilters', null, { root: true })
dispatch('playlists/fetchOwn', null, { root: true }) ])
resolve(response.data) } catch (error) {
}, () => { logger.error('Error while fetching user profile', error)
logger.info('Error while fetching user profile') }
reject(new Error('Error while fetching user profile'))
})
})
}, },
updateUser ({ commit }, data) { updateUser ({ commit }, data) {
commit('authenticated', true) commit('authenticated', true)
commit('profile', data) commit('profile', data)
commit('username', data.username) commit('username', data.username)
commit('fullUsername', data.full_username) commit('fullUsername', data.full_username)
if (data.tokens) { if (data.tokens) {
commit('scopedTokens', data.tokens) commit('scopedTokens', data.tokens)
} }
@ -220,7 +217,7 @@ const store: Module<State, RootState> = {
commit('permission', { key: permission, status: hasPermission }) commit('permission', { key: permission, status: hasPermission })
} }
}, },
async oauthLogin ({ state, rootState, commit }, next) { async oauthLogin ({ state, rootState, commit }, next: RouteLocationRaw) {
const app = await createOauthApp() const app = await createOauthApp()
commit('oauthApp', app) commit('oauthApp', app)
const redirectUri = encodeURIComponent(`${location.origin}/auth/callback`) const redirectUri = encodeURIComponent(`${location.origin}/auth/callback`)

View File

@ -103,13 +103,11 @@ const store: Module<State, RootState> = {
toggle ({ getters, dispatch }, uuid) { toggle ({ getters, dispatch }, uuid) {
dispatch('set', { uuid, value: !getters.isSubscribed(uuid) }) dispatch('set', { uuid, value: !getters.isSubscribed(uuid) })
}, },
fetchSubscriptions ({ commit }) { async fetchSubscriptions ({ commit }) {
const promise = axios.get('subscriptions/all/') const response = await axios.get('subscriptions/all/')
return promise.then((response) => { for (const result of response.data.results) {
response.data.results.forEach((result: { channel: unknown }) => {
commit('subscriptions', { uuid: result.channel, value: true }) commit('subscriptions', { uuid: result.channel, value: true })
}) }
})
} }
} }
} }

View File

@ -64,20 +64,20 @@ const store: Module<State, RootState> = {
toggle ({ getters, dispatch }, id) { toggle ({ getters, dispatch }, id) {
dispatch('set', { id, value: !getters.isFavorite(id) }) dispatch('set', { id, value: !getters.isFavorite(id) })
}, },
fetch ({ commit, rootState }) { async fetch ({ commit, rootState }) {
// will fetch favorites by batches from API to have them locally // will fetch favorites by batches from API to have them locally
const params = { const params = {
user: rootState.auth.profile?.id, user: rootState.auth.profile?.id,
page_size: 50, page_size: 50,
ordering: '-creation_date' ordering: '-creation_date'
} }
const promise = axios.get('favorites/tracks/all/', { params })
return promise.then((response) => { const response = await axios.get('favorites/tracks/all/', { params })
logger.info('Fetched a batch of ' + response.data.results.length + ' favorites') logger.info('Fetched a batch of ' + response.data.results.length + ' favorites')
response.data.results.forEach((result: { track: string }) => {
for (const result of response.data.results) {
commit('track', { id: result.track, value: true }) commit('track', { id: result.track, value: true })
}) }
})
} }
} }
} }

View File

@ -67,13 +67,11 @@ const store: Module<State, RootState> = {
toggle ({ getters, dispatch }, uuid) { toggle ({ getters, dispatch }, uuid) {
dispatch('set', { uuid, value: !getters.follow(uuid) }) dispatch('set', { uuid, value: !getters.follow(uuid) })
}, },
fetchFollows ({ dispatch, state, commit, rootState }, url) { async fetchFollows ({ dispatch, state, commit, rootState }, url) {
const promise = axios.get('federation/follows/library/all/') const response = await axios.get('federation/follows/library/all/')
return promise.then((response) => { for (const result of response.data.results) {
response.data.results.forEach((result: { library: string }) => {
commit('follows', { library: result.library, follow: result }) commit('follows', { library: result.library, follow: result })
}) }
})
} }
} }
} }

View File

@ -128,30 +128,28 @@ const store: Module<State, RootState> = {
commit('reportModalTarget', payload) commit('reportModalTarget', payload)
commit('showReportModal', true) commit('showReportModal', true)
}, },
fetchContentFilters ({ dispatch, commit }, url) { async fetchContentFilters ({ dispatch, commit }, url) {
let params = {} const params = url
let promise ? {}
if (url) { : {
promise = axios.get(url)
} else {
commit('empty')
params = {
page_size: 100, page_size: 100,
ordering: '-creation_date' ordering: '-creation_date'
} }
promise = axios.get('moderation/content-filters/', { params })
} if (!url) commit('empty')
return promise.then((response) => { const response = await axios.get(url ?? 'moderation/content-filters/', { params })
logger.info('Fetched a batch of ' + response.data.results.length + ' filters')
if (response.data.next) { logger.info(`Fetched a batch of ${response.data.results.length} filters`)
dispatch('fetchContentFilters', response.data.next)
} for (const result of response.data.results) {
response.data.results.forEach((result: ContentFilter) => {
commit('contentFilter', result) commit('contentFilter', result)
}) }
})
if (response.data.next) {
await dispatch('fetchContentFilters', response.data.next)
}
}, },
deleteContentFilter ({ commit }, uuid) { async deleteContentFilter ({ commit }, uuid) {
return axios.delete(`moderation/content-filters/${uuid}/`).then(() => { return axios.delete(`moderation/content-filters/${uuid}/`).then(() => {
commit('deleteContentFilter', uuid) commit('deleteContentFilter', uuid)
}) })

View File

@ -41,7 +41,7 @@ const store: Module<State, RootState> = {
const playlists = [] const playlists = []
let url = 'playlists/' let url = 'playlists/'
while (url != null) { while (url !== null) {
const response = await axios.get(url, { params: { scope: 'me' } }) const response = await axios.get(url, { params: { scope: 'me' } })
playlists.push(...response.data.results) playlists.push(...response.data.results)
url = response.data.next url = response.data.next

View File

@ -6,6 +6,7 @@ import { useRouter } from 'vue-router'
import { computed } from 'vue' import { computed } from 'vue'
import { useGettext } from 'vue3-gettext' import { useGettext } from 'vue3-gettext'
import { useStore } from '~/store' import { useStore } from '~/store'
import { whenever } from '@vueuse/core'
interface Props { interface Props {
next?: RouteLocationRaw next?: RouteLocationRaw
@ -21,11 +22,11 @@ const labels = computed(() => ({
})) }))
const store = useStore() const store = useStore()
if (store.state.auth.authenticated) {
const router = useRouter() const router = useRouter()
whenever(() => store.state.auth.authenticated, () => {
const resolved = router.resolve(props.next) const resolved = router.resolve(props.next)
router.push(resolved.name === '404' ? '/library' : props.next) router.push(resolved.name === '404' ? '/library' : props.next)
} })
</script> </script>
<template> <template>