🐛(back) manage can-edit endpoint without created room in the ws (#1152)
In a scenario where the first user is editing a docs without websocket and nobody has reached the websocket server first, the y-provider service will return a 404 and we don't handle this case in the can-edit endpoint leading to a server error.
This commit is contained in:
@@ -11,6 +11,7 @@ and this project adheres to
|
|||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- 🌐(frontend) keep simple tag during export #1154
|
- 🌐(frontend) keep simple tag during export #1154
|
||||||
|
- 🐛(back) manage can-edit endpoint without created room in the ws
|
||||||
|
|
||||||
## [3.4.0] - 2025-07-09
|
## [3.4.0] - 2025-07-09
|
||||||
|
|
||||||
|
|||||||
@@ -62,10 +62,14 @@ class CollaborationService:
|
|||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
raise requests.HTTPError("Failed to get document connection info.") from e
|
raise requests.HTTPError("Failed to get document connection info.") from e
|
||||||
|
|
||||||
if response.status_code != 200:
|
if response.status_code == 200:
|
||||||
raise requests.HTTPError(
|
result = response.json()
|
||||||
f"Failed to get document connection info. Status code: {response.status_code}, "
|
return result.get("count", 0), result.get("exists", False)
|
||||||
f"Response: {response.text}"
|
|
||||||
)
|
if response.status_code == 404:
|
||||||
result = response.json()
|
return 0, False
|
||||||
return result.get("count", 0), result.get("exists", False)
|
|
||||||
|
raise requests.HTTPError(
|
||||||
|
f"Failed to get document connection info. Status code: {response.status_code}, "
|
||||||
|
f"Response: {response.text}"
|
||||||
|
)
|
||||||
|
|||||||
@@ -246,3 +246,73 @@ def test_api_documents_can_edit_websocket_server_unreachable_fallback_to_no_webs
|
|||||||
|
|
||||||
assert cache.get(f"docs:no-websocket:{document.id}") == "other_session_key"
|
assert cache.get(f"docs:no-websocket:{document.id}") == "other_session_key"
|
||||||
assert ws_resp.call_count == 1
|
assert ws_resp.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
@responses.activate
|
||||||
|
def test_api_documents_can_edit_websocket_server_room_not_found(
|
||||||
|
settings,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
When the websocket server returns a 404, the document can be updated like if the user was
|
||||||
|
not connected to the websocket.
|
||||||
|
"""
|
||||||
|
user = factories.UserFactory(with_owned_document=True)
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(user)
|
||||||
|
session_key = client.session.session_key
|
||||||
|
|
||||||
|
document = factories.DocumentFactory(users=[(user, "editor")])
|
||||||
|
|
||||||
|
settings.COLLABORATION_API_URL = "http://example.com/"
|
||||||
|
settings.COLLABORATION_SERVER_SECRET = "secret-token"
|
||||||
|
settings.COLLABORATION_WS_NOT_CONNECTED_READY_ONLY = True
|
||||||
|
endpoint_url = (
|
||||||
|
f"{settings.COLLABORATION_API_URL}get-connections/"
|
||||||
|
f"?room={document.id}&sessionKey={session_key}"
|
||||||
|
)
|
||||||
|
ws_resp = responses.get(endpoint_url, status=404)
|
||||||
|
|
||||||
|
assert cache.get(f"docs:no-websocket:{document.id}") is None
|
||||||
|
|
||||||
|
response = client.get(
|
||||||
|
f"/api/v1.0/documents/{document.id!s}/can-edit/",
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == {"can_edit": True}
|
||||||
|
|
||||||
|
assert ws_resp.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
@responses.activate
|
||||||
|
def test_api_documents_can_edit_websocket_server_room_not_found_other_already_editing(
|
||||||
|
settings,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
When the websocket server returns a 404 and another user is editing the document,
|
||||||
|
the response should be can-edit=False.
|
||||||
|
"""
|
||||||
|
user = factories.UserFactory(with_owned_document=True)
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(user)
|
||||||
|
session_key = client.session.session_key
|
||||||
|
|
||||||
|
document = factories.DocumentFactory(users=[(user, "editor")])
|
||||||
|
|
||||||
|
settings.COLLABORATION_API_URL = "http://example.com/"
|
||||||
|
settings.COLLABORATION_SERVER_SECRET = "secret-token"
|
||||||
|
settings.COLLABORATION_WS_NOT_CONNECTED_READY_ONLY = True
|
||||||
|
endpoint_url = (
|
||||||
|
f"{settings.COLLABORATION_API_URL}get-connections/"
|
||||||
|
f"?room={document.id}&sessionKey={session_key}"
|
||||||
|
)
|
||||||
|
ws_resp = responses.get(endpoint_url, status=404)
|
||||||
|
|
||||||
|
cache.set(f"docs:no-websocket:{document.id}", "other_session_key")
|
||||||
|
|
||||||
|
response = client.get(
|
||||||
|
f"/api/v1.0/documents/{document.id!s}/can-edit/",
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == {"can_edit": False}
|
||||||
|
|
||||||
|
assert ws_resp.call_count == 1
|
||||||
|
|||||||
@@ -539,6 +539,47 @@ def test_api_documents_update_websocket_server_unreachable_fallback_to_no_websoc
|
|||||||
assert ws_resp.call_count == 1
|
assert ws_resp.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
@responses.activate
|
||||||
|
def test_api_documents_update_websocket_server_room_not_found_fallback_to_no_websocket_other_users(
|
||||||
|
settings,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
When the WebSocket server does not have the room created, the logic should fallback to
|
||||||
|
no-WebSocket. If another user is already editing, the update must be denied.
|
||||||
|
"""
|
||||||
|
user = factories.UserFactory(with_owned_document=True)
|
||||||
|
client = APIClient()
|
||||||
|
client.force_login(user)
|
||||||
|
session_key = client.session.session_key
|
||||||
|
|
||||||
|
document = factories.DocumentFactory(users=[(user, "editor")])
|
||||||
|
|
||||||
|
new_document_values = serializers.DocumentSerializer(
|
||||||
|
instance=factories.DocumentFactory()
|
||||||
|
).data
|
||||||
|
new_document_values["websocket"] = False
|
||||||
|
settings.COLLABORATION_API_URL = "http://example.com/"
|
||||||
|
settings.COLLABORATION_SERVER_SECRET = "secret-token"
|
||||||
|
settings.COLLABORATION_WS_NOT_CONNECTED_READY_ONLY = True
|
||||||
|
endpoint_url = (
|
||||||
|
f"{settings.COLLABORATION_API_URL}get-connections/"
|
||||||
|
f"?room={document.id}&sessionKey={session_key}"
|
||||||
|
)
|
||||||
|
ws_resp = responses.get(endpoint_url, status=404)
|
||||||
|
|
||||||
|
cache.set(f"docs:no-websocket:{document.id}", "other_session_key")
|
||||||
|
|
||||||
|
response = client.put(
|
||||||
|
f"/api/v1.0/documents/{document.id!s}/",
|
||||||
|
new_document_values,
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
assert cache.get(f"docs:no-websocket:{document.id}") == "other_session_key"
|
||||||
|
assert ws_resp.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
@responses.activate
|
@responses.activate
|
||||||
def test_api_documents_update_force_websocket_param_to_true(settings):
|
def test_api_documents_update_force_websocket_param_to_true(settings):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user