mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-25 08:46:10 -06:00
Clean up model forms
This commit is contained in:
parent
d24330f412
commit
b5362f059c
@ -1,3 +1,4 @@
|
|||||||
|
from .authentication import *
|
||||||
from .bulk_edit import *
|
from .bulk_edit import *
|
||||||
from .bulk_import import *
|
from .bulk_import import *
|
||||||
from .filtersets import *
|
from .filtersets import *
|
||||||
|
25
netbox/users/forms/authentication.py
Normal file
25
netbox/users/forms/authentication.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
from django.contrib.auth.forms import (
|
||||||
|
AuthenticationForm,
|
||||||
|
PasswordChangeForm as DjangoPasswordChangeForm,
|
||||||
|
)
|
||||||
|
|
||||||
|
from utilities.forms import BootstrapMixin
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'LoginForm',
|
||||||
|
'PasswordChangeForm',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LoginForm(BootstrapMixin, AuthenticationForm):
|
||||||
|
"""
|
||||||
|
Used to authenticate a user by username and password.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordChangeForm(BootstrapMixin, DjangoPasswordChangeForm):
|
||||||
|
"""
|
||||||
|
This form enables a user to change his or her own password.
|
||||||
|
"""
|
||||||
|
pass
|
@ -1,50 +1,33 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm as DjangoPasswordChangeForm, SetPasswordForm as DjangoPasswordSetForm
|
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.postgres.forms import SimpleArrayField
|
from django.contrib.postgres.forms import SimpleArrayField
|
||||||
from django.core.exceptions import FieldError
|
from django.core.exceptions import FieldError
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils.html import mark_safe
|
from django.utils.html import mark_safe
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from ipam.formfields import IPNetworkFormField
|
from ipam.formfields import IPNetworkFormField
|
||||||
from ipam.validators import prefix_validator
|
from ipam.validators import prefix_validator
|
||||||
from netbox.preferences import PREFERENCES
|
from netbox.preferences import PREFERENCES
|
||||||
from utilities.forms import BootstrapMixin
|
|
||||||
from utilities.forms.fields import ContentTypeMultipleChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField
|
|
||||||
from utilities.forms.widgets import DateTimePicker
|
|
||||||
from utilities.utils import flatten_dict
|
|
||||||
from users.constants import *
|
from users.constants import *
|
||||||
from users.models import *
|
from users.models import *
|
||||||
|
from utilities.forms import BootstrapMixin
|
||||||
|
from utilities.forms.fields import ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField
|
||||||
|
from utilities.forms.widgets import DateTimePicker
|
||||||
from utilities.permissions import qs_filter_from_constraints
|
from utilities.permissions import qs_filter_from_constraints
|
||||||
|
from utilities.utils import flatten_dict
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'GroupForm',
|
'GroupForm',
|
||||||
'LoginForm',
|
|
||||||
'ObjectPermissionForm',
|
'ObjectPermissionForm',
|
||||||
'PasswordChangeForm',
|
|
||||||
'PasswordSetForm',
|
|
||||||
'TokenForm',
|
'TokenForm',
|
||||||
'UserConfigForm',
|
'UserConfigForm',
|
||||||
'UserForm',
|
'UserForm',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LoginForm(BootstrapMixin, AuthenticationForm):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class PasswordChangeForm(BootstrapMixin, DjangoPasswordChangeForm):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class PasswordSetForm(BootstrapMixin, DjangoPasswordSetForm):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class UserConfigFormMetaclass(forms.models.ModelFormMetaclass):
|
class UserConfigFormMetaclass(forms.models.ModelFormMetaclass):
|
||||||
|
|
||||||
def __new__(mcs, name, bases, attrs):
|
def __new__(mcs, name, bases, attrs):
|
||||||
@ -180,10 +163,10 @@ class UserForm(BootstrapMixin, forms.ModelForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(_('User'), ('username', 'password', 'confirm_password', 'first_name', 'last_name', 'email', )),
|
(_('User'), ('username', 'password', 'confirm_password', 'first_name', 'last_name', 'email')),
|
||||||
(_('Groups'), ('groups', )),
|
(_('Groups'), ('groups', )),
|
||||||
(_('Status'), ('is_active', 'is_staff', 'is_superuser', )),
|
(_('Status'), ('is_active', 'is_staff', 'is_superuser')),
|
||||||
(_('Permissions'), ('object_permissions', )),
|
(_('Permissions'), ('object_permissions',)),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -196,41 +179,36 @@ class UserForm(BootstrapMixin, forms.ModelForm):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
# Adjust form fields depending if Add or Edit
|
|
||||||
if self.instance.pk:
|
if self.instance.pk:
|
||||||
self.fields['object_permissions'].initial = self.instance.object_permissions.all().values_list('id', flat=True)
|
# Populate assigned permissions
|
||||||
pw_field = self.fields['password']
|
self.fields['object_permissions'].initial = self.instance.object_permissions.values_list('id', flat=True)
|
||||||
pwc_field = self.fields['confirm_password']
|
|
||||||
pw_field.required = False
|
# Password fields are optional for existing Users
|
||||||
pw_field.widget.attrs.pop('required')
|
self.fields['password'].required = False
|
||||||
pw_field.help_text = _("Leave empty to keep the old password.")
|
self.fields['password'].widget.attrs.pop('required')
|
||||||
pwc_field.required = False
|
self.fields['confirm_password'].required = False
|
||||||
pwc_field.widget.attrs.pop('required')
|
self.fields['confirm_password'].widget.attrs.pop('required')
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
edited = getattr(self, 'instance', None)
|
|
||||||
instance = super().save(*args, **kwargs)
|
instance = super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
# Update assigned permissions
|
||||||
instance.object_permissions.set(self.cleaned_data['object_permissions'])
|
instance.object_permissions.set(self.cleaned_data['object_permissions'])
|
||||||
|
|
||||||
# On edit, check if we have to save the password
|
# On edit, check if we have to save the password
|
||||||
if edited and self.cleaned_data.get("password"):
|
if self.cleaned_data.get('password'):
|
||||||
instance.set_password(self.cleaned_data.get("password"))
|
instance.set_password(self.cleaned_data.get('password'))
|
||||||
instance.save()
|
instance.save()
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super().clean()
|
|
||||||
instance = getattr(self, 'instance', None)
|
|
||||||
if not instance or cleaned_data.get("password"):
|
|
||||||
password = cleaned_data.get("password")
|
|
||||||
confirm_password = cleaned_data.get("confirm_password")
|
|
||||||
|
|
||||||
if password != confirm_password:
|
# Check that password confirmation matches if password is set
|
||||||
raise forms.ValidationError(
|
if self.cleaned_data['password'] and self.cleaned_data['password'] != self.cleaned_data['confirm_password']:
|
||||||
_("password and confirm_password does not match")
|
raise forms.ValidationError(_("Passwords do not match! Please check your input and try again."))
|
||||||
)
|
|
||||||
|
|
||||||
|
# TODO: Move this logic to the NetBoxUser class
|
||||||
def clean_username(self):
|
def clean_username(self):
|
||||||
"""Reject usernames that differ only in case."""
|
"""Reject usernames that differ only in case."""
|
||||||
instance = getattr(self, 'instance', None)
|
instance = getattr(self, 'instance', None)
|
||||||
@ -277,22 +255,46 @@ class GroupForm(BootstrapMixin, forms.ModelForm):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Populate assigned users and permissions
|
||||||
if self.instance.pk:
|
if self.instance.pk:
|
||||||
self.fields['users'].initial = self.instance.user_set.all().values_list('id', flat=True)
|
self.fields['users'].initial = self.instance.user_set.values_list('id', flat=True)
|
||||||
self.fields['object_permissions'].initial = self.instance.object_permissions.all().values_list('id', flat=True)
|
self.fields['object_permissions'].initial = self.instance.object_permissions.values_list('id', flat=True)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
instance = super().save(*args, **kwargs)
|
instance = super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
# Update assigned users and permissions
|
||||||
instance.user_set.set(self.cleaned_data['users'])
|
instance.user_set.set(self.cleaned_data['users'])
|
||||||
instance.object_permissions.set(self.cleaned_data['object_permissions'])
|
instance.object_permissions.set(self.cleaned_data['object_permissions'])
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
class ObjectPermissionForm(BootstrapMixin, forms.ModelForm):
|
class ObjectPermissionForm(BootstrapMixin, forms.ModelForm):
|
||||||
|
object_types = ContentTypeMultipleChoiceField(
|
||||||
|
label=_('Object types'),
|
||||||
|
queryset=ContentType.objects.all(),
|
||||||
|
limit_choices_to=OBJECTPERMISSION_OBJECT_TYPES,
|
||||||
|
widget=forms.SelectMultiple(attrs={'size': 6})
|
||||||
|
)
|
||||||
|
can_view = forms.BooleanField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
can_add = forms.BooleanField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
can_change = forms.BooleanField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
can_delete = forms.BooleanField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
actions = SimpleArrayField(
|
actions = SimpleArrayField(
|
||||||
label=_('Actions'),
|
label=_('Additional actions'),
|
||||||
base_field=forms.CharField(),
|
base_field=forms.CharField(),
|
||||||
required=False,
|
required=False,
|
||||||
|
help_text=_('Actions granted in addition to those listed above')
|
||||||
)
|
)
|
||||||
users = DynamicModelMultipleChoiceField(
|
users = DynamicModelMultipleChoiceField(
|
||||||
label=_('Users'),
|
label=_('Users'),
|
||||||
@ -304,17 +306,6 @@ class ObjectPermissionForm(BootstrapMixin, forms.ModelForm):
|
|||||||
required=False,
|
required=False,
|
||||||
queryset=Group.objects.all()
|
queryset=Group.objects.all()
|
||||||
)
|
)
|
||||||
object_types = ContentTypeMultipleChoiceField(
|
|
||||||
label=_('Object types'),
|
|
||||||
queryset=ContentType.objects.all(),
|
|
||||||
limit_choices_to=OBJECTPERMISSION_OBJECT_TYPES,
|
|
||||||
widget=forms.SelectMultiple(attrs={'size': 6})
|
|
||||||
)
|
|
||||||
|
|
||||||
can_view = forms.BooleanField(required=False)
|
|
||||||
can_add = forms.BooleanField(required=False)
|
|
||||||
can_change = forms.BooleanField(required=False)
|
|
||||||
can_delete = forms.BooleanField(required=False)
|
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('name', 'description', 'enabled',)),
|
(None, ('name', 'description', 'enabled',)),
|
||||||
@ -330,13 +321,11 @@ class ObjectPermissionForm(BootstrapMixin, forms.ModelForm):
|
|||||||
'name', 'description', 'enabled', 'object_types', 'users', 'groups', 'constraints', 'actions',
|
'name', 'description', 'enabled', 'object_types', 'users', 'groups', 'constraints', 'actions',
|
||||||
]
|
]
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'actions': _('Actions granted in addition to those listed above'),
|
'constraints': _(
|
||||||
'constraints': _('JSON expression of a queryset filter that will return only permitted objects. Leave null '
|
'JSON expression of a queryset filter that will return only permitted objects. Leave null '
|
||||||
'to match all objects of this type. A list of multiple objects will result in a logical OR '
|
'to match all objects of this type. A list of multiple objects will result in a logical OR '
|
||||||
'operation.')
|
'operation.'
|
||||||
}
|
)
|
||||||
labels = {
|
|
||||||
'actions': 'Additional actions'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
Loading…
Reference in New Issue
Block a user