forms.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. from django import forms
  2. from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm as DjangoPasswordChangeForm
  3. from django.contrib.postgres.forms import SimpleArrayField
  4. from django.utils.html import mark_safe
  5. from ipam.formfields import IPNetworkFormField
  6. from netbox.preferences import PREFERENCES
  7. from utilities.forms import BootstrapMixin, DateTimePicker, StaticSelect
  8. from utilities.utils import flatten_dict
  9. from .models import Token, UserConfig
  10. class LoginForm(BootstrapMixin, AuthenticationForm):
  11. pass
  12. class PasswordChangeForm(BootstrapMixin, DjangoPasswordChangeForm):
  13. pass
  14. class UserConfigFormMetaclass(forms.models.ModelFormMetaclass):
  15. def __new__(mcs, name, bases, attrs):
  16. # Emulate a declared field for each supported user preference
  17. preference_fields = {}
  18. for field_name, preference in PREFERENCES.items():
  19. description = f'{preference.description}<br />' if preference.description else ''
  20. help_text = f'{description}<code>{field_name}</code>'
  21. field_kwargs = {
  22. 'label': preference.label,
  23. 'choices': preference.choices,
  24. 'help_text': mark_safe(help_text),
  25. 'coerce': preference.coerce,
  26. 'required': False,
  27. 'widget': StaticSelect,
  28. }
  29. preference_fields[field_name] = forms.TypedChoiceField(**field_kwargs)
  30. attrs.update(preference_fields)
  31. return super().__new__(mcs, name, bases, attrs)
  32. class UserConfigForm(BootstrapMixin, forms.ModelForm, metaclass=UserConfigFormMetaclass):
  33. fieldsets = (
  34. ('User Interface', (
  35. 'pagination.per_page',
  36. 'pagination.placement',
  37. 'ui.colormode',
  38. )),
  39. ('Miscellaneous', (
  40. 'data_format',
  41. )),
  42. )
  43. # List of clearable preferences
  44. pk = forms.MultipleChoiceField(
  45. choices=[],
  46. required=False
  47. )
  48. class Meta:
  49. model = UserConfig
  50. fields = ()
  51. def __init__(self, *args, instance=None, **kwargs):
  52. # Get initial data from UserConfig instance
  53. initial_data = flatten_dict(instance.data)
  54. kwargs['initial'] = initial_data
  55. super().__init__(*args, instance=instance, **kwargs)
  56. # Compile clearable preference choices
  57. self.fields['pk'].choices = (
  58. (f'tables.{table_name}', '') for table_name in instance.data.get('tables', [])
  59. )
  60. def save(self, *args, **kwargs):
  61. # Set UserConfig data
  62. for pref_name, value in self.cleaned_data.items():
  63. if pref_name == 'pk':
  64. continue
  65. self.instance.set(pref_name, value, commit=False)
  66. # Clear selected preferences
  67. for preference in self.cleaned_data['pk']:
  68. self.instance.clear(preference)
  69. return super().save(*args, **kwargs)
  70. @property
  71. def plugin_fields(self):
  72. return [
  73. name for name in self.fields.keys() if name.startswith('plugins.')
  74. ]
  75. class TokenForm(BootstrapMixin, forms.ModelForm):
  76. key = forms.CharField(
  77. required=False,
  78. help_text="If no key is provided, one will be generated automatically."
  79. )
  80. allowed_ips = SimpleArrayField(
  81. base_field=IPNetworkFormField(),
  82. required=False,
  83. label='Allowed IPs',
  84. help_text='Allowed IPv4/IPv6 networks from where the token can be used. Leave blank for no restrictions. '
  85. 'Ex: "10.1.1.0/24, 192.168.10.16/32, 2001:DB8:1::/64"',
  86. )
  87. class Meta:
  88. model = Token
  89. fields = [
  90. 'key', 'write_enabled', 'expires', 'description', 'allowed_ips',
  91. ]
  92. widgets = {
  93. 'expires': DateTimePicker(),
  94. }