ensure all viewsets have filter and search and add tests (#2946)

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens L 2022-05-24 22:01:18 +02:00 committed by GitHub
parent b0af062d74
commit 80c1dbdfbb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 98 additions and 1 deletions

View File

@ -0,0 +1,29 @@
"""authentik API Modelviewset tests"""
from typing import Callable
from django.test import TestCase
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from authentik.api.v3.urls import router
class TestModelViewSets(TestCase):
"""Test Viewset"""
def viewset_tester_factory(test_viewset: type[ModelViewSet]) -> Callable:
"""Test Viewset"""
def tester(self: TestModelViewSets):
self.assertIsNotNone(getattr(test_viewset, "search_fields", None))
filterset_class = getattr(test_viewset, "filterset_class", None)
if not filterset_class:
self.assertIsNotNone(getattr(test_viewset, "filterset_fields", None))
return tester
for _, viewset, _ in router.registry:
if not issubclass(viewset, (ModelViewSet, ReadOnlyModelViewSet)):
continue
setattr(TestModelViewSets, f"test_viewset_{viewset.__name__}", viewset_tester_factory(viewset))

View File

@ -89,6 +89,7 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
"group", "group",
] ]
lookup_field = "slug" lookup_field = "slug"
filterset_fields = ["name", "slug"]
ordering = ["name"] ordering = ["name"]
def _filter_queryset_for_list(self, queryset: QuerySet) -> QuerySet: def _filter_queryset_for_list(self, queryset: QuerySet) -> QuerySet:

View File

@ -66,6 +66,7 @@ class SourceViewSet(
queryset = Source.objects.none() queryset = Source.objects.none()
serializer_class = SourceSerializer serializer_class = SourceSerializer
lookup_field = "slug" lookup_field = "slug"
search_fields = ["slug", "name"]
def get_queryset(self): # pragma: no cover def get_queryset(self): # pragma: no cover
return Source.objects.select_subclasses() return Source.objects.select_subclasses()

View File

@ -26,3 +26,4 @@ class NotificationWebhookMappingViewSet(UsedByMixin, ModelViewSet):
serializer_class = NotificationWebhookMappingSerializer serializer_class = NotificationWebhookMappingSerializer
filterset_fields = ["name"] filterset_fields = ["name"]
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]

View File

@ -32,3 +32,4 @@ class NotificationRuleViewSet(UsedByMixin, ModelViewSet):
serializer_class = NotificationRuleSerializer serializer_class = NotificationRuleSerializer
filterset_fields = ["name", "severity", "group__name"] filterset_fields = ["name", "severity", "group__name"]
ordering = ["name"] ordering = ["name"]
search_fields = ["name", "group__name"]

View File

@ -68,6 +68,7 @@ class NotificationTransportViewSet(UsedByMixin, ModelViewSet):
queryset = NotificationTransport.objects.all() queryset = NotificationTransport.objects.all()
serializer_class = NotificationTransportSerializer serializer_class = NotificationTransportSerializer
filterset_fields = ["name", "mode", "webhook_url", "send_once"] filterset_fields = ["name", "mode", "webhook_url", "send_once"]
search_fields = ["name", "mode", "webhook_url"]
ordering = ["name"] ordering = ["name"]
@permission_required("authentik_events.change_notificationtransport") @permission_required("authentik_events.change_notificationtransport")

View File

@ -35,3 +35,4 @@ class FlowStageBindingViewSet(UsedByMixin, ModelViewSet):
queryset = FlowStageBinding.objects.all() queryset = FlowStageBinding.objects.all()
serializer_class = FlowStageBindingSerializer serializer_class = FlowStageBindingSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
search_fields = ["stage__name"]

View File

@ -118,6 +118,7 @@ class DockerServiceConnectionViewSet(UsedByMixin, ModelViewSet):
serializer_class = DockerServiceConnectionSerializer serializer_class = DockerServiceConnectionSerializer
filterset_fields = ["name", "local", "url", "tls_verification", "tls_authentication"] filterset_fields = ["name", "local", "url", "tls_verification", "tls_authentication"]
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]
class KubernetesServiceConnectionSerializer(ServiceConnectionSerializer): class KubernetesServiceConnectionSerializer(ServiceConnectionSerializer):
@ -152,3 +153,4 @@ class KubernetesServiceConnectionViewSet(UsedByMixin, ModelViewSet):
serializer_class = KubernetesServiceConnectionSerializer serializer_class = KubernetesServiceConnectionSerializer
filterset_fields = ["name", "local"] filterset_fields = ["name", "local"]
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]

