コード例 #1
0
ファイル: organization.py プロジェクト: kisserleon/posthog
 def to_representation(self, instance) -> Dict:
     data = UserSerializer(instance=instance).data
     data[
         "redirect_url"] = "/personalization" if self.enable_new_onboarding(
         ) else "/ingestion"
     return data
コード例 #2
0
class DashboardSerializer(serializers.ModelSerializer):
    items = serializers.SerializerMethodField()  # type: ignore
    created_by = UserSerializer(read_only=True)
    use_template = serializers.CharField(write_only=True, allow_blank=True, required=False)

    class Meta:
        model = Dashboard
        fields = [
            "id",
            "name",
            "description",
            "pinned",
            "items",
            "created_at",
            "created_by",
            "is_shared",
            "share_token",
            "deleted",
            "creation_mode",
            "use_template",
            "filters",
            "tags",
        ]
        read_only_fields = ("creation_mode",)

    def create(self, validated_data: Dict, *args: Any, **kwargs: Any) -> Dashboard:
        request = self.context["request"]
        validated_data["created_by"] = request.user
        team = Team.objects.get(id=self.context["team_id"])
        use_template: str = validated_data.pop("use_template", None)
        creation_mode = "template" if use_template else "default"
        dashboard = Dashboard.objects.create(team=team, creation_mode=creation_mode, **validated_data)

        if use_template:
            try:
                create_dashboard_from_template(use_template, dashboard)
            except AttributeError:
                raise serializers.ValidationError({"use_template": "Invalid value provided."})

        elif request.data.get("items"):
            for item in request.data["items"]:
                DashboardItem.objects.create(
                    **{key: value for key, value in item.items() if key not in ("id", "deleted", "dashboard", "team")},
                    dashboard=dashboard,
                    team=team,
                )

        posthoganalytics.capture(
            request.user.distinct_id,
            "dashboard created",
            {**dashboard.get_analytics_metadata(), "from_template": bool(use_template), "template_key": use_template},
        )

        return dashboard

    def update(  # type: ignore
        self, instance: Dashboard, validated_data: Dict, *args: Any, **kwargs: Any,
    ) -> Dashboard:
        validated_data.pop("use_template", None)  # Remove attribute if present
        if validated_data.get("is_shared") and not instance.share_token:
            instance.share_token = secrets.token_urlsafe(22)

        instance = super().update(instance, validated_data)

        if "request" in self.context:
            posthoganalytics.capture(
                self.context["request"].user.distinct_id, "dashboard updated", instance.get_analytics_metadata()
            )

        return instance

    def get_items(self, dashboard: Dashboard):
        if self.context["view"].action == "list":
            return None
        items = dashboard.items.filter(deleted=False).order_by("order").all()
        self.context.update({"dashboard": dashboard})
        return DashboardItemSerializer(items, many=True, context=self.context).data
コード例 #3
0
ファイル: organization.py プロジェクト: trustwallet/posthog
 def to_representation(self, instance):
     serializer = UserSerializer(instance=instance)
     return serializer.data
コード例 #4
0
def render_template(template_name: str,
                    request: HttpRequest,
                    context: Dict = {}) -> HttpResponse:
    from loginas.utils import is_impersonated_session

    template = get_template(template_name)

    context["opt_out_capture"] = os.getenv(
        "OPT_OUT_CAPTURE", False) or is_impersonated_session(request)
    context["self_capture"] = settings.SELF_CAPTURE

    if os.environ.get("SENTRY_DSN"):
        context["sentry_dsn"] = os.environ["SENTRY_DSN"]

    if settings.DEBUG and not settings.TEST:
        context["debug"] = True
        context["git_rev"] = get_git_commit()
        context["git_branch"] = get_git_branch()

    if settings.E2E_TESTING:
        context["e2e_testing"] = True

    if settings.SELF_CAPTURE:
        api_token = get_self_capture_api_token(request)

        if api_token:
            context["js_posthog_api_key"] = f"'{api_token}'"
            context["js_posthog_host"] = "window.location.origin"
    else:
        context["js_posthog_api_key"] = "'sTMFPsFhdP1Ssg'"
        context["js_posthog_host"] = "'https://app.posthog.com'"

    context["js_capture_internal_metrics"] = settings.CAPTURE_INTERNAL_METRICS
    context["js_url"] = settings.JS_URL

    posthog_app_context: Dict[str, Any] = {
        "persisted_feature_flags": settings.PERSISTED_FEATURE_FLAGS,
        "anonymous": not request.user or not request.user.is_authenticated,
    }

    # Set the frontend app context
    if not request.GET.get("no-preloaded-app-context"):
        from posthog.api.team import TeamSerializer
        from posthog.api.user import User, UserSerializer
        from posthog.views import preflight_check

        posthog_app_context = {
            "current_user": None,
            "current_team": None,
            "preflight": json.loads(preflight_check(request).getvalue()),
            "default_event_name": get_default_event_name(),
            "switched_team": getattr(request, "switched_team", False),
            **posthog_app_context,
        }

        if request.user.pk:
            user_serialized = UserSerializer(request.user,
                                             context={"request": request},
                                             many=False)
            posthog_app_context["current_user"] = user_serialized.data
            team = cast(User, request.user).team
            if team:
                team_serialized = TeamSerializer(team,
                                                 context={"request": request},
                                                 many=False)
                posthog_app_context["current_team"] = team_serialized.data

    context["posthog_app_context"] = json.dumps(posthog_app_context,
                                                default=json_uuid_convert)

    html = template.render(context, request=request)
    return HttpResponse(html)
