mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-23 12:08:43 -06:00
Introduce OwnerGroup model
This commit is contained in:
6108
contrib/openapi.json
6108
contrib/openapi.json
File diff suppressed because it is too large
Load Diff
@@ -468,6 +468,7 @@ ADMIN_MENU = Menu(
|
||||
MenuGroup(
|
||||
label=_('Ownership'),
|
||||
items=(
|
||||
get_model_item('users', 'ownergroup', _('Owner Groups')),
|
||||
get_model_item('users', 'owner', _('Owners')),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ block.super }}
|
||||
{% if object.group %}
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'users:owner_list' %}?group_id={{ object.group_id }}">{{ object.group }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block subtitle %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@@ -13,6 +22,10 @@
|
||||
<th scope="row">{% trans "Name" %}</th>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Group" %}</th>
|
||||
<td>{{ object.group|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description|placeholder }}</td>
|
||||
@@ -22,7 +35,7 @@
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Groups" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for group in object.groups.all %}
|
||||
{% for group in object.user_groups.all %}
|
||||
<a href="{% url 'users:group' pk=group.pk %}" class="list-group-item list-group-item-action">{{ group }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
|
||||
38
netbox/templates/users/ownergroup.html
Normal file
38
netbox/templates/users/ownergroup.html
Normal file
@@ -0,0 +1,38 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load i18n %}
|
||||
{% load helpers %}
|
||||
{% load render_table from django_tables2 %}
|
||||
|
||||
{% block subtitle %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Group" %}</h2>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "Name" %}</th>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description|placeholder }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Members" %}</h2>
|
||||
<div class="list-group list-group-flush">
|
||||
{% for owner in object.members.all %}
|
||||
<a href="{% url 'users:owner' pk=user.pk %}" class="list-group-item list-group-item-action">{{ owner }}</a>
|
||||
{% empty %}
|
||||
<div class="list-group-item text-muted">{% trans "None" %}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,15 +1,30 @@
|
||||
from netbox.api.fields import SerializedPKRelatedField
|
||||
from netbox.api.fields import RelatedObjectCountField, SerializedPKRelatedField
|
||||
from netbox.api.serializers import ValidatedModelSerializer
|
||||
from users.models import Group, Owner, User
|
||||
from users.models import Group, Owner, OwnerGroup, User
|
||||
from .users import GroupSerializer, UserSerializer
|
||||
|
||||
__all__ = (
|
||||
'OwnerGroupSerializer',
|
||||
'OwnerSerializer',
|
||||
)
|
||||
|
||||
|
||||
class OwnerGroupSerializer(ValidatedModelSerializer):
|
||||
# Related object counts
|
||||
member_count = RelatedObjectCountField('members')
|
||||
|
||||
class Meta:
|
||||
model = OwnerGroup
|
||||
fields = ('id', 'url', 'display_url', 'display', 'name', 'description', 'member_count')
|
||||
brief_fields = ('id', 'url', 'display', 'name', 'description')
|
||||
|
||||
|
||||
class OwnerSerializer(ValidatedModelSerializer):
|
||||
groups = SerializedPKRelatedField(
|
||||
group = OwnerGroupSerializer(
|
||||
nested=True,
|
||||
allow_null=True,
|
||||
)
|
||||
user_groups = SerializedPKRelatedField(
|
||||
queryset=Group.objects.all(),
|
||||
serializer=GroupSerializer,
|
||||
nested=True,
|
||||
@@ -26,5 +41,5 @@ class OwnerSerializer(ValidatedModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Owner
|
||||
fields = ('id', 'url', 'display_url', 'display', 'name', 'description', 'groups', 'users')
|
||||
fields = ('id', 'url', 'display_url', 'display', 'name', 'group', 'description', 'user_groups', 'users')
|
||||
brief_fields = ('id', 'url', 'display', 'name', 'description')
|
||||
|
||||
@@ -11,6 +11,7 @@ router.register('users', views.UserViewSet)
|
||||
router.register('groups', views.GroupViewSet)
|
||||
router.register('tokens', views.TokenViewSet)
|
||||
router.register('permissions', views.ObjectPermissionViewSet)
|
||||
router.register('owner-groups', views.OwnerGroupViewSet)
|
||||
router.register('owners', views.OwnerViewSet)
|
||||
router.register('config', views.UserConfigViewSet, basename='userconfig')
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from rest_framework.viewsets import ViewSet
|
||||
|
||||
from netbox.api.viewsets import NetBoxModelViewSet
|
||||
from users import filtersets
|
||||
from users.models import Group, ObjectPermission, Owner, Token, User, UserConfig
|
||||
from users.models import Group, ObjectPermission, Owner, OwnerGroup, Token, User, UserConfig
|
||||
from utilities.data import deepmerge
|
||||
from utilities.querysets import RestrictedQuerySet
|
||||
from . import serializers
|
||||
@@ -92,6 +92,12 @@ class ObjectPermissionViewSet(NetBoxModelViewSet):
|
||||
# Owners
|
||||
#
|
||||
|
||||
class OwnerGroupViewSet(NetBoxModelViewSet):
|
||||
queryset = OwnerGroup.objects.all()
|
||||
serializer_class = serializers.OwnerGroupSerializer
|
||||
filterset_class = filtersets.OwnerGroupFilterSet
|
||||
|
||||
|
||||
class OwnerViewSet(NetBoxModelViewSet):
|
||||
queryset = Owner.objects.all()
|
||||
serializer_class = serializers.OwnerSerializer
|
||||
|
||||
@@ -6,13 +6,14 @@ from django.utils.translation import gettext as _
|
||||
from core.models import ObjectType
|
||||
from extras.models import NotificationGroup
|
||||
from netbox.filtersets import BaseFilterSet
|
||||
from users.models import Group, ObjectPermission, Owner, Token, User
|
||||
from users.models import Group, ObjectPermission, Owner, OwnerGroup, Token, User
|
||||
from utilities.filters import ContentTypeFilter
|
||||
|
||||
__all__ = (
|
||||
'GroupFilterSet',
|
||||
'ObjectPermissionFilterSet',
|
||||
'OwnerFilterSet',
|
||||
'OwnerGroupFilterSet',
|
||||
'TokenFilterSet',
|
||||
'UserFilterSet',
|
||||
)
|
||||
@@ -246,22 +247,51 @@ class ObjectPermissionFilterSet(BaseFilterSet):
|
||||
return queryset.exclude(actions__contains=[action])
|
||||
|
||||
|
||||
class OwnerGroupFilterSet(BaseFilterSet):
|
||||
q = django_filters.CharFilter(
|
||||
method='search',
|
||||
label=_('Search'),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = OwnerGroup
|
||||
fields = ('id', 'name', 'description')
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
if not value.strip():
|
||||
return queryset
|
||||
return queryset.filter(
|
||||
Q(name__icontains=value) |
|
||||
Q(description__icontains=value)
|
||||
)
|
||||
|
||||
|
||||
class OwnerFilterSet(BaseFilterSet):
|
||||
q = django_filters.CharFilter(
|
||||
method='search',
|
||||
label=_('Search'),
|
||||
)
|
||||
group_id = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='groups',
|
||||
queryset=Group.objects.all(),
|
||||
queryset=OwnerGroup.objects.all(),
|
||||
label=_('Group (ID)'),
|
||||
)
|
||||
group = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='groups__name',
|
||||
queryset=Group.objects.all(),
|
||||
field_name='group__name',
|
||||
queryset=OwnerGroup.objects.all(),
|
||||
to_field_name='name',
|
||||
label=_('Group (name)'),
|
||||
)
|
||||
user_group_id = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='user_groups',
|
||||
queryset=Group.objects.all(),
|
||||
label=_('User group (ID)'),
|
||||
)
|
||||
user_group = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='user_groups__name',
|
||||
queryset=Group.objects.all(),
|
||||
to_field_name='name',
|
||||
label=_('User group (name)'),
|
||||
)
|
||||
user_id = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='users',
|
||||
queryset=User.objects.all(),
|
||||
|
||||
@@ -6,6 +6,7 @@ from ipam.formfields import IPNetworkFormField
|
||||
from ipam.validators import prefix_validator
|
||||
from users.models import *
|
||||
from utilities.forms import BulkEditForm
|
||||
from utilities.forms.fields import DynamicModelChoiceField
|
||||
from utilities.forms.rendering import FieldSet
|
||||
from utilities.forms.widgets import BulkEditNullBooleanSelect, DateTimePicker
|
||||
|
||||
@@ -13,6 +14,7 @@ __all__ = (
|
||||
'GroupBulkEditForm',
|
||||
'ObjectPermissionBulkEditForm',
|
||||
'OwnerBulkEditForm',
|
||||
'OwnerGroupBulkEditForm',
|
||||
'UserBulkEditForm',
|
||||
'TokenBulkEditForm',
|
||||
)
|
||||
@@ -127,11 +129,34 @@ class TokenBulkEditForm(BulkEditForm):
|
||||
)
|
||||
|
||||
|
||||
class OwnerGroupBulkEditForm(BulkEditForm):
|
||||
pk = forms.ModelMultipleChoiceField(
|
||||
queryset=OwnerGroup.objects.all(),
|
||||
widget=forms.MultipleHiddenInput
|
||||
)
|
||||
description = forms.CharField(
|
||||
label=_('Description'),
|
||||
max_length=200,
|
||||
required=False
|
||||
)
|
||||
|
||||
model = OwnerGroup
|
||||
fieldsets = (
|
||||
FieldSet('description',),
|
||||
)
|
||||
nullable_fields = ('description',)
|
||||
|
||||
|
||||
class OwnerBulkEditForm(BulkEditForm):
|
||||
pk = forms.ModelMultipleChoiceField(
|
||||
queryset=Owner.objects.all(),
|
||||
widget=forms.MultipleHiddenInput
|
||||
)
|
||||
group = DynamicModelChoiceField(
|
||||
label=_('Group'),
|
||||
queryset=OwnerGroup.objects.all(),
|
||||
required=False
|
||||
)
|
||||
description = forms.CharField(
|
||||
label=_('Description'),
|
||||
max_length=200,
|
||||
@@ -140,6 +165,6 @@ class OwnerBulkEditForm(BulkEditForm):
|
||||
|
||||
model = Owner
|
||||
fieldsets = (
|
||||
FieldSet('description',),
|
||||
FieldSet('group', 'description'),
|
||||
)
|
||||
nullable_fields = ('description',)
|
||||
nullable_fields = ('group', 'description',)
|
||||
|
||||
@@ -3,11 +3,12 @@ from django.utils.translation import gettext as _
|
||||
from users.models import *
|
||||
from users.choices import TokenVersionChoices
|
||||
from utilities.forms import CSVModelForm
|
||||
from utilities.forms.fields import CSVModelMultipleChoiceField
|
||||
from utilities.forms.fields import CSVModelChoiceField, CSVModelMultipleChoiceField
|
||||
|
||||
|
||||
__all__ = (
|
||||
'GroupImportForm',
|
||||
'OwnerGroupImportForm',
|
||||
'OwnerImportForm',
|
||||
'UserImportForm',
|
||||
'TokenImportForm',
|
||||
@@ -54,8 +55,22 @@ class TokenImportForm(CSVModelForm):
|
||||
fields = ('user', 'version', 'token', 'write_enabled', 'expires', 'description',)
|
||||
|
||||
|
||||
class OwnerGroupImportForm(CSVModelForm):
|
||||
|
||||
class Meta:
|
||||
model = OwnerGroup
|
||||
fields = (
|
||||
'name', 'description',
|
||||
)
|
||||
|
||||
|
||||
class OwnerImportForm(CSVModelForm):
|
||||
groups = CSVModelMultipleChoiceField(
|
||||
group = CSVModelChoiceField(
|
||||
queryset=OwnerGroup.objects.all(),
|
||||
required=False,
|
||||
to_field_name='name',
|
||||
)
|
||||
user_groups = CSVModelMultipleChoiceField(
|
||||
queryset=Group.objects.all(),
|
||||
required=False,
|
||||
to_field_name='name',
|
||||
@@ -69,5 +84,5 @@ class OwnerImportForm(CSVModelForm):
|
||||
class Meta:
|
||||
model = Owner
|
||||
fields = (
|
||||
'name', 'description', 'groups', 'users',
|
||||
'group', 'name', 'description', 'user_groups', 'users',
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
from netbox.forms import NetBoxModelFilterSetForm
|
||||
from netbox.forms.mixins import SavedFiltersMixin
|
||||
from users.choices import TokenVersionChoices
|
||||
from users.models import Group, ObjectPermission, Owner, Token, User
|
||||
from users.models import Group, ObjectPermission, Owner, OwnerGroup, Token, User
|
||||
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm
|
||||
from utilities.forms.fields import DynamicModelMultipleChoiceField
|
||||
from utilities.forms.rendering import FieldSet
|
||||
@@ -15,6 +15,7 @@ __all__ = (
|
||||
'GroupFilterForm',
|
||||
'ObjectPermissionFilterForm',
|
||||
'OwnerFilterForm',
|
||||
'OwnerGroupFilterForm',
|
||||
'TokenFilterForm',
|
||||
'UserFilterForm',
|
||||
)
|
||||
@@ -143,19 +144,32 @@ class TokenFilterForm(SavedFiltersMixin, FilterForm):
|
||||
)
|
||||
|
||||
|
||||
class OwnerGroupFilterForm(NetBoxModelFilterSetForm):
|
||||
model = OwnerGroup
|
||||
fieldsets = (
|
||||
FieldSet('q', 'filter_id',),
|
||||
)
|
||||
|
||||
|
||||
class OwnerFilterForm(NetBoxModelFilterSetForm):
|
||||
model = Owner
|
||||
fieldsets = (
|
||||
FieldSet('q', 'filter_id',),
|
||||
FieldSet('group_id', 'user_id', name=_('Members')),
|
||||
FieldSet('group_id', name=_('Group')),
|
||||
FieldSet('user_group_id', 'user_id', name=_('Membership')),
|
||||
)
|
||||
group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Group.objects.all(),
|
||||
queryset=OwnerGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Group')
|
||||
)
|
||||
user_group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Group.objects.all(),
|
||||
required=False,
|
||||
label=_('Groups')
|
||||
)
|
||||
user_id = DynamicModelMultipleChoiceField(
|
||||
queryset=User.objects.all(),
|
||||
required=False,
|
||||
label=_('User')
|
||||
label=_('Users')
|
||||
)
|
||||
|
||||
@@ -15,7 +15,9 @@ from users.choices import TokenVersionChoices
|
||||
from users.constants import *
|
||||
from users.models import *
|
||||
from utilities.data import flatten_dict
|
||||
from utilities.forms.fields import ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField, JSONField
|
||||
from utilities.forms.fields import (
|
||||
ContentTypeMultipleChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField,
|
||||
)
|
||||
from utilities.forms.rendering import FieldSet
|
||||
from utilities.forms.widgets import DateTimePicker, SplitMultiSelectWidget
|
||||
from utilities.permissions import qs_filter_from_constraints
|
||||
@@ -24,6 +26,7 @@ __all__ = (
|
||||
'GroupForm',
|
||||
'ObjectPermissionForm',
|
||||
'OwnerForm',
|
||||
'OwnerGroupForm',
|
||||
'TokenForm',
|
||||
'UserConfigForm',
|
||||
'UserForm',
|
||||
@@ -433,16 +436,35 @@ class ObjectPermissionForm(forms.ModelForm):
|
||||
return instance
|
||||
|
||||
|
||||
class OwnerForm(forms.ModelForm):
|
||||
class OwnerGroupForm(forms.ModelForm):
|
||||
|
||||
fieldsets = (
|
||||
FieldSet('name', 'description', name=_('Owner')),
|
||||
FieldSet('groups', name=_('Groups')),
|
||||
FieldSet('name', 'description', name=_('Owner Group')),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = OwnerGroup
|
||||
fields = [
|
||||
'name', 'description',
|
||||
]
|
||||
|
||||
|
||||
class OwnerForm(forms.ModelForm):
|
||||
fieldsets = (
|
||||
FieldSet('name', 'group', 'description', name=_('Owner')),
|
||||
FieldSet('user_groups', name=_('Groups')),
|
||||
FieldSet('users', name=_('Users')),
|
||||
)
|
||||
group = DynamicModelChoiceField(
|
||||
label=_('Group'),
|
||||
queryset=OwnerGroup.objects.all(),
|
||||
required=False,
|
||||
selector=True,
|
||||
quick_add=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Owner
|
||||
fields = [
|
||||
'name', 'description', 'groups', 'users',
|
||||
'name', 'group', 'description', 'user_groups', 'users',
|
||||
]
|
||||
|
||||
@@ -11,6 +11,7 @@ from users import models
|
||||
__all__ = (
|
||||
'GroupFilter',
|
||||
'OwnerFilter',
|
||||
'OwnerGroupFilter',
|
||||
'UserFilter',
|
||||
)
|
||||
|
||||
@@ -38,5 +39,16 @@ class UserFilter(BaseObjectTypeFilterMixin):
|
||||
class OwnerFilter(BaseObjectTypeFilterMixin):
|
||||
name: FilterLookup[str] | None = strawberry_django.filter_field()
|
||||
description: FilterLookup[str] | None = strawberry_django.filter_field()
|
||||
groups: Annotated['GroupFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
|
||||
group: Annotated['OwnerGroupFilter', strawberry.lazy('users.graphql.filters')] | None = (
|
||||
strawberry_django.filter_field()
|
||||
)
|
||||
user_groups: Annotated['GroupFilter', strawberry.lazy('users.graphql.filters')] | None = (
|
||||
strawberry_django.filter_field()
|
||||
)
|
||||
users: Annotated['UserFilter', strawberry.lazy('users.graphql.filters')] | None = strawberry_django.filter_field()
|
||||
|
||||
|
||||
@strawberry_django.filter_type(models.OwnerGroup, lookups=True)
|
||||
class OwnerGroupFilter(BaseObjectTypeFilterMixin):
|
||||
name: FilterLookup[str] | None = strawberry_django.filter_field()
|
||||
description: FilterLookup[str] | None = strawberry_django.filter_field()
|
||||
|
||||
@@ -14,5 +14,8 @@ class UsersQuery:
|
||||
user: UserType = strawberry_django.field()
|
||||
user_list: List[UserType] = strawberry_django.field()
|
||||
|
||||
owner_group: OwnerGroupType = strawberry_django.field()
|
||||
owner_group_list: List[OwnerGroupType] = strawberry_django.field()
|
||||
|
||||
owner: OwnerType = strawberry_django.field()
|
||||
owner_list: List[OwnerType] = strawberry_django.field()
|
||||
|
||||
@@ -3,11 +3,12 @@ from typing import List
|
||||
import strawberry_django
|
||||
|
||||
from netbox.graphql.types import BaseObjectType
|
||||
from users.models import Group, Owner, User
|
||||
from users.models import Group, Owner, OwnerGroup, User
|
||||
from .filters import *
|
||||
|
||||
__all__ = (
|
||||
'GroupType',
|
||||
'OwnerGroupType',
|
||||
'OwnerType',
|
||||
'UserType',
|
||||
)
|
||||
@@ -35,11 +36,21 @@ class UserType(BaseObjectType):
|
||||
groups: List[GroupType]
|
||||
|
||||
|
||||
@strawberry_django.type(
|
||||
OwnerGroup,
|
||||
fields=['id', 'name', 'description'],
|
||||
filters=OwnerGroupFilter,
|
||||
pagination=True
|
||||
)
|
||||
class OwnerGroupType(BaseObjectType):
|
||||
pass
|
||||
|
||||
|
||||
@strawberry_django.type(
|
||||
Owner,
|
||||
fields=['id', 'name', 'description', 'groups', 'users'],
|
||||
fields=['id', 'group', 'name', 'description', 'user_groups', 'users'],
|
||||
filters=OwnerFilter,
|
||||
pagination=True
|
||||
)
|
||||
class OwnerType(BaseObjectType):
|
||||
pass
|
||||
group: OwnerGroupType
|
||||
|
||||
@@ -1,28 +1,51 @@
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0014_users_token_v2'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='OwnerGroup',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('description', models.CharField(blank=True, max_length=200)),
|
||||
('name', models.CharField(max_length=100, unique=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'owner group',
|
||||
'verbose_name_plural': 'owner groups',
|
||||
'ordering': ['name'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Owner',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=150, unique=True)),
|
||||
('name', models.CharField(max_length=100, unique=True)),
|
||||
('description', models.CharField(blank=True, max_length=200)),
|
||||
(
|
||||
'groups',
|
||||
'group',
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name='members',
|
||||
to='users.ownergroup',
|
||||
),
|
||||
),
|
||||
(
|
||||
'user_groups',
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
related_name='owners',
|
||||
related_query_name='owner',
|
||||
to='users.group',
|
||||
)
|
||||
),
|
||||
),
|
||||
(
|
||||
'users',
|
||||
@@ -31,7 +54,7 @@ class Migration(migrations.Migration):
|
||||
related_name='owners',
|
||||
related_query_name='owner',
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
)
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
|
||||
@@ -7,16 +7,47 @@ from utilities.querysets import RestrictedQuerySet
|
||||
|
||||
__all__ = (
|
||||
'Owner',
|
||||
'OwnerGroup',
|
||||
)
|
||||
|
||||
|
||||
class OwnerGroup(AdminModel):
|
||||
"""
|
||||
An arbitrary grouping of Owners.
|
||||
"""
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=100,
|
||||
unique=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
verbose_name = _('owner group')
|
||||
verbose_name_plural = _('owner groups')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('users:ownergroup', args=[self.pk])
|
||||
|
||||
|
||||
class Owner(AdminModel):
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=150,
|
||||
max_length=100,
|
||||
unique=True,
|
||||
)
|
||||
groups = models.ManyToManyField(
|
||||
group = models.ForeignKey(
|
||||
to='users.OwnerGroup',
|
||||
on_delete=models.PROTECT,
|
||||
related_name='members',
|
||||
verbose_name=_('group'),
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
user_groups = models.ManyToManyField(
|
||||
to='users.Group',
|
||||
verbose_name=_('groups'),
|
||||
blank=True,
|
||||
@@ -32,7 +63,7 @@ class Owner(AdminModel):
|
||||
)
|
||||
|
||||
objects = RestrictedQuerySet.as_manager()
|
||||
clone_fields = ('groups', 'users')
|
||||
clone_fields = ('user_groups', 'users')
|
||||
|
||||
class Meta:
|
||||
ordering = ('name',)
|
||||
|
||||
@@ -2,11 +2,12 @@ import django_tables2 as tables
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from netbox.tables import NetBoxTable, columns
|
||||
from users.models import Group, ObjectPermission, Owner, Token, User
|
||||
from users.models import Group, ObjectPermission, Owner, OwnerGroup, Token, User
|
||||
|
||||
__all__ = (
|
||||
'GroupTable',
|
||||
'ObjectPermissionTable',
|
||||
'OwnerGroupTable',
|
||||
'OwnerTable',
|
||||
'TokenTable',
|
||||
'UserTable',
|
||||
@@ -146,12 +147,33 @@ class ObjectPermissionTable(NetBoxTable):
|
||||
)
|
||||
|
||||
|
||||
class OwnerGroupTable(NetBoxTable):
|
||||
name = tables.Column(
|
||||
verbose_name=_('Name'),
|
||||
linkify=True
|
||||
)
|
||||
actions = columns.ActionsColumn(
|
||||
actions=('edit', 'delete'),
|
||||
)
|
||||
|
||||
class Meta(NetBoxTable.Meta):
|
||||
model = OwnerGroup
|
||||
fields = (
|
||||
'pk', 'id', 'name', 'description',
|
||||
)
|
||||
default_columns = ('pk', 'name', 'description')
|
||||
|
||||
|
||||
class OwnerTable(NetBoxTable):
|
||||
name = tables.Column(
|
||||
verbose_name=_('Name'),
|
||||
linkify=True
|
||||
)
|
||||
groups = columns.ManyToManyColumn(
|
||||
group = tables.Column(
|
||||
verbose_name=_('Group'),
|
||||
linkify=True,
|
||||
)
|
||||
user_groups = columns.ManyToManyColumn(
|
||||
verbose_name=_('Groups'),
|
||||
linkify_item=('users:group', {'pk': tables.A('pk')})
|
||||
)
|
||||
@@ -166,6 +188,6 @@ class OwnerTable(NetBoxTable):
|
||||
class Meta(NetBoxTable.Meta):
|
||||
model = Owner
|
||||
fields = (
|
||||
'pk', 'id', 'name', 'description', 'groups', 'users',
|
||||
'pk', 'id', 'name', 'group', 'description', 'user_groups', 'users',
|
||||
)
|
||||
default_columns = ('pk', 'name', 'description', 'groups', 'users')
|
||||
default_columns = ('pk', 'name', 'group', 'description', 'user_groups', 'users')
|
||||
|
||||
@@ -18,6 +18,9 @@ urlpatterns = [
|
||||
path('permissions/', include(get_model_urls('users', 'objectpermission', detail=False))),
|
||||
path('permissions/<int:pk>/', include(get_model_urls('users', 'objectpermission'))),
|
||||
|
||||
path('owner-groups/', include(get_model_urls('users', 'ownergroup', detail=False))),
|
||||
path('owner-groups/<int:pk>/', include(get_model_urls('users', 'ownergroup'))),
|
||||
|
||||
path('owners/', include(get_model_urls('users', 'owner', detail=False))),
|
||||
path('owners/<int:pk>/', include(get_model_urls('users', 'owner'))),
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from netbox.object_actions import AddObject, BulkDelete, BulkEdit, BulkExport, B
|
||||
from netbox.views import generic
|
||||
from utilities.views import GetRelatedModelsMixin, register_model_view
|
||||
from . import filtersets, forms, tables
|
||||
from .models import Group, User, ObjectPermission, Owner, Token
|
||||
from .models import Group, User, ObjectPermission, Owner, OwnerGroup, Token
|
||||
|
||||
|
||||
#
|
||||
@@ -233,6 +233,67 @@ class ObjectPermissionBulkDeleteView(generic.BulkDeleteView):
|
||||
table = tables.ObjectPermissionTable
|
||||
|
||||
|
||||
#
|
||||
# Owner groups
|
||||
#
|
||||
|
||||
@register_model_view(OwnerGroup, 'list', path='', detail=False)
|
||||
class OwnerGroupListView(generic.ObjectListView):
|
||||
queryset = OwnerGroup.objects.all()
|
||||
filterset = filtersets.OwnerGroupFilterSet
|
||||
filterset_form = forms.OwnerGroupFilterForm
|
||||
table = tables.OwnerGroupTable
|
||||
|
||||
|
||||
@register_model_view(OwnerGroup)
|
||||
class OwnerGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
||||
queryset = OwnerGroup.objects.all()
|
||||
template_name = 'users/ownergroup.html'
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
return {
|
||||
'related_models': self.get_related_models(request, instance),
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(OwnerGroup, 'add', detail=False)
|
||||
@register_model_view(OwnerGroup, 'edit')
|
||||
class OwnerGroupEditView(generic.ObjectEditView):
|
||||
queryset = OwnerGroup.objects.all()
|
||||
form = forms.OwnerGroupForm
|
||||
|
||||
|
||||
@register_model_view(OwnerGroup, 'delete')
|
||||
class OwnerGroupDeleteView(generic.ObjectDeleteView):
|
||||
queryset = OwnerGroup.objects.all()
|
||||
|
||||
|
||||
@register_model_view(OwnerGroup, 'bulk_import', path='import', detail=False)
|
||||
class OwnerGroupBulkImportView(generic.BulkImportView):
|
||||
queryset = OwnerGroup.objects.all()
|
||||
model_form = forms.OwnerGroupImportForm
|
||||
|
||||
|
||||
@register_model_view(OwnerGroup, 'bulk_edit', path='edit', detail=False)
|
||||
class OwnerGroupBulkEditView(generic.BulkEditView):
|
||||
queryset = OwnerGroup.objects.all()
|
||||
filterset = filtersets.OwnerGroupFilterSet
|
||||
table = tables.OwnerGroupTable
|
||||
form = forms.OwnerGroupBulkEditForm
|
||||
|
||||
|
||||
@register_model_view(OwnerGroup, 'bulk_rename', path='rename', detail=False)
|
||||
class OwnerGroupBulkRenameView(generic.BulkRenameView):
|
||||
queryset = OwnerGroup.objects.all()
|
||||
|
||||
|
||||
@register_model_view(OwnerGroup, 'bulk_delete', path='delete', detail=False)
|
||||
class OwnerGroupBulkDeleteView(generic.BulkDeleteView):
|
||||
queryset = OwnerGroup.objects.all()
|
||||
filterset = filtersets.OwnerGroupFilterSet
|
||||
table = tables.OwnerGroupTable
|
||||
|
||||
|
||||
#
|
||||
# Owners
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user