View File

@ -21,3 +21,4 @@ class DummyPolicyViewSet(UsedByMixin, ModelViewSet):
serializer_class = DummyPolicySerializer serializer_class = DummyPolicySerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]

View File

@ -25,3 +25,4 @@ class EventMatcherPolicyViewSet(UsedByMixin, ModelViewSet):
serializer_class = EventMatcherPolicySerializer serializer_class = EventMatcherPolicySerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]

View File

@ -21,3 +21,4 @@ class PasswordExpiryPolicyViewSet(UsedByMixin, ModelViewSet):
serializer_class = PasswordExpiryPolicySerializer serializer_class = PasswordExpiryPolicySerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]

View File

@ -28,3 +28,4 @@ class ExpressionPolicyViewSet(UsedByMixin, ModelViewSet):
serializer_class = ExpressionPolicySerializer serializer_class = ExpressionPolicySerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]

View File

@ -20,4 +20,5 @@ class HaveIBeenPwendPolicyViewSet(UsedByMixin, ModelViewSet):
queryset = HaveIBeenPwendPolicy.objects.all() queryset = HaveIBeenPwendPolicy.objects.all()
serializer_class = HaveIBeenPwendPolicySerializer serializer_class = HaveIBeenPwendPolicySerializer
filterset_fields = "__all__" filterset_fields = "__all__"
search_fields = ["name", "password_field"]
ordering = ["name"] ordering = ["name"]

View File

@ -30,3 +30,4 @@ class PasswordPolicyViewSet(UsedByMixin, ModelViewSet):
serializer_class = PasswordPolicySerializer serializer_class = PasswordPolicySerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]

View File

@ -26,6 +26,7 @@ class ReputationPolicyViewSet(UsedByMixin, ModelViewSet):
queryset = ReputationPolicy.objects.all() queryset = ReputationPolicy.objects.all()
serializer_class = ReputationPolicySerializer serializer_class = ReputationPolicySerializer
filterset_fields = "__all__" filterset_fields = "__all__"
search_fields = ["name", "threshold"]
ordering = ["name"] ordering = ["name"]

View File

@ -47,6 +47,7 @@ class LDAPProviderViewSet(UsedByMixin, ModelViewSet):
"uid_start_number": ["iexact"], "uid_start_number": ["iexact"],
"gid_start_number": ["iexact"], "gid_start_number": ["iexact"],
} }
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]
@ -81,3 +82,5 @@ class LDAPOutpostConfigViewSet(ReadOnlyModelViewSet):
queryset = LDAPProvider.objects.filter(application__isnull=False) queryset = LDAPProvider.objects.filter(application__isnull=False)
serializer_class = LDAPOutpostConfigSerializer serializer_class = LDAPOutpostConfigSerializer
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]
filterset_fields = ["name"]

View File

@ -72,6 +72,7 @@ class OAuth2ProviderViewSet(UsedByMixin, ModelViewSet):
"property_mappings", "property_mappings",
"issuer_mode", "issuer_mode",
] ]
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]
@extend_schema( @extend_schema(

View File

@ -39,3 +39,4 @@ class ScopeMappingViewSet(UsedByMixin, ModelViewSet):
serializer_class = ScopeMappingSerializer serializer_class = ScopeMappingSerializer
filterset_class = ScopeMappingFilter filterset_class = ScopeMappingFilter
ordering = ["scope_name", "name"] ordering = ["scope_name", "name"]
search_fields = ["name", "scope_name"]

View File

@ -103,6 +103,7 @@ class ProxyProviderViewSet(UsedByMixin, ModelViewSet):
"redirect_uris": ["iexact"], "redirect_uris": ["iexact"],
"cookie_domain": ["iexact"], "cookie_domain": ["iexact"],
} }
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]
@ -166,3 +167,5 @@ class ProxyOutpostConfigViewSet(ReadOnlyModelViewSet):
queryset = ProxyProvider.objects.filter(application__isnull=False) queryset = ProxyProvider.objects.filter(application__isnull=False)
serializer_class = ProxyOutpostConfigSerializer serializer_class = ProxyOutpostConfigSerializer
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]
filterset_fields = ["name"]

