Beispiel #1
0
def preflight_check(request: HttpRequest) -> JsonResponse:
    response = {
        "django": True,
        "redis": is_redis_alive() or settings.TEST,
        "plugins": is_plugin_server_alive() or settings.TEST,
        "celery": is_celery_alive() or settings.TEST,
        "db": is_postgres_alive(),
        "initiated": Organization.objects.exists(),
        "cloud": settings.MULTI_TENANCY,
        "demo": settings.DEMO,
        "realm": get_instance_realm(),
        "available_social_auth_providers":
        get_available_social_auth_providers(),
        "can_create_org": get_can_create_org(),
        "email_service_available": is_email_available(with_absolute_urls=True),
    }

    if request.user.is_authenticated:
        response = {
            **response,
            "db_backend": settings.PRIMARY_DB.value,
            "available_timezones": get_available_timezones_with_offsets(),
            "opt_out_capture": os.environ.get("OPT_OUT_CAPTURE", False),
            "posthog_version": VERSION,
            "is_debug": settings.DEBUG,
            "is_event_property_usage_enabled":
            settings.ASYNC_EVENT_PROPERTY_USAGE,
            "licensed_users_available": get_licensed_users_available(),
            "site_url": settings.SITE_URL,
            "instance_preferences": settings.INSTANCE_PREFERENCES,
        }

    return JsonResponse(response)
def report_user_signed_up(
    distinct_id: str,
    is_instance_first_user: bool,
    is_organization_first_user: bool,
    new_onboarding_enabled: bool = False,
    backend_processor: str = "",  # which serializer/view processed the request
    social_provider: str = "",  # which third-party provider processed the login (empty = no third-party)
) -> None:
    """
    Reports that a new user has joined. Only triggered when a new user is actually created (i.e. when an existing user
    joins a new organization, this event is **not** triggered; see `report_user_joined_organization`).
    """

    props = {
        "is_first_user": is_instance_first_user,
        "is_organization_first_user": is_organization_first_user,
        "new_onboarding_enabled": new_onboarding_enabled,
        "signup_backend_processor": backend_processor,
        "signup_social_provider": social_provider,
        "realm": get_instance_realm(),
    }

    # TODO: This should be $set_once as user props.
    posthoganalytics.identify(distinct_id, props)
    posthoganalytics.capture(distinct_id, "user signed up", properties=props)
Beispiel #3
0
    def get_analytics_metadata(self):

        team_member_count_all: int = (OrganizationMembership.objects.filter(
            organization__in=self.organizations.all(), ).values(
                "user_id").distinct().count())

        project_setup_complete = False
        if self.team and self.team.completed_snippet_onboarding and self.team.ingested_event:
            project_setup_complete = True

        return {
            "realm":
            get_instance_realm(),
            "is_ee_available":
            settings.EE_AVAILABLE,
            "email_opt_in":
            self.email_opt_in,
            "anonymize_data":
            self.anonymize_data,
            "email":
            self.email if not self.anonymize_data else None,
            "is_signed_up":
            True,
            "organization_count":
            self.organization_memberships.count(),
            "project_count":
            self.teams.count(),
            "team_member_count_all":
            team_member_count_all,
            "completed_onboarding_once":
            self.teams.filter(
                completed_snippet_onboarding=True,
                ingested_event=True,
            ).exists(
            ),  # has completed the onboarding at least for one project
            # properties dependent on current project / org below
            "billing_plan":
            self.organization.billing_plan if self.organization else None,
            "organization_id":
            str(self.organization.id) if self.organization else None,
            "project_id":
            str(self.team.uuid) if self.team else None,
            "project_setup_complete":
            project_setup_complete,
            "joined_at":
            self.date_joined,
            "has_password_set":
            self.has_usable_password(),
            "has_social_auth":
            self.social_auth.exists(),  # type: ignore
            "social_providers":
            list(self.social_auth.values_list("provider",
                                              flat=True)),  # type: ignore
        }
