mirror of
https://github.com/Hopiu/django-fobi.git
synced 2026-05-20 02:11:52 +00:00
prepare 0.2.1; do not wrap media files in <a/> tags when saving data of db_store plugin; make sure custom form handler actions are properly listed in the simple theme as well; make it possible to fail silently on missing form element- and form handler- plugins;
This commit is contained in:
parent
309fc06b68
commit
d5d505b962
20 changed files with 279 additions and 95 deletions
|
|
@ -1,5 +1,19 @@
|
|||
Release history and notes
|
||||
=====================================
|
||||
0.2.1
|
||||
-------------------------------------
|
||||
2014-11-06
|
||||
|
||||
- Minor improvements of the `db_store` plugin.
|
||||
- Minor improvements of the `simple` theme. Make sure that custom
|
||||
form handler actions are properly shown in the form handlers list.
|
||||
- Make it possible to fail silently on missing form element or form
|
||||
handler plugins by setting the respected values to False:
|
||||
|
||||
* `FAIL_ON_MISSING_FORM_ELEMENT_PLUGINS`,
|
||||
* `FAIL_ON_MISSING_FORM_HANDLER_PLUGINS`. Raising an appropriate exception
|
||||
otherwise.
|
||||
|
||||
0.2
|
||||
-------------------------------------
|
||||
2014-11-05
|
||||
|
|
@ -12,8 +26,8 @@ Note, that this release contains minor backwards incompatible changes.
|
|||
you have written your own or have changed existing form handler plugins
|
||||
with use of one of the above mentioned methods, append those arguments to
|
||||
the method declarations when upgrading to this version. If you haven't
|
||||
written your own form or changed existing form handler plugins, you may
|
||||
just upgrade to this version.
|
||||
written your own or changed existing form handler plugins, you may just
|
||||
upgrade to this version.
|
||||
- Added data export features to the ``db_store`` plugin.
|
||||
- Minor fixes in ``db_store`` plugin.
|
||||
- Added missing documentation for the ``feincms_integration`` app.
|
||||
|
|
|
|||
22
README.rst
22
README.rst
|
|
@ -1244,6 +1244,28 @@ somehow doesn't appear in the list of available plugins, do run the
|
|||
plugins into the database, but also is a great way of checking for possible
|
||||
errors.
|
||||
|
||||
If you have forms refering to form element- of form handler- plugins
|
||||
that are currently missing (not registered, removed, failed to load - thus
|
||||
there would be a risk that your form would't be rendered properly/fully and
|
||||
the necessary data handling wouldn't happen either) you will get an
|
||||
appropriate exception. Although it's fine to get an instant error message about
|
||||
such failures in development, in production is wouldn't look appropriate.
|
||||
Thus, there are two settings related to the non-existing (not-found) form
|
||||
element- and form handler- plugins.
|
||||
|
||||
- FOBI_FAIL_ON_MISSING_FORM_ELEMENT_PLUGINS: If you want no error to be
|
||||
shown in case of missing form element plugins, set this to False in
|
||||
your settings module. Default value is True.
|
||||
- FOBI_FAIL_ON_MISSING_FORM_HANDLER_PLUGINS: If you want no error to be
|
||||
shown in case of missing form element handlers, set this to False in
|
||||
your settings module. Default value is True.
|
||||
|
||||
Troubleshooting
|
||||
===============================================
|
||||
If you get a ``FormElementPluginDoesNotExist`` or a
|
||||
``FormHandlerPluginDoesNotExist`` exception, make sure you have listed your
|
||||
plugin in the `settings` module of your project.
|
||||
|
||||
License
|
||||
===============================================
|
||||
GPL 2.0/LGPL 2.1
|
||||
|
|
|
|||
|
|
@ -208,6 +208,12 @@ Must haves
|
|||
- Add data export features for the ``db_store`` plugin into the "simpe"
|
||||
theme as well (same way as already done fore "bootstrap 3" and
|
||||
"foundation 5" themes.
|
||||
- Add a management command to remove broken form elements.
|
||||
- Think of making putting several actions (repair) into the management
|
||||
interface (UI).
|
||||
- Add `PluginThemeAddOn`, which would be a stand-alone plugin for having the
|
||||
specific theme HTML/JS/CSS added to the appropriate form element or a form
|
||||
handler plugin.
|
||||
|
||||
Should haves
|
||||
===============================================
|
||||
|
|
|
|||
|
|
@ -1244,6 +1244,28 @@ somehow doesn't appear in the list of available plugins, do run the
|
|||
plugins into the database, but also is a great way of checking for possible
|
||||
errors.
|
||||
|
||||
If you have forms refering to form element- of form handler- plugins
|
||||
that are currently missing (not registered, removed, failed to load - thus
|
||||
there would be a risk that your form would't be rendered properly/fully and
|
||||
the necessary data handling wouldn't happen either) you will get an
|
||||
appropriate exception. Although it's fine to get an instant error message about
|
||||
such failures in development, in production is wouldn't look appropriate.
|
||||
Thus, there are two settings related to the non-existing (not-found) form
|
||||
element- and form handler- plugins.
|
||||
|
||||
- FOBI_FAIL_ON_MISSING_FORM_ELEMENT_PLUGINS: If you want no error to be
|
||||
shown in case of missing form element plugins, set this to False in
|
||||
your settings module. Default value is True.
|
||||
- FOBI_FAIL_ON_MISSING_FORM_HANDLER_PLUGINS: If you want no error to be
|
||||
shown in case of missing form element handlers, set this to False in
|
||||
your settings module. Default value is True.
|
||||
|
||||
Troubleshooting
|
||||
===============================================
|
||||
If you get a ``FormElementPluginDoesNotExist`` or a
|
||||
``FormHandlerPluginDoesNotExist`` exception, make sure you have listed your
|
||||
plugin in the `settings` module of your project.
|
||||
|
||||
License
|
||||
===============================================
|
||||
GPL 2.0/LGPL 2.1
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -56,7 +56,7 @@ for static_dir in static_dirs:
|
|||
for locale_dir in locale_dirs:
|
||||
locale_files += [os.path.join(locale_dir, f) for f in os.listdir(locale_dir)]
|
||||
|
||||
version = '0.2'
|
||||
version = '0.2.1'
|
||||
|
||||
install_requires = [
|
||||
'Pillow>=2.0.0',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
__title__ = 'django-fobi'
|
||||
__version__ = '0.2'
|
||||
__build__ = 0x000008
|
||||
__version__ = '0.2.1'
|
||||
__build__ = 0x000009
|
||||
__author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
|
||||
__copyright__ = 'Copyright (c) 2014 Artur Barseghyan'
|
||||
__license__ = 'GPL 2.0/LGPL 2.1'
|
||||
|
|
|
|||
|
|
@ -54,9 +54,13 @@ from fobi.discover import autodiscover
|
|||
from fobi.constants import CALLBACK_STAGES
|
||||
from fobi.settings import (
|
||||
DEFAULT_THEME, FORM_HANDLER_PLUGINS_EXECUTION_ORDER,
|
||||
CUSTOM_THEME_DATA, THEME_FOOTER_TEXT, DEBUG
|
||||
CUSTOM_THEME_DATA, THEME_FOOTER_TEXT, FAIL_ON_MISSING_FORM_ELEMENT_PLUGINS,
|
||||
FAIL_ON_MISSING_FORM_HANDLER_PLUGINS, DEBUG
|
||||
)
|
||||
from fobi.exceptions import (
|
||||
InvalidRegistryItemType, DoesNotExist, ThemeDoesNotExist,
|
||||
FormElementPluginDoesNotExist, FormHandlerPluginDoesNotExist
|
||||
)
|
||||
from fobi.exceptions import InvalidRegistryItemType, ThemeDoesNotExist
|
||||
from fobi.helpers import (
|
||||
uniquify_sequence, map_field_name_to_label, clean_dict,
|
||||
map_field_name_to_label, get_ignorable_form_values
|
||||
|
|
@ -308,8 +312,12 @@ class BaseTheme(object):
|
|||
<span class="{delete_option_class}"></span> {delete_text}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<input type="hidden" value="{form_element_position}" name="form-{counter}-position" id="id_form-{counter}-position" class="form-element-position">
|
||||
<input type="hidden" value="{form_element_pk}" name="form-{counter}-id" id="id_form-{counter}-id">
|
||||
<input type="hidden" value="{form_element_position}"
|
||||
name="form-{counter}-position"
|
||||
id="id_form-{counter}-position"
|
||||
class="form-element-position">
|
||||
<input type="hidden" value="{form_element_pk}"
|
||||
name="form-{counter}-id" id="id_form-{counter}-id">
|
||||
""".format(
|
||||
container_class = cls.form_list_container_class,
|
||||
edit_option_html = "{edit_option_html}",
|
||||
|
|
@ -460,7 +468,9 @@ class BasePluginForm(object):
|
|||
:param django.http.HttpRequest request:
|
||||
"""
|
||||
if self.plugin_data_fields:
|
||||
return self._get_plugin_data(self.plugin_data_fields, request=request, json_format=json_format)
|
||||
return self._get_plugin_data(self.plugin_data_fields,
|
||||
request=request,
|
||||
json_format=json_format)
|
||||
|
||||
def save_plugin_data(self, request=None):
|
||||
"""
|
||||
|
|
@ -1147,8 +1157,7 @@ class FormElementPlugin(BasePlugin):
|
|||
extra={}):
|
||||
"""
|
||||
If ``kwargs_update_func`` is given, is callable and returns results
|
||||
without failures,
|
||||
return the result. Otherwise - return None.
|
||||
without failures, return the result. Otherwise - return None.
|
||||
"""
|
||||
# Check hooks
|
||||
if kwargs_update_func and callable(kwargs_update_func):
|
||||
|
|
@ -1163,7 +1172,6 @@ class FormElementPlugin(BasePlugin):
|
|||
return kwargs_update
|
||||
except Exception as e:
|
||||
logger.debug(str(e))
|
||||
#import ipdb; ipdb.set_trace()
|
||||
return {}
|
||||
|
||||
def _submit_plugin_form_data(self, form_entry, request, form):
|
||||
|
|
@ -1371,8 +1379,21 @@ class BaseRegistry(object):
|
|||
"""
|
||||
Registry of dash plugins. It's essential, that class registered has the
|
||||
``uid`` property.
|
||||
|
||||
If ``fail_on_missing_plugin`` is set to True, an appropriate exception
|
||||
(``plugin_not_found_exception_cls``) is raised in cases if plugin cound't
|
||||
be found in the registry.
|
||||
|
||||
:property mixed type:
|
||||
:property bool fail_on_missing_plugin:
|
||||
:property fobi.exceptions.DoesNotExist plugin_not_found_exception_cls:
|
||||
:property str plugin_not_found_error_message:
|
||||
"""
|
||||
type = None
|
||||
fail_on_missing_plugin = False
|
||||
plugin_not_found_exception_cls = DoesNotExist
|
||||
plugin_not_found_error_message = "Can't find plugin with uid `{0}` in " \
|
||||
"`{1}` registry."
|
||||
|
||||
def __init__(self):
|
||||
assert self.type
|
||||
|
|
@ -1432,11 +1453,17 @@ class BaseRegistry(object):
|
|||
:return mixed.
|
||||
"""
|
||||
item = self._registry.get(uid, default)
|
||||
|
||||
if not item:
|
||||
logger.debug(
|
||||
"Can't find plugin with uid `{0}` in `{1}` "
|
||||
"registry".format(uid, self.__class__)
|
||||
err_msg = self.plugin_not_found_error_message.format(
|
||||
uid, self.__class__
|
||||
)
|
||||
if self.fail_on_missing_plugin:
|
||||
logger.error(err_msg)
|
||||
raise self.plugin_not_found_exception_cls(err_msg)
|
||||
else:
|
||||
logger.debug(err_msg)
|
||||
|
||||
return item
|
||||
|
||||
|
||||
|
|
@ -1445,6 +1472,8 @@ class FormElementPluginRegistry(BaseRegistry):
|
|||
Form element plugins registry.
|
||||
"""
|
||||
type = (FormElementPlugin, FormFieldPlugin)
|
||||
fail_on_missing_plugin = FAIL_ON_MISSING_FORM_ELEMENT_PLUGINS
|
||||
plugin_not_found_exception_cls = FormElementPluginDoesNotExist
|
||||
|
||||
|
||||
class FormHandlerPluginRegistry(BaseRegistry):
|
||||
|
|
@ -1452,6 +1481,8 @@ class FormHandlerPluginRegistry(BaseRegistry):
|
|||
Form handler plugins registry.
|
||||
"""
|
||||
type = FormHandlerPlugin
|
||||
fail_on_missing_plugin = FAIL_ON_MISSING_FORM_HANDLER_PLUGINS
|
||||
plugin_not_found_exception_cls = FormHandlerPluginDoesNotExist
|
||||
|
||||
|
||||
class ThemeRegistry(BaseRegistry):
|
||||
|
|
@ -1480,7 +1511,7 @@ class FormCallbackRegistry(object):
|
|||
|
||||
:return string:
|
||||
"""
|
||||
name = "{0}.{1}".format(cls.__module__, cls.__name__)
|
||||
return "{0}.{1}".format(cls.__module__, cls.__name__)
|
||||
|
||||
def register(self, cls):
|
||||
"""
|
||||
|
|
@ -1494,7 +1525,7 @@ class FormCallbackRegistry(object):
|
|||
"`{1}`".format(cls, self.__class__)
|
||||
)
|
||||
|
||||
uid = self.uidfy(cls)
|
||||
#uid = self.uidfy(cls)
|
||||
# If item has not been forced yet, add/replace its' value in the
|
||||
# registry.
|
||||
|
||||
|
|
@ -1659,7 +1690,9 @@ def assemble_form_field_widget_class(base_class, plugin):
|
|||
Wrapped class.
|
||||
"""
|
||||
def __new__(cls, name, bases, attrs):
|
||||
new_class = super(DeclarativeMetaclass, cls).__new__(cls, name, bases, attrs)
|
||||
new_class = super(DeclarativeMetaclass, cls).__new__(
|
||||
cls, name, bases, attrs
|
||||
)
|
||||
return new_class
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
|
|
@ -1672,7 +1705,9 @@ def assemble_form_field_widget_class(base_class, plugin):
|
|||
return widget.render(name, value, attrs=attrs)
|
||||
else:
|
||||
#print 'rendered using standard'
|
||||
super(DeclarativeMetaclass, self).render(name, value, attrs=attrs)
|
||||
super(DeclarativeMetaclass, self).render(
|
||||
name, value, attrs=attrs
|
||||
)
|
||||
|
||||
class WrappedWidget(with_metaclass(DeclarativeMetaclass, base_class)):
|
||||
"""
|
||||
|
|
@ -1681,9 +1716,9 @@ def assemble_form_field_widget_class(base_class, plugin):
|
|||
|
||||
return WrappedWidget
|
||||
|
||||
# ********************************************************************************
|
||||
# *********************************** Generic ************************************
|
||||
# ********************************************************************************
|
||||
# *****************************************************************************
|
||||
# *********************************** Generic *********************************
|
||||
# *****************************************************************************
|
||||
|
||||
def get_registered_plugins(registry):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class SelectMultipleModelObjectsInputPlugin(FormFieldPlugin):
|
|||
"""
|
||||
# Get the object
|
||||
obj = form.cleaned_data.get(self.data.name, None)
|
||||
#import ipdb; ipdb.set_trace()
|
||||
|
||||
if obj:
|
||||
# Handle the upload
|
||||
admin_url = admin_change_url(
|
||||
|
|
|
|||
|
|
@ -7,9 +7,6 @@ __all__ = ('DBStoreHandlerPlugin',)
|
|||
import json
|
||||
import datetime
|
||||
|
||||
from six import string_types
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
|
|
@ -32,13 +29,10 @@ class DBStoreHandlerPlugin(FormHandlerPlugin):
|
|||
:param django.http.HttpRequest request:
|
||||
:param django.forms.Form form:
|
||||
"""
|
||||
#import ipdb; ipdb.set_trace()
|
||||
# Clean up the values, leave our content fields and empty values.
|
||||
field_name_to_label_map, cleaned_data = get_processed_form_data(form)
|
||||
|
||||
for key, value in cleaned_data.items():
|
||||
if isinstance(value, string_types) and value.startswith(settings.MEDIA_URL):
|
||||
cleaned_data[key] = '<a href="{value}">{value}</a>'.format(value=value)
|
||||
if isinstance(value, (datetime.datetime, datetime.date)):
|
||||
cleaned_data[key] = value.isoformat() if hasattr(value, 'isoformat') else value
|
||||
|
||||
|
|
@ -58,12 +52,14 @@ class DBStoreHandlerPlugin(FormHandlerPlugin):
|
|||
"""
|
||||
return (
|
||||
(
|
||||
reverse('fobi.contrib.plugins.form_handlers.db_store.view_saved_form_data_entries', args=[form_entry.pk]),
|
||||
reverse('fobi.contrib.plugins.form_handlers.db_store.view_saved_form_data_entries',
|
||||
args=[form_entry.pk]),
|
||||
_("View entries"),
|
||||
'glyphicon glyphicon-list'
|
||||
),
|
||||
(
|
||||
reverse('fobi.contrib.plugins.form_handlers.db_store.export_saved_form_data_entries', args=[form_entry.pk]),
|
||||
reverse('fobi.contrib.plugins.form_handlers.db_store.export_saved_form_data_entries',
|
||||
args=[form_entry.pk]),
|
||||
_("Export entries"),
|
||||
'glyphicon glyphicon-export'
|
||||
),
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@ __all__ = ('SavedFormDataEntry',)
|
|||
|
||||
import json
|
||||
|
||||
from six import string_types
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
#from django.contrib.auth.models import User
|
||||
from django.conf import settings
|
||||
|
||||
from django.db import models
|
||||
|
||||
|
|
@ -38,7 +40,8 @@ except ImportError:
|
|||
raise ImproperlyConfigured("Your custom user model ({0}.{1}) doesn't "
|
||||
"have ``username`` property, while "
|
||||
"``django-fobi`` relies on its' presence"
|
||||
".".format(user._meta.app_label, user._meta.object_name))
|
||||
".".format(user._meta.app_label, \
|
||||
user._meta.object_name))
|
||||
|
||||
# ****************************************************************************
|
||||
# ****************************************************************************
|
||||
|
|
@ -50,9 +53,12 @@ class SavedFormDataEntry(models.Model):
|
|||
"""
|
||||
Saved form data.
|
||||
"""
|
||||
form_entry = models.ForeignKey('fobi.FormEntry', verbose_name=_("Form"), null=True, blank=True)
|
||||
user = models.ForeignKey(User, verbose_name=_("User"), null=True, blank=True)
|
||||
form_data_headers = models.TextField(_("Form data headers"), null=True, blank=True)
|
||||
form_entry = models.ForeignKey('fobi.FormEntry', verbose_name=_("Form"),
|
||||
null=True, blank=True)
|
||||
user = models.ForeignKey(User, verbose_name=_("User"), null=True,
|
||||
blank=True)
|
||||
form_data_headers = models.TextField(_("Form data headers"), null=True,
|
||||
blank=True)
|
||||
saved_data = models.TextField(_("Plugin data"), null=True, blank=True)
|
||||
created = models.DateTimeField(_("Date created"), auto_now_add=True)
|
||||
|
||||
|
|
@ -72,6 +78,13 @@ class SavedFormDataEntry(models.Model):
|
|||
"""
|
||||
headers = json.loads(self.form_data_headers)
|
||||
data = json.loads(self.saved_data)
|
||||
for key, value in data.items():
|
||||
if isinstance(value, string_types) and \
|
||||
(value.startswith(settings.MEDIA_URL) or \
|
||||
value.startswith('http://') or value.startswith('https://')):
|
||||
|
||||
data[key] = '<a href="{value}">{value}</a>'.format(value=value)
|
||||
|
||||
return two_dicts_to_string(headers, data)
|
||||
formatted_saved_data.allow_tags = True
|
||||
formatted_saved_data.short_description = _("Saved data")
|
||||
|
|
|
|||
|
|
@ -56,10 +56,7 @@ class HTTPRepostHandlerPlugin(FormHandlerPlugin):
|
|||
file_path = settings.PROJECT_DIR('../{0}'.format(file_path))
|
||||
files[field_name] = (imf.name, open(file_path, 'rb'))
|
||||
|
||||
#logger.debug("ORIGINAL REQUEST FILES: ")
|
||||
#logger.debug(request.FILES)
|
||||
for field_name, imf in request.FILES.items():
|
||||
#import ipdb; ipdb.set_trace()
|
||||
try:
|
||||
file_path = form.cleaned_data.get(field_name, '')
|
||||
process_path(file_path, imf)
|
||||
|
|
@ -67,9 +64,6 @@ class HTTPRepostHandlerPlugin(FormHandlerPlugin):
|
|||
file_path = extract_file_path(imf.name)
|
||||
process_path(file_path, imf)
|
||||
|
||||
#logger.debug("FILES: ")
|
||||
#logger.debug(files)
|
||||
#import ipdb; ipdb.set_trace()
|
||||
response = requests.post(self.data.endpoint_url, \
|
||||
data=request.POST, files=files)
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@
|
|||
<tbody>
|
||||
{% for form_handler in form_handlers %}
|
||||
{% with form_handler.get_plugin as plugin %}
|
||||
{% if plugin %}
|
||||
<tr>
|
||||
<td>{{ form_handler.plugin_name }}
|
||||
{% if form_handler.plugin_data %}
|
||||
|
|
@ -129,6 +130,7 @@
|
|||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% load i18n %}
|
||||
{% load i18n fobi_tags %}
|
||||
|
||||
<h1>{% trans "Edit form" %}</h1>
|
||||
|
||||
|
|
@ -107,15 +107,15 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
{% for form_handler in form_handlers %}
|
||||
{% with form_handler.get_plugin as plugin %}
|
||||
{% if plugin %}
|
||||
<tr class="{% if forloop.counter|divisibleby:2 %}row2{% else %}row1{% endif %}">
|
||||
<td>{{ form_handler.plugin_name }}
|
||||
{% if form_handler.plugin_data %}
|
||||
{% with form_handler.get_plugin as plugin %}
|
||||
{% if form_handler.plugin_data %}
|
||||
<a class="popover-link" href="javascript:;" data-toggle="popover" data-content="{% spaceless %}{{ plugin.plugin_data_repr|safe }}{% endspaceless %}" role="button">
|
||||
<span class="badge" title="{% trans 'Info' %}">?</span>
|
||||
</a>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<ul class="list-inline">
|
||||
|
|
@ -123,9 +123,15 @@
|
|||
<li><a href="{% url 'fobi.edit_form_handler_entry' form_handler.pk %}"><span class="glyphicon glyphicon-edit"></span> {% trans "Edit" %}</a></li>
|
||||
{% endif %}
|
||||
<li><a href="{% url 'fobi.delete_form_handler_entry' form_handler.pk %}"><span class="glyphicon glyphicon-remove"></span> {% trans "Delete" %}</a></li>
|
||||
{% get_fobi_form_handler_plugin_custom_actions plugin form_entry as form_handler_plugin_custom_actions %}
|
||||
{% for action in form_handler_plugin_custom_actions %}
|
||||
<li><a href="{{ action.0 }}"><span class="{{ action.2 }}"></span> {{ action.1 }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -4,11 +4,17 @@ __copyright__ = 'Copyright (c) 2014 Artur Barseghyan'
|
|||
__license__ = 'GPL 2.0/LGPL 2.1'
|
||||
__all__ = (
|
||||
'RESTRICT_PLUGIN_ACCESS', 'FORM_ELEMENT_PLUGINS_MODULE_NAME',
|
||||
'FORM_HANDLER_PLUGINS_MODULE_NAME', 'FORM_CALLBACKS_MODULE_NAME',
|
||||
'THEMES_MODULE_NAME', 'DEFAULT_THEME', 'DISPLAY_AUTH_LINK',
|
||||
'WAIT_BETWEEN_TEST_STEPS', 'WAIT_AT_TEST_END', 'THEME_FOOTER_TEXT',
|
||||
'FORM_IMPORTER_PLUGINS_MODULE_NAME', 'CUSTOM_THEME_DATA',
|
||||
'DEBUG',
|
||||
'FORM_HANDLER_PLUGINS_MODULE_NAME', 'FORM_IMPORTER_PLUGINS_MODULE_NAME',
|
||||
'FORM_CALLBACKS_MODULE_NAME', 'THEMES_MODULE_NAME', 'DEFAULT_THEME',
|
||||
'DISPLAY_AUTH_LINK', 'DEBUG',
|
||||
|
||||
'CUSTOM_THEME_DATA', 'THEME_FOOTER_TEXT',
|
||||
|
||||
'DEFAULT_MAX_LENGTH', 'FORM_HANDLER_PLUGINS_EXECUTION_ORDER',
|
||||
'FAIL_ON_MISSING_FORM_ELEMENT_PLUGINS',
|
||||
'FAIL_ON_MISSING_FORM_HANDLER_PLUGINS'
|
||||
|
||||
'WAIT_BETWEEN_TEST_STEPS', 'WAIT_AT_TEST_END',
|
||||
)
|
||||
|
||||
from django.utils.translation import ugettext
|
||||
|
|
@ -45,9 +51,6 @@ DEFAULT_THEME = 'bootstrap3'
|
|||
|
||||
DISPLAY_AUTH_LINK = True
|
||||
|
||||
WAIT_BETWEEN_TEST_STEPS = 2
|
||||
WAIT_AT_TEST_END = 4
|
||||
|
||||
DEBUG = False
|
||||
|
||||
# **************************************************************
|
||||
|
|
@ -72,3 +75,15 @@ FORM_HANDLER_PLUGINS_EXECUTION_ORDER = (
|
|||
# The 'db_store' is left out intentionally, since it should
|
||||
# be the last plugin to be executed.
|
||||
)
|
||||
|
||||
FAIL_ON_MISSING_FORM_ELEMENT_PLUGINS = True
|
||||
FAIL_ON_MISSING_FORM_HANDLER_PLUGINS = True
|
||||
|
||||
# **************************************************************
|
||||
# **************************************************************
|
||||
# ************************ Tests related ***********************
|
||||
# **************************************************************
|
||||
# **************************************************************
|
||||
|
||||
WAIT_BETWEEN_TEST_STEPS = 2
|
||||
WAIT_AT_TEST_END = 4
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ __copyright__ = 'Copyright (c) 2014 Artur Barseghyan'
|
|||
__license__ = 'GPL 2.0/LGPL 2.1'
|
||||
__all__ = ('assemble_form_class',)
|
||||
|
||||
import logging
|
||||
#import logging
|
||||
|
||||
from six import with_metaclass
|
||||
|
||||
|
|
@ -12,17 +12,17 @@ from django.utils.datastructures import SortedDict
|
|||
from django.forms.forms import BaseForm#, get_declared_fields
|
||||
from django.forms.widgets import media_property
|
||||
|
||||
logger = logging.getLogger(__file__)
|
||||
#logger = logging.getLogger(__file__)
|
||||
|
||||
# ******************************************************************************
|
||||
# ******************************************************************************
|
||||
# **************************** Form generator **********************************
|
||||
# ******************************************************************************
|
||||
# ******************************************************************************
|
||||
# ****************************************************************************
|
||||
# ****************************************************************************
|
||||
# **************************** Form generator ********************************
|
||||
# ****************************************************************************
|
||||
# ****************************************************************************
|
||||
|
||||
def assemble_form_class(form_entry, base_class=BaseForm, request=None, \
|
||||
origin=None, origin_kwargs_update_func=None, origin_return_func=None,
|
||||
form_element_entries=None):
|
||||
origin=None, origin_kwargs_update_func=None, \
|
||||
origin_return_func=None, form_element_entries=None):
|
||||
"""
|
||||
Assembles a form class by given entry.
|
||||
|
||||
|
|
@ -32,8 +32,8 @@ def assemble_form_class(form_entry, base_class=BaseForm, request=None, \
|
|||
:param string origin:
|
||||
:param callable origin_kwargs_update_func:
|
||||
:param callable origin_return_func:
|
||||
:param iterable form_element_entries: If given, used instead of ``form_entry.formelemententry_set.all`` (no
|
||||
additional database hit).
|
||||
:param iterable form_element_entries: If given, used instead of
|
||||
``form_entry.formelemententry_set.all`` (no additional database hit).
|
||||
"""
|
||||
if form_element_entries is None:
|
||||
form_element_entries = form_entry.formelemententry_set.all()
|
||||
|
|
@ -42,26 +42,37 @@ def assemble_form_class(form_entry, base_class=BaseForm, request=None, \
|
|||
"""
|
||||
Copied from ``django.forms.forms.DeclarativeFieldsMetaclass``.
|
||||
|
||||
Metaclass that converts Field attributes to a dictionary called 'base_fields', taking into
|
||||
account parent class 'base_fields' as well.
|
||||
Metaclass that converts Field attributes to a dictionary called
|
||||
`base_fields`, taking into account parent class 'base_fields' as well.
|
||||
"""
|
||||
def __new__(cls, name, bases, attrs):
|
||||
base_fields = []
|
||||
|
||||
for creation_counter, form_element_entry in enumerate(form_element_entries):
|
||||
plugin = form_element_entry.get_plugin(request=request)
|
||||
plugin_form_field_instances = plugin._get_form_field_instances(
|
||||
form_element_entry = form_element_entry,
|
||||
origin = origin,
|
||||
kwargs_update_func = origin_kwargs_update_func,
|
||||
return_func = origin_return_func,
|
||||
extra = {'counter': creation_counter}
|
||||
)
|
||||
for form_field_name, form_field_instance in plugin_form_field_instances:
|
||||
base_fields.append((form_field_name, form_field_instance))
|
||||
|
||||
# We simply make sure the plugin exists. We don't handle
|
||||
# exceptions relate to the non-existent plugins here. They
|
||||
# are istead handled in registry.
|
||||
if plugin:
|
||||
plugin_form_field_instances = plugin._get_form_field_instances(
|
||||
form_element_entry = form_element_entry,
|
||||
origin = origin,
|
||||
kwargs_update_func = origin_kwargs_update_func,
|
||||
return_func = origin_return_func,
|
||||
extra = {'counter': creation_counter}
|
||||
)
|
||||
for form_field_name, form_field_instance in plugin_form_field_instances:
|
||||
base_fields.append((form_field_name, form_field_instance))
|
||||
|
||||
attrs['base_fields'] = SortedDict(base_fields)
|
||||
new_class = super(DeclarativeFieldsMetaclass, cls).__new__(cls, name, bases, attrs)
|
||||
new_class = super(DeclarativeFieldsMetaclass, cls).__new__(
|
||||
cls, name, bases, attrs
|
||||
)
|
||||
|
||||
if 'media' not in attrs:
|
||||
new_class.media = media_property(new_class)
|
||||
|
||||
return new_class
|
||||
|
||||
class DynamicForm(with_metaclass(DeclarativeFieldsMetaclass, base_class)):
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ __copyright__ = 'Copyright (c) 2014 Artur Barseghyan'
|
|||
__license__ = 'GPL 2.0/LGPL 2.1'
|
||||
__all__ = (
|
||||
'BaseException', 'ImproperlyConfigured', 'InvalidRegistryItemType',
|
||||
'DoesNotExist', 'ThemeDoesNotExist', 'NoDefaultThemeSet',
|
||||
'DoesNotExist', 'ThemeDoesNotExist', 'PluginDoesNotExist',
|
||||
'FormElementPluginDoesNotExist', 'FormHandlerPluginDoesNotExist',
|
||||
'NoDefaultThemeSet',
|
||||
)
|
||||
|
||||
class BaseException(Exception):
|
||||
|
|
@ -37,6 +39,23 @@ class ThemeDoesNotExist(DoesNotExist):
|
|||
"""
|
||||
|
||||
|
||||
class PluginDoesNotExist(DoesNotExist):
|
||||
"""
|
||||
Raised when no plugin with given uid can be found.
|
||||
"""
|
||||
|
||||
|
||||
class FormElementPluginDoesNotExist(PluginDoesNotExist):
|
||||
"""
|
||||
Raised when no form element plugin with given uid can be found.
|
||||
"""
|
||||
|
||||
|
||||
class FormHandlerPluginDoesNotExist(PluginDoesNotExist):
|
||||
"""
|
||||
Raised when no form handler plugin with given uid can be found.
|
||||
"""
|
||||
|
||||
class NoDefaultThemeSet(ImproperlyConfigured):
|
||||
"""
|
||||
Raised when no active theme is chosen.
|
||||
|
|
|
|||
|
|
@ -395,6 +395,11 @@ class AbstractPluginEntry(models.Model):
|
|||
|
||||
if not cls:
|
||||
# No need to log here, since already logged in registry.
|
||||
if registry.fail_on_missing_plugin:
|
||||
err_msg = registry.plugin_not_found_error_message.format(
|
||||
self.plugin_uid, registry.__class__
|
||||
)
|
||||
raise registry.plugin_not_found_exception_cls(err_msg)
|
||||
return None
|
||||
|
||||
# Creating plugin instance.
|
||||
|
|
|
|||
|
|
@ -15,12 +15,18 @@ __author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
|
|||
__copyright__ = 'Copyright (c) 2014 Artur Barseghyan'
|
||||
__license__ = 'GPL 2.0/LGPL 2.1'
|
||||
__all__ = (
|
||||
'RESTRICT_PLUGIN_ACCESS', 'FORM_ELEMENT_PLUGINS_MODULE_NAME',
|
||||
'FORM_HANDLER_PLUGINS_MODULE_NAME', 'FORM_CALLBACKS_MODULE_NAME',
|
||||
'THEMES_MODULE_NAME', 'DEFAULT_THEME', 'DISPLAY_AUTH_LINK',
|
||||
'WAIT_BETWEEN_TEST_STEPS', 'WAIT_AT_TEST_END', 'THEME_FOOTER_TEXT',
|
||||
'FORM_HANDLER_PLUGINS_EXECUTION_ORDER', 'CUSTOM_THEME_DATA',
|
||||
'FORM_IMPORTER_PLUGINS_MODULE_NAME', 'DEBUG',
|
||||
'RESTRICT_PLUGIN_ACCESS', 'FORM_ELEMENT_PLUGINS_MODULE_NAME',
|
||||
'FORM_HANDLER_PLUGINS_MODULE_NAME', 'FORM_IMPORTER_PLUGINS_MODULE_NAME',
|
||||
'FORM_CALLBACKS_MODULE_NAME', 'THEMES_MODULE_NAME', 'DEFAULT_THEME',
|
||||
'DISPLAY_AUTH_LINK', 'DEBUG',
|
||||
|
||||
'CUSTOM_THEME_DATA', 'THEME_FOOTER_TEXT',
|
||||
|
||||
'DEFAULT_MAX_LENGTH', 'FORM_HANDLER_PLUGINS_EXECUTION_ORDER',
|
||||
'FAIL_ON_MISSING_FORM_ELEMENT_PLUGINS',
|
||||
'FAIL_ON_MISSING_FORM_HANDLER_PLUGINS'
|
||||
|
||||
'WAIT_BETWEEN_TEST_STEPS', 'WAIT_AT_TEST_END',
|
||||
)
|
||||
|
||||
from fobi.conf import get_setting
|
||||
|
|
@ -31,14 +37,16 @@ from fobi.exceptions import NoDefaultThemeSet
|
|||
# *************************** Core *****************************
|
||||
# **************************************************************
|
||||
# **************************************************************
|
||||
|
||||
RESTRICT_PLUGIN_ACCESS = get_setting('RESTRICT_PLUGIN_ACCESS')
|
||||
|
||||
FORM_ELEMENT_PLUGINS_MODULE_NAME = get_setting('FORM_ELEMENT_PLUGINS_MODULE_NAME')
|
||||
FORM_ELEMENT_PLUGINS_MODULE_NAME = \
|
||||
get_setting('FORM_ELEMENT_PLUGINS_MODULE_NAME')
|
||||
|
||||
FORM_HANDLER_PLUGINS_MODULE_NAME = get_setting('FORM_HANDLER_PLUGINS_MODULE_NAME')
|
||||
FORM_HANDLER_PLUGINS_MODULE_NAME = \
|
||||
get_setting('FORM_HANDLER_PLUGINS_MODULE_NAME')
|
||||
|
||||
FORM_IMPORTER_PLUGINS_MODULE_NAME = get_setting('FORM_IMPORTER_PLUGINS_MODULE_NAME')
|
||||
FORM_IMPORTER_PLUGINS_MODULE_NAME = \
|
||||
get_setting('FORM_IMPORTER_PLUGINS_MODULE_NAME')
|
||||
|
||||
FORM_CALLBACKS_MODULE_NAME = get_setting('FORM_CALLBACKS_MODULE_NAME')
|
||||
|
||||
|
|
@ -51,9 +59,6 @@ DISPLAY_AUTH_LINK = get_setting('DISPLAY_AUTH_LINK')
|
|||
if not DEFAULT_THEME:
|
||||
raise NoDefaultThemeSet("No default theme set!")
|
||||
|
||||
WAIT_BETWEEN_TEST_STEPS = get_setting('WAIT_BETWEEN_TEST_STEPS')
|
||||
WAIT_AT_TEST_END = get_setting('WAIT_AT_TEST_END')
|
||||
|
||||
DEBUG = get_setting('DEBUG')
|
||||
|
||||
# **************************************************************
|
||||
|
|
@ -69,7 +74,21 @@ THEME_FOOTER_TEXT = get_setting('THEME_FOOTER_TEXT')
|
|||
# *********************** Plugin related ***********************
|
||||
# **************************************************************
|
||||
# **************************************************************
|
||||
|
||||
DEFAULT_MAX_LENGTH = get_setting('DEFAULT_MAX_LENGTH')
|
||||
|
||||
FORM_HANDLER_PLUGINS_EXECUTION_ORDER = get_setting('FORM_HANDLER_PLUGINS_EXECUTION_ORDER')
|
||||
FORM_HANDLER_PLUGINS_EXECUTION_ORDER = \
|
||||
get_setting('FORM_HANDLER_PLUGINS_EXECUTION_ORDER')
|
||||
|
||||
FAIL_ON_MISSING_FORM_ELEMENT_PLUGINS = \
|
||||
get_setting('FAIL_ON_MISSING_FORM_ELEMENT_PLUGINS')
|
||||
|
||||
FAIL_ON_MISSING_FORM_HANDLER_PLUGINS = \
|
||||
get_setting('FAIL_ON_MISSING_FORM_HANDLER_PLUGINS')
|
||||
|
||||
# **************************************************************
|
||||
# **************************************************************
|
||||
# ************************ Tests related ***********************
|
||||
# **************************************************************
|
||||
# **************************************************************
|
||||
WAIT_BETWEEN_TEST_STEPS = get_setting('WAIT_BETWEEN_TEST_STEPS')
|
||||
WAIT_AT_TEST_END = get_setting('WAIT_AT_TEST_END')
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@
|
|||
<tbody>
|
||||
{% for form_handler in form_handlers %}
|
||||
{% with form_handler.get_plugin as plugin %}
|
||||
{% if plugin %}
|
||||
<tr>
|
||||
<td>{{ form_handler.plugin_name }}
|
||||
{% if form_handler.plugin_data or plugin.plugin_data_repr %}
|
||||
|
|
@ -125,6 +126,7 @@
|
|||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ __all__ = (
|
|||
'dashboard', 'view_form_entry', 'form_entry_submitted',
|
||||
)
|
||||
|
||||
#import logging
|
||||
|
||||
from django.template import RequestContext
|
||||
from django.shortcuts import render_to_response, redirect
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
|
@ -43,6 +45,7 @@ from fobi.utils import (
|
|||
append_edit_and_delete_links_to_field
|
||||
)
|
||||
|
||||
#logger = logging.getLogger(__name__)
|
||||
|
||||
# *****************************************************************************
|
||||
# *****************************************************************************
|
||||
|
|
|
|||
Loading…
Reference in a new issue