""" Views. """ import datetime import logging import simplejson as json from django.template import RequestContext from django.shortcuts import redirect from django.core.exceptions import ObjectDoesNotExist from django.http import Http404 from django.core.urlresolvers import reverse from django.contrib import messages from django.utils.translation import ugettext, ugettext_lazy as _ from django.contrib.auth.decorators import login_required, permission_required from django.db import models, IntegrityError from django.utils.datastructures import MultiValueDictKeyError from fobi.models import FormEntry, FormElementEntry, FormHandlerEntry from fobi.forms import ( FormEntryForm, FormElementEntryFormSet, ImportFormEntryForm ) from fobi.dynamic import assemble_form_class from fobi.decorators import permissions_required, SATISFY_ALL, SATISFY_ANY from fobi.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 fobi.form_importers import ( form_importer_plugin_registry, get_form_impoter_plugin_urls, ensure_autodiscover as ensure_importers_autodiscover ) from fobi.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 fobi.utils import ( get_user_form_field_plugin_uids, #get_user_form_element_plugins, get_user_form_element_plugins_grouped, #get_user_form_handler_plugins_grouped, get_user_form_handler_plugins, get_user_form_handler_plugin_uids, append_edit_and_delete_links_to_field ) from fobi.helpers import JSONDataExporter from fobi.settings import GET_PARAM_INITIAL_DATA, DEBUG from nine import versions 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 ' __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 e: 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) 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) def create_form_entry(request, theme=None, template_name=None): """ :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 occured 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) 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 elenments) 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 occured 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 occured 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') 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 not form_element_plugin_uid 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') 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') 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') 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 not form_handler_plugin_uid 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') 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') 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 **************************** # ***************************************************************************** def view_form_entry(request, form_entry_slug, theme=None, template_name=None): """ View create 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 occured: {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 ************************ # ***************************************************************************** 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) 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) 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) 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) def form_importer(request, form_importer_plugin_uid, template_name=None, *args, **kwargs): """ :param django.http.HttpRequest request: :param str form_importer_plugin_uid: :param str template_name: """ ensure_importers_autodiscover() form_importer_cls = form_importer_plugin_registry._registry.get( form_importer_plugin_uid ) form_importer = form_importer_cls(form_entry_cls=FormEntry, form_element_entry_cls=FormElementEntry) return form_importer.get_wizard(request, *args, **kwargs)