Feat: Add required valid presentation middleware (#5567)

This commit is contained in:
Mike
2025-09-29 14:09:38 +02:00
committed by GitHub
parent 017de41539
commit daa88cd052
5 changed files with 85 additions and 1 deletions
@@ -296,6 +296,7 @@ type Documents = {
"\n query NavigationProjectInvites {\n activeUser {\n id\n projectInvites {\n ...HeaderNavNotificationsProjectInvite_PendingStreamCollaborator\n }\n }\n }\n": typeof types.NavigationProjectInvitesDocument,
"\n query NavigationWorkspaceInvites {\n activeUser {\n id\n workspaceInvites {\n ...HeaderNavNotificationsWorkspaceInvite_PendingWorkspaceCollaborator\n }\n }\n }\n": typeof types.NavigationWorkspaceInvitesDocument,
"\n mutation UpdatePresentationSlide($input: UpdateSavedViewInput!) {\n projectMutations {\n savedViewMutations {\n updateView(input: $input) {\n id\n name\n description\n }\n }\n }\n }\n": typeof types.UpdatePresentationSlideDocument,
"\n query PresentationAccessCheck($savedViewGroupId: ID!, $projectId: String!) {\n project(id: $projectId) {\n id\n savedViewGroup(id: $savedViewGroupId) {\n id\n }\n }\n }\n": typeof types.PresentationAccessCheckDocument,
"\n query ProjectPresentationPage(\n $input: SavedViewGroupViewsInput!\n $savedViewGroupId: ID!\n $projectId: String!\n ) {\n project(id: $projectId) {\n id\n limitedWorkspace {\n id\n ...PresentationLeftSidebar_LimitedWorkspace\n }\n savedViewGroup(id: $savedViewGroupId) {\n id\n title\n ...PresentationViewerPageWrapper_SavedViewGroup\n ...PresentationHeader_SavedViewGroup\n ...PresentationSlideList_SavedViewGroup\n ...PresentationPageWrapper_SavedViewGroup\n views(input: $input) {\n totalCount\n items {\n id\n name\n description\n screenshot\n projectId\n visibility\n ...PresentationInfoSidebar_SavedView\n group {\n id\n }\n }\n }\n }\n }\n }\n": typeof types.ProjectPresentationPageDocument,
"\n fragment UseCopyModelLink_Model on Model {\n id\n projectId\n ...GetModelItemRoute_Model\n }\n": typeof types.UseCopyModelLink_ModelFragmentDoc,
"\n fragment UseCanCreatePersonalProject_User on User {\n permissions {\n canCreatePersonalProject {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.UseCanCreatePersonalProject_UserFragmentDoc,
@@ -831,6 +832,7 @@ const documents: Documents = {
"\n query NavigationProjectInvites {\n activeUser {\n id\n projectInvites {\n ...HeaderNavNotificationsProjectInvite_PendingStreamCollaborator\n }\n }\n }\n": types.NavigationProjectInvitesDocument,
"\n query NavigationWorkspaceInvites {\n activeUser {\n id\n workspaceInvites {\n ...HeaderNavNotificationsWorkspaceInvite_PendingWorkspaceCollaborator\n }\n }\n }\n": types.NavigationWorkspaceInvitesDocument,
"\n mutation UpdatePresentationSlide($input: UpdateSavedViewInput!) {\n projectMutations {\n savedViewMutations {\n updateView(input: $input) {\n id\n name\n description\n }\n }\n }\n }\n": types.UpdatePresentationSlideDocument,
"\n query PresentationAccessCheck($savedViewGroupId: ID!, $projectId: String!) {\n project(id: $projectId) {\n id\n savedViewGroup(id: $savedViewGroupId) {\n id\n }\n }\n }\n": types.PresentationAccessCheckDocument,
"\n query ProjectPresentationPage(\n $input: SavedViewGroupViewsInput!\n $savedViewGroupId: ID!\n $projectId: String!\n ) {\n project(id: $projectId) {\n id\n limitedWorkspace {\n id\n ...PresentationLeftSidebar_LimitedWorkspace\n }\n savedViewGroup(id: $savedViewGroupId) {\n id\n title\n ...PresentationViewerPageWrapper_SavedViewGroup\n ...PresentationHeader_SavedViewGroup\n ...PresentationSlideList_SavedViewGroup\n ...PresentationPageWrapper_SavedViewGroup\n views(input: $input) {\n totalCount\n items {\n id\n name\n description\n screenshot\n projectId\n visibility\n ...PresentationInfoSidebar_SavedView\n group {\n id\n }\n }\n }\n }\n }\n }\n": types.ProjectPresentationPageDocument,
"\n fragment UseCopyModelLink_Model on Model {\n id\n projectId\n ...GetModelItemRoute_Model\n }\n": types.UseCopyModelLink_ModelFragmentDoc,
"\n fragment UseCanCreatePersonalProject_User on User {\n permissions {\n canCreatePersonalProject {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.UseCanCreatePersonalProject_UserFragmentDoc,
@@ -2226,6 +2228,10 @@ export function graphql(source: "\n query NavigationWorkspaceInvites {\n act
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation UpdatePresentationSlide($input: UpdateSavedViewInput!) {\n projectMutations {\n savedViewMutations {\n updateView(input: $input) {\n id\n name\n description\n }\n }\n }\n }\n"): (typeof documents)["\n mutation UpdatePresentationSlide($input: UpdateSavedViewInput!) {\n projectMutations {\n savedViewMutations {\n updateView(input: $input) {\n id\n name\n description\n }\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query PresentationAccessCheck($savedViewGroupId: ID!, $projectId: String!) {\n project(id: $projectId) {\n id\n savedViewGroup(id: $savedViewGroupId) {\n id\n }\n }\n }\n"): (typeof documents)["\n query PresentationAccessCheck($savedViewGroupId: ID!, $projectId: String!) {\n project(id: $projectId) {\n id\n savedViewGroup(id: $savedViewGroupId) {\n id\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
File diff suppressed because one or more lines are too long
@@ -1,5 +1,16 @@
import { graphql } from '~/lib/common/generated/gql/gql'
export const presentationAccessCheckQuery = graphql(`
query PresentationAccessCheck($savedViewGroupId: ID!, $projectId: String!) {
project(id: $projectId) {
id
savedViewGroup(id: $savedViewGroupId) {
id
}
}
}
`)
export const projectPresentationPageQuery = graphql(`
query ProjectPresentationPage(
$input: SavedViewGroupViewsInput!
@@ -0,0 +1,57 @@
// import type { Optional } from '@speckle/shared'
import { useApolloClientFromNuxt } from '~/lib/common/composables/graphql'
import {
convertThrowIntoFetchResult,
errorsToAuthResult
} from '~/lib/common/helpers/graphql'
import { presentationAccessCheckQuery } from '~/lib/presentations/graphql/queries'
/**
* Used in presentation page to validate that presentation ID refers to a valid presentation and redirects to 404 if not
*/
export default defineParallelizedNuxtRouteMiddleware(async (to, _from) => {
const savedViewGroupId = to.params.presentationId as string
const projectId = to.params.id as string
// Check if token is present in URL
// const token = to.query.presentationToken as Optional<string>
// Skip middleware validation for tokens - let the auth system handle them
// if (token) {
// return
// }
const client = useApolloClientFromNuxt()
const { data, errors } = await client
.query({
query: presentationAccessCheckQuery,
variables: { savedViewGroupId, projectId },
context: {
skipLoggingErrors: true
}
})
.catch(convertThrowIntoFetchResult)
if (!data?.project?.savedViewGroup) {
const authResult = errorsToAuthResult({ errors })
switch (authResult.code) {
case 'FORBIDDEN':
return abortNavigation(
createError({
statusCode: 403,
message: authResult.message
})
)
default:
return abortNavigation(
createError({
statusCode: 500,
message: authResult.message
})
)
}
}
})
@@ -6,7 +6,8 @@
<script setup lang="ts">
definePageMeta({
layout: 'empty'
layout: 'empty',
middleware: ['require-valid-presentation']
})
useHead({