Beispiel #4
0
    def test_api_invite_sign_up(self, mock_capture):
        invite: OrganizationInvite = OrganizationInvite.objects.create(
            target_email="*****@*****.**", organization=self.organization,
        )

        response = self.client.post(
            f"/api/signup/{invite.id}/", {"first_name": "Alice", "password": "******", "email_opt_in": True},
        )
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        user = cast(User, User.objects.order_by("-pk")[0])
        self.assertEqual(
            response.json(),
            {
                "id": user.pk,
                "uuid": str(user.uuid),
                "distinct_id": user.distinct_id,
                "first_name": "Alice",
                "email": "*****@*****.**",
            },
        )

        # User is now a member of the organization
        self.assertEqual(user.organization_memberships.count(), 1)
        self.assertEqual(user.organization_memberships.first().organization, self.organization)  # type: ignore

        # Defaults are set correctly
        self.assertEqual(user.organization, self.organization)
        self.assertEqual(user.team, self.team)

        # Assert that the user was properly created
        self.assertEqual(user.first_name, "Alice")
        self.assertEqual(user.email, "*****@*****.**")
        self.assertEqual(user.email_opt_in, True)

        # Assert that the sign up event & identify calls were sent to PostHog analytics
        mock_capture.assert_called_once()
        self.assertEqual(user.distinct_id, mock_capture.call_args.args[0])
        self.assertEqual("user signed up", mock_capture.call_args.args[1])
        # Assert that key properties were set properly
        event_props = mock_capture.call_args.kwargs["properties"]
        self.assertEqual(event_props["is_first_user"], False)
        self.assertEqual(event_props["is_organization_first_user"], False)
        self.assertEqual(event_props["new_onboarding_enabled"], False)
        self.assertEqual(event_props["signup_backend_processor"], "OrganizationInviteSignupSerializer")
        self.assertEqual(event_props["signup_social_provider"], "")
        self.assertEqual(event_props["realm"], get_instance_realm())

        # Assert that the user is logged in
        response = self.client.get("/api/users/@me/")
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json()["email"], "*****@*****.**")

        # Assert that the password was correctly saved
        self.assertTrue(user.check_password("test_password"))
Beispiel #5
0
    def test_signup_minimum_attrs(self, mock_identify, mock_capture):
        response = self.client.post(
            "/api/signup/",
            {
                "first_name": "Jane",
                "email": "*****@*****.**",
                "password": "******"
            },
        )
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        user = cast(User, User.objects.order_by("-pk").get())
        organization = cast(Organization, user.organization)
        self.assertEqual(
            response.json(),
            {
                "id": user.pk,
                "uuid": str(user.uuid),
                "distinct_id": user.distinct_id,
                "first_name": "Jane",
                "email": "*****@*****.**",
                "redirect_url": "/ingestion",
            },
        )

        # Assert that the user & org were properly created
        self.assertEqual(user.first_name, "Jane")
        self.assertEqual(user.email, "*****@*****.**")
        self.assertEqual(user.email_opt_in, True)  # Defaults to True
        self.assertEqual(organization.name, "Jane")

        # Assert that the sign up event & identify calls were sent to PostHog analytics
        mock_identify.assert_called_once()
        mock_capture.assert_called_once_with(
            user.distinct_id,
            "user signed up",
            properties={
                "is_first_user": True,
                "is_organization_first_user": True,
                "new_onboarding_enabled": False,
                "signup_backend_processor": "OrganizationSignupSerializer",
                "signup_social_provider": "",
                "realm": get_instance_realm(),
            },
        )

        # Assert that the user is logged in
        response = self.client.get("/api/user/")
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json()["email"], "*****@*****.**")

        # Assert that the password was correctly saved
        self.assertTrue(user.check_password("notsecure"))
