From 58e38c1ff90fff59952cc42c001eff07ae8cca72 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 9 Jan 2019 12:23:39 -0400 Subject: [PATCH] Improve FilteredSelectionForm Improve the configuration process of the FilteredSelectionForm form by adding Meta child class support. The child Meta class is defined in FilteredSelectionFormOptions. Signed-off-by: Roberto Rosario --- mayan/apps/common/forms.py | 104 ++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/mayan/apps/common/forms.py b/mayan/apps/common/forms.py index 2b09759742..4a331e01ab 100644 --- a/mayan/apps/common/forms.py +++ b/mayan/apps/common/forms.py @@ -4,10 +4,13 @@ import os from django import forms from django.conf import settings +from django.core.exceptions import ImproperlyConfigured from django.db import models from django.utils.module_loading import import_string from django.utils.translation import ugettext_lazy as _ +from mayan.apps.acls.models import AccessControlList + from .classes import Package from .models import UserLocaleProfile from .utils import resolve_attribute @@ -111,7 +114,10 @@ class FileDisplayForm(forms.Form): text = forms.CharField( label='', widget=TextAreaDiv( - attrs={'class': 'full-height scrollable', 'data-height-difference': 270} + attrs={ + 'class': 'full-height scrollable', + 'data-height-difference': 270 + } ) ) @@ -125,6 +131,102 @@ class FileDisplayForm(forms.Form): self.fields['text'].initial = file_object.read() +class FilteredSelectionFormOptions(object): + # Dictionary list of option names and default values + option_definitions = ( + {'allow_multiple': False}, + {'field_name': None}, + {'help_text': None}, + {'label': None}, + {'model': None}, + {'permission': None}, + {'queryset': None}, + {'user': None}, + {'widget_class': None}, + {'widget_attributes': {'size': '10'}}, + ) + + def __init__(self, form, kwargs, options=None): + """ + Option definitions will be iterated. The option value will be + determined in the following order: as passed via keyword + arguments during form intialization, as form get_... method or + finally as static Meta options. This is to allow a form with + Meta options or method to be overrided at initialization + and increase the usability of a single class. + """ + for option_definition in self.option_definitions: + name = option_definition.keys()[0] + default_value = option_definition.values()[0] + + try: + # Check for a runtime value via kwargs + value = kwargs.pop(name) + except KeyError: + try: + # Check if there is a get_... method + value = getattr(self, 'get_{}'.format(name))() + except AttributeError: + try: + # Check the meta class options + value = getattr(options, name) + except AttributeError: + value = default_value + + setattr(self, name, value) + + +class FilteredSelectionForm(forms.Form): + """ + Form to select the from a list of choice filtered by access. Can be + configure to allow single or multiple selection. + """ + def __init__(self, *args, **kwargs): + opts = FilteredSelectionFormOptions( + form=self, kwargs=kwargs, options=getattr(self, 'Meta', None) + ) + + if opts.queryset is None: + if not opts.model: + raise ImproperlyConfigured( + '{} requires a queryset or a model to be specified as ' + 'a meta option or passed during initialization.'.format( + self.__class__ + ) + ) + + queryset = opts.model.objects.all() + else: + queryset = opts.queryset + + if not opts.widget_class: + if opts.allow_multiple: + extra_kwargs = {} + field_class = forms.ModelMultipleChoiceField + widget_class = forms.widgets.SelectMultiple + else: + extra_kwargs = {'empty_label': None} + field_class = forms.ModelChoiceField + widget_class = forms.widgets.Select + else: + widget_class = opts.widget_class + + super(FilteredSelectionForm, self).__init__(*args, **kwargs) + + if opts.permission: + queryset = AccessControlList.objects.filter_by_access( + permission=opts.permission, queryset=queryset, + user=opts.user + ) + + self.fields[opts.field_name] = field_class( + help_text=opts.help_text, label=opts.label, + queryset=queryset, required=True, + widget=widget_class(attrs=opts.widget_attributes), + **extra_kwargs + ) + + class LicenseForm(FileDisplayForm): DIRECTORY = () FILENAME = 'LICENSE'