mirror of
https://github.com/suitenumerique/docs.git
synced 2026-09-05 17:27:48 +02:00
✨(backend) serve documents/{id}/formatted-content/ from yhub
The formatted-content endpoint was using the `document.content` to fetch the ydoc from s3, we want to move from this usage to using yhub to retrieve the content, so yhub is becoming our source of thruth.
This commit is contained in:
@@ -20,6 +20,7 @@ and this project adheres to
|
||||
- ✨(backend) call YHubService to seed initial document content
|
||||
- ✨(collaboration) add a get-ydoc endpoint on yhub
|
||||
- ✨(backend) duplicate a document through the collaboration server
|
||||
- ✨(backend) serve `documents/{id}/formatted-content/` from yhub
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
# pylint: disable=too-many-lines
|
||||
|
||||
import base64
|
||||
import ipaddress
|
||||
import json
|
||||
import logging
|
||||
@@ -2437,15 +2436,24 @@ class DocumentViewSet(
|
||||
"Invalid format. Must be one of: json, markdown, html"
|
||||
)
|
||||
|
||||
# Get the base64 content from the document
|
||||
# Get the content from the collaboration server, it is the source of
|
||||
# truth for it
|
||||
try:
|
||||
update = YHubService(user=request.user).get_ydoc(document)
|
||||
except YHubError as e:
|
||||
logger.error("Error getting content for document %s: %s", pk, e)
|
||||
return drf_response.Response(
|
||||
{"error": "Failed to get document content"},
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
|
||||
content = None
|
||||
base64_content = document.content
|
||||
if base64_content is not None:
|
||||
if update is not None:
|
||||
# Convert using the y-provider service
|
||||
try:
|
||||
yprovider = Converter()
|
||||
result = yprovider.convert(
|
||||
base64.b64decode(base64_content),
|
||||
update,
|
||||
mime_types.YJS,
|
||||
{
|
||||
"markdown": mime_types.MARKDOWN,
|
||||
|
||||
@@ -11,10 +11,30 @@ from rest_framework import status
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from core import factories
|
||||
from core.services.yhub_services import (
|
||||
ServiceUnavailableError as YHubServiceUnavailableError,
|
||||
)
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, name="mock_yhub")
|
||||
def mock_yhub_fixture():
|
||||
"""
|
||||
The content of a document is held by the collaboration server.
|
||||
|
||||
It stands for a server holding the very content the factories gave the
|
||||
documents, which is what an editor connected to it would have saved.
|
||||
"""
|
||||
|
||||
def get_ydoc(document):
|
||||
return base64.b64decode(document.content) if document.content else None
|
||||
|
||||
with patch("core.api.viewsets.YHubService") as mock_service:
|
||||
mock_service.return_value.get_ydoc.side_effect = get_ydoc
|
||||
yield mock_service
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"reach, role",
|
||||
[
|
||||
@@ -182,3 +202,46 @@ def test_api_documents_formatted_content_empty_document(mock_request):
|
||||
assert data["title"] == document.title
|
||||
assert data["content"] is None
|
||||
mock_request.assert_not_called()
|
||||
|
||||
|
||||
@patch("core.services.converter_services.YdocConverter.convert")
|
||||
def test_api_documents_formatted_content_from_collaboration_server(
|
||||
mock_content, mock_yhub
|
||||
):
|
||||
"""The content converted is the one held by the collaboration server."""
|
||||
document = factories.DocumentFactory(link_reach="public")
|
||||
mock_content.return_value = {"some": "data"}
|
||||
# what the collaboration server holds, edited since Django last saw it
|
||||
mock_yhub.return_value.get_ydoc.side_effect = None
|
||||
mock_yhub.return_value.get_ydoc.return_value = b"\x01\x02edited update"
|
||||
|
||||
response = APIClient().get(
|
||||
f"/api/v1.0/documents/{document.id!s}/formatted-content/"
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
mock_yhub.return_value.get_ydoc.assert_called_once_with(document)
|
||||
mock_content.assert_called_once_with(
|
||||
b"\x01\x02edited update",
|
||||
"application/vnd.yjs.doc",
|
||||
"application/json",
|
||||
)
|
||||
|
||||
|
||||
@patch("core.services.converter_services.YdocConverter.convert")
|
||||
def test_api_documents_formatted_content_collaboration_server_error(
|
||||
mock_content, mock_yhub
|
||||
):
|
||||
"""A content the collaboration server cannot serve should answer a 500."""
|
||||
document = factories.DocumentFactory(link_reach="public")
|
||||
mock_yhub.return_value.get_ydoc.side_effect = YHubServiceUnavailableError(
|
||||
"Failed to connect to the yhub service"
|
||||
)
|
||||
|
||||
response = APIClient().get(
|
||||
f"/api/v1.0/documents/{document.id!s}/formatted-content/"
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
assert response.json() == {"error": "Failed to get document content"}
|
||||
mock_content.assert_not_called()
|
||||
|
||||
Reference in New Issue
Block a user