+
+
+
+
+ """,
+ """
+
+
+
+
+
+
""",
+ ),
+ (""" """, """ """),
+ ],
+)
+def test_nh3_clean_configuration(test_input, expected):
+ assert nh3_clean_with_whitelist(test_input).replace(" ", "") == expected.replace(" ", "")
diff --git a/posthog/middleware.py b/posthog/middleware.py
index 6953292a5a18b..b480580afad40 100644
--- a/posthog/middleware.py
+++ b/posthog/middleware.py
@@ -30,12 +30,11 @@
from posthog.metrics import LABEL_TEAM_ID
from posthog.models import Action, Cohort, Dashboard, FeatureFlag, Insight, Team, User
from posthog.rate_limit import DecideRateThrottle
-from posthog.settings import SITE_URL
+from posthog.settings import SITE_URL, DEBUG
from posthog.settings.statsd import STATSD_HOST
from posthog.user_permissions import UserPermissions
-from .utils_cors import cors_response
-
from .auth import PersonalAPIKeyAuthentication
+from .utils_cors import cors_response
ALWAYS_ALLOWED_ENDPOINTS = [
"decide",
@@ -49,6 +48,10 @@
"_health",
]
+if DEBUG:
+ # /i/ is the new root path for capture endpoints
+ ALWAYS_ALLOWED_ENDPOINTS.append("i")
+
default_cookie_options = {
"max_age": 365 * 24 * 60 * 60, # one year
"expires": None,
@@ -117,6 +120,8 @@ def process_view(self, request, callback, callback_args, callback_kwargs):
# if super().process_view did not find a valid CSRF token, try looking for a personal API key
if result is not None and PersonalAPIKeyAuthentication.find_key_with_source(request) is not None:
return self._accept(request)
+ if DEBUG and request.path.split("/")[1] in ALWAYS_ALLOWED_ENDPOINTS:
+ return self._accept(request)
return result
def _accept(self, request):
diff --git a/posthog/settings/__init__.py b/posthog/settings/__init__.py
index 5f915f3c1d6f5..099e1812e5311 100644
--- a/posthog/settings/__init__.py
+++ b/posthog/settings/__init__.py
@@ -85,6 +85,9 @@
# Whether kea should be act in verbose mode
KEA_VERBOSE_LOGGING = get_from_env("KEA_VERBOSE_LOGGING", False, type_cast=str_to_bool)
+# MapLibre Style URL to configure map tile source
+MAPLIBRE_STYLE_URL = get_from_env("MAPLIBRE_STYLE_URL", optional=True)
+
# Only written in specific scripts - do not use outside of them.
PERSON_ON_EVENTS_OVERRIDE = get_from_env("PERSON_ON_EVENTS_OVERRIDE", optional=True, type_cast=str_to_bool)
diff --git a/posthog/settings/ingestion.py b/posthog/settings/ingestion.py
index bd9edbc6fb03c..b60206d101ae9 100644
--- a/posthog/settings/ingestion.py
+++ b/posthog/settings/ingestion.py
@@ -1,7 +1,8 @@
import os
+
import structlog
-from posthog.settings.utils import get_from_env, get_list
+from posthog.settings.utils import get_from_env, get_list, get_set
from posthog.utils import str_to_bool
logger = structlog.get_logger(__name__)
@@ -32,3 +33,6 @@
REPLAY_RETENTION_DAYS_MIN = get_from_env("REPLAY_RETENTION_DAYS_MIN", type_cast=int, default=30)
REPLAY_RETENTION_DAYS_MAX = get_from_env("REPLAY_RETENTION_DAYS_MAX", type_cast=int, default=90)
+
+NEW_ANALYTICS_CAPTURE_ENDPOINT = os.getenv("NEW_CAPTURE_ENDPOINT", "/i/v0/e/")
+NEW_ANALYTICS_CAPTURE_TEAM_IDS = get_set(os.getenv("NEW_ANALYTICS_CAPTURE_TEAM_IDS", ""))
diff --git a/posthog/settings/utils.py b/posthog/settings/utils.py
index 150686df42ab6..6dd22dbf97cf8 100644
--- a/posthog/settings/utils.py
+++ b/posthog/settings/utils.py
@@ -1,5 +1,5 @@
import os
-from typing import Any, Callable, List, Optional
+from typing import Any, Callable, List, Optional, Set
from django.core.exceptions import ImproperlyConfigured
@@ -32,3 +32,9 @@ def get_list(text: str) -> List[str]:
if not text:
return []
return [item.strip() for item in text.split(",")]
+
+
+def get_set(text: str) -> Set[str]:
+ if not text:
+ return set()
+ return {item.strip() for item in text.split(",")}
diff --git a/posthog/settings/web.py b/posthog/settings/web.py
index 8eee2e114e02a..b846a2486c5df 100644
--- a/posthog/settings/web.py
+++ b/posthog/settings/web.py
@@ -112,6 +112,10 @@
MIDDLEWARE.insert(0, "django_statsd.middleware.StatsdMiddleware")
MIDDLEWARE.append("django_statsd.middleware.StatsdMiddlewareTimer")
+if DEBUG:
+ # Used on local devenv to reverse-proxy all of /i/* to capture-rs on port 3000
+ INSTALLED_APPS.append("revproxy")
+
# Append Enterprise Edition as an app if available
try:
from ee.apps import EnterpriseConfig # noqa: F401
diff --git a/posthog/templates/head.html b/posthog/templates/head.html
index ed0d359faa014..7ca827ae15914 100644
--- a/posthog/templates/head.html
+++ b/posthog/templates/head.html
@@ -36,6 +36,11 @@
window.SENTRY_ENVIRONMENT = '{{ sentry_environment | escapejs }}';
{% endif %}
+{% if js_maplibre_style_url %}
+
+{% endif %}