From 5064bd45743c0ec2fb1223fc13eae245f9e8d17b Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 25 Jul 2023 10:53:26 -0400 Subject: [PATCH] Employ standard naming for Token view, form, table classes --- netbox/netbox/settings.py | 1 + netbox/templates/inc/profile_button.html | 2 +- netbox/templates/users/account/api_token.html | 6 ++- .../templates/users/account/api_tokens.html | 2 +- netbox/templates/users/account/base.html | 2 +- netbox/users/filtersets.py | 49 ------------------- netbox/users/forms/bulk_edit.py | 4 +- netbox/users/forms/bulk_import.py | 4 +- netbox/users/forms/filtersets.py | 4 +- netbox/users/forms/model_forms.py | 30 +++--------- netbox/users/tables.py | 26 ---------- netbox/users/urls.py | 17 ++++--- netbox/users/views.py | 44 ++++++++--------- 13 files changed, 52 insertions(+), 139 deletions(-) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 7d2da2996..da58b0dd6 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -469,6 +469,7 @@ EXEMPT_EXCLUDE_MODELS = ( ('auth', 'group'), ('auth', 'user'), ('users', 'objectpermission'), + ('users', 'token'), ) # All URLs starting with a string listed here are exempt from login enforcement diff --git a/netbox/templates/inc/profile_button.html b/netbox/templates/inc/profile_button.html index 932b91275..a5d8cef61 100644 --- a/netbox/templates/inc/profile_button.html +++ b/netbox/templates/inc/profile_button.html @@ -34,7 +34,7 @@
  • - + API Tokens
  • diff --git a/netbox/templates/users/account/api_token.html b/netbox/templates/users/account/api_token.html index 7fd6f064d..587a1db38 100644 --- a/netbox/templates/users/account/api_token.html +++ b/netbox/templates/users/account/api_token.html @@ -3,6 +3,10 @@ {% load helpers %} {% load plugins %} +{% block breadcrumbs %} + +{% endblock breadcrumbs %} + {% block content %}
    @@ -50,7 +54,7 @@
    - Add Another + Add Another Cancel
    diff --git a/netbox/templates/users/account/api_tokens.html b/netbox/templates/users/account/api_tokens.html index 25f5f02e6..46addbc47 100644 --- a/netbox/templates/users/account/api_tokens.html +++ b/netbox/templates/users/account/api_tokens.html @@ -7,7 +7,7 @@ {% block content %}
    diff --git a/netbox/templates/users/account/base.html b/netbox/templates/users/account/base.html index f492f89ec..9ac61bced 100644 --- a/netbox/templates/users/account/base.html +++ b/netbox/templates/users/account/base.html @@ -18,7 +18,7 @@ {% endif %} {% endblock %} diff --git a/netbox/users/filtersets.py b/netbox/users/filtersets.py index 100b2ea03..0f590e012 100644 --- a/netbox/users/filtersets.py +++ b/netbox/users/filtersets.py @@ -12,7 +12,6 @@ __all__ = ( 'ObjectPermissionFilterSet', 'TokenFilterSet', 'UserFilterSet', - 'UserTokenFilterSet', ) @@ -112,54 +111,6 @@ class TokenFilterSet(BaseFilterSet): ) -class UserTokenFilterSet(BaseFilterSet): - q = django_filters.CharFilter( - method='search', - label=_('Search'), - ) - user_id = django_filters.ModelMultipleChoiceFilter( - field_name='user', - queryset=get_user_model().objects.all(), - label=_('User'), - ) - user = django_filters.ModelMultipleChoiceFilter( - field_name='user__username', - queryset=get_user_model().objects.all(), - to_field_name='username', - label=_('User (name)'), - ) - created = django_filters.DateTimeFilter() - created__gte = django_filters.DateTimeFilter( - field_name='created', - lookup_expr='gte' - ) - created__lte = django_filters.DateTimeFilter( - field_name='created', - lookup_expr='lte' - ) - expires = django_filters.DateTimeFilter() - expires__gte = django_filters.DateTimeFilter( - field_name='expires', - lookup_expr='gte' - ) - expires__lte = django_filters.DateTimeFilter( - field_name='expires', - lookup_expr='lte' - ) - - class Meta: - model = Token - fields = ['id', 'key', 'write_enabled', 'description'] - - def search(self, queryset, name, value): - if not value.strip(): - return queryset - return queryset.filter( - Q(user__username__icontains=value) | - Q(description__icontains=value) - ) - - class ObjectPermissionFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', diff --git a/netbox/users/forms/bulk_edit.py b/netbox/users/forms/bulk_edit.py index 2eaac4ef9..50f31ae04 100644 --- a/netbox/users/forms/bulk_edit.py +++ b/netbox/users/forms/bulk_edit.py @@ -8,7 +8,7 @@ from utilities.forms.widgets import BulkEditNullBooleanSelect __all__ = ( 'ObjectPermissionBulkEditForm', 'UserBulkEditForm', - 'UserTokenBulkEditForm', + 'TokenBulkEditForm', ) @@ -73,7 +73,7 @@ class ObjectPermissionBulkEditForm(BootstrapMixin, forms.Form): nullable_fields = ('description',) -class UserTokenBulkEditForm(BulkEditForm): +class TokenBulkEditForm(BulkEditForm): pk = forms.ModelMultipleChoiceField( queryset=Token.objects.all(), widget=forms.MultipleHiddenInput diff --git a/netbox/users/forms/bulk_import.py b/netbox/users/forms/bulk_import.py index c50ab463a..dc0185403 100644 --- a/netbox/users/forms/bulk_import.py +++ b/netbox/users/forms/bulk_import.py @@ -7,7 +7,7 @@ from utilities.forms import CSVModelForm __all__ = ( 'GroupImportForm', 'UserImportForm', - 'UserTokenImportForm', + 'TokenImportForm', ) @@ -36,7 +36,7 @@ class UserImportForm(CSVModelForm): return super().save(*args, **kwargs) -class UserTokenImportForm(CSVModelForm): +class TokenImportForm(CSVModelForm): key = forms.CharField( label=_('Key'), required=False, help_text=_("If no key is provided, one will be generated automatically.") ) diff --git a/netbox/users/forms/filtersets.py b/netbox/users/forms/filtersets.py index 121a7ab0b..2232a7986 100644 --- a/netbox/users/forms/filtersets.py +++ b/netbox/users/forms/filtersets.py @@ -16,7 +16,7 @@ __all__ = ( 'GroupFilterForm', 'ObjectPermissionFilterForm', 'UserFilterForm', - 'UserTokenFilterForm', + 'TokenFilterForm', ) @@ -116,7 +116,7 @@ class ObjectPermissionFilterForm(NetBoxModelFilterSetForm): ) -class UserTokenFilterForm(SavedFiltersMixin, FilterForm): +class TokenFilterForm(SavedFiltersMixin, FilterForm): model = Token fieldsets = ( (None, ('q', 'filter_id',)), diff --git a/netbox/users/forms/model_forms.py b/netbox/users/forms/model_forms.py index ba0b11c5c..6ca050110 100644 --- a/netbox/users/forms/model_forms.py +++ b/netbox/users/forms/model_forms.py @@ -20,12 +20,13 @@ from utilities.permissions import qs_filter_from_constraints from utilities.utils import flatten_dict __all__ = ( + 'UserTokenForm', 'GroupForm', 'ObjectPermissionForm', 'TokenForm', 'UserConfigForm', 'UserForm', - 'UserTokenForm', + 'TokenForm', ) @@ -108,9 +109,11 @@ class UserConfigForm(BootstrapMixin, forms.ModelForm, metaclass=UserConfigFormMe ] -class TokenForm(BootstrapMixin, forms.ModelForm): +class UserTokenForm(BootstrapMixin, forms.ModelForm): key = forms.CharField( - label=_('Key'), required=False, help_text=_("If no key is provided, one will be generated automatically.") + label=_('Key'), + required=False, + help_text=_("If no key is provided, one will be generated automatically.") ) allowed_ips = SimpleArrayField( base_field=IPNetworkFormField(validators=[prefix_validator]), @@ -139,25 +142,13 @@ class TokenForm(BootstrapMixin, forms.ModelForm): del self.fields['key'] -class UserTokenForm(BootstrapMixin, forms.ModelForm): - key = forms.CharField( - label=_('Key'), required=False, help_text=_("If no key is provided, one will be generated automatically.") - ) +class TokenForm(UserTokenForm): user = forms.ModelChoiceField( queryset=get_user_model().objects.order_by( 'username' ), required=False ) - allowed_ips = SimpleArrayField( - base_field=IPNetworkFormField(validators=[prefix_validator]), - required=False, - label=_('Allowed IPs'), - help_text=_( - 'Allowed IPv4/IPv6 networks from where the token can be used. Leave blank for no restrictions. ' - 'Example: 10.1.1.0/24,192.168.10.16/32,2001:db8:1::/64' - ), - ) class Meta: model = Token @@ -168,13 +159,6 @@ class UserTokenForm(BootstrapMixin, forms.ModelForm): 'expires': DateTimePicker(), } - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - # Omit the key field if token retrieval is not permitted - if self.instance.pk and not settings.ALLOW_TOKEN_RETRIEVAL: - del self.fields['key'] - class UserForm(BootstrapMixin, forms.ModelForm): password = forms.CharField( diff --git a/netbox/users/tables.py b/netbox/users/tables.py index 6ba1b2add..86ca838e0 100644 --- a/netbox/users/tables.py +++ b/netbox/users/tables.py @@ -8,7 +8,6 @@ __all__ = ( 'ObjectPermissionTable', 'TokenTable', 'UserTable', - 'UserTokenTable', ) @@ -32,31 +31,6 @@ class TokenActionsColumn(columns.ActionsColumn): class TokenTable(NetBoxTable): - key = columns.TemplateColumn( - template_code=TOKEN - ) - write_enabled = columns.BooleanColumn( - verbose_name='Write' - ) - created = columns.DateColumn() - expired = columns.DateColumn() - last_used = columns.DateTimeColumn() - allowed_ips = columns.TemplateColumn( - template_code=ALLOWED_IPS - ) - actions = TokenActionsColumn( - actions=('edit', 'delete'), - extra_buttons=COPY_BUTTON - ) - - class Meta(NetBoxTable.Meta): - model = Token - fields = ( - 'pk', 'description', 'key', 'write_enabled', 'created', 'expires', 'last_used', 'allowed_ips', - ) - - -class UserTokenTable(NetBoxTable): key = columns.TemplateColumn( verbose_name='Key', template_code=TOKEN, diff --git a/netbox/users/urls.py b/netbox/users/urls.py index bb21f72c1..496201b92 100644 --- a/netbox/users/urls.py +++ b/netbox/users/urls.py @@ -11,16 +11,17 @@ urlpatterns = [ path('bookmarks/', views.BookmarkListView.as_view(), name='bookmarks'), path('preferences/', views.UserConfigView.as_view(), name='preferences'), path('password/', views.ChangePasswordView.as_view(), name='change_password'), - path('api-tokens/', views.TokenListView.as_view(), name='token_list'), - path('api-tokens/add/', views.TokenEditView.as_view(), name='token_add'), - path('api-tokens//', include(get_model_urls('users', 'token'))), + path('api-tokens/', views.UserTokenListView.as_view(), name='usertoken_list'), + path('api-tokens/add/', views.UserTokenEditView.as_view(), name='usertoken_add'), + path('api-tokens//edit/', views.UserTokenEditView.as_view(), name='usertoken_edit'), + path('api-tokens//delete/', views.UserTokenDeleteView.as_view(), name='usertoken_delete'), # Tokens - path('tokens/', views.UserTokenListView.as_view(), name='token_list'), - path('tokens/add/', views.UserTokenEditView.as_view(), name='token_add'), - path('tokens/import/', views.UserTokenBulkImportView.as_view(), name='token_import'), - path('tokens/edit/', views.UserTokenBulkEditView.as_view(), name='token_bulk_edit'), - path('tokens/delete/', views.UserTokenBulkDeleteView.as_view(), name='token_bulk_delete'), + path('tokens/', views.TokenListView.as_view(), name='token_list'), + path('tokens/add/', views.TokenEditView.as_view(), name='token_add'), + path('tokens/import/', views.TokenBulkImportView.as_view(), name='token_import'), + path('tokens/edit/', views.TokenBulkEditView.as_view(), name='token_bulk_edit'), + path('tokens/delete/', views.TokenBulkDeleteView.as_view(), name='token_bulk_delete'), path('tokens//', include(get_model_urls('users', 'token'))), # Users diff --git a/netbox/users/views.py b/netbox/users/views.py index f77e8503d..14c8a7d5c 100644 --- a/netbox/users/views.py +++ b/netbox/users/views.py @@ -252,7 +252,7 @@ class BookmarkListView(LoginRequiredMixin, generic.ObjectListView): # API tokens # -class TokenListView(LoginRequiredMixin, View): +class UserTokenListView(LoginRequiredMixin, View): def get(self, request): @@ -267,8 +267,7 @@ class TokenListView(LoginRequiredMixin, View): }) -@register_model_view(Token, 'edit') -class TokenEditView(LoginRequiredMixin, View): +class UserTokenEditView(LoginRequiredMixin, View): def get(self, request, pk=None): @@ -277,7 +276,7 @@ class TokenEditView(LoginRequiredMixin, View): else: token = Token(user=request.user) - form = forms.TokenForm(instance=token) + form = forms.UserTokenForm(instance=token) return render(request, 'generic/object_edit.html', { 'object': token, @@ -289,10 +288,10 @@ class TokenEditView(LoginRequiredMixin, View): if pk: token = get_object_or_404(Token.objects.filter(user=request.user), pk=pk) - form = forms.TokenForm(request.POST, instance=token) + form = forms.UserTokenForm(request.POST, instance=token) else: token = Token(user=request.user) - form = forms.TokenForm(request.POST) + form = forms.UserTokenForm(request.POST) if form.is_valid(): @@ -322,8 +321,7 @@ class TokenEditView(LoginRequiredMixin, View): }) -@register_model_view(Token, 'delete') -class TokenDeleteView(LoginRequiredMixin, View): +class UserTokenDeleteView(LoginRequiredMixin, View): def get(self, request, pk): @@ -356,18 +354,18 @@ class TokenDeleteView(LoginRequiredMixin, View): # -# User Token +# Tokens # -class UserTokenListView(generic.ObjectListView): +class TokenListView(generic.ObjectListView): queryset = Token.objects.all() - filterset = filtersets.UserTokenFilterSet - filterset_form = forms.UserTokenFilterForm - table = tables.UserTokenTable + filterset = filtersets.TokenFilterSet + filterset_form = forms.TokenFilterForm + table = tables.TokenTable @register_model_view(Token) -class UserTokenView(generic.ObjectView): +class TokenView(generic.ObjectView): queryset = Token.objects.all() def get_extra_context(self, request, instance): @@ -375,30 +373,30 @@ class UserTokenView(generic.ObjectView): @register_model_view(Token, 'edit') -class UserTokenEditView(generic.ObjectEditView): +class TokenEditView(generic.ObjectEditView): queryset = Token.objects.all() - form = forms.UserTokenForm + form = forms.TokenForm @register_model_view(Token, 'delete') -class UserTokenDeleteView(generic.ObjectDeleteView): +class TokenDeleteView(generic.ObjectDeleteView): queryset = Token.objects.all() -class UserTokenBulkImportView(generic.BulkImportView): +class TokenBulkImportView(generic.BulkImportView): queryset = Token.objects.all() - model_form = forms.UserTokenImportForm + model_form = forms.TokenImportForm -class UserTokenBulkEditView(generic.BulkEditView): +class TokenBulkEditView(generic.BulkEditView): queryset = Token.objects.all() table = tables.TokenTable - form = forms.UserTokenBulkEditForm + form = forms.TokenBulkEditForm -class UserTokenBulkDeleteView(generic.BulkDeleteView): +class TokenBulkDeleteView(generic.BulkDeleteView): queryset = Token.objects.all() - table = tables.UserTokenTable + table = tables.TokenTable #