Beispiel #6
0
def report_user_signed_up(
        user: User,
        is_instance_first_user: bool,
        is_organization_first_user: bool,
        new_onboarding_enabled: bool = False,
        backend_processor:
    str = "",  # which serializer/view processed the request
        social_provider:
    str = "",  # which third-party provider processed the login (empty = no third-party)
        user_analytics_metadata: Optional[
            dict] = None,  # analytics metadata taken from the User object
        org_analytics_metadata:
    Optional[
        dict] = None,  # analytics metadata taken from the Organization object
) -> None:
    """
    Reports that a new user has joined. Only triggered when a new user is actually created (i.e. when an existing user
    joins a new organization, this event is **not** triggered; see `report_user_joined_organization`).
    """

    props = {
        "is_first_user": is_instance_first_user,
        "is_organization_first_user": is_organization_first_user,
        "new_onboarding_enabled": new_onboarding_enabled,
        "signup_backend_processor": backend_processor,
        "signup_social_provider": social_provider,
        "realm": get_instance_realm(),
    }
    if user_analytics_metadata is not None:
        props.update(user_analytics_metadata)

    if org_analytics_metadata is not None:
        for k, v in org_analytics_metadata.items():
            props[f"org__{k}"] = v

    # TODO: This should be $set_once as user props.
    posthoganalytics.identify(user.distinct_id, props)
    posthoganalytics.capture(
        user.distinct_id,
        "user signed up",
        properties=props,
        groups=groups(user.organization, user.team),
    )
Beispiel #7
0
def user(request):
    """
    DEPRECATED: This endpoint (/api/user/) has been deprecated in favor of /api/users/@me/
    and will be removed soon.
    """
    organization: Optional[Organization] = request.user.organization
    organizations = list(
        request.user.organizations.order_by("-created_at").values(
            "name", "id"))
    team: Optional[Team] = request.user.team
    teams = list(
        request.user.teams.order_by("-created_at").values("name", "id"))
    user = cast(User, request.user)

    if request.method == "PATCH":
        data = json.loads(request.body)

        if team is not None and "team" in data:
            team.app_urls = data["team"].get("app_urls", team.app_urls)
            team.slack_incoming_webhook = data["team"].get(
                "slack_incoming_webhook", team.slack_incoming_webhook)
            team.anonymize_ips = data["team"].get("anonymize_ips",
                                                  team.anonymize_ips)
            team.session_recording_opt_in = data["team"].get(
                "session_recording_opt_in", team.session_recording_opt_in)
            team.session_recording_retention_period_days = data["team"].get(
                "session_recording_retention_period_days",
                team.session_recording_retention_period_days,
            )
            team.completed_snippet_onboarding = data["team"].get(
                "completed_snippet_onboarding",
                team.completed_snippet_onboarding,
            )
            team.test_account_filters = data["team"].get(
                "test_account_filters", team.test_account_filters)
            team.timezone = data["team"].get("timezone", team.timezone)
            team.save()

        if "user" in data:
            try:
                user.current_organization = user.organizations.get(
                    id=data["user"]["current_organization_id"])
                assert user.organization is not None, "Organization should have been just set"
                user.current_team = user.organization.teams.first()
            except (KeyError, ValueError):
                pass
            except ObjectDoesNotExist:
                return JsonResponse(
                    {"detail": "Organization not found for user."}, status=404)
            except KeyError:
                pass
            except ObjectDoesNotExist:
                return JsonResponse(
                    {"detail": "Organization not found for user."}, status=404)
            if user.organization is not None:
                try:
                    user.current_team = user.organization.teams.get(
                        id=int(data["user"]["current_team_id"]))
                except (KeyError, TypeError):
                    pass
                except ValueError:
                    return JsonResponse(
                        {"detail": "Team ID must be an integer."}, status=400)
                except ObjectDoesNotExist:
                    return JsonResponse(
                        {
                            "detail":
                            "Team not found for user's current organization."
                        },
                        status=404)
            user.email_opt_in = data["user"].get("email_opt_in",
                                                 user.email_opt_in)
            user.anonymize_data = data["user"].get("anonymize_data",
                                                   user.anonymize_data)
            user.toolbar_mode = data["user"].get("toolbar_mode",
                                                 user.toolbar_mode)
            user.save()

    user_identify.identify_task.delay(user_id=user.id)

    return JsonResponse({
        "deprecation":
        "Endpoint has been deprecated. Please use `/api/users/@me/`.",
        "id":
        user.pk,
        "distinct_id":
        user.distinct_id,
        "name":
        user.first_name,
        "email":
        user.email,
        "email_opt_in":
        user.email_opt_in,
        "anonymize_data":
        user.anonymize_data,
        "toolbar_mode":
        user.toolbar_mode,
        "organization":
        None if organization is None else {
            "id":
            organization.id,
            "name":
            organization.name,
            "billing_plan":
            organization.billing_plan,
            "available_features":
            organization.available_features,
            "plugins_access_level":
            organization.plugins_access_level,
            "created_at":
            organization.created_at,
            "updated_at":
            organization.updated_at,
            "teams": [{
                "id": team.id,
                "name": team.name
            } for team in organization.teams.all().only("id", "name")],
        },
        "organizations":
        organizations,
        "team":
        None if team is None else {
            "id": team.id,
            "name": team.name,
            "app_urls": team.app_urls,
            "api_token": team.api_token,
            "anonymize_ips": team.anonymize_ips,
            "slack_incoming_webhook": team.slack_incoming_webhook,
            "completed_snippet_onboarding": team.completed_snippet_onboarding,
            "session_recording_opt_in": team.session_recording_opt_in,
            "session_recording_retention_period_days":
            team.session_recording_retention_period_days,
            "ingested_event": team.ingested_event,
            "is_demo": team.is_demo,
            "test_account_filters": team.test_account_filters,
            "timezone": team.timezone,
            "data_attributes": team.data_attributes,
        },
        "teams":
        teams,
        "has_password":
        user.has_usable_password(),
        "opt_out_capture":
        os.environ.get("OPT_OUT_CAPTURE"),
        "posthog_version":
        VERSION,
        "is_multi_tenancy":
        getattr(settings, "MULTI_TENANCY", False),
        "ee_available":
        settings.EE_AVAILABLE,
        "is_clickhouse_enabled":
        is_clickhouse_enabled(),
        "email_service_available":
        is_email_available(with_absolute_urls=True),
        "is_debug":
        getattr(settings, "DEBUG", False),
        "is_staff":
        user.is_staff,
        "is_impersonated":
        is_impersonated_session(request),
        "is_event_property_usage_enabled":
        getattr(settings, "ASYNC_EVENT_PROPERTY_USAGE", False),
        "realm":
        get_instance_realm(),
    })
