diff --git a/posthog/api/action.py b/posthog/api/action.py index 58e1b49f6d3fd..03b88264e7c2e 100644 --- a/posthog/api/action.py +++ b/posthog/api/action.py @@ -266,131 +266,6 @@ def count(self, request: request.Request, **kwargs) -> Response: ) return Response({"count": results[0][0]}) - @action(methods=["GET"], detail=False) - def trends(self, request: request.Request, *args: Any, **kwargs: Any) -> Response: - result = self._calculate_trends(request) - return Response(result) - - @cached_function - def _calculate_trends(self, request: request.Request) -> List[Dict[str, Any]]: - team = self.team - filter = Filter(request=request, team=self.team) - if filter.insight == INSIGHT_STICKINESS or filter.shown_as == TRENDS_STICKINESS: - earliest_timestamp_func = lambda team_id: Event.objects.earliest_timestamp(team_id) - stickiness_filter = StickinessFilter( - request=request, team=team, get_earliest_timestamp=earliest_timestamp_func - ) - result = stickiness.Stickiness().run(stickiness_filter, team) - else: - result = trends.Trends().run(filter, team) - - dashboard_id = request.GET.get("from_dashboard", None) - if dashboard_id: - Insight.objects.filter(pk=dashboard_id).update(last_refresh=now()) - - return result - - @action(methods=["GET"], detail=False) - def retention(self, request: request.Request, *args: Any, **kwargs: Any) -> Response: - team = self.team - properties = request.GET.get("properties", "{}") - - try: - properties = json.loads(properties) - except json.decoder.JSONDecodeError: - raise ValidationError("Properties are unparsable!") - - data: Dict[str, Any] = {"properties": properties} - start_entity_data = request.GET.get("start_entity", None) - if start_entity_data: - entity_data = json.loads(start_entity_data) - data.update({"entites": [Entity({"id": entity_data["id"], "type": entity_data["type"]})]}) - - data.update({"date_from": "-11d"}) - filter = RetentionFilter(data=data, team=self.team) - - result = retention.Retention().run(filter, team) - return Response({"data": result}) - - @action(methods=["GET"], detail=False) - def funnel(self, request: request.Request, *args: Any, **kwargs: Any) -> Response: - team = self.team - refresh = should_refresh(request) - dashboard_id = request.GET.get("from_dashboard", None) - - filter = Filter(request=request, team=self.team) - cache_key = generate_cache_key("{}_{}".format(filter.toJSON(), team.pk)) - result = {"loading": True} - - if refresh: - cache.delete(cache_key) - else: - cached_result = get_safe_cache(cache_key) - if cached_result: - task_id = cached_result.get("task_id", None) - if not task_id: - return Response(cached_result["result"]) - else: - return Response(result) - - payload = {"filter": filter.toJSON(), "team_id": team.pk} - task = update_cache_item_task.delay(cache_key, CacheType.FUNNEL, payload) - if not task.ready(): - task_id = task.id - cache.set(cache_key, {"task_id": task_id}, 180) # task will be live for 3 minutes - - if dashboard_id: - Insight.objects.filter(pk=dashboard_id).update(last_refresh=now()) - - return Response(result) - - -def _filter_cohort_breakdown(events: QuerySet, filter: Filter) -> QuerySet: - if filter.breakdown_type == "cohort" and filter.breakdown_value != "all": - cohort = Cohort.objects.get(pk=int(cast(str, filter.breakdown_value))) - events = events.filter( - Exists( - CohortPeople.objects.filter( - cohort_id=cohort.pk, person_id=OuterRef("person_id"), version=cohort.version - ).only("id") - ) - ) - return events - - -def _filter_person_prop_breakdown(events: QuerySet, filter: Filter) -> QuerySet: - if filter.breakdown_type == "person": - events = events.filter( - Exists( - Person.objects.filter( - **{"id": OuterRef("person_id"), f"properties__{filter.breakdown}": filter.breakdown_value,} - ).only("id") - ) - ) - return events - - -def _filter_event_prop_breakdown(events: QuerySet, filter: Filter) -> QuerySet: - if filter.breakdown_type == "event": - events = events.filter(**{f"properties__{filter.breakdown}": filter.breakdown_value,}) - return events - - -def calculate_people( - team: Team, events: QuerySet, filter: Filter, request: request.Request, use_offset: bool = True -) -> QuerySet: - events = events.values("person_id").distinct() - events = _filter_cohort_breakdown(events, filter) - events = _filter_person_prop_breakdown(events, filter) - events = _filter_event_prop_breakdown(events, filter) - people = Person.objects.filter( - team=team, - id__in=[p["person_id"] for p in (events[filter.offset : filter.offset + 100] if use_offset else events)], - ) - people = base.filter_persons(team.id, request, people) # type: ignore - people = people.prefetch_related(Prefetch("persondistinctid_set", to_attr="distinct_ids_cache")) - return people - @receiver(post_save, sender=Action, dispatch_uid="hook-action-defined") def action_defined(sender, instance, created, raw, using, **kwargs): diff --git a/posthog/api/test/test_team.py b/posthog/api/test/test_team.py index 0cdd2d9ee48b0..397b1368a81f9 100644 --- a/posthog/api/test/test_team.py +++ b/posthog/api/test/test_team.py @@ -59,16 +59,6 @@ def test_cant_create_team_without_license_on_selfhosted(self): response = self.client.post("/api/projects/", {"name": "Test"}) self.assertEqual(Team.objects.count(), 1) - def test_retention_invalid_properties(self): - _, _, team = Organization.objects.bootstrap(self.user, name="New Org") - - properties = "invalid_json" - response = self.client.get(f"/api/projects/{team.pk}/actions/retention", data={"properties": properties}) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertDictEqual( - response.json(), self.validation_error_response("Properties are unparsable!", "invalid_input") - ) - def test_update_project_timezone(self): response = self.client.patch("/api/projects/@current/", {"timezone": "Europe/Istanbul"})