def get_event(request): timer = statsd.Timer("%s_posthog_cloud" % (settings.STATSD_PREFIX, )) timer.start() now = timezone.now() try: data_from_request = load_data_from_request(request) data = data_from_request["data"] except TypeError: return cors_response( request, JsonResponse( { "code": "validation", "message": "Malformed request data. Make sure you're sending valid JSON.", }, status=400, ), ) if not data: return cors_response( request, JsonResponse( { "code": "validation", "message": "No data found. Make sure to use a POST request when sending the payload in the body of the request.", }, status=400, ), ) sent_at = _get_sent_at(data, request) token = _get_token(data, request) if not token: return cors_response( request, JsonResponse( { "code": "validation", "message": "API key not provided. You can find your project API key in PostHog project settings.", }, status=401, ), ) team = Team.objects.get_team_from_token(token) if team is None: try: project_id = _get_project_id(data, request) except: return cors_response( request, JsonResponse( { "code": "validation", "message": "Invalid project ID.", }, status=400, ), ) if not project_id: return cors_response( request, JsonResponse( { "code": "validation", "message": "Project API key invalid. You can find your project API key in PostHog project settings.", }, status=401, ), ) user = User.objects.get_from_personal_api_key(token) if user is None: return cors_response( request, JsonResponse( { "code": "validation", "message": "Personal API key invalid.", }, status=401, ), ) team = user.teams.get(id=project_id) if isinstance(data, dict): if data.get("batch"): # posthog-python and posthog-ruby data = data["batch"] assert data is not None elif "engage" in request.path_info: # JS identify call data["event"] = "$identify" # make sure it has an event name if isinstance(data, list): events = data else: events = [data] for event in events: try: distinct_id = _get_distinct_id(event) except KeyError: return cors_response( request, JsonResponse( { "code": "validation", "message": "You need to set user distinct ID field `distinct_id`.", "item": event, }, status=400, ), ) if not event.get("event"): return cors_response( request, JsonResponse( { "code": "validation", "message": "You need to set event name field `event`.", "item": event, }, status=400, ), ) if not event.get("properties"): event["properties"] = {} _ensure_web_feature_flags_in_properties(event, team, distinct_id) event_uuid = UUIDT() if is_ee_enabled(): log_topics = [KAFKA_EVENTS_WAL] if settings.PLUGIN_SERVER_INGESTION: log_topics.append(KAFKA_EVENTS_PLUGIN_INGESTION) statsd.Counter("%s_posthog_cloud_plugin_server_ingestion" % (settings.STATSD_PREFIX, )).increment() log_event( distinct_id=distinct_id, ip=get_ip_address(request), site_url=request.build_absolute_uri("/")[:-1], data=event, team_id=team.id, now=now, sent_at=sent_at, event_uuid=event_uuid, topics=log_topics, ) # must done after logging because process_event_ee modifies the event, e.g. by removing $elements if not settings.PLUGIN_SERVER_INGESTION: process_event_ee( distinct_id=distinct_id, ip=get_ip_address(request), site_url=request.build_absolute_uri("/")[:-1], data=event, team_id=team.id, now=now, sent_at=sent_at, event_uuid=event_uuid, ) else: task_name = "posthog.tasks.process_event.process_event" if settings.PLUGIN_SERVER_INGESTION or team.plugins_opt_in: task_name += "_with_plugins" celery_queue = settings.PLUGINS_CELERY_QUEUE else: celery_queue = settings.CELERY_DEFAULT_QUEUE celery_app.send_task( name=task_name, queue=celery_queue, args=[ distinct_id, get_ip_address(request), request.build_absolute_uri("/")[:-1], event, team.id, now.isoformat(), sent_at, ], ) timer.stop("event_endpoint") return cors_response(request, JsonResponse({"status": 1}))
def get_event(request): now = timezone.now() try: data_from_request = load_data_from_request(request) data = data_from_request["data"] except TypeError: return cors_response( request, JsonResponse( { "code": "validation", "message": "Malformed request data. Make sure you're sending valid JSON.", }, status=400, ), ) if not data: return cors_response( request, JsonResponse( { "code": "validation", "message": "No data found. Make sure to use a POST request when sending the payload in the body of the request.", }, status=400, ), ) sent_at = _get_sent_at(data, request) token = _get_token(data, request) is_personal_api_key = False if not token: token = PersonalAPIKeyAuthentication.find_key( request, data_from_request["body"], data if isinstance(data, dict) else None) is_personal_api_key = True if not token: return cors_response( request, JsonResponse( { "code": "validation", "message": "Neither api_key nor personal_api_key set. You can find your project API key in PostHog project settings.", }, status=400, ), ) team = Team.objects.get_team_from_token(token, is_personal_api_key) if team is None: return cors_response( request, JsonResponse( { "code": "validation", "message": "Project or personal API key invalid. You can find your project API key in PostHog project settings.", }, status=400, ), ) if isinstance(data, dict): if data.get("batch"): # posthog-python and posthog-ruby data = data["batch"] assert data is not None elif "engage" in request.path_info: # JS identify call data["event"] = "$identify" # make sure it has an event name if isinstance(data, list): events = data else: events = [data] for event in events: try: distinct_id = _get_distinct_id(event) except KeyError: return cors_response( request, JsonResponse( { "code": "validation", "message": "You need to set user distinct ID field `distinct_id`.", "item": event, }, status=400, ), ) if "event" not in event: return cors_response( request, JsonResponse( { "code": "validation", "message": "You need to set event name field `event`.", "item": event, }, status=400, ), ) if check_ee_enabled(): process_event_ee.delay( distinct_id=distinct_id, ip=get_ip_address(request), site_url=request.build_absolute_uri("/")[:-1], data=event, team_id=team.id, now=now, sent_at=sent_at, ) # log the event to kafka write ahead log for processing log_event( distinct_id=distinct_id, ip=get_ip_address(request), site_url=request.build_absolute_uri("/")[:-1], data=event, team_id=team.id, now=now, sent_at=sent_at, ) else: process_event.delay( distinct_id=distinct_id, ip=get_ip_address(request), site_url=request.build_absolute_uri("/")[:-1], data=event, team_id=team.id, now=now, sent_at=sent_at, ) return cors_response(request, JsonResponse({"status": 1}))
def get_event(request): timer = statsd.Timer("%s_posthog_cloud" % (settings.STATSD_PREFIX,)) timer.start() now = timezone.now() try: data = load_data_from_request(request) except RequestParsingError as error: capture_exception(error) # We still capture this on Sentry to identify actual potential bugs return cors_response( request, generate_exception_response(f"Malformed request data: {error}", code="invalid_payload"), ) if not data: return cors_response( request, generate_exception_response( "No data found. Make sure to use a POST request when sending the payload in the body of the request.", code="no_data", ), ) sent_at = _get_sent_at(data, request) token = _get_token(data, request) if not token: return cors_response( request, generate_exception_response( "API key not provided. You can find your project API key in PostHog project settings.", type="authentication_error", code="missing_api_key", status_code=status.HTTP_401_UNAUTHORIZED, ), ) team = Team.objects.get_team_from_token(token) if team is None: try: project_id = _get_project_id(data, request) except ValueError: return cors_response( request, generate_exception_response("Invalid Project ID.", code="invalid_project", attr="project_id"), ) if not project_id: return cors_response( request, generate_exception_response( "Project API key invalid. You can find your project API key in PostHog project settings.", type="authentication_error", code="invalid_api_key", status_code=status.HTTP_401_UNAUTHORIZED, ), ) user = User.objects.get_from_personal_api_key(token) if user is None: return cors_response( request, generate_exception_response( "Invalid Personal API key.", type="authentication_error", code="invalid_personal_api_key", status_code=status.HTTP_401_UNAUTHORIZED, ), ) team = user.teams.get(id=project_id) if isinstance(data, dict): if data.get("batch"): # posthog-python and posthog-ruby data = data["batch"] assert data is not None elif "engage" in request.path_info: # JS identify call data["event"] = "$identify" # make sure it has an event name if isinstance(data, list): events = data else: events = [data] try: events = preprocess_session_recording_events(events) except ValueError as e: return cors_response(request, generate_exception_response(f"Invalid payload: {e}", code="invalid_payload")) for event in events: try: distinct_id = _get_distinct_id(event) except KeyError: return cors_response( request, generate_exception_response( "You need to set user distinct ID field `distinct_id`.", code="required", attr="distinct_id" ), ) if not event.get("event"): return cors_response( request, generate_exception_response( "You need to set user event name, field `event`.", code="required", attr="event" ), ) if not event.get("properties"): event["properties"] = {} _ensure_web_feature_flags_in_properties(event, team, distinct_id) event_uuid = UUIDT() ip = None if team.anonymize_ips else get_ip_address(request) if is_ee_enabled(): log_topics = [KAFKA_EVENTS_WAL] if settings.PLUGIN_SERVER_INGESTION: log_topics.append(KAFKA_EVENTS_PLUGIN_INGESTION) statsd.Counter("%s_posthog_cloud_plugin_server_ingestion" % (settings.STATSD_PREFIX,)).increment() log_event( distinct_id=distinct_id, ip=ip, site_url=request.build_absolute_uri("/")[:-1], data=event, team_id=team.id, now=now, sent_at=sent_at, event_uuid=event_uuid, topics=log_topics, ) # must done after logging because process_event_ee modifies the event, e.g. by removing $elements if not settings.PLUGIN_SERVER_INGESTION: process_event_ee( distinct_id=distinct_id, ip=ip, site_url=request.build_absolute_uri("/")[:-1], data=event, team_id=team.id, now=now, sent_at=sent_at, event_uuid=event_uuid, ) else: task_name = "posthog.tasks.process_event.process_event_with_plugins" celery_queue = settings.PLUGINS_CELERY_QUEUE celery_app.send_task( name=task_name, queue=celery_queue, args=[distinct_id, ip, request.build_absolute_uri("/")[:-1], event, team.id, now.isoformat(), sent_at,], ) timer.stop("event_endpoint") return cors_response(request, JsonResponse({"status": 1}))
def get_event(request): timer = statsd.Timer("%s_posthog_cloud" % (settings.STATSD_PREFIX,)) timer.start() now = timezone.now() try: data_from_request = load_data_from_request(request) data = data_from_request["data"] except TypeError: return cors_response( request, JsonResponse( {"code": "validation", "message": "Malformed request data. Make sure you're sending valid JSON.",}, status=400, ), ) if not data: return cors_response( request, JsonResponse( { "code": "validation", "message": "No data found. Make sure to use a POST request when sending the payload in the body of the request.", }, status=400, ), ) sent_at = _get_sent_at(data, request) token = _get_token(data, request) if not token: return cors_response( request, JsonResponse( { "code": "validation", "message": "API key not provided. You can find your project API key in PostHog project settings.", }, status=400, ), ) team = Team.objects.get_team_from_token(token) if team is None: try: project_id = _get_project_id(data, request) except: return cors_response( request, JsonResponse({"code": "validation", "message": "Invalid project ID.",}, status=400,), ) if not project_id: return cors_response( request, JsonResponse( { "code": "validation", "message": "Project API key invalid. You can find your project API key in PostHog project settings.", }, status=400, ), ) user = User.objects.get_from_personal_api_key(token) if user is None: return cors_response( request, JsonResponse({"code": "validation", "message": "Personal API key invalid.",}, status=400,), ) team = user.teams.get(id=project_id) if isinstance(data, dict): if data.get("batch"): # posthog-python and posthog-ruby data = data["batch"] assert data is not None elif "engage" in request.path_info: # JS identify call data["event"] = "$identify" # make sure it has an event name if isinstance(data, list): events = data else: events = [data] for event in events: try: distinct_id = _get_distinct_id(event) except KeyError: return cors_response( request, JsonResponse( { "code": "validation", "message": "You need to set user distinct ID field `distinct_id`.", "item": event, }, status=400, ), ) if "event" not in event: return cors_response( request, JsonResponse( {"code": "validation", "message": "You need to set event name field `event`.", "item": event,}, status=400, ), ) if is_ee_enabled(): process_event_ee( distinct_id=distinct_id, ip=get_ip_address(request), site_url=request.build_absolute_uri("/")[:-1], data=event, team_id=team.id, now=now, sent_at=sent_at, ) else: task_name = "posthog.tasks.process_event.process_event" celery_queue = settings.CELERY_DEFAULT_QUEUE if team.plugins_opt_in: task_name += "_with_plugins" celery_queue = settings.PLUGINS_CELERY_QUEUE celery_app.send_task( name=task_name, queue=celery_queue, args=[ distinct_id, get_ip_address(request), request.build_absolute_uri("/")[:-1], event, team.id, now.isoformat(), sent_at, ], ) if is_ee_enabled() and settings.LOG_TO_WAL: # log the event to kafka write ahead log for processing log_event( distinct_id=distinct_id, ip=get_ip_address(request), site_url=request.build_absolute_uri("/")[:-1], data=event, team_id=team.id, now=now, sent_at=sent_at, ) timer.stop("event_endpoint") return cors_response(request, JsonResponse({"status": 1}))