def calculate_funnel_correlation_persons( self, request: request.Request ) -> Dict[str, Tuple[list, Optional[str], Optional[str]]]: if request.user.is_anonymous or not self.team: return {"result": ([], None, None)} filter = Filter(request=request, data={"insight": INSIGHT_FUNNELS}, team=self.team) if not filter.correlation_person_limit: filter = filter.with_data({FUNNEL_CORRELATION_PERSON_LIMIT: 100}) base_uri = request.build_absolute_uri("/") actors, serialized_actors = FunnelCorrelationActors( filter=filter, team=self.team, base_uri=base_uri ).get_actors() _should_paginate = should_paginate(actors, filter.correlation_person_limit) next_url = ( format_query_params_absolute_url( request, filter.correlation_person_offset + filter.correlation_person_limit, offset_alias=FUNNEL_CORRELATION_PERSON_OFFSET, limit_alias=FUNNEL_CORRELATION_PERSON_LIMIT, ) if _should_paginate else None ) initial_url = format_query_params_absolute_url(request, 0) # cached_function expects a dict with the key result return {"result": (serialized_actors, next_url, initial_url)}
def persons(self, request: Request, **kwargs) -> Response: cohort: Cohort = self.get_object() team = self.team filter = Filter(request=request, team=self.team) is_csv_request = self.request.accepted_renderer.format == "csv" if is_csv_request: filter = filter.with_data({LIMIT: CSV_EXPORT_LIMIT, OFFSET: 0}) elif not filter.limit: filter = filter.with_data({LIMIT: 100}) query, params = PersonQuery(filter, team.pk, cohort=cohort).get_query() raw_result = sync_execute(query, params) actor_ids = [row[0] for row in raw_result] actors, serialized_actors = get_people(team.pk, actor_ids) _should_paginate = should_paginate(actors, filter.limit) next_url = format_query_params_absolute_url( request, filter.offset + filter.limit) if _should_paginate else None previous_url = (format_query_params_absolute_url( request, filter.offset - filter.limit) if filter.offset - filter.limit >= 0 else None) return Response({ "results": serialized_actors, "next": next_url, "previous": previous_url })
def calculate_path_persons( self, request: Request ) -> Dict[str, Tuple[list, Optional[str], Optional[str]]]: if request.user.is_anonymous or not self.team: return {"result": ([], None, None)} filter = PathFilter(request=request, data={"insight": INSIGHT_PATHS}, team=self.team) funnel_filter = None funnel_filter_data = request.GET.get( "funnel_filter") or request.data.get("funnel_filter") if funnel_filter_data: if isinstance(funnel_filter_data, str): funnel_filter_data = json.loads(funnel_filter_data) funnel_filter = Filter(data={ "insight": INSIGHT_FUNNELS, **funnel_filter_data }, team=self.team) people, should_paginate = ClickhousePathsPersons( filter, self.team, funnel_filter=funnel_filter).run() limit = filter.limit or 100 next_url = format_query_params_absolute_url( request, filter.offset + limit) if should_paginate else None initial_url = format_query_params_absolute_url(request, 0) # cached_function expects a dict with the key result return {"result": (people, next_url, initial_url)}
def persons(self, request: Request, **kwargs) -> Response: cohort: Cohort = self.get_object() team = self.team filter = Filter(request=request, team=self.team) if not filter.limit: filter = filter.with_data({LIMIT: 100}) raw_result = sync_execute( GET_STATIC_COHORTPEOPLE_BY_COHORT_ID if cohort.is_static else GET_COHORTPEOPLE_BY_COHORT_ID, { "team_id": team.pk, "cohort_id": cohort.pk, "limit": filter.limit, "offset": filter.offset }, ) actor_ids = [row[0] for row in raw_result] actors, serialized_actors = get_people(team.pk, actor_ids) _should_paginate = should_paginate(actors, filter.limit) next_url = format_query_params_absolute_url( request, filter.offset + filter.limit) if _should_paginate else None previous_url = (format_query_params_absolute_url( request, filter.offset - filter.limit) if filter.offset - filter.limit >= 0 else None) return Response({ "results": serialized_actors, "next": next_url, "previous": previous_url })
def _return_activity_page(activity_page: ActivityPage, limit: int, page: int, request: request.Request) -> Response: return Response( { "results": ActivityLogSerializer(activity_page.results, many=True,).data, "next": format_query_params_absolute_url(request, page + 1, limit, offset_alias="page") if activity_page.has_next else None, "previous": format_query_params_absolute_url(request, page - 1, limit, offset_alias="page") if activity_page.has_previous else None, "total_count": activity_page.total_count, }, status=status.HTTP_200_OK, )
def run(self) -> Dict[str, Any]: from posthog.api.person import PersonSerializer distinct_id, start_time, snapshots = self.get_snapshot_data() # Apply limit and offset after decompressing to account for non-fully formed chunks. snapshots_subset = snapshots[self._offset:(self._offset + self._limit)] duration = 0 if len(snapshots) > 1: duration = get_milliseconds_between_dates( datetime.fromtimestamp(snapshots[-1].get("timestamp", 0) / 1000.0), datetime.fromtimestamp(snapshots[0].get("timestamp", 0) / 1000.0), ) has_next = len(snapshots) > (self._offset + self._limit + 1) next_url = (format_query_params_absolute_url( self._request, self._offset + self._limit, self._limit) if has_next else None) person = (PersonSerializer( Person.objects.get(team=self._team, persondistinctid__distinct_id=distinct_id)).data if distinct_id else None) return { "snapshots": snapshots_subset, "person": person, "start_time": start_time, "next": next_url, "duration": duration, }
def calculate_funnel_persons( self, request: request.Request ) -> Dict[str, Tuple[list, Optional[str], Optional[str]]]: if request.user.is_anonymous or not self.team: return {"result": ([], None, None)} filter = Filter(request=request, data={"insight": INSIGHT_FUNNELS}, team=self.team) if not filter.limit: filter = filter.with_data({LIMIT: 100}) funnel_actor_class = get_funnel_actor_class(filter) actors, serialized_actors = funnel_actor_class(filter, self.team).get_actors() _should_paginate = should_paginate(actors, filter.limit) next_url = format_query_params_absolute_url(request, filter.offset + filter.limit) if _should_paginate else None initial_url = format_query_params_absolute_url(request, 0) # cached_function expects a dict with the key result return {"result": (serialized_actors, next_url, initial_url)}
def get_snapshots(self) -> RecordingSnapshots: all_recording_snapshots = [event.snapshot_data for event in list(self._query_recording_snapshots())] paginated_chunks = paginate_chunk_decompression( self._team.pk, self._session_recording_id, all_recording_snapshots, self._limit, self._offset ) next_url = ( format_query_params_absolute_url(self._request, self._offset + self._limit, self._limit) if paginated_chunks.has_next else None ) return RecordingSnapshots(next=next_url, snapshots=paginated_chunks.paginated_list)
def calculate_funnel_persons( self, request: Request ) -> Dict[str, Tuple[list, Optional[str], Optional[str]]]: if request.user.is_anonymous or not self.team: return {"result": ([], None, None)} filter = Filter(request=request, data={"insight": INSIGHT_FUNNELS}, team=self.team) funnel_class: Callable = ClickhouseFunnelPersons if filter.funnel_viz_type == FunnelVizType.TRENDS: funnel_class = ClickhouseFunnelTrendsPersons people, should_paginate = funnel_class(filter, self.team).run() limit = filter.limit if filter.limit else 100 next_url = format_query_params_absolute_url( request, filter.offset + limit) if should_paginate else None initial_url = format_query_params_absolute_url(request, 0) # cached_function expects a dict with the key result return {"result": (people, next_url, initial_url)}
def calculate_funnel_correlation_persons( self, request: Request ) -> Dict[str, Tuple[list, Optional[str], Optional[str]]]: if request.user.is_anonymous or not self.team: return {"result": ([], None, None)} filter = Filter(request=request, data={"insight": INSIGHT_FUNNELS}, team=self.team) people, should_paginate = FunnelCorrelationPersons( filter=filter, team=self.team).run() limit = filter.correlation_person_limit if filter.correlation_person_limit else 100 next_url = (format_query_params_absolute_url( request, filter.correlation_person_offset + limit, offset_alias=FUNNEL_CORRELATION_PERSON_OFFSET, limit_alias=FUNNEL_CORRELATION_PERSON_LIMIT, ) if should_paginate else None) initial_url = format_query_params_absolute_url(request, 0) # cached_function expects a dict with the key result return {"result": (people, next_url, initial_url)}
def test_format_query_params_absolute_url(self): build_req = HttpRequest() build_req.META = {"HTTP_HOST": "www.testserver"} test_to_expected: list = [ (None, (50, None), "http://www.testserver?offset=50"), (None, (50, None), "http://www.testserver?offset=50"), (None, (None, 50), "http://www.testserver?limit=50"), (None, (50, 100), "http://www.testserver?offset=50&limit=100"), (None, (None, None), "http://www.testserver"), ("http://www.testserver?offset=20", (50, None), "http://www.testserver?offset=50"), ("http://www.testserver?limit=20", (None, 50), "http://www.testserver?limit=50"), ("http://www.testserver?offset=20&limit=20", (50, 50), "http://www.testserver?offset=50&limit=50"), # test with alias (None, (50, None, "off2", "lim2"), "http://www.testserver?off2=50" ), (None, (50, None, "off2", "lim2"), "http://www.testserver?off2=50"), (None, (None, 50, "off2", "lim2"), "http://www.testserver?lim2=50"), (None, (50, 100, "off2", "lim2"), "http://www.testserver?off2=50&lim2=100"), (None, (None, None, "off2", "lim2"), "http://www.testserver"), ("http://www.testserver?off2=20", (50, None, "off2", "lim2"), "http://www.testserver?off2=50"), ("http://www.testserver?lim2=20", (None, 50, "off2", "lim2"), "http://www.testserver?lim2=50"), ( "http://www.testserver?off2=20&lim2=20", (50, 50, "off2", "lim2"), "http://www.testserver?off2=50&lim2=50", ), ] for start_url, params, expected in test_to_expected: self.assertEqual( expected, format_query_params_absolute_url(Request(build_req, start_url), *params))
def snapshots(self, request: request.Request, **kwargs): session_recording_id = kwargs["pk"] filter = Filter(request=request) limit = filter.limit if filter.limit else DEFAULT_RECORDING_CHUNK_LIMIT offset = filter.offset if filter.offset else 0 session_recording_snapshot_data = self._get_session_recording_snapshots( request, session_recording_id, limit, offset) if session_recording_snapshot_data.snapshot_data_by_window_id == {}: raise exceptions.NotFound("Snapshots not found") next_url = (format_query_params_absolute_url(request, offset + limit, limit) if session_recording_snapshot_data.has_next else None) return response.Response({ "result": { "next": next_url, "snapshot_data_by_window_id": session_recording_snapshot_data.snapshot_data_by_window_id, } })