コード例 #5
0
 def get_created_by(self, dashboard_item: DashboardItem):
     if dashboard_item.created_by:
         return UserSerializer(dashboard_item.created_by).data
コード例 #6
0
ファイル: feature_flag.py プロジェクト: PithomLabs/posthog
class FeatureFlagSerializer(serializers.HyperlinkedModelSerializer):
    created_by = UserSerializer(required=False, read_only=True)
    # :TRICKY: Needed for backwards compatibility
    filters = serializers.DictField(source="get_filters", required=False)
    is_simple_flag = serializers.SerializerMethodField()
    rollout_percentage = serializers.SerializerMethodField()

    class Meta:
        model = FeatureFlag
        fields = [
            "id",
            "name",
            "key",
            "filters",
            "deleted",
            "active",
            "created_by",
            "created_at",
            "is_simple_flag",
            "rollout_percentage",
        ]

    # Simple flags are ones that only have rollout_percentage
    #  That means server side libraries are able to gate these flags without calling to the server
    def get_is_simple_flag(self, feature_flag: FeatureFlag) -> bool:
        return len(feature_flag.groups) == 1 and all(
            len(group.get("properties", [])) == 0
            for group in feature_flag.groups)

    def get_rollout_percentage(self,
                               feature_flag: FeatureFlag) -> Optional[int]:
        if self.get_is_simple_flag(feature_flag):
            return feature_flag.groups[0].get("rollout_percentage")
        else:
            return None

    def validate_key(self, value):
        exclude_kwargs = {}
        if self.instance:
            exclude_kwargs = {"pk": self.instance.pk}

        if (FeatureFlag.objects.filter(
                key=value, team=self.context["request"].user.team,
                deleted=False).exclude(**exclude_kwargs).exists()):
            raise serializers.ValidationError(
                "There is already a feature flag with this key.",
                code="unique")

        return value

    def create(self, validated_data: Dict, *args: Any,
               **kwargs: Any) -> FeatureFlag:
        request = self.context["request"]
        validated_data["created_by"] = request.user
        validated_data["team_id"] = self.context["team_id"]
        self._update_filters(validated_data)

        FeatureFlag.objects.filter(key=validated_data["key"],
                                   team=request.user.team,
                                   deleted=True).delete()
        instance = super().create(validated_data)

        posthoganalytics.capture(
            request.user.distinct_id,
            "feature flag created",
            instance.get_analytics_metadata(),
        )

        return instance

    def update(self, instance: FeatureFlag, validated_data: Dict, *args: Any,
               **kwargs: Any) -> FeatureFlag:  # type: ignore
        request = self.context["request"]
        validated_key = validated_data.get("key", None)
        if validated_key:
            FeatureFlag.objects.filter(key=validated_key,
                                       team=instance.team,
                                       deleted=True).delete()
        self._update_filters(validated_data)
        instance = super().update(instance, validated_data)

        posthoganalytics.capture(
            request.user.distinct_id,
            "feature flag updated",
            instance.get_analytics_metadata(),
        )
        return instance

    def _update_filters(self, validated_data):
        if "get_filters" in validated_data:
            validated_data["filters"] = validated_data.pop("get_filters")
