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 && (