diff --git a/dbrepo-ui/bun.lockb b/dbrepo-ui/bun.lockb index 45a8c51c621dab127458d68a4493b23d2df9f88d..7ee1d3897245ee94212d8bfb6a6b97556b64f1d2 100755 Binary files a/dbrepo-ui/bun.lockb and b/dbrepo-ui/bun.lockb differ diff --git a/dbrepo-ui/components/OntologiesList.vue b/dbrepo-ui/components/OntologiesList.vue index c7120cac4a1e58e4a1f22c651f77aebcaf002584..432d26e428eed1085d2806ed371342b445822599 100644 --- a/dbrepo-ui/components/OntologiesList.vue +++ b/dbrepo-ui/components/OntologiesList.vue @@ -34,29 +34,20 @@ </div> </template> +<script setup> +</script> <script> -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { data () { return { - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - token () { - return this.userStore.getToken - }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, ontologies () { - return this.cacheStore.getOntologies + return [] } }, mounted () { diff --git a/dbrepo-ui/components/database/DatabaseToolbar.vue b/dbrepo-ui/components/database/DatabaseToolbar.vue index 4177ae592cbae97090d0b109c576137b0ee74cbc..9d43b262e3c3b67cfe748fcb13168d17362af1d0 100644 --- a/dbrepo-ui/components/database/DatabaseToolbar.vue +++ b/dbrepo-ui/components/database/DatabaseToolbar.vue @@ -81,9 +81,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import { useCacheStore } from '@/stores/cache.js' -import { useUserStore } from '@/stores/user.js' import ResourceStatus from '@/components/ResourceStatus.vue' export default { @@ -94,8 +100,7 @@ export default { return { tab: null, error: false, - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { @@ -103,13 +108,7 @@ export default { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess - }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles + return this.cacheStore.getAccess }, isContrastTheme () { return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') @@ -172,7 +171,7 @@ export default { if (!this.database || !this.user) { return false } - return this.database.owner.username === this.user.username + return this.database.owner.id === this.userInfo.uid }, buttonVariant () { const runtimeConfig = useRuntimeConfig() diff --git a/dbrepo-ui/components/identifier/Persist.vue b/dbrepo-ui/components/identifier/Persist.vue index 3dba450e634c6db374ccd28bd327ff2823756f3e..408d7e8265b667a6f1ab2b8a8e5c966bfa8e7028 100644 --- a/dbrepo-ui/components/identifier/Persist.vue +++ b/dbrepo-ui/components/identifier/Persist.vue @@ -827,10 +827,16 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import { formatYearUTC, formatMonthUTC, formatDayUTC, languages } from '@/utils' import { useCacheStore } from '@/stores/cache.js' -import { useUserStore } from '@/stores/user.js' import { MerkleJson } from 'merkle-json' export default { @@ -962,17 +968,10 @@ export default { { value: 'IsObsoletedBy' }, { value: 'Obsoletes' } ], - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, isSubset () { return this.type === 'subset' }, @@ -1045,9 +1044,6 @@ export default { } } }, - isUpdate () { - return 'id' in this.identifier && this.identifier.id - }, canInsertSelf () { if (!this.user) { return false diff --git a/dbrepo-ui/components/identifier/Select.vue b/dbrepo-ui/components/identifier/Select.vue index 4404a09635c6833e609f74c4f685988550dc97c8..84f87e321fcb81c7d7e233cedd4a79ad45b21271 100644 --- a/dbrepo-ui/components/identifier/Select.vue +++ b/dbrepo-ui/components/identifier/Select.vue @@ -41,10 +41,16 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import Banner from '@/components/identifier/Banner.vue' import { formatTimestampUTCLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -68,17 +74,10 @@ export default { data () { return { idx: null, - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, displayIdentifiers () { if (!this.identifiers) { return [] diff --git a/dbrepo-ui/components/identifier/Summary.vue b/dbrepo-ui/components/identifier/Summary.vue index 655a7bb907c9f8a6b868e280097033b157cd893c..6ef120599b515fece88870ad832ed23a508e4ebe 100644 --- a/dbrepo-ui/components/identifier/Summary.vue +++ b/dbrepo-ui/components/identifier/Summary.vue @@ -170,10 +170,10 @@ export default { }, computed: { access () { - return this.userStore.getAccess.value + return this.cacheStore.getAccess }, database () { - return this.cacheStore.getDatabase.value + return this.cacheStore.getDatabase }, pid () { return `/pid/${this.database.identifier.id}` diff --git a/dbrepo-ui/components/subset/Builder.vue b/dbrepo-ui/components/subset/Builder.vue index b45881479cb5243861ab8137a99999def787e551..ae7df2768370f472a85c1dd5cbe673773c92cac1 100644 --- a/dbrepo-ui/components/subset/Builder.vue +++ b/dbrepo-ui/components/subset/Builder.vue @@ -1,5 +1,6 @@ <template> - <div> + <div + v-if="loggedIn"> <v-toolbar flat> <v-btn size="small" @@ -303,12 +304,16 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +</script> <script> import TimeDrift from '@/components/TimeDrift.vue' import Raw from '@/components/subset/Raw.vue' import Results from '@/components/subset/Results.vue' import { useCacheStore } from '@/stores/cache.js' -import { useUserStore } from '@/stores/user.js' import { format } from 'sql-formatter' export default { @@ -359,8 +364,7 @@ export default { tabs: 0, loadingQuery: false, loadingColumns: false, - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { @@ -388,9 +392,6 @@ export default { } return this.database.container.image.data_types }, - user () { - return this.userStore.getUser - }, viewNames () { if (!this.database) { return [] diff --git a/dbrepo-ui/components/subset/SubsetList.vue b/dbrepo-ui/components/subset/SubsetList.vue index 6908b2b4381d88d7b5a7a19ce540b4c88c633e0e..eb6a27aacda5ba99b16fa920ccc08594f8ccea92 100644 --- a/dbrepo-ui/components/subset/SubsetList.vue +++ b/dbrepo-ui/components/subset/SubsetList.vue @@ -45,8 +45,6 @@ </template> <script> -import { formatTimestampUTCLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -55,14 +53,10 @@ export default { loadingSubsets: false, loadingIdentifiers: false, subsets: [], - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -130,7 +124,6 @@ export default { } } </script> - <style lang="scss" scoped> .pid-icon { flex: 0 !important; diff --git a/dbrepo-ui/components/subset/SubsetToolbar.vue b/dbrepo-ui/components/subset/SubsetToolbar.vue index d5f45e48e3a2d596977a37186a0076179bcd583f..45ca7626289965f57d5771afaed4c1159fd0f414 100644 --- a/dbrepo-ui/components/subset/SubsetToolbar.vue +++ b/dbrepo-ui/components/subset/SubsetToolbar.vue @@ -55,10 +55,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +</script> <script> import DownloadButton from '@/components/identifier/DownloadButton.vue' import { formatTimestampUTCLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -71,7 +76,6 @@ export default { loading: false, loadingSave: false, downloadLoading: false, - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -86,13 +90,7 @@ export default { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess - }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles + return this.cacheStore.getAccess }, subset () { return this.cacheStore.getSubset @@ -154,10 +152,10 @@ export default { return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' }, canGetPid () { - if (!this.user || !this.subset || !this.database) { + if (!this.userInfo || !this.subset || !this.database) { return false } - return this.database.owner.id === this.user.id || (this.subset.owner.id === this.user.id && this.hasReadAccess) + return this.database.owner.id === this.userInfo.uid || (this.subset.owner.id === this.userInfo.uid && this.hasReadAccess) }, title () { if (!this.identifier) { diff --git a/dbrepo-ui/components/table/TableList.vue b/dbrepo-ui/components/table/TableList.vue index b78e20ae3a6d423a90a636f119d96e4b406ea45d..d34483422d232292b6d108a3a5aa4a13e4a16ac4 100644 --- a/dbrepo-ui/components/table/TableList.vue +++ b/dbrepo-ui/components/table/TableList.vue @@ -38,9 +38,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import { formatTimestampUTCLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -74,19 +80,15 @@ export default { { value: 'string', title: 'Character Varying' }, { value: 'text', title: 'Text' } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, tables () { if (!this.database) { diff --git a/dbrepo-ui/components/table/TableToolbar.vue b/dbrepo-ui/components/table/TableToolbar.vue index d6fd4868eae0e65a52d932339ba5bbab6e3ad56f..9aee22348ffc55c1b11c385592f685314a7b5e20 100644 --- a/dbrepo-ui/components/table/TableToolbar.vue +++ b/dbrepo-ui/components/table/TableToolbar.vue @@ -77,10 +77,16 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import EditTuple from '@/components/dialogs/EditTuple.vue' import { useCacheStore } from '@/stores/cache.js' -import { useUserStore } from '@/stores/user.js' export default { components: { @@ -93,8 +99,7 @@ export default { error: false, edit: false, dropTableDialog: false, - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { @@ -105,7 +110,7 @@ export default { return this.cacheStore.getTable }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, hasReadAccess () { if (!this.access) { @@ -113,17 +118,11 @@ export default { } return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, canUpdateTable () { if (!this.roles || !this.user || !this.table) { return false } - return this.roles.includes('update-table') && this.table.owner.id === this.user.id + return this.roles.includes('update-table') && this.table.owner.id === this.userInfo.uid }, canExecuteQuery () { if (!this.roles || !this.table || !this.user) { @@ -149,7 +148,7 @@ export default { if (!this.user) { return false } - return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id + return this.hasReadAccess || this.table.owner.id === this.userInfo.uid || this.database.owner.id === this.userInfo.uid }, canViewSchema () { if (!this.table) { @@ -161,7 +160,7 @@ export default { if (!this.user) { return false } - return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id + return this.hasReadAccess || this.table.owner.id === this.userInfo.uid || this.database.owner.id === this.userInfo.uid }, canImportCsv () { if (!this.roles || !this.table || !this.user) { @@ -173,7 +172,7 @@ export default { if (!this.user || !this.table || !this.database) { return false } - return this.database.owner.id === this.user.id || this.table.owner.id === this.user.id + return this.database.owner.id === this.userInfo.uid || this.table.owner.id === this.userInfo.uid }, buttonVariant () { const runtimeConfig = useRuntimeConfig() diff --git a/dbrepo-ui/components/user/UserToolbar.vue b/dbrepo-ui/components/user/UserToolbar.vue index e5a20c75a3230d80dc3e6f63c27c5bb6a743a463..868bab88a94123ae28aa2702f543ddab3f54dc0d 100644 --- a/dbrepo-ui/components/user/UserToolbar.vue +++ b/dbrepo-ui/components/user/UserToolbar.vue @@ -1,6 +1,9 @@ <template> - <div> - <v-toolbar title="Settings" flat> + <div + v-if="loggedIn"> + <v-toolbar + title="Settings" + flat> <template v-slot:extension> <v-tabs v-model="tab" @@ -11,31 +14,20 @@ <v-tab :text="$t('toolbars.user.authentication')" to="/user/authentication" /> - <v-tab - :text="$t('toolbars.user.developer')" - to="/user/developer" /> </v-tabs> </template> </v-toolbar> </div> </template> +<script setup> +const { loggedIn, user, login, logout } = useOidcAuth() +</script> <script> -import { useUserStore } from '@/stores/user.js' - export default { data () { return { tab: null, - userStore: useUserStore() - } - }, - computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles } } } diff --git a/dbrepo-ui/components/view/ViewList.vue b/dbrepo-ui/components/view/ViewList.vue index d6539bd253cb7ef40c202633db53d564ec1e6269..58038b7a82f038aeebef4e7a70e684cccab51449 100644 --- a/dbrepo-ui/components/view/ViewList.vue +++ b/dbrepo-ui/components/view/ViewList.vue @@ -34,7 +34,6 @@ </template> <script> -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -43,14 +42,10 @@ export default { loading: false, loadingDetails: false, error: false, - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, diff --git a/dbrepo-ui/components/view/ViewToolbar.vue b/dbrepo-ui/components/view/ViewToolbar.vue index 4ed83ff43fa777f9f8f663cf020d89d5d58456cd..74eac9dedf5d7e446585dd01a5e5e4a107f1ae29 100644 --- a/dbrepo-ui/components/view/ViewToolbar.vue +++ b/dbrepo-ui/components/view/ViewToolbar.vue @@ -56,8 +56,14 @@ </v-toolbar> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' import CreateOntology from '@/components/dialogs/CreateOntology.vue' import ViewVisibility from '@/components/dialogs/ViewVisibility.vue' @@ -73,7 +79,6 @@ export default { loading: false, loadingDelete: false, updateViewDialog: false, - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -101,7 +106,7 @@ export default { if (!this.user) { return false } - return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id + return this.hasReadAccess || this.view.owner.id === this.userInfo.id || this.database.owner.id === this.userInfo.id }, canViewSchema () { if (!this.view) { @@ -113,13 +118,13 @@ export default { if (!this.user) { return false } - return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id + return this.hasReadAccess || this.view.owner.id === this.userInfo.id || this.database.owner.id === this.userInfo.id }, canViewSettings () { if (!this.user || !this.view) { return false } - return this.view.owner.id === this.user.id + return this.view.owner.id === this.userInfo.id }, canCreatePid () { if (!this.roles || !this.user || !this.view) { @@ -129,13 +134,7 @@ export default { return this.roles.includes('create-identifier') && userService.hasReadAccess(this.access) }, access () { - return this.userStore.getAccess - }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles + return this.cacheStore.getAccess }, hasReadAccess () { if (!this.access) { diff --git a/dbrepo-ui/composables/axios-instance.ts b/dbrepo-ui/composables/axios-instance.ts index 95edea3c28d5c12f1f2422ccf8b457e409c5b459..ca7a7b111cf70cf92524f5459808277e4b14144e 100644 --- a/dbrepo-ui/composables/axios-instance.ts +++ b/dbrepo-ui/composables/axios-instance.ts @@ -1,11 +1,9 @@ import axios, {type AxiosInstance} from 'axios' -import {useUserStore} from '@/stores/user' let instance: AxiosInstance | null = null; export const useAxiosInstance = () => { const config = useRuntimeConfig() - const userStore = useUserStore() if (!instance) { instance = axios.create({ timeout: 90_000, @@ -18,38 +16,16 @@ export const useAxiosInstance = () => { baseURL: config.public.api.client }); instance.interceptors.request.use((config) => { - const token = userStore.getToken - const refreshToken = userStore.getRefreshToken - if (!token || !refreshToken) { + const { loggedIn, user, login, logout } = useOidcAuth() + if (!loggedIn) { return config } - const authenticationService = useAuthenticationService() - if (authenticationService.isExpiredToken(refreshToken)) { - console.warn('Refresh token is expired: trigger logout of user') - userStore.logout() + const { accessToken } = user.value + if (!accessToken) { return config } - if (!authenticationService.isExpiredToken(token)) { - config.headers.Authorization = `Bearer ${token}` - return config - } - console.warn('Access token expired: request a new one') - const userService = useUserService() - return userService.refreshToken(refreshToken) - .then((response: KeycloakOpenIdTokenDto) => { - userStore.setToken(response.access_token) - userStore.setRefreshToken(response.refresh_token) - console.debug('new access token expires:', authenticationService.tokenToExpiryDate(response.access_token)) - config.headers.Authorization = `Bearer ${response.access_token}` - return config - }) - .catch((error: ApiErrorDto) => { - if (error.code === 'error.user.credentials') { - console.warn('User session expired.') - userStore.logout() - } - return config - }); + config.headers.Authorization = `Bearer ${accessToken}` + return config }) } return instance; diff --git a/dbrepo-ui/composables/upload-service.ts b/dbrepo-ui/composables/upload-service.ts index f7a6964d58cba007c3aa7e515f362349ca0a4f4a..ee0bdd5dc029a061ee102a9e526933ef7ca26413 100644 --- a/dbrepo-ui/composables/upload-service.ts +++ b/dbrepo-ui/composables/upload-service.ts @@ -1,11 +1,9 @@ import * as tus from 'tus-js-client' import {useCacheStore} from '@/stores/cache' -import {useUserStore} from '@/stores/user' export const useUploadService = (): any => { function create (data: File) { - const userStore = useUserStore() const config = useRuntimeConfig() const endpoint = config.public.upload.client return new Promise<string>((resolve, reject) => { @@ -13,10 +11,16 @@ export const useUploadService = (): any => { console.error('Your browser does not support uploads!') return } + const { loggedIn, user, login, logout } = useOidcAuth() + if (!loggedIn || !user.value?.accessToken) { + console.error('Please login to use the upload!') + return + } + const { accessToken } = user.value const uploadClient: tus.Upload = new tus.Upload(data, { endpoint, headers: { - 'Authorization': `Bearer ${userStore.getToken}` + 'Authorization': `Bearer ${accessToken}` }, retryDelays: [0, 3000, 5000, 10000, 20000], onError (error) { diff --git a/dbrepo-ui/composables/user-service.ts b/dbrepo-ui/composables/user-service.ts index e68b914e0e5bd5cfc410b82213e18f3eb0fa32ab..5381fee565a0953fec4b7b523b425a54f1e99229 100644 --- a/dbrepo-ui/composables/user-service.ts +++ b/dbrepo-ui/composables/user-service.ts @@ -80,32 +80,6 @@ export const useUserService = (): any => { }) } - async function obtainToken(username: string, password: string): Promise<KeycloakOpenIdTokenDto> { - console.debug('obtain user token for user with username', username) - return new Promise<KeycloakOpenIdTokenDto>((resolve, reject) => { - const config = useRuntimeConfig() - const userStore = useUserStore() - const instance = axios.create({ - timeout: 90_000, - params: {}, - baseURL: config.public.api.client - }) - instance.post<KeycloakOpenIdTokenDto>('/api/user/token', {username, password}) - .then((response) => { - console.info('Obtained user token') - // eslint-disable-next-line camelcase - const {access_token, refresh_token} = response.data - userStore.setToken(access_token) - userStore.setRefreshToken(refresh_token) - userStore.setRoles(tokenToRoles(access_token)) - resolve(response.data) - }).catch((error) => { - console.error('Failed to obtain user token', error) - reject(axiosErrorToApiError(error)) - }) - }) - } - async function refreshToken(refreshToken: string): Promise<KeycloakOpenIdTokenDto> { console.debug('refresh user token') return new Promise<KeycloakOpenIdTokenDto>((resolve, reject) => { @@ -136,21 +110,6 @@ export const useUserService = (): any => { return data.realm_access.roles || [] } - function tokenToUserId(token: string): string { - const data: Token = jwtDecode<Token>(token) - return data.uid - } - - function userInfoToUser(data: UserDto) { - const obj: UserDto = Object.assign({}, data) - obj.attributes = { - theme: data.attributes.theme, - orcid: data.attributes.orcid, - affiliation: data.attributes.affiliation - } - return obj - } - function nameIdentifierToNameIdentifierScheme(nameIdentifier: string) { if (nameIdentifier.includes('orcid.org')) { return 'ORCID' @@ -197,11 +156,7 @@ export const useUserService = (): any => { update, create, updatePassword, - obtainToken, refreshToken, - tokenToRoles, - tokenToUserId, - userInfoToUser, nameIdentifierToNameIdentifierScheme, userToFullName, hasReadAccess, diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue index 0ad4cb818d353d283c15d0cc7c6240fec513a54b..e65a25690654b2bd87ad618c795fb2f0658b92b2 100644 --- a/dbrepo-ui/layouts/default.vue +++ b/dbrepo-ui/layouts/default.vue @@ -96,16 +96,16 @@ @click:append-inner="retrieve" /> <v-spacer /> <v-btn - v-if="!user" + v-if="!loggedIn" class="mr-2" color="secondary" variant="flat" :prepend-icon="$vuetify.display.mdAndUp ? 'mdi-login' : null" - to="/login"> + @click="login()"> {{ $t('navigation.login') }} </v-btn> <v-btn - v-if="!user" + v-if="!loggedIn" color="primary" variant="flat" :prepend-icon="$vuetify.display.mdAndUp ? 'mdi-account-plus' : null" @@ -113,12 +113,12 @@ {{ $t('navigation.signup') }} </v-btn> <v-btn - v-if="user" + v-if="loggedIn" to="/user" variant="plain" - :text="user.username" /> + :text="userInfo.preferred_username" /> <v-menu - v-if="user" + v-if="loggedIn" location="bottom"> <template v-slot:activator="{ props }"> <v-btn @@ -140,7 +140,7 @@ </v-list-item> <v-list-item v-if="user" - @click="logout"> + @click="logout()"> {{ $t('navigation.logout') }} </v-list-item> </v-list> @@ -163,6 +163,9 @@ <script setup> import { ref } from 'vue' +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) const runtimeConfig = useRuntimeConfig() const config = ref(runtimeConfig) useServerHead({ @@ -175,10 +178,10 @@ useServerHead({ </script> <script> import JumboBox from '@/components/JumboBox.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' import { errorCodeKey, makeError } from '@/utils' + export default { components: { JumboBox @@ -197,26 +200,13 @@ export default { loadingSearch: false, loadingDatabases: false, search: null, - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - token () { - return this.userStore.getToken - }, - user () { - return this.userStore.getUser - }, - locale () { - return this.userStore.getLocale - }, messages () { return this.cacheStore.getMessages }, - access () { - return this.userStore.getAccess - }, table () { return this.cacheStore.getTable }, @@ -244,9 +234,6 @@ export default { } return 'database' }, - roles () { - return this.userStore.getRoles - }, version () { return this.$config.public.version }, @@ -295,6 +282,9 @@ export default { logo () { return this.$config.public.logo }, + locale () { + return this.cacheStore.getLocale + }, searchVariant () { const runtimeConfig = useRuntimeConfig() return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.input.contrast : 'solo-filled' @@ -319,8 +309,8 @@ export default { .catch((error) => { this.databaseError = error }) - if (this.user) { - this.userStore.setRouteAccess(newObj.database_id) + if (this.userInfo) { + this.cacheStore.setRouteAccess(newObj.database_id, this.userInfo.uid) } /* load table */ if (newObj.table_id) { @@ -357,27 +347,14 @@ export default { this.cacheStore.reloadMessages() }, methods: { - errorCodeKey, - login () { - const redirect = ![undefined, '/', '/login'].includes(this.$router.currentRoute.path) - this.$router.push({ path: '/login', query: redirect ? { redirect: this.$router.currentRoute.path } : {} }) - }, - logout () { - this.$vuetify.theme.global.name = 'tuwThemeLight' - this.userStore.logout() - this.$router.push('/database') - }, retrieve () { console.debug('performing fuzzy search') this.$router.push({ path: '/search', query: { q: this.search } }) }, initEnvironment () { - if (this.token && !this.user) { - console.error('Something went wrong with loading the user: reset user cache') - this.userStore.logout() - } if (!this.locale) { - this.userStore.setLocale('en') + this.cacheStore.setLocale('en') + return } this.$i18n.locale = this.locale }, @@ -398,7 +375,7 @@ export default { } }, setLocale (code) { - this.userStore.setLocale(code) + this.cacheStore.setLocale(code) this.$i18n.locale = this.locale } } diff --git a/dbrepo-ui/nuxt.config.ts b/dbrepo-ui/nuxt.config.ts index 4b1833d8162e7e1494f4164fa90bb76e107f7635..1804b3a3fd322ffe6cc5ae82e8c9ae6bace1f0a8 100644 --- a/dbrepo-ui/nuxt.config.ts +++ b/dbrepo-ui/nuxt.config.ts @@ -107,11 +107,32 @@ export default defineNuxtConfig({ port: 3001 }, + oidc: { + providers: { + keycloak: { + audience: 'account', + baseUrl: 'http://localhost:8080/realms/dbrepo', + clientId: 'dbrepo-client', + clientSecret: '', // inject on runtime + scope: ['openid', 'roles'], + optionalClaims: ['realm_access'], + redirectUri: 'http://localhost/auth/keycloak/callback', + userNameClaim: 'preferred_username', + exposeAccessToken: true, + logoutRedirectUri: 'http://localhost', + }, + }, + middleware: { + globalMiddlewareEnabled: false + }, + }, + modules: [ - '@artmizu/nuxt-prometheus', + ['@artmizu/nuxt-prometheus', {verbose: false}], '@nuxtjs/i18n', '@pinia/nuxt', '@pinia-plugin-persistedstate/nuxt', + 'nuxt-oidc-auth', async (options, nuxt) => { nuxt.hooks.hook('vite:extendConfig', config => config.plugins.push( vuetify() @@ -160,6 +181,8 @@ export default defineNuxtConfig({ }, }, - devtools: {enabled: true}, - compatibilityDate: '2024-07-24' + devtools: { + enabled: false + }, + compatibilityDate: '2025-01-25' }) diff --git a/dbrepo-ui/package.json b/dbrepo-ui/package.json index a1354778200ebabb28a575e204e264e6bd155774..ec3ae1e6a44710998f0642760cf1e506b1d546d3 100644 --- a/dbrepo-ui/package.json +++ b/dbrepo-ui/package.json @@ -28,6 +28,7 @@ "merkle-json": "^2.6.0", "moment": "^2.30.1", "nuxt": "^3.10.3", + "nuxt-oidc-auth": "^1.0.0-beta.5", "parse-md": "^3.0.3", "pinia": "^2.1.7", "qs": "^6.11.2", diff --git a/dbrepo-ui/pages/container/index.vue b/dbrepo-ui/pages/container/index.vue index 360ce1543fdf086d60d568ed066ccca1f7c04537..ec2149372e509c064d45e0ee684a60824bf17520 100644 --- a/dbrepo-ui/pages/container/index.vue +++ b/dbrepo-ui/pages/container/index.vue @@ -25,19 +25,19 @@ export default { containers: [] } }, - computed: { - roles () { - return this.userStore.getRoles - }, - }, mounted () { - this.loading = true - const containerService = useContainerService(); - containerService.findAll() - .then((containers) => { - this.containers = containers - this.loading = false - }) + this.fetchContainers() + }, + methods: { + fetchContainers () { + this.loading = true + const containerService = useContainerService(); + containerService.findAll() + .then((containers) => { + this.containers = containers + this.loading = false + }) + } } } </script> diff --git a/dbrepo-ui/pages/database/[database_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/info.vue index 6e1e35aabb3b2c150f532edf8c8fea5af610088c..33d63b29a938d7cb9fa5015605846a9a42d85a17 100644 --- a/dbrepo-ui/pages/database/[database_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/info.vue @@ -163,13 +163,17 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +</script> <script> import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue' import Summary from '@/components/identifier/Summary.vue' import Select from '@/components/identifier/Select.vue' import UserBadge from '@/components/user/UserBadge.vue' import { sizeToHumanLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -197,7 +201,6 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -223,15 +226,9 @@ export default { } return this.database.identifier.publisher }, - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, - roles () { - return this.userStore.getRoles - }, identifiers () { if (!this.database) { return [] @@ -257,7 +254,7 @@ export default { return this.filteredIdentifiers[0] }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, pid () { return this.$route.query.pid diff --git a/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue index a57b439b216ae4743fd4bda292dc53e5f7e05a69..2c2e5ef120a044b4d2f551e0508fd842678aa7a9 100644 --- a/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue @@ -8,10 +8,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> -import Persist from '~/components/identifier/Persist.vue' -import { useUserStore } from '~/stores/user.js' -import { useCacheStore } from '~/stores/cache.js' +import Persist from '@/components/identifier/Persist.vue' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -39,17 +44,10 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, diff --git a/dbrepo-ui/pages/database/[database_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/persist/index.vue index df675d262e8e116b0c4252d74fe6878681388acb..a3581c0c828aec8b076151d306bd5a15ab69e16a 100644 --- a/dbrepo-ui/pages/database/[database_id]/persist/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/persist/index.vue @@ -8,10 +8,16 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> -import Persist from '~/components/identifier/Persist.vue' -import { useUserStore } from '~/stores/user.js' -import { useCacheStore } from '~/stores/cache.js' +import Persist from '@/components/identifier/Persist.vue' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -35,17 +41,10 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -56,10 +55,10 @@ export default { return false }, isOwner () { - if (!this.database || !this.user) { + if (!this.database || !this.userInfo) { return false } - return this.database.owner.username === this.user.username + return this.database.owner.id === this.userInfo.uid }, canCreateIdentifier () { if (!this.roles || this.hasIdentifier) { diff --git a/dbrepo-ui/pages/database/[database_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/settings.vue index d0fb517daebc37d65c3d18f1faed9f631a0ecff0..5b0aa2a4537a69cd943cf6528b12ee14f94e44b3 100644 --- a/dbrepo-ui/pages/database/[database_id]/settings.vue +++ b/dbrepo-ui/pages/database/[database_id]/settings.vue @@ -244,10 +244,16 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue' import EditAccess from '@/components/dialogs/EditAccess.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -323,7 +329,6 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -335,16 +340,7 @@ export default { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess - }, - token () { - return this.userStore.getToken - }, - roles () { - return this.userStore.getRoles - }, - user () { - return this.userStore.getUser + return this.cacheStore.getAccess }, uploadProgress () { return this.cacheStore.getUploadProgress diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue index f067fbadb4a190aff0843e289281971997426772..a9956278d100eae3c66f50ad0ca2b8e461a4588d 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue @@ -92,7 +92,6 @@ import SubsetToolbar from '@/components/subset/SubsetToolbar.vue' import Select from '@/components/identifier/Select.vue' import UserBadge from '@/components/user/UserBadge.vue' import { formatTimestampUTCLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -134,7 +133,6 @@ export default { downloadLoading: false, error: false, promises: [], - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -146,14 +144,11 @@ export default { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, subset () { return this.cacheStore.getSubset }, - user () { - return this.userStore.getUser - }, identifiers () { if (!this.database || !this.database.subsets || this.database.subsets.length === 0) { return [] diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue index b15ecb3292520979e550f68c7c16ef873638b124..0e1dac8c7e7fef9dfa3d4b50bad535af3f4ddfbc 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue @@ -8,10 +8,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> -import Persist from '~/components/identifier/Persist.vue' -import { useUserStore } from '~/stores/user.js' -import { useCacheStore } from '~/stores/cache.js' +import Persist from '@/components/identifier/Persist.vue' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -47,17 +52,10 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue index 07be66bc73911c9bd7580991ef2c71c6d36de5bc..cc0dbf495865c2276d15411b2d8f05bd69c5cefb 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue @@ -9,10 +9,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> -import Persist from '~/components/identifier/Persist.vue' -import { useUserStore } from '~/stores/user.js' -import { useCacheStore } from '~/stores/cache.js' +import Persist from '@/components/identifier/Persist.vue' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -47,19 +52,15 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, database () { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, canPersistQuery () { if (this.loadingQuery || !this.query) { diff --git a/dbrepo-ui/pages/database/[database_id]/subset/create.vue b/dbrepo-ui/pages/database/[database_id]/subset/create.vue index 0fb591f9f8307018da13539491089c68c2a9ba16..2ea1c5022a9932dab4a655f0ebd19a9d522e9ba1 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/create.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/create.vue @@ -6,8 +6,13 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> -import { useUserStore } from '@/stores/user.js' import Builder from '@/components/subset/Builder.vue' import {useCacheStore} from '@/stores/cache.js' @@ -36,22 +41,15 @@ export default { disabled: true } ], - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, database () { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, hasReadAccess () { if (!this.access) { diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue index 07747ed0cb50cdd950ee24dece9ff3c5faf6de06..ca120e89f737ffc602c80378cc2bd27bb15fed89 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue @@ -81,6 +81,7 @@ @close="pickVersion" /> </v-dialog> <v-dialog + v-if="loggedIn" v-model="addTupleDialog" persistent max-width="640"> @@ -91,6 +92,7 @@ @close="close" /> </v-dialog> <v-dialog + v-if="loggedIn" v-model="editTupleDialog" persistent max-width="640"> @@ -104,12 +106,18 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import TableHistory from '@/components/table/TableHistory.vue' import TimeDrift from '@/components/TimeDrift.vue' import TableToolbar from '@/components/table/TableToolbar.vue' import { formatTimestamp } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' import EditTuple from '@/components/dialogs/EditTuple.vue' import BlobDownload from '@/components/table/BlobDownload.vue' @@ -179,25 +187,18 @@ export default { ], headers: [], rows: [], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, database () { return this.cacheStore.getDatabase }, table () { return this.cacheStore.getTable }, - user () { - return this.userStore.getUser - }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, hasReadAccess () { if (!this.access) { @@ -230,10 +231,10 @@ export default { return this.version.substring(0, 10) + 'T' + this.version.substring(11, 19) + 'Z' }, canModify () { - if (!this.user || !this.access || !this.table) { + if (!this.userInfo || !this.access || !this.table) { return false } - if (this.access.type === 'write_own' && this.table.owner.id === this.user.id) { + if (this.access.type === 'write_own' && this.table.owner.id === this.userInfo.uid) { return true } return this.access.type === 'write_all' @@ -264,28 +265,28 @@ export default { return false } const userService = useUserService() - return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('insert-table-data') + return userService.hasWriteAccess(this.table, this.access, this.userInfo) && this.roles.includes('insert-table-data') }, canSelectTuples () { if (!this.roles) { return false } const userService = useUserService() - return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('insert-table-data') + return userService.hasWriteAccess(this.table, this.access, this.userInfo) && this.roles.includes('insert-table-data') }, canEditTuple () { if (!this.roles || this.selection === null || this.selection.length !== 1) { return false } const userService = useUserService() - return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('insert-table-data') + return userService.hasWriteAccess(this.table, this.access, this.userInfo) && this.roles.includes('insert-table-data') }, canDeleteTuple () { if (!this.roles || this.selection === null || this.selection.length < 1) { return false } const userService = useUserService() - return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('delete-table-data') + return userService.hasWriteAccess(this.table, this.access, this.userInfo) && this.roles.includes('delete-table-data') } }, watch: { diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue index 4cf0057ea429438ca08282a63ac27f182f80baf0..46eb7106fd8449b93e4403abc2b2866280e3403b 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue @@ -28,9 +28,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import TableImport from '@/components/table/TableImport.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -69,17 +75,10 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, table () { return this.cacheStore.getTable }, diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue index 916c72b85052ce54c71d0bfa3cbe67708d606b0a..ca295a558743451b37ea415691861c864b0bbdbc 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue @@ -118,12 +118,18 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import TableToolbar from '@/components/table/TableToolbar.vue' import Select from '@/components/identifier/Select.vue' import Summary from '@/components/identifier/Summary.vue' import UserBadge from '@/components/user/UserBadge.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -165,7 +171,6 @@ export default { loading: false, exchange: null, queue: null, - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -173,18 +178,12 @@ export default { pid () { return this.$route.query.pid }, - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, table () { return this.cacheStore.getTable }, - roles () { - return this.userStore.getRoles - }, canRead () { if (this.database && this.database.is_public) { return true @@ -204,19 +203,19 @@ export default { if (this.table.is_schema_public || this.table.is_public) { return true } - if (!this.user) { + if (!this.userInfo) { return false } - return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id + return this.hasReadAccess || this.table.owner.id === this.userInfo.uid || this.database.owner.id === this.userInfo.uid }, canWrite () { if (!this.table || !this.user || !this.access) { return false } - return (this.access.type === 'write_own' && this.table.owned_by === this.user.id) || this.access.type === 'write_all' + return (this.access.type === 'write_own' && this.table.owned_by === this.userInfo.uid) || this.access.type === 'write_all' }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, hasDescription () { return this.table && this.table.description @@ -237,10 +236,10 @@ export default { if (!this.identifiers) { return [] } - if (!this.user) { + if (!this.userInfo) { return this.identifiers.filter(i => i.status === 'published') } - return this.identifiers.filter(i => i.status === 'published' || i.owned_by === this.user.id) + return this.identifiers.filter(i => i.status === 'published' || i.owned_by === this.userInfo.uid) }, identifier () { if (this.pid) { diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue index 663b2a5550d7875e1da0c3ed86fab1f24f359350..0e82a2210beba8d7bce5865bf12234e2c43a279a 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue @@ -6,9 +6,14 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import Persist from '@/components/identifier/Persist.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -45,17 +50,10 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue index 250fedaa5d4676dc6c304d3d71aa9b3a23b21ffc..ef608876be1e974c216b80cbba5903d9d32c716e 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue @@ -13,7 +13,6 @@ <script> import Persist from '@/components/identifier/Persist.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -48,19 +47,15 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, database () { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, table () { return this.cacheStore.getTable diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue index 0c6a60e15b9c052656a61e9d71ec3fcd3d944cb2..4cbb8d37d1abfd1c88b5daebd579e403a5545705 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue @@ -120,9 +120,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import TableToolbar from '@/components/table/TableToolbar.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -168,14 +174,10 @@ export default { { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') }, ], dateColumns: [], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -183,7 +185,7 @@ export default { return this.cacheStore.getTable }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, hasReadAccess () { if (!this.access) { @@ -191,9 +193,6 @@ export default { } return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' }, - roles () { - return this.userStore.getRoles - }, canViewSchema () { if (this.error) { return false @@ -204,16 +203,16 @@ export default { if (this.table.is_schema_public) { return true } - if (!this.user) { + if (!this.userInfo) { return false } - return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id + return this.hasReadAccess || this.table.owner.id === this.userInfo.uid || this.database.owner.id === this.userInfo.uid }, primaryKeysColumns () { return this.table.constraints.primary_key.map(pk => pk.column.internal_name).join(', ') }, canAssignSemanticInformation () { - if (!this.user) { + if (!this.userInfo) { return false } if (this.roles.includes('modify-foreign-table-column-semantics')) { @@ -222,7 +221,7 @@ export default { if (!this.access) { return false } - return this.roles.includes('modify-table-column-semantics') && (this.access.type === 'write_all' || this.table.owner.username === this.user.username) + return this.roles.includes('modify-table-column-semantics') && (this.access.type === 'write_all' || this.table.owner.id === this.userInfo.uid) }, inputVariant () { const runtimeConfig = useRuntimeConfig() diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue index f9530711363fb38884ac05dcaba3d28e1b6ee82a..ddf319328ca039f0fbe1230117b6dc89eff31646 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue @@ -3,7 +3,7 @@ v-if="canUpdateTable"> <TableToolbar /> <v-window - v-if="user" + v-if="loggedIn" v-model="tab"> <v-window-item> <v-form @@ -114,9 +114,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import TableToolbar from '@/components/table/TableToolbar.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' import { max } from '@/utils' @@ -175,14 +181,10 @@ export default { { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') }, ], dateColumns: [], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -190,7 +192,7 @@ export default { return this.cacheStore.getTable }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, hasReadAccess () { if (!this.access) { @@ -198,9 +200,6 @@ export default { } return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' }, - roles () { - return this.userStore.getRoles - }, isChange () { if (!this.table) { return false @@ -211,26 +210,26 @@ export default { return this.table.is_schema_public !== this.modify.is_schema_public }, canUpdateTable () { - if (!this.roles || !this.user || !this.table) { + if (!this.roles || !this.userInfo || !this.table) { return false } - return this.roles.includes('update-table') && this.table.owner.id === this.user.id + return this.roles.includes('update-table') && this.table.owner.id === this.userInfo.uid }, canModifyVisibility () { - if (!this.roles || !this.user || !this.table) { + if (!this.roles || !this.userInfo || !this.table) { return false } - return this.roles.includes('update-table') && this.table.owner.id === this.user.id + return this.roles.includes('update-table') && this.table.owner.id === this.userInfo.uid }, canDropTable () { - if (!this.roles || !this.table || !this.user) { + if (!this.roles || !this.table || !this.userInfo) { return false } if (this.roles.includes('delete-foreign-table')) { return true } const tableService = useTableService() - return tableService.isOwner(this.table, this.user) && this.roles.includes('delete-table') && this.table.identifiers.length === 0 + return tableService.isOwner(this.table, this.userInfo) && this.roles.includes('delete-table') && this.table.identifiers.length === 0 }, inputVariant () { const runtimeConfig = useRuntimeConfig() diff --git a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue index df74cc6e7046e90f6e5e9844769a2e1e8f45e372..78bd1367513474e92efdc02efdeb93a537819729 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue @@ -219,10 +219,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import TableSchema from '@/components/table/TableSchema.vue' import { notEmpty } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -304,7 +309,6 @@ export default { loading: false, url: null, columns: [], - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -316,12 +320,6 @@ export default { this.tableCreate.is_schema_public = this.database.is_schema_public }, computed: { - user() { - return this.userStore.getUser - }, - roles() { - return this.userStore.getRoles - }, database() { return this.cacheStore.getDatabase }, diff --git a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue index c900ba31aa104dcc1ce5e3250dd0bb5a2b92f6fa..cf8de848de793631ee2064bd84ad41010a0a0f17 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue @@ -185,10 +185,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import TableSchema from '@/components/table/TableSchema.vue' import { notEmpty } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -247,7 +252,6 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -259,12 +263,6 @@ export default { const tableService = useTableService() return tableService.tableNameToInternalName(this.tableCreate.name) }, - roles () { - return this.userStore.getRoles - }, - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue index 54c54dad00d4764383c8d38e979870391680d563..0b0caa3c4fc82b414b91c48bed401ebc239d0351 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue @@ -34,10 +34,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +</script> <script> import TimeDrift from '@/components/TimeDrift.vue' import QueryResults from '@/components/subset/Results.vue' -import { useUserStore } from '@/stores/user.js' export default { components: { @@ -70,14 +75,10 @@ export default { disabled: true } ], - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -85,7 +86,7 @@ export default { return this.cacheStore.getView }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, hasReadAccess () { if (!this.access) { @@ -100,10 +101,10 @@ export default { if (this.view.is_public) { return true } - if (!this.user) { + if (!this.userInfo) { return false } - return this.view.owner.id === this.user.id || this.hasReadAccess + return this.view.owner.id === this.userInfo.uid || this.hasReadAccess }, }, mounted () { diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue index c9865a1b4abbefd3bd07361b7c6a5a5ff86b0834..0ed006c4bef542f4bf5f4f51eeb2fd760f004acc 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue @@ -59,13 +59,18 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +</script> <script> import ViewToolbar from '@/components/view/ViewToolbar.vue' import Summary from '@/components/identifier/Summary.vue' import Select from '@/components/identifier/Select.vue' import UserBadge from '@/components/user/UserBadge.vue' import { formatTimestampUTCLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -103,22 +108,15 @@ export default { } ], error: false, - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, database () { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, view () { return this.cacheStore.getView @@ -139,10 +137,10 @@ export default { if (!this.identifiers) { return [] } - if (!this.user) { + if (!this.userInfo) { return this.identifiers.filter(i => i.status === 'published') } - return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.user.id) + return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.userInfo.uid) }, identifier () { if (this.pid) { @@ -179,10 +177,10 @@ export default { if (this.view.is_public) { return true } - if (!this.user) { + if (!this.userInfo) { return false } - return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id + return this.hasReadAccess || this.view.owner.id === this.userInfo.uid || this.database.owner.id === this.userInfo.uid } }, methods: { diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue index 8c1f24c2a166150bd1dc3903dfa984c435815f9b..f528c86675b9d48f1d7d0a2a68cfd614b946442b 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue @@ -8,9 +8,14 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import Persist from '@/components/identifier/Persist.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -47,17 +52,10 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue index b76d076645e05ef7123215c578d20b489924d523..c5082c3be9bd10250df6be5957c620d813f73326 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue @@ -11,7 +11,6 @@ <script> import Persist from '@/components/identifier/Persist.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -45,14 +44,10 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, database () { return this.cacheStore.getDatabase }, @@ -63,7 +58,7 @@ export default { return this.database.views.filter(v => v.id === Number(this.$route.params.view_id))[0] }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, canPersistView () { if (!this.view) { diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue index 477654f656c9dbc5361315d323b8cc638add6ca9..5bd1ff5f9cf6019d6e36e4dd316ee9b43848a8d1 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue @@ -51,9 +51,14 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +</script> <script> import TableToolbar from '@/components/table/TableToolbar.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -95,14 +100,10 @@ export default { { value: 'is_null_allowed', title: this.$t('pages.table.subpages.schema.nullable.title') }, { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') }, ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -110,7 +111,7 @@ export default { return this.cacheStore.getView }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, hasReadAccess () { if (!this.access) { @@ -125,13 +126,10 @@ export default { if (this.view.is_schema_public) { return true } - if (!this.user) { + if (!this.userInfo) { return false } - return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id - }, - roles () { - return this.userStore.getRoles + return this.hasReadAccess || this.view.owner.id === this.userInfo.uid || this.database.owner.id === this.userInfo.uid }, inputVariant () { const runtimeConfig = useRuntimeConfig() diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue index 18d73d05768d1a45b36eed9a58ea7841235554b3..575e5b5f27d484a248ef7df71f9ff1c013baefc5 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue @@ -90,9 +90,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import ViewToolbar from '@/components/view/ViewToolbar.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -148,14 +154,10 @@ export default { { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') }, ], dateColumns: [], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -163,7 +165,7 @@ export default { return this.cacheStore.getView }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, hasReadAccess () { if (!this.access) { @@ -171,9 +173,6 @@ export default { } return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' }, - roles () { - return this.userStore.getRoles - }, isChange () { if (!this.view) { return false @@ -184,22 +183,22 @@ export default { return this.view.is_schema_public !== this.modify.is_schema_public }, canUpdateVisibility () { - if (!this.roles || !this.user || !this.view) { + if (!this.roles || !this.userInfo || !this.view) { return false } - return this.roles.includes('modify-view-visibility') && this.view.owner.id === this.user.id + return this.roles.includes('modify-view-visibility') && this.view.owner.id === this.userInfo.uid }, canDeleteView () { - if (!this.roles || !this.user || !this.view) { + if (!this.roles || !this.userInfo || !this.view) { return false } - return this.roles.includes('delete-database-view') && this.view.owner.id === this.user.id + return this.roles.includes('delete-database-view') && this.view.owner.id === this.userInfo.uid }, canViewSettings () { - if (!this.user || !this.view) { + if (!this.userInfo || !this.view) { return false } - return this.view.owner.id === this.user.id + return this.view.owner.id === this.userInfo.uid }, inputVariant () { const runtimeConfig = useRuntimeConfig() diff --git a/dbrepo-ui/pages/database/[database_id]/view/create.vue b/dbrepo-ui/pages/database/[database_id]/view/create.vue index 47b56cfbad81968d056d028cc48758d250efc612..b9d4a684d764de219014e7f840c422b98a2d4c75 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/create.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/create.vue @@ -6,9 +6,14 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import Builder from '@/components/subset/Builder.vue' -import { useUserStore } from '@/stores/user.js' export default { components: { @@ -34,17 +39,10 @@ export default { to: `/database/${this.$route.params.database_id}/view/create`, disabled: true } - ], - userStore: useUserStore() + ] } }, computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, canCreateView () { if (!this.roles) { return false diff --git a/dbrepo-ui/pages/index.vue b/dbrepo-ui/pages/index.vue index 1c30c25e5c7e9edfd52861ca568c492ce39f13a7..16cbbb283fd3a86e14dfb4865c4d61477ad2cf8e 100644 --- a/dbrepo-ui/pages/index.vue +++ b/dbrepo-ui/pages/index.vue @@ -27,10 +27,12 @@ </div> </template> +<script setup> +const { loggedIn, user, login, logout } = useOidcAuth() +</script> <script> import DatabaseList from '@/components/database/DatabaseList.vue' import DatabaseCreate from '@/components/database/DatabaseCreate.vue' -import { useUserStore } from '@/stores/user.js' export default { components: { @@ -41,13 +43,21 @@ export default { return { loading: true, dialog: null, - databases: [], - userStore: useUserStore() + databases: [] } }, computed: { + userInfo () { + if (!this.user) { + return null + } + return this.user.userInfo + }, roles () { - return this.userStore.getRoles + if (!this.user) { + return [] + } + return [] }, canCreateDatabase () { if (!this.roles) { @@ -57,17 +67,20 @@ export default { } }, mounted () { - this.loading = true - const databaseService = useDatabaseService(); - databaseService.findAll() - .then((databases) => { - this.databases = databases - this.loading = false - }) + this.fetchDatabases() }, methods: { closed () { this.dialog = false + }, + fetchDatabases () { + this.loading = true + const databaseService = useDatabaseService() + databaseService.findAll() + .then((databases) => { + this.databases = databases + this.loading = false + }) } } } diff --git a/dbrepo-ui/pages/login.vue b/dbrepo-ui/pages/login.vue deleted file mode 100644 index 532a221c4823cfd8be39fd53e94c34426311260a..0000000000000000000000000000000000000000 --- a/dbrepo-ui/pages/login.vue +++ /dev/null @@ -1,160 +0,0 @@ -<template> - <div> - <v-toolbar - v-if="!user" - variant="flat" - :title="$t('pages.login.name')"> - </v-toolbar> - <v-card - rounded="0" - variant="flat"> - <v-card-text> - <v-form - v-if="!user" - ref="form" - v-model="valid" - @submit.prevent="submit"> - <v-row - dense> - <v-col - md="8"> - <v-text-field - v-model="username" - autocomplete="off" - autofocus - required - name="username" - persistent-hint - :rules="[v => !!v || $t('validation.required')]" - :label="$t('pages.login.username.label')" - :hint="$t('pages.login.username.hint')"/> - </v-col> - </v-row> - <v-row - dense> - <v-col - md="8"> - <v-text-field - v-model="password" - autocomplete="off" - type="password" - required - name="password" - persistent-hint - :rules="[v => !!v || $t('validation.required')]" - :label="$t('pages.login.password.label')" - :hint="$t('pages.login.password.hint')"/> - </v-col> - </v-row> - <v-row> - <v-col - md="8"> - <v-btn - id="login" - class="mb-2" - :disabled="!valid" - color="primary" - variant="flat" - type="submit" - name="submit" - :loading="loading" - :text="$t('pages.login.submit.label')" - @click="login"/> - </v-col> - </v-row> - </v-form> - </v-card-text> - <v-card-actions> - <v-spacer/> - <v-btn - v-for="(link, i) in loginLinks" - :key="`li-${i}`" - variant="plain" - size="small" - :text="link.text" - :href="link.href"/> - </v-card-actions> - </v-card> - </div> -</template> - -<script> -import {useUserStore} from '@/stores/user.js' - -export default { - data() { - return { - loading: false, - valid: false, - username: null, - password: null, - userStore: useUserStore() - } - }, - computed: { - user() { - return this.userStore.getUser - }, - loginLinks() { - if (!this.$config.public.links) { - return [] - } - return Object.keys(this.$config.public.links).map(key => { - return this.$config.public.links[key] - }) - } - }, - methods: { - submit() { - this.$refs.form.validate() - }, - login() { - this.loading = true - const userService = useUserService() - userService.obtainToken(this.username, this.password) - .then((data) => { - const userId = userService.tokenToUserId(data.access_token) - userService.findOne(userId) - .then((user) => { - const toast = useToastInstance() - toast.success(this.$t('success.user.login', { username : user.username })) - switch (user.attributes.theme) { - case 'dark': - this.$vuetify.theme.global.name = 'tuwThemeDark' - break - case 'light': - this.$vuetify.theme.global.name = 'tuwThemeLight' - break - case 'light-contrast': - this.$vuetify.theme.global.name = 'tuwThemeLightContrast' - break - case 'dark-contrast': - this.$vuetify.theme.global.name = 'tuwThemeDarkContrast' - break - } - this.userStore.setUser(user) - this.$router.push('/database') - }) - .catch(({code}) => { - const toast = useToastInstance() - if (typeof code !== 'string') { - return - } - toast.error(this.$t(code)) - }) - }) - .catch(({code}) => { - this.loading = false - const toast = useToastInstance() - if (typeof code !== 'string') { - return - } - toast.error(this.$t(code)) - }) - .finally(() => { - this.loading = false - }) - } - } -} -</script> diff --git a/dbrepo-ui/pages/search.vue b/dbrepo-ui/pages/search.vue index 15475b212bc724e0e55d9f0765461990e574618e..ca80b1efda6c185a0e39323cb66c13d0a131e97b 100644 --- a/dbrepo-ui/pages/search.vue +++ b/dbrepo-ui/pages/search.vue @@ -63,9 +63,14 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import AdvancedSearch from '@/components/search/AdvancedSearch.vue' -import { useUserStore } from '@/stores/user.js' export default { components: { @@ -75,14 +80,10 @@ export default { return { results: [], type: 'database', - loading: false, - userStore: useUserStore() + loading: false } }, computed: { - roles () { - return this.userStore.getRoles - }, q () { if (!this.$route.query || !this.$route.query.q) { return null diff --git a/dbrepo-ui/pages/semantic/index.vue b/dbrepo-ui/pages/semantic/index.vue deleted file mode 100644 index db555b4c0d4778401e6988015b1064cc8bd0c82e..0000000000000000000000000000000000000000 --- a/dbrepo-ui/pages/semantic/index.vue +++ /dev/null @@ -1,194 +0,0 @@ -<template> - <div v-if="canListOntologies"> - <v-toolbar flat> - <v-toolbar-title> - {{ $t('pages.semantics.title') }} - </v-toolbar-title> - <v-spacer /> - <v-btn - v-if="canListOntologies" - to="/semantic/ontology" - variant="flat" - :text="ontologies.length + ' ' + $t('toolbars.semantic.ontologies.text')" - color="secondary" /> - <template v-slot:extension> - <v-tabs - v-model="tab" - color="primary"> - <v-tab> - {{ $t('toolbars.semantic.ontologies.concepts') }} - </v-tab> - <v-tab> - {{ $t('toolbars.semantic.ontologies.units') }} - </v-tab> - </v-tabs> - </template> - </v-toolbar> - <v-card flat> - <v-card-text> - <v-data-table - :headers="headers" - :items="rows" - :options.sync="options" - :server-items-length="total" - :footer-props="footerProps" - :items-per-page-options="footerProps.itemsPerPageOptions"> - <template v-slot:item.uri="{ item }"> - <a :href="item.uri" - target="_blank"> - {{ item.uri }} - </a> - </template> - <template v-slot:item.action="{ item }"> - <v-btn - small - :disabled="disabled(item)" - :text="$t('pages.semantics.usages.text')" - @click="view(item)" /> - </template> - </v-data-table> - </v-card-text> - </v-card> - <v-dialog - v-model="viewSemanticEntityDialog" - max-width="640"> - <ViewSemanticEntity - :mode="mode" - :entity="entity" - @close="close" /> - </v-dialog> - <v-breadcrumbs - :items="items" - class="pa-0 mt-2" /> - </div> -</template> - -<script> -import ViewSemanticEntity from '@/components/dialogs/ViewSemanticEntity.vue' -import { useUserStore } from '@/stores/user.js' -import { useCacheStore } from '@/stores/cache.js' - -export default { - components: { - ViewSemanticEntity - }, - data () { - return { - loadingConcepts: false, - loadingUnits: false, - entity: null, - viewSemanticEntityDialog: false, - headers: [ - { text: 'URI', value: 'uri' }, - { text: 'Name', value: 'name' }, - { text: 'Description', value: 'description' }, - { text: 'Usages', value: 'usages' }, - { text: null, value: 'action' } - ], - options: { - page: 1, - itemsPerPage: 10 - }, - total: -1, - footerProps: { - itemsPerPageOptions: [10, 25, 50, 100] - }, - tab: 0, - tabs: [ - 'concepts', 'units' - ], - concepts: [], - units: [], - createOntologyDialog: false, - items: [ - { - title: `${this.$t('navigation.semantics')}`, - to: '/semantic' - } - ], - userStore: useUserStore(), - cacheStore: useCacheStore() - } - }, - computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, - ontologies () { - return this.cacheStore.getOntologies - }, - rows () { - return this.tab === 0 ? this.concepts : this.units - }, - mode () { - return this.tab === 0 ? 'concept' : 'unit' - }, - canListOntologies () { - if (!this.roles) { - return false - } - return this.roles.includes('list-ontologies') - } - }, - mounted () { - this.loadUnits() - this.loadConcepts() - }, - methods: { - loadConcepts () { - this.loadingConcepts = true - const conceptService = useConceptService() - conceptService.findAll() - .then((concepts) => { - concepts = concepts.map((column) => { - column.usages = column.columns.length - return column - }) - this.concepts = concepts - }) - .catch(() => { - this.loadingConcepts = false - }) - .finally(() => { - this.loadingConcepts = false - }) - }, - loadUnits () { - this.loadingUnits = true - const unitService = useUnitService() - unitService.findAll() - .then((units) => { - units = units.map((unit) => { - unit.usages = unit.columns.length - return unit - }) - this.units = units - }) - .catch(() => { - this.loadingUnits = false - }) - .finally(() => { - this.loadingUnits = false - }) - }, - disabled (item) { - return !item.usages || this.usages === 0 - }, - view (entity) { - this.entity = entity - this.viewSemanticEntityDialog = true - }, - close (event) { - if (this.mode === 'unit') { - this.loadUnits() - } else if (this.mode === 'concept') { - this.loadConcepts() - } - this.viewSemanticEntityDialog = false - } - } -} -</script> diff --git a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue b/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue deleted file mode 100644 index 14749460c931c70c8430a28e51a7aa3c13d26ed1..0000000000000000000000000000000000000000 --- a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue +++ /dev/null @@ -1,273 +0,0 @@ -<template> - <div - v-if="canListOntologies"> - <v-toolbar flat> - <v-toolbar-title> - <v-btn - id="back-btn" - plain - class="mr-2" - to="/semantic/ontology"> - <v-icon left>mdi-arrow-left</v-icon> - </v-btn> - </v-toolbar-title> - <v-toolbar-title> - <v-skeleton-loader - v-if="loading" - type="text" - class="skeleton-small" /> - <span v-if="!loading"> - Ontology - <a - v-if="ontology" - :href="ontology.uri" - target="_blank"> - {{ ontology.uri }} - </a> - </span> - </v-toolbar-title> - <v-spacer /> - <v-toolbar-title> - <v-btn - v-if="canDeleteOntology" - :loading="loadingDelete" - color="error" - @click="deleteOntology"> - Delete Ontology - </v-btn> - </v-toolbar-title> - </v-toolbar> - <v-form ref="form" v-model="valid" autocomplete="off" @submit.prevent="submit"> - <v-card v-if="ontology" variant="flat"> - <v-card-text> - <v-row dense> - <v-col cols="6"> - <v-text-field - id="prefix" - v-model="ontologyChangeDto.prefix" - name="prefix" - label="Prefix *" - hint="Only lowercase alphanumeric letters, max. 8" - autofocus - :rules="[ - v => notEmpty(v) || $t('validation.required'), - v => validPrefix(v) || $t('validation.prefix.pattern'), - v => validPrefixLength(v,1,8) || $t('validation.prefix.length'), - v => validPrefixNotExists(v) || $t('validation.prefix.exists') - ]" - required /> - </v-col> - </v-row> - <v-row dense> - <v-col cols="6"> - <v-text-field - id="uri" - v-model="ontologyChangeDto.uri" - name="uri" - label="URI *" - :rules="[ - v => notEmpty(v) || $t('validation.required'), - v => validUri(v) || $t('validation.uri.pattern'), - v => validUriNotExists(v) || $t('validation.uri.exists') - ]" - required /> - </v-col> - </v-row> - <v-row dense> - <v-col cols="6"> - <v-text-field - id="sparql-endpoint" - v-model="ontologyChangeDto.sparql_endpoint" - name="sparql-endpoint" - label="SPARQL Endpoint" - :rules="[ - v => validUriOptional(v) || $t('validation.uri.pattern') - ]" /> - </v-col> - </v-row> - </v-card-text> - <v-card-actions> - <v-btn - id="createDB" - class="mb-2 ml-2" - :disabled="!valid || loading" - color="primary" - type="submit" - :loading="loading" - @click="save"> - Update - </v-btn> - </v-card-actions> - </v-card> - </v-form> - <v-breadcrumbs :items="items" class="pa-0 mt-2" /> - </div> -</template> - -<script> -import { notEmpty } from '@/utils' -import { useUserStore } from '@/stores/user.js' -import { useCacheStore } from '@/stores/cache.js' - -export default { - data () { - return { - loading: false, - loadingDelete: false, - ontology: null, - ontologyChangeDto: { - uri: null, - prefix: null, - sparql_endpoint: null - }, - valid: false, - createOntologyDialog: false, - items: [ - { text: `${this.$t('layout.semantics')}`, to: '/semantic', activeClass: '' }, - { text: `${this.$t('layout.ontologies')}`, to: '/semantic/ontology', activeClass: '' }, - { text: `${this.$route.params.ontology_id}`, to: `/semantic/ontology/${this.$route.params.ontology_id}`, activeClass: '' } - ], - userStore: useUserStore(), - cacheStore: useCacheStore() - } - }, - computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, - ontologies () { - return this.cacheStore.getOntologies - }, - canListOntologies () { - if (!this.roles) { - return false - } - return this.roles.includes('list-ontologies') - }, - canDeleteOntology () { - if (!this.roles) { - return false - } - return this.roles.includes('delete-ontology') - } - }, - mounted () { - this.loadOntology() - }, - methods: { - loadOntology () { - this.loading = true - const ontologyService = useOntologyService() - ontologyService.findOne(this.$route.params.ontology_id) - .then((ontology) => { - this.ontology = ontology - this.ontologyChangeDto = Object.assign({}, ontology) - }) - .catch(() => { - this.loading = false - }) - .finally(() => { - this.loading = false - }) - }, - deleteOntology () { - this.loadingDelete = true - const ontologyService = useOntologyService() - ontologyService.remove(this.$route.params.ontology_id) - .then(async () => { - // await this.$store.dispatch('reloadOntologies') - await this.$router.push('/semantic/ontology') - }) - .catch(() => { - this.loadingDelete = false - }) - .finally(() => { - this.loadingDelete = false - }) - }, - save () { - this.loading = true - const payload = { - uri: this.ontologyChangeDto.uri, - prefix: this.ontologyChangeDto.prefix, - sparql_endpoint: this.ontologyChangeDto.sparql_endpoint - } - const ontologyService = useOntologyService() - ontologyService.update(this.$route.params.ontology_id, payload) - .then(() => { - this.loadOntology() - // this.$store.dispatch('reloadOntologies') - const toast = useToastInstance() - toast.success('Successfully update ontology!') - }) - .catch(() => { - this.loading = false - }) - .finally(() => { - this.loading = false - }) - }, - validPrefix (str) { - if (!str) { - return false - } - return str.match(/[a-z0-9]+/g) - }, - validPrefixLength (str, min, max) { - if (!str) { - return false - } - return str.length > min && str.length <= max - }, - validPrefixNotExists (str) { - const ontologies = this.ontologies.filter(o => o.prefix === str) - if (ontologies && ontologies.length !== 0) { - /* same prefix is fine for the same ontology, but not for others */ - return ontologies[0].id === this.ontology.id - } - return !this.ontologies.map(o => o.prefix).includes(str) - }, - validUriNotExists (str) { - const ontologies = this.ontologies.filter(o => o.uri === str) - if (ontologies && ontologies.length !== 0) { - /* same uri is fine for the same ontology, but not for others */ - return ontologies[0].id === this.ontology.id - } - return !this.ontologies.map(o => o.uri).includes(str) - }, - validUriOptional (str) { - if (!str) { - return true - } - return this.validUri(str) - }, - validUri (str) { - if (!str) { - return false - } - return str.match(/^https?:\/\//g) - }, - close (event) { - if (event.success) { - // this.$store.dispatch('reloadOntologies') - } - this.createOntologyDialog = false - }, - submit () { - this.$refs.form.validate() - }, - notEmpty - } -} -</script> -<style> -.skeleton-medium > div { - width: 200px !important; -} -.skeleton-xsmall > div { - width: 50px !important; -} -</style> diff --git a/dbrepo-ui/pages/semantic/ontology/index.vue b/dbrepo-ui/pages/semantic/ontology/index.vue deleted file mode 100644 index 36898d90739c2d219e9f9987c02527e2409a676f..0000000000000000000000000000000000000000 --- a/dbrepo-ui/pages/semantic/ontology/index.vue +++ /dev/null @@ -1,96 +0,0 @@ -<template> - <div v-if="canListOntologies"> - <v-toolbar flat> - <v-btn - variant="plain" - size="small" - icon="mdi-arrow-left" - to="/semantic" /> - <v-toolbar-title> - {{ ontologies.length + ' ' + $t('toolbars.semantic.ontologies.title') }} - </v-toolbar-title> - <v-spacer /> - <v-btn - v-if="canCreateOntology" - color="secondary" - variant="flat" - name="create-ontology" - prepend-icon="mdi-plus" - :text="$t('toolbars.semantic.ontology.text')" - @click.stop="createOntologyDialog = true" /> - </v-toolbar> - <OntologiesList /> - <v-dialog - v-model="createOntologyDialog" - persistent - max-width="640"> - <CreateOntology ref="ont" @close="close" /> - </v-dialog> - <v-breadcrumbs :items="items" class="pa-0 mt-2" /> - </div> -</template> - -<script> -import OntologiesList from '@/components/OntologiesList.vue' -import CreateOntology from '@/components/dialogs/CreateOntology.vue' -import { useUserStore } from '@/stores/user.js' -import { useCacheStore } from '@/stores/cache.js' - -export default { - components: { - OntologiesList, - CreateOntology - }, - data () { - return { - createOntologyDialog: false, - items: [ - { - title: `${this.$t('navigation.semantics')}`, - to: '/semantic' - }, - { - title: `${this.$t('navigation.ontologies')}`, - to: '/semantic/ontology' - } - ], - userStore: useUserStore(), - cacheStore: useCacheStore() - } - }, - computed: { - token () { - return this.userStore.getToken - }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, - ontologies () { - return this.cacheStore.getOntologies - }, - canListOntologies () { - if (!this.roles) { - return false - } - return this.roles.includes('list-ontologies') - }, - canCreateOntology () { - if (!this.roles) { - return false - } - return this.roles.includes('create-ontology') - } - }, - methods: { - close (event) { - if (event.success) { - // this.$store.dispatch('reloadOntologies') - } - this.createOntologyDialog = false - } - } -} -</script> diff --git a/dbrepo-ui/pages/signup.vue b/dbrepo-ui/pages/signup.vue index 54c00602256c7815d8aff0b255214e66836bc727..19f781572a73f9be766bcb3a91c8c4fd2bb6c9e5 100644 --- a/dbrepo-ui/pages/signup.vue +++ b/dbrepo-ui/pages/signup.vue @@ -1,5 +1,6 @@ <template> - <div> + <div + v-if="!loggedIn"> <v-toolbar :title="$t('pages.signup.name')" flat /> @@ -91,6 +92,9 @@ </div> </template> +<script setup> +const { loggedIn, user, login, logout } = useOidcAuth() +</script> <script> export default { data () { diff --git a/dbrepo-ui/pages/user/authentication.vue b/dbrepo-ui/pages/user/authentication.vue index 3a43421a709560b3e841760620321f0c640275f9..03c40e5d82f9ac2a787a663eab1e6b7fb2f89699 100644 --- a/dbrepo-ui/pages/user/authentication.vue +++ b/dbrepo-ui/pages/user/authentication.vue @@ -1,5 +1,6 @@ <template> - <div> + <div + v-if="loggedIn"> <UserToolbar /> <v-window v-model="tab"> <v-window-item> @@ -10,8 +11,7 @@ rounded="0"> <v-card-text> <v-form - v-model="valid2" - @submit.prevent="submit"> + v-model="valid2"> <v-row dense> <v-col md="6"> <v-text-field @@ -60,9 +60,15 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import UserToolbar from '@/components/user/UserToolbar.vue' -import { useUserStore } from '@/stores/user.js' export default { components: { @@ -87,14 +93,10 @@ export default { ], email: null, password: null, - password2: null, - userStore: useUserStore() + password2: null } }, computed: { - user () { - return this.userStore.getUser - }, inputVariant () { const runtimeConfig = useRuntimeConfig() return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.input.contrast : runtimeConfig.public.variant.input.normal @@ -104,15 +106,11 @@ export default { return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal } }, - mounted () { - }, methods: { - submit () { - }, changePassword () { this.loadingUpdate = true const userService = useUserService() - userService.updatePassword(this.user.id, {'password': this.password}) + userService.updatePassword(this.userInfo.uid, {'password': this.password}) .then(() => { const toast = useToastInstance() toast.success(this.$t('success.user.password')) diff --git a/dbrepo-ui/pages/user/developer.vue b/dbrepo-ui/pages/user/developer.vue deleted file mode 100644 index de52a490aff050b7a7a92c1870645301bf68b9d3..0000000000000000000000000000000000000000 --- a/dbrepo-ui/pages/user/developer.vue +++ /dev/null @@ -1,230 +0,0 @@ -<template> - <div> - <UserToolbar /> - <v-window - v-model="tab"> - <v-window-item> - <v-card - v-if="canHandleMessages" - :title="$t('pages.settings.subpages.developer.maintenance.title')" - rounded="0" - variant="flat"> - <v-data-table - :headers="headers" - :items="messages" - :loading="loadingMessages" - :items-per-page="10"> - <template v-slot:item.action="{ item }"> - <v-btn - size="x-small" - variant="flat" - :text="$t('pages.settings.subpages.developer.maintenance.modify.text')" - @click="modifyMessage(item)" /> - </template> - </v-data-table> - <v-card-text> - <v-btn - size="small" - variant="flat" - :text="$t('pages.settings.subpages.developer.maintenance.add.text')" - :disabled="!canCreateMessage" - @click="createMessage" /> - </v-card-text> - </v-card> - <v-divider - v-if="canHandleMessages" /> - <v-card - :title="$t('pages.settings.subpages.developer.token.title')" - :subtitle="$t('pages.settings.subpages.developer.token.subtitle')" - variant="flat" - rounded="0"> - <v-card-text> - <v-row dense> - <v-col xl="4"> - <v-text-field - v-model="accessTokenField" - disabled - :variant="inputVariant" - :label="$t('pages.settings.subpages.developer.token.access.label')" /> - </v-col> - <v-col xl="2"> - <v-text-field - v-model="tokenExpiry" - disabled - :variant="inputVariant" - :label="expiryLabel(token)" /> - </v-col> - </v-row> - <v-row dense> - <v-col xl="4"> - <v-text-field - v-model="refreshTokenField" - disabled - :variant="inputVariant" - :label="$t('pages.settings.subpages.developer.token.refresh.label')" /> - </v-col> - <v-col xl="2"> - <v-text-field - v-model="refreshTokenExpiry" - disabled - :variant="inputVariant" - :label="expiryLabel(refreshToken)" /> - </v-col> - </v-row> - </v-card-text> - </v-card> - </v-window-item> - </v-window> - <v-breadcrumbs :items="items" class="pa-0 mt-2" /> - <v-dialog - v-model="dialog" - persistent - max-width="640"> - <EditMaintenanceMessage - :id="messageId" - @close-dialog="closeDialog" /> - </v-dialog> - </div> -</template> - -<script> -import UserToolbar from '@/components/user/UserToolbar.vue' -import EditMaintenanceMessage from '@/components/dialogs/EditMaintenanceMessage.vue' -import { formatTimestampUTCLabel, isActiveMessage, timestampsToHumanDifference } from '@/utils' -import { useUserStore } from '@/stores/user.js' -import { useCacheStore } from '@/stores/cache.js' - -export default { - components: { - UserToolbar, - EditMaintenanceMessage - }, - data () { - return { - tab: 0, - accessTokenField: null, - refreshTokenField: null, - headers: [ - { title: this.$t('pages.settings.subpages.developer.maintenance.active'), value: 'active' }, - { title: this.$t('pages.settings.subpages.developer.maintenance.type'), value: 'type' }, - { title: this.$t('pages.settings.subpages.developer.maintenance.message'), value: 'message' }, - { title: this.$t('pages.settings.subpages.developer.maintenance.action'), value: 'action' } - ], - items: [ - { - title: this.$t('navigation.user'), - to: '/user' - }, - { - title: this.$t('toolbars.user.developer'), - to: `/user/developer`, - disabled: true - } - ], - messages: [], - loadingMessages: false, - dialog: false, - messageId: null, - userStore: useUserStore(), - cacheStore: useCacheStore() - } - }, - computed: { - token () { - return this.userStore.getToken - }, - tokenExpiry () { - if (!this.token) { - return null - } - const authenticationService = useAuthenticationService() - return formatTimestampUTCLabel(authenticationService.tokenToExpiryDate(this.token)) - }, - refreshToken () { - return this.userStore.getRefreshToken - }, - refreshTokenExpiry () { - if (!this.refreshToken) { - return null - } - const authenticationService = useAuthenticationService() - return formatTimestampUTCLabel(authenticationService.tokenToExpiryDate(this.refreshToken)) - }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, - canCreateMessage () { - if (!this.roles) { - return false - } - return this.roles.includes('create-maintenance-message') - }, - canModifyMessage () { - if (!this.roles) { - return false - } - return this.roles.includes('modify-maintenance-message') - }, - canHandleMessages () { - return this.canCreateMessage || this.canModifyMessage - }, - inputVariant () { - const runtimeConfig = useRuntimeConfig() - return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.input.contrast : runtimeConfig.public.variant.input.normal - }, - buttonVariant () { - const runtimeConfig = useRuntimeConfig() - return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal - } - }, - mounted () { - this.loadMessages() - if (!this.token || !this.refreshToken) { - return - } - this.accessTokenField = this.token - this.refreshTokenField = this.refreshToken - }, - methods: { - submit () { - }, - modifyMessage (message) { - this.messageId = message.id - this.dialog = true - }, - createMessage () { - this.messageId = null - this.dialog = true - }, - expiryLabel (token) { - const authenticationService = useAuthenticationService() - return this.$t('pages.settings.subpages.developer.token.expiry') + ' ' + timestampsToHumanDifference(Date.now(), authenticationService.tokenToExpiryDate(token)) - }, - loadMessages () { - const messageService = useMessageService() - messageService.findAll() - .then((messages) => { - this.messages = messages.map((message) => { - message.active = isActiveMessage(message) ? '● true' : 'false' - return message - }) - }) - .catch(() => { - this.loadingMessages = false - }) - .finally(() => { - this.loadingMessages = false - }) - }, - closeDialog (event) { - if (event.success) { - this.cacheStore.reloadMessages() - } - this.dialog = false - } - } -} -</script> diff --git a/dbrepo-ui/pages/user/index.vue b/dbrepo-ui/pages/user/index.vue index accae861052044324dc08ae48f6858e643172c5f..1d76677059d6dbc26ad41ac48bfaf88d3ef6acb2 100644 --- a/dbrepo-ui/pages/user/index.vue +++ b/dbrepo-ui/pages/user/index.vue @@ -2,25 +2,13 @@ <div /> </template> +<script setup> +const { loggedIn, user, login, logout } = useOidcAuth() +</script> <script> -import { useUserStore } from '@/stores/user.js' - export default { - data () { - return { - userStore: useUserStore() - } - }, - computed: { - token () { - return this.userStore.getToken - }, - user () { - return this.userStore.getUser - } - }, mounted () { - if (!this.user) { + if (!this.loggedIn) { return } this.$router.push('/user/info') diff --git a/dbrepo-ui/pages/user/info.vue b/dbrepo-ui/pages/user/info.vue index 9b94dde4dad312bb648e992efbc38120798bf869..58e265b59ffe78ce7627c572df60e91b67e24df3 100644 --- a/dbrepo-ui/pages/user/info.vue +++ b/dbrepo-ui/pages/user/info.vue @@ -1,7 +1,8 @@ <template> <div> <UserToolbar /> - <v-window v-model="tab"> + <v-window + v-model="tab"> <v-window-item> <v-form v-model="valid1" @submit.prevent="submit"> <v-card @@ -122,9 +123,16 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const { loggedIn, user, login, logout } = useOidcAuth() +const userInfo = ref(loggedIn ? user.value?.userInfo : null) +const roles = ref(loggedIn ? user.value?.claims?.realm_access?.roles : []) +</script> <script> import UserToolbar from '@/components/user/UserToolbar.vue' -import { useUserStore } from '@/stores/user.js' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -169,18 +177,12 @@ export default { disabled: true } ], - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, locale () { - return this.userStore.getLocale + return this.cacheStore.getLocale }, canModifyTheme () { return this.roles.includes('modify-user-theme') @@ -214,14 +216,13 @@ export default { language: this.model.language, } const userService = useUserService() - userService.update(this.user.id, payload) + userService.update(this.userInfo.id, payload) .then((user) => { console.info('Updated user information') const toast = useToastInstance() toast.success(this.$t('success.user.info')) - this.userStore.setUser(user) /* language */ - this.userStore.setLocale(this.model.language) + this.cacheStore.setLocale(this.model.language) this.$i18n.locale = this.locale /* theme */ switch (this.model.theme) { @@ -251,14 +252,14 @@ export default { return } this.model = { - id: this.user.id, - username: this.user.username, - firstname: this.user.given_name, - lastname: this.user.family_name, - orcid: this.user.attributes.orcid, - affiliation: this.user.attributes.affiliation, - theme: this.user.attributes.theme, - language: this.user.attributes.language + id: this.userInfo.id, + username: this.userInfo.username, + firstname: this.userInfo.given_name, + lastname: this.userInfo.family_name, + orcid: this.userInfo.attributes.orcid, + affiliation: this.userInfo.attributes.affiliation, + theme: this.userInfo.attributes.theme, + language: this.userInfo.attributes.language } }, retrieve () { diff --git a/dbrepo-ui/stores/cache.js b/dbrepo-ui/stores/cache.js index 41059ba7270d93717998ac5b245e37d6ed239ee3..4582dce19945e18b962b1ee5a5f4da7d368ed80b 100644 --- a/dbrepo-ui/stores/cache.js +++ b/dbrepo-ui/stores/cache.js @@ -7,7 +7,9 @@ export const useCacheStore = defineStore('cache', { database: null, table: null, view: null, + access: null, subset: null, + locale: null, ontologies: [], messages: [], uploadProgress: null @@ -17,7 +19,9 @@ export const useCacheStore = defineStore('cache', { getDatabase: (state) => state.database, getTable: (state) => state.table, getView: (state) => state.view, + getAccess: (state) => state.access, getSubset: (state) => state.subset, + getLocale: (state) => state.locale, getOntologies: (state) => state.ontologies, getMessages: (state) => state.messages, getUploadProgress: (state) => state.uploadProgress, @@ -32,9 +36,15 @@ export const useCacheStore = defineStore('cache', { setView(view) { this.view = view }, + setAccess(access) { + this.access = access + }, setSubset(subset) { this.subset = subset }, + setLocale(locale) { + this.locale = locale + }, setOntologies(ontologies) { this.ontologies = ontologies }, @@ -117,6 +127,16 @@ export const useCacheStore = defineStore('cache', { tableService.findOne(databaseId, tableId) .then(table => this.table = table) }, + setRouteAccess(databaseId, userId) { + if (!databaseId || !userId) { + this.access = null + console.error('Cannot set route access: missing database id', databaseId, 'or user id', userId) + return + } + const accessService = useAccessService() + accessService.findOne(databaseId, userId) + .then(access => this.access = access) + }, setRouteView(databaseId, viewId) { if (!databaseId || !viewId) { this.view = null diff --git a/dbrepo-ui/stores/user.js b/dbrepo-ui/stores/user.js deleted file mode 100644 index 522ce02a06ed1c695897d92a73c2682d791b499a..0000000000000000000000000000000000000000 --- a/dbrepo-ui/stores/user.js +++ /dev/null @@ -1,60 +0,0 @@ -import {defineStore} from 'pinia' - -export const useUserStore = defineStore('user', { - persist: true, - state: () => { - return { - /** @type String */ - token: null, - /** @type String */ - refreshToken: null, - roles: [], - user: null, - access: null, - locale: null - } - }, - getters: { - getToken: (state) => state.token, - getRefreshToken: (state) => state.refreshToken, - getRoles: (state) => state.roles, - getUser: (state) => state.user, - getAccess: (state) => state.access, - getLocale: (state) => state.locale - }, - actions: { - setToken(token) { - this.token = token - }, - setRefreshToken(refreshToken) { - this.refreshToken = refreshToken - }, - setRoles(roles) { - this.roles = roles - }, - setUser(user) { - this.user = user - }, - setAccess(access) { - this.access = access - }, - setLocale (locale) { - this.locale = locale - }, - logout() { - this.token = null - this.refreshToken = null - this.roles = [] - this.user = null - this.access = null - }, - setRouteAccess(databaseId) { - if (!databaseId || !this.user || !this.user.id) { - return - } - const accessService = useAccessService() - accessService.findOne(databaseId, this.user.id) - .then(access => this.access = access) - } - } -}) diff --git a/docker-compose.yml b/docker-compose.yml index ad1dacb6b7b19a8fb4ee3303968cd684bef75967..efcc9a76ccf71be7b78c49cd842d66e7f868deca 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -329,8 +329,13 @@ services: network: host environment: NUXT_PUBLIC_API_CLIENT: "${BASE_URL:-http://localhost}" - NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://localhost}" + NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://gateway-service}" NUXT_PUBLIC_UPLOAD_CLIENT: "${BASE_URL:-http://localhost}/api/upload/files" + NUXT_OIDC_PROVIDERS_KEYCLOAK_BASE_URL: "${BASE_URL:-http://localhost:8080}/realms/dbrepo" + NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_ID: "${AUTH_SERVICE_CLIENT:-dbrepo-client}" + NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_SECRET: "${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}" + NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI: "${BASE_URL:-http://localhost}/auth/keycloak/callback" + NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI: "${BASE_URL:-http://localhost}" depends_on: dbrepo-search-service: condition: service_healthy @@ -341,6 +346,8 @@ services: interval: 10s timeout: 5s retries: 12 + extra_hosts: + - "localhost:host-gateway" logging: driver: json-file