Beispiel #8
0
def status_report(*, dry_run: bool = False) -> Dict[str, Any]:
    period_start, period_end = get_previous_week()
    report: Dict[str, Any] = {
        "posthog_version": VERSION,
        "clickhouse_version":
        str(version_requirement.get_clickhouse_version()),
        "deployment": os.getenv("DEPLOYMENT", "unknown"),
        "realm": get_instance_realm(),
        "period": {
            "start_inclusive": period_start.isoformat(),
            "end_inclusive": period_end.isoformat()
        },
        "site_url": os.getenv("SITE_URL", "unknown"),
        "license_keys": get_instance_licenses(),
    }

    report["helm"] = get_helm_info_env()

    report["users_who_logged_in"] = [{
        "id": user.id,
        "distinct_id": user.distinct_id
    } if user.anonymize_data else {
        "id": user.id,
        "distinct_id": user.distinct_id,
        "first_name": user.first_name,
        "email": user.email
    } for user in User.objects.filter(is_active=True,
                                      last_login__gte=period_start)]
    report["teams"] = {}
    report["table_sizes"] = {
        "posthog_event":
        fetch_table_size("posthog_event"),
        "posthog_sessionrecordingevent":
        fetch_table_size("posthog_sessionrecordingevent"),
    }

    plugin_configs = PluginConfig.objects.select_related("plugin").all()

    report["plugins_installed"] = Counter(plugin_config.plugin.name
                                          for plugin_config in plugin_configs)
    report["plugins_enabled"] = Counter(plugin_config.plugin.name
                                        for plugin_config in plugin_configs
                                        if plugin_config.enabled)

    instance_usage_summary: Dict[str, int] = {
        "events_count_new_in_period": 0,
        "persons_count_new_in_period": 0,
        "persons_count_total": 0,
        "events_count_total": 0,
        "dashboards_count": 0,
        "ff_count": 0,
        "using_groups": False,
    }

    for team in Team.objects.exclude(organization__for_internal_metrics=True):
        try:
            params = (team.id, report["period"]["start_inclusive"],
                      report["period"]["end_inclusive"])
            team_report: Dict[str, Any] = {}
            # pull events stats from clickhouse
            from ee.clickhouse.models.event import (
                get_event_count_for_team,
                get_event_count_for_team_and_period,
                get_events_count_for_team_by_client_lib,
                get_events_count_for_team_by_event_type,
            )
            from ee.clickhouse.models.person import (
                count_duplicate_distinct_ids_for_team,
                count_total_persons_with_multiple_ids,
            )

            team_event_count = get_event_count_for_team(team.id)
            instance_usage_summary["events_count_total"] += team_event_count
            team_report["events_count_total"] = team_event_count
            team_events_in_period_count = get_event_count_for_team_and_period(
                team.id, period_start, period_end)
            team_report[
                "events_count_new_in_period"] = team_events_in_period_count
            instance_usage_summary[
                "events_count_new_in_period"] += team_report[
                    "events_count_new_in_period"]

            team_report[
                "events_count_by_lib"] = get_events_count_for_team_by_client_lib(
                    team.id, period_start, period_end)
            team_report[
                "events_count_by_name"] = get_events_count_for_team_by_event_type(
                    team.id, period_start, period_end)

            team_report[
                "duplicate_distinct_ids"] = count_duplicate_distinct_ids_for_team(
                    team.id)
            team_report[
                "multiple_ids_per_person"] = count_total_persons_with_multiple_ids(
                    team.id)
            team_report["group_types_count"] = GroupTypeMapping.objects.filter(
                team_id=team.id).count()

            if team_report["group_types_count"] > 0:
                instance_usage_summary["using_groups"] = True
            # pull person stats and the rest here from Postgres always
            persons_considered_total = Person.objects.filter(team_id=team.id)
            persons_considered_total_new_in_period = persons_considered_total.filter(
                created_at__gte=period_start,
                created_at__lte=period_end,
            )
            team_report[
                "persons_count_total"] = persons_considered_total.count()
            instance_usage_summary["persons_count_total"] += team_report[
                "persons_count_total"]

            team_report[
                "persons_count_new_in_period"] = persons_considered_total_new_in_period.count(
                )
            instance_usage_summary[
                "persons_count_new_in_period"] += team_report[
                    "persons_count_new_in_period"]

            # Dashboards
            team_dashboards = Dashboard.objects.filter(team=team).exclude(
                deleted=True)
            team_report["dashboards_count"] = team_dashboards.count()
            instance_usage_summary["dashboards_count"] += team_report[
                "dashboards_count"]
            team_report["dashboards_template_count"] = team_dashboards.filter(
                creation_mode="template").count()
            team_report["dashboards_shared_count"] = team_dashboards.filter(
                is_shared=True).count()
            team_report["dashboards_tagged_count"] = team_dashboards.exclude(
                tagged_items__isnull=True).count()

            # Feature Flags
            feature_flags = FeatureFlag.objects.filter(team=team).exclude(
                deleted=True)
            team_report["ff_count"] = feature_flags.count()
            instance_usage_summary["ff_count"] += team_report["ff_count"]
            team_report["ff_active_count"] = feature_flags.filter(
                active=True).count()
            report["teams"][team.id] = team_report
        except Exception as err:
            capture_event("instance status report failure",
                          {"error": str(err)},
                          dry_run=dry_run)

    report["instance_usage_summary"] = instance_usage_summary
    capture_event("instance status report", report, dry_run=dry_run)
    return report