View File

@ -99,6 +99,7 @@ class SAMLProviderViewSet(UsedByMixin, ModelViewSet):
serializer_class = SAMLProviderSerializer serializer_class = SAMLProviderSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]
@extend_schema( @extend_schema(
responses={ responses={
@ -216,4 +217,5 @@ class SAMLPropertyMappingViewSet(UsedByMixin, ModelViewSet):
queryset = SAMLPropertyMapping.objects.all() queryset = SAMLPropertyMapping.objects.all()
serializer_class = SAMLPropertyMappingSerializer serializer_class = SAMLPropertyMappingSerializer
filterset_class = SAMLPropertyMappingFilter filterset_class = SAMLPropertyMappingFilter
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]

View File

@ -91,6 +91,7 @@ class LDAPSourceViewSet(UsedByMixin, ModelViewSet):
"property_mappings", "property_mappings",
"property_mappings_group", "property_mappings_group",
] ]
search_fields = ["name", "slug"]
ordering = ["name"] ordering = ["name"]
@extend_schema( @extend_schema(
@ -142,4 +143,5 @@ class LDAPPropertyMappingViewSet(UsedByMixin, ModelViewSet):
queryset = LDAPPropertyMapping.objects.all() queryset = LDAPPropertyMapping.objects.all()
serializer_class = LDAPPropertyMappingSerializer serializer_class = LDAPPropertyMappingSerializer
filterset_class = LDAPPropertyMappingFilter filterset_class = LDAPPropertyMappingFilter
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]

View File

@ -90,7 +90,6 @@ class OAuthSourceSerializer(SourceSerializer):
if getattr(provider_type, url, None) is None: if getattr(provider_type, url, None) is None:
if url not in attrs: if url not in attrs:
raise ValidationError(f"{url} is required for provider {provider_type.name}") raise ValidationError(f"{url} is required for provider {provider_type.name}")
print(attrs)
return attrs return attrs
class Meta: class Meta:
@ -135,6 +134,7 @@ class OAuthSourceViewSet(UsedByMixin, ModelViewSet):
"consumer_key", "consumer_key",
"additional_scopes", "additional_scopes",
] ]
search_fields = ["name", "slug"]
ordering = ["name"] ordering = ["name"]
@extend_schema( @extend_schema(

View File

@ -26,6 +26,7 @@ class UserOAuthSourceConnectionViewSet(UsedByMixin, ModelViewSet):
queryset = UserOAuthSourceConnection.objects.all() queryset = UserOAuthSourceConnection.objects.all()
serializer_class = UserOAuthSourceConnectionSerializer serializer_class = UserOAuthSourceConnectionSerializer
filterset_fields = ["source__slug"] filterset_fields = ["source__slug"]
search_fields = ["source__slug"]
permission_classes = [OwnerSuperuserPermissions] permission_classes = [OwnerSuperuserPermissions]
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter] filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
ordering = ["source__slug"] ordering = ["source__slug"]

View File

@ -60,6 +60,7 @@ class PlexSourceViewSet(UsedByMixin, ModelViewSet):
"client_id", "client_id",
"allow_friends", "allow_friends",
] ]
search_fields = ["name", "slug"]
ordering = ["name"] ordering = ["name"]
@permission_required(None) @permission_required(None)

View File

@ -35,3 +35,4 @@ class PlexSourceConnectionViewSet(UsedByMixin, ModelViewSet):
permission_classes = [OwnerSuperuserPermissions] permission_classes = [OwnerSuperuserPermissions]
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter] filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
ordering = ["pk"] ordering = ["pk"]
search_fields = ["source__slug"]

View File

