From 15700ddd8d8f07522c959d059e51ab8ebeed6704 Mon Sep 17 00:00:00 2001 From: Samuel Paccoud - DINUM Date: Wed, 23 Oct 2024 08:26:40 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(backend)=20add=20new=20ability=20on?= =?UTF-8?q?=20document=20"accesses=5Fview"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need this ability in the frontend to know whether we should try to display the list of users who have document accesses. If this ability is False (e.g for anonymous users), we should only show the link reach and link role when clicking on the "Share" button. --- CHANGELOG.md | 1 + src/backend/core/models.py | 12 ++++++---- .../documents/test_api_documents_retrieve.py | 6 +++-- .../templates/test_api_templates_retrieve.py | 4 ++-- .../core/tests/test_models_documents.py | 24 ++++++++++++------- .../core/tests/test_models_templates.py | 18 +++++++------- .../apps/e2e/__tests__/app-impress/common.ts | 2 +- .../__tests__/app-impress/doc-editor.spec.ts | 2 +- .../__tests__/app-impress/doc-grid.spec.ts | 2 +- .../__tests__/app-impress/doc-header.spec.ts | 10 ++++---- .../src/features/docs/doc-header/types.ts | 2 +- .../doc-management/components/ModalShare.tsx | 2 +- .../features/docs/doc-management/types.tsx | 2 +- .../src/features/docs/doc-management/utils.ts | 2 +- .../components/InvitationItem.tsx | 2 +- .../members-add/components/AddMembers.tsx | 6 ++--- .../members-list/components/MemberItem.tsx | 6 ++--- .../src/features/service-worker/ApiPlugin.ts | 2 +- 18 files changed, 59 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 312f1307..af1e3e30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to - 🌐(frontend) add localization to editor #268 - ✨Public and restricted doc editable #357 - ✨(frontend) Add full name if available #380 +- ✨(backend) Add view accesses ability #376 ## Fixed diff --git a/src/backend/core/models.py b/src/backend/core/models.py index 6be54d64..9e5f02a7 100644 --- a/src/backend/core/models.py +++ b/src/backend/core/models.py @@ -496,7 +496,8 @@ class Document(BaseModel): # Compute version roles before adding link roles because we don't # want anonymous users to access versions (we wouldn't know from # which date to allow them anyway) - can_get_versions = bool(roles) + # Anonymous users should also not see document accesses + has_role = bool(roles) # Add role provided by the document link if self.link_reach == LinkReachChoices.PUBLIC or ( @@ -511,19 +512,20 @@ class Document(BaseModel): can_get = bool(roles) return { + "accesses_manage": is_owner_or_admin, + "accesses_view": has_role, "ai_transform": is_owner_or_admin or is_editor, "ai_translate": is_owner_or_admin or is_editor, "attachment_upload": is_owner_or_admin or is_editor, "destroy": RoleChoices.OWNER in roles, "link_configuration": is_owner_or_admin, - "manage_accesses": is_owner_or_admin, "invite_owner": RoleChoices.OWNER in roles, "partial_update": is_owner_or_admin or is_editor, "retrieve": can_get, "update": is_owner_or_admin or is_editor, "versions_destroy": is_owner_or_admin, - "versions_list": can_get_versions, - "versions_retrieve": can_get_versions, + "versions_list": has_role, + "versions_retrieve": has_role, } def email_invitation(self, language, email, role, sender): @@ -679,7 +681,7 @@ class Template(BaseModel): return { "destroy": RoleChoices.OWNER in roles, "generate_document": can_get, - "manage_accesses": is_owner_or_admin, + "accesses_manage": is_owner_or_admin, "update": is_owner_or_admin or is_editor, "partial_update": is_owner_or_admin or is_editor, "retrieve": can_get, diff --git a/src/backend/core/tests/documents/test_api_documents_retrieve.py b/src/backend/core/tests/documents/test_api_documents_retrieve.py index 220b5213..c7a76032 100644 --- a/src/backend/core/tests/documents/test_api_documents_retrieve.py +++ b/src/backend/core/tests/documents/test_api_documents_retrieve.py @@ -21,13 +21,14 @@ def test_api_documents_retrieve_anonymous_public(): assert response.json() == { "id": str(document.id), "abilities": { + "accesses_manage": False, + "accesses_view": False, "ai_transform": document.link_role == "editor", "ai_translate": document.link_role == "editor", "attachment_upload": document.link_role == "editor", "destroy": False, "invite_owner": False, "link_configuration": False, - "manage_accesses": False, "partial_update": document.link_role == "editor", "retrieve": True, "update": document.link_role == "editor", @@ -78,13 +79,14 @@ def test_api_documents_retrieve_authenticated_unrelated_public_or_authenticated( assert response.json() == { "id": str(document.id), "abilities": { + "accesses_manage": False, + "accesses_view": False, "ai_transform": document.link_role == "editor", "ai_translate": document.link_role == "editor", "attachment_upload": document.link_role == "editor", "link_configuration": False, "destroy": False, "invite_owner": False, - "manage_accesses": False, "partial_update": document.link_role == "editor", "retrieve": True, "update": document.link_role == "editor", diff --git a/src/backend/core/tests/templates/test_api_templates_retrieve.py b/src/backend/core/tests/templates/test_api_templates_retrieve.py index 7af1fbaf..e3466ab2 100644 --- a/src/backend/core/tests/templates/test_api_templates_retrieve.py +++ b/src/backend/core/tests/templates/test_api_templates_retrieve.py @@ -22,7 +22,7 @@ def test_api_templates_retrieve_anonymous_public(): "abilities": { "destroy": False, "generate_document": True, - "manage_accesses": False, + "accesses_manage": False, "partial_update": False, "retrieve": True, "update": False, @@ -68,7 +68,7 @@ def test_api_templates_retrieve_authenticated_unrelated_public(): "abilities": { "destroy": False, "generate_document": True, - "manage_accesses": False, + "accesses_manage": False, "partial_update": False, "retrieve": True, "update": False, diff --git a/src/backend/core/tests/test_models_documents.py b/src/backend/core/tests/test_models_documents.py index d034f011..0859db69 100644 --- a/src/backend/core/tests/test_models_documents.py +++ b/src/backend/core/tests/test_models_documents.py @@ -83,13 +83,14 @@ def test_models_documents_get_abilities_forbidden(is_authenticated, reach, role) user = factories.UserFactory() if is_authenticated else AnonymousUser() abilities = document.get_abilities(user) assert abilities == { + "accesses_manage": False, + "accesses_view": False, "ai_transform": False, "ai_translate": False, "attachment_upload": False, "link_configuration": False, "destroy": False, "invite_owner": False, - "manage_accesses": False, "partial_update": False, "retrieve": False, "update": False, @@ -116,13 +117,14 @@ def test_models_documents_get_abilities_reader(is_authenticated, reach): user = factories.UserFactory() if is_authenticated else AnonymousUser() abilities = document.get_abilities(user) assert abilities == { + "accesses_manage": False, + "accesses_view": False, "ai_transform": False, "ai_translate": False, "attachment_upload": False, "destroy": False, "link_configuration": False, "invite_owner": False, - "manage_accesses": False, "partial_update": False, "retrieve": True, "update": False, @@ -149,13 +151,14 @@ def test_models_documents_get_abilities_editor(is_authenticated, reach): user = factories.UserFactory() if is_authenticated else AnonymousUser() abilities = document.get_abilities(user) assert abilities == { + "accesses_manage": False, + "accesses_view": False, "ai_transform": True, "ai_translate": True, "attachment_upload": True, "destroy": False, "link_configuration": False, "invite_owner": False, - "manage_accesses": False, "partial_update": True, "retrieve": True, "update": True, @@ -171,13 +174,14 @@ def test_models_documents_get_abilities_owner(): access = factories.UserDocumentAccessFactory(role="owner", user=user) abilities = access.document.get_abilities(access.user) assert abilities == { + "accesses_manage": True, + "accesses_view": True, "ai_transform": True, "ai_translate": True, "attachment_upload": True, "destroy": True, "link_configuration": True, "invite_owner": True, - "manage_accesses": True, "partial_update": True, "retrieve": True, "update": True, @@ -192,13 +196,14 @@ def test_models_documents_get_abilities_administrator(): access = factories.UserDocumentAccessFactory(role="administrator") abilities = access.document.get_abilities(access.user) assert abilities == { + "accesses_manage": True, + "accesses_view": True, "ai_transform": True, "ai_translate": True, "attachment_upload": True, "destroy": False, "link_configuration": True, "invite_owner": False, - "manage_accesses": True, "partial_update": True, "retrieve": True, "update": True, @@ -216,13 +221,14 @@ def test_models_documents_get_abilities_editor_user(django_assert_num_queries): abilities = access.document.get_abilities(access.user) assert abilities == { + "accesses_manage": False, + "accesses_view": True, "ai_transform": True, "ai_translate": True, "attachment_upload": True, "destroy": False, "link_configuration": False, "invite_owner": False, - "manage_accesses": False, "partial_update": True, "retrieve": True, "update": True, @@ -242,13 +248,14 @@ def test_models_documents_get_abilities_reader_user(django_assert_num_queries): abilities = access.document.get_abilities(access.user) assert abilities == { + "accesses_manage": False, + "accesses_view": True, "ai_transform": False, "ai_translate": False, "attachment_upload": False, "destroy": False, "link_configuration": False, "invite_owner": False, - "manage_accesses": False, "partial_update": False, "retrieve": True, "update": False, @@ -269,13 +276,14 @@ def test_models_documents_get_abilities_preset_role(django_assert_num_queries): abilities = access.document.get_abilities(access.user) assert abilities == { + "accesses_manage": False, + "accesses_view": True, "ai_transform": False, "ai_translate": False, "attachment_upload": False, "destroy": False, "link_configuration": False, "invite_owner": False, - "manage_accesses": False, "partial_update": False, "retrieve": True, "update": False, diff --git a/src/backend/core/tests/test_models_templates.py b/src/backend/core/tests/test_models_templates.py index d38fcea9..6e7cba2c 100644 --- a/src/backend/core/tests/test_models_templates.py +++ b/src/backend/core/tests/test_models_templates.py @@ -62,7 +62,7 @@ def test_models_templates_get_abilities_anonymous_public(): "destroy": False, "retrieve": True, "update": False, - "manage_accesses": False, + "accesses_manage": False, "partial_update": False, "generate_document": True, } @@ -76,7 +76,7 @@ def test_models_templates_get_abilities_anonymous_not_public(): "destroy": False, "retrieve": False, "update": False, - "manage_accesses": False, + "accesses_manage": False, "partial_update": False, "generate_document": False, } @@ -90,7 +90,7 @@ def test_models_templates_get_abilities_authenticated_public(): "destroy": False, "retrieve": True, "update": False, - "manage_accesses": False, + "accesses_manage": False, "partial_update": False, "generate_document": True, } @@ -104,7 +104,7 @@ def test_models_templates_get_abilities_authenticated_not_public(): "destroy": False, "retrieve": False, "update": False, - "manage_accesses": False, + "accesses_manage": False, "partial_update": False, "generate_document": False, } @@ -119,7 +119,7 @@ def test_models_templates_get_abilities_owner(): "destroy": True, "retrieve": True, "update": True, - "manage_accesses": True, + "accesses_manage": True, "partial_update": True, "generate_document": True, } @@ -133,7 +133,7 @@ def test_models_templates_get_abilities_administrator(): "destroy": False, "retrieve": True, "update": True, - "manage_accesses": True, + "accesses_manage": True, "partial_update": True, "generate_document": True, } @@ -150,7 +150,7 @@ def test_models_templates_get_abilities_editor_user(django_assert_num_queries): "destroy": False, "retrieve": True, "update": True, - "manage_accesses": False, + "accesses_manage": False, "partial_update": True, "generate_document": True, } @@ -167,7 +167,7 @@ def test_models_templates_get_abilities_reader_user(django_assert_num_queries): "destroy": False, "retrieve": True, "update": False, - "manage_accesses": False, + "accesses_manage": False, "partial_update": False, "generate_document": True, } @@ -185,7 +185,7 @@ def test_models_templates_get_abilities_preset_role(django_assert_num_queries): "destroy": False, "retrieve": True, "update": False, - "manage_accesses": False, + "accesses_manage": False, "partial_update": False, "generate_document": True, } diff --git a/src/frontend/apps/e2e/__tests__/app-impress/common.ts b/src/frontend/apps/e2e/__tests__/app-impress/common.ts index 2c52eeee..900d3265 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/common.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/common.ts @@ -144,7 +144,7 @@ export const mockedDocument = async (page: Page, json: object) => { versions_destroy: false, versions_list: true, versions_retrieve: true, - manage_accesses: false, // Means not admin + accesses_manage: false, // Means not admin update: false, partial_update: false, // Means not editor retrieve: true, diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts index bd5c7f62..d41660a5 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts @@ -215,7 +215,7 @@ test.describe('Doc Editor', () => { versions_destroy: false, versions_list: true, versions_retrieve: true, - manage_accesses: false, // Means not admin + accesses_manage: false, // Means not admin update: false, partial_update: false, // Means not editor retrieve: true, diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts index 6807647e..54febf83 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts @@ -303,7 +303,7 @@ test.describe('Documents Grid mobile', () => { attachment_upload: true, destroy: true, link_configuration: true, - manage_accesses: true, + accesses_manage: true, partial_update: true, retrieve: true, update: true, diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts index 5bb9aa6d..cd5e2efa 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts @@ -45,7 +45,7 @@ test.describe('Doc Header', () => { versions_destroy: true, versions_list: true, versions_retrieve: true, - manage_accesses: true, + accesses_manage: true, update: true, partial_update: true, retrieve: true, @@ -182,7 +182,7 @@ test.describe('Doc Header', () => { versions_destroy: true, versions_list: true, versions_retrieve: true, - manage_accesses: true, // Means admin + accesses_manage: true, // Means admin update: true, partial_update: true, retrieve: true, @@ -252,7 +252,7 @@ test.describe('Doc Header', () => { versions_destroy: true, versions_list: true, versions_retrieve: true, - manage_accesses: false, // Means not admin + accesses_manage: false, // Means not admin update: true, partial_update: true, // Means editor retrieve: true, @@ -329,7 +329,7 @@ test.describe('Doc Header', () => { versions_destroy: false, versions_list: true, versions_retrieve: true, - manage_accesses: false, // Means not admin + accesses_manage: false, // Means not admin update: false, partial_update: false, // Means not editor retrieve: true, @@ -489,7 +489,7 @@ test.describe('Documents Header mobile', () => { versions_destroy: true, versions_list: true, versions_retrieve: true, - manage_accesses: true, + accesses_manage: true, update: true, partial_update: true, retrieve: true, diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/types.ts b/src/frontend/apps/impress/src/features/docs/doc-header/types.ts index 8a81c870..70b62e56 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/types.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-header/types.ts @@ -5,7 +5,7 @@ export interface Template { abilities: { destroy: boolean; generate_document: boolean; - manage_accesses: boolean; + accesses_manage: boolean; retrieve: boolean; update: boolean; partial_update: boolean; diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalShare.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalShare.tsx index 3c8807bc..7361ec54 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalShare.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalShare.tsx @@ -115,7 +115,7 @@ export const ModalShare = ({ onClose, doc }: ModalShareProps) => { - {doc.abilities.manage_accesses && ( + {doc.abilities.accesses_manage && ( { return abilities.destroy ? Role.OWNER - : abilities.manage_accesses + : abilities.accesses_manage ? Role.ADMIN : abilities.partial_update ? Role.EDITOR diff --git a/src/frontend/apps/impress/src/features/docs/members/invitation-list/components/InvitationItem.tsx b/src/frontend/apps/impress/src/features/docs/members/invitation-list/components/InvitationItem.tsx index e92358c8..9de0e8db 100644 --- a/src/frontend/apps/impress/src/features/docs/members/invitation-list/components/InvitationItem.tsx +++ b/src/frontend/apps/impress/src/features/docs/members/invitation-list/components/InvitationItem.tsx @@ -112,7 +112,7 @@ export const InvitationItem = ({ }} /> - {doc.abilities.manage_accesses && ( + {doc.abilities.accesses_manage && (