Beispiel #9
0
def send_all_reports(*, dry_run: bool = False) -> List[OrgReport]:
    """
    Generic way to generate and send org usage reports.
    Specify Postgres or ClickHouse for event queries.
    """
    period_start, period_end = get_previous_day()
    realm = get_instance_realm()
    license_keys = get_instance_licenses()
    metadata: OrgReportMetadata = {
        "posthog_version": VERSION,
        "deployment_infrastructure": os.getenv("DEPLOYMENT", "unknown"),
        "realm": realm,
        "period": {
            "start_inclusive": period_start.isoformat(),
            "end_inclusive": period_end.isoformat()
        },
        "site_url": os.getenv("SITE_URL", "unknown"),
        "license_keys": license_keys,
        "product": get_product_name(realm, license_keys),
    }
    org_data: Dict[str, OrgData] = {}
    org_reports: List[OrgReport] = []

    for team in Team.objects.exclude(organization__for_internal_metrics=True):
        org = team.organization
        organization_id = str(org.id)
        if organization_id in org_data:
            org_data[organization_id]["teams"].append(team.id)
        else:
            org_data[organization_id] = {
                "teams": [team.id],
                "user_count": get_org_user_count(organization_id),
                "name": org.name,
                "created_at": str(org.created_at),
            }

    for organization_id, org in org_data.items():
        org_owner = get_org_owner_or_first_user(organization_id)
        if not org_owner:
            continue
        distinct_id = org_owner.distinct_id
        try:
            month_start = period_start.replace(day=1)
            usage = get_org_usage(
                team_ids=org["teams"],
                period_start=period_start,
                period_end=period_end,
                month_start=month_start,
            )
            report: dict = {
                **metadata,
                **usage,
                "organization_id": organization_id,
                "organization_name": org["name"],
                "organization_created_at": org["created_at"],
                "organization_user_count": org["user_count"],
                "team_count": len(org["teams"]),
            }
            org_reports.append(report)  # type: ignore
        except Exception as err:
            logger.warning("Organization usage report calculation failed", err)
            if not dry_run:
                report_org_usage_failure(organization_id, distinct_id,
                                         str(err))
        if not dry_run:
            report_org_usage(organization_id, distinct_id, report)
            time.sleep(0.25)

    return org_reports