@ -41,6 +41,7 @@ class SAMLSourceViewSet(UsedByMixin, ModelViewSet):
serializer_class = SAMLSourceSerializer serializer_class = SAMLSourceSerializer
lookup_field = "slug" lookup_field = "slug"
filterset_fields = "__all__" filterset_fields = "__all__"
search_fields = ["name", "slug"]
ordering = ["name"] ordering = ["name"]
@extend_schema(responses={200: SAMLMetadataSerializer(many=False)}) @extend_schema(responses={200: SAMLMetadataSerializer(many=False)})

View File

@ -51,6 +51,7 @@ class AuthenticatorDuoStageViewSet(UsedByMixin, ModelViewSet):
"client_id", "client_id",
"api_hostname", "api_hostname",
] ]
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]
@extend_schema( @extend_schema(

View File

@ -36,6 +36,7 @@ class AuthenticatorSMSStageViewSet(UsedByMixin, ModelViewSet):
serializer_class = AuthenticatorSMSStageSerializer serializer_class = AuthenticatorSMSStageSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]
class SMSDeviceSerializer(ModelSerializer): class SMSDeviceSerializer(ModelSerializer):

View File

@ -29,6 +29,7 @@ class AuthenticatorStaticStageViewSet(UsedByMixin, ModelViewSet):
serializer_class = AuthenticatorStaticStageSerializer serializer_class = AuthenticatorStaticStageSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]
class StaticDeviceTokenSerializer(ModelSerializer): class StaticDeviceTokenSerializer(ModelSerializer):

View File

@ -29,6 +29,7 @@ class AuthenticatorTOTPStageViewSet(UsedByMixin, ModelViewSet):
serializer_class = AuthenticatorTOTPStageSerializer serializer_class = AuthenticatorTOTPStageSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]
class TOTPDeviceSerializer(ModelSerializer): class TOTPDeviceSerializer(ModelSerializer):

View File

@ -41,3 +41,4 @@ class AuthenticatorValidateStageViewSet(UsedByMixin, ModelViewSet):
serializer_class = AuthenticatorValidateStageSerializer serializer_class = AuthenticatorValidateStageSerializer
filterset_fields = ["name", "not_configured_action", "configuration_stages"] filterset_fields = ["name", "not_configured_action", "configuration_stages"]
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]

View File

@ -33,6 +33,7 @@ class AuthenticateWebAuthnStageViewSet(UsedByMixin, ModelViewSet):
serializer_class = AuthenticateWebAuthnStageSerializer serializer_class = AuthenticateWebAuthnStageSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]
class WebAuthnDeviceSerializer(ModelSerializer): class WebAuthnDeviceSerializer(ModelSerializer):

View File

@ -22,4 +22,5 @@ class CaptchaStageViewSet(UsedByMixin, ModelViewSet):
queryset = CaptchaStage.objects.all() queryset = CaptchaStage.objects.all()
serializer_class = CaptchaStageSerializer serializer_class = CaptchaStageSerializer
filterset_fields = ["name", "public_key"] filterset_fields = ["name", "public_key"]
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]

View File

@ -28,6 +28,7 @@ class ConsentStageViewSet(UsedByMixin, ModelViewSet):
serializer_class = ConsentStageSerializer serializer_class = ConsentStageSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]
class UserConsentSerializer(StageSerializer): class UserConsentSerializer(StageSerializer):
@ -60,6 +61,7 @@ class UserConsentViewSet(
OrderingFilter, OrderingFilter,
SearchFilter, SearchFilter,
] ]
search_fields = ["user__username"]
def get_queryset(self): def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user() user = self.request.user if self.request else get_anonymous_user()

View File

@ -22,3 +22,4 @@ class DenyStageViewSet(UsedByMixin, ModelViewSet):
serializer_class = DenyStageSerializer serializer_class = DenyStageSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]

View File

@ -21,4 +21,5 @@ class DummyStageViewSet(UsedByMixin, ModelViewSet):
queryset = DummyStage.objects.all() queryset = DummyStage.objects.all()
serializer_class = DummyStageSerializer serializer_class = DummyStageSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]

View File

@ -68,6 +68,7 @@ class EmailStageViewSet(UsedByMixin, ModelViewSet):
"template", "template",
"activate_user_on_success", "activate_user_on_success",
] ]
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]
@extend_schema(responses={200: TypeCreateSerializer(many=True)}) @extend_schema(responses={200: TypeCreateSerializer(many=True)})

View File

