def insert_cohort_actors_into_ch(cohort: Cohort, filter_data: Dict): insight_type = filter_data.get("insight") query_builder: ActorBaseQuery if insight_type == INSIGHT_TRENDS: filter = Filter(data=filter_data, team=cohort.team) entity = get_target_entity(filter) query_builder = ClickhouseTrendsActors(cohort.team, entity, filter) elif insight_type == INSIGHT_STICKINESS: stickiness_filter = StickinessFilter(data=filter_data, team=cohort.team) entity = get_target_entity(stickiness_filter) query_builder = ClickhouseStickinessActors(cohort.team, entity, stickiness_filter) elif insight_type == INSIGHT_FUNNELS: funnel_filter = Filter(data=filter_data, team=cohort.team) if funnel_filter.correlation_person_entity: query_builder = FunnelCorrelationActors(filter=funnel_filter, team=cohort.team) else: funnel_actor_class = get_funnel_actor_class(funnel_filter) query_builder = funnel_actor_class(filter=funnel_filter, team=cohort.team) elif insight_type == INSIGHT_PATHS: path_filter = PathFilter(data=filter_data, team=cohort.team) query_builder = ClickhousePathsActors(path_filter, cohort.team, funnel_filter=None) else: if settings.DEBUG: raise ValueError( f"Insight type: {insight_type} not supported for cohort creation" ) else: capture_exception( Exception( f"Insight type: {insight_type} not supported for cohort creation" )) if query_builder.is_aggregating_by_groups: if settings.DEBUG: raise ValueError( f"Query type: Group based queries are not supported for cohort creation" ) else: capture_exception( Exception( f"Query type: Group based queries are not supported for cohort creation" )) else: query, params = query_builder.actor_query(limit_actors=False) insert_actors_into_cohort_by_query(cohort, query, params)
def people(self, request: Request, *args: Any, **kwargs: Any) -> Response: team = self.team filter = Filter(request=request) entity = get_target_entity(request) current_url = request.get_full_path() serialized_people = calculate_entity_people(team, entity, filter) current_url = request.get_full_path() next_url: Optional[str] = request.get_full_path() offset = filter.offset if len(serialized_people) > 100 and next_url: if "offset" in next_url: next_url = next_url[1:] next_url = next_url.replace("offset=" + str(offset), "offset=" + str(offset + 100)) else: next_url = request.build_absolute_uri( "{}{}offset={}".format(next_url, "&" if "?" in next_url else "?", offset + 100) ) else: next_url = None return Response( { "results": [{"people": serialized_people[0:100], "count": len(serialized_people[0:99])}], "next": next_url, "previous": current_url[1:], } )
def get_people(self, request: request.Request) -> Union[Dict[str, Any], List]: team = self.team filter = Filter(request=request) entity = get_target_entity(request) events = filter_by_type(entity=entity, team=team, filter=filter) people = calculate_people(team=team, events=events, filter=filter) serialized_people = PersonSerializer(people, context={ "request": request }, many=True).data current_url = request.get_full_path() next_url = paginated_result(serialized_people, request, filter.offset) return { "results": [{ "people": serialized_people, "count": len(serialized_people) }], "next": next_url, "previous": current_url[1:], }
def stickiness(self, request: request.Request) -> response.Response: team = cast(User, request.user).team if not team: return response.Response( { "message": "Could not retrieve team", "detail": "Could not validate team associated with user" }, status=400, ) earliest_timestamp_func = lambda team_id: Event.objects.earliest_timestamp( team_id) filter = StickinessFilter( request=request, team=team, get_earliest_timestamp=earliest_timestamp_func) target_entity = get_target_entity(request) people = self.stickiness_class().people(target_entity, filter, team, request) next_url = paginated_result(people, request, filter.offset) return response.Response({ "results": [{ "people": people, "count": len(people) }], "next": next_url })
def test_get_target_entity(self): request = lambda url: cast(Any, RequestFactory().get(url)) filter = Filter( data={ "entity_id": "$pageview", "entity_type": "events", "events": [{ "id": "$pageview", "type": "events" }], }) entity = get_target_entity(filter) assert entity.id == "$pageview" assert entity.type == "events" assert entity.math is None filter = Filter( data={ "entity_id": "$pageview", "entity_type": "events", "entity_math": "unique_group", "events": [ { "id": "$pageview", "type": "events", "math": "unique_group" }, { "id": "$pageview", "type": "events" }, ], }) entity = get_target_entity(filter) assert entity.id == "$pageview" assert entity.type == "events" assert entity.math == "unique_group"
def people(self, request: request.Request, *args: Any, **kwargs: Any) -> Response: team = self.team filter = Filter(request=request, team=self.team) entity = get_target_entity(filter) actors, serialized_actors = ClickhouseTrendsActors( team, entity, filter).get_actors() current_url = request.get_full_path() next_url: Optional[str] = request.get_full_path() offset = filter.offset if len(actors) > 100 and next_url: if "offset" in next_url: next_url = next_url[1:] next_url = next_url.replace("offset=" + str(offset), "offset=" + str(offset + 100)) else: next_url = request.build_absolute_uri("{}{}offset={}".format( next_url, "&" if "?" in next_url else "?", offset + 100)) else: next_url = None if request.accepted_renderer.format == "csv": csvrenderers.CSVRenderer.header = [ "Distinct ID", "Internal ID", "Email", "Name", "Properties" ] content = [{ "Name": get_person_name(person), "Distinct ID": person.distinct_ids[0] if person.distinct_ids else "", "Internal ID": str(person.uuid), "Email": person.properties.get("email"), "Properties": person.properties, } for person in actors if isinstance(person, Person)] return Response(content) return Response({ "results": [{ "people": serialized_actors[0:100], "count": len(serialized_actors[0:100]) }], "next": next_url, "previous": current_url[1:], })
def stickiness(self, request: request.Request) -> response.Response: team = cast(User, request.user).team if not team: return response.Response( {"message": "Could not retrieve team", "detail": "Could not validate team associated with user"}, status=400, ) filter = StickinessFilter(request=request, team=team, get_earliest_timestamp=get_earliest_timestamp) if not filter.limit: filter = filter.with_data({LIMIT: 100}) target_entity = get_target_entity(filter) people = self.stickiness_class().people(target_entity, filter, team, request) next_url = paginated_result(people, request, filter.offset) return response.Response({"results": [{"people": people, "count": len(people)}], "next": next_url})
def people(self, request: Request, *args: Any, **kwargs: Any) -> Response: # type: ignore team = self.team filter = Filter(request=request, team=self.team) entity = get_target_entity(request) current_url = request.get_full_path() serialized_people = TrendsPersonQuery(team, entity, filter).get_people() current_url = request.get_full_path() next_url: Optional[str] = request.get_full_path() offset = filter.offset if len(serialized_people) > 100 and next_url: if "offset" in next_url: next_url = next_url[1:] next_url = next_url.replace("offset=" + str(offset), "offset=" + str(offset + 100)) else: next_url = request.build_absolute_uri("{}{}offset={}".format( next_url, "&" if "?" in next_url else "?", offset + 100)) else: next_url = None if request.accepted_renderer.format == "csv": csvrenderers.CSVRenderer.header = [ "Distinct ID", "Internal ID", "Email", "Name", "Properties" ] content = [{ "Name": person.get("properties", {}).get("name"), "Distinct ID": person.get("distinct_ids", [""])[0], "Internal ID": person.get("id"), "Email": person.get("properties", {}).get("email"), "Properties": person.get("properties", {}), } for person in serialized_people] return Response(content) return Response({ "results": [{ "people": serialized_people[0:100], "count": len(serialized_people[0:100]) }], "next": next_url, "previous": current_url[1:], })
def _handle_static(self, cohort: Cohort, request: Request): if request.FILES.get("csv"): self._calculate_static_by_csv(request.FILES["csv"], cohort) else: try: filter = Filter(request=request) team = request.user.team target_entity = get_target_entity(request) if filter.shown_as == TRENDS_STICKINESS: stickiness_filter = StickinessFilter( request=request, team=team, get_earliest_timestamp=self.earliest_timestamp_func ) self._handle_stickiness_people(target_entity, cohort, stickiness_filter) else: self._handle_trend_people(target_entity, cohort, filter) except Exception as e: capture_exception(e) raise ValueError("This cohort has no conditions")
def get_people(self, request: request.Request) -> Union[Dict[str, Any], List]: team = self.team filter = Filter(request=request) entity = get_target_entity(request) events = filter_by_type(entity=entity, team=team, filter=filter) people = calculate_people(team=team, events=events, filter=filter, request=request) serialized_people = PersonSerializer(people, context={ "request": request }, many=True).data current_url = request.get_full_path() next_url = paginated_result(serialized_people, request, filter.offset) if request.accepted_renderer.format == "csv": csvrenderers.CSVRenderer.header = [ "Distinct ID", "Internal ID", "Email", "Name", "Properties" ] content = [{ "Name": person.get("properties", {}).get("name"), "Distinct ID": person.get("distinct_ids", [""])[0], "Internal ID": person["uuid"], "Email": person.get("properties", {}).get("email"), "Properties": person.get("properties", {}), } for person in serialized_people] return content return { "results": [{ "people": serialized_people, "count": len(serialized_people) }], "next": next_url, "previous": current_url[1:], }
def people(self, request: Request, *args: Any, **kwargs: Any) -> Response: team = self.team filter = Filter(request=request) entity = get_target_entity(request) # adhoc date handling. parsed differently with django orm date_from = filter.date_from or timezone.now() data = {} if filter.interval == "month": data.update( {"date_to": (date_from + relativedelta(months=1) - timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")} ) elif filter.interval == "week": data.update({"date_to": (date_from + relativedelta(weeks=1)).strftime("%Y-%m-%d %H:%M:%S")}) elif filter.interval == "hour": data.update({"date_to": date_from + timedelta(hours=1)}) elif filter.interval == "minute": data.update({"date_to": date_from + timedelta(minutes=1)}) filter = Filter(data={**filter._data, **data}) current_url = request.get_full_path() serialized_people = self._calculate_entity_people(team, entity, filter) current_url = request.get_full_path() next_url: Optional[str] = request.get_full_path() offset = filter.offset if len(serialized_people) > 100 and next_url: if "offset" in next_url: next_url = next_url[1:] next_url = next_url.replace("offset=" + str(offset), "offset=" + str(offset + 100)) else: next_url = request.build_absolute_uri( "{}{}offset={}".format(next_url, "&" if "?" in next_url else "?", offset + 100) ) else: next_url = None return Response( { "results": [{"people": serialized_people[0:100], "count": len(serialized_people[0:99])}], "next": next_url, "previous": current_url[1:], } )
def get_people(self, request: request.Request) -> Union[Dict[str, Any], List]: team = self.team filter = Filter(request=request) offset = int(request.GET.get("offset", 0)) def _calculate_people(events: QuerySet, offset: int): events = events.values("person_id").distinct() if request.GET.get( "breakdown_type" ) == "cohort" and request.GET.get("breakdown_value") != "all": events = events.filter( Exists( CohortPeople.objects.filter( cohort_id=int(request.GET["breakdown_value"]), person_id=OuterRef("person_id"), ).only("id"))) if request.GET.get("breakdown_type") == "person": events = events.filter( Exists( Person.objects.filter( **{ "id": OuterRef("person_id"), "team_id": self.team.pk, "properties__{}".format(request.GET["breakdown"]): request.GET["breakdown_value"], }).only("id"))) people = Person.objects.filter( team=team, id__in=[p["person_id"] for p in events[offset:offset + 100]]) people = people.prefetch_related( Prefetch("persondistinctid_set", to_attr="distinct_ids_cache")) return PersonSerializer(people, context={ "request": request }, many=True).data filtered_events: QuerySet = QuerySet() if request.GET.get("session"): filtered_events = (Event.objects.filter(team=team).filter( base.filter_events(team.pk, filter)).add_person_id(team.pk)) else: entity = get_target_entity(request) if entity.type == TREND_FILTER_TYPE_EVENTS: filtered_events = base.process_entity_for_events( entity, team_id=team.pk, order_by=None).filter( base.filter_events(team.pk, filter, entity)) elif entity.type == TREND_FILTER_TYPE_ACTIONS: actions = super().get_queryset() actions = actions.filter(deleted=False) try: action = actions.get(pk=entity.id) except Action.DoesNotExist: return [] filtered_events = base.process_entity_for_events( entity, team_id=team.pk, order_by=None).filter( base.filter_events(team.pk, filter, entity)) people = _calculate_people(events=filtered_events, offset=offset) current_url = request.get_full_path() next_url = paginated_result(people, request, offset) return { "results": [{ "people": people, "count": len(people) }], "next": next_url, "previous": current_url[1:] }