📈(backend) capture an event when a document is moved

When a document is moved we want to capture an event. The position and
target_document_id is added to the sent properties.
This commit is contained in:
Manuel Raynaud
2026-06-01 17:47:28 +02:00
parent 0df2d753c4
commit c91c443b08
3 changed files with 68 additions and 16 deletions
+10
View File
@@ -1076,6 +1076,16 @@ class DocumentViewSet(
defaults={"role": models.RoleChoices.OWNER},
)
posthog_capture(
PosthogEventName.DOC_MOVED,
user,
{
"position": position,
"targeted_document_id": str(target_document_id),
},
document=document,
)
return drf.response.Response(
{"message": "Document moved successfully."}, status=status.HTTP_200_OK
)
@@ -3,6 +3,7 @@ Test moving documents within the document tree via an detail action API endpoint
"""
import random
from unittest import mock
from uuid import uuid4
from django.utils import timezone
@@ -11,6 +12,7 @@ import pytest
from rest_framework.test import APIClient
from core import enums, factories, models
from core.utils.analytics import PosthogEventName
pytestmark = pytest.mark.django_db
@@ -144,10 +146,11 @@ def test_api_documents_move_authenticated_target_roles_mocked(
models.DocumentAccess.objects.create(document=target, user=user, role=target_role)
target_children = factories.DocumentFactory.create_batch(2, parent=target)
response = client.post(
f"/api/v1.0/documents/{document.id!s}/move/",
data={"target_document_id": str(target.id), "position": position},
)
with mock.patch("core.api.viewsets.posthog_capture") as mock_capture:
response = client.post(
f"/api/v1.0/documents/{document.id!s}/move/",
data={"target_document_id": str(target.id), "position": position},
)
document.refresh_from_db()
@@ -161,6 +164,14 @@ def test_api_documents_move_authenticated_target_roles_mocked(
assert response.status_code == 200
assert response.json() == {"message": "Document moved successfully."}
# The move should be tracked in PostHog
mock_capture.assert_called_once_with(
PosthogEventName.DOC_MOVED,
user,
{"position": position, "targeted_document_id": str(target.id)},
document=document,
)
match position:
case "first-child":
assert list(target.get_children()) == [document, *target_children]
@@ -207,6 +218,9 @@ def test_api_documents_move_authenticated_target_roles_mocked(
)
assert document.is_root() is True
# No event should be tracked when the move is not permitted
mock_capture.assert_not_called()
def test_api_documents_move_authenticated_no_owner_user_and_team():
"""
@@ -226,15 +240,24 @@ def test_api_documents_move_authenticated_no_owner_user_and_team():
child = factories.DocumentFactory(parent=document)
target = factories.DocumentFactory()
response = client.post(
f"/api/v1.0/documents/{document.id!s}/move/",
data={"target_document_id": str(target.id), "position": "first-sibling"},
)
with mock.patch("core.api.viewsets.posthog_capture") as mock_capture:
response = client.post(
f"/api/v1.0/documents/{document.id!s}/move/",
data={"target_document_id": str(target.id), "position": "first-sibling"},
)
assert response.status_code == 200
assert response.json() == {"message": "Document moved successfully."}
assert list(target.get_siblings()) == [document, parent, target]
# The move should be tracked in PostHog
mock_capture.assert_called_once_with(
PosthogEventName.DOC_MOVED,
user,
{"position": "first-sibling", "targeted_document_id": str(target.id)},
document=document,
)
document.refresh_from_db()
assert list(document.get_children()) == [child]
@@ -260,15 +283,24 @@ def test_api_documents_move_authenticated_no_owner_same_user():
child = factories.DocumentFactory(parent=document)
target = factories.DocumentFactory()
response = client.post(
f"/api/v1.0/documents/{document.id!s}/move/",
data={"target_document_id": str(target.id), "position": "first-sibling"},
)
with mock.patch("core.api.viewsets.posthog_capture") as mock_capture:
response = client.post(
f"/api/v1.0/documents/{document.id!s}/move/",
data={"target_document_id": str(target.id), "position": "first-sibling"},
)
assert response.status_code == 200
assert response.json() == {"message": "Document moved successfully."}
assert list(target.get_siblings()) == [document, parent, target]
# The move should be tracked in PostHog
mock_capture.assert_called_once_with(
PosthogEventName.DOC_MOVED,
user,
{"position": "first-sibling", "targeted_document_id": str(target.id)},
document=document,
)
document.refresh_from_db()
assert list(document.get_children()) == [child]
assert document.accesses.count() == 2
@@ -293,15 +325,24 @@ def test_api_documents_move_authenticated_no_owner_same_team():
child = factories.DocumentFactory(parent=document)
target = factories.DocumentFactory()
response = client.post(
f"/api/v1.0/documents/{document.id!s}/move/",
data={"target_document_id": str(target.id), "position": "first-sibling"},
)
with mock.patch("core.api.viewsets.posthog_capture") as mock_capture:
response = client.post(
f"/api/v1.0/documents/{document.id!s}/move/",
data={"target_document_id": str(target.id), "position": "first-sibling"},
)
assert response.status_code == 200
assert response.json() == {"message": "Document moved successfully."}
assert list(target.get_siblings()) == [document, parent, target]
# The move should be tracked in PostHog
mock_capture.assert_called_once_with(
PosthogEventName.DOC_MOVED,
user,
{"position": "first-sibling", "targeted_document_id": str(target.id)},
document=document,
)
document.refresh_from_db()
assert list(document.get_children()) == [child]
+1
View File
@@ -21,6 +21,7 @@ class PosthogEventName(StrEnum):
DOC_IMPORTED = "doc_imported"
DOC_FAVORITED = "doc_favorited"
DOC_AI_ACTION = "doc_ai_action"
DOC_MOVED = "doc_moved"
# DocumentAccess
DOC_ACCESS_CREATED = "doc_access_created"