diff --git a/netbox/users/api/nested_serializers.py b/netbox/users/api/nested_serializers.py index 6e89f1da0..f1bcf3b37 100644 --- a/netbox/users/api/nested_serializers.py +++ b/netbox/users/api/nested_serializers.py @@ -13,20 +13,23 @@ __all__ = [ class NestedGroupSerializer(WritableNestedSerializer): + url = serializers.HyperlinkedIdentityField(view_name='users-api:group-detail') class Meta: model = Group - fields = ['id', 'name'] + fields = ['id', 'url', 'name'] class NestedUserSerializer(WritableNestedSerializer): + url = serializers.HyperlinkedIdentityField(view_name='users-api:user-detail') class Meta: model = User - fields = ['id', 'username'] + fields = ['id', 'url', 'username'] class NestedObjectPermissionSerializer(WritableNestedSerializer): + url = serializers.HyperlinkedIdentityField(view_name='users-api:objectpermission-detail') object_types = ContentTypeField( queryset=ContentType.objects.all(), many=True @@ -36,7 +39,7 @@ class NestedObjectPermissionSerializer(WritableNestedSerializer): class Meta: model = ObjectPermission - fields = ['id', 'name', 'enabled', 'object_types', 'groups', 'users', 'actions'] + fields = ['id', 'url', 'name', 'enabled', 'object_types', 'groups', 'users', 'actions'] def get_groups(self, obj): return [g.name for g in obj.groups.all()] diff --git a/netbox/users/api/serializers.py b/netbox/users/api/serializers.py index c91f9be4a..5141abb10 100644 --- a/netbox/users/api/serializers.py +++ b/netbox/users/api/serializers.py @@ -7,6 +7,32 @@ from utilities.api import ContentTypeField, SerializedPKRelatedField, ValidatedM from .nested_serializers import * +class UserSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='users-api:user-detail') + groups = SerializedPKRelatedField( + queryset=Group.objects.all(), + serializer=NestedGroupSerializer, + required=False, + many=True + ) + + class Meta: + model = User + fields = ( + 'id', 'url', 'username', 'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'date_joined', + 'groups', + ) + + +class GroupSerializer(ValidatedModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='users-api:group-detail') + user_count = serializers.IntegerField(read_only=True) + + class Meta: + model = Group + fields = ('id', 'url', 'name', 'user_count') + + class ObjectPermissionSerializer(ValidatedModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='users-api:objectpermission-detail') object_types = ContentTypeField( diff --git a/netbox/users/api/urls.py b/netbox/users/api/urls.py index fffea5968..a81b56bed 100644 --- a/netbox/users/api/urls.py +++ b/netbox/users/api/urls.py @@ -14,6 +14,10 @@ class UsersRootView(routers.APIRootView): router = routers.DefaultRouter() router.APIRootView = UsersRootView +# Users and groups +router.register('users', views.UserViewSet) +router.register('groups', views.GroupViewSet) + # Permissions router.register('permissions', views.ObjectPermissionViewSet) diff --git a/netbox/users/api/views.py b/netbox/users/api/views.py index 74b315b44..07c449236 100644 --- a/netbox/users/api/views.py +++ b/netbox/users/api/views.py @@ -1,7 +1,27 @@ +from django.contrib.auth.models import Group, User +from django.db.models import Count + +from users import filters +from users.models import ObjectPermission from utilities.api import ModelViewSet +from utilities.querysets import RestrictedQuerySet from . import serializers -from users.models import ObjectPermission + +# +# Users and groups +# + +class UserViewSet(ModelViewSet): + queryset = RestrictedQuerySet(model=User).prefetch_related('groups') + serializer_class = serializers.UserSerializer + filterset_class = filters.UserFitlerSet + + +class GroupViewSet(ModelViewSet): + queryset = RestrictedQuerySet(model=Group).annotate(user_count=Count('user')) + serializer_class = serializers.GroupSerializer + filterset_class = filters.GroupFitlerSet # diff --git a/netbox/users/filters.py b/netbox/users/filters.py new file mode 100644 index 000000000..e433dc5fa --- /dev/null +++ b/netbox/users/filters.py @@ -0,0 +1,58 @@ +import django_filters +from django.contrib.auth.models import Group, User +from django.db.models import Q + +from utilities.filters import BaseFilterSet + +__all__ = ( + 'GroupFitlerSet', + 'UserFitlerSet', +) + + +class GroupFitlerSet(BaseFilterSet): + q = django_filters.CharFilter( + method='search', + label='Search', + ) + + class Meta: + model = Group + fields = ['id', 'name'] + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter(name__icontains=value) + + +class UserFitlerSet(BaseFilterSet): + q = django_filters.CharFilter( + method='search', + label='Search', + ) + group_id = django_filters.ModelMultipleChoiceFilter( + field_name='groups', + queryset=Group.objects.all(), + label='Group', + ) + group = django_filters.ModelMultipleChoiceFilter( + field_name='groups__name', + queryset=Group.objects.all(), + to_field_name='name', + label='Group (name)', + ) + + class Meta: + model = User + fields = ['id', 'username', 'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'date_joined'] + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(username__icontains=value) | + Q(first_name__icontains=value) | + Q(last_name__icontains=value) | + Q(email__icontains=value) + )