mirror of
https://github.com/suitenumerique/docs.git
synced 2026-08-17 21:25:43 +02:00
📈(backend) capture an event when a document is imported
We want to capture an event when a file is imported. We add in the properties the type of file imported and if it is in the create-for-owner api call.
This commit is contained in:
@@ -492,6 +492,15 @@ class ServerCreateDocumentSerializer(serializers.Serializer):
|
||||
)
|
||||
|
||||
posthog_capture(PosthogEventName.DOC_CREATED, user, {}, document=document)
|
||||
posthog_capture(
|
||||
PosthogEventName.DOC_IMPORTED,
|
||||
user,
|
||||
{
|
||||
"content_type": mime_types.MARKDOWN,
|
||||
"create_for_owner": True,
|
||||
},
|
||||
document=document,
|
||||
)
|
||||
|
||||
if user:
|
||||
# Associate the document with the pre-existing user
|
||||
|
||||
@@ -755,6 +755,12 @@ class DocumentViewSet(
|
||||
serializer.validated_data["content"] = converted_content
|
||||
serializer.validated_data["title"] = uploaded_file.name
|
||||
logger.info("conversion ended successfully")
|
||||
|
||||
posthog_capture(
|
||||
PosthogEventName.DOC_IMPORTED,
|
||||
self.request.user,
|
||||
{"content_type": uploaded_file.content_type},
|
||||
)
|
||||
except ConversionError as err:
|
||||
logger.error("could not convert file content with error: %s", err)
|
||||
raise drf.exceptions.ValidationError(
|
||||
|
||||
@@ -330,13 +330,14 @@ def test_api_documents_children_create_with_docx_file_success(mock_convert, sett
|
||||
|
||||
parent = factories.DocumentFactory(creator=user, users=[(user, "owner")])
|
||||
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{parent.id}/children/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with mock.patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{parent.id}/children/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
assert Document.objects.count() == 2
|
||||
@@ -351,6 +352,13 @@ def test_api_documents_children_create_with_docx_file_success(mock_convert, sett
|
||||
accept=mime_types.YJS,
|
||||
)
|
||||
|
||||
# The successful conversion should be tracked in PostHog
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_IMPORTED,
|
||||
user,
|
||||
{"content_type": mime_types.DOCX},
|
||||
)
|
||||
|
||||
|
||||
@patch("core.services.converter_services.Converter.convert")
|
||||
def test_api_documents_children_create_with_docx_file_disabled(mock_convert, settings):
|
||||
@@ -370,13 +378,14 @@ def test_api_documents_children_create_with_docx_file_disabled(mock_convert, set
|
||||
|
||||
parent = factories.DocumentFactory(creator=user, users=[(user, "owner")])
|
||||
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{parent.id}/children/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with mock.patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
f"/api/v1.0/documents/{parent.id}/children/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {"file": ["file upload is not allowed"]}
|
||||
@@ -384,6 +393,9 @@ def test_api_documents_children_create_with_docx_file_disabled(mock_convert, set
|
||||
# Verify the converter was not called
|
||||
mock_convert.assert_not_called()
|
||||
|
||||
# No event should be tracked since the upload is rejected
|
||||
mock_capture.assert_not_called()
|
||||
|
||||
|
||||
def test_api_documents_children_create_with_file_max_size_exceeded(settings):
|
||||
"""
|
||||
|
||||
@@ -207,12 +207,23 @@ def test_api_documents_create_for_owner_existing(mock_convert_md):
|
||||
assert document.creator == user
|
||||
assert document.accesses.filter(user=user, role="owner").exists()
|
||||
|
||||
mock_capture.assert_called_once_with(
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_CREATED,
|
||||
user,
|
||||
{},
|
||||
document=document,
|
||||
)
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_IMPORTED,
|
||||
user,
|
||||
{
|
||||
"content_type": mime_types.MARKDOWN,
|
||||
"create_for_owner": True,
|
||||
},
|
||||
document=document,
|
||||
)
|
||||
|
||||
assert mock_capture.call_count == 2
|
||||
|
||||
assert Invitation.objects.exists() is False
|
||||
|
||||
@@ -262,12 +273,23 @@ def test_api_documents_create_for_owner_new_user(mock_convert_md):
|
||||
assert document.creator is None
|
||||
assert document.accesses.exists() is False
|
||||
|
||||
mock_capture.assert_called_once_with(
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_CREATED,
|
||||
None,
|
||||
{},
|
||||
document=document,
|
||||
)
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_IMPORTED,
|
||||
None,
|
||||
{
|
||||
"content_type": mime_types.MARKDOWN,
|
||||
"create_for_owner": True,
|
||||
},
|
||||
document=document,
|
||||
)
|
||||
|
||||
assert mock_capture.call_count == 2
|
||||
|
||||
invitation = Invitation.objects.get()
|
||||
assert invitation.email == "john.doe@example.com"
|
||||
|
||||
@@ -16,6 +16,7 @@ from core.services.converter_services import (
|
||||
ConversionError,
|
||||
ServiceUnavailableError,
|
||||
)
|
||||
from core.utils.analytics import PosthogEventName
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
@@ -60,13 +61,14 @@ def test_api_documents_create_with_docx_file_success(mock_convert, settings):
|
||||
file = BytesIO(file_content)
|
||||
file.name = "My Important Document.docx"
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
document = Document.objects.get()
|
||||
@@ -81,6 +83,21 @@ def test_api_documents_create_with_docx_file_success(mock_convert, settings):
|
||||
accept=mime_types.YJS,
|
||||
)
|
||||
|
||||
# The successful conversion should be tracked in PostHog
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_IMPORTED,
|
||||
user,
|
||||
{"content_type": mime_types.DOCX},
|
||||
)
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_CREATED,
|
||||
user,
|
||||
{},
|
||||
document=document,
|
||||
)
|
||||
|
||||
assert mock_capture.call_count == 2
|
||||
|
||||
|
||||
@patch("core.services.converter_services.Converter.convert")
|
||||
def test_api_documents_create_with_docx_file_disabled(mock_convert, settings):
|
||||
@@ -98,13 +115,14 @@ def test_api_documents_create_with_docx_file_disabled(mock_convert, settings):
|
||||
file = BytesIO(file_content)
|
||||
file.name = "My Important Document.docx"
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {"file": ["file upload is not allowed"]}
|
||||
@@ -112,6 +130,9 @@ def test_api_documents_create_with_docx_file_disabled(mock_convert, settings):
|
||||
# Verify the converter was not called
|
||||
mock_convert.assert_not_called()
|
||||
|
||||
# No event should be tracked since the upload is rejected
|
||||
mock_capture.assert_not_called()
|
||||
|
||||
|
||||
@patch("core.services.converter_services.Converter.convert")
|
||||
def test_api_documents_create_with_markdown_file_success(mock_convert, settings):
|
||||
@@ -133,13 +154,14 @@ def test_api_documents_create_with_markdown_file_success(mock_convert, settings)
|
||||
file = BytesIO(file_content)
|
||||
file.name = "readme.md"
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
document = Document.objects.get()
|
||||
@@ -154,6 +176,21 @@ def test_api_documents_create_with_markdown_file_success(mock_convert, settings)
|
||||
accept=mime_types.YJS,
|
||||
)
|
||||
|
||||
# The successful conversion should be tracked in PostHog
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_IMPORTED,
|
||||
user,
|
||||
{"content_type": mime_types.MARKDOWN},
|
||||
)
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_CREATED,
|
||||
user,
|
||||
{},
|
||||
document=document,
|
||||
)
|
||||
|
||||
assert mock_capture.call_count == 2
|
||||
|
||||
|
||||
@patch("core.services.converter_services.Converter.convert")
|
||||
def test_api_documents_create_with_file_and_explicit_title(mock_convert, settings):
|
||||
@@ -175,20 +212,36 @@ def test_api_documents_create_with_file_and_explicit_title(mock_convert, setting
|
||||
file = BytesIO(file_content)
|
||||
file.name = "Uploaded Document.docx"
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
"title": "This should be overridden",
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
"title": "This should be overridden",
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
document = Document.objects.get()
|
||||
# The filename should take precedence
|
||||
assert document.title == "Uploaded Document.docx"
|
||||
|
||||
# The successful conversion should be tracked in PostHog
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_IMPORTED,
|
||||
user,
|
||||
{"content_type": mime_types.DOCX},
|
||||
)
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_CREATED,
|
||||
user,
|
||||
{},
|
||||
document=document,
|
||||
)
|
||||
|
||||
assert mock_capture.call_count == 2
|
||||
|
||||
|
||||
def test_api_documents_create_with_empty_file(settings):
|
||||
"""
|
||||
@@ -204,18 +257,21 @@ def test_api_documents_create_with_empty_file(settings):
|
||||
file = BytesIO(b"")
|
||||
file.name = "empty.docx"
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {"file": ["The submitted file is empty."]}
|
||||
assert not Document.objects.exists()
|
||||
|
||||
mock_capture.assert_not_called()
|
||||
|
||||
|
||||
@patch("core.services.converter_services.Converter.convert")
|
||||
def test_api_documents_create_with_file_conversion_error(mock_convert, settings):
|
||||
@@ -236,18 +292,22 @@ def test_api_documents_create_with_file_conversion_error(mock_convert, settings)
|
||||
file = BytesIO(file_content)
|
||||
file.name = "corrupted.docx"
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {"file": ["Could not convert file content"]}
|
||||
assert not Document.objects.exists()
|
||||
|
||||
# No event should be tracked when the conversion fails
|
||||
mock_capture.assert_not_called()
|
||||
|
||||
|
||||
@patch("core.services.converter_services.Converter.convert")
|
||||
def test_api_documents_create_with_file_service_unavailable(mock_convert, settings):
|
||||
@@ -270,18 +330,22 @@ def test_api_documents_create_with_file_service_unavailable(mock_convert, settin
|
||||
file = BytesIO(file_content)
|
||||
file.name = "document.docx"
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {"file": ["Could not convert file content"]}
|
||||
assert not Document.objects.exists()
|
||||
|
||||
# No event should be tracked when the conversion service is unavailable
|
||||
mock_capture.assert_not_called()
|
||||
|
||||
|
||||
def test_api_documents_create_without_file_still_works():
|
||||
"""
|
||||
@@ -291,13 +355,14 @@ def test_api_documents_create_without_file_still_works():
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"title": "Regular document without file",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"title": "Regular document without file",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
document = Document.objects.get()
|
||||
@@ -305,6 +370,13 @@ def test_api_documents_create_without_file_still_works():
|
||||
assert document.content is None
|
||||
assert document.accesses.filter(role="owner", user=user).exists()
|
||||
|
||||
mock_capture.assert_called_once_with(
|
||||
PosthogEventName.DOC_CREATED,
|
||||
user,
|
||||
{},
|
||||
document=document,
|
||||
)
|
||||
|
||||
|
||||
@patch("core.services.converter_services.Converter.convert")
|
||||
def test_api_documents_create_with_file_null_value(mock_convert, settings):
|
||||
@@ -317,20 +389,27 @@ def test_api_documents_create_with_file_null_value(mock_convert, settings):
|
||||
|
||||
settings.CONVERSION_UPLOAD_ENABLED = True
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"title": "Document with null file",
|
||||
"file": None,
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"title": "Document with null file",
|
||||
"file": None,
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
document = Document.objects.get()
|
||||
assert document.title == "Document with null file"
|
||||
# Converter should not have been called
|
||||
mock_convert.assert_not_called()
|
||||
mock_capture.assert_called_once_with(
|
||||
PosthogEventName.DOC_CREATED,
|
||||
user,
|
||||
{},
|
||||
document=document,
|
||||
)
|
||||
|
||||
|
||||
@patch("core.services.converter_services.Converter.convert")
|
||||
@@ -355,13 +434,14 @@ def test_api_documents_create_with_file_preserves_content_format(
|
||||
file = BytesIO(file_content)
|
||||
file.name = "complex_document.docx"
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
document = Document.objects.get()
|
||||
@@ -369,6 +449,21 @@ def test_api_documents_create_with_file_preserves_content_format(
|
||||
# Verify the content is stored as returned by the converter
|
||||
assert document.content == converted_yjs
|
||||
|
||||
# The successful conversion should be tracked in PostHog
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_IMPORTED,
|
||||
user,
|
||||
{"content_type": mime_types.DOCX},
|
||||
)
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_CREATED,
|
||||
user,
|
||||
{},
|
||||
document=document,
|
||||
)
|
||||
|
||||
assert mock_capture.call_count == 2
|
||||
|
||||
# Verify it's valid base64 (can be decoded)
|
||||
try:
|
||||
b64decode(converted_yjs)
|
||||
@@ -396,18 +491,34 @@ def test_api_documents_create_with_file_unicode_filename(mock_convert, settings)
|
||||
file = BytesIO(file_content)
|
||||
file.name = "文档-télécharger-документ.docx"
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
document = Document.objects.get()
|
||||
assert document.title == "文档-télécharger-документ.docx"
|
||||
|
||||
# The successful conversion should be tracked in PostHog
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_IMPORTED,
|
||||
user,
|
||||
{"content_type": mime_types.DOCX},
|
||||
)
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_CREATED,
|
||||
user,
|
||||
{},
|
||||
document=document,
|
||||
)
|
||||
|
||||
assert mock_capture.call_count == 2
|
||||
|
||||
|
||||
def test_api_documents_create_with_file_max_size_exceeded(settings):
|
||||
"""
|
||||
@@ -423,17 +534,19 @@ def test_api_documents_create_with_file_max_size_exceeded(settings):
|
||||
file = BytesIO(b"a" * (10))
|
||||
file.name = "test.docx"
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
assert response.json() == {"file": ["File size exceeds the maximum limit of 0 MB."]}
|
||||
mock_capture.assert_not_called()
|
||||
|
||||
|
||||
def test_api_documents_create_with_file_extension_not_allowed(settings):
|
||||
@@ -450,13 +563,14 @@ def test_api_documents_create_with_file_extension_not_allowed(settings):
|
||||
file = BytesIO(b"fake docx content")
|
||||
file.name = "test.md"
|
||||
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {
|
||||
@@ -464,3 +578,5 @@ def test_api_documents_create_with_file_extension_not_allowed(settings):
|
||||
"File extension .md is not allowed. Allowed extensions are: ['.docx']."
|
||||
]
|
||||
}
|
||||
|
||||
mock_capture.assert_not_called()
|
||||
|
||||
@@ -18,6 +18,7 @@ from rest_framework.test import APIClient
|
||||
|
||||
from core import factories, models
|
||||
from core.services import mime_types
|
||||
from core.utils.analytics import PosthogEventName
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
@@ -283,13 +284,14 @@ def test_external_api_documents_create_with_markdown_file_success(
|
||||
file = BytesIO(file_content)
|
||||
file.name = "readme.md"
|
||||
|
||||
response = client.post(
|
||||
"/external_api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
with patch("core.api.viewsets.posthog_capture") as mock_capture:
|
||||
response = client.post(
|
||||
"/external_api/v1.0/documents/",
|
||||
{
|
||||
"file": file,
|
||||
},
|
||||
format="multipart",
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
@@ -307,6 +309,13 @@ def test_external_api_documents_create_with_markdown_file_success(
|
||||
accept=mime_types.YJS,
|
||||
)
|
||||
|
||||
# The successful conversion should be tracked in PostHog
|
||||
mock_capture.assert_any_call(
|
||||
PosthogEventName.DOC_IMPORTED,
|
||||
user_specific_sub,
|
||||
{"content_type": mime_types.MARKDOWN},
|
||||
)
|
||||
|
||||
|
||||
def test_external_api_documents_list_with_multiple_roles(
|
||||
user_token, resource_server_backend, user_specific_sub
|
||||
|
||||
@@ -17,6 +17,7 @@ class PosthogEventName(StrEnum):
|
||||
DOC_CREATED = "doc_created"
|
||||
DOC_DELETED = "doc_deleted"
|
||||
DOC_DUPLICATED = "doc_duplicated"
|
||||
DOC_IMPORTED = "doc_imported"
|
||||
USER_LOGIN = "user_login"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user