Repository: goauthentik/authentik
File: authentik/enterprise/lifecycle/api/iterations.py (Python)

Code before:
        fields = [
            "id",
            "content_type",
            "object_id",
            "object_verbose",
            "object_admin_url",
            "state",
            "opened_on",
            "grace_period_end",
            "next_review_date",
            "reviews",
            "user_can_review",
            "reviewer_groups",
            "min_reviewers",
            "reviewers",
        ]
        read_only_fields = fields

    def get_object_verbose(self, iteration: LifecycleIteration) -> str:
        return str(iteration.object)

    def get_object_admin_url(self, iteration: LifecycleIteration) -> str:
        return admin_link_for_model(iteration.object)

    @extend_schema_field(DateTimeField())
    def get_grace_period_end(self, iteration: LifecycleIteration) -> date:
        return start_of_day(
            iteration.opened_on + timedelta_from_string(iteration.rule.grace_period)
        )

    @extend_schema_field(DateTimeField())
    def get_next_review_date(self, iteration: LifecycleIteration):
        return start_of_day(iteration.opened_on + timedelta_from_string(iteration.rule.interval))

    def get_user_can_review(self, iteration: LifecycleIteration) -> bool:
        return iteration.user_can_review(self.context["request"].user)


class LifecycleIterationFilterSet(FilterSet):
    user_is_reviewer = BooleanFilter(field_name="user_is_reviewer", lookup_expr="exact")


class IterationViewSet(EnterpriseRequiredMixin, CreateModelMixin, GenericViewSet):
    queryset = LifecycleIteration.objects.all()
    serializer_class = LifecycleIterationSerializer
    ordering = ["-opened_on"]
    ordering_fields = ["state", "content_type__model", "opened_on", "grace_period_end"]
    filterset_class = LifecycleIterationFilterSet

    def get_queryset(self):
        user = self.request.user

Review comment (suggestion):
```suggestion
    def get_grace_period_end(self, iteration: LifecycleIteration) -> datetime:
```

with this you shouldn't need `@extend_schema_field()`

Code after:
        fields = [
            "id",
            "content_type",
            "object_id",
            "object_verbose",
            "object_admin_url",
            "state",
            "opened_on",
            "grace_period_end",
            "next_review_date",
            "reviews",
            "user_can_review",
            "reviewer_groups",
            "min_reviewers",
            "reviewers",
        ]
        read_only_fields = fields

    def get_object_verbose(self, iteration: LifecycleIteration) -> str:
        return str(iteration.object)

    def get_object_admin_url(self, iteration: LifecycleIteration) -> str:
        return admin_link_for_model(iteration.object)

    def get_grace_period_end(self, iteration: LifecycleIteration) -> datetime:
        return start_of_day(
            iteration.opened_on + timedelta_from_string(iteration.rule.grace_period)
        )

    def get_next_review_date(self, iteration: LifecycleIteration) -> datetime:
        return start_of_day(iteration.opened_on + timedelta_from_string(iteration.rule.interval))

    def get_user_can_review(self, iteration: LifecycleIteration) -> bool:
        return iteration.user_can_review(self.context["request"].user)


class LifecycleIterationFilterSet(FilterSet):
    user_is_reviewer = BooleanFilter(field_name="user_is_reviewer", lookup_expr="exact")


class IterationViewSet(EnterpriseRequiredMixin, CreateModelMixin, GenericViewSet):
    queryset = LifecycleIteration.objects.all()
    serializer_class = LifecycleIterationSerializer
    ordering = ["-opened_on"]
    ordering_fields = ["state", "content_type__model", "opened_on", "grace_period_end"]
    filterset_class = LifecycleIterationFilterSet

    def get_queryset(self):
        user = self.request.user
        return self.queryset.annotate(
            user_is_reviewer=Case(