django-fobi/src/fobi/views/class_based.py

365 lines
12 KiB
Python
Raw Normal View History

2022-07-07 20:49:50 +00:00
import logging
2022-07-06 23:38:37 +00:00
from django.contrib import messages
2022-07-07 23:36:48 +00:00
from django.core.exceptions import PermissionDenied
2022-07-06 23:38:37 +00:00
from django.db import IntegrityError
from django.shortcuts import redirect
from django.urls import reverse_lazy
2022-07-07 20:49:50 +00:00
from django.utils.datastructures import MultiValueDictKeyError
2022-07-06 23:38:37 +00:00
from django.utils.translation import gettext_lazy as _
from django.views import View
2022-07-07 20:49:50 +00:00
from django.views.generic import CreateView, UpdateView
2022-07-06 23:38:37 +00:00
from ..base import get_theme
2022-07-07 20:49:50 +00:00
from ..dynamic import assemble_form_class
from ..forms import (
FormElementEntryFormSet,
FormEntryForm,
FormWizardEntryForm,
FormWizardFormEntryFormSet,
ImportFormEntryForm,
ImportFormWizardEntryForm,
)
from ..models import (
FormElementEntry,
FormEntry,
FormHandlerEntry,
FormWizardEntry,
FormWizardFormEntry,
FormWizardHandlerEntry,
)
2022-07-07 23:40:12 +00:00
from ..permissions.default import (
CreateFormEntryPermission,
EditFormEntryPermission,
)
2022-07-07 20:49:50 +00:00
from ..settings import DEBUG, GET_PARAM_INITIAL_DATA, SORT_PLUGINS_BY_VALUE
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_handler_plugin_uids,
get_user_form_handler_plugins,
get_user_form_wizard_handler_plugin_uids,
get_user_form_wizard_handler_plugins,
get_wizard_files_upload_dir,
perform_form_entry_import,
prepare_form_entry_export_data,
)
2022-07-06 23:38:37 +00:00
2022-07-07 21:38:54 +00:00
__all__ = (
"CreateFormEntryView",
"EditFormEntryView",
)
2022-07-06 23:38:37 +00:00
2022-07-07 20:49:50 +00:00
logger = logging.getLogger(__name__)
2022-07-06 23:38:37 +00:00
2022-07-07 23:36:48 +00:00
class PermissionMixin(View):
"""Mixin for permission-based views."""
permission_classes: tuple = ()
def permission_denied(self, request, message=None, code=None):
"""If request is not permitted, raise."""
raise PermissionDenied()
def get_permissions(self):
"""Return initialized list of permissions required by this view."""
return [permission() for permission in self.permission_classes]
def dispatch(self, request, *args, **kwargs):
"""Dispatch the request."""
self.check_permissions(request)
return super(PermissionMixin, self).dispatch(request, *args, **kwargs)
def check_permissions(self, request):
"""Check if the request should be permitted.
Raises an appropriate exception if the request is not permitted.
"""
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request,
message=getattr(permission, 'message', None),
code=getattr(permission, 'code', None)
)
class CreateFormEntryView(PermissionMixin, CreateView):
2022-07-06 23:38:37 +00:00
"""Create form entry view."""
template_name = None
form_class = FormEntryForm
theme = None
2022-07-07 23:40:12 +00:00
permission_classes = (CreateFormEntryPermission,)
2022-07-06 23:38:37 +00:00
def get_context_data(self, **kwargs):
"""Get context data."""
2022-07-07 23:36:48 +00:00
context = super(CreateFormEntryView, self).get_context_data(**kwargs)
2022-07-06 23:38:37 +00:00
context["form"] = self.get_form()
2022-07-07 22:18:23 +00:00
if not self.theme:
theme = get_theme(request=self.request, as_instance=True)
else:
theme = self.theme
if theme:
context.update({"fobi_theme": theme})
2022-07-06 23:38:37 +00:00
return context
def get_template_names(self):
"""Get template names."""
template_name = self.template_name
if not template_name:
if not self.theme:
theme = get_theme(request=self.request, as_instance=True)
2022-07-07 21:38:54 +00:00
else:
theme = self.theme
2022-07-06 23:38:37 +00:00
template_name = theme.create_form_entry_template
return [template_name]
def get_form_kwargs(self):
2022-07-07 23:36:48 +00:00
kwargs = super(CreateFormEntryView, self).get_form_kwargs()
2022-07-06 23:38:37 +00:00
kwargs["request"] = self.request
return kwargs
def get(self, request, *args, **kwargs):
"""Handle GET requests: instantiate a blank version of the form."""
self.object = None
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
"""
Handle POST requests: instantiate a form instance with the passed
POST variables and then check if it's valid.
"""
self.object = None
form = self.get_form()
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)
),
)
return self.render_to_response(self.get_context_data())
2022-07-07 20:49:50 +00:00
def run_after_form_create(self, form_entry):
2022-07-06 23:38:37 +00:00
"""Post hook."""
2022-07-07 20:49:50 +00:00
2022-07-07 23:36:48 +00:00
class EditFormEntryView(PermissionMixin, UpdateView):
2022-07-07 20:49:50 +00:00
"""Edit form entry."""
template_name = None
form_class = FormEntryForm
theme = None
2022-07-07 21:38:54 +00:00
pk_url_kwarg = "form_entry_id"
2022-07-07 23:40:12 +00:00
permission_classes = (EditFormEntryPermission,)
2022-07-07 20:49:50 +00:00
def get_context_data(self, **kwargs):
"""Get context data."""
2022-07-07 23:36:48 +00:00
context = super(EditFormEntryView, self).get_context_data(**kwargs)
2022-07-07 20:49:50 +00:00
# In case of success, we don't need this (since redirect would happen).
# Thus, fetch only if needed.
form_elements = self.object.formelemententry_set.all()
form_handlers = self.object.formhandlerentry_set.all()[:]
used_form_handler_uids = [
form_handler.plugin_uid for form_handler in form_handlers
]
# The code below (two lines below) is not really used at the moment,
# thus - comment out, but do not remove, as we might need it later on.
# 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(
self.request.user, sort_by_value=SORT_PLUGINS_BY_VALUE
)
# List of form handler plugins allowed to user
user_form_handler_plugins = get_user_form_handler_plugins(
self.request.user,
exclude_used_singles=True,
used_form_handler_plugin_uids=used_form_handler_uids,
)
# Assembling the form for preview
form_cls = assemble_form_class(
self.object,
origin="edit_form_entry",
origin_kwargs_update_func=append_edit_and_delete_links_to_field,
request=self.request,
)
assembled_form = form_cls()
# In debug mode, try to identify possible problems.
if DEBUG:
assembled_form.as_p()
else:
try:
assembled_form.as_p()
except Exception as err:
logger.error(err)
# If no theme provided, pick a default one.
if not self.theme:
2022-07-07 22:18:23 +00:00
theme = get_theme(request=self.request, as_instance=True)
else:
theme = self.theme
2022-07-07 20:49:50 +00:00
2022-07-07 22:18:23 +00:00
if theme:
context.update({"fobi_theme": theme})
2022-07-07 20:49:50 +00:00
2022-07-07 22:18:23 +00:00
theme.collect_plugin_media(form_elements)
2022-07-07 20:49:50 +00:00
context.update(
{
"form": self.get_form(),
"form_entry": self.object,
"form_elements": form_elements,
"form_handlers": form_handlers,
"user_form_element_plugins": user_form_element_plugins,
"user_form_handler_plugins": user_form_handler_plugins,
"assembled_form": assembled_form,
2022-07-07 22:18:23 +00:00
"fobi_theme": theme,
2022-07-07 20:49:50 +00:00
}
)
return context
def get_template_names(self):
"""Get template names."""
template_name = self.template_name
if not template_name:
if not self.theme:
theme = get_theme(request=self.request, as_instance=True)
2022-07-07 21:38:54 +00:00
else:
theme = self.theme
2022-07-07 20:49:50 +00:00
template_name = theme.edit_form_entry_template
return [template_name]
def get_form_kwargs(self):
2022-07-07 23:36:48 +00:00
kwargs = super(EditFormEntryView, self).get_form_kwargs()
2022-07-07 20:49:50 +00:00
kwargs["request"] = self.request
return kwargs
2022-07-07 21:38:54 +00:00
def _get_queryset(self, request):
"""Get queryset."""
return FormEntry._default_manager \
.select_related('user') \
.prefetch_related('formelemententry_set') \
.filter(user__pk=request.user.pk)
2022-07-07 20:49:50 +00:00
def get(self, request, *args, **kwargs):
2022-07-07 21:38:54 +00:00
self.object = self.get_object(queryset=self._get_queryset(request))
2022-07-07 20:49:50 +00:00
"""Handle GET requests: instantiate a blank version of the form."""
form_element_entry_formset = FormElementEntryFormSet(
queryset=self.object.formelemententry_set.all(),
# prefix='form_element'
)
return self.render_to_response(
self.get_context_data(
2022-07-07 22:18:23 +00:00
form_element_entry_formset=form_element_entry_formset,
2022-07-07 20:49:50 +00:00
)
)
def post(self, request, *args, **kwargs):
"""
Handle POST requests: instantiate a form instance with the passed
POST variables and then check if it's valid.
"""
2022-07-07 21:38:54 +00:00
self.object = self.get_object(queryset=self._get_queryset(request))
2022-07-07 20:49:50 +00:00
form = self.get_form()
# This is where we save ordering if it has been changed.
# The `FormElementEntryFormSet` contain ids and positions only.
if "ordering" in request.POST:
form_element_entry_formset = FormElementEntryFormSet(
request.POST,
request.FILES,
queryset=self.object.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_lazy(
"fobi.edit_form_entry",
kwargs={"form_entry_id": self.object.pk},
)
)
except MultiValueDictKeyError as err:
messages.error(
request,
_(
"Errors occurred while trying to change the "
"elements ordering!"
),
)
return redirect(
reverse_lazy(
"fobi.edit_form_entry",
kwargs={"form_entry_id": self.object.pk},
)
)
else:
form_element_entry_formset = FormElementEntryFormSet(
queryset=self.object.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(obj.name),
)
return redirect(
reverse_lazy(
"fobi.edit_form_entry", kwargs={"form_entry_id": obj.pk}
)
)
except IntegrityError as err:
messages.info(
request,
_("Errors occurred while saving the form: {0}.").format(
str(err)
),
)
return self.render_to_response(
self.get_context_data(
2022-07-07 22:18:23 +00:00
form_element_entry_formset=form_element_entry_formset,
2022-07-07 20:49:50 +00:00
)
)