a6287fc06d
* init db migration * WIP store view * create service call * WIP insertion * insert sort of works * moving code arounmd * creation tests * avoid duplicate entries * fixes from main * basic group retrieval works * group filtering works * WIP view listing * filter by acl * fixes + WIP single group retrieval * wip pivot * more pivot query fixes * tests fixed after pivot * views list tests * fixing test command * business plan only checks * more tests for coverage * .dts import fix * cli fix * anutha one * auth policy tests for business plan access * WIP saved views panel base * BE listing adjustments * WIP group rendering * group render done * WIP post create cache updates * listing fine? * my vs theirs * auto open * minor fixes * click load omg * nicely loading views * type fix * less spammy loading * another type fix: * more lint fix * test fix * codecov disable * moar coverage * fix sidebar flashin * more test coverage * more test cvoverage * minor adfjustments * adj * saved view wipe fixes * CSR viewer * more improvements * extra feature flag checks * lint fix * feature flags fix * more test fixes
88 lines
2.8 KiB
TypeScript
88 lines
2.8 KiB
TypeScript
import type { Optional } from '@speckle/shared'
|
|
|
|
import { useApolloClientFromNuxt } from '~/lib/common/composables/graphql'
|
|
import {
|
|
convertThrowIntoFetchResult,
|
|
errorsToAuthResult
|
|
} from '~/lib/common/helpers/graphql'
|
|
import { projectAccessCheckQuery } from '~/lib/projects/graphql/queries'
|
|
import { WorkspaceSsoErrorCodes } from '~/lib/workspaces/helpers/types'
|
|
import { useSetActiveWorkspace } from '~/lib/user/composables/activeWorkspace'
|
|
|
|
/**
|
|
* Used in project page to validate that project ID refers to a valid project and redirects to 404 if not
|
|
*/
|
|
export default defineNuxtRouteMiddleware(async (to, from) => {
|
|
const projectId = to.params.id as string
|
|
|
|
// Check if embed token is present in URL
|
|
const embedToken = to.query.embedToken as Optional<string>
|
|
|
|
// Skip middleware validation for embed tokens - let the auth system handle them
|
|
if (embedToken) {
|
|
return
|
|
}
|
|
|
|
const client = useApolloClientFromNuxt()
|
|
const { setActiveWorkspace } = useSetActiveWorkspace()
|
|
const { isLoggedIn } = useActiveUser()
|
|
const isWorkspacesEnabled = useIsWorkspacesEnabled()
|
|
|
|
const isInPlaceNavigation = checkIfIsInPlaceNavigation(to, from)
|
|
|
|
const { data, errors } = await client
|
|
.query({
|
|
query: projectAccessCheckQuery,
|
|
variables: { id: projectId },
|
|
context: {
|
|
skipLoggingErrors: true
|
|
},
|
|
fetchPolicy: isInPlaceNavigation ? 'cache-first' : 'network-only'
|
|
})
|
|
.catch(convertThrowIntoFetchResult)
|
|
|
|
// we may not even get to the authResult because of project() resolver errors, hence the mapping
|
|
// from errors to authResult
|
|
const authResult = data?.project.permissions.canRead || errorsToAuthResult({ errors })
|
|
if (!authResult.authorized) {
|
|
switch (authResult.code) {
|
|
case WorkspaceSsoErrorCodes.SESSION_MISSING_OR_EXPIRED: {
|
|
// Redirect to the SSO error page
|
|
const payload = authResult.payload as Optional<{
|
|
workspaceSlug: string
|
|
}>
|
|
const workspaceSlug = payload?.workspaceSlug
|
|
if (workspaceSlug) {
|
|
return navigateTo(`/workspaces/${workspaceSlug}/sso/session-error`)
|
|
}
|
|
}
|
|
// eslint-disable-next-line no-fallthrough
|
|
case 'FORBIDDEN':
|
|
return abortNavigation(
|
|
createError({
|
|
statusCode: 403,
|
|
message: authResult.message
|
|
})
|
|
)
|
|
case 'STREAM_NOT_FOUND':
|
|
return abortNavigation(
|
|
createError({
|
|
statusCode: 404,
|
|
message: authResult.message
|
|
})
|
|
)
|
|
default:
|
|
return abortNavigation(
|
|
createError({
|
|
statusCode: 500,
|
|
message: authResult.message
|
|
})
|
|
)
|
|
}
|
|
}
|
|
|
|
if (isLoggedIn.value && isWorkspacesEnabled.value && !isInPlaceNavigation) {
|
|
await setActiveWorkspace({ id: data?.project.workspaceId })
|
|
}
|
|
})
|