@ -40,4 +40,5 @@ class IdentificationStageViewSet(UsedByMixin, ModelViewSet):
"passwordless_flow", "passwordless_flow",
"show_source_labels", "show_source_labels",
] ]
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]

View File

@ -41,6 +41,7 @@ class InvitationStageViewSet(UsedByMixin, ModelViewSet):
serializer_class = InvitationStageSerializer serializer_class = InvitationStageSerializer
filterset_class = InvitationStageFilter filterset_class = InvitationStageFilter
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]
class InvitationSerializer(ModelSerializer): class InvitationSerializer(ModelSerializer):

View File

@ -29,4 +29,5 @@ class PasswordStageViewSet(UsedByMixin, ModelViewSet):
"configure_flow", "configure_flow",
"failed_attempts_before_cancel", "failed_attempts_before_cancel",
] ]
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]

View File

@ -29,6 +29,7 @@ class PromptStageViewSet(UsedByMixin, ModelViewSet):
serializer_class = PromptStageSerializer serializer_class = PromptStageSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]
class PromptSerializer(ModelSerializer): class PromptSerializer(ModelSerializer):
@ -59,3 +60,4 @@ class PromptViewSet(UsedByMixin, ModelViewSet):
queryset = Prompt.objects.all().prefetch_related("promptstage_set") queryset = Prompt.objects.all().prefetch_related("promptstage_set")
serializer_class = PromptSerializer serializer_class = PromptSerializer
filterset_fields = ["field_key", "label", "type", "placeholder"] filterset_fields = ["field_key", "label", "type", "placeholder"]
search_fields = ["field_key", "label", "type", "placeholder"]

View File

@ -22,3 +22,4 @@ class UserDeleteStageViewSet(UsedByMixin, ModelViewSet):
serializer_class = UserDeleteStageSerializer serializer_class = UserDeleteStageSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
ordering = ["name"] ordering = ["name"]
search_fields = ["name"]

View File

@ -23,4 +23,5 @@ class UserLoginStageViewSet(UsedByMixin, ModelViewSet):
queryset = UserLoginStage.objects.all() queryset = UserLoginStage.objects.all()
serializer_class = UserLoginStageSerializer serializer_class = UserLoginStageSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]

View File

@ -21,4 +21,5 @@ class UserLogoutStageViewSet(UsedByMixin, ModelViewSet):
queryset = UserLogoutStage.objects.all() queryset = UserLogoutStage.objects.all()
serializer_class = UserLogoutStageSerializer serializer_class = UserLogoutStageSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]

View File

@ -21,4 +21,5 @@ class UserWriteStageViewSet(UsedByMixin, ModelViewSet):
queryset = UserWriteStage.objects.all() queryset = UserWriteStage.objects.all()
serializer_class = UserWriteStageSerializer serializer_class = UserWriteStageSerializer
filterset_fields = "__all__" filterset_fields = "__all__"
search_fields = ["name"]
ordering = ["name"] ordering = ["name"]

View File

@ -1601,6 +1601,10 @@ paths:
operationId: core_applications_list operationId: core_applications_list
description: Custom list method that checks Policy based access instead of guardian description: Custom list method that checks Policy based access instead of guardian
parameters: parameters:
- in: query
name: name
schema:
type: string
- name: ordering - name: ordering
required: false required: false
in: query in: query
@ -1625,6 +1629,10 @@ paths:
description: A search term. description: A search term.
schema: schema:
type: string type: string
- in: query
name: slug
schema:
type: string
- in: query - in: query
name: superuser_full_list name: superuser_full_list
schema: schema:
@ -6114,6 +6122,10 @@ paths:
operationId: outposts_ldap_list operationId: outposts_ldap_list
description: LDAPProvider Viewset description: LDAPProvider Viewset
parameters: parameters:
- in: query
name: name
schema:
type: string
- name: ordering - name: ordering
required: false required: false
in: query in: query
@ -6184,6 +6196,10 @@ paths:
operationId: outposts_proxy_list operationId: outposts_proxy_list
description: ProxyProvider Viewset description: ProxyProvider Viewset
parameters: parameters:
- in: query
name: name
schema:
type: string
- name: ordering - name: ordering
required: false required: false
in: query in: query