Beispiel #10
0
def status_report(*, dry_run: bool = False) -> Dict[str, Any]:
    period_start, period_end = get_previous_week()
    report: Dict[str, Any] = {
        "posthog_version": VERSION,
        "deployment": os.getenv("DEPLOYMENT", "unknown"),
        "realm": get_instance_realm(),
        "period": {
            "start_inclusive": period_start.isoformat(),
            "end_inclusive": period_end.isoformat()
        },
        "site_url": os.getenv("SITE_URL", "unknown"),
    }

    report["helm"] = get_helm_info_env()

    report["users_who_logged_in"] = [{
        "id": user.id,
        "distinct_id": user.distinct_id
    } if user.anonymize_data else {
        "id": user.id,
        "distinct_id": user.distinct_id,
        "first_name": user.first_name,
        "email": user.email
    } for user in User.objects.filter(last_login__gte=period_start)]
    report["teams"] = {}
    report["table_sizes"] = {
        "posthog_event":
        fetch_table_size("posthog_event"),
        "posthog_sessionrecordingevent":
        fetch_table_size("posthog_sessionrecordingevent"),
    }

    plugin_configs = PluginConfig.objects.select_related("plugin").all()

    report["plugins_installed"] = Counter(
        (plugin_config.plugin.name for plugin_config in plugin_configs))
    report["plugins_enabled"] = Counter((plugin_config.plugin.name
                                         for plugin_config in plugin_configs
                                         if plugin_config.enabled))

    instance_usage_summary: Dict[str, int] = {
        "events_count_new_in_period": 0,
        "persons_count_new_in_period": 0,
        "persons_count_total": 0,
        "events_count_total": 0,
        "dashboards_count": 0,
        "ff_count": 0,
    }

    for team in Team.objects.exclude(organization__for_internal_metrics=True):
        try:
            team_report: Dict[str, Any] = {}
            events_considered_total = Event.objects.filter(team_id=team.id)
            instance_usage_summary[
                "events_count_total"] += events_considered_total.count()
            events_considered_new_in_period = events_considered_total.filter(
                timestamp__gte=period_start,
                timestamp__lte=period_end,
            )
            persons_considered_total = Person.objects.filter(team_id=team.id)
            persons_considered_total_new_in_period = persons_considered_total.filter(
                created_at__gte=period_start,
                created_at__lte=period_end,
            )
            team_report["events_count_total"] = events_considered_total.count()
            team_report[
                "events_count_new_in_period"] = events_considered_new_in_period.count(
                )
            instance_usage_summary[
                "events_count_new_in_period"] += team_report[
                    "events_count_new_in_period"]

            team_report[
                "persons_count_total"] = persons_considered_total.count()
            instance_usage_summary["persons_count_total"] += team_report[
                "persons_count_total"]

            team_report[
                "persons_count_new_in_period"] = persons_considered_total_new_in_period.count(
                )
            instance_usage_summary[
                "persons_count_new_in_period"] += team_report[
                    "persons_count_new_in_period"]

            params = (team.id, report["period"]["start_inclusive"],
                      report["period"]["end_inclusive"])

            team_report[
                "persons_count_active_in_period"] = fetch_persons_count_active_in_period(
                    params)
            team_report["events_count_by_lib"] = fetch_event_counts_by_lib(
                params)
            team_report["events_count_by_name"] = fetch_events_count_by_name(
                params)

            # Dashboards
            team_dashboards = Dashboard.objects.filter(team=team).exclude(
                deleted=True)
            team_report["dashboards_count"] = team_dashboards.count()
            instance_usage_summary["dashboards_count"] += team_report[
                "dashboards_count"]
            team_report["dashboards_template_count"] = team_dashboards.filter(
                creation_mode="template").count()
            team_report["dashboards_shared_count"] = team_dashboards.filter(
                is_shared=True).count()
            team_report["dashboards_tagged_count"] = team_dashboards.exclude(
                tags=[]).count()

            # Feature Flags
            feature_flags = FeatureFlag.objects.filter(team=team).exclude(
                deleted=True)
            team_report["ff_count"] = feature_flags.count()
            instance_usage_summary["ff_count"] += team_report["ff_count"]
            team_report["ff_active_count"] = feature_flags.filter(
                active=True).count()
            report["teams"][team.id] = team_report
        except Exception as err:
            capture_event("instance status report failure",
                          {"error": str(err)},
                          dry_run=dry_run)

    report["instance_usage_summary"] = instance_usage_summary
    capture_event("instance status report", report, dry_run=dry_run)
    return report
