def city_gis(request, format=None): """ Available endpoints: `Connection`, `Event`, `Monitoring`, `Position` """ return Response({ 'connections': request.build_absolute_uri('connections'), 'events': request.build_absolute_uri('events'), 'monitoring': request.build_absolute_uri('monitoring'), 'positions': request.build_absolute_uri('positions'), })
def create(self, request, *args, **kwargs): try: validate_password(request.data.get('password')) except ValidationError as e: print('User creation failed: password did not validate.', e) return Response({'message': '\n'.join(e.messages)}, 400) try: User.objects.get(username=request.data.get('username')) return Response({'message': 'User already exists'}, 400) except ObjectDoesNotExist: pass response = super().create(request, *args, **kwargs) # Prep to send email. user = User.objects.get(username=response.data['username']) url = reverse('user-register', kwargs={'pk': user.id}) registration_url = request.build_absolute_uri(url) try: send_registration_email_to_user.delay(registration_url, user.registration_code, user.email) except Exception as e: print('Error sending mail', e) return Response({'description': 'User created. Registration Needed'}, 201)
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 create(self, request, *args, **kwargs): try: validate_password(request.data.get('password')) except ValidationError as e: logger.error('User creation failed: password did not validate.') return Response({ 'message': '\n'.join(e.messages) }, 400) try: User.objects.get(username=request.data.get('username')) logger.error('User creation failed: user already exists.') return Response({ 'message': 'User already exists' }, 400) except ObjectDoesNotExist: pass response = super().create(request, *args, **kwargs) # Prep to send email. user = User.objects.get(username=response.data['username']) url = reverse('api:user-register', kwargs={'pk': user.id}) registration_url = request.build_absolute_uri(url) try: send_registration_email_to_user.delay(registration_url, user.registration_code, user.email) except Exception as e: logger.error('An exception occurred while creating user. %s' % e) return Response({ 'description': 'User created. Registration Needed' }, 201)
def list(self, request: request.Request, *args: Any, **kwargs: Any) -> response.Response: queryset = self.get_queryset() monday = now() + timedelta(days=-now().weekday()) events = queryset.filter( timestamp__gte=monday.replace(hour=0, minute=0, second=0))[0:101] if len(events) < 101: events = queryset[0:101] prefetched_events = self._prefetch_events([event for event in events]) path = request.get_full_path() reverse = request.GET.get("orderBy", "-timestamp") != "-timestamp" if len(events) > 100: next_url: Optional[str] = request.build_absolute_uri( "{}{}{}={}".format( path, "&" if "?" in path else "?", "after" if reverse else "before", events[99].timestamp.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), )) else: next_url = None return response.Response({ "next": next_url, "results": EventSerializer(prefetched_events, many=True).data, })
def list(self, request: request.Request, *args: Any, **kwargs: Any) -> response.Response: queryset = self.get_queryset() monday = now() + timedelta(days=-now().weekday()) events = queryset.filter( timestamp__gte=monday.replace(hour=0, minute=0, second=0))[0:101] if len(events) < 101: events = queryset[0:101] prefetched_events = self._prefetch_events([event for event in events]) path = request.get_full_path() reverse = request.GET.get('orderBy', '-timestamp') != '-timestamp' if len(events) > 100: next_url: Optional[str] = request.build_absolute_uri( '{}{}{}={}'.format( path, '&' if '?' in path else '?', 'after' if reverse else 'before', events[99].timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ'))) else: next_url = None return response.Response({ 'next': next_url, 'results': EventSerializer(prefetched_events, many=True).data })
def city_gis(request, format=None): """ Available endpoints: `Connection`, `Event`, `Monitoring`, `Position` """ return Response( { 'connections': request.build_absolute_uri('connections'), 'events': request.build_absolute_uri('events'), 'monitoring': request.build_absolute_uri('monitoring'), 'positions': request.build_absolute_uri('positions'), } )
def calculate_retention(self, request: request.Request) -> Dict[str, Any]: team = self.team data = {} if not request.GET.get("date_from"): data.update({"date_from": "-11d"}) filter = RetentionFilter(data=data, request=request, team=self.team) base_uri = request.build_absolute_uri("/") result = ClickhouseRetention(base_uri=base_uri).run(filter, team) return {"result": result}
def _build_next_url(self, request: request.Request, last_event_timestamp: datetime) -> str: params = request.GET.dict() reverse = request.GET.get("orderBy", "-timestamp") != "-timestamp" timestamp = last_event_timestamp.astimezone().isoformat() if reverse: params["after"] = timestamp else: params["before"] = timestamp return request.build_absolute_uri(f"{request.path}?{urllib.parse.urlencode(params)}")
def add_submission_with(request, username, id_string): import uuid import requests from django.template import loader, Context from dpath import util as dpath_util from dict2xml import dict2xml def geopoint_xpaths(username, id_string): d = DataDictionary.objects.get(user__username__iexact=username, id_string__exact=id_string) return [ e.get_abbreviated_xpath() for e in d.get_survey_elements() if e.bind.get(u'type') == u'geopoint' ] value = request.GET.get('coordinates') xpaths = geopoint_xpaths(username, id_string) xml_dict = {} for path in xpaths: dpath_util.new(xml_dict, path, value) context = { 'username': username, 'id_string': id_string, 'xml_content': dict2xml(xml_dict) } instance_xml = loader.get_template("instance_add.xml")\ .render(Context(context)) url = settings.ENKETO_API_INSTANCE_IFRAME_URL return_url = reverse('thank_you_submission', kwargs={ "username": username, "id_string": id_string }) if settings.DEBUG: openrosa_url = "https://dev.formhub.org/{}".format(username) else: openrosa_url = request.build_absolute_uri("/{}".format(username)) payload = { 'return_url': return_url, 'form_id': id_string, 'server_url': openrosa_url, 'instance': instance_xml, 'instance_id': uuid.uuid4().hex } r = requests.post(url, data=payload, auth=(settings.ENKETO_API_TOKEN, ''), verify=False) return HttpResponse(r.text, content_type='application/json')
def authenticate(self, request: request.Request): # if the Origin is different, the only authentication method should be temporary_token # This happens when someone is trying to create actions from the editor on their own website if request.headers.get('Origin') and request.headers['Origin'] not in request.build_absolute_uri('/'): if not request.GET.get('temporary_token'): raise AuthenticationFailed(detail='No token') if request.GET.get('temporary_token'): user = User.objects.filter(temporary_token=request.GET.get('temporary_token')) if not user.exists(): raise AuthenticationFailed(detail='User doesnt exist') return (user.first(), None) return None
def format_next_url(request: request.Request, offset: int, page_size: int): next_url = request.get_full_path() if not next_url: return None if "offset" in next_url: next_url = next_url[1:] next_url = next_url.replace("offset=" + str(offset), "offset=" + str(offset + page_size)) else: next_url = request.build_absolute_uri("{}{}offset={}".format( next_url, "&" if "?" in next_url else "?", offset + page_size)) return next_url
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 paginated_result(entites: Union[List[Dict[str, Any]], ReturnDict], request: request.Request, offset: int = 0) -> Optional[str]: next_url: Optional[str] = request.get_full_path() if len(entites) > 99 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 next_url
def authenticate(self, request: request.Request): # if the Origin is different, the only authentication method should be temporary_token # This happens when someone is trying to create actions from the editor on their own website if request.headers.get('Origin') and request.headers['Origin'] not in request.build_absolute_uri('/'): if not request.GET.get('temporary_token'): raise AuthenticationFailed(detail="""No temporary_token set. That means you're either trying to access this API from a different site, or it means your proxy isn\'t sending the correct headers. See https://github.com/PostHog/posthog/wiki/Running-behind-a-proxy for more information. """) if request.GET.get('temporary_token'): user = User.objects.filter(temporary_token=request.GET.get('temporary_token')) if not user.exists(): raise AuthenticationFailed(detail='User doesnt exist') return (user.first(), None) return None
def add_submission_with(request, username, id_string): import uuid import requests from django.template import loader, Context from dpath import util as dpath_util from dict2xml import dict2xml def geopoint_xpaths(username, id_string): d = DataDictionary.objects.get( user__username__iexact=username, id_string__exact=id_string) return [e.get_abbreviated_xpath() for e in d.get_survey_elements() if e.bind.get(u'type') == u'geopoint'] value = request.GET.get('coordinates') xpaths = geopoint_xpaths(username, id_string) xml_dict = {} for path in xpaths: dpath_util.new(xml_dict, path, value) context = {'username': username, 'id_string': id_string, 'xml_content': dict2xml(xml_dict)} instance_xml = loader.get_template("instance_add.xml")\ .render(Context(context)) url = settings.ENKETO_API_INSTANCE_IFRAME_URL return_url = reverse('thank_you_submission', kwargs={"username": username, "id_string": id_string}) if settings.DEBUG: openrosa_url = "https://dev.formhub.org/{}".format(username) else: openrosa_url = request.build_absolute_uri("/{}".format(username)) payload = {'return_url': return_url, 'form_id': id_string, 'server_url': openrosa_url, 'instance': instance_xml, 'instance_id': uuid.uuid4().hex} r = requests.post(url, data=payload, auth=(settings.ENKETO_API_TOKEN, ''), verify=False) return HttpResponse(r.text, content_type='application/json')
def retention(self, request: request.Request) -> response.Response: display = request.GET.get("display", None) 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 = RetentionFilter(request=request, team=team) base_uri = request.build_absolute_uri("/") if display == TRENDS_TABLE: people = self.retention_class(base_uri=base_uri).actors_in_period(filter, team) else: people = self.retention_class(base_uri=base_uri).actors(filter, team) next_url = paginated_result(people, request, filter.offset) return response.Response({"result": people, "next": next_url})
def format_paginated_url(request: request.Request, offset: int, page_size: int, mode=PaginationMode.next): result = request.get_full_path() if not result: return None new_offset = offset - page_size if mode == PaginationMode.previous else offset + page_size if new_offset < 0: return None if "offset" in result: result = result[1:] result = result.replace(f"offset={offset}", f"offset={new_offset}") else: result = request.build_absolute_uri("{}{}offset={}".format( result, "&" if "?" in result else "?", new_offset)) return result
def authenticate(self, request: request.Request): # if the Origin is different, the only authentication method should be temporary_token # This happens when someone is trying to create actions from the editor on their own website if ( request.headers.get("Origin") and urlsplit(request.headers["Origin"]).netloc not in urlsplit(request.build_absolute_uri("/")).netloc ): if not request.GET.get("temporary_token"): raise AuthenticationFailed( detail="No temporary_token set. " + "That means you're either trying to access this API from a different site, " + "or it means your proxy isn't sending the correct headers. " + "See https://posthog.com/docs/deployment/running-behind-proxy for more information." ) if request.GET.get("temporary_token"): user_model = apps.get_model(app_label="posthog", model_name="User") user = user_model.objects.filter(temporary_token=request.GET.get("temporary_token")) if not user.exists(): raise AuthenticationFailed(detail="User doesnt exist") return (user.first(), None) return None
def list(self, request: request.Request, *args: Any, **kwargs: Any) -> response.Response: is_csv_request = self.request.accepted_renderer.format == "csv" monday = now() + timedelta(days=-now().weekday()) # Don't allow events too far into the future queryset = self.get_queryset().filter(timestamp__lte=now() + timedelta(seconds=5)) next_url: Optional[str] = None if is_csv_request: events = queryset[:self.CSV_EXPORT_LIMIT] else: events = queryset.filter(timestamp__gte=monday.replace( hour=0, minute=0, second=0))[:101] if len(events) < 101: events = queryset[:101] path = request.get_full_path() reverse = request.GET.get("orderBy", "-timestamp") != "-timestamp" if len(events) > 100: next_url = request.build_absolute_uri("{}{}{}={}".format( path, "&" if "?" in path else "?", "after" if reverse else "before", events[99].timestamp.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), )) events = self.paginator.paginate_queryset( events, request, view=self) # type: ignore prefetched_events = self._prefetch_events(list(events)) return response.Response({ "next": next_url, "results": EventSerializer(prefetched_events, many=True, context={ "format": self.request.accepted_renderer.format }).data, })
def get(self, request): print(request.build_absolute_uri().split('/?redirect=')[1]) target_url = request.build_absolute_uri().split('/?redirect=')[1] return redirect(target_url)
def people(self, request: request.Request, *args: Any, **kwargs: Any) -> Response: team = request.user.team_set.get() filter = Filter(request=request) offset = int(request.GET.get("offset", 0)) def _calculate_people(events: QuerySet, offset: int): shown_as = request.GET.get("shown_as") if shown_as is not None and shown_as == "Stickiness": stickiness_days = int(request.GET["stickiness_days"]) events = ( events.values("person_id") .annotate( day_count=Count(functions.TruncDay("timestamp"), distinct=True) ) .filter(day_count=stickiness_days) ) else: 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") ) ) 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 serialize_people(people=people, request=request) filtered_events: QuerySet = QuerySet() if request.GET.get("session"): filtered_events = ( Event.objects.filter(team=team) .filter(filter_events(team.pk, filter)) .add_person_id(team.pk) ) else: if len(filter.entities) >= 1: entity = filter.entities[0] else: entity = Entity( {"id": request.GET["entityId"], "type": request.GET["type"]} ) if entity.type == TREND_FILTER_TYPE_EVENTS: filtered_events = process_entity_for_events( entity, team_id=team.pk, order_by=None ).filter(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 Response([]) filtered_events = process_entity_for_events( entity, team_id=team.pk, order_by=None ).filter(filter_events(team.pk, filter, entity)) people = _calculate_people(events=filtered_events, offset=offset) current_url = request.get_full_path() next_url: Optional[str] = request.get_full_path() if people["count"] > 99 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], "next": next_url, "previous": current_url[1:]} )