import socket
from six.moves.urllib.parse import urlparse
from django.forms.models import modelformset_factory
from django import forms
from django.utils.translation import ugettext, ugettext_lazy as _
from fobi.models import (
# Plugins
FormElement, FormHandler,
# Entries
FormEntry, FormFieldsetEntry, FormElementEntry, FormHandlerEntry
)
from .base import (
get_registered_form_element_plugins, get_registered_form_handler_plugins,
get_theme
)
from .constants import ACTION_CHOICES
from .exceptions import ImproperlyConfigured
from .validators import url_exists
__title__ = 'fobi.forms'
__author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
__copyright__ = '2014-2016 Artur Barseghyan'
__license__ = 'GPL 2.0/LGPL 2.1'
__all__ = (
'FormEntryForm', 'FormFieldsetEntryForm', 'FormElementEntryFormSet',
'BulkChangeFormElementPluginsForm', 'BulkChangeFormHandlerPluginsForm',
'ImportFormEntryForm', 'FormHandlerForm', 'FormHandlerEntryForm'
)
# *****************************************************************************
# *****************************************************************************
# ******************************* Entry forms *********************************
# *****************************************************************************
# *****************************************************************************
[docs]class FormEntryForm(forms.ModelForm):
"""Form for ``fobi.models.FormEntry`` model."""
[docs] class Meta:
"""Meta class."""
model = FormEntry
fields = ('name', 'is_public', 'success_page_title',
'success_page_message', 'action',) # 'is_cloneable',
def __init__(self, *args, **kwargs):
"""Constructor."""
self.request = kwargs.pop('request', None)
if self.request is None:
raise ImproperlyConfigured(
ugettext("The {0} form requires a "
"request argument.".format(self.__class__.__name__))
)
super(FormEntryForm, self).__init__(*args, **kwargs)
theme = get_theme(request=None, as_instance=True)
self.fields['name'].widget = forms.widgets.TextInput(
attrs={'class': theme.form_element_html_class}
)
self.fields['success_page_title'].widget = forms.widgets.TextInput(
attrs={'class': theme.form_element_html_class}
)
self.fields['success_page_message'].widget = forms.widgets.Textarea(
attrs={'class': theme.form_element_html_class}
)
self.fields['action'].widget = forms.widgets.TextInput(
attrs={'class': theme.form_element_html_class}
)
# At the moment this is done for Foundation 5 theme. Remove this once
# it's possible for a theme to override this form. Alternatively, add
# the attrs to the theme API.
self.fields['is_public'].widget = forms.widgets.CheckboxInput(
attrs={'data-customforms': 'disabled'}
)
# self.fields['is_cloneable'].widget = forms.widgets.CheckboxInput(
# attrs={'data-customforms': 'disabled'}
# )
[docs] def clean_action(self):
"""Validate the action (URL).
Checks if URL exists.
"""
url = self.cleaned_data['action']
if url:
full_url = url
if not (url.startswith('http://') or url.startswith('https://')):
full_url = self.request.build_absolute_uri(url)
parsed_url = urlparse(full_url)
local = False
try:
localhost = socket.gethostbyname('localhost')
except Exception as err:
localhost = '127.0.0.1'
try:
host = socket.gethostbyname(parsed_url.hostname)
local = (localhost == host)
except socket.gaierror as err:
pass
if local:
full_url = parsed_url.path
if not url_exists(full_url, local=local):
raise forms.ValidationError(
ugettext("Invalid action URL {0}.").format(full_url)
)
return url
[docs]class FormFieldsetEntryForm(forms.ModelForm):
"""Form for ``fobi.models.FormFieldsetEntry`` model."""
[docs] class Meta:
"""Meta class."""
model = FormFieldsetEntry
fields = ('name',)
def __init__(self, *args, **kwargs):
"""Constructor."""
super(FormFieldsetEntryForm, self).__init__(*args, **kwargs)
theme = get_theme(request=None, as_instance=True)
self.fields['name'].widget = forms.widgets.TextInput(
attrs={'class': theme.form_element_html_class}
)
class FormElementForm(forms.ModelForm):
"""FormElement form."""
# plugin_uid = forms.ChoiceField(
# choices=get_registered_form_element_plugins()
# )
class Meta:
"""Meta class."""
model = FormElement
fields = ('users', 'groups')
class FormElementEntryForm(forms.ModelForm):
"""FormElementEntry form."""
plugin_uid = forms.ChoiceField(
choices=get_registered_form_element_plugins()
)
class Meta:
"""Meta class."""
model = FormElementEntry
fields = ('form_entry', 'plugin_data', 'plugin_uid', 'position')
FormElementEntryFormSet = modelformset_factory(
FormElementEntry, fields=('position',), extra=0, form=FormElementEntryForm
)
[docs]class FormHandlerEntryForm(forms.ModelForm):
"""FormHandlerEntry form."""
plugin_uid = forms.ChoiceField(
choices=get_registered_form_handler_plugins()
)
[docs] class Meta:
"""Meta class."""
model = FormHandlerEntry
fields = ('form_entry', 'plugin_data', 'plugin_uid')
# *****************************************************************************
# *****************************************************************************
# *********************************** Base ************************************
# *****************************************************************************
# *****************************************************************************
class BaseBulkChangePluginsForm(forms.ModelForm):
"""Bulk change plugins form.
- `selected_plugins` (str): List of comma separated values to be
changed.
- `users_action` (int): For indicating wheither the users shall be appended
to the dashbard plugins or replaced.
- `groups_action` (int): For indicating wheither the groups shall be
appended to the dashboard plugins or replaced.
"""
selected_plugins = forms.CharField(
required=True,
label=_("Selected plugins"),
widget=forms.widgets.HiddenInput
)
users_action = forms.ChoiceField(
required=False,
label=_("Users action"),
choices=ACTION_CHOICES,
help_text=_("If set to ``replace``, the groups are replaced; "
"otherwise - appended.")
)
groups_action = forms.ChoiceField(
required=False,
label=_("Groups action"),
choices=ACTION_CHOICES,
help_text=_("If set to ``replace``, the groups are replaced; "
"otherwise - appended.")
)
class Media:
"""Media class."""
css = {
'all': ('css/admin_custom.css',)
}
def __init__(self, *args, **kwargs):
"""Constructor."""
super(BaseBulkChangePluginsForm, self).__init__(*args, **kwargs)
self.fields['users'].required = False
self.fields['groups'].required = False
# *****************************************************************************
# *****************************************************************************
# **************************** Import form entry ******************************
# *****************************************************************************
# *****************************************************************************
[docs]class ImportFormEntryForm(forms.Form):
"""Import form entry form."""
file = forms.FileField(required=True, label=_("File"))
# ignore_broken_form_element_entries = forms.BooleanField(
# required=False,
# label=_("Ignore broken form element entries"))
# ignore_broken_form_handler_entries = forms.BooleanField(
# required=False,
# label=_("Ignore broken form handler entries"))