コード例 #7
0
ファイル: utils.py プロジェクト: copyit/posthog
def render_template(template_name: str,
                    request: HttpRequest,
                    context: Dict = {}) -> HttpResponse:
    from posthog.models import Team

    template = get_template(template_name)

    # Get the current user's team (or first team in the instance) to set opt out capture & self capture configs
    team: Optional[Team] = None
    try:
        team = request.user.team  # type: ignore
    except (Team.DoesNotExist, AttributeError):
        team = Team.objects.first()

    context["self_capture"] = False
    context["opt_out_capture"] = os.getenv("OPT_OUT_CAPTURE", False)

    if os.environ.get("SENTRY_DSN"):
        context["sentry_dsn"] = os.environ["SENTRY_DSN"]

    if settings.DEBUG and not settings.TEST:
        context["debug"] = True
        context["git_rev"] = get_git_commit()
        context["git_branch"] = get_git_branch()

    if settings.SELF_CAPTURE:
        context["self_capture"] = True
        if team:
            context["js_posthog_api_key"] = f"'{team.api_token}'"
            context["js_posthog_host"] = "window.location.origin"
    else:
        context["js_posthog_api_key"] = "'sTMFPsFhdP1Ssg'"
        context["js_posthog_host"] = "'https://app.posthog.com'"

    context["js_capture_internal_metrics"] = settings.CAPTURE_INTERNAL_METRICS

    # Set the frontend app context
    if not request.GET.get("no-preloaded-app-context"):
        from posthog.api.user import UserSerializer
        from posthog.models import EventDefinition
        from posthog.views import preflight_check

        posthog_app_context: Dict = {
            "current_user": None,
            "preflight": json.loads(preflight_check(request).getvalue()),
            "default_event_name": get_default_event_name(),
            "persisted_feature_flags": settings.PERSISTED_FEATURE_FLAGS,
        }

        if request.user.pk:
            user = UserSerializer(request.user,
                                  context={"request": request},
                                  many=False)
            posthog_app_context["current_user"] = user.data

        context["posthog_app_context"] = json.dumps(posthog_app_context,
                                                    default=json_uuid_convert)
    else:
        context["posthog_app_context"] = "null"

    html = template.render(context, request=request)
    return HttpResponse(html)
コード例 #8
0
ファイル: action.py プロジェクト: Auz/posthog
class ActionSerializer(serializers.HyperlinkedModelSerializer):
    steps = ActionStepSerializer(many=True, required=False)
    count = serializers.SerializerMethodField()
    created_by = UserSerializer(read_only=True)

    class Meta:
        model = Action
        fields = [
            "id",
            "name",
            "post_to_slack",
            "slack_message_format",
            "steps",
            "created_at",
            "deleted",
            "count",
            "is_calculating",
            "last_calculated_at",
            "created_by",
            "team_id",
        ]
        extra_kwargs = {"team_id": {"read_only": True}}

    def get_count(self, action: Action) -> Optional[int]:
        if hasattr(action, "count"):
            return action.count  # type: ignore
        return None

    def _calculate_action(self, action: Action) -> None:
        calculate_action.delay(action_id=action.pk)

    def validate(self, attrs):
        exclude_args = {}
        if self.instance:
            include_args = {"team": self.instance.team}
            exclude_args = {"id": self.instance.pk}
        else:
            attrs["team_id"] = self.context["view"].team_id
            include_args = {"team_id": attrs["team_id"]}

        if Action.objects.filter(
                name=attrs["name"], deleted=False,
                **include_args).exclude(**exclude_args).exists():
            raise serializers.ValidationError(
                {"name": "This project already has an action with that name."},
                code="unique")

        return attrs

    def create(self, validated_data: Any) -> Any:
        steps = validated_data.pop("steps", [])
        validated_data["created_by"] = self.context["request"].user
        instance = super().create(validated_data)

        for step in steps:
            ActionStep.objects.create(
                action=instance,
                **{
                    key: value
                    for key, value in step.items()
                    if key not in ("isNew", "selection")
                },
            )

        self._calculate_action(instance)
        posthoganalytics.capture(validated_data["created_by"].distinct_id,
                                 "action created",
                                 instance.get_analytics_metadata())

        return instance

    def update(self, instance: Any, validated_data: Dict[str, Any]) -> Any:

        steps = validated_data.pop("steps", None)
        # If there's no steps property at all we just ignore it
        # If there is a step property but it's an empty array [], we'll delete all the steps
        if steps is not None:
            # remove steps not in the request
            step_ids = [step["id"] for step in steps if step.get("id")]
            instance.steps.exclude(pk__in=step_ids).delete()

            for step in steps:
                if step.get("id"):
                    step_instance = ActionStep.objects.get(pk=step["id"])
                    step_serializer = ActionStepSerializer(
                        instance=step_instance)
                    step_serializer.update(step_instance, step)
                else:
                    ActionStep.objects.create(
                        action=instance,
                        **{
                            key: value
                            for key, value in step.items()
                            if key not in ("isNew", "selection")
                        },
                    )

        instance = super().update(instance, validated_data)
        self._calculate_action(instance)
        instance.refresh_from_db()
        posthoganalytics.capture(
            self.context["request"].user.distinct_id,
            "action updated",
            {
                **instance.get_analytics_metadata(),
                "updated_by_creator":
                self.context["request"].user == instance.created_by,
            },
        )
        return instance
