diff --git a/CHANGELOG.md b/CHANGELOG.md index dabe99e1c..d89b178bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to ### Changed +- ♻️(backend) rename documents content endpoint in formatted-content - 🚸(frontend) show Crisp from the help menu #2222 - ♿️(frontend) structure correctly 5xx error alerts #2128 - ♿️(frontend) make doc search result labels uniquely identifiable #2212 diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 32e52f710..361118abb 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -2193,10 +2193,10 @@ class DocumentViewSet( @drf.decorators.action( detail=True, methods=["get"], - url_path="content", - name="Get document content in different formats", + url_path="formatted-content", + name="Convert document content to different formats", ) - def content(self, request, pk=None): + def formatted_content(self, request, pk=None): """ Retrieve document content in different formats (JSON, Markdown, HTML). diff --git a/src/backend/core/models.py b/src/backend/core/models.py index c6ed9ae16..45a7b0e72 100644 --- a/src/backend/core/models.py +++ b/src/backend/core/models.py @@ -1308,7 +1308,7 @@ class Document(MP_Node, BaseModel): "children_create": can_create_children, "collaboration_auth": can_get, "comment": can_comment, - "content": can_get, + "formatted_content": can_get, "cors_proxy": can_get, "descendants": can_get, "destroy": can_destroy, diff --git a/src/backend/core/tests/documents/test_api_documents_content.py b/src/backend/core/tests/documents/test_api_documents_formatted_content.py similarity index 79% rename from src/backend/core/tests/documents/test_api_documents_content.py rename to src/backend/core/tests/documents/test_api_documents_formatted_content.py index 459bf5a0c..b2318b627 100644 --- a/src/backend/core/tests/documents/test_api_documents_content.py +++ b/src/backend/core/tests/documents/test_api_documents_formatted_content.py @@ -1,5 +1,5 @@ """ -Tests for Documents API endpoint in impress's core app: content +Tests for Documents API endpoint in impress's core app: convert """ import base64 @@ -23,12 +23,14 @@ pytestmark = pytest.mark.django_db ], ) @patch("core.services.converter_services.YdocConverter.convert") -def test_api_documents_content_public(mock_content, reach, role): +def test_api_documents_formatted_content_public(mock_content, reach, role): """Anonymous users should be allowed to access content of public documents.""" document = factories.DocumentFactory(link_reach=reach, link_role=role) mock_content.return_value = {"some": "data"} - response = APIClient().get(f"/api/v1.0/documents/{document.id!s}/content/") + response = APIClient().get( + f"/api/v1.0/documents/{document.id!s}/formatted-content/" + ) assert response.status_code == status.HTTP_200_OK data = response.json() @@ -58,7 +60,9 @@ def test_api_documents_content_public(mock_content, reach, role): ], ) @patch("core.services.converter_services.YdocConverter.convert") -def test_api_documents_content_not_public(mock_content, reach, doc_role, user_role): +def test_api_documents_formatted_content_not_public( + mock_content, reach, doc_role, user_role +): """Authenticated users need access to get non-public document content.""" user = factories.UserFactory() document = factories.DocumentFactory(link_reach=reach, link_role=doc_role) @@ -66,14 +70,14 @@ def test_api_documents_content_not_public(mock_content, reach, doc_role, user_ro # First anonymous request should fail client = APIClient() - response = client.get(f"/api/v1.0/documents/{document.id!s}/content/") + response = client.get(f"/api/v1.0/documents/{document.id!s}/formatted-content/") assert response.status_code == status.HTTP_401_UNAUTHORIZED mock_content.assert_not_called() # Login and try again client.force_login(user) - response = client.get(f"/api/v1.0/documents/{document.id!s}/content/") + response = client.get(f"/api/v1.0/documents/{document.id!s}/formatted-content/") # If restricted, we still should not have access if user_role is not None: @@ -85,7 +89,7 @@ def test_api_documents_content_not_public(mock_content, reach, doc_role, user_ro document=document, user=user, role=user_role ) - response = client.get(f"/api/v1.0/documents/{document.id!s}/content/") + response = client.get(f"/api/v1.0/documents/{document.id!s}/formatted-content/") assert response.status_code == status.HTTP_200_OK data = response.json() @@ -108,13 +112,13 @@ def test_api_documents_content_not_public(mock_content, reach, doc_role, user_ro ], ) @patch("core.services.converter_services.YdocConverter.convert") -def test_api_documents_content_format(mock_content, content_format, accept): - """Test that the content endpoint returns a specific format.""" +def test_api_documents_formatted_content_format(mock_content, content_format, accept): + """Test that the convert endpoint returns a specific format.""" document = factories.DocumentFactory(link_reach="public") mock_content.return_value = {"some": "data"} response = APIClient().get( - f"/api/v1.0/documents/{document.id!s}/content/?content_format={content_format}" + f"/api/v1.0/documents/{document.id!s}/formatted-content/?content_format={content_format}" ) assert response.status_code == status.HTTP_200_OK @@ -128,45 +132,49 @@ def test_api_documents_content_format(mock_content, content_format, accept): @patch("core.services.converter_services.YdocConverter._request") -def test_api_documents_content_invalid_format(mock_request): - """Test that the content endpoint rejects invalid formats.""" +def test_api_documents_formatted_content_invalid_format(mock_request): + """Test that the convert endpoint rejects invalid formats.""" document = factories.DocumentFactory(link_reach="public") response = APIClient().get( - f"/api/v1.0/documents/{document.id!s}/content/?content_format=invalid" + f"/api/v1.0/documents/{document.id!s}/formatted-content/?content_format=invalid" ) assert response.status_code == status.HTTP_400_BAD_REQUEST mock_request.assert_not_called() @patch("core.services.converter_services.YdocConverter._request") -def test_api_documents_content_yservice_error(mock_request): +def test_api_documents_formatted_content_yservice_error(mock_request): """Test that service errors are handled properly.""" document = factories.DocumentFactory(link_reach="public") mock_request.side_effect = requests.RequestException() - response = APIClient().get(f"/api/v1.0/documents/{document.id!s}/content/") + response = APIClient().get( + f"/api/v1.0/documents/{document.id!s}/formatted-content/" + ) mock_request.assert_called_once() assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR @patch("core.services.converter_services.YdocConverter._request") -def test_api_documents_content_nonexistent_document(mock_request): +def test_api_documents_formatted_content_nonexistent_document(mock_request): """Test that accessing a nonexistent document returns 404.""" client = APIClient() response = client.get( - "/api/v1.0/documents/00000000-0000-0000-0000-000000000000/content/" + "/api/v1.0/documents/00000000-0000-0000-0000-000000000000/formatted-content/" ) assert response.status_code == status.HTTP_404_NOT_FOUND mock_request.assert_not_called() @patch("core.services.converter_services.YdocConverter._request") -def test_api_documents_content_empty_document(mock_request): +def test_api_documents_formatted_content_empty_document(mock_request): """Test that accessing an empty document returns empty content.""" document = factories.DocumentFactory(link_reach="public", content="") - response = APIClient().get(f"/api/v1.0/documents/{document.id!s}/content/") + response = APIClient().get( + f"/api/v1.0/documents/{document.id!s}/formatted-content/" + ) assert response.status_code == status.HTTP_200_OK data = response.json() 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 f4a4876c5..e9d05c577 100644 --- a/src/backend/core/tests/documents/test_api_documents_retrieve.py +++ b/src/backend/core/tests/documents/test_api_documents_retrieve.py @@ -39,7 +39,7 @@ def test_api_documents_retrieve_anonymous_public_standalone(): "collaboration_auth": True, "comment": document.link_role in ["commenter", "editor"], "cors_proxy": True, - "content": True, + "formatted_content": True, "descendants": True, "destroy": False, "duplicate": False, @@ -120,7 +120,7 @@ def test_api_documents_retrieve_anonymous_public_parent(): "comment": grand_parent.link_role in ["commenter", "editor"], "descendants": True, "cors_proxy": True, - "content": True, + "formatted_content": True, "destroy": False, "duplicate": False, # Anonymous user can't favorite a document even with read access @@ -230,7 +230,7 @@ def test_api_documents_retrieve_authenticated_unrelated_public_or_authenticated( "comment": document.link_role in ["commenter", "editor"], "descendants": True, "cors_proxy": True, - "content": True, + "formatted_content": True, "destroy": False, "duplicate": True, "favorite": True, @@ -317,7 +317,7 @@ def test_api_documents_retrieve_authenticated_public_or_authenticated_parent(rea "comment": grand_parent.link_role in ["commenter", "editor"], "descendants": True, "cors_proxy": True, - "content": True, + "formatted_content": True, "destroy": False, "duplicate": True, "favorite": True, @@ -517,7 +517,7 @@ def test_api_documents_retrieve_authenticated_related_parent(): "comment": access.role != "reader", "descendants": True, "cors_proxy": True, - "content": True, + "formatted_content": True, "destroy": access.role in ["administrator", "owner"], "duplicate": True, "favorite": True, diff --git a/src/backend/core/tests/documents/test_api_documents_trashbin.py b/src/backend/core/tests/documents/test_api_documents_trashbin.py index a8ee83689..16a1bd2d5 100644 --- a/src/backend/core/tests/documents/test_api_documents_trashbin.py +++ b/src/backend/core/tests/documents/test_api_documents_trashbin.py @@ -83,7 +83,7 @@ def test_api_documents_trashbin_format(): "descendants": False, "cors_proxy": False, "comment": False, - "content": False, + "formatted_content": False, "destroy": False, "duplicate": False, "favorite": False, diff --git a/src/backend/core/tests/test_models_documents.py b/src/backend/core/tests/test_models_documents.py index 82edf82d9..434aef1a0 100644 --- a/src/backend/core/tests/test_models_documents.py +++ b/src/backend/core/tests/test_models_documents.py @@ -165,7 +165,7 @@ def test_models_documents_get_abilities_forbidden( "collaboration_auth": False, "descendants": False, "cors_proxy": False, - "content": False, + "formatted_content": False, "destroy": False, "duplicate": False, "favorite": False, @@ -233,7 +233,7 @@ def test_models_documents_get_abilities_reader( "comment": False, "descendants": True, "cors_proxy": True, - "content": True, + "formatted_content": True, "destroy": False, "duplicate": is_authenticated, "favorite": is_authenticated, @@ -303,7 +303,7 @@ def test_models_documents_get_abilities_commenter( "children_list": True, "collaboration_auth": True, "comment": True, - "content": True, + "formatted_content": True, "descendants": True, "cors_proxy": True, "destroy": False, @@ -374,7 +374,7 @@ def test_models_documents_get_abilities_editor( "comment": True, "descendants": True, "cors_proxy": True, - "content": True, + "formatted_content": True, "destroy": False, "duplicate": is_authenticated, "favorite": is_authenticated, @@ -432,7 +432,7 @@ def test_models_documents_get_abilities_owner(django_assert_num_queries): "comment": True, "descendants": True, "cors_proxy": True, - "content": True, + "formatted_content": True, "destroy": True, "duplicate": True, "favorite": True, @@ -476,7 +476,7 @@ def test_models_documents_get_abilities_owner(django_assert_num_queries): "comment": False, "descendants": False, "cors_proxy": False, - "content": False, + "formatted_content": False, "destroy": False, "duplicate": False, "favorite": False, @@ -524,7 +524,7 @@ def test_models_documents_get_abilities_administrator(django_assert_num_queries) "comment": True, "descendants": True, "cors_proxy": True, - "content": True, + "formatted_content": True, "destroy": False, "duplicate": True, "favorite": True, @@ -582,7 +582,7 @@ def test_models_documents_get_abilities_editor_user(django_assert_num_queries): "comment": True, "descendants": True, "cors_proxy": True, - "content": True, + "formatted_content": True, "destroy": False, "duplicate": True, "favorite": True, @@ -648,7 +648,7 @@ def test_models_documents_get_abilities_reader_user( and document.link_role in ["commenter", "editor"], "descendants": True, "cors_proxy": True, - "content": True, + "formatted_content": True, "destroy": False, "duplicate": True, "favorite": True, @@ -713,7 +713,7 @@ def test_models_documents_get_abilities_commenter_user( "children_list": True, "collaboration_auth": True, "comment": True, - "content": True, + "formatted_content": True, "descendants": True, "cors_proxy": True, "destroy": False, @@ -778,7 +778,7 @@ def test_models_documents_get_abilities_preset_role(django_assert_num_queries): "comment": False, "descendants": True, "cors_proxy": True, - "content": True, + "formatted_content": True, "destroy": False, "duplicate": True, "favorite": True,