From a900c25628f910c08f5be60d4b095a91e1e8b8ed Mon Sep 17 00:00:00 2001 From: Kim Lan Phan Hoang Date: Wed, 9 Oct 2024 12:39:42 +0200 Subject: [PATCH] fix: show request membership only for forbidden access (#1507) * fix: show request membership only for forbidden access * test: add tests * refactor: apply PR requested changes --- cypress/e2e/item/share/publicItems.cy.ts | 4 +- cypress/e2e/item/view/notFound.cy.ts | 20 +++++ cypress/support/server.ts | 5 +- package.json | 4 +- src/components/main/ItemMenuContent.tsx | 26 +++--- src/components/main/Main.tsx | 3 +- .../itemSelectionModal/RootNavigationTree.tsx | 1 - .../item/accessWrapper/ItemAccessWrapper.tsx | 12 ++- yarn.lock | 86 +++++++++---------- 9 files changed, 95 insertions(+), 66 deletions(-) create mode 100644 cypress/e2e/item/view/notFound.cy.ts diff --git a/cypress/e2e/item/share/publicItems.cy.ts b/cypress/e2e/item/share/publicItems.cy.ts index 9637dbf95..441c62baf 100644 --- a/cypress/e2e/item/share/publicItems.cy.ts +++ b/cypress/e2e/item/share/publicItems.cy.ts @@ -79,7 +79,7 @@ describe('Public Items', () => { }); cy.visit(buildItemPath(item.id)); cy.wait('@getItem').then(({ response: { statusCode } }) => { - expect(statusCode).to.equal(StatusCodes.UNAUTHORIZED); + expect(statusCode).to.equal(StatusCodes.FORBIDDEN); }); cy.get(`#${REQUEST_MEMBERSHIP_BUTTON_ID}`).click(); cy.wait('@requestMembership').then(({ request }) => { @@ -95,7 +95,7 @@ describe('Public Items', () => { }); cy.visit(buildItemPath(item.id)); cy.wait('@getItem').then(({ response: { statusCode } }) => { - expect(statusCode).to.equal(StatusCodes.UNAUTHORIZED); + expect(statusCode).to.equal(StatusCodes.FORBIDDEN); }); cy.get(`#${REQUEST_MEMBERSHIP_BUTTON_ID}`).click(); cy.wait('@requestMembership').then(({ request }) => { diff --git a/cypress/e2e/item/view/notFound.cy.ts b/cypress/e2e/item/view/notFound.cy.ts new file mode 100644 index 000000000..636e4661c --- /dev/null +++ b/cypress/e2e/item/view/notFound.cy.ts @@ -0,0 +1,20 @@ +import { v4 } from 'uuid'; + +import { buildItemPath } from '@/config/paths'; +import { + ITEM_LOGIN_SCREEN_FORBIDDEN_ID, + REQUEST_MEMBERSHIP_BUTTON_ID, +} from '@/config/selectors'; + +describe('Item does not exist', () => { + it('Show forbidden message and cannot request membership', () => { + cy.setUpApi(); + cy.visit(buildItemPath(v4())); + + // show forbidden message + cy.get(`#${ITEM_LOGIN_SCREEN_FORBIDDEN_ID}`).should('be.visible'); + + // do not show request membership button + cy.get(`#${REQUEST_MEMBERSHIP_BUTTON_ID}`).should('not.exist'); + }); +}); diff --git a/cypress/support/server.ts b/cypress/support/server.ts index f40d24453..d12f50e0b 100644 --- a/cypress/support/server.ts +++ b/cypress/support/server.ts @@ -358,7 +358,10 @@ export const mockGetItem = ( } if (!checkMembership({ item, currentMember })) { - return reply({ statusCode: StatusCodes.UNAUTHORIZED, body: null }); + if (!currentMember) { + return reply({ statusCode: StatusCodes.UNAUTHORIZED, body: null }); + } + return reply({ statusCode: StatusCodes.FORBIDDEN, body: null }); } return reply({ diff --git a/package.json b/package.json index a1b6d609e..0762d7b53 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,11 @@ "@emotion/styled": "11.13.0", "@graasp/chatbox": "3.3.0", "@graasp/map": "1.19.0", - "@graasp/query-client": "3.26.0", + "@graasp/query-client": "4.0.0", "@graasp/sdk": "4.31.0", "@graasp/stylis-plugin-rtl": "2.2.0", "@graasp/translations": "1.39.0", - "@graasp/ui": "5.2.0", + "@graasp/ui": "5.2.2", "@mui/icons-material": "5.16.7", "@mui/lab": "5.0.0-alpha.173", "@mui/material": "5.16.7", diff --git a/src/components/main/ItemMenuContent.tsx b/src/components/main/ItemMenuContent.tsx index cdfdb0cba..385f9f1d6 100644 --- a/src/components/main/ItemMenuContent.tsx +++ b/src/components/main/ItemMenuContent.tsx @@ -98,19 +98,19 @@ const ItemMenuContent = ({ item }: Props): JSX.Element | null => { ) : ( false ), - ...(member.type === AccountType.Individual - ? [ - { - openCopyModal(); - closeMenu(); - }} - />, - , - ] - : []), + member.type === AccountType.Individual ? ( + { + openCopyModal(); + closeMenu(); + }} + /> + ) : ( + false + ), + canWrite ? : false, canAdmin ? ( ({ display: 'flex', alignItems: 'center', })); -const LinkComponent = ({ children }: { children: JSX.Element }) => ( +const LinkComponent = ({ children }: { children: ReactNode }) => ( {children} ); diff --git a/src/components/main/itemSelectionModal/RootNavigationTree.tsx b/src/components/main/itemSelectionModal/RootNavigationTree.tsx index fc9f11a29..a43d82e77 100644 --- a/src/components/main/itemSelectionModal/RootNavigationTree.tsx +++ b/src/components/main/itemSelectionModal/RootNavigationTree.tsx @@ -51,7 +51,6 @@ const RootNavigationTree = ({ const { data: parents } = hooks.useParents({ id: items[0]?.id, - path: items[0]?.path, enabled: Boolean(items[0]), }); diff --git a/src/components/pages/item/accessWrapper/ItemAccessWrapper.tsx b/src/components/pages/item/accessWrapper/ItemAccessWrapper.tsx index bfcca17db..9ebaac675 100644 --- a/src/components/pages/item/accessWrapper/ItemAccessWrapper.tsx +++ b/src/components/pages/item/accessWrapper/ItemAccessWrapper.tsx @@ -12,7 +12,7 @@ import { ForbiddenContent, ItemLoginWrapper } from '@graasp/ui'; import Redirect from '@/components/main/Redirect'; import EnrollContent from '@/components/pages/item/accessWrapper/EnrollContent'; import RequestAccessContent from '@/components/pages/item/accessWrapper/RequestAccessContent'; -import { hooks, mutations } from '@/config/queryClient'; +import { axios, hooks, mutations } from '@/config/queryClient'; import { ITEM_LOGIN_SCREEN_FORBIDDEN_ID, ITEM_LOGIN_SIGN_IN_BUTTON_ID, @@ -22,7 +22,11 @@ import { const ItemAccessWrapper = (): JSX.Element => { const { itemId } = useParams(); - const { data: item, isLoading: itemIsLoading } = hooks.useItem(itemId); + const { + data: item, + isLoading: itemIsLoading, + error: itemError, + } = hooks.useItem(itemId); const { data: currentMember, isLoading: currentMemberIsLoading } = hooks.useCurrentMember(); const { data: itemLoginSchemaType, isLoading: itemLoginSchemaTypeIsLoading } = @@ -41,10 +45,12 @@ const ItemAccessWrapper = (): JSX.Element => { if (!itemId) { return ; } - + const errorStatusCode = + (axios.isAxiosError(itemError) && itemError.status) || null; return ( } signInButtonId={ITEM_LOGIN_SIGN_IN_BUTTON_ID} diff --git a/yarn.lock b/yarn.lock index 5db530b0c..3552acf27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1637,19 +1637,19 @@ __metadata: languageName: node linkType: hard -"@graasp/query-client@npm:3.26.0": - version: 3.26.0 - resolution: "@graasp/query-client@npm:3.26.0" +"@graasp/query-client@npm:4.0.0": + version: 4.0.0 + resolution: "@graasp/query-client@npm:4.0.0" dependencies: - "@tanstack/react-query": "npm:5.52.0" - "@tanstack/react-query-devtools": "npm:5.52.0" + "@tanstack/react-query": "npm:5.59.0" + "@tanstack/react-query-devtools": "npm:5.59.0" axios: "npm:1.7.7" http-status-codes: "npm:2.3.0" peerDependencies: "@graasp/sdk": ^4.0.0 "@graasp/translations": "*" react: ^18.0.0 - checksum: 10/80e18fdfaa2ac9e34d3c3893d0fb476c6a05004c5b0ee3a4a0dbdfb5736a1aa3a4213ca7a4c50a372faf514c0331a62196c421be21aabdb5061e4d21bc2058a4 + checksum: 10/52ecdddfdea99a6cb6b8e35c64007968694debe980756964158b0c564534a43fbc439cc7f8b3432c1b0f27efd9205a20465aa5c38d40e7c82b355a44c1c1dbcb languageName: node linkType: hard @@ -1688,9 +1688,9 @@ __metadata: languageName: node linkType: hard -"@graasp/ui@npm:5.2.0": - version: 5.2.0 - resolution: "@graasp/ui@npm:5.2.0" +"@graasp/ui@npm:5.2.2": + version: 5.2.2 + resolution: "@graasp/ui@npm:5.2.2" dependencies: http-status-codes: "npm:2.3.0" interweave: "npm:13.1.0" @@ -1699,7 +1699,7 @@ __metadata: react-dnd: "npm:16.0.1" react-dnd-html5-backend: "npm:16.0.1" react-quill: "npm:2.0.0" - react-rnd: "npm:10.4.12" + react-rnd: "npm:10.4.13" uuid: "npm:10.0.0" peerDependencies: "@emotion/cache": ~11.10.7 || ~11.11.0 || ~11.13.0 @@ -1713,13 +1713,13 @@ __metadata: "@mui/material": ~5.14.0 || ~5.15.0 || ~5.16.0 i18next: ^22.4.15 || ^23.0.0 katex: 0.16.11 - lucide-react: ^0.417.0 || ^0.429.0 || ^0.436.0 || ^0.439.0 || ^0.441.0 + lucide-react: ^0.417.0 || ^0.429.0 || ^0.436.0 || ^0.439.0 || ^0.441.0 || ^0.446.0 || ^0.447.0 || ^0.451.0 react: ^18.0.0 react-dom: ^18.0.0 react-i18next: ^13.0.0 || ^14.0.0 || ^15.0.0 react-router-dom: ^6.11.0 stylis: ^4.1.3 - checksum: 10/b98fc515f4f2bc7d2d1b800404cbfb480485e178db8e79c5681d10c5d152669bbffcbd0cdcf044d04b7b39856c64a10d0478f40d072213a23eb8d1fef0120853 + checksum: 10/717d2a0d282dfc4fa7de61f6b132765bdf933870d13ff0570caa713c40281ca96690af7566f41ceff94c7c49a7f22489b0ddddd83329bb5537a5f0f46542af1a languageName: node linkType: hard @@ -2560,40 +2560,40 @@ __metadata: languageName: node linkType: hard -"@tanstack/query-core@npm:5.52.0": - version: 5.52.0 - resolution: "@tanstack/query-core@npm:5.52.0" - checksum: 10/cd21e87ad7a0bbb262dea21704352eb1bbaafc26776ae1602b4be9a2d0d1f16a89cc4b5951f69083e26f970d75386431240d5a573ed9bce5a37ba2dc862e376a +"@tanstack/query-core@npm:5.59.0": + version: 5.59.0 + resolution: "@tanstack/query-core@npm:5.59.0" + checksum: 10/2e8fd7d9bdd62cabc1a2b20b2cf0c9275174ee5550170f224bd4e30fe2d01cc8d39a0dd03caae55ddb8aea259d991966bb54b581b4046fd67c621c081f4b0ba7 languageName: node linkType: hard -"@tanstack/query-devtools@npm:5.51.16": - version: 5.51.16 - resolution: "@tanstack/query-devtools@npm:5.51.16" - checksum: 10/b0e8c1f86890a515d4ddbab4743387aecd882271f7be2cbc36f69d05ba42b803ae2e9bbfd53a03450ca4827c94f6b5d7d6fa5e013bfabe6ee0aa9a7b34a223d3 +"@tanstack/query-devtools@npm:5.58.0": + version: 5.58.0 + resolution: "@tanstack/query-devtools@npm:5.58.0" + checksum: 10/ca16c47c943ea392dfddc301f7e09ecdb0c8b905fb684b8f26b908a244e2e897679efb0ead5fa8e728711017341fdd91d8c51ebb19f746819e26ade5549f539e languageName: node linkType: hard -"@tanstack/react-query-devtools@npm:5.52.0": - version: 5.52.0 - resolution: "@tanstack/react-query-devtools@npm:5.52.0" +"@tanstack/react-query-devtools@npm:5.59.0": + version: 5.59.0 + resolution: "@tanstack/react-query-devtools@npm:5.59.0" dependencies: - "@tanstack/query-devtools": "npm:5.51.16" + "@tanstack/query-devtools": "npm:5.58.0" peerDependencies: - "@tanstack/react-query": ^5.52.0 + "@tanstack/react-query": ^5.59.0 react: ^18 || ^19 - checksum: 10/67fff9fe45a54e6823800bd15de5d5712b65bda9bb567907765481025775817b03c56925add47dd51fe19de1135b57b290570e5cb00b5a071ca3f7d409c39805 + checksum: 10/a4deb3fe97355fcb98febd3b9cd5e871f3756771eb9eb15a2a226a0a9fb0314502522f70d12f54c25aec7985eae77b82b39bce37f86ee0312da046f4f1822bcf languageName: node linkType: hard -"@tanstack/react-query@npm:5.52.0": - version: 5.52.0 - resolution: "@tanstack/react-query@npm:5.52.0" +"@tanstack/react-query@npm:5.59.0": + version: 5.59.0 + resolution: "@tanstack/react-query@npm:5.59.0" dependencies: - "@tanstack/query-core": "npm:5.52.0" + "@tanstack/query-core": "npm:5.59.0" peerDependencies: - react: ^18.0.0 - checksum: 10/6976d309d306f0dd70f25e0de820812c47bfc39b654294e1512d4bb5320d0abad1bc3d6de16a25b7ae6766eb9b928c5e396e996d7d6689d33a1c1436de68cf7b + react: ^18 || ^19 + checksum: 10/48963e7d0603958390db0087c018b71e87187ad84dea03279716b4869de83509027c37f65f3c6c4a1cd7b6f9f14250afffc2aeee5d481528e2308d937422ae41 languageName: node linkType: hard @@ -6472,11 +6472,11 @@ __metadata: "@emotion/styled": "npm:11.13.0" "@graasp/chatbox": "npm:3.3.0" "@graasp/map": "npm:1.19.0" - "@graasp/query-client": "npm:3.26.0" + "@graasp/query-client": "npm:4.0.0" "@graasp/sdk": "npm:4.31.0" "@graasp/stylis-plugin-rtl": "npm:2.2.0" "@graasp/translations": "npm:1.39.0" - "@graasp/ui": "npm:5.2.0" + "@graasp/ui": "npm:5.2.2" "@mui/icons-material": "npm:5.16.7" "@mui/lab": "npm:5.0.0-alpha.173" "@mui/material": "npm:5.16.7" @@ -9735,13 +9735,13 @@ __metadata: languageName: node linkType: hard -"re-resizable@npm:6.9.17": - version: 6.9.17 - resolution: "re-resizable@npm:6.9.17" +"re-resizable@npm:6.10.0": + version: 6.10.0 + resolution: "re-resizable@npm:6.10.0" peerDependencies: react: ^16.13.1 || ^17.0.0 || ^18.0.0 react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - checksum: 10/768c3a0fe39d6916caf4e003240d326d62c4d7512c7d3115cc2a98085416fdba80097afdbb93df57b69543c41ce56b33589f2fea6987cd5149faa83cf11c8ba1 + checksum: 10/303e582feffdfd3e491e2b51dc75c8641c726882e2d8e3ec249b2bc1d23bfffa73bd4a982ed5456bcab9ec25f52b5430e8c632f32647295ed773679691a961a2 languageName: node linkType: hard @@ -10057,17 +10057,17 @@ __metadata: languageName: node linkType: hard -"react-rnd@npm:10.4.12": - version: 10.4.12 - resolution: "react-rnd@npm:10.4.12" +"react-rnd@npm:10.4.13": + version: 10.4.13 + resolution: "react-rnd@npm:10.4.13" dependencies: - re-resizable: "npm:6.9.17" + re-resizable: "npm:6.10.0" react-draggable: "npm:4.4.6" tslib: "npm:2.6.2" peerDependencies: react: ">=16.3.0" react-dom: ">=16.3.0" - checksum: 10/f29429a9ceafdf19c3b50571882c36eee29430a22d526fe2aaf641e38146e1bf5a1337639e0c9eba7c6ddaa85721cff9f390cf8d807a62634a27a77e49e2653c + checksum: 10/3a343d71117c37e105286eeee38e244d9dc62e0e4b2efa929128995056408cf7fda15f5100f66b8548370ae63f886b94c7851e862fd90dd0b543ec382f43c4f1 languageName: node linkType: hard