コード例 #9
0
class CohortSerializer(serializers.ModelSerializer):
    created_by = UserSerializer(required=False, read_only=True)
    count = serializers.SerializerMethodField()

    class Meta:
        model = Cohort
        fields = [
            "id",
            "name",
            "groups",
            "deleted",
            "is_calculating",
            "created_by",
            "created_at",
            "last_calculation",
            "errors_calculating",
            "count",
            "is_static",
        ]
        read_only_fields = [
            "id",
            "is_calculating",
            "created_by",
            "created_at",
            "last_calculation",
            "errors_calculating",
            "count",
        ]

    def _handle_csv(self, file, cohort: Cohort) -> None:
        decoded_file = file.read().decode("utf-8").splitlines()
        reader = csv.reader(decoded_file)
        distinct_ids_and_emails = [
            row[0] for row in reader if len(row) > 0 and row
        ]
        calculate_cohort_from_csv.delay(cohort.pk, distinct_ids_and_emails)

    def create(self, validated_data: Dict, *args: Any,
               **kwargs: Any) -> Cohort:
        request = self.context["request"]
        validated_data["created_by"] = request.user
        if not validated_data.get("is_static"):
            validated_data["is_calculating"] = True
        cohort = Cohort.objects.create(team_id=self.context["team_id"],
                                       **validated_data)

        if request.FILES.get("csv"):
            self._handle_csv(request.FILES["csv"], cohort)

        posthoganalytics.capture(request.user.distinct_id, "cohort created",
                                 cohort.get_analytics_metadata())
        if not cohort.is_static:
            calculate_cohort.delay(cohort_id=cohort.pk)
        return cohort

    def update(self, cohort: Cohort, validated_data: Dict, *args: Any,
               **kwargs: Any) -> Cohort:  # type: ignore
        request = self.context["request"]
        cohort.name = validated_data.get("name", cohort.name)
        cohort.groups = validated_data.get("groups", cohort.groups)
        cohort.deleted = validated_data.get("deleted", cohort.deleted)
        if not cohort.is_static:
            cohort.is_calculating = True
        cohort.save()

        if request.FILES.get("csv") and cohort.is_static:
            self._handle_csv(request.FILES["csv"], cohort)

        posthoganalytics.capture(
            request.user.distinct_id,
            "cohort updated",
            {
                **cohort.get_analytics_metadata(), "updated_by_creator":
                request.user == cohort.created_by
            },
        )
        if not cohort.is_static:
            calculate_cohort.delay(cohort_id=cohort.pk)
        return cohort

    def get_count(self, action: Cohort) -> Optional[int]:
        if hasattr(action, "count"):
            return action.count  # type: ignore
        return None
