diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-member-create.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-member-create.spec.ts index d0a98028..38a05864 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-member-create.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-member-create.spec.ts @@ -7,6 +7,7 @@ import { randomName, verifyDocName, } from './common'; +import { createRootSubPage } from './sub-pages-utils'; test.describe('Document create member', () => { test.beforeEach(async ({ page }) => { @@ -272,7 +273,9 @@ test.describe('Document create member: Multiple login', () => { await expect( page.getByRole('link', { name: 'Docs Logo Docs' }), - ).toBeVisible(); + ).toBeVisible({ + timeout: 10000, + }); await page.goto(urlDoc); @@ -294,4 +297,61 @@ test.describe('Document create member: Multiple login', () => { await expect(page.getByText('Share with 2 users')).toBeVisible(); await expect(page.getByText(`E2E ${otherBrowser}`)).toBeVisible(); }); + + test('It cannot request member access on child doc on a 403 page', async ({ + page, + browserName, + }) => { + test.slow(); + + await page.goto('/'); + await keyCloakSignIn(page, browserName); + + const [docParent] = await createDoc( + page, + 'Block Member access request on child doc - parent', + browserName, + 1, + ); + + await verifyDocName(page, docParent); + + await createRootSubPage( + page, + browserName, + 'Block Member access request on child doc - child', + ); + + const urlDoc = page.url(); + + await page + .getByRole('button', { + name: 'Logout', + }) + .click(); + + const otherBrowser = BROWSERS.find((b) => b !== browserName); + + await keyCloakSignIn(page, otherBrowser!); + + await expect( + page.getByRole('link', { name: 'Docs Logo Docs' }), + ).toBeVisible({ + timeout: 10000, + }); + + await page.goto(urlDoc); + + await expect( + page.getByText( + "You're currently viewing a sub-document. To gain access, please request permission from the main document.", + ), + ).toBeVisible({ + timeout: 10000, + }); + + await expect( + page.getByRole('button', { name: 'Request access' }), + ).toBeHidden(); + }); }); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts index 47c151df..a0833d43 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts @@ -7,6 +7,7 @@ import { keyCloakSignIn, verifyDocName, } from './common'; +import { createRootSubPage } from './sub-pages-utils'; test.describe('Doc Visibility', () => { test.beforeEach(async ({ page }) => { @@ -271,7 +272,7 @@ test.describe('Doc Visibility: Public', () => { await page.getByRole('button', { name: 'Share' }).click(); await expect( page.getByText( - 'You do not have permission to view users sharing this document or modify link settings.', + 'You can view this document but need additional access to see its members or modify settings.', ), ).toBeVisible(); @@ -398,6 +399,8 @@ test.describe('Doc Visibility: Authenticated', () => { page, browserName, }) => { + test.slow(); + await page.goto('/'); await keyCloakSignIn(page, browserName); @@ -435,6 +438,14 @@ test.describe('Doc Visibility: Authenticated', () => { const urlDoc = page.url(); + const { name: childTitle } = await createRootSubPage( + page, + browserName, + 'Authenticated read onlyc - child', + ); + + const urlChildDoc = page.url(); + await page .getByRole('button', { name: 'Logout', @@ -446,7 +457,9 @@ test.describe('Doc Visibility: Authenticated', () => { await expect( page.getByRole('link', { name: 'Docs Logo Docs' }), - ).toBeVisible(); + ).toBeVisible({ + timeout: 10000, + }); await page.goto(urlDoc); @@ -457,7 +470,7 @@ test.describe('Doc Visibility: Authenticated', () => { await expect( page.getByText( - 'You do not have permission to view users sharing this document or modify link settings.', + 'You can view this document but need additional access to see its members or modify settings.', ), ).toBeVisible(); @@ -466,6 +479,22 @@ test.describe('Doc Visibility: Authenticated', () => { await expect( page.getByRole('button', { name: 'Request access' }), ).toBeDisabled(); + + await page.goto(urlChildDoc); + + await expect(page.locator('h2').getByText(childTitle)).toBeVisible(); + + await page.getByRole('button', { name: 'Share' }).click(); + + await expect( + page.getByText( + 'As this is a sub-document, please request access to the parent document to enable these features.', + ), + ).toBeVisible(); + + await expect( + page.getByRole('button', { name: 'Request access' }), + ).toBeHidden(); }); test('It checks a authenticated doc in editable mode', async ({ diff --git a/src/frontend/apps/impress/src/components/Loading.tsx b/src/frontend/apps/impress/src/components/Loading.tsx index ec688b48..db6c89de 100644 --- a/src/frontend/apps/impress/src/components/Loading.tsx +++ b/src/frontend/apps/impress/src/components/Loading.tsx @@ -1,7 +1,7 @@ import { Loader } from '@openfun/cunningham-react'; import { useTranslation } from 'react-i18next'; -import { Box } from './Box'; +import { Box, BoxProps } from './Box'; import { Icon } from './Icon'; import { Text } from './Text'; @@ -36,8 +36,8 @@ export const LoadMoreText = ({ ); }; -export const Loading = () => ( - +export const Loading = (props: BoxProps) => ( + ); diff --git a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareAccessRequest.tsx b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareAccessRequest.tsx index 31b83f39..8f585484 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareAccessRequest.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocShareAccessRequest.tsx @@ -8,7 +8,14 @@ import { useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { createGlobalStyle } from 'styled-components'; -import { Box, BoxButton, Icon, LoadMoreText } from '@/components'; +import { + Box, + BoxButton, + Icon, + LoadMoreText, + Loading, + Text, +} from '@/components'; import { QuickSearchData, QuickSearchGroup } from '@/components/quick-search'; import { useCunninghamTheme } from '@/cunningham'; import { AccessRequest, Doc } from '@/docs/doc-management/'; @@ -161,7 +168,11 @@ export const ButtonAccessRequest = ({ ...buttonProps }: ButtonAccessRequestProps) => { const { authenticated } = useAuth(); - const { data: requests } = useDocAccessRequests({ + const { + data: requests, + error: docAccessError, + isLoading, + } = useDocAccessRequests({ docId, page: 1, }); @@ -175,14 +186,28 @@ export const ButtonAccessRequest = ({ }, }); - const hasRequested = !!( - requests && requests?.results.find((request) => request.document === docId) - ); - if (!authenticated) { return null; } + if (docAccessError?.status === 404) { + return ( + + {t( + 'As this is a sub-document, please request access to the parent document to enable these features.', + )} + + ); + } + + if (isLoading) { + return ; + } + + const hasRequested = !!( + requests && requests?.results.find((request) => request.document === docId) + ); + return (