Beispiel #11
0
    def test_api_sign_up(self, mock_capture):

        # Ensure the internal system metrics org doesn't prevent org-creation
        Organization.objects.create(name="PostHog Internal Metrics",
                                    for_internal_metrics=True)

        response = self.client.post(
            "/api/signup/",
            {
                "first_name": "John",
                "email": "*****@*****.**",
                "password": "******",
                "organization_name": "Hedgehogs United, LLC",
                "email_opt_in": False,
            },
        )
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        user = cast(User, User.objects.order_by("-pk")[0])
        team = cast(Team, user.team)
        organization = cast(Organization, user.organization)

        self.assertEqual(
            response.json(),
            {
                "id": user.pk,
                "uuid": str(user.uuid),
                "distinct_id": user.distinct_id,
                "first_name": "John",
                "email": "*****@*****.**",
                "redirect_url": "/ingestion",
            },
        )

        # Assert that the user was properly created
        self.assertEqual(user.first_name, "John")
        self.assertEqual(user.email, "*****@*****.**")
        self.assertEqual(user.email_opt_in, False)

        # Assert that the team was properly created
        self.assertEqual(team.name, "Default Project")

        # Assert that the org was properly created
        self.assertEqual(organization.name, "Hedgehogs United, LLC")

        # Assert that the sign up event & identify calls were sent to PostHog analytics
        mock_capture.assert_called_once_with(
            user.distinct_id,
            "user signed up",
            properties={
                "is_first_user": True,
                "is_organization_first_user": True,
                "new_onboarding_enabled": False,
                "signup_backend_processor": "OrganizationSignupSerializer",
                "signup_social_provider": "",
                "realm": get_instance_realm(),
            },
        )

        # Assert that the user is logged in
        response = self.client.get("/api/user/")
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.json()["email"], "*****@*****.**")

        # Assert that the password was correctly saved
        self.assertTrue(user.check_password("notsecure"))