"""
Views.
"""
import datetime
import logging
import simplejson as json
from django.db import models, IntegrityError
from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.http import Http404
from django.template import RequestContext
from django.shortcuts import redirect
from django.utils.datastructures import MultiValueDictKeyError
from django.utils.translation import ugettext, ugettext_lazy as _
from nine import versions
from .models import FormEntry, FormElementEntry, FormHandlerEntry
from .forms import (
FormEntryForm, FormElementEntryFormSet, ImportFormEntryForm
)
from .base import (
fire_form_callbacks, run_form_handlers, form_element_plugin_registry,
form_handler_plugin_registry, submit_plugin_form_data, get_theme,
# get_registered_form_handler_plugins
)
from .constants import (
CALLBACK_BEFORE_FORM_VALIDATION,
CALLBACK_FORM_VALID_BEFORE_SUBMIT_PLUGIN_FORM_DATA,
CALLBACK_FORM_VALID, CALLBACK_FORM_VALID_AFTER_FORM_HANDLERS,
CALLBACK_FORM_INVALID
)
from .decorators import permissions_required, SATISFY_ALL, SATISFY_ANY
from .dynamic import assemble_form_class
from .form_importers import (
ensure_autodiscover as ensure_importers_autodiscover,
form_importer_plugin_registry, get_form_impoter_plugin_urls
)
from .helpers import JSONDataExporter
from .utils import (
append_edit_and_delete_links_to_field,
get_user_form_element_plugins_grouped,
get_user_form_field_plugin_uids,
# get_user_form_element_plugins,
# get_user_form_handler_plugins_grouped,
get_user_form_handler_plugins,
get_user_form_handler_plugin_uids
)
from .settings import GET_PARAM_INITIAL_DATA, DEBUG
if versions.DJANGO_GTE_1_10:
from django.shortcuts import render
else:
from django.shortcuts import render_to_response
__title__ = 'fobi.views'
__author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
__copyright__ = '2014-2016 Artur Barseghyan'
__license__ = 'GPL 2.0/LGPL 2.1'
__all__ = (
'create_form_entry', 'edit_form_entry', 'delete_form_entry',
'add_form_element_entry', 'edit_form_element_entry',
'delete_form_element_entry', 'add_form_handler_entry',
'edit_form_handler_entry', 'delete_form_handler_entry',
'dashboard', 'view_form_entry', 'form_entry_submitted',
'export_form_entry', 'import_form_entry', 'form_importer',
)
logger = logging.getLogger(__name__)
# *****************************************************************************
# *****************************************************************************
# *********************************** Generic *********************************
# *****************************************************************************
# *****************************************************************************
def _delete_plugin_entry(request,
entry_id,
EntryModel,
get_user_plugin_uids_func,
message,
html_anchor):
"""Abstract delete element entry.
:param django.http.HttpRequest request:
:param int entry_id:
:param fobi.models.AbstractPluginEntry EntryModel: Subclass of
``fobi.models.AbstractPluginEntry``.
:param callable get_user_plugin_uids_func:
:param str message:
:return django.http.HttpResponse:
"""
try:
obj = EntryModel._default_manager \
.select_related('form_entry') \
.get(pk=entry_id, form_entry__user__pk=request.user.pk)
except ObjectDoesNotExist as err:
raise Http404(_("{0} not found."
"").format(EntryModel._meta.verbose_name))
form_entry = obj.form_entry
plugin = obj.get_plugin(request=request)
plugin.request = request
plugin._delete_plugin_data()
obj.delete()
messages.info(request, message.format(plugin.name))
redirect_url = reverse(
'fobi.edit_form_entry', kwargs={'form_entry_id': form_entry.pk}
)
return redirect("{0}{1}".format(redirect_url, html_anchor))
# *****************************************************************************
# *****************************************************************************
# ********************************* Dashboard *********************************
# *****************************************************************************
# *****************************************************************************
dashboard_permissions = [
'fobi.add_formentry',
'fobi.change_formentry',
'fobi.delete_formentry',
]
@login_required
@permissions_required(satisfy=SATISFY_ANY, perms=dashboard_permissions)
[docs]def dashboard(request, theme=None, template_name=None):
"""Dashboard.
:param django.http.HttpRequest request:
:param fobi.base.BaseTheme theme: Theme instance.
:param string template_name:
:return django.http.HttpResponse:
"""
form_entries = FormEntry._default_manager \
.filter(user__pk=request.user.pk) \
.select_related('user')
context = {
'form_entries': form_entries,
'form_importers': get_form_impoter_plugin_urls(),
}
# If given, pass to the template (and override the value set by
# the context processor.
if theme:
context.update({'fobi_theme': theme})
if not template_name:
theme = get_theme(request=request, as_instance=True)
template_name = theme.dashboard_template
if versions.DJANGO_GTE_1_10:
return render(request, template_name, context)
else:
return render_to_response(
template_name, context, context_instance=RequestContext(request)
)
# *****************************************************************************
# *****************************************************************************
# ********************************** Builder **********************************
# *****************************************************************************
# *****************************************************************************
# *****************************************************************************
# **************************** Create form entry ******************************
# *****************************************************************************
create_form_entry_permissions = [
'fobi.add_formentry',
'fobi.add_formelemententry',
'fobi.add_formhandlerentry',
]
@login_required
@permissions_required(satisfy=SATISFY_ALL, perms=create_form_entry_permissions)
[docs]def create_form_entry(request, theme=None, template_name=None):
"""Create form entry.
:param django.http.HttpRequest request:
:param fobi.base.BaseTheme theme: Theme instance.
:param str template_name:
:return django.http.HttpResponse:
"""
if 'POST' == request.method:
form = FormEntryForm(request.POST, request.FILES, request=request)
if form.is_valid():
form_entry = form.save(commit=False)
form_entry.user = request.user
try:
form_entry.save()
messages.info(
request,
_('Form {0} was created '
'successfully.').format(form_entry.name)
)
return redirect(
'fobi.edit_form_entry', form_entry_id=form_entry.pk
)
except IntegrityError as err:
messages.info(
request,
_('Errors occurred while saving '
'the form: {0}.').format(str(err))
)
else:
form = FormEntryForm(request=request)
context = {'form': form}
# If given, pass to the template (and override the value set by
# the context processor.
if theme:
context.update({'fobi_theme': theme})
if not template_name:
if not theme:
theme = get_theme(request=request, as_instance=True)
template_name = theme.create_form_entry_template
if versions.DJANGO_GTE_1_10:
return render(request, template_name, context)
else:
return render_to_response(
template_name, context, context_instance=RequestContext(request)
)
# **************************************************************************
# ******************************* Edit form entry **************************
# **************************************************************************
edit_form_entry_permissions = [
'fobi.change_formentry', 'fobi.change_formelemententry',
'fobi.change_formhandlerentry',
'fobi.add_formelemententry', 'fobi.add_formhandlerentry',
'fobi.delete_formelemententry', 'fobi.delete_formhandlerentry',
]
@login_required
@permissions_required(satisfy=SATISFY_ANY, perms=edit_form_entry_permissions)
[docs]def edit_form_entry(request, form_entry_id, theme=None, template_name=None):
"""Edit form entry.
:param django.http.HttpRequest request:
:param int form_entry_id:
:param fobi.base.BaseTheme theme: Theme instance.
:param str template_name:
:return django.http.HttpResponse:
"""
try:
form_entry = FormEntry._default_manager \
.select_related('user') \
.prefetch_related('formelemententry_set') \
.get(pk=form_entry_id, user__pk=request.user.pk)
# .prefetch_related('formhandlerentry_set') \
except ObjectDoesNotExist as err:
raise Http404(ugettext("Form entry not found."))
if 'POST' == request.method:
# The form entry form (does not contain form elements)
form = FormEntryForm(request.POST, request.FILES, instance=form_entry,
request=request)
if 'ordering' in request.POST:
form_element_entry_formset = FormElementEntryFormSet(
request.POST,
request.FILES,
queryset=form_entry.formelemententry_set.all(),
# prefix = 'form_element'
)
# If form elements aren't properly made (developers's fault)
# there might be problems with saving the ordering - likely
# in case of hidden elements only. Thus, we want to avoid
# errors here.
try:
if form_element_entry_formset.is_valid():
form_element_entry_formset.save()
messages.info(
request,
_("Elements ordering edited successfully.")
)
return redirect(
reverse('fobi.edit_form_entry',
kwargs={'form_entry_id': form_entry_id})
)
except MultiValueDictKeyError as err:
messages.error(
request,
_("Errors occurred while trying to change the "
"elements ordering!")
)
return redirect(
reverse('fobi.edit_form_entry',
kwargs={'form_entry_id': form_entry_id})
)
else:
form_element_entry_formset = FormElementEntryFormSet(
queryset=form_entry.formelemententry_set.all(),
# prefix='form_element'
)
if form.is_valid():
obj = form.save(commit=False)
obj.user = request.user
try:
obj.save()
messages.info(
request,
_('Form {0} was edited '
'successfully.').format(form_entry.name)
)
return redirect(
reverse('fobi.edit_form_entry',
kwargs={'form_entry_id': form_entry_id})
)
except IntegrityError as err:
messages.info(
request,
_('Errors occurred while saving '
'the form: {0}.').format(str(err))
)
else:
# The form entry form (does not contain form elenments)
form = FormEntryForm(instance=form_entry, request=request)
form_element_entry_formset = FormElementEntryFormSet(
queryset=form_entry.formelemententry_set.all(),
# prefix='form_element'
)
# In case of success, we don't need this (since redirect would happen).
# Thus, fetch only if needed.
form_elements = form_entry.formelemententry_set.all()
form_handlers = form_entry.formhandlerentry_set.all()[:]
used_form_handler_uids = [form_handler.plugin_uid
for form_handler
in form_handlers]
all_form_entries = FormEntry._default_manager.only('id', 'name', 'slug') \
.filter(user__pk=request.user.pk)
# List of form element plugins allowed to user
user_form_element_plugins = get_user_form_element_plugins_grouped(
request.user
)
# List of form handler plugins allowed to user
user_form_handler_plugins = get_user_form_handler_plugins(
request.user,
exclude_used_singles=True,
used_form_handler_plugin_uids=used_form_handler_uids
)
# Assembling the form for preview
FormClass = assemble_form_class(
form_entry,
origin='edit_form_entry',
origin_kwargs_update_func=append_edit_and_delete_links_to_field,
request=request
)
assembled_form = FormClass()
# In debug mode, try to identify possible problems.
if DEBUG:
try:
assembled_form.as_p()
except Exception as err:
logger.error(err)
# If no theme provided, pick a default one.
if not theme:
theme = get_theme(request=request, as_instance=True)
theme.collect_plugin_media(form_elements)
context = {
'form': form,
'form_entry': form_entry,
'form_elements': form_elements,
'form_handlers': form_handlers,
'all_form_entries': all_form_entries,
'user_form_element_plugins': user_form_element_plugins,
'user_form_handler_plugins': user_form_handler_plugins,
'assembled_form': assembled_form,
'form_element_entry_formset': form_element_entry_formset,
'fobi_theme': theme,
}
if not template_name:
template_name = theme.edit_form_entry_template
if versions.DJANGO_GTE_1_10:
return render(request, template_name, context)
else:
return render_to_response(
template_name, context, context_instance=RequestContext(request)
)
# *****************************************************************************
# **************************** Add form element entry *************************
# *****************************************************************************
@login_required
@permission_required('fobi.add_formelemententry')
[docs]def add_form_element_entry(request,
form_entry_id,
form_element_plugin_uid,
theme=None,
template_name=None):
"""Add form element entry.
:param django.http.HttpRequest request:
:param int form_entry_id:
:param int form_element_plugin_uid:
:param fobi.base.BaseTheme theme: Theme instance.
:param string template_name:
:return django.http.HttpResponse:
"""
try:
form_entry = FormEntry._default_manager \
.prefetch_related('formelemententry_set') \
.get(pk=form_entry_id)
except ObjectDoesNotExist as err:
raise Http404(ugettext("Form entry not found."))
form_elements = form_entry.formelemententry_set.all()
user_form_element_plugin_uids = get_user_form_field_plugin_uids(
request.user
)
if form_element_plugin_uid not in user_form_element_plugin_uids:
raise Http404(ugettext("Plugin does not exist or you are not allowed "
"to use this plugin!"))
FormElementPlugin = form_element_plugin_registry.get(
form_element_plugin_uid
)
form_element_plugin = FormElementPlugin(user=request.user)
form_element_plugin.request = request
FormElementPluginForm = form_element_plugin.get_form()
form = None
obj = FormElementEntry()
obj.form_entry = form_entry
obj.plugin_uid = form_element_plugin_uid
obj.user = request.user
save_object = False
# If plugin doesn't have a form
if not FormElementPluginForm:
save_object = True
# If POST
elif 'POST' == request.method:
# If element has a form
form = form_element_plugin.get_initialised_create_form_or_404(
data=request.POST,
files=request.FILES
)
form.validate_plugin_data(form_elements, request=request)
if form.is_valid():
# Saving the plugin form data.
form.save_plugin_data(request=request)
# Getting the plugin data.
obj.plugin_data = form.get_plugin_data(request=request)
save_object = True
# If not POST
else:
form = form_element_plugin.get_initialised_create_form_or_404()
if save_object:
# Handling the position
position = 1
records = FormElementEntry.objects.filter(form_entry=form_entry) \
.aggregate(models.Max('position'))
if records:
try:
position = records['{0}__max'.format('position')] + 1
except TypeError as err:
pass
obj.position = position
# Save the object.
obj.save()
messages.info(
request,
_('The form element plugin "{0}" was added '
'successfully.').format(form_element_plugin.name)
)
return redirect(
"{0}?active_tab=tab-form-elemenets".format(
reverse('fobi.edit_form_entry',
kwargs={'form_entry_id': form_entry_id})
)
)
context = {
'form': form,
'form_entry': form_entry,
'form_element_plugin': form_element_plugin,
}
# If given, pass to the template (and override the value set by
# the context processor.
if theme:
context.update({'fobi_theme': theme})
if not template_name:
if not theme:
theme = get_theme(request=request, as_instance=True)
template_name = theme.add_form_element_entry_template
if versions.DJANGO_GTE_1_10:
return render(request, template_name, context)
else:
return render_to_response(
template_name, context, context_instance=RequestContext(request)
)
# *****************************************************************************
# **************************** Edit form element entry ************************
# *****************************************************************************
@login_required
@permission_required('fobi.change_formelemententry')
[docs]def edit_form_element_entry(request,
form_element_entry_id,
theme=None,
template_name=None):
"""Edit form element entry.
:param django.http.HttpRequest request:
:param int form_element_entry_id:
:param fobi.base.BaseTheme: Theme instance.
:param string template_name:
:return django.http.HttpResponse:
"""
try:
obj = FormElementEntry._default_manager \
.select_related('form_entry',
'form_entry__user') \
.get(pk=form_element_entry_id,
form_entry__user__pk=request.user.pk)
except ObjectDoesNotExist as err:
raise Http404(ugettext("Form element entry not found."))
form_entry = obj.form_entry
form_element_plugin = obj.get_plugin(request=request)
form_element_plugin.request = request
FormElementPluginForm = form_element_plugin.get_form()
form = None
if not FormElementPluginForm:
messages.info(
request,
_('The form element plugin "{0}" '
'is not configurable!').format(form_element_plugin.name)
)
return redirect('fobi.edit_form_entry', form_entry_id=form_entry.pk)
elif 'POST' == request.method:
form = form_element_plugin.get_initialised_edit_form_or_404(
data=request.POST,
files=request.FILES
)
form_elements = FormElementEntry._default_manager \
.select_related('form_entry',
'form_entry__user') \
.exclude(pk=form_element_entry_id) \
.filter(form_entry=form_entry)
form.validate_plugin_data(form_elements, request=request)
if form.is_valid():
# Saving the plugin form data.
form.save_plugin_data(request=request)
# Getting the plugin data.
obj.plugin_data = form.get_plugin_data(request=request)
# Save the object.
obj.save()
messages.info(
request,
_('The form element plugin "{0}" was edited '
'successfully.').format(form_element_plugin.name)
)
return redirect('fobi.edit_form_entry',
form_entry_id=form_entry.pk)
else:
form = form_element_plugin.get_initialised_edit_form_or_404()
form_element_plugin = obj.get_plugin(request=request)
form_element_plugin.request = request
context = {
'form': form,
'form_entry': form_entry,
'form_element_plugin': form_element_plugin,
}
# If given, pass to the template (and override the value set by
# the context processor.
if theme:
context.update({'fobi_theme': theme})
if not template_name:
if not theme:
theme = get_theme(request=request, as_instance=True)
template_name = theme.edit_form_element_entry_template
if versions.DJANGO_GTE_1_10:
return render(request, template_name, context)
else:
return render_to_response(
template_name, context, context_instance=RequestContext(request)
)
# *****************************************************************************
# **************************** Delete form element entry **********************
# *****************************************************************************
@login_required
@permission_required('fobi.delete_formelemententry')
[docs]def delete_form_element_entry(request, form_element_entry_id):
"""Delete form element entry.
:param django.http.HttpRequest request:
:param int form_element_entry_id:
:return django.http.HttpResponse:
"""
return _delete_plugin_entry(
request=request,
entry_id=form_element_entry_id,
EntryModel=FormElementEntry,
get_user_plugin_uids_func=get_user_form_field_plugin_uids,
message=_('The form element plugin "{0}" was deleted successfully.'),
html_anchor='?active_tab=tab-form-elemenets'
)
# *****************************************************************************
# **************************** Add form handler entry *************************
# *****************************************************************************
@login_required
@permission_required('fobi.add_formhandlerentry')
[docs]def add_form_handler_entry(request,
form_entry_id,
form_handler_plugin_uid,
theme=None,
template_name=None):
"""Add form handler entry.
:param django.http.HttpRequest request:
:param int form_entry_id:
:param int form_handler_plugin_uid:
:param fobi.base.BaseTheme theme: Theme instance.
:param string template_name:
:return django.http.HttpResponse:
"""
try:
form_entry = FormEntry._default_manager.get(pk=form_entry_id)
except ObjectDoesNotExist as err:
raise Http404(ugettext("Form entry not found."))
user_form_handler_plugin_uids = get_user_form_handler_plugin_uids(
request.user
)
if form_handler_plugin_uid not in user_form_handler_plugin_uids:
raise Http404(ugettext("Plugin does not exist or you are not allowed "
"to use this plugin!"))
FormHandlerPlugin = form_handler_plugin_registry.get(
form_handler_plugin_uid
)
# Check if we deal with form handler plugin that is only allowed to be
# used once. In that case, check if it has been used already in the current
# form entry.
if not FormHandlerPlugin.allow_multiple:
times_used = FormHandlerEntry._default_manager \
.filter(form_entry__id=form_entry_id,
plugin_uid=FormHandlerPlugin.uid) \
.count()
if times_used > 0:
raise Http404(ugettext("The {0} plugin can be used only once in a "
"form.").format(FormHandlerPlugin.name))
form_handler_plugin = FormHandlerPlugin(user=request.user)
form_handler_plugin.request = request
FormHandlerPluginForm = form_handler_plugin.get_form()
form = None
obj = FormHandlerEntry()
obj.form_entry = form_entry
obj.plugin_uid = form_handler_plugin_uid
obj.user = request.user
save_object = False
if not FormHandlerPluginForm:
save_object = True
elif 'POST' == request.method:
form = form_handler_plugin.get_initialised_create_form_or_404(
data=request.POST,
files=request.FILES
)
if form.is_valid():
# Saving the plugin form data.
form.save_plugin_data(request=request)
# Getting the plugin data.
obj.plugin_data = form.get_plugin_data(request=request)
save_object = True
else:
form = form_handler_plugin.get_initialised_create_form_or_404()
if save_object:
# Save the object.
obj.save()
messages.info(
request,
_('The form handler plugin "{0}" was added '
'successfully.').format(form_handler_plugin.name)
)
return redirect(
"{0}?active_tab=tab-form-handlers".format(
reverse(
'fobi.edit_form_entry',
kwargs={'form_entry_id': form_entry_id}
)
)
)
context = {
'form': form,
'form_entry': form_entry,
'form_handler_plugin': form_handler_plugin,
}
# If given, pass to the template (and override the value set by
# the context processor.
if theme:
context.update({'fobi_theme': theme})
if not template_name:
if not theme:
theme = get_theme(request=request, as_instance=True)
template_name = theme.add_form_handler_entry_template
if versions.DJANGO_GTE_1_10:
return render(request, template_name, context)
else:
return render_to_response(
template_name, context, context_instance=RequestContext(request)
)
# *****************************************************************************
# **************************** Edit form handler entry ************************
# *****************************************************************************
@login_required
@permission_required('fobi.change_formhandlerentry')
[docs]def edit_form_handler_entry(request,
form_handler_entry_id,
theme=None,
template_name=None):
"""Edit form handler entry.
:param django.http.HttpRequest request:
:param int form_handler_entry_id:
:param fobi.base.BaseTheme theme: Theme instance.
:param string template_name:
:return django.http.HttpResponse:
"""
try:
obj = FormHandlerEntry._default_manager \
.select_related('form_entry') \
.get(pk=form_handler_entry_id)
except ObjectDoesNotExist as err:
raise Http404(ugettext("Form handler entry not found."))
form_entry = obj.form_entry
form_handler_plugin = obj.get_plugin(request=request)
form_handler_plugin.request = request
FormHandlerPluginForm = form_handler_plugin.get_form()
form = None
if not FormHandlerPluginForm:
messages.info(
request,
_('The form handler plugin "{0}" is not '
'configurable!').format(form_handler_plugin.name)
)
return redirect('fobi.edit_form_entry', form_entry_id=form_entry.pk)
elif 'POST' == request.method:
form = form_handler_plugin.get_initialised_edit_form_or_404(
data=request.POST,
files=request.FILES
)
if form.is_valid():
# Saving the plugin form data.
form.save_plugin_data(request=request)
# Getting the plugin data.
obj.plugin_data = form.get_plugin_data(request=request)
# Save the object.
obj.save()
messages.info(
request,
_('The form handler plugin "{0}" was edited '
'successfully.').format(form_handler_plugin.name)
)
return redirect('fobi.edit_form_entry',
form_entry_id=form_entry.pk)
else:
form = form_handler_plugin.get_initialised_edit_form_or_404()
context = {
'form': form,
'form_entry': form_entry,
'form_handler_plugin': form_handler_plugin,
}
# If given, pass to the template (and override the value set by
# the context processor.
if theme:
context.update({'fobi_theme': theme})
if not template_name:
if not theme:
theme = get_theme(request=request, as_instance=True)
template_name = theme.edit_form_handler_entry_template
if versions.DJANGO_GTE_1_10:
return render(request, template_name, context)
else:
return render_to_response(
template_name, context, context_instance=RequestContext(request)
)
# *****************************************************************************
# **************************** Delete form handler entry **********************
# *****************************************************************************
@login_required
@permission_required('fobi.delete_formhandlerentry')
[docs]def delete_form_handler_entry(request, form_handler_entry_id):
"""Delete form handler entry.
:param django.http.HttpRequest request:
:param int form_handler_entry_id:
:return django.http.HttpResponse:
"""
return _delete_plugin_entry(
request=request,
entry_id=form_handler_entry_id,
EntryModel=FormHandlerEntry,
get_user_plugin_uids_func=get_user_form_handler_plugin_uids,
message=_('The form handler plugin "{0}" was deleted successfully.'),
html_anchor='?active_tab=tab-form-handlers'
)
# *****************************************************************************
# *****************************************************************************
# ******************************** View form entry ****************************
# *****************************************************************************
# *****************************************************************************
# *****************************************************************************
# ******************************** View form entry ****************************
# *****************************************************************************
[docs]def view_form_entry(request, form_entry_slug, theme=None, template_name=None):
"""View created form.
:param django.http.HttpRequest request:
:param string form_entry_slug:
:param fobi.base.BaseTheme theme: Theme instance.
:param string template_name:
:return django.http.HttpResponse:
"""
try:
kwargs = {'slug': form_entry_slug}
if not request.user.is_authenticated():
kwargs.update({'is_public': True})
form_entry = FormEntry._default_manager.select_related('user') \
.get(**kwargs)
except ObjectDoesNotExist as err:
raise Http404(ugettext("Form entry not found."))
form_element_entries = form_entry.formelemententry_set.all()[:]
# This is where the most of the magic happens. Our form is being built
# dynamically.
FormClass = assemble_form_class(
form_entry,
form_element_entries=form_element_entries,
request=request
)
if 'POST' == request.method:
form = FormClass(request.POST, request.FILES)
# Fire pre form validation callbacks
fire_form_callbacks(form_entry=form_entry, request=request, form=form,
stage=CALLBACK_BEFORE_FORM_VALIDATION)
if form.is_valid():
# Fire form valid callbacks, before handling submitted plugin
# form data.
form = fire_form_callbacks(
form_entry=form_entry,
request=request,
form=form,
stage=CALLBACK_FORM_VALID_BEFORE_SUBMIT_PLUGIN_FORM_DATA
)
# Fire plugin processors
form = submit_plugin_form_data(form_entry=form_entry,
request=request, form=form)
# Fire form valid callbacks
form = fire_form_callbacks(form_entry=form_entry,
request=request, form=form,
stage=CALLBACK_FORM_VALID)
# Run all handlers
handler_responses, handler_errors = run_form_handlers(
form_entry=form_entry,
request=request,
form=form,
form_element_entries=form_element_entries
)
# Warning that not everything went ok.
if handler_errors:
for handler_error in handler_errors:
messages.warning(
request,
_("Error occurred: {0}."
"").format(handler_error)
)
# Fire post handler callbacks
fire_form_callbacks(
form_entry=form_entry,
request=request,
form=form,
stage=CALLBACK_FORM_VALID_AFTER_FORM_HANDLERS
)
messages.info(
request,
_("Form {0} was submitted successfully."
"").format(form_entry.name)
)
return redirect(
reverse('fobi.form_entry_submitted', args=[form_entry.slug])
)
else:
# Fire post form validation callbacks
fire_form_callbacks(form_entry=form_entry, request=request,
form=form, stage=CALLBACK_FORM_INVALID)
else:
# Providing initial form data by feeding entire GET dictionary
# to the form, if ``GET_PARAM_INITIAL_DATA`` is present in the
# GET.
kwargs = {}
if GET_PARAM_INITIAL_DATA in request.GET:
kwargs = {'initial': request.GET}
form = FormClass(**kwargs)
# In debug mode, try to identify possible problems.
if DEBUG:
try:
form.as_p()
except Exception as err:
logger.error(err)
theme = get_theme(request=request, as_instance=True)
theme.collect_plugin_media(form_element_entries)
context = {
'form': form,
'form_entry': form_entry,
'fobi_theme': theme,
}
if not template_name:
template_name = theme.view_form_entry_template
if versions.DJANGO_GTE_1_10:
return render(request, template_name, context)
else:
return render_to_response(
template_name, context, context_instance=RequestContext(request)
)
# *****************************************************************************
# **************************** View form entry success ************************
# *****************************************************************************
[docs]def form_entry_submitted(request, form_entry_slug=None, template_name=None):
"""Form entry submitted.
:param django.http.HttpRequest request:
:param string form_entry_slug:
:param string template_name:
:return django.http.HttpResponse:
"""
try:
kwargs = {'slug': form_entry_slug}
if not request.user.is_authenticated():
kwargs.update({'is_public': True})
form_entry = FormEntry._default_manager \
.select_related('user') \
.get(**kwargs)
except ObjectDoesNotExist as err:
raise Http404(ugettext("Form entry not found."))
# try:
# form_entry = FormEntry._default_manager.get(slug=form_entry_slug,
# user__pk=request.user.pk)
# except ObjectDoesNotExist as err:
# raise Http404(ugettext("Form entry not found."))
context = {
'form_entry_slug': form_entry_slug,
'form_entry': form_entry
}
if not template_name:
theme = get_theme(request=request, as_instance=True)
template_name = theme.form_entry_submitted_template
if versions.DJANGO_GTE_1_10:
return render(request, template_name, context)
else:
return render_to_response(
template_name, context, context_instance=RequestContext(request)
)
# *****************************************************************************
# *****************************************************************************
# ********************************* Delete form entry *************************
# *****************************************************************************
# *****************************************************************************
delete_form_entry_permissions = [
'fobi.delete_formentry', 'fobi.delete_formelemententry',
'fobi.delete_formhandlerentry',
]
@login_required
@permissions_required(satisfy=SATISFY_ALL, perms=delete_form_entry_permissions)
[docs]def delete_form_entry(request, form_entry_id, template_name=None):
"""Delete form entry.
:param django.http.HttpRequest request:
:param int form_entry_id:
:param string template_name:
:return django.http.HttpResponse:
"""
try:
obj = FormEntry._default_manager \
.get(pk=form_entry_id, user__pk=request.user.pk)
except ObjectDoesNotExist as err:
raise Http404(ugettext("Form entry not found."))
obj.delete()
messages.info(
request,
_('The form "{0}" was deleted successfully.').format(obj.name)
)
return redirect('fobi.dashboard')
# *****************************************************************************
# *****************************************************************************
# **************************** Export form entry ******************************
# *****************************************************************************
# *****************************************************************************
@login_required
@permissions_required(satisfy=SATISFY_ALL, perms=create_form_entry_permissions)
[docs]def export_form_entry(request, form_entry_id, template_name=None):
"""Export form entry to JSON.
:param django.http.HttpRequest request:
:param int form_entry_id:
:param string template_name:
:return django.http.HttpResponse:
"""
try:
form_entry = FormEntry._default_manager \
.get(pk=form_entry_id, user__pk=request.user.pk)
except ObjectDoesNotExist as err:
raise Http404(ugettext("Form entry not found."))
data = {
'name': form_entry.name,
'slug': form_entry.slug,
'is_public': False,
'is_cloneable': False,
'position': form_entry.position,
'success_page_title': form_entry.success_page_title,
'success_page_message': form_entry.success_page_message,
'action': form_entry.action,
'form_elements': [],
'form_handlers': [],
}
form_element_entries = form_entry.formelemententry_set.all()[:]
form_handler_entries = form_entry.formhandlerentry_set.all()[:]
for form_element_entry in form_element_entries:
data['form_elements'].append(
{
'plugin_uid': form_element_entry.plugin_uid,
'position': form_element_entry.position,
'plugin_data': form_element_entry.plugin_data,
}
)
for form_handler_entry in form_handler_entries:
data['form_handlers'].append(
{
'plugin_uid': form_handler_entry.plugin_uid,
'plugin_data': form_handler_entry.plugin_data,
}
)
data_exporter = JSONDataExporter(json.dumps(data), form_entry.slug)
return data_exporter.export()
# *****************************************************************************
# *****************************************************************************
# **************************** Import form entry ******************************
# *****************************************************************************
# *****************************************************************************
@login_required
@permissions_required(satisfy=SATISFY_ALL, perms=create_form_entry_permissions)
[docs]def import_form_entry(request, template_name=None):
"""Import form entry.
:param django.http.HttpRequest request:
:param string template_name:
:return django.http.HttpResponse:
"""
if 'POST' == request.method:
form = ImportFormEntryForm(request.POST, request.FILES)
if form.is_valid():
# Reading the contents of the file into JSON
json_file = form.cleaned_data['file']
file_contents = json_file.read()
# This is the form data which we are going to use when recreating
# the form.
form_data = json.loads(file_contents)
# Since we just feed all the data to the `FormEntry` class,
# we need to make sure it doesn't have strange fields in.
# Furthermore, we will use the `form_element_data` and
# `form_handler_data` for filling the missing plugin data.
form_elements_data = form_data.pop('form_elements', [])
form_handlers_data = form_data.pop('form_handlers', [])
# User information we always recreate!
form_data['user'] = request.user
form_entry = FormEntry(**form_data)
form_entry.name += ugettext(" (imported on {0})").format(
datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
form_entry.save()
# One by one, importing form element plugins.
for form_element_data in form_elements_data:
if form_element_plugin_registry._registry.get(
form_element_data.get('plugin_uid', None), None):
form_element = FormElementEntry(**form_element_data)
form_element.form_entry = form_entry
form_element.save()
else:
if form_element_data.get('plugin_uid', None):
messages.warning(
request,
_('Plugin {0} is missing in the system.'
'').format(form_element_data.get('plugin_uid'))
)
else:
messages.warning(
request,
_('Some essential plugin data missing in the JSON '
'import.')
)
# One by one, importing form handler plugins.
for form_handler_data in form_handlers_data:
if form_handler_plugin_registry._registry.get(
form_handler_data.get('plugin_uid', None), None):
form_handler = FormHandlerEntry(**form_handler_data)
form_handler.form_entry = form_entry
form_handler.save()
else:
if form_handler.get('plugin_uid', None):
messages.warning(
request,
_('Plugin {0} is missing in the system.'
'').format(form_handler.get('plugin_uid'))
)
else:
messages.warning(
request,
_('Some essential data missing in the JSON '
'import.')
)
messages.info(
request,
_('The form was imported successfully.')
)
return redirect(
'fobi.edit_form_entry', form_entry_id=form_entry.pk
)
else:
form = ImportFormEntryForm()
# When importing entries from saved JSON we shouldn't just save
# them into database and consider it done, since there might be cases
# if a certain plugin doesn't exist in the system, which will lead
# to broken form entries. Instead, we should check every single
# form-element or form-handler plugin for existence. If not doesn't exist
# in the system, we might: (1) roll entire transaction back or (2) ignore
# broken entries. The `ImportFormEntryForm` form has two fields to
# additional fields which serve the purpose:
# `ignore_broken_form_element_entries` and
# `ignore_broken_form_handler_entries`. When set to True, when a broken
# form element/handler plugin has been discovered, the import would
# continue, having the broken form element/handler entries not imported.
context = {
'form': form,
# 'form_entry': form_entry
}
if not template_name:
theme = get_theme(request=request, as_instance=True)
template_name = theme.import_form_entry_template
if versions.DJANGO_GTE_1_10:
return render(request, template_name, context)
else:
return render_to_response(
template_name, context, context_instance=RequestContext(request)
)
# *****************************************************************************
# *****************************************************************************
# ****************************** Form importers *******************************
# *****************************************************************************
# *****************************************************************************
@login_required
@permissions_required(satisfy=SATISFY_ALL, perms=create_form_entry_permissions)