├── ee
├── __init__.py
├── api
│ ├── __init__.py
│ ├── test
│ │ ├── __init__.py
│ │ └── __snapshots__
│ │ │ └── test_instance_settings.ambr
│ └── debug_ch_queries.py
├── tasks
│ ├── __init__.py
│ ├── test
│ │ ├── __init__.py
│ │ └── subscriptions
│ │ │ ├── __init__.py
│ │ │ └── subscriptions_test_factory.py
│ └── org_usage_report.py
├── benchmarks
│ └── __init__.py
├── clickhouse
│ ├── __init__.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── group.py
│ │ └── test
│ │ │ ├── __init__.py
│ │ │ ├── __snapshots__
│ │ │ └── test_cohort.ambr
│ │ │ └── utils
│ │ │ └── util.py
│ ├── queries
│ │ ├── __init__.py
│ │ ├── test
│ │ │ ├── __init__.py
│ │ │ └── test_person_distinct_id_query.py
│ │ ├── funnels
│ │ │ ├── __init__.py
│ │ │ └── test
│ │ │ │ └── __init__.py
│ │ ├── session_recordings
│ │ │ ├── __init__.py
│ │ │ └── test
│ │ │ │ └── test_clickhouse_session_recording.py
│ │ ├── retention
│ │ │ ├── __init__.py
│ │ │ └── retention.py
│ │ ├── stickiness
│ │ │ ├── __init__.py
│ │ │ ├── stickiness.py
│ │ │ ├── stickiness_event_query.py
│ │ │ └── stickiness_actors.py
│ │ ├── paths
│ │ │ ├── __init__.py
│ │ │ ├── paths_event_query.py
│ │ │ └── paths_actors.py
│ │ └── experiments
│ │ │ └── __init__.py
│ ├── test
│ │ ├── __init__.py
│ │ └── test_calculate_event_property_usage.py
│ ├── views
│ │ ├── __init__.py
│ │ └── test
│ │ │ ├── __init__.py
│ │ │ └── funnel
│ │ │ └── __init__.py
│ ├── materialized_columns
│ │ ├── util.py
│ │ ├── __init__.py
│ │ └── test
│ │ │ └── __init__.py
│ └── bin
│ │ └── clickhouse-flamegraph
├── migrations
│ ├── __init__.py
│ ├── 0003_license_max_users.py
│ ├── 0010_migrate_definitions_tags.py
│ └── 0009_deprecated_old_tags.py
├── models
│ ├── test
│ │ └── __init__.py
│ └── __init__.py
├── conftest.py
├── bin
│ ├── docker-ch-dev-web
│ ├── docker-ch-dev-backend
│ └── docker-ch-test
├── apps.py
└── pytest.ini
├── staticfiles
└── empty.txt
├── posthog
├── api
│ ├── test
│ │ ├── __init__.py
│ │ └── mock_sentry.py
│ ├── forbid_destroy_model.py
│ └── unsubscribe.py
├── queries
│ ├── __init__.py
│ ├── test
│ │ └── __init__.py
│ ├── trends
│ │ └── __init__.py
│ ├── funnels
│ │ ├── test
│ │ │ └── __init__.py
│ │ ├── sql.py
│ │ └── __init__.py
│ ├── column_optimizer
│ │ ├── __init__.py
│ │ └── column_optimizer.py
│ ├── session_recordings
│ │ └── __init__.py
│ ├── retention
│ │ ├── types.py
│ │ └── __init__.py
│ ├── event_query
│ │ └── __init__.py
│ ├── groups_join_query
│ │ └── __init__.py
│ ├── cohort_query.py
│ ├── paths
│ │ └── __init__.py
│ └── stickiness
│ │ └── __init__.py
├── test
│ ├── __init__.py
│ ├── activity_logging
│ │ └── __init__.py
│ ├── mock_urls_cloud.py
│ ├── mock_urls_self_hosted.py
│ └── db_context_capturing.py
├── clickhouse
│ ├── __init__.py
│ ├── test
│ │ └── __init__.py
│ ├── migrations
│ │ ├── __init__.py
│ │ ├── 0002_events_materialized.py
│ │ ├── 0011_cohortpeople_no_shard.py
│ │ ├── 0010_cohortpeople.py
│ │ ├── 0007_static_cohorts_table.py
│ │ ├── 0025_json_events.py
│ │ ├── 0031_event_properties_zstd.py
│ │ ├── 0018_group_analytics_schema.py
│ │ ├── 0001_initial.py
│ │ ├── 0022_person_distinct_id2.py
│ │ ├── 0008_plugin_log_entries.py
│ │ ├── 0017_events_dead_letter_queue.py
│ │ └── 0024_materialize_window_and_session_id.py
│ ├── replication
│ │ ├── __init__.py
│ │ └── utils.py
│ └── materialized_columns
│ │ └── __init__.py
├── helpers
│ ├── tests
│ │ └── __init__.py
│ └── __init__.py
├── kafka_client
│ └── __init__.py
├── migrations
│ ├── __init__.py
│ ├── 0175_should_update_person_props_function.py
│ ├── 0244_drop_should_update_person_prop.py
│ ├── 0041_merge_20200407_1805.py
│ ├── 0049_delete_funnelstep.py
│ ├── 0184_delete_sessionsfilter.py
│ ├── 0129_merge_20210223_0757.py
│ ├── 0148_merge_20210506_0823.py
│ ├── 0239_delete_postgres_pluginlogentry.py
│ ├── 0040_remove_event_ip.py
│ ├── 0117_merge_20210126_0917.py
│ ├── 0176_update_person_props_function.py
│ ├── 0005_remove_person_distinct_ids.py
│ ├── 0093_remove_user_is_superuser.py
│ ├── 0009_auto_20200127_0018.py
│ ├── 0173_should_update_person_props_function.py
│ ├── 0036_remove_current_url_index.py
│ ├── 0191_rename_specialmigration_asyncmigration.py
│ ├── 0018_funnel_deleted.py
│ ├── 0022_action_deleted.py
│ ├── 0062_team_anonymize_ips.py
│ ├── 0067_team_updated_at.py
│ ├── 0113_cohort_is_static.py
│ ├── 0207_cohort_count.py
│ ├── 0210_drop_update_person_functions.py
│ ├── 0023_team_opt_out_capture.py
│ ├── 0057_action_updated_at.py
│ ├── 0138_featureflag_name_optional.py
│ ├── 0157_plugin_metrics.py
│ ├── 0153_plugin_capabilities.py
│ ├── 0180_person_version.py
│ ├── 0105_cohort_errors_calculating.py
│ ├── 0151_plugin_preinstalled.py
│ ├── 0209_plugin_logs_disabled.py
│ ├── 0230_cohort_filters.py
│ ├── 0034_pg_trgm_and_btree_20200318_1447.py
│ ├── 0039_user_email_opt_in.py
│ ├── 0059_dashboarditem_refreshing.py
│ ├── 0081_person_is_identified.py
│ ├── 0166_plugin_public_jobs.py
│ ├── 0211_async_migrations_errors_length.py
│ ├── 0019_team_name.py
│ ├── 0202_descriptions_for_action.py
│ ├── 0214_migrate_dashboard_insight_tags.py
│ ├── 0012_team_app_url.py
│ ├── 0097_invite_emails.py
│ ├── 0208_alter_plugin_updated_at.py
│ ├── 0086_team_session_recording_opt_in.py
│ ├── 0015_actionstep_event.py
│ ├── 0045_add_timestamp_index.py
│ ├── 0119_mandatory_plugin_order.py
│ ├── 0134_event_site_url.py
│ ├── 0186_insight_refresh_attempt.py
│ ├── 0188_person_distinct_id_version.py
│ ├── 0016_user_temporary_token.py
│ ├── 0058_dashboarditem_last_refresh.py
│ ├── 0060_auto_20200616_0746.py
│ ├── 0171_cohort_description.py
│ ├── 0216_insight_placeholder_name.py
│ ├── 0054_dashboard_item_color.py
│ ├── 0055_user_anonymize_data.py
│ ├── 0181_team_correlation_config.py
│ ├── 0197_plugin_is_stateless.py
│ ├── 0076_auto_20200819_1214.py
│ ├── 0077_cohortpeople_id_to_bigautofield.py
│ ├── 0172_person_properties_last_operation.py
│ ├── 0240_organizationinvite_message.py
│ ├── 0047_auto_20200416_1631.py
│ ├── 0178_rename_dashboard_item_to_insight.py
│ ├── 0065_auto_20200624_1842.py
│ ├── 0084_person_uuid.py
│ ├── 0122_organization_setup_section_2_completed.py
│ ├── 0162_organization_is_member_join_email_enabled.py
│ ├── 0089_auto_20201015_1031.py
│ ├── 0104_auto_20201208_1052.py
│ ├── 0024_add_event_distinct_id_index.py
│ ├── 0075_action_slack_message_format.py
│ ├── 0177_path_cleaning_filters.py
│ ├── 0035_current_url_index_20200318_1459.py
│ ├── 0039_populate_event_ip_property.py
│ ├── 0127_add_dashboard_filters.py
│ ├── 0064_toolbar_mode.py
│ ├── 0125_longer_webhook_url.py
│ ├── 0226_longer_action_slack_message_format.py
│ ├── 0182_sessionrecordingevent_window_id.py
│ ├── 0020_auto_20200210_0212.py
│ ├── 0116_session_recording_retention_period.py
│ ├── 0123_organizationinvite_first_name.py
│ ├── 0169_person_properties_last_updated_at.py
│ ├── 0004_auto_20200125_0415.py
│ ├── 0053_dashboard_item_layouts.py
│ ├── 0121_person_email_index.py
│ ├── 0087_fix_annotation_created_at.py
│ ├── 0070_team_event_properties_numerical.py
│ ├── 0120_organization_personalization.py
│ ├── 0152_user_events_column_config.py
│ ├── 0066_team_created_at.py
│ ├── 0199_update_experiment_model.py
│ ├── 0048_auto_20200420_1051.py
│ ├── 0136_global_plugin_attachments.py
│ ├── 0028_actionstep_url_matching.py
│ ├── 0110_sessionrecordingeventbyteamandtimestamp.py
│ └── 0237_remove_timezone_from_teams.py
├── models
│ ├── test
│ │ └── __init__.py
│ ├── activity_logging
│ │ └── __init__.py
│ ├── filters
│ │ ├── mixins
│ │ │ ├── __init__.py
│ │ │ ├── test
│ │ │ │ └── __init__.py
│ │ │ └── base.py
│ │ ├── __init__.py
│ │ └── session_recordings_filter.py
│ ├── event
│ │ └── __init__.py
│ ├── group
│ │ └── __init__.py
│ ├── team
│ │ └── __init__.py
│ ├── cohort
│ │ └── __init__.py
│ ├── element
│ │ └── __init__.py
│ ├── entity
│ │ └── __init__.py
│ ├── person
│ │ └── __init__.py
│ ├── property
│ │ └── __init__.py
│ ├── session_recording_event
│ │ └── __init__.py
│ ├── action
│ │ └── __init__.py
│ ├── event_buffer.py
│ └── tag.py
├── plugins
│ ├── test
│ │ └── __init__.py
│ ├── __init__.py
│ └── reload.py
├── tasks
│ ├── exports
│ │ └── __init__.py
│ ├── test
│ │ └── __init__.py
│ ├── user_identify.py
│ ├── sync_all_organization_available_features.py
│ ├── delete_clickhouse_data.py
│ └── split_person.py
├── templatetags
│ └── __init__.py
├── async_migrations
│ ├── __init__.py
│ ├── test
│ │ └── __init__.py
│ ├── examples
│ │ └── __init__.py
│ └── migrations
│ │ ├── __init__.py
│ │ └── 0001_events_sample_by.py
├── gitsha.py
├── version.py
├── management
│ └── commands
│ │ ├── test
│ │ └── __init__.py
│ │ ├── api_keys.py
│ │ └── sync_available_features.py
├── settings
│ ├── geoip.py
│ ├── ee.py
│ ├── statsd.py
│ ├── ingestion.py
│ ├── feature_flags.py
│ ├── cloud.py
│ └── shell_plus.py
├── demo
│ └── matrix
│ │ └── __init__.py
├── __init__.py
├── templates
│ ├── email
│ │ ├── async_migration_status.html
│ │ ├── async_migration_error.html
│ │ └── canary_email.html
│ └── live_server_inject.html
├── types.py
├── wsgi.py
├── idl
│ └── idl.md
├── logging
│ ├── timing.py
│ └── test
│ │ └── test_timing.py
└── datetime.py
├── Dockerfile
├── runtime.txt
├── depot.json
├── frontend
├── src
│ ├── scenes
│ │ ├── billing
│ │ │ └── index.ts
│ │ ├── organization
│ │ │ ├── TeamMembers
│ │ │ │ └── index.tsx
│ │ │ └── Create
│ │ │ │ └── index.tsx
│ │ ├── insights
│ │ │ ├── EmptyStates
│ │ │ │ └── index.ts
│ │ │ ├── views
│ │ │ │ ├── Histogram
│ │ │ │ │ └── index.js
│ │ │ │ ├── InsightsTable
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── WorldMap
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── WorldMap.scss
│ │ │ │ └── LineGraph
│ │ │ │ │ └── LineGraph.scss
│ │ │ ├── filters
│ │ │ │ ├── InsightDateFilter
│ │ │ │ │ └── index.ts
│ │ │ │ ├── TestAccountFilter
│ │ │ │ │ └── index.ts
│ │ │ │ └── BreakdownFilter
│ │ │ │ │ └── index.ts
│ │ │ ├── __image_snapshots__
│ │ │ │ ├── Insights trends can render bar graphs #0.png
│ │ │ │ └── Insights trends can render bar graphs #1.png
│ │ │ └── EditorFilters
│ │ │ │ └── LifecycleGlobalFilters.tsx
│ │ ├── authentication
│ │ │ ├── PasswordReset.scss
│ │ │ └── PasswordInput.scss
│ │ ├── funnels
│ │ │ ├── FunnelHistogram.scss
│ │ │ └── FunnelCanvasLabel.scss
│ │ ├── trends
│ │ │ └── viz
│ │ │ │ └── index.ts
│ │ ├── events
│ │ │ └── index.ts
│ │ ├── toolbar-launch
│ │ │ └── AuthorizedUrls.scss
│ │ ├── plugins
│ │ │ ├── source
│ │ │ │ └── PluginSource.scss
│ │ │ ├── plugin
│ │ │ │ ├── SourcePluginTag.tsx
│ │ │ │ └── styles
│ │ │ │ │ └── metrics-drawer.scss
│ │ │ └── edit
│ │ │ │ └── CapabilitiesInfo.ts
│ │ ├── Unsubscribe
│ │ │ ├── Unsubscribe.scss
│ │ │ └── Unsubscribe.stories.tsx
│ │ ├── persons
│ │ │ ├── PersonHeader.scss
│ │ │ └── Persons.scss
│ │ ├── cohorts
│ │ │ └── Cohort.scss
│ │ ├── instance
│ │ │ ├── SystemStatus
│ │ │ │ └── index.scss
│ │ │ └── Licenses
│ │ │ │ └── Licenses.stories.tsx
│ │ ├── PreflightCheck
│ │ │ └── PreflightCheck.stories.tsx
│ │ ├── ingestion
│ │ │ ├── Ingestion.stories.tsx
│ │ │ ├── types.ts
│ │ │ └── frameworks
│ │ │ │ ├── index.tsx
│ │ │ │ └── CodeSnippet.scss
│ │ ├── project
│ │ │ └── Create
│ │ │ │ └── index.tsx
│ │ └── retention
│ │ │ └── RetentionTable.scss
│ ├── lib
│ │ ├── components
│ │ │ ├── CompareFilter
│ │ │ │ └── index.ts
│ │ │ ├── ChartFilter
│ │ │ │ └── index.ts
│ │ │ ├── IntervalFilter
│ │ │ │ ├── index.ts
│ │ │ │ └── intervals.ts
│ │ │ ├── SmoothingFilter
│ │ │ │ └── index.ts
│ │ │ ├── InsightCard
│ │ │ │ └── index.tsx
│ │ │ ├── LemonCheckbox
│ │ │ │ └── index.ts
│ │ │ ├── PersonalAPIKeys
│ │ │ │ └── index.tsx
│ │ │ ├── Sharing
│ │ │ │ └── SharingModal.scss
│ │ │ ├── LemonModal
│ │ │ │ └── index.ts
│ │ │ ├── LemonRow
│ │ │ │ └── index.ts
│ │ │ ├── AlertMessage
│ │ │ │ └── index.ts
│ │ │ ├── Annotations
│ │ │ │ ├── index.ts
│ │ │ │ └── utils.ts
│ │ │ ├── LemonDivider
│ │ │ │ └── index.ts
│ │ │ ├── ActivityLog
│ │ │ │ └── SentenceList.scss
│ │ │ ├── PropertyKeyInfo.scss
│ │ │ ├── UserActivityIndicator
│ │ │ │ └── UserActivityIndicator.scss
│ │ │ ├── ProfilePicture
│ │ │ │ └── index.ts
│ │ │ ├── DatePicker.tsx
│ │ │ ├── LemonTable
│ │ │ │ └── index.ts
│ │ │ ├── LemonButton
│ │ │ │ └── index.ts
│ │ │ ├── HelpButton
│ │ │ │ └── HelpButton.scss
│ │ │ ├── PaginationControl
│ │ │ │ ├── index.tsx
│ │ │ │ └── PaginationControl.scss
│ │ │ ├── DurationPicker
│ │ │ │ └── DurationPicker.scss
│ │ │ ├── AddToDashboard
│ │ │ │ └── AddToDashboard.scss
│ │ │ ├── PropertyFilters
│ │ │ │ ├── components
│ │ │ │ │ └── FilterRow.scss
│ │ │ │ └── PropertyFilters.scss
│ │ │ ├── Fade
│ │ │ │ └── Fade.scss
│ │ │ ├── EmptyMessage
│ │ │ │ └── EmptyMessage.scss
│ │ │ ├── Property.tsx
│ │ │ ├── Drawer.tsx
│ │ │ ├── LinkButton.tsx
│ │ │ ├── CloseButton.tsx
│ │ │ ├── NotFound
│ │ │ │ ├── NotFound.scss
│ │ │ │ └── NotFound.stories.tsx
│ │ │ ├── SelectDownIcon.tsx
│ │ │ ├── LemonSnack
│ │ │ │ └── LemonSnack.scss
│ │ │ ├── StarryBackground
│ │ │ │ ├── index.tsx
│ │ │ │ └── index.scss
│ │ │ ├── Lettermark
│ │ │ │ └── Lettermark.scss
│ │ │ ├── DateDisplay
│ │ │ │ └── DateDisplay.scss
│ │ │ ├── TitleWithIcon.tsx
│ │ │ ├── icons.scss
│ │ │ ├── DateFilter
│ │ │ │ └── DateFilterRange.scss
│ │ │ ├── PayCard
│ │ │ │ └── PayCard.scss
│ │ │ ├── icons
│ │ │ │ └── Splotch.stories.tsx
│ │ │ ├── HotkeyButton
│ │ │ │ └── HotkeyButton.tsx
│ │ │ └── PayGateMini
│ │ │ │ └── PayGateMini.scss
│ │ ├── experimental
│ │ │ └── README.md
│ │ ├── hooks
│ │ │ ├── usePeriodicRerender.ts
│ │ │ ├── useSecondRender.js
│ │ │ ├── useBreakpoint.ts
│ │ │ ├── useEscapeKey.js
│ │ │ └── useInterval.js
│ │ ├── internalMetrics.ts
│ │ └── utils
│ │ │ ├── getAppContext.ts
│ │ │ ├── logics.ts
│ │ │ └── changeType.js
│ ├── test
│ │ └── mocks
│ │ │ └── styleMock.js
│ ├── layout
│ │ ├── ErrorBoundary
│ │ │ └── index.ts
│ │ ├── navigation
│ │ │ └── DemoWarnings
│ │ │ │ └── DemoWarnings.scss
│ │ ├── Error404.tsx
│ │ └── ErrorNetwork.tsx
│ ├── toolbar
│ │ ├── elements
│ │ │ └── Elements.scss
│ │ └── button
│ │ │ └── icons
│ │ │ └── Close.tsx
│ ├── styles
│ │ ├── vars.ts
│ │ └── index.tsx
│ ├── mocks
│ │ ├── features.ts
│ │ └── jest.ts
│ ├── stories
│ │ └── Missing components.stories.mdx
│ ├── exporter
│ │ └── types.ts
│ ├── globals.d.ts
│ └── custom.d.ts
├── public
│ ├── Inter.woff
│ ├── squeak.mp3
│ ├── Inter.woff2
│ ├── hedgehog-blue.png
│ ├── icons
│ │ ├── favicon.ico
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon-dev.ico
│ │ ├── apple-touch-icon.png
│ │ ├── android-chrome-192x192.png
│ │ └── android-chrome-512x512.png
│ ├── posthog-logo.png
│ ├── surprised-hog.png
│ ├── email
│ │ ├── arrow-up-red.png
│ │ ├── arrow-down-red.png
│ │ ├── arrow-up-green.png
│ │ ├── arrow-down-green.png
│ │ └── invite-email-welcome.png
│ ├── hedgehog-bridge-page.png
│ └── site.webmanifest
└── @posthog
│ ├── apps-common
│ ├── README.md
│ ├── tsconfig.json
│ └── src
│ │ └── index.ts
│ └── lemon-ui
│ ├── tsconfig.json
│ └── README.md
├── cypress
├── fixtures
│ ├── api
│ │ ├── personal_api_keys.json
│ │ ├── cohort
│ │ │ └── cohorts.json
│ │ ├── event
│ │ │ ├── only_time_property_definition.json
│ │ │ └── only_browser_version_property_definition.json
│ │ ├── person
│ │ │ └── properties.json
│ │ └── decide.js
│ └── example.json
├── data
│ └── exports
│ │ └── export-pageview-count.png
├── e2e
│ ├── commandPalette.js
│ ├── persons.js
│ ├── organizationSettings.js
│ ├── systemStatus.js
│ ├── licenses.js
│ └── annotations.js
└── README.md
├── .environment
├── bin
├── docker-migrate
├── start-backend
├── docker
├── docker-backend
├── docker-frontend
├── docker-dev-web
├── docker-dev
├── docker-worker-beat
├── migrate-check
├── start-frontend
├── migrate
├── start-frontend-https
├── start-https
├── docker-worker
├── check_kafka_clickhouse_up
├── start-worker
└── install-macosx_arm64
├── .husky
└── pre-commit
├── jest.setup.ts
├── plugin-server
├── bin
│ └── posthog-plugin-server
├── tests
│ ├── assets
│ │ └── GeoLite2-City-Test.mmdb.br
│ └── helpers
│ │ ├── promises.ts
│ │ └── worker.ts
├── src
│ ├── worker
│ │ ├── piscina.d.ts
│ │ ├── vm
│ │ │ ├── transforms
│ │ │ │ └── common.ts
│ │ │ └── extensions
│ │ │ │ ├── geoip.ts
│ │ │ │ └── google.ts
│ │ └── ingestion
│ │ │ └── event-pipeline
│ │ │ └── 5-createEventStep.ts
│ ├── utils
│ │ ├── node-schedule.ts
│ │ ├── posthog.ts
│ │ ├── kill.ts
│ │ └── fetch.ts
│ ├── init.ts
│ ├── config
│ │ ├── constants.ts
│ │ └── mmdb-constants.ts
│ └── main
│ │ └── job-queues
│ │ └── buffer.ts
├── .babelrc
├── .editorconfig
├── tsconfig.eslint.json
└── jest.config.js
├── codecov.yml
├── docker
└── clickhouse
│ └── docker-entrypoint-initdb.d
│ └── init-db.sh
├── .prettierrc
├── .coveragerc
├── .devcontainer
└── container_start.sh
├── .kearc
├── pyproject.toml
├── Procfile
├── pytest.ini
├── .prettierignore
├── postcss.config.js
├── share
└── share.md
├── .storybook
├── storybook.scss
└── app-context.ts
├── latest_migrations.manifest
├── SECURITY.md
├── .run
├── Frontend.run.xml
├── Storybook.run.xml
└── Jest Tests.run.xml
├── CHANGELOG.md
├── .deepsource.toml
├── mypy.ini
└── babel.config.js
/ee/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/api/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/api/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/tasks/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/staticfiles/empty.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/benchmarks/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/clickhouse/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/models/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/tasks/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/api/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/queries/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | production.Dockerfile
--------------------------------------------------------------------------------
/ee/clickhouse/models/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/clickhouse/models/group.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/clickhouse/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/clickhouse/views/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/clickhouse/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/helpers/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/kafka_client/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/models/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/plugins/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/queries/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/tasks/exports/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/tasks/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/templatetags/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.8.12
2 |
--------------------------------------------------------------------------------
/depot.json:
--------------------------------------------------------------------------------
1 | { "id": "x19jffd9zf" }
2 |
--------------------------------------------------------------------------------
/ee/clickhouse/models/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/clickhouse/views/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/scenes/billing/index.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/async_migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/clickhouse/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/queries/trends/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/clickhouse/materialized_columns/util.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/funnels/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/clickhouse/views/test/funnel/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/tasks/test/subscriptions/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/async_migrations/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/clickhouse/replication/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/gitsha.py:
--------------------------------------------------------------------------------
1 | GIT_SHA = "Undefined"
2 |
--------------------------------------------------------------------------------
/posthog/models/activity_logging/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/models/filters/mixins/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/queries/funnels/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/test/activity_logging/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/version.py:
--------------------------------------------------------------------------------
1 | VERSION = "1.38.0"
2 |
--------------------------------------------------------------------------------
/ee/clickhouse/materialized_columns/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/funnels/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/async_migrations/examples/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/async_migrations/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/management/commands/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/models/filters/mixins/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/queries/column_optimizer/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/queries/session_recordings/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/cypress/fixtures/api/personal_api_keys.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/ee/clickhouse/materialized_columns/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/session_recordings/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/CompareFilter/index.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.environment:
--------------------------------------------------------------------------------
1 | export SECRET_KEY=$PLATFORM_PROJECT_ENTROPY
--------------------------------------------------------------------------------
/frontend/src/scenes/organization/TeamMembers/index.tsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/posthog/models/event/__init__.py:
--------------------------------------------------------------------------------
1 | from .event import *
2 |
--------------------------------------------------------------------------------
/posthog/models/group/__init__.py:
--------------------------------------------------------------------------------
1 | from .group import *
2 |
--------------------------------------------------------------------------------
/posthog/models/team/__init__.py:
--------------------------------------------------------------------------------
1 | from .team import *
2 |
--------------------------------------------------------------------------------
/frontend/src/test/mocks/styleMock.js:
--------------------------------------------------------------------------------
1 | module.exports = {}
2 |
--------------------------------------------------------------------------------
/posthog/models/cohort/__init__.py:
--------------------------------------------------------------------------------
1 | from .cohort import *
2 |
--------------------------------------------------------------------------------
/posthog/models/element/__init__.py:
--------------------------------------------------------------------------------
1 | from .element import *
2 |
--------------------------------------------------------------------------------
/posthog/models/entity/__init__.py:
--------------------------------------------------------------------------------
1 | from .entity import *
2 |
--------------------------------------------------------------------------------
/posthog/models/person/__init__.py:
--------------------------------------------------------------------------------
1 | from .person import *
2 |
--------------------------------------------------------------------------------
/posthog/models/property/__init__.py:
--------------------------------------------------------------------------------
1 | from .property import *
2 |
--------------------------------------------------------------------------------
/ee/conftest.py:
--------------------------------------------------------------------------------
1 | # flake8: noqa
2 | from posthog.conftest import *
3 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/retention/__init__.py:
--------------------------------------------------------------------------------
1 | from .retention import *
2 |
--------------------------------------------------------------------------------
/bin/docker-migrate:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | python manage.py migrate
--------------------------------------------------------------------------------
/bin/start-backend:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | python3 manage.py runserver
--------------------------------------------------------------------------------
/ee/clickhouse/queries/stickiness/__init__.py:
--------------------------------------------------------------------------------
1 | from .stickiness import *
2 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ChartFilter/index.ts:
--------------------------------------------------------------------------------
1 | export * from './ChartFilter'
2 |
--------------------------------------------------------------------------------
/frontend/src/scenes/insights/EmptyStates/index.ts:
--------------------------------------------------------------------------------
1 | export * from './EmptyStates'
2 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/IntervalFilter/index.ts:
--------------------------------------------------------------------------------
1 | export * from './IntervalFilter'
2 |
--------------------------------------------------------------------------------
/frontend/src/scenes/authentication/PasswordReset.scss:
--------------------------------------------------------------------------------
1 | @import './bridgePagesShared';
2 |
--------------------------------------------------------------------------------
/frontend/src/scenes/insights/views/Histogram/index.js:
--------------------------------------------------------------------------------
1 | export * from './Histogram'
2 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | yarn lint-staged
5 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/SmoothingFilter/index.ts:
--------------------------------------------------------------------------------
1 | export * from './SmoothingFilter'
2 |
--------------------------------------------------------------------------------
/posthog/models/session_recording_event/__init__.py:
--------------------------------------------------------------------------------
1 | from .session_recording_event import *
2 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/paths/__init__.py:
--------------------------------------------------------------------------------
1 | from .paths import *
2 | from .paths_actors import *
3 |
--------------------------------------------------------------------------------
/frontend/src/layout/ErrorBoundary/index.ts:
--------------------------------------------------------------------------------
1 | export { ErrorBoundary } from './ErrorBoundary'
2 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/InsightCard/index.tsx:
--------------------------------------------------------------------------------
1 | export { InsightCard } from './InsightCard'
2 |
--------------------------------------------------------------------------------
/posthog/models/action/__init__.py:
--------------------------------------------------------------------------------
1 | from .action import Action
2 |
3 | __all__ = ["Action"]
4 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/LemonCheckbox/index.ts:
--------------------------------------------------------------------------------
1 | export { LemonCheckbox } from './LemonCheckbox'
2 |
--------------------------------------------------------------------------------
/frontend/src/scenes/insights/filters/InsightDateFilter/index.ts:
--------------------------------------------------------------------------------
1 | export * from './InsightDateFilter'
2 |
--------------------------------------------------------------------------------
/frontend/src/scenes/insights/filters/TestAccountFilter/index.ts:
--------------------------------------------------------------------------------
1 | export * from './TestAccountFilter'
2 |
--------------------------------------------------------------------------------
/cypress/fixtures/api/cohort/cohorts.json:
--------------------------------------------------------------------------------
1 | { "count": 0, "next": null, "previous": null, "results": [] }
2 |
--------------------------------------------------------------------------------
/frontend/public/Inter.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/Inter.woff
--------------------------------------------------------------------------------
/frontend/public/squeak.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/squeak.mp3
--------------------------------------------------------------------------------
/jest.setup.ts:
--------------------------------------------------------------------------------
1 | import 'whatwg-fetch'
2 | import 'jest-canvas-mock'
3 |
4 | window.scrollTo = jest.fn()
5 |
--------------------------------------------------------------------------------
/bin/docker:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | ./bin/migrate
5 | ./bin/docker-worker &
6 | ./bin/docker-server
7 |
--------------------------------------------------------------------------------
/frontend/public/Inter.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/Inter.woff2
--------------------------------------------------------------------------------
/frontend/src/lib/components/PersonalAPIKeys/index.tsx:
--------------------------------------------------------------------------------
1 | export { PersonalAPIKeys } from './PersonalAPIKeys'
2 |
--------------------------------------------------------------------------------
/plugin-server/bin/posthog-plugin-server:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | require(__dirname + '/../dist/index.js')
4 |
--------------------------------------------------------------------------------
/ee/bin/docker-ch-dev-web:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | ./ee/bin/docker-ch-dev-backend & ./bin/docker-frontend
6 |
--------------------------------------------------------------------------------
/frontend/public/hedgehog-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/hedgehog-blue.png
--------------------------------------------------------------------------------
/frontend/public/icons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/icons/favicon.ico
--------------------------------------------------------------------------------
/frontend/public/posthog-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/posthog-logo.png
--------------------------------------------------------------------------------
/frontend/public/surprised-hog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/surprised-hog.png
--------------------------------------------------------------------------------
/frontend/src/scenes/insights/filters/BreakdownFilter/index.ts:
--------------------------------------------------------------------------------
1 | export { BreakdownFilter } from './TaxonomicBreakdownFilter'
2 |
--------------------------------------------------------------------------------
/bin/docker-backend:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | python manage.py migrate
6 |
7 | python manage.py runserver 0.0.0.0:8000
8 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | # Disable PR comments for now to not spam PRs. We should still have annotations
2 | # on files
3 | comment: false
4 |
--------------------------------------------------------------------------------
/ee/bin/docker-ch-dev-backend:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | ./bin/migrate
6 |
7 | python manage.py runserver 0.0.0.0:8000
8 |
--------------------------------------------------------------------------------
/ee/clickhouse/bin/clickhouse-flamegraph:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/ee/clickhouse/bin/clickhouse-flamegraph
--------------------------------------------------------------------------------
/frontend/public/email/arrow-up-red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/email/arrow-up-red.png
--------------------------------------------------------------------------------
/frontend/public/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/frontend/public/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/frontend/public/icons/favicon-dev.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/icons/favicon-dev.ico
--------------------------------------------------------------------------------
/frontend/public/email/arrow-down-red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/email/arrow-down-red.png
--------------------------------------------------------------------------------
/frontend/public/email/arrow-up-green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/email/arrow-up-green.png
--------------------------------------------------------------------------------
/frontend/public/hedgehog-bridge-page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/hedgehog-bridge-page.png
--------------------------------------------------------------------------------
/bin/docker-frontend:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | export WEBPACK_HOT_RELOAD_HOST="0.0.0.0"
5 |
6 | yarn install
7 | yarn start-docker
8 |
--------------------------------------------------------------------------------
/docker/clickhouse/docker-entrypoint-initdb.d/init-db.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | cp -r /idl/* /var/lib/clickhouse/format_schemas/
5 |
--------------------------------------------------------------------------------
/frontend/public/email/arrow-down-green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/email/arrow-down-green.png
--------------------------------------------------------------------------------
/frontend/public/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/frontend/src/scenes/insights/views/InsightsTable/index.tsx:
--------------------------------------------------------------------------------
1 | import { InsightsTable } from './InsightsTable'
2 | export { InsightsTable }
3 |
--------------------------------------------------------------------------------
/frontend/src/toolbar/elements/Elements.scss:
--------------------------------------------------------------------------------
1 | #posthog-toolbar-elements,
2 | #posthog-infowindow-container {
3 | color: #333333;
4 | }
5 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 4,
4 | "semi": false,
5 | "singleQuote": true,
6 | "printWidth": 120,
7 | }
8 |
--------------------------------------------------------------------------------
/cypress/data/exports/export-pageview-count.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/cypress/data/exports/export-pageview-count.png
--------------------------------------------------------------------------------
/frontend/public/email/invite-email-welcome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/email/invite-email-welcome.png
--------------------------------------------------------------------------------
/frontend/src/lib/components/Sharing/SharingModal.scss:
--------------------------------------------------------------------------------
1 | .SharingPreview {
2 | background-color: var(--bg-mid);
3 | padding: 0.5rem;
4 | }
5 |
--------------------------------------------------------------------------------
/posthog/settings/geoip.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from django.conf import settings
4 |
5 | GEOIP_PATH = os.path.join(settings.BASE_DIR, "share")
6 |
--------------------------------------------------------------------------------
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | source =
3 | posthog/
4 | ee/
5 |
6 | branch = true
7 |
8 | omit =
9 | */migrations/*
10 | manage.py
11 |
--------------------------------------------------------------------------------
/.devcontainer/container_start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/env zsh
2 |
3 | echo "printf 'Hello 🦔! To start PostHog run this:\n "./ee/bin/docker-ch-dev-web"\n'" > ~/.zshrc
--------------------------------------------------------------------------------
/bin/docker-dev-web:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 | python manage.py migrate
5 |
6 | python manage.py runserver 0.0.0.0:8000 & ./bin/docker-frontend
7 |
--------------------------------------------------------------------------------
/ee/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class EnterpriseConfig(AppConfig):
5 | name = "ee"
6 | verbose_name = "Enterprise"
7 |
--------------------------------------------------------------------------------
/frontend/public/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/frontend/public/icons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/public/icons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/frontend/src/lib/components/LemonModal/index.ts:
--------------------------------------------------------------------------------
1 | export { LemonModal } from './LemonModal'
2 | export type { LemonModalProps } from './LemonModal'
3 |
--------------------------------------------------------------------------------
/posthog/helpers/__init__.py:
--------------------------------------------------------------------------------
1 | from .dashboard_templates import create_dashboard_from_template
2 |
3 | __all__ = ["create_dashboard_from_template"]
4 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/LemonRow/index.ts:
--------------------------------------------------------------------------------
1 | export { LemonRow } from './LemonRow'
2 | export type { LemonRowProps, LemonRowPropsBase } from './LemonRow'
3 |
--------------------------------------------------------------------------------
/frontend/src/scenes/funnels/FunnelHistogram.scss:
--------------------------------------------------------------------------------
1 | .funnel-histogram-outer-container {
2 | &.scrollable {
3 | overflow-x: auto;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/frontend/src/scenes/trends/viz/index.ts:
--------------------------------------------------------------------------------
1 | export * from './ActionsPie'
2 | export * from './ActionsLineGraph'
3 | export * from './ActionsHorizontalBar'
4 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/0002_events_materialized.py:
--------------------------------------------------------------------------------
1 | from infi.clickhouse_orm import migrations
2 |
3 | operations = [migrations.RunSQL("SELECT 1")]
4 |
--------------------------------------------------------------------------------
/.kearc:
--------------------------------------------------------------------------------
1 | {
2 | "tsConfigPath": "./tsconfig.json",
3 | "rootPath": "./frontend/src",
4 | "typesPath": "./frontend/src",
5 | "writePaths": true
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/AlertMessage/index.ts:
--------------------------------------------------------------------------------
1 | export { AlertMessage } from './AlertMessage'
2 | export type { AlertMessageProps } from './AlertMessage'
3 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/Annotations/index.ts:
--------------------------------------------------------------------------------
1 | export * from './AnnotationMarker'
2 | export * from './Annotations'
3 | export * from './annotationsLogic'
4 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/LemonDivider/index.ts:
--------------------------------------------------------------------------------
1 | export { LemonDivider } from './LemonDivider'
2 | export type { LemonDividerProps } from './LemonDivider'
3 |
--------------------------------------------------------------------------------
/plugin-server/tests/assets/GeoLite2-City-Test.mmdb.br:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/plugin-server/tests/assets/GeoLite2-City-Test.mmdb.br
--------------------------------------------------------------------------------
/frontend/src/scenes/insights/views/WorldMap/index.ts:
--------------------------------------------------------------------------------
1 | export { WorldMap } from './WorldMap'
2 | export { countryCodeToFlag, countryCodeToName } from './countryCodes'
3 |
--------------------------------------------------------------------------------
/bin/docker-dev:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 | python manage.py migrate
5 |
6 | python manage.py runserver 0.0.0.0:8000 & ./bin/start-worker & ./bin/docker-frontend
7 |
--------------------------------------------------------------------------------
/bin/docker-worker-beat:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | rm celerybeat.pid || echo "celerybeat.pid not found, proceeding"
5 | celery -A posthog beat -S redbeat.RedBeatScheduler
--------------------------------------------------------------------------------
/posthog/demo/matrix/__init__.py:
--------------------------------------------------------------------------------
1 | # There is no spoon.
2 | from .manager import MatrixManager
3 | from .matrix import Matrix
4 |
5 | __all__ = ["Matrix", "MatrixManager"]
6 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ActivityLog/SentenceList.scss:
--------------------------------------------------------------------------------
1 | .sentence-list {
2 | display: inline;
3 |
4 | .sentence-part {
5 | display: inline;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/frontend/@posthog/apps-common/README.md:
--------------------------------------------------------------------------------
1 | # PostHog App Common Packages
2 |
3 | This is an experimental package that contains tools frontend apps can use. Please don't use yet.
4 |
--------------------------------------------------------------------------------
/frontend/src/scenes/events/index.ts:
--------------------------------------------------------------------------------
1 | export * from './EventDetails'
2 | export * from './EventElements'
3 | export * from './EventsTable'
4 | export * from './eventsTableLogic'
5 |
--------------------------------------------------------------------------------
/frontend/src/scenes/toolbar-launch/AuthorizedUrls.scss:
--------------------------------------------------------------------------------
1 | .AuthorizedUrlRow {
2 | &.highlight-on-hover:hover {
3 | background: var(--primary-bg-hover);
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/bin/migrate-check:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | python manage.py migrate --check
5 | python manage.py migrate_clickhouse --check
6 | python manage.py run_async_migrations --check
7 |
--------------------------------------------------------------------------------
/bin/start-frontend:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | # pass first argument to WEBPACK_HOT_RELOAD_HOST
5 | [ $# -ge 1 ] && export WEBPACK_HOT_RELOAD_HOST=$1
6 |
7 | yarn install
8 | yarn start
--------------------------------------------------------------------------------
/frontend/src/lib/experimental/README.md:
--------------------------------------------------------------------------------
1 | This folder contains components that are being actively tested. As such, any code/components here is subject to change or be removed at any time.
2 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/paths/paths_event_query.py:
--------------------------------------------------------------------------------
1 | from posthog.queries.paths.paths_event_query import PathEventQuery
2 |
3 |
4 | class ClickhousePathEventQuery(PathEventQuery):
5 | pass
6 |
--------------------------------------------------------------------------------
/frontend/src/scenes/plugins/source/PluginSource.scss:
--------------------------------------------------------------------------------
1 | .PluginSource {
2 | .ant-form-item-explain-error {
3 | white-space: pre-wrap;
4 | font-family: monospace;
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/posthog/settings/ee.py:
--------------------------------------------------------------------------------
1 | EE_AVAILABLE = False
2 |
3 | try:
4 | from ee.apps import EnterpriseConfig # noqa: F401
5 | except ImportError:
6 | pass
7 | else:
8 | EE_AVAILABLE = True
9 |
--------------------------------------------------------------------------------
/bin/migrate:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | python manage.py migrate
5 | python manage.py migrate_clickhouse
6 | python manage.py run_async_migrations --check
7 | python manage.py sync_replicated_schema
--------------------------------------------------------------------------------
/frontend/src/styles/vars.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Values duplicated from global.scss
3 |
4 | If you edit this file, check there too
5 | */
6 | export const styles = { zDrawer: 950, zGraphAnnotationPrompt: 99 }
7 |
--------------------------------------------------------------------------------
/bin/start-frontend-https:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | # pass first argument to WEBPACK_HOT_RELOAD_HOST
5 | [ $# -ge 1 ] && export WEBPACK_HOT_RELOAD_HOST=$1
6 |
7 | yarn install
8 | yarn start-https
9 |
--------------------------------------------------------------------------------
/frontend/@posthog/apps-common/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../../tsconfig.json",
3 | "compilerOptions": {
4 | "emitDeclarationOnly": true,
5 | "noEmit": false
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/frontend/@posthog/lemon-ui/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../../tsconfig.json",
3 | "compilerOptions": {
4 | "emitDeclarationOnly": true,
5 | "noEmit": false
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/plugin-server/src/worker/piscina.d.ts:
--------------------------------------------------------------------------------
1 | import Piscina from '@posthog/piscina'
2 |
3 | import { PluginsServerConfig } from '../types'
4 | export const makePiscina: (config: PluginsServerConfig) => Piscina
5 |
--------------------------------------------------------------------------------
/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io",
4 | "body": "Fixtures are a great way to mock data for responses to routes"
5 | }
6 |
--------------------------------------------------------------------------------
/frontend/@posthog/apps-common/src/index.ts:
--------------------------------------------------------------------------------
1 | import '~/styles'
2 | import '~/initKea'
3 |
4 | export * from 'lib/components/AdHocInsight/AdHocInsight'
5 |
6 | import api_ from 'lib/api'
7 | export const api = api_
8 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/PropertyKeyInfo.scss:
--------------------------------------------------------------------------------
1 | .property-key-info-tooltip,
2 | /* must join .ant-popover to override default width */
3 | .ant-popover.property-key-info-tooltip {
4 | max-width: 300px;
5 | }
6 |
--------------------------------------------------------------------------------
/frontend/src/styles/index.tsx:
--------------------------------------------------------------------------------
1 | import './global.scss' /* Contains PostHog's main styling configurations */
2 | import './antd.less' /* Imports Ant Design's components */
3 | import './style.scss' /* DEPRECATED */
4 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.black]
2 | line-length = 120
3 |
4 | [tool.isort]
5 | multi_line_output = 3
6 | include_trailing_comma = true
7 | force_grid_wrap = 8
8 | ensure_newline_before_comments = true
9 | line_length = 120
--------------------------------------------------------------------------------
/posthog/__init__.py:
--------------------------------------------------------------------------------
1 | # This will make sure the app is always imported when
2 | # Django starts so that shared_task will use this app.
3 | from posthog.celery import app as celery_app
4 |
5 | __all__ = ("celery_app",)
6 |
--------------------------------------------------------------------------------
/posthog/clickhouse/materialized_columns/__init__.py:
--------------------------------------------------------------------------------
1 | from posthog.settings import EE_AVAILABLE
2 |
3 | if EE_AVAILABLE:
4 | from ee.clickhouse.materialized_columns.columns import *
5 | else:
6 | from .column import *
7 |
--------------------------------------------------------------------------------
/ee/bin/docker-ch-test:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | ./bin/migrate
5 |
6 | mkdir -p frontend/dist
7 | touch frontend/dist/index.html
8 | touch frontend/dist/layout.html
9 | touch frontend/dist/exporter.html
10 | pytest ee
11 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/0011_cohortpeople_no_shard.py:
--------------------------------------------------------------------------------
1 | # This migration has been removed - it was only ever relevant on posthog-cloud and caused issues with
2 | # replicated schema migration.
3 | operations = [] # type: ignore
4 |
--------------------------------------------------------------------------------
/posthog/queries/retention/types.py:
--------------------------------------------------------------------------------
1 | from typing import NamedTuple, Tuple, Union
2 |
3 | BreakdownValues = Tuple[Union[str, int], ...]
4 | CohortKey = NamedTuple("CohortKey", (("breakdown_values", BreakdownValues), ("period", int)))
5 |
--------------------------------------------------------------------------------
/ee/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | env =
3 | DEBUG=1
4 | TEST=1
5 | DJANGO_SETTINGS_MODULE = posthog.settings
6 | addopts = -p no:warnings --reuse-db
7 |
8 | markers =
9 | ee
10 | clickhouse_only
11 | skip_on_multitenancy
12 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/UserActivityIndicator/UserActivityIndicator.scss:
--------------------------------------------------------------------------------
1 | .UserActivityIndicator {
2 | display: flex;
3 | align-items: center;
4 | font-size: 0.8125rem;
5 | white-space: nowrap;
6 | overflow-x: auto;
7 | }
8 |
--------------------------------------------------------------------------------
/frontend/src/scenes/Unsubscribe/Unsubscribe.scss:
--------------------------------------------------------------------------------
1 | .Unsubscribe {
2 | min-height: 80vh;
3 | align-items: center;
4 | justify-content: center;
5 | display: flex;
6 | flex-direction: column;
7 | padding: 40px 16px;
8 | }
9 |
--------------------------------------------------------------------------------
/frontend/src/scenes/insights/__image_snapshots__/Insights trends can render bar graphs #0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/src/scenes/insights/__image_snapshots__/Insights trends can render bar graphs #0.png
--------------------------------------------------------------------------------
/frontend/src/scenes/insights/__image_snapshots__/Insights trends can render bar graphs #1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kefranabg/posthog/master/frontend/src/scenes/insights/__image_snapshots__/Insights trends can render bar graphs #1.png
--------------------------------------------------------------------------------
/posthog/plugins/__init__.py:
--------------------------------------------------------------------------------
1 | # flake8: noqa
2 | from .access import can_configure_plugins, can_install_plugins
3 | from .reload import reload_plugins_on_workers
4 | from .utils import download_plugin_archive, get_file_from_archive, parse_url
5 |
--------------------------------------------------------------------------------
/plugin-server/src/utils/node-schedule.ts:
--------------------------------------------------------------------------------
1 | import * as schedule from 'node-schedule'
2 |
3 | export function cancelAllScheduledJobs(): void {
4 | Object.values(schedule.scheduledJobs).forEach((job) => {
5 | job.cancel()
6 | })
7 | }
8 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/0010_cohortpeople.py:
--------------------------------------------------------------------------------
1 | from infi.clickhouse_orm import migrations
2 |
3 | from posthog.models.cohort.sql import CREATE_COHORTPEOPLE_TABLE_SQL
4 |
5 | operations = [migrations.RunSQL(CREATE_COHORTPEOPLE_TABLE_SQL())]
6 |
--------------------------------------------------------------------------------
/posthog/models/filters/__init__.py:
--------------------------------------------------------------------------------
1 | from .filter import Filter
2 | from .path_filter import PathFilter
3 | from .retention_filter import RetentionFilter
4 |
5 | __all__ = [
6 | "Filter",
7 | "PathFilter",
8 | "RetentionFilter",
9 | ]
10 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | release: REDIS_URL='redis://' python manage.py migrate
2 | web: gunicorn posthog.wsgi --log-file -
3 | worker: ./bin/docker-worker
4 | celeryworker: ./bin/docker-worker-celery --with-scheduler # optional
5 | pluginworker: ./bin/plugin-server # optional
6 |
--------------------------------------------------------------------------------
/posthog/templates/email/async_migration_status.html:
--------------------------------------------------------------------------------
1 | {% extends "email/base.html" %} {% load posthog_assets %} {% load posthog_filters %} {% block section %}
2 |
3 |
4 | {{ migration_status_update }}
5 |
6 | {% endblock %}
7 |
--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | env =
3 | DEBUG=1
4 | TEST=1
5 | DJANGO_SETTINGS_MODULE = posthog.settings
6 | addopts = -p no:warnings --reuse-db
7 |
8 | markers =
9 | ee
10 | clickhouse_only
11 | skip_on_multitenancy
12 | async_migrations
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | venv
2 | env
3 | .venv
4 | __pycache__/
5 | staticfiles
6 | .env
7 | *.code-workspace
8 | frontend/.cache/
9 | .mypy_cache
10 | frontend/dist/
11 | *Type.ts
12 | .idea
13 | .yalc
14 | .python-version
15 | storybook-static
16 | dist/
17 | node_modules/
--------------------------------------------------------------------------------
/ee/clickhouse/queries/paths/paths_actors.py:
--------------------------------------------------------------------------------
1 | from ee.clickhouse.queries.paths.paths import ClickhousePaths
2 | from posthog.queries.paths.paths_actors import PathsActors
3 |
4 |
5 | class ClickhousePathsActors(PathsActors, ClickhousePaths): # type: ignore
6 | pass
7 |
--------------------------------------------------------------------------------
/plugin-server/src/utils/posthog.ts:
--------------------------------------------------------------------------------
1 | import PostHog from 'posthog-node'
2 |
3 | export const posthog = new PostHog('sTMFPsFhdP1Ssg', {
4 | host: 'https://app.posthog.com',
5 | })
6 |
7 | if (process.env.NODE_ENV === 'test') {
8 | posthog.disable()
9 | }
10 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 |
3 | const plugins = [require('autoprefixer')] // postCSS modules here
4 | if (process.env.NODE_ENV === 'production') {
5 | plugins.push(require('cssnano'))
6 | }
7 |
8 | module.exports = {
9 | plugins,
10 | }
11 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/0007_static_cohorts_table.py:
--------------------------------------------------------------------------------
1 | from infi.clickhouse_orm import migrations
2 |
3 | from posthog.models.person.sql import PERSON_STATIC_COHORT_TABLE_SQL
4 |
5 | operations = [
6 | migrations.RunSQL(PERSON_STATIC_COHORT_TABLE_SQL()),
7 | ]
8 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ProfilePicture/index.ts:
--------------------------------------------------------------------------------
1 | export { ProfilePicture } from './ProfilePicture'
2 | export type { ProfilePictureProps } from './ProfilePicture'
3 | export { ProfileBubbles } from './ProfileBubbles'
4 | export type { ProfileBubblesProps } from './ProfileBubbles'
5 |
--------------------------------------------------------------------------------
/frontend/src/scenes/authentication/PasswordInput.scss:
--------------------------------------------------------------------------------
1 | .password-input {
2 | .password-input-strength-indicator {
3 | margin: 0;
4 | flex-grow: 1;
5 | .ant-form-item-control-input {
6 | min-height: unset;
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/frontend/src/scenes/insights/views/LineGraph/LineGraph.scss:
--------------------------------------------------------------------------------
1 | .graph-container {
2 | position: absolute;
3 | width: 100%;
4 | height: 100%;
5 |
6 | .annotations-root {
7 | position: absolute;
8 | top: 0;
9 | left: 0;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/plugin-server/src/worker/vm/transforms/common.ts:
--------------------------------------------------------------------------------
1 | import { PluginObj } from '@babel/core'
2 | import * as types from '@babel/types'
3 |
4 | import { Hub } from '../../../types'
5 |
6 | export type PluginGen = (server: Hub, ...args: any[]) => (param: { types: typeof types }) => PluginObj
7 |
--------------------------------------------------------------------------------
/bin/start-https:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
5 |
6 | export IS_BEHIND_PROXY=1
7 | export DISABLE_SECURE_SSL_REDIRECT=1
8 | ./bin/start-worker &
9 | ./bin/start-backend &
10 | ./bin/start-frontend-https &
11 |
12 | wait
13 |
--------------------------------------------------------------------------------
/posthog/queries/event_query/__init__.py:
--------------------------------------------------------------------------------
1 | from posthog.settings import EE_AVAILABLE
2 |
3 | if EE_AVAILABLE:
4 | from ee.clickhouse.queries.event_query import EnterpriseEventQuery as EventQuery
5 | else:
6 | from posthog.queries.event_query.event_query import EventQuery # type: ignore
7 |
--------------------------------------------------------------------------------
/frontend/src/scenes/persons/PersonHeader.scss:
--------------------------------------------------------------------------------
1 | .person-header {
2 | .profile-picture {
3 | transition: opacity 200ms ease;
4 | margin-right: 0.5rem;
5 | }
6 | a:hover {
7 | .profile-picture {
8 | opacity: 0.75;
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/plugin-server/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "loose": true,
7 | "targets": { "node": 16 }
8 | }
9 | ],
10 | "@babel/preset-typescript"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/posthog/models/filters/session_recordings_filter.py:
--------------------------------------------------------------------------------
1 | from posthog.models import Filter
2 | from posthog.models.filters.mixins.session_recordings import PersonUUIDMixin, SessionRecordingsMixin
3 |
4 |
5 | class SessionRecordingsFilter(SessionRecordingsMixin, PersonUUIDMixin, Filter):
6 | pass
7 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/DatePicker.tsx:
--------------------------------------------------------------------------------
1 | import dayjsGenerateConfig from 'rc-picker/lib/generate/dayjs'
2 | import generatePicker from 'antd/lib/date-picker/generatePicker'
3 |
4 | import { dayjs } from 'lib/dayjs'
5 |
6 | export const DatePicker = generatePicker(dayjsGenerateConfig)
7 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/LemonTable/index.ts:
--------------------------------------------------------------------------------
1 | export { LemonTable } from './LemonTable'
2 | export type { LemonTableProps } from './LemonTable'
3 | export type { Sorting } from './sorting'
4 | export type { ExpandableConfig, LemonTableColumn, LemonTableColumnGroup, LemonTableColumns } from './types'
5 |
--------------------------------------------------------------------------------
/posthog/queries/groups_join_query/__init__.py:
--------------------------------------------------------------------------------
1 | from posthog.settings import EE_AVAILABLE
2 |
3 | if EE_AVAILABLE:
4 | from ee.clickhouse.queries.groups_join_query import GroupsJoinQuery
5 | else:
6 | from posthog.queries.groups_join_query.groups_join_query import GroupsJoinQuery # type: ignore
7 |
--------------------------------------------------------------------------------
/posthog/settings/statsd.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | # Metrics - StatsD
4 | STATSD_HOST = os.getenv("STATSD_HOST")
5 | STATSD_PORT = os.getenv("STATSD_PORT", 8125)
6 | STATSD_PREFIX = os.getenv("STATSD_PREFIX", "")
7 | STATSD_TELEGRAF = True
8 | STATSD_CLIENT = "statshog"
9 | STATSD_SEPARATOR = "_"
10 |
--------------------------------------------------------------------------------
/posthog/test/mock_urls_cloud.py:
--------------------------------------------------------------------------------
1 | from posthog.urls import opt_slash_path
2 | from posthog.views import robots_txt
3 |
4 | settings = {"MULTI_TENANCY": True}
5 |
6 | urlpatterns = []
7 |
8 | if not settings["MULTI_TENANCY"]:
9 | urlpatterns.append(opt_slash_path("robots.txt", robots_txt))
10 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/LemonButton/index.ts:
--------------------------------------------------------------------------------
1 | export { LemonButton, LemonButtonWithSideAction, LemonButtonWithPopup } from './LemonButton'
2 | export type {
3 | LemonButtonProps,
4 | LemonButtonWithSideActionProps,
5 | LemonButtonWithPopupProps,
6 | SideAction,
7 | } from './LemonButton'
8 |
--------------------------------------------------------------------------------
/posthog/models/event_buffer.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class EventBuffer(models.Model):
5 | event: models.JSONField = models.JSONField(null=True, blank=True)
6 | process_at: models.DateTimeField = models.DateTimeField()
7 | locked: models.BooleanField = models.BooleanField()
8 |
--------------------------------------------------------------------------------
/posthog/queries/cohort_query.py:
--------------------------------------------------------------------------------
1 | from posthog.settings import EE_AVAILABLE
2 |
3 | if EE_AVAILABLE:
4 | from ee.clickhouse.queries.enterprise_cohort_query import EnterpriseCohortQuery as CohortQuery
5 | else:
6 | from posthog.queries.foss_cohort_query import FOSSCohortQuery as CohortQuery # type: ignore
7 |
--------------------------------------------------------------------------------
/posthog/test/mock_urls_self_hosted.py:
--------------------------------------------------------------------------------
1 | from posthog.urls import opt_slash_path
2 | from posthog.views import robots_txt
3 |
4 | settings = {"MULTI_TENANCY": False}
5 |
6 | urlpatterns = []
7 |
8 | if not settings["MULTI_TENANCY"]:
9 | urlpatterns.append(opt_slash_path("robots.txt", robots_txt))
10 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/HelpButton/HelpButton.scss:
--------------------------------------------------------------------------------
1 | .help-button {
2 | align-items: center;
3 | height: 2.5rem;
4 | cursor: pointer;
5 | display: flex;
6 | font-size: 1.5rem;
7 | color: var(--primary-alt);
8 |
9 | &.inline {
10 | display: inline-flex;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/PaginationControl/index.tsx:
--------------------------------------------------------------------------------
1 | export { PaginationControl } from './PaginationControl'
2 | export { usePagination } from './usePagination'
3 | export type { PaginationControlProps } from './PaginationControl'
4 | export type { PaginationAuto, PaginationManual, PaginationState } from './types'
5 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/DurationPicker/DurationPicker.scss:
--------------------------------------------------------------------------------
1 | .DurationPicker {
2 | display: flex;
3 | flex-direction: row;
4 | .DurationPicker__time-input {
5 | flex: 1;
6 | }
7 | .DurationPicker__unit-picker {
8 | flex: 1;
9 | margin-left: 0.5rem;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/plugin-server/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 | max_line_length = 120
12 |
13 | [*.md]
14 | trim_trailing_whitespace = false
15 |
--------------------------------------------------------------------------------
/plugin-server/tsconfig.eslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "rootDir": "./",
6 | "noEmit": true
7 | },
8 | "include": [".", "src", "tests", ".eslintrc.js"],
9 | "exclude": ["node_modules", "dist", "bin"]
10 | }
11 |
--------------------------------------------------------------------------------
/bin/docker-worker:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | ./bin/migrate-check
5 |
6 | # Stop any background jobs on exit
7 | trap 'kill $(jobs -p)' EXIT
8 |
9 | ./bin/plugin-server &
10 | ./bin/docker-worker-celery --with-scheduler &
11 |
12 | # Exit if any processes exit, and exit with it's exit code
13 | wait -n
14 | exit $?
15 |
--------------------------------------------------------------------------------
/frontend/src/mocks/features.ts:
--------------------------------------------------------------------------------
1 | import { AvailableFeature } from '~/types'
2 |
3 | let features: AvailableFeature[] = []
4 | export const useAvailableFeatures = (f: AvailableFeature[]): void => {
5 | features = f
6 | }
7 | export const getAvailableFeatures = (): AvailableFeature[] => {
8 | return features
9 | }
10 |
--------------------------------------------------------------------------------
/share/share.md:
--------------------------------------------------------------------------------
1 | # Share folder
2 |
3 | Put here any resources that should be shared across all projects (events, web, worker, plugins, etc.). Most likely this will be things like small static databases or other resources.
4 |
5 | Examples:
6 | - GeoLite2-City.mmdb
7 | - Some small lookup Sqlite db
8 | - random data?
9 |
10 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/AddToDashboard/AddToDashboard.scss:
--------------------------------------------------------------------------------
1 | .add-to-dashboard-modal {
2 | .list-wrapper {
3 | min-height: 420px;
4 | }
5 |
6 | .existing-links-info {
7 | color: var(--muted-alt);
8 |
9 | strong {
10 | color: var(--default);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/PropertyFilters/components/FilterRow.scss:
--------------------------------------------------------------------------------
1 | .filter-row-popup {
2 | // so the datepicker is visible
3 | overflow: visible;
4 | }
5 |
6 | .property-filter-row {
7 | overflow: hidden;
8 | flex-basis: 100%;
9 |
10 | &.wrap-filters {
11 | flex-basis: auto;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/0025_json_events.py:
--------------------------------------------------------------------------------
1 | from infi.clickhouse_orm import migrations
2 |
3 | from posthog.models.event.sql import EVENTS_TABLE_JSON_MV_SQL, KAFKA_EVENTS_TABLE_JSON_SQL
4 |
5 | operations = [
6 | migrations.RunSQL(KAFKA_EVENTS_TABLE_JSON_SQL()),
7 | migrations.RunSQL(EVENTS_TABLE_JSON_MV_SQL()),
8 | ]
9 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/Fade/Fade.scss:
--------------------------------------------------------------------------------
1 | @keyframes fadeComponentFadeIn {
2 | 0% {
3 | opacity: 0;
4 | }
5 | 100% {
6 | opacity: 1;
7 | }
8 | }
9 |
10 | @keyframes fadeComponentFadeOut {
11 | 0% {
12 | opacity: 1;
13 | }
14 | 100% {
15 | opacity: 0;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/frontend/src/scenes/cohorts/Cohort.scss:
--------------------------------------------------------------------------------
1 | .Cohort__Name {
2 | &.ant-form-item-has-error {
3 | .ant-form-item-explain-error {
4 | font-weight: 500;
5 | margin: 0.25rem 0;
6 | }
7 |
8 | .LemonInput {
9 | border: 1px solid var(--danger);
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ee/api/test/__snapshots__/test_instance_settings.ambr:
--------------------------------------------------------------------------------
1 | # name: TestInstanceSettings.test_update_recordings_ttl_setting
2 | '
3 | /* request:api_instance_settings_(?P[^_.]+)_?$ (InstanceSettingsViewset) */
4 | ALTER TABLE sharded_session_recording_events ON CLUSTER 'posthog' MODIFY TTL toDate(created_at) + toIntervalWeek(5)
5 | '
6 | ---
7 |
--------------------------------------------------------------------------------
/frontend/src/scenes/plugins/plugin/SourcePluginTag.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Tag } from 'antd'
3 |
4 | export function SourcePluginTag({
5 | title = 'Source Code',
6 | style,
7 | }: {
8 | title?: string
9 | style?: React.CSSProperties
10 | }): JSX.Element {
11 | return {title}
12 | }
13 |
--------------------------------------------------------------------------------
/posthog/migrations/0175_should_update_person_props_function.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.12 on 2021-10-05 13:06
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0174_organization_slug"),
10 | ]
11 |
12 | operations = [] # type: ignore
13 |
--------------------------------------------------------------------------------
/posthog/models/filters/mixins/base.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, Literal
2 |
3 | BreakdownType = Literal["event", "person", "cohort", "group", "session"]
4 | IntervalType = Literal["hour", "day", "week", "month"]
5 | FunnelWindowIntervalType = Literal["minute", "hour", "day", "week", "month"]
6 |
7 |
8 | class BaseParamMixin:
9 | _data: Dict
10 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/EmptyMessage/EmptyMessage.scss:
--------------------------------------------------------------------------------
1 | .empty-message {
2 | display: flex;
3 | flex-direction: column;
4 | height: 100%;
5 | justify-content: center;
6 | align-items: center;
7 |
8 | .title {
9 | text-align: center;
10 | }
11 | .description {
12 | text-align: center;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/Property.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export function Property({ value }: { value: any }): JSX.Element {
4 | return (
5 |
6 | {typeof value === 'object' ? JSON.stringify(value) : value && value.toString().replace(/(^\w+:|^)\/\//, '')}
7 |
8 | )
9 | }
10 |
--------------------------------------------------------------------------------
/frontend/src/scenes/plugins/plugin/styles/metrics-drawer.scss:
--------------------------------------------------------------------------------
1 | .metrics-drawer {
2 | z-index: var(--z-drawer);
3 | .metrics-chart-wrapper {
4 | canvas {
5 | max-width: 90%;
6 | max-height: 80%;
7 | }
8 | canvas:hover {
9 | cursor: default !important;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/0031_event_properties_zstd.py:
--------------------------------------------------------------------------------
1 | from infi.clickhouse_orm import migrations
2 |
3 | from posthog.settings import CLICKHOUSE_CLUSTER
4 |
5 | operations = [
6 | migrations.RunSQL(
7 | f"ALTER TABLE sharded_events ON CLUSTER '{CLICKHOUSE_CLUSTER}' MODIFY COLUMN properties VARCHAR CODEC(ZSTD(3))"
8 | ),
9 | ]
10 |
--------------------------------------------------------------------------------
/posthog/tasks/user_identify.py:
--------------------------------------------------------------------------------
1 | import posthoganalytics
2 |
3 | from posthog.celery import app
4 | from posthog.models import User
5 |
6 |
7 | @app.task(ignore_result=True)
8 | def identify_task(user_id: int) -> None:
9 |
10 | user = User.objects.get(id=user_id)
11 | posthoganalytics.identify(user.distinct_id, user.get_analytics_metadata())
12 |
--------------------------------------------------------------------------------
/posthog/plugins/reload.py:
--------------------------------------------------------------------------------
1 | import structlog
2 | from django.conf import settings
3 |
4 | from posthog.redis import get_client
5 |
6 | logger = structlog.get_logger(__name__)
7 |
8 |
9 | def reload_plugins_on_workers():
10 | logger.info("Reloading plugins on workers")
11 | get_client().publish(settings.PLUGINS_RELOAD_PUBSUB_CHANNEL, "reload!")
12 |
--------------------------------------------------------------------------------
/posthog/settings/ingestion.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from posthog.settings.utils import get_from_env, get_list
4 |
5 | INGESTION_LAG_METRIC_TEAM_IDS = get_list(os.getenv("INGESTION_LAG_METRIC_TEAM_IDS", ""))
6 |
7 | # KEEP IN SYNC WITH plugin-server/src/config/config.ts
8 | BUFFER_CONVERSION_SECONDS = get_from_env("BUFFER_CONVERSION_SECONDS", default=60, type_cast=int)
9 |
--------------------------------------------------------------------------------
/posthog/templates/email/async_migration_error.html:
--------------------------------------------------------------------------------
1 | {% extends "email/base.html" %} {% load posthog_assets %} {% load posthog_filters %} {% block section %}
2 |
3 |
4 | Async migration {{ migration_key }} errored at {{ time }} with error:
5 |
6 |
7 | {{ error }}
8 |
9 |
10 | {% endblock %}
11 |
--------------------------------------------------------------------------------
/bin/check_kafka_clickhouse_up:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | # Check Kafka
6 | while true; do
7 | nc -z localhost 9092 && break || echo 'Checking Kafka status...' && sleep 1
8 | done
9 |
10 | # Check ClickHouse
11 | while true; do
12 | curl -s -o /dev/null -I 'http://localhost:8123/' && break || echo 'Checking ClickHouse status...' && sleep 1
13 | done
14 |
--------------------------------------------------------------------------------
/frontend/src/layout/navigation/DemoWarnings/DemoWarnings.scss:
--------------------------------------------------------------------------------
1 | .demo-warning {
2 | display: flex;
3 | align-items: center;
4 |
5 | .ant-alert-message {
6 | font-weight: bold;
7 | }
8 |
9 | .ant-alert-close-icon .anticon-close svg {
10 | height: 14px;
11 | width: 14px;
12 | margin-left: 1rem;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/src/scenes/persons/Persons.scss:
--------------------------------------------------------------------------------
1 | .extra-ids {
2 | display: inline-flex;
3 | align-items: center;
4 | height: 1.25rem;
5 | line-height: 1.125rem;
6 | margin: 0 0 0 0.25rem;
7 | padding: 0 0.25rem 0 0.375rem;
8 | color: var(--primary);
9 | cursor: pointer;
10 | svg {
11 | margin-left: 0.25rem;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/plugin-server/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | transform: {
3 | '^.+\\.(t|j)s$': ['@swc/jest'],
4 | },
5 | testEnvironment: 'node',
6 | clearMocks: true,
7 | coverageProvider: 'v8',
8 | setupFilesAfterEnv: ['./jest.setup.fetch-mock.js'],
9 | testMatch: ['/tests/**/*.test.ts'],
10 | testTimeout: 60000,
11 | }
12 |
--------------------------------------------------------------------------------
/cypress/e2e/commandPalette.js:
--------------------------------------------------------------------------------
1 | describe('Command Palette', () => {
2 | it('Shows on Ctrl + K press', () => {
3 | cy.get('body').type('{ctrl}k')
4 | cy.get('[data-attr=command-palette-input]').should('exist')
5 |
6 | cy.get('body').type('{cmd}k')
7 | cy.get('[data-attr=command-palette-input]').should('not.exist')
8 | })
9 | })
10 |
--------------------------------------------------------------------------------
/posthog/migrations/0244_drop_should_update_person_prop.py:
--------------------------------------------------------------------------------
1 | from django.db import migrations
2 |
3 |
4 | class Migration(migrations.Migration):
5 |
6 | dependencies = [
7 | ("posthog", "0243_unpack_plugin_source_files"),
8 | ]
9 |
10 | operations = [
11 | migrations.RunSQL("DROP FUNCTION IF EXISTS should_update_person_prop"),
12 | ]
13 |
--------------------------------------------------------------------------------
/.storybook/storybook.scss:
--------------------------------------------------------------------------------
1 | // Counteract toolbar styles
2 |
3 | .sb-show-main {
4 | .ant-modal-mask,
5 | .ant-modal-wrap {
6 | z-index: 1050 !important;
7 | }
8 | .ant-select-dropdown,
9 | .ant-picker-dropdown {
10 | z-index: 1060 !important;
11 | }
12 | .ant-tooltip {
13 | z-index: 1060 !important;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/Drawer.tsx:
--------------------------------------------------------------------------------
1 | import React, { PropsWithChildren } from 'react'
2 | import { Drawer as AntDrawer } from 'antd'
3 | import { DrawerProps } from 'antd/lib/drawer'
4 | import { styles } from '~/styles/vars'
5 |
6 | export function Drawer(props: PropsWithChildren): JSX.Element {
7 | return
8 | }
9 |
--------------------------------------------------------------------------------
/plugin-server/src/init.ts:
--------------------------------------------------------------------------------
1 | import { initSentry } from './sentry'
2 | import { PluginsServerConfig } from './types'
3 | import { setLogLevel } from './utils/utils'
4 |
5 | // Code that runs on app start, in both the main and worker threads
6 | export function initApp(config: PluginsServerConfig): void {
7 | setLogLevel(config.LOG_LEVEL)
8 | initSentry(config)
9 | }
10 |
--------------------------------------------------------------------------------
/frontend/src/scenes/instance/SystemStatus/index.scss:
--------------------------------------------------------------------------------
1 | .system-status-scene {
2 | margin-bottom: 64px;
3 | .metric-column {
4 | @media (min-width: 750px) {
5 | width: 33%;
6 | }
7 | }
8 | }
9 |
10 | .embedded-svg-wrapper {
11 | cursor: text;
12 |
13 | svg {
14 | width: 100%;
15 | height: 100%;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/posthog/migrations/0041_merge_20200407_1805.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-04-07 18:05
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0040_remove_event_ip"),
10 | ("posthog", "0039_user_email_opt_in"),
11 | ]
12 |
13 | operations = [] # type: ignore
14 |
--------------------------------------------------------------------------------
/posthog/migrations/0049_delete_funnelstep.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-04-21 10:08
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0048_auto_20200420_1051"),
10 | ]
11 |
12 | operations = [
13 | migrations.DeleteModel(name="FunnelStep",),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0184_delete_sessionsfilter.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2021-11-29 14:38
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0183_groups_pg"),
10 | ]
11 |
12 | operations = [
13 | migrations.DeleteModel(name="SessionsFilter",),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/types.py:
--------------------------------------------------------------------------------
1 | from typing import Union
2 |
3 | from posthog.models.filters.filter import Filter
4 | from posthog.models.filters.path_filter import PathFilter
5 | from posthog.models.filters.retention_filter import RetentionFilter
6 | from posthog.models.filters.stickiness_filter import StickinessFilter
7 |
8 | FilterType = Union[Filter, PathFilter, RetentionFilter, StickinessFilter]
9 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/0018_group_analytics_schema.py:
--------------------------------------------------------------------------------
1 | from infi.clickhouse_orm import migrations
2 |
3 | from posthog.models.group.sql import GROUPS_TABLE_MV_SQL, GROUPS_TABLE_SQL, KAFKA_GROUPS_TABLE_SQL
4 |
5 | operations = [
6 | migrations.RunSQL(GROUPS_TABLE_SQL()),
7 | migrations.RunSQL(KAFKA_GROUPS_TABLE_SQL()),
8 | migrations.RunSQL(GROUPS_TABLE_MV_SQL),
9 | ]
10 |
--------------------------------------------------------------------------------
/posthog/migrations/0129_merge_20210223_0757.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.6 on 2021-02-23 07:57
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0128_stricter_team_schema"),
10 | ("posthog", "0127_add_dashboard_filters"),
11 | ]
12 |
13 | operations = [] # type: ignore
14 |
--------------------------------------------------------------------------------
/posthog/migrations/0148_merge_20210506_0823.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.8 on 2021-05-06 08:23
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0147_plugin_logs"),
10 | ("posthog", "0147_fix_stickiness_dashboard_items"),
11 | ]
12 |
13 | operations = [] # type: ignore
14 |
--------------------------------------------------------------------------------
/frontend/src/layout/Error404.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { PageHeader } from 'lib/components/PageHeader'
3 |
4 | export function Error404(): JSX.Element {
5 | return (
6 |
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/LinkButton.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button } from 'antd'
3 | import { Link, LinkProps } from 'lib/components/Link'
4 |
5 | export function LinkButton(props: LinkProps & { icon?: React.ReactNode }): JSX.Element {
6 | const { icon, ...linkProps } = props
7 | return } />
8 | }
9 |
--------------------------------------------------------------------------------
/posthog/migrations/0239_delete_postgres_pluginlogentry.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-05-24 12:34
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0238_exportedasset"),
10 | ]
11 |
12 | operations = [
13 | migrations.DeleteModel(name="PluginLogEntry",),
14 | ]
15 |
--------------------------------------------------------------------------------
/frontend/src/lib/hooks/usePeriodicRerender.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | export function usePeriodicRerender(milliseconds: number): void {
4 | const [, setTick] = useState(0)
5 |
6 | useEffect(() => {
7 | const intervalId = setInterval(() => setTick((state) => state + 1), milliseconds)
8 | return () => clearInterval(intervalId)
9 | })
10 | }
11 |
--------------------------------------------------------------------------------
/latest_migrations.manifest:
--------------------------------------------------------------------------------
1 | admin: 0003_logentry_add_action_flag_choices
2 | auth: 0012_alter_user_first_name_max_length
3 | axes: 0006_remove_accesslog_trusted
4 | contenttypes: 0002_remove_content_type_name
5 | ee: 0013_silence_deprecated_tags_warnings
6 | posthog: 0254_prompt_sequence_state
7 | rest_hooks: 0002_swappable_hook_model
8 | sessions: 0001_initial
9 | social_django: 0010_uid_db_index
10 |
--------------------------------------------------------------------------------
/posthog/migrations/0040_remove_event_ip.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-04-04 11:45
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0039_populate_event_ip_property"),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(model_name="event", name="ip",),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0117_merge_20210126_0917.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-01-26 09:17
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0116_plugin_latest_tag"),
10 | ("posthog", "0116_session_recording_retention_period"),
11 | ]
12 |
13 | operations = [] # type: ignore
14 |
--------------------------------------------------------------------------------
/ee/clickhouse/test/test_calculate_event_property_usage.py:
--------------------------------------------------------------------------------
1 | from posthog.tasks.test.test_calculate_event_property_usage import calculate_event_property_usage_test_factory
2 | from posthog.test.base import ClickhouseTestMixin, _create_event
3 |
4 |
5 | class CalculateEventPropertyUsage(
6 | ClickhouseTestMixin, calculate_event_property_usage_test_factory(_create_event), # type: ignore
7 | ):
8 | pass
9 |
--------------------------------------------------------------------------------
/posthog/migrations/0176_update_person_props_function.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.12 on 2021-10-05 13:06
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0175_should_update_person_props_function"),
10 | ]
11 |
12 | # The type and function were never used
13 | operations = [] # type: ignore
14 |
--------------------------------------------------------------------------------
/posthog/tasks/sync_all_organization_available_features.py:
--------------------------------------------------------------------------------
1 | from typing import Sequence, cast
2 |
3 | from posthog.models.organization import Organization
4 |
5 |
6 | def sync_all_organization_available_features() -> None:
7 | for organization in cast(Sequence[Organization], Organization.objects.all().only("id")):
8 | organization.update_available_features()
9 | organization.save()
10 |
--------------------------------------------------------------------------------
/ee/tasks/org_usage_report.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from posthog.tasks.org_usage_report import OrgReport, send_all_reports
4 |
5 |
6 | def send_all_org_usage_reports(*, dry_run: bool = False) -> List[OrgReport]:
7 | """
8 | Creates and sends usage reports for all teams.
9 | Returns a list of all the successfully sent reports.
10 | """
11 | return send_all_reports(dry_run=dry_run)
12 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/CloseButton.tsx:
--------------------------------------------------------------------------------
1 | import { CloseOutlined } from '@ant-design/icons'
2 | import React from 'react'
3 |
4 | export function CloseButton(props: Record): JSX.Element {
5 | return (
6 |
7 |
8 |
9 | )
10 | }
11 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/PaginationControl/PaginationControl.scss:
--------------------------------------------------------------------------------
1 | .PaginationControl {
2 | align-self: flex-end;
3 | display: flex;
4 | align-items: center;
5 | justify-content: flex-end;
6 | border: 1px solid var(--border);
7 | border-radius: var(--radius);
8 | padding: 0.5rem 1rem;
9 | margin-top: 1rem;
10 | > span {
11 | margin-right: 0.5rem;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/lib/hooks/useSecondRender.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | export function useSecondRender(callback) {
4 | const [secondRender, setSecondRender] = useState(false)
5 |
6 | useEffect(() => {
7 | requestAnimationFrame(() => {
8 | setSecondRender(true)
9 | callback()
10 | })
11 | }, [])
12 |
13 | return secondRender
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/src/stories/Missing components.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta } from '@storybook/addon-docs';
2 |
3 |
4 |
5 | # Missing components
6 |
7 | A lot of components are missing. TODO for now:
8 |
9 | 1. Make an overview of what is there in the `lib/components` folder, and `lib/` in general.
10 | 2. Make a list of components that need stories
11 | 3. Create those stories
12 |
--------------------------------------------------------------------------------
/posthog/migrations/0005_remove_person_distinct_ids.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.7 on 2020-01-25 19:13
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0004_auto_20200125_0415"),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(model_name="person", name="distinct_ids",),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0093_remove_user_is_superuser.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.7 on 2020-10-26 11:07
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0092_rename_projects_to_default"),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveField(model_name="user", name="is_superuser",),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/queries/column_optimizer/column_optimizer.py:
--------------------------------------------------------------------------------
1 | # isort: skip_file
2 | from posthog.settings import EE_AVAILABLE
3 |
4 | if EE_AVAILABLE:
5 | from ee.clickhouse.queries.column_optimizer import EnterpriseColumnOptimizer as ColumnOptimizer
6 | else:
7 | from posthog.queries.column_optimizer.foss_column_optimizer import ( # type: ignore
8 | FOSSColumnOptimizer as ColumnOptimizer,
9 | )
10 |
--------------------------------------------------------------------------------
/posthog/queries/paths/__init__.py:
--------------------------------------------------------------------------------
1 | from posthog.settings import EE_AVAILABLE
2 |
3 | if EE_AVAILABLE:
4 | from ee.clickhouse.queries.paths import ClickhousePaths as Paths
5 | from ee.clickhouse.queries.paths import ClickhousePathsActors as PathsActors
6 | else:
7 | from posthog.queries.paths.paths import Paths # type: ignore
8 | from posthog.queries.paths.paths_actors import PathsActors # type: ignore
9 |
--------------------------------------------------------------------------------
/plugin-server/src/config/constants.ts:
--------------------------------------------------------------------------------
1 | import { logLevel } from 'kafkajs'
2 |
3 | export const ONE_MINUTE = 60 * 1000
4 | export const ONE_HOUR = 60 * 60 * 1000
5 | export const CELERY_DEFAULT_QUEUE = 'celery'
6 | export const KAFKAJS_LOG_LEVEL_MAPPING = {
7 | NOTHING: logLevel.NOTHING,
8 | DEBUG: logLevel.INFO,
9 | INFO: logLevel.INFO,
10 | WARN: logLevel.WARN,
11 | ERROR: logLevel.ERROR,
12 | }
13 |
--------------------------------------------------------------------------------
/posthog/api/forbid_destroy_model.py:
--------------------------------------------------------------------------------
1 | from rest_framework import status
2 | from rest_framework.response import Response
3 |
4 |
5 | class ForbidDestroyModel:
6 | """
7 | Override the default in ModelViewSet that allows callers to destroy a model instance.
8 | """
9 |
10 | def destroy(self, request, *args, **kwargs) -> Response:
11 | return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
12 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | from infi.clickhouse_orm import migrations
2 |
3 | from posthog.models.event.sql import EVENTS_TABLE_SQL
4 | from posthog.settings import CLICKHOUSE_CLUSTER, CLICKHOUSE_DATABASE
5 |
6 | operations = [
7 | migrations.RunSQL(f"CREATE DATABASE IF NOT EXISTS {CLICKHOUSE_DATABASE} ON CLUSTER '{CLICKHOUSE_CLUSTER}'"),
8 | migrations.RunSQL(EVENTS_TABLE_SQL()),
9 | ]
10 |
--------------------------------------------------------------------------------
/posthog/migrations/0009_auto_20200127_0018.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.7 on 2020-01-27 00:18
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0008_action_actionstep"),
10 | ]
11 |
12 | operations = [
13 | migrations.RenameField(model_name="element", old_name="el_text", new_name="text",),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0173_should_update_person_props_function.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.12 on 2021-10-05 13:06
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0172_person_properties_last_operation"),
10 | ]
11 |
12 | # Superseded by 0175_should_update_person_props
13 | operations = [] # type: ignore
14 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/experiments/__init__.py:
--------------------------------------------------------------------------------
1 | # The FF variant name for control
2 | CONTROL_VARIANT_KEY = "control"
3 |
4 | # controls minimum number of people to be exposed to a variant
5 | # before the results are deemed significant
6 | FF_DISTRIBUTION_THRESHOLD = 100
7 |
8 | # If probability of a variant is below this threshold, it will be considered
9 | # insignificant
10 | MIN_PROBABILITY_FOR_SIGNIFICANCE = 0.9
11 |
--------------------------------------------------------------------------------
/posthog/test/db_context_capturing.py:
--------------------------------------------------------------------------------
1 | from contextlib import contextmanager
2 |
3 | from django.db import DEFAULT_DB_ALIAS, connections
4 | from django.test.utils import CaptureQueriesContext
5 |
6 |
7 | @contextmanager
8 | def capture_db_queries():
9 | db_connection = connections[DEFAULT_DB_ALIAS]
10 | with CaptureQueriesContext(db_connection) as capture_query_context:
11 | yield capture_query_context
12 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | We always recommend using the latest version of PostHog to ensure you get all security updates.
6 |
7 | ## Reporting a Vulnerability
8 |
9 | Please report security vulnerabilities to hey@posthog.com.
10 |
11 | We currently do not operate a bug bounty program, but we will generously reward you with merch for any actionable security vulnerabilities found.
12 |
--------------------------------------------------------------------------------
/posthog/migrations/0036_remove_current_url_index.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-03-19 11:11
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0035_current_url_index_20200318_1459"),
10 | ]
11 |
12 | operations = [migrations.RunSQL("DROP INDEX IF EXISTS posthog_event_properties_current_url_gin;", "SELECT 1;",)]
13 |
--------------------------------------------------------------------------------
/posthog/migrations/0191_rename_specialmigration_asyncmigration.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2021-12-13 19:41
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0190_experiment"),
10 | ]
11 |
12 | operations = [
13 | migrations.RenameModel(old_name="SpecialMigration", new_name="AsyncMigration",),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/tasks/delete_clickhouse_data.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from posthog.celery import app
4 | from posthog.models.team.util import delete_teams_clickhouse_data, is_clickhouse_data_cron_enabled
5 |
6 |
7 | @app.task(ignore_result=True, max_retries=1)
8 | def delete_clickhouse_data(team_ids: List[int]) -> None:
9 | if not is_clickhouse_data_cron_enabled():
10 | delete_teams_clickhouse_data(team_ids)
11 |
--------------------------------------------------------------------------------
/posthog/settings/feature_flags.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from posthog.settings.utils import get_list
4 |
5 | # These flags will be force-enabled on the frontend
6 | # The features here are released, but the flags are just not yet removed from the code
7 | PERSISTED_FEATURE_FLAGS = get_list(os.getenv("PERSISTED_FEATURE_FLAGS", "")) + [
8 | "invite-teammates-prompt",
9 | "insight-legends",
10 | "simplify-actions",
11 | ]
12 |
--------------------------------------------------------------------------------
/.run/Frontend.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/frontend/src/scenes/Unsubscribe/Unsubscribe.stories.tsx:
--------------------------------------------------------------------------------
1 | import { Meta } from '@storybook/react'
2 |
3 | import { Unsubscribe } from './Unsubscribe'
4 | import React from 'react'
5 |
6 | export default {
7 | title: 'Scenes-Other/Unsubscribe',
8 | parameters: { layout: 'fullscreen', options: { showPanel: false }, viewMode: 'story' },
9 | } as Meta
10 |
11 | export const UnsubscribeScene = (): JSX.Element =>
12 |
--------------------------------------------------------------------------------
/posthog/migrations/0018_funnel_deleted.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.7 on 2020-02-09 06:17
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0017_dashboarditem"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="funnel", name="deleted", field=models.BooleanField(default=False),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0022_action_deleted.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-02-11 18:27
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0021_user_distinct_id"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="action", name="deleted", field=models.BooleanField(default=False),),
14 | ]
15 |
--------------------------------------------------------------------------------
/frontend/src/scenes/PreflightCheck/PreflightCheck.stories.tsx:
--------------------------------------------------------------------------------
1 | import { Meta } from '@storybook/react'
2 |
3 | import { PreflightCheck } from './PreflightCheck'
4 | import React from 'react'
5 |
6 | export default {
7 | title: 'Scenes-Other/Onboarding',
8 | parameters: { layout: 'fullscreen', options: { showPanel: false }, viewMode: 'story' },
9 | } as Meta
10 |
11 | export const Preflight = (): JSX.Element =>
12 |
--------------------------------------------------------------------------------
/frontend/src/scenes/ingestion/Ingestion.stories.tsx:
--------------------------------------------------------------------------------
1 | import { Meta } from '@storybook/react'
2 |
3 | import { IngestionWizard } from './IngestionWizard'
4 |
5 | import React from 'react'
6 |
7 | export default {
8 | title: 'Scenes-Other/Onboarding',
9 | parameters: { layout: 'fullscreen', options: { showPanel: false }, viewMode: 'story' },
10 | } as Meta
11 |
12 | export const Ingestion = (): JSX.Element =>
13 |
--------------------------------------------------------------------------------
/posthog/migrations/0062_team_anonymize_ips.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.6 on 2020-06-24 05:26
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0061_featureflag"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="team", name="anonymize_ips", field=models.BooleanField(default=False),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0067_team_updated_at.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.7 on 2020-06-23 19:16
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0066_team_created_at"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="team", name="updated_at", field=models.DateTimeField(auto_now=True),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0113_cohort_is_static.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-01-12 13:42
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0112_sessions_filter"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="cohort", name="is_static", field=models.BooleanField(default=False),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0207_cohort_count.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2022-02-14 15:42
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0206_global_tags_setup"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="cohort", name="count", field=models.IntegerField(blank=True, null=True),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0210_drop_update_person_functions.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2022-02-11 15:43
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0209_plugin_logs_disabled"),
10 | ]
11 |
12 | operations = [
13 | migrations.RunSQL("DROP FUNCTION IF EXISTS update_person_props, should_update_person_props"),
14 | ]
15 |
--------------------------------------------------------------------------------
/.run/Storybook.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/NotFound/NotFound.scss:
--------------------------------------------------------------------------------
1 | .not-found-component {
2 | text-align: center;
3 | margin-top: 2rem;
4 | .graphic {
5 | background: url('../../../../public/not-found-rocket.svg') no-repeat center center;
6 | height: 270px;
7 | width: 100%;
8 | }
9 | b {
10 | display: block;
11 | }
12 | p {
13 | margin: 0 auto;
14 | max-width: 600px;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0023_team_opt_out_capture.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-02-18 20:29
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0022_action_deleted"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="team", name="opt_out_capture", field=models.BooleanField(default=False),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0057_action_updated_at.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.5 on 2020-05-30 01:12
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0056_auto_20200522_1024"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="action", name="updated_at", field=models.DateTimeField(auto_now=True),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0138_featureflag_name_optional.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-03-19 23:38
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0137_team_timezone"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(model_name="featureflag", name="name", field=models.TextField(blank=True),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0157_plugin_metrics.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.8 on 2021-06-21 17:37
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0156_insight_short_id"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="plugin", name="metrics", field=models.JSONField(default=dict, null=True),),
14 | ]
15 |
--------------------------------------------------------------------------------
/cypress/e2e/persons.js:
--------------------------------------------------------------------------------
1 | describe('Persons', () => {
2 | beforeEach(() => {
3 | cy.clickNavMenu('persons')
4 | })
5 |
6 | it('All tabs work', () => {
7 | cy.get('h1').should('contain', 'Persons')
8 | cy.get('[data-attr=persons-search]').type('marisol').type('{enter}').should('have.value', 'marisol')
9 | cy.wait(200)
10 | cy.get('[data-row-key]').its('length').should('be.gte', 0)
11 | })
12 | })
13 |
--------------------------------------------------------------------------------
/frontend/src/scenes/insights/views/WorldMap/WorldMap.scss:
--------------------------------------------------------------------------------
1 | .WorldMap {
2 | padding: 1rem 0;
3 | width: 100%;
4 | color: hsl(0, 0%, 85%); // Alpha-less equivalent of --border
5 | .landxx {
6 | fill: currentColor;
7 | stroke: var(--bg-light);
8 | stroke-width: 0.125rem;
9 | fill-rule: evenodd;
10 | &:hover {
11 | color: var(--primary-dark) !important;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/plugin-server/src/worker/vm/extensions/geoip.ts:
--------------------------------------------------------------------------------
1 | import { GeoIPExtension } from '@posthog/plugin-scaffold'
2 |
3 | import { Hub } from '../../../types'
4 | import { fetchIpLocationInternally } from '../../mmdb'
5 |
6 | export function createGeoIp(server: Hub): GeoIPExtension {
7 | return {
8 | locate: async function (ipAddress) {
9 | return await fetchIpLocationInternally(ipAddress, server)
10 | },
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/posthog/migrations/0153_plugin_capabilities.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.8 on 2021-05-18 10:21
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0152_user_events_column_config"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="plugin", name="capabilities", field=models.JSONField(default=dict),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0180_person_version.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2021-10-25 11:26
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0179_add_group_type_mapping"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="person", name="version", field=models.BigIntegerField(blank=True, null=True),)
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/tasks/split_person.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from posthog.celery import app
4 | from posthog.models import Person
5 |
6 |
7 | @app.task(ignore_result=True, max_retries=1)
8 | def split_person(person_id: int, main_distinct_id: Optional[str]) -> None:
9 | """
10 | Split all distinct ids into separate persons
11 | """
12 | person = Person.objects.get(pk=person_id)
13 | person.split_person(main_distinct_id)
14 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/SelectDownIcon.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { DownOutlined } from '@ant-design/icons'
3 |
4 | // Downward arrow icon with styling that mimics that of the antd Select
5 | export const SelectDownIcon = (props: React.HTMLAttributes): JSX.Element => {
6 | return (
7 |
8 |
9 |
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/plugin-server/src/worker/ingestion/event-pipeline/5-createEventStep.ts:
--------------------------------------------------------------------------------
1 | import { PreIngestionEvent } from '../../../types'
2 | import { EventPipelineRunner, StepResult } from './runner'
3 |
4 | export async function createEventStep(runner: EventPipelineRunner, event: PreIngestionEvent): Promise {
5 | const ingestionEvent = await runner.hub.eventsProcessor.createEvent(event)
6 | return runner.nextStep('runAsyncHandlersStep', ingestionEvent)
7 | }
8 |
--------------------------------------------------------------------------------
/posthog/migrations/0105_cohort_errors_calculating.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2020-12-10 14:19
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0104_auto_20201208_1052"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="cohort", name="errors_calculating", field=models.IntegerField(default=0),),
14 | ]
15 |
--------------------------------------------------------------------------------
/.run/Jest Tests.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/stickiness/stickiness.py:
--------------------------------------------------------------------------------
1 | from ee.clickhouse.queries.stickiness.stickiness_actors import ClickhouseStickinessActors
2 | from ee.clickhouse.queries.stickiness.stickiness_event_query import ClickhouseStickinessEventsQuery
3 | from posthog.queries.stickiness.stickiness import Stickiness
4 |
5 |
6 | class ClickhouseStickiness(Stickiness):
7 | event_query_class = ClickhouseStickinessEventsQuery
8 | actor_query_class = ClickhouseStickinessActors
9 |
--------------------------------------------------------------------------------
/posthog/migrations/0151_plugin_preinstalled.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.8 on 2021-04-26 15:22
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0150_increase_element_varchars"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="plugin", name="is_preinstalled", field=models.BooleanField(default=False),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0209_plugin_logs_disabled.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2022-02-09 12:45
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0208_alter_plugin_updated_at"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="plugin", name="log_level", field=models.IntegerField(blank=True, null=True),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0230_cohort_filters.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-05-02 14:53
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0229_add_filters_hash_to_dashboard_table"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="cohort", name="filters", field=models.JSONField(blank=True, null=True),),
14 | ]
15 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | Updates to the PostHog project can be found at [https://posthog.com/blog/categories/product-updates](https://posthog.com/blog/categories/product-updates). Each release of PostHog self-hosted is accompanied by an "Array" blog post which details all relevant changes and any deprecation or warning notices.
4 |
5 | Find the latest Array blog post in the [Product updates](https://posthog.com/blog/categories/product-updates) section of our blog.
6 |
--------------------------------------------------------------------------------
/cypress/fixtures/api/event/only_time_property_definition.json:
--------------------------------------------------------------------------------
1 | {
2 | "count": 1,
3 | "next": null,
4 | "previous": null,
5 | "results": [
6 | {
7 | "id": "017dde0e-1cc9-0000-ed91-26909937767f",
8 | "name": "$time",
9 | "is_numerical": true,
10 | "query_usage_30_day": null,
11 | "property_type": "DateTime",
12 | "is_event_property": null
13 | }
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/ee/migrations/0003_license_max_users.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-04-14 00:20
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("ee", "0002_hook"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="license", name="max_users", field=models.IntegerField(default=None, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/Annotations/utils.ts:
--------------------------------------------------------------------------------
1 | import { AnnotationType } from '~/types'
2 |
3 | export function getNextKey(arr: AnnotationType[]): number {
4 | if (arr.length === 0) {
5 | return -1
6 | }
7 | const result = arr.reduce((prev, curr) => (parseInt(prev.id) < parseInt(curr.id) ? prev : curr))
8 | if (parseInt(result.id) >= 0) {
9 | return -1
10 | } else {
11 | return parseInt(result.id) - 1
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/lib/internalMetrics.ts:
--------------------------------------------------------------------------------
1 | import api from 'lib/api'
2 |
3 | interface InternalMetricsPayload {
4 | method: 'incr' | 'timing'
5 | metric: string
6 | value: number
7 | tags: Record
8 | }
9 |
10 | export async function captureInternalMetric(payload: InternalMetricsPayload): Promise {
11 | if (window.JS_CAPTURE_INTERNAL_METRICS) {
12 | await api.create('api/instance_status/capture', payload)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/posthog/management/commands/api_keys.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from posthog.models import Team
4 |
5 |
6 | class Command(BaseCommand):
7 | help = "Get project API keys through command line instead of having to go through settings"
8 |
9 | def handle(self, *args, **options):
10 | for team in Team.objects.all():
11 | print(f"{team.name + ' ' if team.name else ''}(ID {team.id}) - {team.api_token}")
12 |
--------------------------------------------------------------------------------
/posthog/migrations/0034_pg_trgm_and_btree_20200318_1447.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-03-18 14:47
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0033_auto_20200316_1655"),
10 | ]
11 |
12 | # We used to install TrigramExtension and BtreeGinExtension, but realised that made things slower rather than faster
13 | operations = [] # type: ignore
14 |
--------------------------------------------------------------------------------
/posthog/migrations/0039_user_email_opt_in.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-04-06 17:13
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0038_migrate_actions_to_precalculate_events"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="user", name="email_opt_in", field=models.BooleanField(default=False),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0059_dashboarditem_refreshing.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.7 on 2020-06-15 18:55
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0058_dashboarditem_last_refresh"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="dashboarditem", name="refreshing", field=models.BooleanField(default=False),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0081_person_is_identified.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.6 on 2020-08-22 18:04
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0080_update_dashboard_funnel_filters"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="person", name="is_identified", field=models.BooleanField(default=False),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0166_plugin_public_jobs.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.12 on 2021-09-02 14:08
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0165_dashboarditem_dive_dashboard"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="plugin", name="public_jobs", field=models.JSONField(default=dict, null=True),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0211_async_migrations_errors_length.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2022-02-16 19:29
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0210_drop_update_person_functions"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(model_name="asyncmigrationerror", name="description", field=models.TextField(),),
14 | ]
15 |
--------------------------------------------------------------------------------
/.deepsource.toml:
--------------------------------------------------------------------------------
1 | version = 1
2 |
3 | test_patterns = [
4 | "**/test_*.py",
5 | ]
6 |
7 | exclude_patterns = [
8 | "**/migrations/*.py",
9 | ]
10 |
11 | [[analyzers]]
12 | name = "python"
13 | enabled = true
14 |
15 | [analyzers.meta]
16 | runtime_version = "3.x.x"
17 |
18 | [[analyzers]]
19 | name = "docker"
20 | enabled = true
21 |
22 | [analyzers.meta]
23 | dockerfile_paths = [
24 | "preview.Dockerfile",
25 | "production.Dockerfile",
26 | ]
27 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/session_recordings/test/test_clickhouse_session_recording.py:
--------------------------------------------------------------------------------
1 | from posthog.queries.session_recordings.session_recording import SessionRecording
2 | from posthog.queries.session_recordings.test.test_session_recording import factory_session_recording_test
3 | from posthog.test.base import ClickhouseTestMixin
4 |
5 |
6 | class TestClickhouseSessionRecording(ClickhouseTestMixin, factory_session_recording_test(SessionRecording)): # type: ignore
7 | pass
8 |
--------------------------------------------------------------------------------
/frontend/src/scenes/project/Create/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { CreateProjectModal } from '../CreateProjectModal'
3 | import { SceneExport } from 'scenes/sceneTypes'
4 | import { teamLogic } from 'scenes/teamLogic'
5 |
6 | export const scene: SceneExport = {
7 | component: ProjectCreate,
8 | logic: teamLogic,
9 | }
10 |
11 | export function ProjectCreate(): JSX.Element {
12 | return
13 | }
14 |
--------------------------------------------------------------------------------
/posthog/settings/cloud.py:
--------------------------------------------------------------------------------
1 | # Overridden in posthog-cloud
2 |
3 | import sys
4 |
5 | from posthog.settings.utils import get_from_env, print_warning, str_to_bool
6 |
7 | # Early exit to avoid issues with cloud not being properly included
8 | if get_from_env("MULTI_TENANCY", False, type_cast=str_to_bool):
9 | print_warning(("️Environment variable MULTI_TENANCY is set, but cloud settings have not been included",))
10 | sys.exit("[ERROR] Stopping Django server…\n")
11 |
--------------------------------------------------------------------------------
/posthog/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for posthog project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "posthog.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/frontend/src/lib/utils/getAppContext.ts:
--------------------------------------------------------------------------------
1 | import { AppContext, PathType } from '~/types'
2 |
3 | declare global {
4 | export interface Window {
5 | POSTHOG_APP_CONTEXT?: AppContext
6 | }
7 | }
8 |
9 | export function getAppContext(): AppContext | undefined {
10 | return window.POSTHOG_APP_CONTEXT || undefined
11 | }
12 |
13 | export function getDefaultEventName(): string {
14 | return getAppContext()?.default_event_name || PathType.PageView
15 | }
16 |
--------------------------------------------------------------------------------
/plugin-server/src/main/job-queues/buffer.ts:
--------------------------------------------------------------------------------
1 | import Piscina from '@posthog/piscina'
2 | import { PluginEvent } from '@posthog/plugin-scaffold'
3 | import { Hub } from 'types'
4 |
5 | export function runBufferEventPipeline(hub: Hub, piscina: Piscina, event: PluginEvent): Promise {
6 | hub.lastActivity = new Date().valueOf()
7 | hub.lastActivityType = 'runBufferEventPipeline'
8 | return piscina.run({ task: 'runBufferEventPipeline', args: { event } })
9 | }
10 |
--------------------------------------------------------------------------------
/posthog/migrations/0019_team_name.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.7 on 2020-02-09 19:13
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0018_funnel_deleted"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="team", name="name", field=models.CharField(blank=True, max_length=200, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0202_descriptions_for_action.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2022-01-31 22:13
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0201_remove_property_type_format_constraint"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="action", name="description", field=models.TextField(blank=True, default=""),),
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/queries/stickiness/__init__.py:
--------------------------------------------------------------------------------
1 | from posthog.settings import EE_AVAILABLE
2 |
3 | if EE_AVAILABLE:
4 | from ee.clickhouse.queries.stickiness import ClickhouseStickiness as Stickiness
5 | from ee.clickhouse.queries.stickiness import ClickhouseStickinessActors as StickinessActors
6 | else:
7 | from posthog.queries.stickiness.stickiness import Stickiness # type: ignore
8 | from posthog.queries.stickiness.stickiness_actors import StickinessActors # type: ignore
9 |
--------------------------------------------------------------------------------
/bin/start-worker:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | # this kills all processes when the last one terminates
5 | trap 'kill $(jobs -p)' EXIT
6 |
7 | # start celery worker with heartbeat (-B)
8 | SKIP_ASYNC_MIGRATIONS_SETUP=0 celery -A posthog worker -B --scheduler redbeat.RedBeatScheduler --without-heartbeat --without-gossip --without-mingle -Ofair -n node@%h &
9 |
10 | if [[ "$PLUGIN_SERVER_IDLE" != "1" && "$PLUGIN_SERVER_IDLE" != "true" ]]; then
11 | ./bin/plugin-server
12 | fi
13 |
--------------------------------------------------------------------------------
/cypress/fixtures/api/event/only_browser_version_property_definition.json:
--------------------------------------------------------------------------------
1 | {
2 | "count": 1,
3 | "next": null,
4 | "previous": null,
5 | "results": [
6 | {
7 | "id": "017dde0e-1cb5-0000-68b4-44835b7c894f",
8 | "name": "$browser_version",
9 | "is_numerical": true,
10 | "query_usage_30_day": null,
11 | "property_type": null,
12 | "is_event_property": null
13 | }
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/LemonSnack/LemonSnack.scss:
--------------------------------------------------------------------------------
1 | .LemonSnack {
2 | display: inline-block;
3 | background: var(--primary-bg-hover);
4 | border-radius: var(--radius);
5 | color: var(--primary-alt);
6 |
7 | .LemonSnack__inner {
8 | display: flex;
9 | flex-direction: row;
10 | align-items: center;
11 | padding: 0.25rem 0.4rem;
12 | }
13 |
14 | .LemonSnack__close {
15 | margin-left: 0.25rem;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/frontend/src/scenes/ingestion/types.ts:
--------------------------------------------------------------------------------
1 | import {
2 | API,
3 | MOBILE,
4 | mobileFrameworks,
5 | BACKEND,
6 | WEB,
7 | webFrameworks,
8 | THIRD_PARTY,
9 | BOOKMARKLET,
10 | } from 'scenes/ingestion/constants'
11 |
12 | export type Framework = keyof typeof webFrameworks | keyof typeof mobileFrameworks | typeof API | null
13 |
14 | export type PlatformType = typeof WEB | typeof MOBILE | typeof BACKEND | typeof THIRD_PARTY | typeof BOOKMARKLET | null
15 |
--------------------------------------------------------------------------------
/mypy.ini:
--------------------------------------------------------------------------------
1 | [mypy]
2 | plugins =
3 | mypy_django_plugin.main,
4 | mypy_drf_plugin.main
5 | strict_optional = True
6 | no_implicit_optional = True
7 | warn_unused_ignores = True
8 | check_untyped_defs = True
9 | warn_unreachable = True
10 | strict_equality = True
11 | ignore_missing_imports = True
12 |
13 | [mypy-posthog.tasks.*]
14 | disallow_untyped_defs = True
15 | check_untyped_defs = True
16 |
17 | [mypy.plugins.django-stubs]
18 | django_settings_module = posthog.settings
--------------------------------------------------------------------------------
/posthog/idl/idl.md:
--------------------------------------------------------------------------------
1 | # IDL - Interface Definition Language
2 |
3 | This directory is responsible for defining the schemas of the data between services.
4 | Primarily this will be between services and ClickHouse, but can be really any thing at the boundry of services.
5 |
6 | The reason why we do this is because it makes generating code, validating data, and understanding the system a whole lot easier. We've had a few customers request this of us for engineering a deeper integration with us.
--------------------------------------------------------------------------------
/posthog/logging/timing.py:
--------------------------------------------------------------------------------
1 | from typing import Any
2 |
3 | from statshog.defaults.django import statsd
4 |
5 |
6 | def timed(name: str):
7 | def timed_decorator(func: Any) -> Any:
8 | def wrapper(*args, **kwargs):
9 | timer = statsd.timer(name).start()
10 | try:
11 | return func(*args, **kwargs)
12 | finally:
13 | timer.stop()
14 |
15 | return wrapper
16 |
17 | return timed_decorator
18 |
--------------------------------------------------------------------------------
/posthog/migrations/0214_migrate_dashboard_insight_tags.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2022-01-28 21:40
2 | from django.db import migrations
3 |
4 |
5 | def forwards(apps, schema_editor):
6 | pass
7 |
8 |
9 | def reverse(apps, schema_editor):
10 | pass
11 |
12 |
13 | class Migration(migrations.Migration):
14 | dependencies = [
15 | ("posthog", "0213_deprecated_old_tags"),
16 | ]
17 |
18 | operations = [migrations.RunPython(forwards, reverse)]
19 |
--------------------------------------------------------------------------------
/ee/api/debug_ch_queries.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from rest_framework import mixins, viewsets
4 | from rest_framework.response import Response
5 |
6 | from posthog.utils import get_safe_cache
7 |
8 |
9 | class DebugCHQueries(mixins.ListModelMixin, viewsets.GenericViewSet):
10 | """
11 | Show recent queries for this user
12 | """
13 |
14 | def list(self, request):
15 | return Response(json.loads(get_safe_cache("save_query_{}".format(request.user.pk)) or "[]"))
16 |
--------------------------------------------------------------------------------
/frontend/src/scenes/ingestion/frameworks/index.tsx:
--------------------------------------------------------------------------------
1 | export * from './AndroidInstructions'
2 | export * from './GoInstructions'
3 | export * from './NodeInstructions'
4 | export * from './iOSInstructions'
5 | export * from './PHPInstructions'
6 | export * from './PythonInstructions'
7 | export * from './ReactNativeInstructions'
8 | export * from './RubyInstructions'
9 | export * from './APIInstructions'
10 | export * from './ElixirInstructions'
11 | export * from './FlutterInstructions'
12 |
--------------------------------------------------------------------------------
/plugin-server/src/utils/kill.ts:
--------------------------------------------------------------------------------
1 | export function killProcess(): void {
2 | // In tests, only call SIGTERM once to avoid leaky tests.
3 | // In production, kill two more times if the first one fails.
4 | setTimeout(() => process.kill(process.pid, 'SIGTERM'), 100)
5 | if (process.env.NODE_ENV !== 'test') {
6 | setTimeout(() => process.kill(process.pid, 'SIGTERM'), 60000)
7 | setTimeout(() => process.kill(process.pid, 'SIGKILL'), 120000)
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/posthog/migrations/0012_team_app_url.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.7 on 2020-01-28 22:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0011_auto_20200127_2105"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="team", name="app_url", field=models.CharField(blank=True, max_length=200, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0097_invite_emails.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.7 on 2020-10-29 15:48
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0096_plugins"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="organizationinvite", name="emailing_attempt_made", field=models.BooleanField(default=False),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0208_alter_plugin_updated_at.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2022-02-14 14:28
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0207_cohort_count"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name="plugin", name="updated_at", field=models.DateTimeField(blank=True, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/frontend/@posthog/lemon-ui/README.md:
--------------------------------------------------------------------------------
1 | # PostHog Lemon UI
2 |
3 | [](https://www.npmjs.com/package/@posthog/lemon-ui)
4 | [](https://opensource.org/licenses/MIT)
5 |
6 | Please see [PostHog Storybook](https://storybook.posthog.net/).
7 | Specifically, [Lemon UI Overview](https://storybook.posthog.net/?path=/docs/lemon-ui-overview--page).
8 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/PropertyFilters/PropertyFilters.scss:
--------------------------------------------------------------------------------
1 | .PropertyFilters {
2 | display: flex;
3 | gap: 0.5rem;
4 |
5 | .PropertyFilters-content {
6 | flex: 1;
7 | display: flex;
8 | flex-wrap: wrap;
9 | gap: 0.5rem;
10 | overflow: hidden;
11 | }
12 |
13 | .PropertyFilters-prefix {
14 | color: #c4c4c4;
15 | font-size: 18px;
16 | user-select: none;
17 | padding: 0px 5px;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/0022_person_distinct_id2.py:
--------------------------------------------------------------------------------
1 | from infi.clickhouse_orm import migrations
2 |
3 | from posthog.models.person.sql import (
4 | KAFKA_PERSON_DISTINCT_ID2_TABLE_SQL,
5 | PERSON_DISTINCT_ID2_MV_SQL,
6 | PERSON_DISTINCT_ID2_TABLE_SQL,
7 | )
8 |
9 | operations = [
10 | migrations.RunSQL(PERSON_DISTINCT_ID2_TABLE_SQL()),
11 | migrations.RunSQL(KAFKA_PERSON_DISTINCT_ID2_TABLE_SQL()),
12 | migrations.RunSQL(PERSON_DISTINCT_ID2_MV_SQL,),
13 | ]
14 |
--------------------------------------------------------------------------------
/posthog/migrations/0086_team_session_recording_opt_in.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.6 on 2020-10-07 20:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0085_org_models"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="team", name="session_recording_opt_in", field=models.BooleanField(default=False),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/templates/email/canary_email.html:
--------------------------------------------------------------------------------
1 | {% extends "email/base.html" %} {% load posthog_assets %} {% block section %}
2 |
3 | If you are seeing this email, you have properly configured your email settings for your PostHog instance at
4 | {{ site_url }} . Nothing else to do here, emails will now be sent when
5 | applicable.
6 |
7 | {% endblock %}{% load posthog_filters %} {% block heading %}Email successfully set up!{% endblock %}
8 |
--------------------------------------------------------------------------------
/posthog/migrations/0015_actionstep_event.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.7 on 2020-01-30 22:58
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0014_auto_20200129_0703"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="actionstep", name="event", field=models.CharField(blank=True, max_length=400, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0045_add_timestamp_index.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-04-14 18:40
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0044_auto_20200413_1936"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddIndex(
14 | model_name="event", index=models.Index(fields=["timestamp"], name="posthog_eve_timesta_b00cec_idx"),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0119_mandatory_plugin_order.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.6 on 2021-01-28 14:55
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0118_is_demo"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name="pluginconfig", name="order", field=models.IntegerField(default=0), preserve_default=False,
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0134_event_site_url.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-03-17 02:15
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0133_plugins_access_control"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="event", name="site_url", field=models.CharField(blank=True, max_length=200, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0186_insight_refresh_attempt.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2021-11-30 13:10
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0185_special_migrations"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="insight", name="refresh_attempt", field=models.IntegerField(blank=True, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0188_person_distinct_id_version.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2021-12-08 07:25
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0187_stale_events"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="persondistinctid", name="version", field=models.BigIntegerField(blank=True, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/StarryBackground/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import './index.scss'
3 |
4 | export function StarryBackground({
5 | children,
6 | style,
7 | }: {
8 | children: JSX.Element
9 | style?: React.CSSProperties
10 | }): JSX.Element {
11 | return (
12 |
13 |
14 |
{children}
15 |
16 | )
17 | }
18 |
--------------------------------------------------------------------------------
/plugin-server/tests/helpers/promises.ts:
--------------------------------------------------------------------------------
1 | interface MockPromise {
2 | promise: Promise
3 | resolve: (value?: any) => void
4 | reject: (error: any) => void
5 | }
6 |
7 | export function createPromise(): MockPromise {
8 | const result: Partial> = {}
9 | result.promise = new Promise((_resolve, _reject) => {
10 | result.resolve = _resolve
11 | result.reject = _reject
12 | })
13 |
14 | return result as MockPromise
15 | }
16 |
--------------------------------------------------------------------------------
/posthog/migrations/0016_user_temporary_token.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.7 on 2020-02-01 22:13
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0015_actionstep_event"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="user", name="temporary_token", field=models.CharField(blank=True, max_length=200, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0058_dashboarditem_last_refresh.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.5 on 2020-06-10 17:56
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0057_action_updated_at"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="dashboarditem", name="last_refresh", field=models.DateTimeField(blank=True, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0060_auto_20200616_0746.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.7 on 2020-06-16 07:46
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0059_dashboarditem_refreshing"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name="element", name="href", field=models.CharField(blank=True, max_length=2048, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0171_cohort_description.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.12 on 2021-09-23 15:38
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0170_project_based_permissioning"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="cohort", name="description", field=models.CharField(blank=True, max_length=1000),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0216_insight_placeholder_name.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2022-03-03 11:44
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0215_add_tags_back"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="insight", name="derived_name", field=models.CharField(blank=True, max_length=400, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/models/tag.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | from posthog.models.utils import UUIDModel
4 |
5 |
6 | def tagify(tag: str):
7 | return tag.strip().lower()
8 |
9 |
10 | class Tag(UUIDModel):
11 | name: models.CharField = models.CharField(max_length=255)
12 | team: models.ForeignKey = models.ForeignKey("Team", on_delete=models.CASCADE)
13 |
14 | class Meta:
15 | unique_together = ("name", "team")
16 |
17 | def __str__(self):
18 | return self.name
19 |
--------------------------------------------------------------------------------
/ee/migrations/0010_migrate_definitions_tags.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2022-01-28 19:21
2 | from django.db import migrations
3 |
4 |
5 | def forwards(apps, schema_editor):
6 | pass
7 |
8 |
9 | def reverse(apps, schema_editor):
10 | pass
11 |
12 |
13 | class Migration(migrations.Migration):
14 | dependencies = [("ee", "0009_deprecated_old_tags"), ("posthog", "0213_deprecated_old_tags")]
15 |
16 | operations = [
17 | migrations.RunPython(forwards, reverse),
18 | ]
19 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/0008_plugin_log_entries.py:
--------------------------------------------------------------------------------
1 | from infi.clickhouse_orm import migrations
2 |
3 | from posthog.clickhouse.plugin_log_entries import (
4 | KAFKA_PLUGIN_LOG_ENTRIES_TABLE_SQL,
5 | PLUGIN_LOG_ENTRIES_TABLE_MV_SQL,
6 | PLUGIN_LOG_ENTRIES_TABLE_SQL,
7 | )
8 |
9 | operations = [
10 | migrations.RunSQL(PLUGIN_LOG_ENTRIES_TABLE_SQL()),
11 | migrations.RunSQL(KAFKA_PLUGIN_LOG_ENTRIES_TABLE_SQL()),
12 | migrations.RunSQL(PLUGIN_LOG_ENTRIES_TABLE_MV_SQL),
13 | ]
14 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/0017_events_dead_letter_queue.py:
--------------------------------------------------------------------------------
1 | from infi.clickhouse_orm import migrations
2 |
3 | from posthog.clickhouse.dead_letter_queue import (
4 | DEAD_LETTER_QUEUE_TABLE_MV_SQL,
5 | DEAD_LETTER_QUEUE_TABLE_SQL,
6 | KAFKA_DEAD_LETTER_QUEUE_TABLE_SQL,
7 | )
8 |
9 | operations = [
10 | migrations.RunSQL(DEAD_LETTER_QUEUE_TABLE_SQL()),
11 | migrations.RunSQL(KAFKA_DEAD_LETTER_QUEUE_TABLE_SQL()),
12 | migrations.RunSQL(DEAD_LETTER_QUEUE_TABLE_MV_SQL),
13 | ]
14 |
--------------------------------------------------------------------------------
/posthog/migrations/0054_dashboard_item_color.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.5 on 2020-05-12 13:50
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0053_dashboard_item_layouts"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="dashboarditem", name="color", field=models.CharField(blank=True, max_length=400, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0055_user_anonymize_data.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.5 on 2020-05-21 12:03
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0054_dashboard_item_color"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="user", name="anonymize_data", field=models.BooleanField(blank=True, default=False, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0181_team_correlation_config.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2021-11-01 14:15
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0180_person_version"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="team", name="correlation_config", field=models.JSONField(blank=True, default=dict, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0197_plugin_is_stateless.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2022-01-17 19:27
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0196_update_property_types"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="plugin", name="is_stateless", field=models.BooleanField(default=False, null=True, blank=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/IntervalFilter/intervals.ts:
--------------------------------------------------------------------------------
1 | export const intervals = {
2 | hour: {
3 | label: 'Hour',
4 | newDateFrom: 'dStart',
5 | },
6 | day: {
7 | label: 'Day',
8 | newDateFrom: undefined,
9 | },
10 | week: {
11 | label: 'Week',
12 | newDateFrom: '-30d',
13 | },
14 | month: {
15 | label: 'Month',
16 | newDateFrom: '-90d',
17 | },
18 | }
19 |
20 | export type IntervalKeyType = keyof typeof intervals
21 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/Lettermark/Lettermark.scss:
--------------------------------------------------------------------------------
1 | .Lettermark {
2 | flex-shrink: 0;
3 | width: 1.5rem;
4 | height: 1.5rem;
5 | border-radius: var(--radius);
6 | font-size: 0.75rem;
7 | font-weight: 600;
8 | line-height: 1.5rem;
9 | text-align: center;
10 | color: #5f3366;
11 | background: rgba(#6b355f, 0.25);
12 | user-select: none;
13 | &.Lettermark--gray {
14 | color: var(--default);
15 | background: var(--border-light);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/plugin-server/src/worker/vm/extensions/google.ts:
--------------------------------------------------------------------------------
1 | import * as BigQuery from '@google-cloud/bigquery'
2 | import * as PubSub from '@google-cloud/pubsub'
3 |
4 | type DummyCloud = {
5 | bigquery: typeof BigQuery
6 | pubsub: typeof PubSub
7 | }
8 |
9 | type DummyGoogle = {
10 | cloud: DummyCloud
11 | }
12 |
13 | export function createGoogle(): DummyGoogle {
14 | return {
15 | cloud: {
16 | bigquery: BigQuery,
17 | pubsub: PubSub,
18 | },
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/posthog/migrations/0076_auto_20200819_1214.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.7 on 2020-08-19 12:14
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0075_action_slack_message_format"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name="cohortpeople", name="id", field=models.BigIntegerField(primary_key=True, serialize=False),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0077_cohortpeople_id_to_bigautofield.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.7 on 2020-08-21 09:27
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0076_auto_20200819_1214"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name="cohortpeople", name="id", field=models.BigAutoField(primary_key=True, serialize=False),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0172_person_properties_last_operation.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.12 on 2021-10-05 12:11
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0171_cohort_description"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="person", name="properties_last_operation", field=models.JSONField(blank=True, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0240_organizationinvite_message.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-05-31 15:00
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0239_delete_postgres_pluginlogentry"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="organizationinvite", name="message", field=models.TextField(blank=True, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/cypress/e2e/organizationSettings.js:
--------------------------------------------------------------------------------
1 | // For tests related to team members administration please see `inviteMembers.js`
2 | describe('Organization settings', () => {
3 | it('can navigate to organization settings', () => {
4 | cy.get('[data-attr=top-menu-toggle]').click()
5 | cy.get('[data-attr=top-menu-item-org-settings]').click()
6 | cy.location('pathname').should('include', '/organization/settings')
7 | cy.get('.page-title').should('contain', 'Organization')
8 | })
9 | })
10 |
--------------------------------------------------------------------------------
/cypress/e2e/systemStatus.js:
--------------------------------------------------------------------------------
1 | import { urls } from 'scenes/urls'
2 |
3 | describe('System Status', () => {
4 | it('System Status loaded', () => {
5 | cy.location('pathname').should('eq', urls.savedInsights())
6 | cy.wait(500)
7 | cy.get('[data-attr=top-menu-toggle]').click()
8 | cy.get('[data-attr=system-status-badge]').click()
9 | cy.get('h1').should('contain', 'Instance status')
10 | cy.get('table').should('contain', 'Events in ClickHouse')
11 | })
12 | })
13 |
--------------------------------------------------------------------------------
/cypress/fixtures/api/person/properties.json:
--------------------------------------------------------------------------------
1 | [
2 | { "name": "is_demo", "count": 160 },
3 | { "name": "email", "count": 36 },
4 | { "name": "address", "count": 35 },
5 | { "name": "name", "count": 35 },
6 | { "name": "phone", "count": 35 },
7 | { "name": "$browser", "count": 1 },
8 | { "name": "$browser_version", "count": 1 },
9 | { "name": "$initial_referrer", "count": 1 },
10 | { "name": "$initial_referring_domain", "count": 1 },
11 | { "name": "$os", "count": 1 }
12 | ]
13 |
--------------------------------------------------------------------------------
/posthog/migrations/0047_auto_20200416_1631.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-04-16 16:31
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0046_event_names_properties_to_team"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name="user", name="email_opt_in", field=models.BooleanField(blank=True, default=False, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0178_rename_dashboard_item_to_insight.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.12 on 2021-10-20 10:53
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0177_path_cleaning_filters"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterModelTable(name="dashboarditem", table="posthog_dashboarditem",),
14 | migrations.RenameModel(old_name="DashboardItem", new_name="Insight",),
15 | ]
16 |
--------------------------------------------------------------------------------
/posthog/datetime.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime, timedelta
2 |
3 |
4 | def end_of_day(reference_date: datetime):
5 | return datetime(
6 | year=reference_date.year, month=reference_date.month, day=reference_date.day, tzinfo=reference_date.tzinfo
7 | ) + timedelta(days=1, microseconds=-1)
8 |
9 |
10 | def start_of_day(reference_date: datetime):
11 | return datetime(
12 | year=reference_date.year, month=reference_date.month, day=reference_date.day, tzinfo=reference_date.tzinfo
13 | )
14 |
--------------------------------------------------------------------------------
/posthog/migrations/0065_auto_20200624_1842.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.6 on 2020-06-24 18:42
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0064_toolbar_mode"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddIndex(
14 | model_name="action",
15 | index=models.Index(fields=["team_id", "-updated_at"], name="posthog_act_team_id_8c04de_idx"),
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/posthog/migrations/0084_person_uuid.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.7 on 2020-09-21 14:00
2 |
3 | import uuid
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ("posthog", "0083_auto_20200826_1504"),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name="person", name="uuid", field=models.UUIDField(db_index=True, default=uuid.uuid4, editable=False),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/posthog/migrations/0122_organization_setup_section_2_completed.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-02-02 15:51
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0121_person_email_index"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="organization", name="setup_section_2_completed", field=models.BooleanField(default=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/DateDisplay/DateDisplay.scss:
--------------------------------------------------------------------------------
1 | .dated-highlight {
2 | color: var(--muted);
3 | margin-right: 4px;
4 | padding: 2px 4px;
5 | border: 1px solid var(--border-light);
6 | background-color: #fff;
7 | border-radius: var(--radius);
8 | white-space: nowrap;
9 | }
10 |
11 | .date-display-dates {
12 | white-space: nowrap;
13 |
14 | .secondary-date {
15 | margin-left: 2px;
16 | color: var(--muted-alt);
17 | font-weight: normal;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/frontend/src/lib/hooks/useBreakpoint.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import { useWindowSize } from './useWindowSize'
3 | import { getActiveBreakpointValue } from 'lib/utils/responsiveUtils'
4 |
5 | export const useBreakpoint = (): number => {
6 | const { width } = useWindowSize()
7 | const [breakpoint, setBreakpoint] = useState(getActiveBreakpointValue)
8 |
9 | useEffect(() => {
10 | setBreakpoint(getActiveBreakpointValue)
11 | }, [width])
12 |
13 | return breakpoint
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/src/scenes/organization/Create/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { CreateOrganizationModal } from '../CreateOrganizationModal'
3 | import { SceneExport } from 'scenes/sceneTypes'
4 | import { organizationLogic } from 'scenes/organizationLogic'
5 |
6 | export const scene: SceneExport = {
7 | component: OrganizationCreate,
8 | logic: organizationLogic,
9 | }
10 |
11 | export function OrganizationCreate(): JSX.Element {
12 | return
13 | }
14 |
--------------------------------------------------------------------------------
/posthog/migrations/0162_organization_is_member_join_email_enabled.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.8 on 2021-08-03 17:10
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0161_property_defs_search"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="organization", name="is_member_join_email_enabled", field=models.BooleanField(default=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/posthog/templates/live_server_inject.html:
--------------------------------------------------------------------------------
1 | {% if debug and js_url %}
2 |
3 |
13 | {% endif %}
14 |
--------------------------------------------------------------------------------
/ee/models/__init__.py:
--------------------------------------------------------------------------------
1 | from .dashboard_privilege import DashboardPrivilege
2 | from .event_definition import EnterpriseEventDefinition
3 | from .explicit_team_membership import ExplicitTeamMembership
4 | from .hook import Hook
5 | from .license import License
6 | from .property_definition import EnterprisePropertyDefinition
7 |
8 | __all__ = [
9 | "EnterpriseEventDefinition",
10 | "ExplicitTeamMembership",
11 | "DashboardPrivilege",
12 | "Hook",
13 | "License",
14 | "EnterprisePropertyDefinition",
15 | ]
16 |
--------------------------------------------------------------------------------
/posthog/api/test/mock_sentry.py:
--------------------------------------------------------------------------------
1 | from unittest.mock import Mock
2 |
3 |
4 | def mock_sentry_context_for_tagging(patched_scope):
5 | mock_scope = Mock()
6 | mock_set_tag = Mock()
7 | mock_scope.set_context = Mock()
8 | mock_scope.set_tag = mock_set_tag
9 | mock_context_manager = Mock()
10 | mock_context_manager.__enter__ = Mock(return_value=mock_scope)
11 | mock_context_manager.__exit__ = Mock(return_value=None)
12 | patched_scope.return_value = mock_context_manager
13 | return mock_set_tag
14 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/NotFound/NotFound.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { ComponentStory, ComponentMeta } from '@storybook/react'
3 |
4 | import { NotFound } from './index'
5 |
6 | export default {
7 | title: 'Components/Not Found',
8 | component: NotFound,
9 | } as ComponentMeta
10 |
11 | const Template: ComponentStory = (args) =>
12 |
13 | export const NotFound_ = Template.bind({})
14 | NotFound_.args = {
15 | object: 'Person',
16 | }
17 |
--------------------------------------------------------------------------------
/posthog/api/unsubscribe.py:
--------------------------------------------------------------------------------
1 | import jwt
2 | from django.http import HttpRequest, JsonResponse
3 |
4 | from posthog.models.subscription import unsubscribe_using_token
5 |
6 |
7 | def unsubscribe(request: HttpRequest):
8 | token = request.GET.get("token")
9 | if not token:
10 | return JsonResponse({"success": False})
11 |
12 | try:
13 | unsubscribe_using_token(token)
14 | except jwt.DecodeError:
15 | return JsonResponse({"success": False})
16 |
17 | return JsonResponse({"success": True})
18 |
--------------------------------------------------------------------------------
/cypress/fixtures/api/decide.js:
--------------------------------------------------------------------------------
1 | export function decideResponse(featureFlags) {
2 | return {
3 | config: {
4 | enable_collect_everything: true,
5 | },
6 | editorParams: {
7 | toolbarVersion: 'toolbar',
8 | jsURL: 'http://localhost:8234/',
9 | },
10 | isAuthenticated: true,
11 | supportedCompression: ['gzip', 'gzip-js', 'lz64'],
12 | featureFlags,
13 | sessionRecording: {
14 | endpoint: '/s/',
15 | },
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/frontend/src/exporter/types.ts:
--------------------------------------------------------------------------------
1 | import { DashboardType, InsightModel, TeamType } from '~/types'
2 |
3 | export enum ExportType {
4 | Image = 'image',
5 | Embed = 'embed',
6 | Scene = 'scene',
7 | }
8 |
9 | export interface ExportOptions {
10 | whitelabel?: boolean
11 | noHeader?: boolean
12 | legend?: boolean
13 | }
14 |
15 | export interface ExportedData extends ExportOptions {
16 | type: ExportType
17 | dashboard?: DashboardType
18 | insight?: InsightModel
19 | team?: Partial
20 | }
21 |
--------------------------------------------------------------------------------
/plugin-server/tests/helpers/worker.ts:
--------------------------------------------------------------------------------
1 | import Piscina from '@posthog/piscina'
2 |
3 | import { defaultConfig } from '../../src/config/config'
4 | import { LogLevel } from '../../src/types'
5 | import { makePiscina } from '../../src/worker/piscina'
6 |
7 | export function setupPiscina(workers: number, tasksPerWorker: number): Piscina {
8 | return makePiscina({
9 | ...defaultConfig,
10 | WORKER_CONCURRENCY: workers,
11 | TASKS_PER_WORKER: tasksPerWorker,
12 | LOG_LEVEL: LogLevel.Log,
13 | })
14 | }
15 |
--------------------------------------------------------------------------------
/.storybook/app-context.ts:
--------------------------------------------------------------------------------
1 | import { AppContext } from '~/types'
2 | import { MOCK_DEFAULT_TEAM } from 'lib/api.mock'
3 |
4 | export const getStorybookAppContext = (): AppContext => ({
5 | anonymous: false,
6 | current_team: MOCK_DEFAULT_TEAM,
7 | current_user: undefined as any, // undefined triggers a fetch and lets us mock the data
8 | default_event_name: '$pageview',
9 | persisted_feature_flags: [],
10 | preflight: null as any, // null triggers a fetch and lets us mock the data
11 | switched_team: null,
12 | })
13 |
--------------------------------------------------------------------------------
/posthog/migrations/0089_auto_20201015_1031.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.7 on 2020-10-15 10:31
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0088_toolbar_disabled"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name="action",
15 | name="slack_message_format",
16 | field=models.CharField(blank=True, default="", max_length=200),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/posthog/migrations/0104_auto_20201208_1052.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2020-12-08 10:52
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0103_retention_remove_date"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name="dashboarditem", name="funnel", field=models.IntegerField(blank=True, null=True),
15 | ),
16 | migrations.DeleteModel(name="Funnel",),
17 | ]
18 |
--------------------------------------------------------------------------------
/bin/install-macosx_arm64:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Install scripts for M1 Macs
4 | # See https://github.com/PostHog/posthog/issues/2916
5 | # NB: use cryptography==3.4.7
6 |
7 | # Set ld flags to use OpenSSL installed with brew
8 | export LDFLAGS="-L$(brew --prefix openssl)/lib"
9 | export CPPFLAGS="-I$(brew --prefix openssl)/include"
10 |
11 | # Use system OpenSSL instead of BoringSSL for GRPC
12 | export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1
13 | export GRPC_PYTHON_BUILD_SYSTEM_ZLIB=1
14 |
15 | pip cache purge
16 | pip install -r requirements.txt
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0024_add_event_distinct_id_index.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-02-25 04:07
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | atomic = False
8 | dependencies = [
9 | ("posthog", "0023_team_opt_out_capture"),
10 | ]
11 |
12 | operations = [
13 | migrations.RunSQL(
14 | "CREATE INDEX CONCURRENTLY idx_distinct_id ON posthog_event(distinct_id);",
15 | reverse_sql='DROP INDEX "idx_distinct_id";',
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/posthog/migrations/0075_action_slack_message_format.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.7 on 2020-08-04 14:29
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0074_toolbar_default_on"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="action",
15 | name="slack_message_format",
16 | field=models.CharField(blank=True, max_length=200, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/posthog/migrations/0177_path_cleaning_filters.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.8 on 2021-10-15 17:06
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0176_update_person_props_function"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="team",
15 | name="path_cleaning_filters",
16 | field=models.JSONField(blank=True, default=list, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | /* global module */
2 | module.exports = {
3 | plugins: [
4 | '@babel/plugin-transform-runtime',
5 | '@babel/plugin-transform-react-jsx',
6 | '@babel/plugin-proposal-class-properties',
7 | '@babel/plugin-proposal-private-property-in-object',
8 | ],
9 | presets: [
10 | [
11 | '@babel/preset-env',
12 | {
13 | useBuiltIns: 'usage',
14 | corejs: 3,
15 | },
16 | ],
17 | '@babel/typescript',
18 | ],
19 | }
20 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/test/test_person_distinct_id_query.py:
--------------------------------------------------------------------------------
1 | from posthog.queries import person_distinct_id_query
2 |
3 |
4 | def test_person_distinct_id_query(db, snapshot):
5 | person_distinct_id_query.using_new_table = True
6 | assert person_distinct_id_query.get_team_distinct_ids_query(2) == snapshot
7 |
8 | person_distinct_id_query.using_new_table = False
9 | assert person_distinct_id_query.get_team_distinct_ids_query(2) == snapshot
10 |
11 | # Reset for other tests
12 | person_distinct_id_query.using_new_table = True
13 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/TitleWithIcon.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export interface TitleWithIconProps {
4 | icon: JSX.Element
5 | children: string | JSX.Element
6 | 'data-attr'?: string
7 | }
8 |
9 | export function TitleWithIcon({ icon, children, 'data-attr': dataAttr }: TitleWithIconProps): JSX.Element {
10 | return (
11 |
12 |
{children}
13 |
{icon}
14 |
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/icons.scss:
--------------------------------------------------------------------------------
1 | // Antd arrows rotated at convenient angles
2 | .anticon-wraper-arrow {
3 | &.topLeft {
4 | svg {
5 | transform: rotate(-45deg);
6 | }
7 | }
8 | &.topRight {
9 | svg {
10 | transform: rotate(45deg);
11 | }
12 | }
13 | &.bottomRight {
14 | svg {
15 | transform: rotate(135deg);
16 | }
17 | }
18 | &.bottomLeft {
19 | svg {
20 | transform: rotate(-135deg);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/posthog/migrations/0035_current_url_index_20200318_1459.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-03-18 14:59
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [
8 | ("posthog", "0034_pg_trgm_and_btree_20200318_1447"),
9 | ]
10 |
11 | operations = [
12 | # We used to create an index here, but realised that made things slower rather than faster
13 | migrations.RunSQL("SELECT 1;", "DROP INDEX IF EXISTS posthog_event_properties_current_url_gin")
14 | ]
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0039_populate_event_ip_property.py:
--------------------------------------------------------------------------------
1 | from django.db import migrations
2 |
3 |
4 | class Migration(migrations.Migration):
5 |
6 | dependencies = [
7 | ("posthog", "0038_migrate_actions_to_precalculate_events"),
8 | ]
9 |
10 | operations = [
11 | migrations.RunSQL(
12 | """
13 | UPDATE "posthog_event"
14 | SET properties = properties || jsonb_build_object('$ip', ip)
15 | WHERE ip IS NOT NULL;
16 | """,
17 | "",
18 | )
19 | ]
20 |
--------------------------------------------------------------------------------
/posthog/migrations/0127_add_dashboard_filters.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-02-16 13:38
2 |
3 | import django.contrib.postgres.fields.jsonb
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("posthog", "0126_fix_funnels_insights_links"),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name="dashboard", name="filters", field=django.contrib.postgres.fields.jsonb.JSONField(default=dict),
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/DateFilter/DateFilterRange.scss:
--------------------------------------------------------------------------------
1 | .DateFilterRange__calendartoday {
2 | display: inline-block;
3 | position: relative;
4 | }
5 |
6 | .DateFilterRange__calendartoday::before {
7 | content: '•' !important;
8 | top: 0.5rem !important;
9 | border: 0 !important;
10 | font-size: 0.625em;
11 | }
12 |
13 | .ant-picker-range-arrow {
14 | border-top: 1px solid var(--primary);
15 | border-right: 1px solid var(--primary);
16 | }
17 | .ant-picker-range-wrapper {
18 | border: 1px solid var(--primary);
19 | }
20 |
--------------------------------------------------------------------------------
/posthog/clickhouse/replication/utils.py:
--------------------------------------------------------------------------------
1 | from posthog.models.async_migration import is_async_migration_complete
2 | from posthog.settings import TEST
3 |
4 | _is_replicated = False
5 |
6 |
7 | def clickhouse_is_replicated() -> bool:
8 | # This is cached in a way where subsequent lookups don't result in queries if the migration is complete!
9 | global _is_replicated
10 |
11 | if _is_replicated:
12 | return True
13 |
14 | _is_replicated = is_async_migration_complete("0004_replicated_schema")
15 | return _is_replicated or TEST
16 |
--------------------------------------------------------------------------------
/posthog/migrations/0064_toolbar_mode.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.5 on 2020-06-08 09:41
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0063_team_completed_snippet_onboarding"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="user",
15 | name="toolbar_mode",
16 | field=models.CharField(blank=True, default="default", max_length=200, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/posthog/migrations/0125_longer_webhook_url.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-02-11 11:32
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0124_unset_is_calculating_static_cohorts"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name="team",
15 | name="slack_incoming_webhook",
16 | field=models.CharField(blank=True, max_length=500, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/posthog/migrations/0226_longer_action_slack_message_format.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-04-20 12:08
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0225_insight_viewed"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name="action",
15 | name="slack_message_format",
16 | field=models.CharField(blank=True, default="", max_length=600),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/frontend/src/scenes/ingestion/frameworks/CodeSnippet.scss:
--------------------------------------------------------------------------------
1 | .CodeSnippet {
2 | position: relative;
3 | .CodeSnippet__actions {
4 | position: absolute;
5 | display: flex;
6 | top: 0.75rem;
7 | right: 0.75rem;
8 | gap: 0.5rem;
9 | font-size: 1.5rem;
10 | .CodeSnippet__copy-button {
11 | background: rgb(39, 40, 34) !important;
12 | box-shadow: 0 0 10px rgb(39 40 34) !important;
13 | }
14 | }
15 | button,
16 | svg {
17 | color: #fff;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/posthog/migrations/0182_sessionrecordingevent_window_id.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2021-11-03 21:03
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0181_team_correlation_config"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="sessionrecordingevent",
15 | name="window_id",
16 | field=models.CharField(blank=True, max_length=200, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/ee/migrations/0009_deprecated_old_tags.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2022-02-17 18:11
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("ee", "0008_null_definition_descriptions"),
10 | ]
11 |
12 | operations = [
13 | migrations.RenameField(model_name="enterpriseeventdefinition", old_name="tags", new_name="deprecated_tags",),
14 | migrations.RenameField(model_name="enterprisepropertydefinition", old_name="tags", new_name="deprecated_tags",),
15 | ]
16 |
--------------------------------------------------------------------------------
/frontend/public/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "PostHog",
3 | "short_name": "PostHog",
4 | "icons": [
5 | {
6 | "src": "/static/icons/android-chrome-192x192.png?v=2021-04-28",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/static/icons/android-chrome-512x512.png?v=2021-04-28",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff"
18 | }
19 |
--------------------------------------------------------------------------------
/frontend/src/globals.d.ts:
--------------------------------------------------------------------------------
1 | import posthog from 'posthog-js'
2 | import { ExportedData } from '~/exporter/types'
3 |
4 | declare global {
5 | interface Window {
6 | JS_POSTHOG_API_KEY?: str
7 | JS_POSTHOG_HOST?: str
8 | JS_POSTHOG_SELF_CAPTURE?: boolean
9 | JS_CAPTURE_INTERNAL_METRICS?: boolean
10 | posthog?: posthog
11 | ESBUILD_LOAD_SCRIPT: (name) => void
12 | ESBUILD_LOAD_CHUNKS: (name) => void
13 | ESBUILD_LOADED_CHUNKS: Set
14 | POSTHOG_EXPORTED_DATA: ExportedData
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/plugin-server/src/config/mmdb-constants.ts:
--------------------------------------------------------------------------------
1 | export const MMDB_ENDPOINT = 'https://mmdbcdn.posthog.net/'
2 | export const MMDB_ATTACHMENT_KEY = '@posthog/mmdb'
3 | export const MMDB_STALE_AGE_DAYS = 45
4 | export const MMDB_STATUS_REDIS_KEY = '@posthog-plugin-server/mmdb-status'
5 | export const MMDB_INTERNAL_SERVER_TIMEOUT_SECONDS = 10
6 |
7 | export enum MMDBRequestStatus {
8 | TimedOut = 'Internal MMDB server connection timed out!',
9 | ServiceUnavailable = 'IP location capabilities are not available in this PostHog instance!',
10 | OK = 'OK',
11 | }
12 |
--------------------------------------------------------------------------------
/posthog/management/commands/sync_available_features.py:
--------------------------------------------------------------------------------
1 | import structlog
2 | from django.core.management.base import BaseCommand
3 |
4 | from posthog.tasks.sync_all_organization_available_features import sync_all_organization_available_features
5 |
6 | logger = structlog.get_logger(__name__)
7 |
8 |
9 | class Command(BaseCommand):
10 | help = "Sync available features for all organizations"
11 |
12 | def handle(self, *args, **options):
13 | sync_all_organization_available_features()
14 | logger.info("Features synced for all organizations")
15 |
--------------------------------------------------------------------------------
/posthog/migrations/0020_auto_20200210_0212.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.7 on 2020-02-10 02:12
2 |
3 | import django.utils.timezone
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("posthog", "0019_team_name"),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name="event",
16 | name="timestamp",
17 | field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/posthog/migrations/0116_session_recording_retention_period.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-01-25 11:38
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0115_session_recording_viewed"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="team",
15 | name="session_recording_retention_period_days",
16 | field=models.IntegerField(default=None, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/retention/retention.py:
--------------------------------------------------------------------------------
1 | from ee.clickhouse.queries.retention.retention_actors import (
2 | ClickhouseRetentionActors,
3 | ClickhouseRetentionActorsByPeriod,
4 | )
5 | from ee.clickhouse.queries.retention.retention_event_query import ClickhouseRetentionEventsQuery
6 | from posthog.queries.retention.retention import Retention
7 |
8 |
9 | class ClickhouseRetention(Retention):
10 | event_query = ClickhouseRetentionEventsQuery
11 | actors_query = ClickhouseRetentionActors
12 | actors_by_period_query = ClickhouseRetentionActorsByPeriod
13 |
--------------------------------------------------------------------------------
/posthog/logging/test/test_timing.py:
--------------------------------------------------------------------------------
1 | from unittest.mock import Mock, call, patch
2 |
3 | from posthog.logging.timing import timed
4 |
5 |
6 | @patch("posthog.logging.timing.statsd.timer")
7 | def test_wrap_with_timing_calls_statsd(mock_timer) -> None:
8 | timer_instance = Mock()
9 | mock_timer.return_value = timer_instance
10 |
11 | @timed(name="test")
12 | def test_func():
13 | pass
14 |
15 | test_func()
16 |
17 | mock_timer.assert_called_with("test")
18 | timer_instance.assert_has_calls(calls=[call.start(), call.start().stop()])
19 |
--------------------------------------------------------------------------------
/posthog/migrations/0123_organizationinvite_first_name.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-02-03 09:26
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0122_organization_setup_section_2_completed"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="organizationinvite",
15 | name="first_name",
16 | field=models.CharField(blank=True, default="", max_length=30),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/posthog/migrations/0169_person_properties_last_updated_at.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.12 on 2021-09-21 16:11
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0168_action_step_empty_string_reset"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="person",
15 | name="properties_last_updated_at",
16 | field=models.JSONField(blank=True, default=dict, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/frontend/src/scenes/insights/EditorFilters/LifecycleGlobalFilters.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { TestAccountFilter } from 'scenes/insights/filters/TestAccountFilter'
3 | import { useActions } from 'kea'
4 | import { trendsLogic } from 'scenes/trends/trendsLogic'
5 | import { EditorFilterProps } from '~/types'
6 |
7 | export function LifecycleGlobalFilters({ filters, insightProps }: EditorFilterProps): JSX.Element {
8 | const { setFilters } = useActions(trendsLogic(insightProps))
9 | return
10 | }
11 |
--------------------------------------------------------------------------------
/posthog/queries/retention/__init__.py:
--------------------------------------------------------------------------------
1 | from posthog.settings import EE_AVAILABLE
2 |
3 | if EE_AVAILABLE:
4 | from ee.clickhouse.queries.retention.retention import ClickhouseRetention as Retention
5 | from ee.clickhouse.queries.retention.retention_actors import ClickhouseRetentionActors as RetentionActors
6 | else:
7 | from posthog.queries.retention.actors_query import RetentionActors # type: ignore
8 | from posthog.queries.retention.retention import Retention # type: ignore
9 |
10 | from .retention import build_returning_event_query, build_target_event_query
11 |
--------------------------------------------------------------------------------
/ee/clickhouse/models/test/__snapshots__/test_cohort.ambr:
--------------------------------------------------------------------------------
1 | # name: TestCohort.test_static_cohort_precalculated
2 | '
3 |
4 | SELECT distinct_id
5 | FROM
6 | (SELECT distinct_id,
7 | argMax(person_id, version) as person_id
8 | FROM person_distinct_id2
9 | WHERE team_id = 2
10 | GROUP BY distinct_id
11 | HAVING argMax(is_deleted, version) = 0)
12 | WHERE person_id IN
13 | (SELECT person_id
14 | FROM person_static_cohort
15 | WHERE cohort_id = %(_cohort_id_0)s
16 | AND team_id = %(team_id)s)
17 | '
18 | ---
19 |
--------------------------------------------------------------------------------
/frontend/src/lib/utils/logics.ts:
--------------------------------------------------------------------------------
1 | import { teamLogic } from '../../scenes/teamLogic'
2 | import { TeamType } from '../../types'
3 | import { getAppContext } from './getAppContext'
4 |
5 | export function getCurrentTeamId(providedMaybeTeamId?: TeamType['id'] | null): TeamType['id'] {
6 | const maybeTeamId = providedMaybeTeamId !== undefined ? providedMaybeTeamId : teamLogic.values.currentTeamId
7 | if (!maybeTeamId) {
8 | throw new Error(`Project ID is not known.${getAppContext()?.anonymous ? ' User is anonymous.' : ''}`)
9 | }
10 | return maybeTeamId
11 | }
12 |
--------------------------------------------------------------------------------
/posthog/migrations/0004_auto_20200125_0415.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.7 on 2020-01-25 04:15
2 |
3 | import django.contrib.postgres.fields.jsonb
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("posthog", "0003_person_is_user"),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name="event",
16 | name="elements",
17 | field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/posthog/migrations/0053_dashboard_item_layouts.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.5 on 2020-05-12 10:13
2 |
3 | import django.contrib.postgres.fields.jsonb
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("posthog", "0052_data_precalculate_cohorts"),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name="dashboarditem",
16 | name="layouts",
17 | field=django.contrib.postgres.fields.jsonb.JSONField(default=dict),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/posthog/migrations/0121_person_email_index.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-01-05 12:55
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | atomic = False
8 |
9 | dependencies = [
10 | ("posthog", "0120_organization_personalization"),
11 | ]
12 |
13 | operations = [
14 | migrations.RunSQL(
15 | "CREATE INDEX CONCURRENTLY IF NOT EXISTS posthog_person_email ON posthog_person((properties->>'email'));",
16 | reverse_sql='DROP INDEX "posthog_person_email";',
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/posthog/settings/shell_plus.py:
--------------------------------------------------------------------------------
1 | from posthog.settings.utils import get_from_env, str_to_bool
2 |
3 | # shell_plus settings
4 | # https://django-extensions.readthedocs.io/en/latest/shell_plus.html
5 |
6 | SHELL_PLUS_PRINT_SQL = get_from_env("PRINT_SQL", False, type_cast=str_to_bool)
7 | SHELL_PLUS_POST_IMPORTS = [
8 | ("posthog.models.filters", ("Filter",)),
9 | ("posthog.models.property", ("Property",)),
10 | ]
11 |
12 | SHELL_PLUS_POST_IMPORTS.append(("posthog.client", ("sync_execute",)))
13 | SHELL_PLUS_POST_IMPORTS.append(("infi.clickhouse_orm.utils", ("import_submodules",)))
14 |
--------------------------------------------------------------------------------
/cypress/e2e/licenses.js:
--------------------------------------------------------------------------------
1 | describe('Licenses', () => {
2 | it('Licenses loaded', () => {
3 | cy.get('[data-attr=top-menu-toggle]').click()
4 | cy.get('[data-attr=top-menu-item-licenses]').click()
5 | cy.get('[data-attr=breadcrumb-0]').should('contain', Cypress.config().baseUrl.replace('http://', '')) // Breadcrumbs work
6 | cy.get('[data-attr=breadcrumb-1]').should('have.text', 'Licenses') // Breadcrumbs work
7 | cy.get('h1').should('contain', 'Licenses')
8 | cy.title().should('equal', 'Licenses • PostHog') // Page title works
9 | })
10 | })
11 |
--------------------------------------------------------------------------------
/frontend/src/scenes/funnels/FunnelCanvasLabel.scss:
--------------------------------------------------------------------------------
1 | .insights-graph-header.funnels {
2 | border-bottom: 1px solid var(--border);
3 |
4 | .funnel-canvas-label {
5 | .ant-btn-link {
6 | padding: 0;
7 | &:disabled {
8 | cursor: default;
9 | color: var(--default);
10 | }
11 | }
12 |
13 | .funnel-options-label {
14 | padding: 4px;
15 | }
16 |
17 | .funnel-options-inputs {
18 | align-items: center;
19 | padding: 4px;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/posthog/migrations/0087_fix_annotation_created_at.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.7 on 2020-10-14 07:46
2 |
3 | import django.utils.timezone
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("posthog", "0086_team_session_recording_opt_in"),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name="annotation",
16 | name="created_at",
17 | field=models.DateTimeField(default=django.utils.timezone.now, null=True),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/cypress/README.md:
--------------------------------------------------------------------------------
1 | ## Testing Feature Flags
2 |
3 | The Cypress tests run with a PostHog instance that has no feature flags set up.
4 |
5 | To test feature flags you can intercept the call to the `decide` endpoint
6 |
7 | ```javascript
8 | // sometimes the system under test calls `/decide`
9 | // and sometimes it calls https://app.posthog.com/decide
10 | cy.intercept('https://app.posthog.com/decide/*', (req) =>
11 | req.reply(
12 | decideResponse({
13 | // add feature flags here, for e.g.
14 | // 'feature-flag-key': true,
15 | })
16 | )
17 | )
18 | ```
19 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/stickiness/stickiness_event_query.py:
--------------------------------------------------------------------------------
1 | from posthog.models.group.util import get_aggregation_target_field
2 | from posthog.queries.stickiness.stickiness_event_query import StickinessEventsQuery
3 |
4 |
5 | class ClickhouseStickinessEventsQuery(StickinessEventsQuery):
6 | def aggregation_target(self):
7 | return get_aggregation_target_field(
8 | self._entity.math_group_type_index,
9 | self.EVENT_TABLE_ALIAS,
10 | f"{self.DISTINCT_ID_TABLE_ALIAS if not self._using_person_on_events else self.EVENT_TABLE_ALIAS}.person_id",
11 | )
12 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/PayCard/PayCard.scss:
--------------------------------------------------------------------------------
1 | .pay-card {
2 | box-shadow: var(--shadow-elevation);
3 | padding: 1rem;
4 | border-radius: var(--radius);
5 | border: 1px solid var(--warning);
6 | margin-top: 1rem;
7 | cursor: pointer;
8 | position: relative;
9 | background: var(--bg-light);
10 |
11 | h3 {
12 | font-weight: var(--font-medium);
13 | }
14 |
15 | .close-button {
16 | position: absolute;
17 | top: 16px;
18 | right: 16px;
19 | color: var(--muted);
20 | z-index: var(--z-raised);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/icons/Splotch.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { ComponentMeta, ComponentStory } from '@storybook/react'
3 | import { Splotch, SplotchColor, SplotchProps } from './Splotch'
4 |
5 | export default {
6 | title: 'Lemon UI/Splotch',
7 | component: Splotch,
8 | argTypes: {
9 | color: {
10 | defaultValue: SplotchColor.Purple,
11 | },
12 | },
13 | } as ComponentMeta
14 |
15 | export const _Splotch: ComponentStory = (props: SplotchProps) => {
16 | return
17 | }
18 |
--------------------------------------------------------------------------------
/frontend/src/mocks/jest.ts:
--------------------------------------------------------------------------------
1 | import { setupServer } from 'msw/node'
2 | import { handlers } from '~/mocks/handlers'
3 | import { Mocks, mocksToHandlers } from '~/mocks/utils'
4 | import { useAvailableFeatures } from '~/mocks/features'
5 |
6 | export const mswServer = setupServer(...handlers)
7 | export const useMocks = (mocks: Mocks): void => mswServer.use(...mocksToHandlers(mocks))
8 |
9 | window.confirm = jest.fn()
10 |
11 | beforeAll(() => {
12 | useAvailableFeatures([])
13 | mswServer.listen()
14 | })
15 | afterEach(() => mswServer.resetHandlers())
16 | afterAll(() => mswServer.close())
17 |
--------------------------------------------------------------------------------
/posthog/migrations/0070_team_event_properties_numerical.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.6 on 2020-07-21 13:25
2 |
3 | import django.contrib.postgres.fields.jsonb
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("posthog", "0069_auto_20200714_1642"),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name="team",
16 | name="event_properties_numerical",
17 | field=django.contrib.postgres.fields.jsonb.JSONField(default=list),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/posthog/migrations/0120_organization_personalization.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-01-29 09:24
2 |
3 | import django.contrib.postgres.fields.jsonb
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("posthog", "0119_mandatory_plugin_order"),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name="organization",
16 | name="personalization",
17 | field=django.contrib.postgres.fields.jsonb.JSONField(default=dict),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/posthog/migrations/0152_user_events_column_config.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.8 on 2021-04-30 20:16
2 |
3 | from django.db import migrations, models
4 |
5 | import posthog.models.user
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ("posthog", "0151_plugin_preinstalled"),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name="user",
17 | name="events_column_config",
18 | field=models.JSONField(default=posthog.models.user.events_column_config_default),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/posthog/migrations/0066_team_created_at.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.7 on 2020-06-23 17:13
2 |
3 | from django.db import migrations, models
4 | from django.utils.timezone import now
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("posthog", "0065_auto_20200624_1842"),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name="team",
16 | name="created_at",
17 | field=models.DateTimeField(auto_now_add=True, default=now),
18 | preserve_default=False,
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/StarryBackground/index.scss:
--------------------------------------------------------------------------------
1 | .starry-background {
2 | height: 100%;
3 | background: linear-gradient(180deg, #200c39 0%, #373088 75%, #4a3587 100%);
4 |
5 | .stars {
6 | z-index: var(--z-city-background-image);
7 | position: absolute;
8 | top: 0;
9 | left: 0;
10 | right: 0;
11 | bottom: 0;
12 | background: url('./stars.svg') repeat center center;
13 | }
14 |
15 | .children {
16 | height: 100%;
17 | position: relative;
18 | z-index: var(--z-city-background-content);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/frontend/src/scenes/plugins/edit/CapabilitiesInfo.ts:
--------------------------------------------------------------------------------
1 | export const capabilitiesInfo: Record = {
2 | processEvent: 'Read + modify access to events before ingestion',
3 | processEventBatch: 'Read + modify access to events before ingestion, in batches',
4 | onEvent: 'Read-only access to events',
5 | onSnapshot: 'Read-only access to session recording events',
6 | exportEvents: 'Read-only access to events, optimized for export',
7 | runEveryMinute: 'Runs a task every minute',
8 | runEveryHour: 'Runs a task every hour',
9 | runEveryDay: 'Runs a task every day',
10 | }
11 |
--------------------------------------------------------------------------------
/frontend/src/layout/ErrorNetwork.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Button } from 'antd'
3 | import { ReloadOutlined } from '@ant-design/icons'
4 |
5 | export function ErrorNetwork(): JSX.Element {
6 | return (
7 |
8 |
Network Error
9 |
There was an issue loading the requested resource.
10 |
11 | window.location.reload()}>
12 | Reload the page!
13 |
14 |
15 |
16 | )
17 | }
18 |
--------------------------------------------------------------------------------
/frontend/src/lib/hooks/useEscapeKey.js:
--------------------------------------------------------------------------------
1 | import { useCallback, useEffect } from 'react'
2 |
3 | export function useEscapeKey(callback, deps = []) {
4 | const escFunction = useCallback(
5 | (event) => {
6 | if (event.keyCode === 27) {
7 | callback()
8 | }
9 | },
10 |
11 | deps
12 | )
13 |
14 | useEffect(
15 | () => {
16 | document.addEventListener('keydown', escFunction, false)
17 | return () => document.removeEventListener('keydown', escFunction, false)
18 | },
19 |
20 | deps
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/frontend/src/scenes/instance/Licenses/Licenses.stories.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import { Meta } from '@storybook/react'
3 | import { App } from 'scenes/App'
4 | import { router } from 'kea-router'
5 | import { urls } from 'scenes/urls'
6 |
7 | export default {
8 | title: 'Scenes-App/Licenses',
9 | parameters: { layout: 'fullscreen', options: { showPanel: false }, viewMode: 'story' },
10 | } as Meta
11 |
12 | export const Licenses = (): JSX.Element => {
13 | useEffect(() => {
14 | router.actions.push(urls.instanceLicenses())
15 | }, [])
16 | return
17 | }
18 |
--------------------------------------------------------------------------------
/posthog/migrations/0199_update_experiment_model.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.5 on 2022-01-24 12:16
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0198_async_migration_error"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(model_name="experiment", name="archived", field=models.BooleanField(default=False),),
14 | migrations.AddField(
15 | model_name="experiment", name="secondary_metrics", field=models.JSONField(default=list, null=True),
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/cypress/e2e/annotations.js:
--------------------------------------------------------------------------------
1 | describe('Annotations', () => {
2 | beforeEach(() => {
3 | cy.clickNavMenu('annotations')
4 | })
5 |
6 | it('Annotations loaded', () => {
7 | cy.get('h1').should('contain', 'Annotations')
8 | })
9 |
10 | it('Create annotation', () => {
11 | cy.get('[data-attr=create-annotation]').click()
12 | cy.get('[data-attr=create-annotation-input]').type('Test Annotation')
13 | cy.get('[data-attr=create-annotation-submit]').click()
14 | cy.get('[data-attr=annotations-table]').contains('Test Annotation').should('exist')
15 | })
16 | })
17 |
--------------------------------------------------------------------------------
/ee/clickhouse/models/test/utils/util.py:
--------------------------------------------------------------------------------
1 | from time import sleep, time
2 |
3 | from posthog.client import sync_execute
4 |
5 |
6 | # this normally is unnecessary as CH is fast to consume from Kafka when testing
7 | # but it helps prevent potential flakiness
8 | def delay_until_clickhouse_consumes_from_kafka(table_name: str, target_row_count: int, timeout_seconds=10) -> None:
9 | ts_start = time()
10 | while time() < ts_start + timeout_seconds:
11 | result = sync_execute(f"SELECT COUNT(1) FROM {table_name}")
12 | if result[0][0] == target_row_count:
13 | return
14 | sleep(0.5)
15 |
--------------------------------------------------------------------------------
/ee/tasks/test/subscriptions/subscriptions_test_factory.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | from typing import Any
3 |
4 | import pytz
5 |
6 | from posthog.models.subscription import Subscription
7 |
8 |
9 | def create_subscription(**kwargs: Any) -> Subscription:
10 | payload = dict(
11 | target_type="email",
12 | target_value="test1@posthog.com,test2@posthog.com",
13 | frequency="daily",
14 | interval=1,
15 | start_date=datetime(2022, 1, 1, 9, 0).replace(tzinfo=pytz.UTC),
16 | )
17 |
18 | payload.update(kwargs)
19 | return Subscription.objects.create(**payload)
20 |
--------------------------------------------------------------------------------
/frontend/src/lib/utils/changeType.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Change Type Of Passed Value
3 | * @param {Type} type The type to be casted to
4 | * @param {Number/String} value the value to be changed
5 | **/
6 | export function changeType(type, value) {
7 | switch (type) {
8 | case 'text':
9 | return String(value)
10 | case 'number':
11 | return Number(value)
12 | case 'boolean':
13 | return value == 'true' ? true : false
14 | case 'string':
15 | return String(value)
16 | default:
17 | throw 'Unsupported type'
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/posthog/queries/funnels/sql.py:
--------------------------------------------------------------------------------
1 | FUNNEL_PERSONS_BY_STEP_SQL = """
2 | SELECT aggregation_target AS actor_id{matching_events_select_statement} {extra_fields}
3 | FROM (
4 | {steps_per_person_query}
5 | )
6 | WHERE {persons_steps}
7 | ORDER BY aggregation_target
8 | {limit}
9 | {offset}
10 | SETTINGS allow_experimental_window_functions = 1
11 | """
12 |
13 | FUNNEL_INNER_EVENT_STEPS_QUERY = """
14 | SELECT
15 | aggregation_target,
16 | timestamp,
17 | {steps}
18 | {select_prop}
19 | {extra_fields}
20 | FROM (
21 | {event_query}
22 | ) events
23 | {extra_join}
24 | WHERE (
25 | {steps_condition}
26 | )
27 | """
28 |
--------------------------------------------------------------------------------
/frontend/src/scenes/retention/RetentionTable.scss:
--------------------------------------------------------------------------------
1 | .retention-table {
2 | .ant-table-tbody .ant-table-cell {
3 | padding: 0px !important;
4 | }
5 |
6 | .percentage-cell {
7 | padding: 8px;
8 | }
9 |
10 | .period-in-progress {
11 | background: repeating-linear-gradient(-45deg, #e4edf9, #e4edf9 10px, #f8fbfe 10px, #f8fbfe 20px);
12 | color: #555555;
13 | }
14 | }
15 |
16 | .retention-success {
17 | border-radius: var(--radius);
18 | background-color: var(--depr-lighten-primary-20);
19 | }
20 | .retention-dropped {
21 | background-color: var(--bg-mid);
22 | }
23 |
--------------------------------------------------------------------------------
/posthog/clickhouse/migrations/0024_materialize_window_and_session_id.py:
--------------------------------------------------------------------------------
1 | # This migration has been replaced by 0026_fix_materialized_window_and_session_ids
2 | # The original migration led to potentially inconsistent names for materialized columns
3 | # If the columns were created with this migration, they would be `$session_id` and `$window_id`,
4 | # but if the columns were created with the normal column materialization job, they would be `mat_$session_id`
5 | # and `mat_$window_id`. This led to potential inconsistencies between the tables state and the
6 | # schema defined by `EVENTS_TABLE_SQL`
7 |
8 | operations = [] # type: ignore
9 |
--------------------------------------------------------------------------------
/posthog/migrations/0048_auto_20200420_1051.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-04-20 10:51
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0047_auto_20200416_1631"),
10 | ]
11 |
12 | operations = [
13 | migrations.RemoveIndex(model_name="event", name="posthog_eve_timesta_b00cec_idx",),
14 | migrations.AddIndex(
15 | model_name="event",
16 | index=models.Index(fields=["timestamp", "team_id", "event"], name="posthog_eve_timesta_1f6a8c_idx",),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/ee/clickhouse/queries/stickiness/stickiness_actors.py:
--------------------------------------------------------------------------------
1 | from ee.clickhouse.queries.stickiness.stickiness_event_query import ClickhouseStickinessEventsQuery
2 | from posthog.models.filters.mixins.utils import cached_property
3 | from posthog.queries.stickiness.stickiness_actors import StickinessActors
4 |
5 |
6 | class ClickhouseStickinessActors(StickinessActors):
7 | event_query_class = ClickhouseStickinessEventsQuery
8 |
9 | @cached_property
10 | def aggregation_group_type_index(self):
11 | if self.entity.math == "unique_group":
12 | return self.entity.math_group_type_index
13 | return None
14 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/HotkeyButton/HotkeyButton.tsx:
--------------------------------------------------------------------------------
1 | import { Button, ButtonProps } from 'antd'
2 | import React from 'react'
3 | import { HotKeys } from '~/types'
4 | import './HotkeyButton.scss'
5 |
6 | interface HotkeyButtonProps extends ButtonProps {
7 | hotkey: HotKeys
8 | }
9 |
10 | export function HotkeyButton({ hotkey, children, ...props }: HotkeyButtonProps): JSX.Element {
11 | return (
12 |
13 |
14 | {children} {hotkey}
15 |
16 |
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/posthog/migrations/0136_global_plugin_attachments.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-03-23 17:11
2 |
3 | import django.db.models.deletion
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ("posthog", "0135_plugins_on_cloud"),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name="pluginattachment",
16 | name="plugin_config",
17 | field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to="posthog.PluginConfig"),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/posthog/queries/funnels/__init__.py:
--------------------------------------------------------------------------------
1 | # flake8: noqa
2 | from .base import ClickhouseFunnelBase
3 | from .funnel import ClickhouseFunnel
4 | from .funnel_persons import ClickhouseFunnelActors
5 | from .funnel_strict import ClickhouseFunnelStrict
6 | from .funnel_strict_persons import ClickhouseFunnelStrictActors
7 | from .funnel_time_to_convert import ClickhouseFunnelTimeToConvert
8 | from .funnel_trends import ClickhouseFunnelTrends
9 | from .funnel_trends_persons import ClickhouseFunnelTrendsActors
10 | from .funnel_unordered import ClickhouseFunnelUnordered
11 | from .funnel_unordered_persons import ClickhouseFunnelUnorderedActors
12 |
--------------------------------------------------------------------------------
/frontend/src/lib/hooks/useInterval.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef } from 'react'
2 |
3 | export function useInterval(callback, delay) {
4 | const savedCallback = useRef()
5 |
6 | // Remember the latest callback.
7 | useEffect(() => {
8 | savedCallback.current = callback
9 | }, [callback])
10 |
11 | // Set up the interval.
12 | useEffect(() => {
13 | function tick() {
14 | savedCallback.current()
15 | }
16 | if (delay !== null) {
17 | let id = setInterval(tick, delay)
18 | return () => clearInterval(id)
19 | }
20 | }, [delay])
21 | }
22 |
--------------------------------------------------------------------------------
/posthog/migrations/0028_actionstep_url_matching.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.3 on 2020-03-04 01:20
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ("posthog", "0027_move_elements_to_group"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="actionstep",
15 | name="url_matching",
16 | field=models.CharField(
17 | choices=[("exact", "exact"), ("contains", "contains")], default="contains", max_length=400,
18 | ),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/posthog/migrations/0110_sessionrecordingeventbyteamandtimestamp.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.11 on 2021-01-05 12:55
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | atomic = False
8 |
9 | dependencies = [
10 | ("posthog", "0109_fix_retention_filters"),
11 | ]
12 |
13 | operations = [
14 | migrations.RunSQL(
15 | "CREATE INDEX CONCURRENTLY IF NOT EXISTS posthog_ses_team_id_0409c4_idx ON posthog_sessionrecordingevent(team_id, timestamp);",
16 | reverse_sql='DROP INDEX "posthog_ses_team_id_0409c4_idx";',
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/frontend/src/custom.d.ts:
--------------------------------------------------------------------------------
1 | // This fixes TS errors when importing a .svg file
2 | declare module '*.svg' {
3 | const content: any
4 | export default content
5 | }
6 |
7 | // This fixes TS errors when importing a .png file
8 | declare module '*.png' {
9 | const content: any
10 | export default content
11 | }
12 |
13 | // This fixes TS errors when importing an .mp3 file
14 | declare module '*.mp3' {
15 | const content: any
16 | export default content
17 | }
18 |
19 | // This fixes TS errors when importing an .lottie file
20 | declare module '*.lottie' {
21 | const content: any
22 | export default content
23 | }
24 |
--------------------------------------------------------------------------------
/plugin-server/src/utils/fetch.ts:
--------------------------------------------------------------------------------
1 | // This module wraps node-fetch with a sentry tracing-aware extension
2 |
3 | import fetch, { Request, Response } from 'node-fetch'
4 |
5 | import { runInSpan } from '../sentry'
6 |
7 | function fetchWrapper(...args: Parameters): Promise {
8 | const request = new Request(...args)
9 | return runInSpan(
10 | {
11 | op: 'fetch',
12 | description: `${request.method} ${request.hostname}`,
13 | },
14 | () => fetch(...args)
15 | )
16 | }
17 |
18 | fetchWrapper.isRedirect = fetch.isRedirect
19 |
20 | export default fetchWrapper
21 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/PayGateMini/PayGateMini.scss:
--------------------------------------------------------------------------------
1 | .PayGateMini {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | text-align: center;
6 | background: var(--bg-side);
7 | border-radius: var(--radius);
8 | padding: 0.75rem;
9 | font-size: 0.875rem;
10 | }
11 |
12 | .PayGateMini__icon {
13 | display: flex;
14 | color: var(--warning);
15 | font-size: 2rem;
16 | }
17 |
18 | .PayGateMini__description {
19 | margin-top: 0.75rem;
20 | font-weight: 600;
21 | color: var(--primary-alt);
22 | }
23 |
24 | .PayGateMini__cta {
25 | margin-bottom: 0.75rem;
26 | }
27 |
--------------------------------------------------------------------------------
/frontend/src/toolbar/button/icons/Close.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export function Close(props: React.PropsWithoutRef): JSX.Element {
4 | return (
5 |
6 |
10 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/posthog/async_migrations/migrations/0001_events_sample_by.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from posthog.async_migrations.definition import AsyncMigrationDefinition, AsyncMigrationOperation
4 |
5 | """
6 | Nooping this migration for future compatibility. Superseded by 0002_events_sample_by.
7 |
8 | If users ran the old version of this, they will be ok to run 0002, if not, they will also be ok to run it.
9 | """
10 |
11 |
12 | class Migration(AsyncMigrationDefinition):
13 |
14 | description = "Test migration"
15 |
16 | operations: List[AsyncMigrationOperation] = []
17 |
18 | def is_required(self):
19 | return False
20 |
--------------------------------------------------------------------------------
/posthog/migrations/0237_remove_timezone_from_teams.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-04-22 09:10
2 | from django.db import migrations
3 |
4 |
5 | def reset_team_timezone_to_UTC(apps, _) -> None:
6 | Team = apps.get_model("posthog", "Team")
7 | Team.objects.exclude(timezone="UTC").update(timezone="UTC")
8 |
9 |
10 | class Migration(migrations.Migration):
11 |
12 | dependencies = [
13 | ("posthog", "0236_add_instance_setting_model"),
14 | ]
15 |
16 | def reverse(apps, _) -> None:
17 | pass
18 |
19 | operations = [
20 | migrations.RunPython(reset_team_timezone_to_UTC, reverse),
21 | ]
22 |
--------------------------------------------------------------------------------