diff --git a/netbox/templates/users/group.html b/netbox/templates/users/group.html index d3f02af12..defc61854 100644 --- a/netbox/templates/users/group.html +++ b/netbox/templates/users/group.html @@ -17,6 +17,10 @@ {% trans "Name" %} {{ object.name }} + + {% trans "Description" %} + {{ object.description|placeholder }} + diff --git a/netbox/users/api/serializers_/users.py b/netbox/users/api/serializers_/users.py index ded5dd1d9..b546aeb7b 100644 --- a/netbox/users/api/serializers_/users.py +++ b/netbox/users/api/serializers_/users.py @@ -29,7 +29,7 @@ class GroupSerializer(ValidatedModelSerializer): class Meta: model = Group fields = ('id', 'url', 'display', 'name', 'permissions', 'user_count') - brief_fields = ('id', 'url', 'display', 'name') + brief_fields = ('id', 'url', 'display', 'name', 'description') class UserSerializer(ValidatedModelSerializer): diff --git a/netbox/users/filtersets.py b/netbox/users/filtersets.py index da0095a1c..14c02ed37 100644 --- a/netbox/users/filtersets.py +++ b/netbox/users/filtersets.py @@ -40,7 +40,10 @@ class GroupFilterSet(BaseFilterSet): def search(self, queryset, name, value): if not value.strip(): return queryset - return queryset.filter(name__icontains=value) + return queryset.filter( + Q(name__icontains=value) | + Q(description__icontains=value) + ) class UserFilterSet(BaseFilterSet): diff --git a/netbox/users/forms/bulk_edit.py b/netbox/users/forms/bulk_edit.py index a26842d09..52a022de3 100644 --- a/netbox/users/forms/bulk_edit.py +++ b/netbox/users/forms/bulk_edit.py @@ -10,6 +10,7 @@ from utilities.forms.rendering import FieldSet from utilities.forms.widgets import BulkEditNullBooleanSelect, DateTimePicker __all__ = ( + 'GroupBulkEditForm', 'ObjectPermissionBulkEditForm', 'UserBulkEditForm', 'TokenBulkEditForm', @@ -54,6 +55,24 @@ class UserBulkEditForm(forms.Form): nullable_fields = ('first_name', 'last_name') +class GroupBulkEditForm(forms.Form): + pk = forms.ModelMultipleChoiceField( + queryset=Group.objects.all(), + widget=forms.MultipleHiddenInput + ) + description = forms.CharField( + label=_('Description'), + max_length=200, + required=False + ) + + model = User + fieldsets = ( + FieldSet('description'), + ) + nullable_fields = ('description',) + + class ObjectPermissionBulkEditForm(forms.Form): pk = forms.ModelMultipleChoiceField( queryset=ObjectPermission.objects.all(), diff --git a/netbox/users/forms/bulk_import.py b/netbox/users/forms/bulk_import.py index cbaa1ad76..748338a64 100644 --- a/netbox/users/forms/bulk_import.py +++ b/netbox/users/forms/bulk_import.py @@ -15,9 +15,7 @@ class GroupImportForm(CSVModelForm): class Meta: model = Group - fields = ( - 'name', - ) + fields = ('name', 'description') class UserImportForm(CSVModelForm): diff --git a/netbox/users/forms/model_forms.py b/netbox/users/forms/model_forms.py index 2d4431f96..7320e603b 100644 --- a/netbox/users/forms/model_forms.py +++ b/netbox/users/forms/model_forms.py @@ -19,12 +19,12 @@ from utilities.forms.widgets import DateTimePicker from utilities.permissions import qs_filter_from_constraints __all__ = ( - 'UserTokenForm', 'GroupForm', 'ObjectPermissionForm', 'TokenForm', 'UserConfigForm', 'UserForm', + 'UserTokenForm', 'TokenForm', ) @@ -237,7 +237,7 @@ class GroupForm(forms.ModelForm): ) fieldsets = ( - FieldSet('name'), + FieldSet('name', 'description'), FieldSet('users', name=_('Users')), FieldSet('object_permissions', name=_('Permissions')), ) @@ -245,7 +245,7 @@ class GroupForm(forms.ModelForm): class Meta: model = Group fields = [ - 'name', 'users', 'object_permissions', + 'name', 'description', 'users', 'object_permissions', ] def __init__(self, *args, **kwargs): diff --git a/netbox/users/tables.py b/netbox/users/tables.py index 813d729c9..fc2f9702d 100644 --- a/netbox/users/tables.py +++ b/netbox/users/tables.py @@ -68,10 +68,7 @@ class GroupTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Group - fields = ( - 'pk', 'id', 'name', 'users_count', - ) - default_columns = ('pk', 'name', 'users_count', ) + fields = ('pk', 'id', 'name', 'users_count', 'description') class ObjectPermissionTable(NetBoxTable): diff --git a/netbox/users/tests/test_views.py b/netbox/users/tests/test_views.py index 588730dbd..8711e2b44 100644 --- a/netbox/users/tests/test_views.py +++ b/netbox/users/tests/test_views.py @@ -66,6 +66,7 @@ class GroupTestCase( ViewTestCases.DeleteObjectViewTestCase, ViewTestCases.ListObjectsViewTestCase, ViewTestCases.BulkImportObjectsViewTestCase, + ViewTestCases.BulkEditObjectsViewTestCase, ViewTestCases.BulkDeleteObjectsViewTestCase, ): model = Group @@ -99,6 +100,10 @@ class GroupTestCase( f"{groups[2].pk},group9", ) + cls.bulk_edit_data = { + 'description': 'New description', + } + class ObjectPermissionTestCase( ViewTestCases.GetObjectViewTestCase, diff --git a/netbox/users/urls.py b/netbox/users/urls.py index adfeba378..0540eae1f 100644 --- a/netbox/users/urls.py +++ b/netbox/users/urls.py @@ -25,6 +25,7 @@ urlpatterns = [ # Groups path('groups/', views.GroupListView.as_view(), name='group_list'), path('groups/add/', views.GroupEditView.as_view(), name='group_add'), + path('groups/edit/', views.GroupBulkEditView.as_view(), name='group_bulk_edit'), path('groups/import/', views.GroupBulkImportView.as_view(), name='group_import'), path('groups/delete/', views.GroupBulkDeleteView.as_view(), name='group_bulk_delete'), path('groups//', include(get_model_urls('users', 'group'))), diff --git a/netbox/users/views.py b/netbox/users/views.py index a8754d4d9..624c8c8b4 100644 --- a/netbox/users/views.py +++ b/netbox/users/views.py @@ -138,6 +138,13 @@ class GroupBulkImportView(generic.BulkImportView): model_form = forms.GroupImportForm +class GroupBulkEditView(generic.BulkEditView): + queryset = Group.objects.all() + filterset = filtersets.GroupFilterSet + table = tables.GroupTable + form = forms.GroupBulkEditForm + + class GroupBulkDeleteView(generic.BulkDeleteView): queryset = Group.objects.annotate(users_count=Count('user')).order_by('name') filterset = filtersets.GroupFilterSet