From 36d2422eefa25d2414b2141dca518e8111a55736 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 21 Dec 2021 17:05:06 -0500 Subject: [PATCH] Introduce UserPreference to define user preferences --- netbox/users/forms.py | 60 ++++++++++++++++--------------------- netbox/users/preferences.py | 46 ++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 35 deletions(-) create mode 100644 netbox/users/preferences.py diff --git a/netbox/users/forms.py b/netbox/users/forms.py index 7007ef958..c4e55c5bc 100644 --- a/netbox/users/forms.py +++ b/netbox/users/forms.py @@ -2,9 +2,9 @@ from django import forms from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm as DjangoPasswordChangeForm from utilities.forms import BootstrapMixin, DateTimePicker -from utilities.paginator import EnhancedPaginator from utilities.utils import flatten_dict from .models import Token, UserConfig +from .preferences import PREFERENCES class LoginForm(BootstrapMixin, AuthenticationForm): @@ -15,53 +15,45 @@ class PasswordChangeForm(BootstrapMixin, DjangoPasswordChangeForm): pass -def get_page_lengths(): - return [ - (v, str(v)) for v in EnhancedPaginator.default_page_lengths - ] +class UserConfigFormMetaclass(forms.models.ModelFormMetaclass): + + def __new__(mcs, name, bases, attrs): + + # Emulate a declared field for each supported user preference + preference_fields = {} + for field_name, preference in PREFERENCES.items(): + field_kwargs = { + 'label': preference.label, + 'choices': preference.choices, + 'help_text': preference.description, + 'coerce': preference.coerce, + 'required': False, + } + preference_fields[field_name] = forms.TypedChoiceField(**field_kwargs) + attrs.update(preference_fields) + + return super().__new__(mcs, name, bases, attrs) -class UserConfigForm(BootstrapMixin, forms.ModelForm): - pagination__per_page = forms.TypedChoiceField( - label='Page length', - coerce=lambda val: int(val), - choices=get_page_lengths, - required=False - ) - ui__colormode = forms.ChoiceField( - label='Color mode', - choices=( - ('light', 'Light'), - ('dark', 'Dark'), - ), - required=False - ) - extras__configcontext__format = forms.ChoiceField( - label='ConfigContext format', - choices=( - ('json', 'JSON'), - ('yaml', 'YAML'), - ), - required=False - ) +class UserConfigForm(BootstrapMixin, forms.ModelForm, metaclass=UserConfigFormMetaclass): class Meta: model = UserConfig fields = () fieldsets = ( ('User Interface', ( - 'pagination__per_page', - 'ui__colormode', + 'pagination.per_page', + 'ui.colormode', )), ('Miscellaneous', ( - 'extras__configcontext__format', + 'data_format', )), ) def __init__(self, *args, instance=None, **kwargs): # Get initial data from UserConfig instance - initial_data = flatten_dict(instance.data, separator='__') + initial_data = flatten_dict(instance.data) kwargs['initial'] = initial_data super().__init__(*args, instance=instance, **kwargs) @@ -69,9 +61,7 @@ class UserConfigForm(BootstrapMixin, forms.ModelForm): def save(self, *args, **kwargs): # Set UserConfig data - for field_name, value in self.cleaned_data.items(): - pref_name = field_name.replace('__', '.') - print(f'{pref_name}: {value}') + for pref_name, value in self.cleaned_data.items(): self.instance.set(pref_name, value, commit=False) return super().save(*args, **kwargs) diff --git a/netbox/users/preferences.py b/netbox/users/preferences.py new file mode 100644 index 000000000..18c3dbac0 --- /dev/null +++ b/netbox/users/preferences.py @@ -0,0 +1,46 @@ +from utilities.paginator import EnhancedPaginator + + +def get_page_lengths(): + return [ + (v, str(v)) for v in EnhancedPaginator.default_page_lengths + ] + + +class UserPreference: + + def __init__(self, label, choices, default=None, description='', coerce=lambda x: x): + self.label = label + self.choices = choices + self.default = default if default is not None else choices[0] + self.description = description + self.coerce = coerce + + +PREFERENCES = { + + # User interface + 'ui.colormode': UserPreference( + label='Color mode', + choices=( + ('light', 'Light'), + ('dark', 'Dark'), + ), + default='light', + ), + 'pagination.per_page': UserPreference( + label='Page length', + choices=get_page_lengths(), + coerce=lambda x: int(x) + ), + + # Miscellaneous + 'data_format': UserPreference( + label='Data format', + choices=( + ('json', 'JSON'), + ('yaml', 'YAML'), + ), + ), + +}