コード例 #10
0
ファイル: cohort.py プロジェクト: cwsuba/posthog-foss
class CohortSerializer(serializers.ModelSerializer):
    created_by = UserSerializer(required=False, read_only=True)
    count = serializers.SerializerMethodField()
    earliest_timestamp_func = lambda team_id: Event.objects.earliest_timestamp(
        team_id)

    class Meta:
        model = Cohort
        fields = [
            "id",
            "name",
            "groups",
            "deleted",
            "is_calculating",
            "created_by",
            "created_at",
            "last_calculation",
            "errors_calculating",
            "count",
            "is_static",
        ]
        read_only_fields = [
            "id",
            "is_calculating",
            "created_by",
            "created_at",
            "last_calculation",
            "errors_calculating",
            "count",
        ]

    def _handle_csv(self, file, cohort: Cohort) -> None:
        decoded_file = file.read().decode("utf-8").splitlines()
        reader = csv.reader(decoded_file)
        distinct_ids_and_emails = [
            row[0] for row in reader if len(row) > 0 and row
        ]
        calculate_cohort_from_list.delay(cohort.pk, distinct_ids_and_emails)

    def create(self, validated_data: Dict, *args: Any,
               **kwargs: Any) -> Cohort:
        request = self.context["request"]
        validated_data["created_by"] = request.user
        if not validated_data.get("is_static"):
            validated_data["is_calculating"] = True
        cohort = Cohort.objects.create(team_id=self.context["team_id"],
                                       **validated_data)

        if cohort.is_static:
            self._handle_static(cohort, request)
        else:
            calculate_cohort.delay(cohort_id=cohort.pk)

        posthoganalytics.capture(request.user.distinct_id, "cohort created",
                                 cohort.get_analytics_metadata())
        return cohort

    def _handle_static(self, cohort: Cohort, request: Request):
        if request.FILES.get("csv"):
            self._calculate_static_by_csv(request.FILES["csv"], cohort)
        else:
            try:
                filter = Filter(request=request)
                team = request.user.team
                target_entity = get_target_entity(request)
                if filter.shown_as == TRENDS_STICKINESS:
                    stickiness_filter = StickinessFilter(
                        request=request,
                        team=team,
                        get_earliest_timestamp=self.earliest_timestamp_func)
                    self._handle_stickiness_people(target_entity, cohort,
                                                   stickiness_filter)
                else:
                    self._handle_trend_people(target_entity, cohort, filter)
            except Exception as e:
                capture_exception(e)
                raise ValueError("This cohort has no conditions")

    def _calculate_static_by_csv(self, file, cohort: Cohort) -> None:
        decoded_file = file.read().decode("utf-8").splitlines()
        reader = csv.reader(decoded_file)
        distinct_ids_and_emails = [
            row[0] for row in reader if len(row) > 0 and row
        ]
        calculate_cohort_from_list.delay(cohort.pk, distinct_ids_and_emails)

    def _calculate_static_by_people(self, people: List[str],
                                    cohort: Cohort) -> None:
        calculate_cohort_from_list.delay(cohort.pk, people)

    def _handle_stickiness_people(self, target_entity: Entity, cohort: Cohort,
                                  filter: StickinessFilter) -> None:
        events = stickiness_process_entity_type(target_entity, cohort.team,
                                                filter)
        events = stickiness_format_intervals(events, filter)
        people = stickiness_fetch_people(events, cohort.team, filter)
        ids = [
            person.distinct_ids[0] for person in people
            if len(person.distinct_ids)
        ]
        self._calculate_static_by_people(ids, cohort)

    def _handle_trend_people(self, target_entity: Entity, cohort: Cohort,
                             filter: Filter) -> None:
        events = filter_by_type(entity=target_entity,
                                team=cohort.team,
                                filter=filter)
        people = calculate_people(team=cohort.team,
                                  events=events,
                                  filter=filter)
        ids = [
            person.distinct_ids[0] for person in people
            if len(person.distinct_ids)
        ]
        self._calculate_static_by_people(ids, cohort)

    def update(self, cohort: Cohort, validated_data: Dict, *args: Any,
               **kwargs: Any) -> Cohort:  # type: ignore
        request = self.context["request"]
        cohort.name = validated_data.get("name", cohort.name)
        cohort.groups = validated_data.get("groups", cohort.groups)
        deleted_state = validated_data.get("deleted", None)
        is_deletion_change = deleted_state is not None
        if is_deletion_change:
            cohort.deleted = deleted_state

        if not cohort.is_static and not is_deletion_change:
            cohort.is_calculating = True
        cohort.save()

        if not deleted_state:
            if cohort.is_static:
                self._handle_static(cohort, request)
            else:
                calculate_cohort.delay(cohort_id=cohort.pk)

        posthoganalytics.capture(
            request.user.distinct_id,
            "cohort updated",
            {
                **cohort.get_analytics_metadata(), "updated_by_creator":
                request.user == cohort.created_by
            },
        )

        return cohort

    def get_count(self, action: Cohort) -> Optional[int]:
        if hasattr(action, "count"):
            return action.count  # type: ignore
        return None