Skip to content

Commit 4ebbf45

Browse files
sakcecursoragent
andauthored
chore: add activity logging to Endpoints backend (#39863)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
1 parent 6278948 commit 4ebbf45

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

posthog/models/activity_logging/activity_log.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"EventDefinition",
3737
"PropertyDefinition",
3838
"Notebook",
39+
"Endpoint",
3940
"Dashboard",
4041
"Replay",
4142
"Experiment",

products/endpoints/backend/api.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from django.shortcuts import get_object_or_404
66

77
from django_filters.rest_framework import DjangoFilterBackend
8+
from loginas.utils import is_impersonated_session
89
from pydantic import BaseModel
910
from rest_framework import status, viewsets
1011
from rest_framework.exceptions import Throttled, ValidationError
@@ -40,6 +41,7 @@
4041
from posthog.hogql_queries.hogql_query_runner import HogQLQueryRunner
4142
from posthog.hogql_queries.query_runner import BLOCKING_EXECUTION_MODES
4243
from posthog.models import User
44+
from posthog.models.activity_logging.activity_log import Detail, changes_between, log_activity
4345
from posthog.rate_limit import APIQueriesBurstThrottle, APIQueriesSustainedThrottle
4446
from posthog.schema_migrations.upgrade import upgrade
4547
from posthog.types import InsightQueryNode
@@ -156,6 +158,18 @@ def create(self, request: Request, *args, **kwargs) -> Response:
156158
is_active=data.is_active if data.is_active is not None else True,
157159
)
158160

161+
# Activity log: created
162+
log_activity(
163+
organization_id=self.organization.id,
164+
team_id=self.team.id,
165+
user=cast(User, request.user),
166+
was_impersonated=is_impersonated_session(request),
167+
item_id=str(endpoint.id),
168+
scope="Endpoint",
169+
activity="created",
170+
detail=Detail(name=endpoint.name),
171+
)
172+
159173
return Response(
160174
{
161175
"id": str(endpoint.id),
@@ -183,6 +197,11 @@ def create(self, request: Request, *args, **kwargs) -> Response:
183197
def update(self, request: Request, name=None, *args, **kwargs) -> Response:
184198
"""Update an existing endpoint."""
185199
endpoint = get_object_or_404(Endpoint, team=self.team, name=name)
200+
# Capture a snapshot for diffing
201+
try:
202+
before_update = Endpoint.objects.get(pk=endpoint.id)
203+
except Endpoint.DoesNotExist:
204+
before_update = None
186205

187206
upgraded_query = upgrade(request.data)
188207
data = self.get_model(upgraded_query, EndpointRequest)
@@ -200,6 +219,19 @@ def update(self, request: Request, name=None, *args, **kwargs) -> Response:
200219

201220
endpoint.save()
202221

222+
# Activity log: updated with field diffs
223+
changes = changes_between("Endpoint", previous=before_update, current=endpoint)
224+
log_activity(
225+
organization_id=self.organization.id,
226+
team_id=self.team.id,
227+
user=cast(User, request.user),
228+
was_impersonated=is_impersonated_session(request),
229+
item_id=str(endpoint.id),
230+
scope="Endpoint",
231+
activity="updated",
232+
detail=Detail(name=endpoint.name, changes=changes),
233+
)
234+
203235
return Response(
204236
{
205237
"id": str(endpoint.id),

products/endpoints/backend/tests/test_endpoint.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from posthog.schema import EndpointLastExecutionTimesRequest
1010

11+
from posthog.models.activity_logging.activity_log import ActivityLog
1112
from posthog.models.insight_variable import InsightVariable
1213
from posthog.models.team import Team
1314
from posthog.models.user import User
@@ -61,6 +62,14 @@ def test_create_endpoint(self):
6162
self.assertEqual(endpoint.query, self.sample_query)
6263
self.assertEqual(endpoint.created_by, self.user)
6364

65+
# Activity log created
66+
logs = ActivityLog.objects.filter(team_id=self.team.id, scope="Endpoint", activity="created")
67+
self.assertEqual(logs.count(), 1, list(logs.values("activity", "scope", "item_id")))
68+
log = logs.latest("created_at")
69+
self.assertEqual(log.item_id, str(endpoint.id))
70+
assert log.detail is not None
71+
self.assertEqual(log.detail.get("name"), "test_query")
72+
6473
def test_update_endpoint(self):
6574
"""Test updating an existing endpoint."""
6675
endpoint = Endpoint.objects.create(
@@ -107,6 +116,18 @@ def test_update_endpoint(self):
107116
self.assertEqual(endpoint.description, "Updated description")
108117
self.assertFalse(endpoint.is_active)
109118

119+
# Activity log updated with changes
120+
logs = ActivityLog.objects.filter(
121+
team_id=self.team.id, scope="Endpoint", activity="updated", item_id=str(endpoint.id)
122+
)
123+
self.assertEqual(logs.count(), 1, list(logs.values("activity", "detail")))
124+
log = logs.latest("created_at")
125+
assert log.detail is not None
126+
changes = log.detail.get("changes", [])
127+
changed_fields = {c.get("field") for c in changes}
128+
self.assertIn("description", changed_fields)
129+
self.assertIn("is_active", changed_fields)
130+
110131
def test_delete_endpoint(self):
111132
"""Test deleting a endpoint."""
112133
Endpoint.objects.create(

0 commit comments

Comments
 (0)