From 0611193e5b3d37a87945bce4ededa211b206bee0 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Tue, 25 Oct 2016 23:09:10 +0200 Subject: [PATCH 01/39] changelog drafted; fix failing test --- CHANGELOG.rst | 7 +++++++ src/fobi/tests/test_browser_build_dynamic_forms.py | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index cee89e08..4aa65771 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,13 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.9.7 +----- +yyyy-mm-dd (not released yet) + +- Minor improvements to the generic integration processor. +- Wagtail integration. + 0.9.6 ----- 2016-10-25 diff --git a/src/fobi/tests/test_browser_build_dynamic_forms.py b/src/fobi/tests/test_browser_build_dynamic_forms.py index b33e545a..a9d85371 100644 --- a/src/fobi/tests/test_browser_build_dynamic_forms.py +++ b/src/fobi/tests/test_browser_build_dynamic_forms.py @@ -379,8 +379,8 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): delete_form_element_label_parent_container.find_element_by_partial_link_text( 'Delete' ) - # delete_form_element_link.click() - self._click(delete_form_element_link) + delete_form_element_link.click() + # self._click(delete_form_element_link) logger.debug(form_element_name) From 08f19340807b45c6e98c64b495edf9c82d2e300b Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Wed, 26 Oct 2016 16:28:22 +0200 Subject: [PATCH 02/39] update todos; better navigation for form wizards --- .gitignore | 1 + TODOS.rst | 3 +++ pytest.ini | 2 +- .../bootstrap3/templates/bootstrap3/_base.html | 2 ++ src/fobi/templates/fobi/generic/_base.html | 14 ++++++++++++++ src/fobi/templates/fobi/generic/dashboard.html | 5 +++++ .../fobi/generic/form_wizards_dashboard.html | 12 +++++++++++- 7 files changed, 37 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 12dadd7c..f7654677 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ .zip /.coverage /dev.db +/.cache/ MANIFEST.in~ MIND_BUCKET.rst diff --git a/TODOS.rst b/TODOS.rst index d978d7c2..a8341c5d 100644 --- a/TODOS.rst +++ b/TODOS.rst @@ -54,6 +54,9 @@ Roadmap Uncategorised ------------- +- Rethink templating of the integration packages (feincms_integration, + djangocms_integration, mezzanine_intergration), as now they are a bit + of a mess. Document integration properly, if not yet done. - Add tests for import/export of forms. - Add tests for export of plugin data (db_store). - In the form element plugins, when handling submit_form_data, somehow diff --git a/pytest.ini b/pytest.ini index 80381d50..e1b9b352 100644 --- a/pytest.ini +++ b/pytest.ini @@ -10,7 +10,7 @@ norecursedirs= python_files = test_*.py export = - DJANGO_SETTINGS_MODULE=./examples/simple/settings.testing + DJANGO_SETTINGS_MODULE=examples.simple.settings.settings_test addopts= --cov=src/fobi --ignore=.tox diff --git a/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/_base.html b/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/_base.html index fe62c740..76d78cd1 100644 --- a/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/_base.html +++ b/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/_base.html @@ -16,7 +16,9 @@ + {% block dashboard-menu-item %} {% url 'fobi.dashboard' as fobi_dashboard_url %} {{ fobi_theme.project_name }} + {% endblock dashboard-menu-item %} {% endblock navbar-header %} diff --git a/src/fobi/templates/fobi/generic/_base.html b/src/fobi/templates/fobi/generic/_base.html index 3fa2c9c2..5c2103f7 100644 --- a/src/fobi/templates/fobi/generic/_base.html +++ b/src/fobi/templates/fobi/generic/_base.html @@ -60,8 +60,10 @@ + {% block dashboard-menu-item %} {% url 'fobi.dashboard' as fobi_dashboard_url %} {{ fobi_theme.project_name }} + {% endblock dashboard-menu-item %} {% endblock navbar-header %} @@ -85,6 +87,7 @@ --> {% endblock navbar-menu-content %} {% block navbar-menu-navigation-content %} + {% comment %}
  • {% trans "Form wizards dashboard" %}
  • + {% endcomment %} {% endblock navbar-menu-navigation-content %} {% endblock navbar-menu %} + + {% block navbar-menu-right %} + + {% endblock navbar-menu-right %} + {% endblock navbar-menu-wrapper %} {% endblock navbar-content %} diff --git a/src/fobi/templates/fobi/generic/dashboard.html b/src/fobi/templates/fobi/generic/dashboard.html index cea16fa7..2a92cfef 100644 --- a/src/fobi/templates/fobi/generic/dashboard.html +++ b/src/fobi/templates/fobi/generic/dashboard.html @@ -7,6 +7,11 @@ {% block navbar-menu-content %} {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block main-content-inner-attrs %}{% endblock main-content-inner-attrs %} {% block content-wrapper %} diff --git a/src/fobi/templates/fobi/generic/form_wizards_dashboard.html b/src/fobi/templates/fobi/generic/form_wizards_dashboard.html index c5834c30..443d58e7 100644 --- a/src/fobi/templates/fobi/generic/form_wizards_dashboard.html +++ b/src/fobi/templates/fobi/generic/form_wizards_dashboard.html @@ -9,9 +9,19 @@ {% block main-content-inner-attrs %}{% endblock main-content-inner-attrs %} +{% block dashboard-menu-item %} +{% url 'fobi.form_wizards_dashboard' as fobi_wizards_dashboard_url %} +{{ fobi_theme.project_name }} +{% endblock dashboard-menu-item %} + +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content-wrapper %}
    From 5e3a8305c7e2ebeef2a5a0c37504123f5c96c112 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 27 Oct 2016 00:33:03 +0200 Subject: [PATCH 03/39] prepare 0.9.7; add import and export functionality for form wizards; improved gui and navigation for form wizards; improvements in the generic integration processor --- CHANGELOG.rst | 8 +- CREDITS.rst | 9 + pytest.ini | 17 - setup.py | 4 +- src/fobi/__init__.py | 4 +- src/fobi/forms.py | 12 + src/fobi/helpers.py | 6 + .../fobi/generic/add_form_element_entry.html | 5 + .../fobi/generic/add_form_handler_entry.html | 5 + .../add_form_wizard_handler_entry.html | 5 + .../fobi/generic/create_form_entry.html | 5 + .../generic/create_form_wizard_entry.html | 9 + .../fobi/generic/edit_form_element_entry.html | 5 + .../fobi/generic/edit_form_entry.html | 5 + .../fobi/generic/edit_form_handler_entry.html | 5 + .../fobi/generic/edit_form_wizard_entry.html | 9 + .../generic/edit_form_wizard_entry_ajax.html | 8 +- .../fobi/generic/form_entry_submitted.html | 5 + .../templates/fobi/generic/form_importer.html | 5 + .../generic/form_wizard_entry_submitted.html | 5 + .../fobi/generic/form_wizards_dashboard.html | 13 +- .../fobi/generic/import_form_entry.html | 5 + .../fobi/generic/view_form_entry.html | 5 + .../fobi/generic/view_form_wizard_entry.html | 9 + src/fobi/urls/edit.py | 16 + src/fobi/utils.py | 146 +++++- src/fobi/views.py | 416 +++++++++++++----- 27 files changed, 606 insertions(+), 140 deletions(-) delete mode 100644 pytest.ini diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4aa65771..121365c3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,10 +17,12 @@ are used for versioning (schema follows below): 0.9.7 ----- -yyyy-mm-dd (not released yet) +2016-10-27 -- Minor improvements to the generic integration processor. -- Wagtail integration. +- Improvements in the generic integration processor. +- Improved form wizard interface and navigation. +- Fixed a broken test. +- Added import/export functionality for form wizards. 0.9.6 ----- diff --git a/CREDITS.rst b/CREDITS.rst index b74383c1..a9997b54 100644 --- a/CREDITS.rst +++ b/CREDITS.rst @@ -23,3 +23,12 @@ Thanks to the following people for their contributions: - `Mario Taddei `_ for his initiative to make `Select multiple with max` plugin. +- `Andy Babic + `_ + for improvements in the generic integration processor. +- `Heldroe + `_ + for minor fixes. +- `Michal Dabski + `_ + for minor fixes. diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index e1b9b352..00000000 --- a/pytest.ini +++ /dev/null @@ -1,17 +0,0 @@ -[pytest] -norecursedirs= - *.egg - .git - .tox - .env - _sass - build - dist -python_files = - test_*.py -export = - DJANGO_SETTINGS_MODULE=examples.simple.settings.settings_test -addopts= - --cov=src/fobi - --ignore=.tox - --ignore=requirements diff --git a/setup.py b/setup.py index b5bfaaec..cfb85c14 100644 --- a/setup.py +++ b/setup.py @@ -4,6 +4,8 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages +version = '0.9.7' + # *************************************************************************** # ************************** Django version ********************************* # *************************************************************************** @@ -204,8 +206,6 @@ for locale_dir in locale_dirs: for f in os.listdir(locale_dir)] -version = '0.9.6' - install_requires = [] # If certain version of Django is already installed, choose version agnostic # dependencies. diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index 2e4b8e80..8046690d 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.9.6' -__build__ = 0x000068 +__version__ = '0.9.7' +__build__ = 0x000069 __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/forms.py b/src/fobi/forms.py index b6723e2c..5bec08ec 100644 --- a/src/fobi/forms.py +++ b/src/fobi/forms.py @@ -53,6 +53,7 @@ __all__ = ( 'FormWizardFormEntryFormSet', 'FormWizardHandlerEntryForm', 'ImportFormEntryForm', + 'ImportFormWizardEntryForm', ) # ***************************************************************************** @@ -512,3 +513,14 @@ class ImportFormEntryForm(forms.Form): # ignore_broken_form_handler_entries = forms.BooleanField( # required=False, # label=_("Ignore broken form handler entries")) + + +# ***************************************************************************** +# ***************************************************************************** +# ************************** Import form wizard entry ************************* +# ***************************************************************************** +# ***************************************************************************** + + +class ImportFormWizardEntryForm(ImportFormEntryForm): + """Import form entry wizard form.""" diff --git a/src/fobi/helpers.py b/src/fobi/helpers.py index e9db70fd..fdcb4cbd 100644 --- a/src/fobi/helpers.py +++ b/src/fobi/helpers.py @@ -633,6 +633,11 @@ class StrippedRequest(object): } return _meta +# ***************************************************************************** +# ***************************************************************************** +# ******************************** Export related ***************************** +# ***************************************************************************** +# ***************************************************************************** class JSONDataExporter(object): """Exporting the data into JSON.""" @@ -852,3 +857,4 @@ def get_wizard_form_field_value_from_request(request, ) return value + diff --git a/src/fobi/templates/fobi/generic/add_form_element_entry.html b/src/fobi/templates/fobi/generic/add_form_element_entry.html index 168ea189..15c54922 100644 --- a/src/fobi/templates/fobi/generic/add_form_element_entry.html +++ b/src/fobi/templates/fobi/generic/add_form_element_entry.html @@ -7,6 +7,11 @@ {% block navbar-menu-content %} {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content %} {% include fobi_theme.add_form_element_entry_ajax_template %} {% endblock content %} diff --git a/src/fobi/templates/fobi/generic/add_form_handler_entry.html b/src/fobi/templates/fobi/generic/add_form_handler_entry.html index 8619242c..467f573c 100644 --- a/src/fobi/templates/fobi/generic/add_form_handler_entry.html +++ b/src/fobi/templates/fobi/generic/add_form_handler_entry.html @@ -7,6 +7,11 @@ {% block navbar-menu-content %} {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content %} {% include fobi_theme.add_form_handler_entry_ajax_template %} {% endblock content %} diff --git a/src/fobi/templates/fobi/generic/add_form_wizard_handler_entry.html b/src/fobi/templates/fobi/generic/add_form_wizard_handler_entry.html index 131e82c4..9551f99d 100644 --- a/src/fobi/templates/fobi/generic/add_form_wizard_handler_entry.html +++ b/src/fobi/templates/fobi/generic/add_form_wizard_handler_entry.html @@ -7,6 +7,11 @@ {% block navbar-menu-content %} {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content %} {% include fobi_theme.add_form_wizard_handler_entry_ajax_template %} {% endblock content %} diff --git a/src/fobi/templates/fobi/generic/create_form_entry.html b/src/fobi/templates/fobi/generic/create_form_entry.html index 84142d89..bd5a9540 100644 --- a/src/fobi/templates/fobi/generic/create_form_entry.html +++ b/src/fobi/templates/fobi/generic/create_form_entry.html @@ -7,6 +7,11 @@ {% block navbar-menu-content %} {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content %} {% include fobi_theme.create_form_entry_ajax_template %} {% endblock content %} diff --git a/src/fobi/templates/fobi/generic/create_form_wizard_entry.html b/src/fobi/templates/fobi/generic/create_form_wizard_entry.html index cdd028e5..8061b726 100644 --- a/src/fobi/templates/fobi/generic/create_form_wizard_entry.html +++ b/src/fobi/templates/fobi/generic/create_form_wizard_entry.html @@ -7,6 +7,15 @@ {% block navbar-menu-content %} {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + +{% block dashboard-menu-item %} +{{ fobi_theme.project_name }} +{% endblock dashboard-menu-item %} + {% block content %} {% include fobi_theme.create_form_wizard_entry_ajax_template %} {% endblock content %} diff --git a/src/fobi/templates/fobi/generic/edit_form_element_entry.html b/src/fobi/templates/fobi/generic/edit_form_element_entry.html index 1cbe1963..d06cbe2b 100644 --- a/src/fobi/templates/fobi/generic/edit_form_element_entry.html +++ b/src/fobi/templates/fobi/generic/edit_form_element_entry.html @@ -7,6 +7,11 @@ {% block navbar-menu-content %} {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content %} {% include fobi_theme.edit_form_element_entry_ajax_template %} {% endblock content %} diff --git a/src/fobi/templates/fobi/generic/edit_form_entry.html b/src/fobi/templates/fobi/generic/edit_form_entry.html index 09e5f98e..9afeca58 100644 --- a/src/fobi/templates/fobi/generic/edit_form_entry.html +++ b/src/fobi/templates/fobi/generic/edit_form_entry.html @@ -4,6 +4,11 @@ {% block page-title %}{% trans "Edit form entry" %}{% endblock page-title %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block navbar-menu-content %}
  • {% trans "Edit" %}
  • {% trans "View" %}
  • diff --git a/src/fobi/templates/fobi/generic/edit_form_handler_entry.html b/src/fobi/templates/fobi/generic/edit_form_handler_entry.html index f4e5f310..e4ca4b5e 100644 --- a/src/fobi/templates/fobi/generic/edit_form_handler_entry.html +++ b/src/fobi/templates/fobi/generic/edit_form_handler_entry.html @@ -7,6 +7,11 @@ {% block navbar-menu-content %} {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content %} {% include fobi_theme.edit_form_handler_entry_ajax_template %} {% endblock content %} diff --git a/src/fobi/templates/fobi/generic/edit_form_wizard_entry.html b/src/fobi/templates/fobi/generic/edit_form_wizard_entry.html index 9c8bc939..35cd2f78 100644 --- a/src/fobi/templates/fobi/generic/edit_form_wizard_entry.html +++ b/src/fobi/templates/fobi/generic/edit_form_wizard_entry.html @@ -4,6 +4,15 @@ {% block page-title %}{% trans "Edit form wizard entry" %}{% endblock page-title %} +{% block dashboard-menu-item %} +{{ fobi_theme.project_name }} +{% endblock dashboard-menu-item %} + +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block navbar-menu-content %}
  • {% trans "Edit" %}
  • {% if form_wizard_entry_forms %}
  • {% trans "View" %}
  • {% endif %} diff --git a/src/fobi/templates/fobi/generic/edit_form_wizard_entry_ajax.html b/src/fobi/templates/fobi/generic/edit_form_wizard_entry_ajax.html index a79316b6..58d976ed 100644 --- a/src/fobi/templates/fobi/generic/edit_form_wizard_entry_ajax.html +++ b/src/fobi/templates/fobi/generic/edit_form_wizard_entry_ajax.html @@ -192,17 +192,15 @@
    - {% comment %}
    -

    {% trans "Export your form as JSON" %}

    +

    {% trans "Export your form wizard as JSON" %}

    {% trans "Export your form into JSON format and import it again any time!" %}

    - - {% trans "Export form" %} + + {% trans "Export form wizard" %}

    - {% endcomment %}

    {% trans "Delete your form wizard" %}

    {% trans "Once deleted, can't be undone!" %}

    diff --git a/src/fobi/templates/fobi/generic/form_entry_submitted.html b/src/fobi/templates/fobi/generic/form_entry_submitted.html index bc42d75a..f22d5ab4 100644 --- a/src/fobi/templates/fobi/generic/form_entry_submitted.html +++ b/src/fobi/templates/fobi/generic/form_entry_submitted.html @@ -7,6 +7,11 @@ {% block navbar-menu-content %} {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content %} {% include fobi_theme.form_entry_submitted_ajax_template %} {% endblock content %} diff --git a/src/fobi/templates/fobi/generic/form_importer.html b/src/fobi/templates/fobi/generic/form_importer.html index 756c7717..f4836aa7 100644 --- a/src/fobi/templates/fobi/generic/form_importer.html +++ b/src/fobi/templates/fobi/generic/form_importer.html @@ -7,6 +7,11 @@ {% block navbar-menu-content %} {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content %} {% include fobi_theme.form_importer_ajax_template %} {% endblock content %} diff --git a/src/fobi/templates/fobi/generic/form_wizard_entry_submitted.html b/src/fobi/templates/fobi/generic/form_wizard_entry_submitted.html index 21130bfe..563b7d2c 100644 --- a/src/fobi/templates/fobi/generic/form_wizard_entry_submitted.html +++ b/src/fobi/templates/fobi/generic/form_wizard_entry_submitted.html @@ -7,6 +7,11 @@ {% block navbar-menu-content %} {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content %} {% include fobi_theme.form_wizard_entry_submitted_ajax_template %} {% endblock content %} diff --git a/src/fobi/templates/fobi/generic/form_wizards_dashboard.html b/src/fobi/templates/fobi/generic/form_wizards_dashboard.html index 443d58e7..34c9b8a2 100644 --- a/src/fobi/templates/fobi/generic/form_wizards_dashboard.html +++ b/src/fobi/templates/fobi/generic/form_wizards_dashboard.html @@ -10,8 +10,7 @@ {% block main-content-inner-attrs %}{% endblock main-content-inner-attrs %} {% block dashboard-menu-item %} -{% url 'fobi.form_wizards_dashboard' as fobi_wizards_dashboard_url %} -{{ fobi_theme.project_name }} +{{ fobi_theme.project_name }} {% endblock dashboard-menu-item %} {% block navbar-menu-right-content %} @@ -61,13 +60,11 @@ {% trans "Delete" %} - {% comment %}
  • - + {% trans "Export" %}
  • - {% endcomment %} @@ -88,10 +85,10 @@ {% trans "Create form wizard" %} - {% comment %} - - {% trans "Import form" %} + + {% trans "Import form wizard" %} + {% comment %} {% for form_importer_uid,form_importer_name,form_importer_url in form_importers %} {{ form_importer_name }} diff --git a/src/fobi/templates/fobi/generic/import_form_entry.html b/src/fobi/templates/fobi/generic/import_form_entry.html index 66c48292..a24ac902 100644 --- a/src/fobi/templates/fobi/generic/import_form_entry.html +++ b/src/fobi/templates/fobi/generic/import_form_entry.html @@ -7,6 +7,11 @@ {% block navbar-menu-content %} {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content %} {% include fobi_theme.import_form_entry_ajax_template %} {% endblock content %} diff --git a/src/fobi/templates/fobi/generic/view_form_entry.html b/src/fobi/templates/fobi/generic/view_form_entry.html index 864b675c..647c2881 100644 --- a/src/fobi/templates/fobi/generic/view_form_entry.html +++ b/src/fobi/templates/fobi/generic/view_form_entry.html @@ -9,6 +9,11 @@
  • {% trans "View" %}
  • {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content %} {% include fobi_theme.view_form_entry_ajax_template %} {% endblock content %} diff --git a/src/fobi/templates/fobi/generic/view_form_wizard_entry.html b/src/fobi/templates/fobi/generic/view_form_wizard_entry.html index b3a53c4b..37955387 100644 --- a/src/fobi/templates/fobi/generic/view_form_wizard_entry.html +++ b/src/fobi/templates/fobi/generic/view_form_wizard_entry.html @@ -4,11 +4,20 @@ {% block page-title %}{% trans "View form wizard" %}{% endblock page-title %} +{% block dashboard-menu-item %} +{{ fobi_theme.project_name }} +{% endblock dashboard-menu-item %} + {% block navbar-menu-content %}
  • {% trans "Edit" %}
  • {% trans "View" %}
  • {% endblock navbar-menu-content %} +{% block navbar-menu-right-content %} +
  • {% trans "Forms" %}
  • +
  • {% trans "Wizards" %}
  • +{% endblock navbar-menu-right-content %} + {% block content %} {% include fobi_theme.view_form_wizard_entry_ajax_template %} {% endblock content %} diff --git a/src/fobi/urls/edit.py b/src/fobi/urls/edit.py index 90cf690a..9d6dc765 100644 --- a/src/fobi/urls/edit.py +++ b/src/fobi/urls/edit.py @@ -21,9 +21,11 @@ from fobi.views import ( edit_form_wizard_entry, edit_form_wizard_handler_entry, export_form_entry, + export_form_wizard_entry, form_importer, form_wizards_dashboard, import_form_entry, + import_form_wizard_entry ) __title__ = 'fobi.urls.edit' @@ -171,6 +173,20 @@ urlpatterns = [ delete_form_wizard_handler_entry, name='fobi.delete_form_wizard_handler_entry'), + # *********************************************************************** + # *********************** Form wizard entry add-ons ********************* + # *********************************************************************** + + # Export form wizard entry + url(_(r'^wizard/export/(?P\d+)/$'), + export_form_wizard_entry, + name='fobi.export_form_wizard_entry'), + + # Import form wizard entry + url(_(r'^wizard/import/$'), + import_form_wizard_entry, + name='fobi.import_form_wizard_entry'), + # *********************************************************************** # ****************************** Dashboard ****************************** # *********************************************************************** diff --git a/src/fobi/utils.py b/src/fobi/utils.py index c77e73a0..be94c06b 100644 --- a/src/fobi/utils.py +++ b/src/fobi/utils.py @@ -2,16 +2,18 @@ Another helper module. This module can NOT be safely imported from any fobi (sub)module - thus should be imported carefully. """ +import datetime import os import logging from six import PY3 from django.conf import settings +from django.contrib import messages from django.core.urlresolvers import reverse from django.forms.widgets import TextInput from django.utils.encoding import force_text -from django.utils.translation import ugettext +from django.utils.translation import ugettext, ugettext_lazy as _ from .base import ( form_element_plugin_registry, @@ -31,8 +33,11 @@ from .base import ( from .dynamic import assemble_form_class from .helpers import update_plugin_data, safe_text from .models import ( + FormEntry, FormElement, + FormElementEntry, FormHandler, + FormHandlerEntry, FormWizardHandler ) from .settings import RESTRICT_PLUGIN_ACCESS, DEBUG, WIZARD_FILES_UPLOAD_DIR @@ -59,6 +64,8 @@ __all__ = ( 'get_user_form_element_plugins_grouped', 'get_user_form_handler_plugins_grouped', 'get_user_form_wizard_handler_plugins_grouped', + 'prepare_form_entry_export_data', + 'perform_form_entry_import', ) logger = logging.getLogger(__name__) @@ -645,3 +652,140 @@ def get_wizard_files_upload_dir(): return os.path.abspath( os.path.join(settings.BASE_DIR, WIZARD_FILES_UPLOAD_DIR) ) + +# ***************************************************************************** +# ***************************************************************************** +# ******************************** Export related ***************************** +# ***************************************************************************** +# ***************************************************************************** + + +def prepare_form_entry_export_data(form_entry, + form_element_entries=None, + form_handler_entries=None): + """Prepare form entry export data. + + :param fobi.modes.FormEntry form_entry: Instance of. + :param django.db.models.QuerySet form_element_entries: QuerySet of + FormElementEntry instances. + :param django.db.models.QuerySet form_handler_entries: QuerySet of + FormHandlerEntry instances. + :return str: + """ + 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': [], + } + + if not form_element_entries: + form_element_entries = form_entry.formelemententry_set.all()[:] + + if not form_handler_entries: + 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, + } + ) + return data + + +def perform_form_entry_import(request, form_data): + """Perform form entry import. + + :param django.http.HttpRequest request: + :param dict form_data: + :return :class:`fobi.modes.FormEntry: Instance of. + """ + form_elements_data = form_data.pop('form_elements', []) + form_handlers_data = form_data.pop('form_handlers', []) + + form_data_keys_whitelist = ( + 'name', + 'slug', + 'is_public', + 'is_cloneable', + # 'position', + 'success_page_title', + 'success_page_message', + 'action', + ) + + # In this way we keep possible trash out. + for key in form_data.keys(): + if key not in form_data_keys_whitelist: + form_data.pop(key) + + # 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_data.get('plugin_uid', None): + messages.warning( + request, + _('Plugin {0} is missing in the system.' + '').format(form_handler_data.get('plugin_uid')) + ) + else: + messages.warning( + request, + _('Some essential data missing in the JSON ' + 'import.') + ) + + return form_entry diff --git a/src/fobi/views.py b/src/fobi/views.py index f6016501..67b26724 100644 --- a/src/fobi/views.py +++ b/src/fobi/views.py @@ -53,6 +53,7 @@ from .forms import ( FormEntryForm, FormElementEntryFormSet, ImportFormEntryForm, + ImportFormWizardEntryForm, FormWizardEntryForm, FormWizardFormEntry, FormWizardFormEntryFormSet, @@ -79,7 +80,9 @@ from .utils import ( get_user_form_wizard_handler_plugins, get_user_form_handler_plugin_uids, get_user_form_wizard_handler_plugin_uids, - get_wizard_files_upload_dir + get_wizard_files_upload_dir, + perform_form_entry_import, + prepare_form_entry_export_data ) from .wizard import DynamicSessionWizardView, DynamicCookieWizardView @@ -121,6 +124,7 @@ __all__ = ( 'form_wizards_dashboard', 'FormWizardView', 'import_form_entry', + 'import_form_wizard_entry', 'view_form_entry', ) @@ -2271,38 +2275,40 @@ def export_form_entry(request, form_entry_id, template_name=None): 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': [], - } + data = prepare_form_entry_export_data(form_entry) - 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 = { + # '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) @@ -2340,76 +2346,77 @@ def import_form_entry(request, template_name=None): # 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', []) - - form_data_keys_whitelist = ( - 'name', - 'slug', - 'is_public', - 'is_cloneable', - # 'position', - 'success_page_title', - 'success_page_message', - 'action', - ) - - # In this way we keep possible trash out. - for key in form_data.keys(): - if key not in form_data_keys_whitelist: - form_data.pop(key) - - # 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.') - ) + form_entry = perform_form_entry_import(request, form_data) + # form_elements_data = form_data.pop('form_elements', []) + # form_handlers_data = form_data.pop('form_handlers', []) + # + # form_data_keys_whitelist = ( + # 'name', + # 'slug', + # 'is_public', + # 'is_cloneable', + # # 'position', + # 'success_page_title', + # 'success_page_message', + # 'action', + # ) + # + # # In this way we keep possible trash out. + # for key in form_data.keys(): + # if key not in form_data_keys_whitelist: + # form_data.pop(key) + # + # # 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, @@ -2450,6 +2457,211 @@ def import_form_entry(request, template_name=None): template_name, context, context_instance=RequestContext(request) ) +# ***************************************************************************** +# ***************************************************************************** +# ************************* Export form wizard entry ************************** +# ***************************************************************************** +# ***************************************************************************** + + +@login_required +@permissions_required(satisfy=SATISFY_ALL, + perms=create_form_wizard_entry_permissions) +def export_form_wizard_entry(request, + form_wizard_entry_id, + template_name=None): + """Export form entry to JSON. + + :param django.http.HttpRequest request: + :param int form_wizard_entry_id: + :param string template_name: + :return django.http.HttpResponse: + """ + try: + form_wizard_entry = FormWizardEntry._default_manager \ + .get(pk=form_wizard_entry_id, user__pk=request.user.pk) + + except ObjectDoesNotExist as err: + raise Http404(ugettext("Form wizard entry not found.")) + + data = { + 'name': form_wizard_entry.name, + 'slug': form_wizard_entry.slug, + 'is_public': False, + 'is_cloneable': False, + 'success_page_title': form_wizard_entry.success_page_title, + 'success_page_message': form_wizard_entry.success_page_message, + 'form_wizard_forms': [], + 'form_wizard_handlers': [], + } + + form_wizard_form_entries = \ + form_wizard_entry.formwizardformentry_set.all()[:] + form_wizard_handler_entries = \ + form_wizard_entry.formwizardhandlerentry_set.all()[:] + + for wizard_form_entry in form_wizard_form_entries: + data['form_wizard_forms'].append( + prepare_form_entry_export_data(wizard_form_entry.form_entry) + ) + + for wizard_handler_entry in form_wizard_handler_entries: + data['form_wizard_handlers'].append( + { + 'plugin_uid': wizard_handler_entry.plugin_uid, + 'plugin_data': wizard_handler_entry.plugin_data, + } + ) + + data_exporter = JSONDataExporter(json.dumps(data), form_wizard_entry.slug) + + return data_exporter.export() + + +# ***************************************************************************** +# ***************************************************************************** +# **************************** Import form entry ****************************** +# ***************************************************************************** +# ***************************************************************************** + + +@login_required +@permissions_required(satisfy=SATISFY_ALL, + perms=create_form_wizard_entry_permissions) +def import_form_wizard_entry(request, template_name=None): + """Import form wizard entry. + + :param django.http.HttpRequest request: + :param string template_name: + :return django.http.HttpResponse: + """ + if 'POST' == request.method: + form = ImportFormWizardEntryForm(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_wizard_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_wizard_forms_data = form_wizard_data.pop( + 'form_wizard_forms', [] + ) + form_wizard_handlers_data = form_wizard_data.pop( + 'form_wizard_handlers', [] + ) + + form_wizard_data_keys_whitelist = ( + 'name', + 'slug', + 'is_public', + 'is_cloneable', + 'success_page_title', + 'success_page_message', + 'action', + ) + + # In this way we keep possible trash out. + for key in form_wizard_data.keys(): + if key not in form_wizard_data_keys_whitelist: + form_wizard_data.pop(key) + + # User information we always recreate! + form_wizard_data['user'] = request.user + + form_wizard_entry = FormWizardEntry(**form_wizard_data) + + form_wizard_entry.name += ugettext(" (imported on {0})").format( + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + ) + form_wizard_entry.save() + + # One by one, importing form element plugins. + for counter, form_entry_data \ + in enumerate(form_wizard_forms_data): + form_entry = perform_form_entry_import( + request, + form_entry_data + ) + FormWizardFormEntry.objects.create( + form_wizard_entry=form_wizard_entry, + form_entry=form_entry, + position=counter + ) + # One by one, importing form handler plugins. + for form_wizard_handler_data in form_wizard_handlers_data: + if form_wizard_handler_plugin_registry.registry.get( + form_wizard_handler_data.get('plugin_uid', None), + None + ): + form_wizard_handler = FormWizardHandlerEntry( + **form_wizard_handler_data + ) + form_wizard_handler.form_wizard_entry = form_wizard_entry + form_wizard_handler.save() + else: + if form_wizard_handler_data.get('plugin_uid', None): + messages.warning( + request, + _('Plugin {0} is missing in the system.').format( + form_wizard_handler_data.get('plugin_uid') + ) + ) + else: + messages.warning( + request, + _('Some essential data missing in the JSON ' + 'import.') + ) + + messages.info( + request, + _('The form wizard was imported successfully.') + ) + return redirect( + 'fobi.edit_form_wizard_entry', + form_wizard_entry_id=form_wizard_entry.pk + ) + else: + form = ImportFormWizardEntryForm() + + # 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 ******************************* From dc7761363434c1c839fc7a8f1ef395c285a0f727 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 27 Oct 2016 00:58:40 +0200 Subject: [PATCH 04/39] update docs - add section about tests --- README.rst | 39 +++++++++++++++++++++++++++++++++++++++ docs/index.rst | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/README.rst b/README.rst index 04e4aa3e..707b4bc1 100644 --- a/README.rst +++ b/README.rst @@ -1985,6 +1985,45 @@ element- and form handler- plugins. shown in case of missing form element handlers, set this to False in your settings module. Default value is True. +Tests +===== +Project is covered by test (functional- and browser-tests). + +To test type: + +.. code:: sh + + tox + +It's assumed that you have all the requirements installed. If not, first +install the test requirements: + +.. code:: sh + + pip install -r examples/simple/requirements/common_test_requirements.txt + +Selenium +-------- +Latest versions of Firefox are often not supported by Selenium. Current +version of the Selenium for Python (2.53.6) works fine with Firefox 47. +Thus, instead of using system Firefox you could better use a custom one. + +Set up Firefox 47 +~~~~~~~~~~~~~~~~~ +1. Download Firefox 47 from + `this + `__ + location and unzip it into ``/usr/lib/firefox47/`` + +2. Specify the full path to your Firefox in ``FIREFOX_BIN_PATH`` + setting. Example: + + .. code:: python + + FIREFOX_BIN_PATH = '/usr/lib/firefox47/firefox' + +After that your Selenium tests would work. + Troubleshooting =============== If you get a ``FormElementPluginDoesNotExist`` or a diff --git a/docs/index.rst b/docs/index.rst index 20c7cfc6..84d40669 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1985,6 +1985,45 @@ element- and form handler- plugins. shown in case of missing form element handlers, set this to False in your settings module. Default value is True. +Tests +===== +Project is covered by test (functional- and browser-tests). + +To test type: + +.. code:: sh + + tox + +It's assumed that you have all the requirements installed. If not, first +install the test requirements: + +.. code:: sh + + pip install -r examples/simple/requirements/common_test_requirements.txt + +Selenium +-------- +Latest versions of Firefox are often not supported by Selenium. Current +version of the Selenium for Python (2.53.6) works fine with Firefox 47. +Thus, instead of using system Firefox you could better use a custom one. + +Set up Firefox 47 +~~~~~~~~~~~~~~~~~ +1. Download Firefox 47 from + `this + `__ + location and unzip it into ``/usr/lib/firefox47/`` + +2. Specify the full path to your Firefox in ``FIREFOX_BIN_PATH`` + setting. Example: + + .. code:: python + + FIREFOX_BIN_PATH = '/usr/lib/firefox47/firefox' + +After that your Selenium tests would work. + Troubleshooting =============== If you get a ``FormElementPluginDoesNotExist`` or a From e032b0311ffe21e049dfc2e704dbec4ddd28ed48 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 27 Oct 2016 23:05:21 +0200 Subject: [PATCH 05/39] prepare 0.9.8; support multiple sliders per form --- .gitignore | 1 + CHANGELOG.rst | 6 +++++ setup.py | 2 +- src/fobi/__init__.py | 4 ++-- .../fobi.plugin.slider-bootstrap3-widget.js | 22 +++++++++++-------- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index f7654677..be48c4ea 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ README_PARTS.rst /examples/media/fobi_plugins/content_image/ /examples/media/fobi_plugins/file/ /examples/media/cache/ +/examples/simple/lund_urls.py /examples/simple/lund/ /examples/simple/settings/local_settings.py /examples/simple/settings/local_settings_foundation5.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 121365c3..1be41b7e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,12 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.9.8 +----- +2016-10-27 + +- Support multiple sliders in one form. + 0.9.7 ----- 2016-10-27 diff --git a/setup.py b/setup.py index cfb85c14..7d04f883 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.9.7' +version = '0.9.8' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index 8046690d..f75d295a 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.9.7' -__build__ = 0x000069 +__version__ = '0.9.8' +__build__ = 0x00006a __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/slider_bootstrap3_widget/static/bootstrap3/js/fobi.plugin.slider-bootstrap3-widget.js b/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/slider_bootstrap3_widget/static/bootstrap3/js/fobi.plugin.slider-bootstrap3-widget.js index b8cae56c..00a84a2d 100644 --- a/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/slider_bootstrap3_widget/static/bootstrap3/js/fobi.plugin.slider-bootstrap3-widget.js +++ b/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/slider_bootstrap3_widget/static/bootstrap3/js/fobi.plugin.slider-bootstrap3-widget.js @@ -8,13 +8,17 @@ ; $(document).ready(function() { - var selectElement = $('select.slider'); - var selectedValue = null; - try { - selectedValue = parseInt(selectElement.val()); - } catch(err) { - selectedValue = parseInt(selectElement.data('data-slider-value')); - } - var sliderElement = $('.slider').bootstrapSlider(); - sliderElement.bootstrapSlider('setValue', selectedValue); + // We consider multiple sliders + $('select.slider').each(function() { + var selectElement = $(this); + var selectedValue = null; + try { + selectedValue = parseInt(selectElement.val()); + } catch(err) { + selectedValue = parseInt(selectElement.data('data-slider-value')); + } + var sliderElement = $(this).bootstrapSlider(); + sliderElement.bootstrapSlider('setValue', selectedValue); + }); + }); From 47519241715af8f199ee19c7049154fddbc7547f Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Mon, 31 Oct 2016 00:47:28 +0100 Subject: [PATCH 06/39] prepare 0.9.9; make it possible to add custom ticks to the slider plugin --- .gitignore | 3 +- CHANGELOG.rst | 6 ++ setup.py | 2 +- src/fobi/__init__.py | 4 +- .../fields/slider/fobi_form_elements.py | 79 +++++++++++++------ .../form_elements/fields/slider/forms.py | 60 ++++++++------ .../form_elements/fields/slider/helpers.py | 39 +++++++++ src/fobi/helpers.py | 31 +++++++- .../fobi/generic/edit_form_element_entry.html | 7 ++ 9 files changed, 176 insertions(+), 55 deletions(-) create mode 100644 src/fobi/contrib/plugins/form_elements/fields/slider/helpers.py diff --git a/.gitignore b/.gitignore index be48c4ea..c2f79f34 100644 --- a/.gitignore +++ b/.gitignore @@ -32,10 +32,11 @@ README_PARTS.rst /src/django_fobi.egg-info /src/fobi/contrib/plugins/form_elements/fields/hidden_model_object/ /src/fobi/contrib/plugins/form_importers/mailchimp_importer/bucket.py -/src/fobi/contrib/apps/wagtail_integration/ +/src/fobi/contrib/apps/wagtail_integration_/ /scripts/install_django_1_7_wagtail.sh /scripts/reinstall_django_1_7_wagtail.sh +/scripts/copy_lund_files.sh /examples/db/ /examples/tmp/ diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1be41b7e..d1a09f0b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,12 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.9.9 +----- +2016-10-31 + +- Make it possible to add custom ticks to the `slider` plugin. + 0.9.8 ----- 2016-10-27 diff --git a/setup.py b/setup.py index 7d04f883..58bb17e9 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.9.8' +version = '0.9.9' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index f75d295a..c5d7b4cc 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.9.8' -__build__ = 0x00006a +__version__ = '0.9.9' +__build__ = 0x00006b __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py index d22e8528..fe26e7be 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py @@ -6,7 +6,12 @@ from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme +from fobi.base import ( + FormFieldPlugin, + form_element_plugin_registry, + get_theme +) +from fobi.helpers import get_select_field_choices from fobi.widgets import RichSelect from . import UID @@ -18,6 +23,7 @@ from .constants import ( SLIDER_DEFAULT_SHOW_ENDPOINTS_AS ) from .forms import SliderInputForm +from .helpers import generate_ticks from .settings import INITIAL, MAX_VALUE, MIN_VALUE, STEP __title__ = 'fobi.contrib.plugins.form_elements.fields.slider.' \ @@ -53,9 +59,11 @@ class SliderInputPlugin(FormFieldPlugin): if self.data.handle \ else SLIDER_DEFAULT_HANDLE - # custom_ticks = get_select_field_choices(self.data.custom_ticks) \ - # if self.data.custom_ticks \ - # else [] + custom_ticks = get_select_field_choices(self.data.custom_ticks, + key_type=int, + value_type=text_type) \ + if self.data.custom_ticks \ + else [] _choices = range(min_value, max_value+1, step) choices = zip(_choices, _choices) @@ -88,34 +96,53 @@ class SliderInputPlugin(FormFieldPlugin): # Show endpoints as labeled ticks if SLIDER_SHOW_ENDPOINTS_AS_LABELED_TICKS == show_endpoints_as: - label_start = self.data.label_start \ - if self.data.label_start \ - else text_type(min_value) + if custom_ticks: + ticks_data = generate_ticks(custom_ticks) + else: + ticks_data = generate_ticks([ + (min_value, self.data.label_start), + (max_value, self.data.label_end), + ]) + # label_start = self.data.label_start \ + # if self.data.label_start \ + # else text_type(min_value) + # + # label_end = self.data.label_end \ + # if self.data.label_end \ + # else text_type(max_value) - label_end = self.data.label_end \ - if self.data.label_end \ - else text_type(max_value) + # widget_attrs.update({ + # 'data-slider-ticks': "[{0}, {1}]".format( + # min_value, max_value + # ), + # 'data-slider-ticks-labels': '["{0!s}", "{1!s}"]'.format( + # label_start.encode('utf8'), label_end.encode('utf8') + # ), + # }) - widget_attrs.update({ - 'data-slider-ticks': "[{0}, {1}]".format( - min_value, max_value - ), - 'data-slider-ticks-labels': '["{0!s}", "{1!s}"]'.format( - label_start.encode('utf8'), label_end.encode('utf8') - ), - }) + widget_attrs.update(ticks_data) # Show endpoints as ticks elif SLIDER_SHOW_ENDPOINTS_AS_TICKS == show_endpoints_as: - widget_attrs.update({ - 'data-slider-ticks': "[{0}, {1}]".format( - min_value, max_value - ), - 'data-slider-ticks-labels': '["{0}", "{1}"]'.format( - "", "" - ), - }) + if custom_ticks: + ticks_data = generate_ticks(custom_ticks, empty_labels=True) + else: + ticks_data = generate_ticks([ + (min_value, ""), + (max_value, ""), + ]) + + # widget_attrs.update({ + # 'data-slider-ticks': "[{0}, {1}]".format( + # min_value, max_value + # ), + # 'data-slider-ticks-labels': '["{0}", "{1}"]'.format( + # "", "" + # ), + # }) + + widget_attrs.update(ticks_data) # Show endpoints as labels else: diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/forms.py b/src/fobi/contrib/plugins/form_elements/fields/slider/forms.py index b0df30af..99f82ef9 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/forms.py @@ -2,6 +2,7 @@ from django import forms from django.utils.translation import ugettext_lazy as _ from fobi.base import BaseFormFieldPluginForm, get_theme +from fobi.helpers import get_select_field_choices from fobi.widgets import NumberInput from .constants import ( @@ -44,7 +45,7 @@ class SliderInputForm(forms.Form, BaseFormFieldPluginForm): ("show_endpoints_as", SLIDER_DEFAULT_SHOW_ENDPOINTS_AS), ("label_start", ""), ("label_end", ""), - # ("custom_ticks", ""), + ("custom_ticks", ""), ("help_text", ""), ("required", False) ] @@ -140,27 +141,27 @@ class SliderInputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_html_class} ) ) - # custom_ticks = forms.CharField( - # label=_("Custom ticks"), - # required=False, - # help_text=_("Enter single values/pairs per line. Example:
    " - # "    1
    " - # "    2
    " - # "    3, Alpha
    " - # "    4, Beta
    " - # "

    " - # "It finally transforms into the following HTML " - # "code:
    " - # '    ' - # 'data-slider-ticks="[1, 2, 3, 4]"
    ' - # '    ' - # "data-slider-ticks-labels='" - # '["1", "2", "Alpha", "Beta"]' - # "'
    "), - # widget=forms.widgets.Textarea( - # attrs={'class': theme.form_element_html_class} - # ) - # ) + custom_ticks = forms.CharField( + label=_("Custom ticks"), + required=False, + help_text=_("Enter single values/pairs per line. Example:
    " + "    1
    " + "    2
    " + "    3, Alpha
    " + "    4, Beta
    " + "

    " + "It finally transforms into the following HTML " + "code:
    " + '    ' + 'data-slider-ticks="[1, 2, 3, 4]"
    ' + '    ' + "data-slider-ticks-labels='" + '["1", "2", "Alpha", "Beta"]' + "'
    "), + widget=forms.widgets.Textarea( + attrs={'class': theme.form_element_html_class} + ) + ) help_text = forms.CharField( label=_("Help text"), required=False, @@ -186,6 +187,7 @@ class SliderInputForm(forms.Form, BaseFormFieldPluginForm): step = self.cleaned_data['step'] show_endpoints_as = self.cleaned_data['show_endpoints_as'] handle = self.cleaned_data['handle'] + custom_ticks = self.cleaned_data['custom_ticks'] if max_value < min_value: self.add_error( @@ -222,3 +224,17 @@ class SliderInputForm(forms.Form, BaseFormFieldPluginForm): _("You are not allowed to use Triangle or Custom handles " "with ticks enabled.") ) + + if custom_ticks: + ticks = get_select_field_choices( + custom_ticks, + key_type=int, + value_type=str, + fail_silently=False + ) + if ticks is None: + self.add_error( + 'custom_ticks', + _("Invalid format. First value should be an integer, " + "second value should be a string.") + ) diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/helpers.py b/src/fobi/contrib/plugins/form_elements/fields/slider/helpers.py new file mode 100644 index 00000000..303f6e15 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/helpers.py @@ -0,0 +1,39 @@ +from six import text_type + +from django.utils.safestring import mark_safe + +__title__ = 'fobi.contrib.plugins.form_elements.fields.slider.helpers' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2015 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ( + 'generate_ticks', +) + + +def generate_ticks(choices, empty_labels=False): + """Generate ticks. + + :param iterable choices: Iterable of tuples or lists: + :param bool empty_labels: + :return dict: + """ + keys = [int(k) for (k, v) in choices] + # values = [v for (k, v) in choices if v else text_type(k)] + values = [] + + if empty_labels: + values = ["".encode('utf8') for k in keys] + else: + for k, v in choices: + if v is not None: + values.append(v.encode('utf8')) + else: + values.append(text_type(k).encode('utf8')) + + ticks = { + 'data-slider-ticks': mark_safe(str(keys)), + 'data-slider-ticks-labels': mark_safe(str(values)), + } + + return ticks diff --git a/src/fobi/helpers.py b/src/fobi/helpers.py index fdcb4cbd..78d5455f 100644 --- a/src/fobi/helpers.py +++ b/src/fobi/helpers.py @@ -396,13 +396,19 @@ def update_plugin_data(entry, request=None): return plugin._update_plugin_data(entry) -def get_select_field_choices(raw_choices_data): +def get_select_field_choices(raw_choices_data, + key_type=None, + value_type=None, + fail_silently=True): """Get select field choices. Used in ``radio``, ``select`` and other choice based fields. :param str raw_choices_data: + :param type key_type: + :param type value_type: + :param bool fail_silently: :return list: """ choices = [] # Holds return value @@ -417,8 +423,25 @@ def get_select_field_choices(raw_choices_data): if ',' in choice: key, value = choice.split(',', 1) key = key.strip() + + # If type specified, cast to the type + if key_type and key is not None: + try: + key = key_type(key) + except (ValueError, TypeError): + return [] if fail_silently else None + value = value.strip() - if key and key not in keys and value not in values: + # If type specified, cast to the type + if value_type and value is not None: + try: + value = value_type(value) + except (ValueError, TypeError): + return [] if fail_silently else None + + if key is not None \ + and key not in keys \ + and value not in values: choices.append((key, value)) keys.add(key) values.add(value) @@ -426,7 +449,9 @@ def get_select_field_choices(raw_choices_data): # If key is also the value else: choice = choice.strip() - if choice and choice not in keys and choice not in values: + if choice is not None \ + and choice not in keys \ + and choice not in values: choices.append((choice, choice)) keys.add(choice) values.add(choice) diff --git a/src/fobi/templates/fobi/generic/edit_form_element_entry.html b/src/fobi/templates/fobi/generic/edit_form_element_entry.html index d06cbe2b..df348d08 100644 --- a/src/fobi/templates/fobi/generic/edit_form_element_entry.html +++ b/src/fobi/templates/fobi/generic/edit_form_element_entry.html @@ -4,6 +4,13 @@ {% block page-title %}{% blocktrans with form_element_plugin.name as plugin_name %}Edit "{{ plugin_name }}" element of the form{% endblocktrans %}{% endblock page-title %} +{% block extrahead %} + {% if form %} + {{ form.media }} + {% endif %} + {{ block.super }} +{% endblock extrahead %} + {% block navbar-menu-content %} {% endblock navbar-menu-content %} From be9eeffdf74ad7684d39c9a5a5e5ac6b7ec18696 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Mon, 31 Oct 2016 02:14:28 +0100 Subject: [PATCH 07/39] simplify tox --- examples/requirements/django_1_7.txt | 2 +- examples/simple/settings/test.py | 94 ++++++++++++++++++++++++++++ tox.ini | 28 ++------- 3 files changed, 99 insertions(+), 25 deletions(-) diff --git a/examples/requirements/django_1_7.txt b/examples/requirements/django_1_7.txt index 4b42f139..fc1bd010 100644 --- a/examples/requirements/django_1_7.txt +++ b/examples/requirements/django_1_7.txt @@ -7,6 +7,6 @@ django-debug-toolbar==0.11.0 django-localeurl>=2.0.2 #django-nine>=0.1.10 #django-nonefield>=0.1 -django-registration-redux>=1.3 +django-registration-redux==1.3 #easy-thumbnails==2.3 #vishap>=0.1.5 diff --git a/examples/simple/settings/test.py b/examples/simple/settings/test.py index 9b5ed21c..d306633c 100644 --- a/examples/simple/settings/test.py +++ b/examples/simple/settings/test.py @@ -1 +1,95 @@ +# Use in `tox`. + from .base import * + +INSTALLED_APPS = list(INSTALLED_APPS) + +from nine import versions + + +if versions.DJANGO_1_5: + + try: + INSTALLED_APPS.append( + 'south') if 'south' not in INSTALLED_APPS else None + except Exception as e: + pass + +elif versions.DJANGO_1_6: + + try: + INSTALLED_APPS.append( + 'south') if 'south' not in INSTALLED_APPS else None + except Exception as e: + pass + + +elif versions.DJANGO_1_7: + + try: + INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None + INSTALLED_APPS.remove( + 'tinymce') if 'tinymce' in INSTALLED_APPS else None + except Exception as e: + pass + +elif versions.DJANGO_1_8: + + try: + INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None + INSTALLED_APPS.remove( + 'tinymce') if 'tinymce' in INSTALLED_APPS else None + except Exception as e: + pass + + try: + INSTALLED_APPS.remove('admin_tools') \ + if 'admin_tools' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.menu') \ + if 'admin_tools.menu' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.dashboard') \ + if 'admin_tools.dashboard' in INSTALLED_APPS else None + except Exception as e: + pass + +elif versions.DJANGO_1_9: + + try: + INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None + INSTALLED_APPS.remove( + 'tinymce') if 'tinymce' in INSTALLED_APPS else None + INSTALLED_APPS.remove( + 'localeurl') if 'localeurl' in INSTALLED_APPS else None + except Exception as e: + pass + + try: + INSTALLED_APPS.remove('admin_tools') \ + if 'admin_tools' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.menu') \ + if 'admin_tools.menu' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.dashboard') \ + if 'admin_tools.dashboard' in INSTALLED_APPS else None + except Exception as e: + pass + +elif versions.DJANGO_1_10: + + try: + INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None + INSTALLED_APPS.remove( + 'tinymce') if 'tinymce' in INSTALLED_APPS else None + INSTALLED_APPS.remove( + 'localeurl') if 'localeurl' in INSTALLED_APPS else None + except Exception as e: + pass + + try: + INSTALLED_APPS.remove('admin_tools') \ + if 'admin_tools' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.menu') \ + if 'admin_tools.menu' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.dashboard') \ + if 'admin_tools.dashboard' in INSTALLED_APPS else None + except Exception as e: + pass diff --git a/tox.ini b/tox.ini index 5e8144ec..08c27163 100644 --- a/tox.ini +++ b/tox.ini @@ -1,40 +1,20 @@ [tox] envlist = - #py{27,33,34}-{django15,django16}, - #py{27,33,34}-{django17,django18} + py{27,33,34}-{django15,django16}, + py{27,33,34}-{django17,django18} py{27,34}-{django17,django18} py{27,34}-{django19} py{27,35}-{django110} #flake8, #isort -[testenv:django15] +[testenv] +envlogdir=examples/logs/ passenv = * deps = django15: -r{toxinidir}/examples/requirements/django_1_5.txt -commands = - {envpython} examples/simple/manage.py test {posargs:fobi} --settings=settings.bootstrap3_theme_django_1_5 --traceback -v 3 - -[testenv:django16] -passenv = * -deps = django16: -r{toxinidir}/examples/requirements/django_1_6.txt -commands = - {envpython} examples/simple/manage.py test {posargs:fobi} --settings=settings.bootstrap3_theme_django_1_6 - -[testenv:django17] -passenv = * -deps = django17: -r{toxinidir}/examples/requirements/django_1_7.txt -commands = - {envpython} examples/simple/manage.py test {posargs:fobi} --settings=settings.bootstrap3_theme_django_1_7 - -[testenv] -passenv = * -deps = -# django15: -r{toxinidir}/examples/requirements/django_1_5.txt -# django16: -r{toxinidir}/examples/requirements/django_1_6.txt -# django17: -r{toxinidir}/examples/requirements/django_1_7.txt django18: -r{toxinidir}/examples/requirements/django_1_8.txt django19: -r{toxinidir}/examples/requirements/django_1_9.txt django110: -r{toxinidir}/examples/requirements/django_1_10.txt From 535f5d31e31635c84951c822729f6b117ef2bd4c Mon Sep 17 00:00:00 2001 From: Andy Babic Date: Mon, 31 Oct 2016 11:03:51 +0000 Subject: [PATCH 08/39] Fixes `get_absolute_url()` methods on `FormEntry` and `FormWizardEntry` models, so that 'View on site' links work from the django admin --- src/fobi/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/fobi/models.py b/src/fobi/models.py index 4055055e..21195027 100644 --- a/src/fobi/models.py +++ b/src/fobi/models.py @@ -308,7 +308,8 @@ class FormWizardEntry(models.Model): :return string: """ - return reverse('fobi.form_wizard', kwargs={'slug': self.slug}) + return reverse('fobi.view_form_wizard_entry', + kwargs={'slug': self.slug}) @python_2_unicode_compatible @@ -383,7 +384,7 @@ class FormEntry(models.Model): :return string: """ - return reverse('fobi.form_entry', kwargs={'slug': self.slug}) + return reverse('fobi.view_form_entry', kwargs={'slug': self.slug}) class FormWizardFormEntry(models.Model): From 8dde9d8675671ef7a889e256d37acf770c253dd5 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Tue, 1 Nov 2016 01:03:33 +0100 Subject: [PATCH 09/39] prepare 0.9.10; fixes --- CHANGELOG.rst | 11 ++++++- README.rst | 6 ++-- setup.py | 2 +- src/fobi/__init__.py | 4 +-- .../content/content_image/README.rst | 4 +-- .../content/content_text/README.rst | 4 +-- .../content/content_video/README.rst | 4 +-- .../form_elements/fields/boolean/README.rst | 4 +-- .../checkbox_select_multiple/README.rst | 8 ++--- .../form_elements/fields/date/README.rst | 4 +-- .../fields/date_drop_down/README.rst | 4 +-- .../form_elements/fields/datetime/README.rst | 4 +-- .../form_elements/fields/decimal/README.rst | 4 +-- .../form_elements/fields/email/README.rst | 4 +-- .../form_elements/fields/file/README.rst | 4 +-- .../form_elements/fields/float/README.rst | 4 +-- .../form_elements/fields/hidden/README.rst | 4 +-- .../form_elements/fields/input/README.rst | 4 +-- .../form_elements/fields/integer/README.rst | 4 +-- .../fields/ip_address/README.rst | 4 +-- .../fields/null_boolean/README.rst | 4 +-- .../form_elements/fields/password/README.rst | 4 +-- .../form_elements/fields/radio/README.rst | 14 ++++---- .../fields/range_select/README.rst | 12 +++++-- .../fields/range_select/defaults.py | 4 +++ .../fields/range_select/fobi_form_elements.py | 17 ++++++++-- .../fields/range_select/forms.py | 15 +++++++-- .../fields/range_select/settings.py | 6 ++++ .../form_elements/fields/regex/README.rst | 4 +-- .../form_elements/fields/select/README.rst | 14 ++++---- .../fields/select_model_object/README.rst | 14 ++++---- .../select_mptt_model_object/README.rst | 26 ++++++++------- .../fields/select_multiple/README.rst | 14 ++++---- .../select_multiple_model_objects/README.rst | 22 +++++++------ .../README.rst | 26 ++++++++------- .../select_multiple_with_max/README.rst | 14 ++++---- .../form_elements/fields/slider/README.rst | 28 ++++++++++------ .../form_elements/fields/slider/constants.py | 2 +- .../form_elements/fields/slider/defaults.py | 4 +++ .../fields/slider/fobi_form_elements.py | 30 +++++++++++++---- .../form_elements/fields/slider/forms.py | 15 +++++++-- .../form_elements/fields/slider/helpers.py | 6 ++-- .../form_elements/fields/slider/settings.py | 6 ++++ .../form_elements/fields/slider/widgets.py | 4 ++- .../form_elements/fields/slug/README.rst | 4 +-- .../form_elements/fields/text/README.rst | 4 +-- .../form_elements/fields/textarea/README.rst | 4 +-- .../form_elements/fields/time/README.rst | 4 +-- .../form_elements/fields/url/README.rst | 4 +-- .../form_elements/security/captcha/README.rst | 8 ++--- .../security/honeypot/README.rst | 4 +-- .../security/recaptcha/README.rst | 10 +++--- .../form_elements/test/dummy/README.rst | 4 +-- .../plugins/form_handlers/db_store/README.rst | 16 ++++----- .../form_handlers/http_repost/README.rst | 4 +-- .../plugins/form_handlers/mail/README.rst | 4 +-- .../date_bootstrap3_widget/README.rst | 2 +- .../djangocms_admin_style_theme/README.rst | 4 +-- src/fobi/helpers.py | 33 +++++++++++++++++++ src/fobi/widgets.py | 24 ++++++++++++++ 60 files changed, 349 insertions(+), 180 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d1a09f0b..9e55e9b5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,15 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.9.10 +------ +2016-11-01 + +- Fixed issue with custom labels in the `slider` plugin. +- Made `slider` plugin compatible with Django <= 1.6. +- Fixes `get_absolute_url` methods on `FormEntry` and `FormWizardEntry` + models. #48 + 0.9.9 ----- 2016-10-31 @@ -31,7 +40,7 @@ are used for versioning (schema follows below): ----- 2016-10-27 -- Improvements in the generic integration processor. +- Improvements in the generic integration processor. #47 - Improved form wizard interface and navigation. - Fixed a broken test. - Added import/export functionality for form wizards. diff --git a/README.rst b/README.rst index 707b4bc1..1004756b 100644 --- a/README.rst +++ b/README.rst @@ -1985,8 +1985,8 @@ element- and form handler- plugins. shown in case of missing form element handlers, set this to False in your settings module. Default value is True. -Tests -===== +Testing +======= Project is covered by test (functional- and browser-tests). To test type: @@ -2000,7 +2000,7 @@ install the test requirements: .. code:: sh - pip install -r examples/simple/requirements/common_test_requirements.txt + pip install -r examples/requirements/common_test_requirements.txt Selenium -------- diff --git a/setup.py b/setup.py index 58bb17e9..984f0499 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.9.9' +version = '0.9.10' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index c5d7b4cc..ab797b25 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.9.9' -__build__ = 0x00006b +__version__ = '0.9.10' +__build__ = 0x00006c __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/contrib/plugins/form_elements/content/content_image/README.rst b/src/fobi/contrib/plugins/form_elements/content/content_image/README.rst index 10517a6a..b85bd301 100644 --- a/src/fobi/contrib/plugins/form_elements/content/content_image/README.rst +++ b/src/fobi/contrib/plugins/form_elements/content/content_image/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst b/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst index 70bbb754..ac981477 100644 --- a/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst +++ b/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst @@ -18,9 +18,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/content/content_video/README.rst b/src/fobi/contrib/plugins/form_elements/content/content_video/README.rst index 9645b95f..79b1c699 100644 --- a/src/fobi/contrib/plugins/form_elements/content/content_video/README.rst +++ b/src/fobi/contrib/plugins/form_elements/content/content_video/README.rst @@ -18,9 +18,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/boolean/README.rst b/src/fobi/contrib/plugins/form_elements/fields/boolean/README.rst index cb8b8092..caed1cf9 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/boolean/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/boolean/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/README.rst b/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/README.rst index aeb85413..350bd64c 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/README.rst @@ -20,9 +20,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. @@ -45,7 +45,7 @@ Installation - "val": `value` (example: "alpha"). - "repr" (default): `label` (example: "Alpha"). - - "mix": `value (label)` (examle: "Alpha (alpha)"). + - "mix": `value (label)` (example: "Alpha (alpha)"). Simply set the ``FOBI_FORM_ELEMENT_CHECKBOX_SELECT_MULTIPLE_SUBMIT_VALUE_AS`` assign one of @@ -58,7 +58,7 @@ consist of just a single value or value/label pair. For example: -.. code-block:: none +.. code-block:: text 1 2 diff --git a/src/fobi/contrib/plugins/form_elements/fields/date/README.rst b/src/fobi/contrib/plugins/form_elements/fields/date/README.rst index 92ac50f5..3874b285 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/date/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/date/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/date_drop_down/README.rst b/src/fobi/contrib/plugins/form_elements/fields/date_drop_down/README.rst index 03be871d..2a35d9b1 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/date_drop_down/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/date_drop_down/README.rst @@ -20,9 +20,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/datetime/README.rst b/src/fobi/contrib/plugins/form_elements/fields/datetime/README.rst index 5340263c..ed7ce351 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/datetime/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/datetime/README.rst @@ -20,9 +20,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/decimal/README.rst b/src/fobi/contrib/plugins/form_elements/fields/decimal/README.rst index 6fe1f295..d3fbcfc5 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/decimal/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/decimal/README.rst @@ -21,9 +21,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/email/README.rst b/src/fobi/contrib/plugins/form_elements/fields/email/README.rst index 7d5e5503..509020f9 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/email/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/email/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/file/README.rst b/src/fobi/contrib/plugins/form_elements/fields/file/README.rst index d652344a..04821ed3 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/file/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/file/README.rst @@ -20,9 +20,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/float/README.rst b/src/fobi/contrib/plugins/form_elements/fields/float/README.rst index a54e8109..67458df2 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/float/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/float/README.rst @@ -21,9 +21,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/hidden/README.rst b/src/fobi/contrib/plugins/form_elements/fields/hidden/README.rst index 24660550..35d90259 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/hidden/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/hidden/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/input/README.rst b/src/fobi/contrib/plugins/form_elements/fields/input/README.rst index 27396ed5..51d26341 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/input/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/input/README.rst @@ -38,9 +38,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/integer/README.rst b/src/fobi/contrib/plugins/form_elements/fields/integer/README.rst index 268aeac2..834e08a8 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/integer/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/integer/README.rst @@ -21,9 +21,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/ip_address/README.rst b/src/fobi/contrib/plugins/form_elements/fields/ip_address/README.rst index 1e897058..f4751e6f 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/ip_address/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/ip_address/README.rst @@ -20,9 +20,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/null_boolean/README.rst b/src/fobi/contrib/plugins/form_elements/fields/null_boolean/README.rst index 2a40af8b..2a6d548b 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/null_boolean/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/null_boolean/README.rst @@ -20,9 +20,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/password/README.rst b/src/fobi/contrib/plugins/form_elements/fields/password/README.rst index c59a0bac..bfe8d3ef 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/password/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/password/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/radio/README.rst b/src/fobi/contrib/plugins/form_elements/fields/radio/README.rst index f5730ac0..38326b8c 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/radio/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/radio/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. @@ -42,9 +42,11 @@ Installation ('gamma', 'Gamma'), ] - - "val": `value` (example: "alpha"). - - "repr" (default): `label` (example: "Alpha"). - - "mix": `value (label)` (example: "Alpha (alpha)"). + .. code-block:: text + + - "val": `value` (example: "alpha"). + - "repr" (default): `label` (example: "Alpha"). + - "mix": `value (label)` (example: "Alpha (alpha)"). Simply set the ``FOBI_FORM_ELEMENT_RADIO_SUBMIT_VALUE_AS`` assign one of the following @@ -57,7 +59,7 @@ consist of just a single value or value/label pair. For example: -.. code-block:: none +.. code-block:: text 1 2 diff --git a/src/fobi/contrib/plugins/form_elements/fields/range_select/README.rst b/src/fobi/contrib/plugins/form_elements/fields/range_select/README.rst index a56290e7..43ed9ce6 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/range_select/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/range_select/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. @@ -29,7 +29,11 @@ Installation 4. Ranges are specified within the given min/max values. The default values are: +.. code-block:: text + - INITIAL: 50 + - INITIAL_MAX_VALUE: 100 + - INITIAL_MIN_VALUE: 0 - MIN_VALUE: 0 - MAX_VALUE: 100 - STEP: 1 @@ -37,7 +41,11 @@ Installation However, you can override each of them in the settings of your project by prefixing correspondent names with `FOBI_FORM_ELEMENT_RANGE_SELECT_`: +.. code-block:: text + - FOBI_FORM_ELEMENT_RANGE_SELECT_INITIAL + - FOBI_FORM_ELEMENT_RANGE_SELECT_INITIAL_MAX_VALUE + - FOBI_FORM_ELEMENT_RANGE_SELECT_INITIAL_MIN_VALUE - FOBI_FORM_ELEMENT_RANGE_SELECT_MIN_VALUE - FOBI_FORM_ELEMENT_RANGE_SELECT_MAX_VALUE - FOBI_FORM_ELEMENT_RANGE_SELECT_STEP diff --git a/src/fobi/contrib/plugins/form_elements/fields/range_select/defaults.py b/src/fobi/contrib/plugins/form_elements/fields/range_select/defaults.py index 2a34668e..1f61d5f9 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/range_select/defaults.py +++ b/src/fobi/contrib/plugins/form_elements/fields/range_select/defaults.py @@ -4,6 +4,8 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ( 'INITIAL', + 'INITIAL_MAX_VALUE', + 'INITIAL_MIN_VALUE', 'MAX_VALUE', 'MIN_VALUE', 'STEP', @@ -11,5 +13,7 @@ __all__ = ( INITIAL = 50 MIN_VALUE = 0 +INITIAL_MIN_VALUE = 0 MAX_VALUE = 5000 +INITIAL_MAX_VALUE = 100 STEP = 1 diff --git a/src/fobi/contrib/plugins/form_elements/fields/range_select/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/range_select/fobi_form_elements.py index 112086c7..84a8966e 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/range_select/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/range_select/fobi_form_elements.py @@ -6,7 +6,14 @@ from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme from . import UID from .forms import RangeSelectInputForm -from .settings import INITIAL, MAX_VALUE, MIN_VALUE, STEP +from .settings import ( + INITIAL, + INITIAL_MAX_VALUE, + INITIAL_MIN_VALUE, + # MAX_VALUE, + # MIN_VALUE, + STEP +) __title__ = 'fobi.contrib.plugins.form_elements.fields.range_select.' \ 'fobi_form_elements' @@ -30,8 +37,12 @@ class RangeSelectInputPlugin(FormFieldPlugin): form_element_entries=None, **kwargs): """Get form field instances.""" initial = self.data.initial if self.data.initial else INITIAL - max_value = self.data.max_value if self.data.max_value else MAX_VALUE - min_value = self.data.min_value if self.data.min_value else MIN_VALUE + max_value = self.data.max_value \ + if self.data.max_value \ + else INITIAL_MAX_VALUE + min_value = self.data.min_value \ + if self.data.min_value \ + else INITIAL_MIN_VALUE step = self.data.step if self.data.step else STEP _choices = range(min_value, max_value+1, step) diff --git a/src/fobi/contrib/plugins/form_elements/fields/range_select/forms.py b/src/fobi/contrib/plugins/form_elements/fields/range_select/forms.py index 67da57ad..19402655 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/range_select/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/range_select/forms.py @@ -4,7 +4,14 @@ from django.utils.translation import ugettext_lazy as _ from fobi.base import BaseFormFieldPluginForm, get_theme from fobi.widgets import NumberInput -from .settings import INITIAL, MAX_VALUE, MIN_VALUE, STEP +from .settings import ( + INITIAL, + INITIAL_MAX_VALUE, + INITIAL_MIN_VALUE, + MAX_VALUE, + MIN_VALUE, + STEP +) __title__ = 'fobi.contrib.plugins.form_elements.fields.range_select.forms' __author__ = 'Artur Barseghyan ' @@ -21,8 +28,8 @@ class RangeSelectInputForm(forms.Form, BaseFormFieldPluginForm): plugin_data_fields = [ ("label", ""), ("name", ""), - ("min_value", MIN_VALUE), - ("max_value", MAX_VALUE), + ("min_value", INITIAL_MIN_VALUE), + ("max_value", INITIAL_MAX_VALUE), ("step", STEP), ("help_text", ""), ("initial", INITIAL), @@ -46,6 +53,7 @@ class RangeSelectInputForm(forms.Form, BaseFormFieldPluginForm): min_value = forms.IntegerField( label=_("Min value"), required=True, + initial=INITIAL_MIN_VALUE, widget=NumberInput(attrs={'class': theme.form_element_html_class}), min_value=MIN_VALUE, max_value=MAX_VALUE @@ -53,6 +61,7 @@ class RangeSelectInputForm(forms.Form, BaseFormFieldPluginForm): max_value = forms.IntegerField( label=_("Max value"), required=True, + initial=INITIAL_MAX_VALUE, widget=NumberInput(attrs={'class': theme.form_element_html_class}), min_value=MIN_VALUE, max_value=MAX_VALUE diff --git a/src/fobi/contrib/plugins/form_elements/fields/range_select/settings.py b/src/fobi/contrib/plugins/form_elements/fields/range_select/settings.py index 0f198e68..5b23ccff 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/range_select/settings.py +++ b/src/fobi/contrib/plugins/form_elements/fields/range_select/settings.py @@ -6,6 +6,8 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ( 'INITIAL', + 'INITIAL_MAX_VALUE', + 'INITIAL_MIN_VALUE', 'MAX_VALUE', 'MIN_VALUE', 'STEP', @@ -13,6 +15,10 @@ __all__ = ( INITIAL = get_setting('INITIAL') +INITIAL_MAX_VALUE = get_setting('INITIAL_MAX_VALUE') + +INITIAL_MIN_VALUE = get_setting('INITIAL_MIN_VALUE') + MAX_VALUE = get_setting('MAX_VALUE') MIN_VALUE = get_setting('MIN_VALUE') diff --git a/src/fobi/contrib/plugins/form_elements/fields/regex/README.rst b/src/fobi/contrib/plugins/form_elements/fields/regex/README.rst index 7a4c4522..8a2e784d 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/regex/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/regex/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/select/README.rst b/src/fobi/contrib/plugins/form_elements/fields/select/README.rst index d89552be..ad905181 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/select/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. @@ -42,9 +42,11 @@ Installation ('gamma', 'Gamma'), ] - - "val": `value` (example: "alpha"). - - "repr" (default): `label` (example: "Alpha"). - - "mix": `value (label)` (example: "Alpha (alpha)"). + .. code-block:: text + + - "val": `value` (example: "alpha"). + - "repr" (default): `label` (example: "Alpha"). + - "mix": `value (label)` (example: "Alpha (alpha)"). Simply set the ``FOBI_FORM_ELEMENT_SELECT_SUBMIT_VALUE_AS`` assign one of the following @@ -57,7 +59,7 @@ consist of just a single value or value/label pair. For example: -.. code-block:: none +.. code-block:: text 1 2 diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_model_object/README.rst b/src/fobi/contrib/plugins/form_elements/fields/select_model_object/README.rst index 75e37416..83783fa9 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select_model_object/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/select_model_object/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. @@ -35,16 +35,18 @@ Installation FOBI_FORM_ELEMENT_SELECT_MODEL_OBJECT_IGNORED_MODELS = [ 'auth.User', 'auth.Group', - ] + ] 5. By default, the submitted form value of `select_model_object` elements is `app_label.model_name.object_pk.object_repr`. However, that part of the behaviour has been made configurable. You can choose between the following options: - - "val": `app_label.model_name.object_pk.object_repr`. - - "repr": `object_repr` (uses the ``__unicode__`` method of the model). - - "mix" (default): `app_label.model_name.object_pk.object_repr`. + .. code-block:: text + + - "val": `app_label.model_name.object_pk.object_repr`. + - "repr": `object_repr` (uses the ``__unicode__`` method of the model). + - "mix" (default): `app_label.model_name.object_pk.object_repr`. Simply set the ``FOBI_FORM_ELEMENT_SELECT_MODEL_OBJECT_SUBMIT_VALUE_AS`` assign one of the following values: "val", "repr" or "mix" to get the diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_mptt_model_object/README.rst b/src/fobi/contrib/plugins/form_elements/fields/select_mptt_model_object/README.rst index ae33eae4..b6066ee1 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select_mptt_model_object/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/select_mptt_model_object/README.rst @@ -13,9 +13,9 @@ Taken from django-mptt `Getting started 1. Download ``django-mptt`` using pip by running: -.. code-block:: none +.. code-block:: sh - $ pip install django-mptt + pip install django-mptt 2. Add ``mptt`` to the ``INSTALLED_APPS`` in your ``settings.py``. @@ -36,9 +36,9 @@ Install `select_mptt_model_object` plugin 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. @@ -47,21 +47,23 @@ Install `select_mptt_model_object` plugin ``fobi.contrib.plugins.form_elements.fields.select_mptt_model_object.defaults.IGNORED_MODELS``. If necessary, override it in your `settings` as shown in the example below: -.. code-block:: python + .. code-block:: python - FOBI_FORM_ELEMENT_SELECT_MPTT_MODEL_OBJECT_IGNORED_MODELS = [ - 'auth.User', - 'auth.Group', - ] + FOBI_FORM_ELEMENT_SELECT_MPTT_MODEL_OBJECT_IGNORED_MODELS = [ + 'auth.User', + 'auth.Group', + ] 5. By default, the submitted form value of `select_mptt_model_object` elements is `app_label.model_name.object_pk.object_repr`. However, that part of the behaviour has been made configurable. You can choose between the following options: - - "val": `app_label.model_name.object_pk.object_repr`. - - "repr": `object_repr` (uses the ``__unicode__`` method of the model). - - "mix" (default): `app_label.model_name.object_pk.object_repr`. + .. code-block:: text + + - "val": `app_label.model_name.object_pk.object_repr`. + - "repr": `object_repr` (uses the ``__unicode__`` method of the model). + - "mix" (default): `app_label.model_name.object_pk.object_repr`. Simply set the ``FOBI_FORM_ELEMENT_SELECT_MPTT_MODEL_OBJECT_SUBMIT_VALUE_AS`` assign one of the following values: "val", "repr" or "mix" to get the diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_multiple/README.rst b/src/fobi/contrib/plugins/form_elements/fields/select_multiple/README.rst index dc4584fb..b47ddc39 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select_multiple/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/select_multiple/README.rst @@ -20,9 +20,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. @@ -43,9 +43,11 @@ Installation ('gamma', 'Gamma'), ] - - "val": `value` (example: "alpha"). - - "repr" (default): `label` (example: "Alpha"). - - "mix": `value (label)` (example: "Alpha (alpha)"). + .. code-block:: text + + - "val": `value` (example: "alpha"). + - "repr" (default): `label` (example: "Alpha"). + - "mix": `value (label)` (example: "Alpha (alpha)"). Simply set the ``FOBI_FORM_ELEMENT_SELECT_MULTIPLE_SUBMIT_VALUE_AS`` assign one of the @@ -58,7 +60,7 @@ consist of just a single value or value/label pair. For example: -.. code-block:: none +.. code-block:: text 1 2 diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_model_objects/README.rst b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_model_objects/README.rst index ef813bce..7151a58d 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_model_objects/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_model_objects/README.rst @@ -21,9 +21,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. @@ -32,21 +32,23 @@ Installation ``fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects.defaults.IGNORED_MODELS``. If necessary, override it in your `settings` as shown in the example below: -.. code-block:: python + .. code-block:: python - FOBI_FORM_ELEMENT_SELECT_MULTIPLE_MODEL_OBJECTS_IGNORED_MODELS = [ - 'auth.User', - 'auth.Group', - ] + FOBI_FORM_ELEMENT_SELECT_MULTIPLE_MODEL_OBJECTS_IGNORED_MODELS = [ + 'auth.User', + 'auth.Group', + ] 5. By default, the submitted form value of `select_multiple_model_objects` elements is `app_label.model_name.object_pk.object_repr`. However, that part of the behaviour has been made configurable. You can choose between the following options: - - "val": `app_label.model_name.object_pk.object_repr`. - - "repr": `object_repr` (uses the ``__unicode__`` method of the model). - - "mix" (default): `app_label.model_name.object_pk.object_repr`. + .. code-block:: text + + - "val": `app_label.model_name.object_pk.object_repr`. + - "repr": `object_repr` (uses the ``__unicode__`` method of the model). + - "mix" (default): `app_label.model_name.object_pk.object_repr`. Simply set the ``FOBI_FORM_ELEMENT_SELECT_MULTIPLE_MODEL_OBJECTS_SUBMIT_VALUE_AS`` assign diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_mptt_model_objects/README.rst b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_mptt_model_objects/README.rst index ef8d74ae..302b410e 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_mptt_model_objects/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_mptt_model_objects/README.rst @@ -14,9 +14,9 @@ Taken from django-mptt `Getting started 1. Download ``django-mptt`` using pip by running: -.. code-block:: none +.. code-block:: sh - $ pip install django-mptt + pip install django-mptt 2. Add ``mptt`` to the ``INSTALLED_APPS`` in your ``settings.py``. @@ -37,9 +37,9 @@ Install `select_multiple_mptt_model_objects` plugin 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. @@ -48,21 +48,23 @@ Install `select_multiple_mptt_model_objects` plugin ``fobi.contrib.plugins.form_elements.fields.select_multiple_mptt_model_objects.defaults.IGNORED_MODELS``. If necessary, override it in your `settings` as shown in the example below: -.. code-block:: python + .. code-block:: python - FOBI_FORM_ELEMENT_SELECT_MULTIPLE_MPTT_MODEL_OBJECTS_IGNORED_MODELS = [ - 'auth.User', - 'auth.Group', - ] + FOBI_FORM_ELEMENT_SELECT_MULTIPLE_MPTT_MODEL_OBJECTS_IGNORED_MODELS = [ + 'auth.User', + 'auth.Group', + ] 5. By default, the submitted form value of `select_multiple_mptt_model_objects` elements is `app_label.model_name.object_pk.object_repr`. However, that part of the behaviour has been made configurable. You can choose between the following options: - - "val": `app_label.model_name.object_pk.object_repr`. - - "repr": `object_repr` (uses the ``__unicode__`` method of the model). - - "mix" (default): `app_label.model_name.object_pk.object_repr`. + .. code-block:: text + + - "val": `app_label.model_name.object_pk.object_repr`. + - "repr": `object_repr` (uses the ``__unicode__`` method of the model). + - "mix" (default): `app_label.model_name.object_pk.object_repr`. Simply set the ``FOBI_FORM_ELEMENT_SELECT_MULTIPLE_MPTT_MODEL_OBJECTS_SUBMIT_VALUE_AS`` diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_with_max/README.rst b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_with_max/README.rst index aca9aa91..a864db4f 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_with_max/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_with_max/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. @@ -42,9 +42,11 @@ Installation ('gamma', 'Gamma'), ] - - "val": `value` (example: "alpha"). - - "repr" (default): `label` (example: "Alpha"). - - "mix": `value (label)` (example: "Alpha (alpha)"). + .. code-block:: text + + - "val": `value` (example: "alpha"). + - "repr" (default): `label` (example: "Alpha"). + - "mix": `value (label)` (example: "Alpha (alpha)"). Simply set the ``FOBI_FORM_ELEMENT_SELECT_MULTIPLE_WITH_MAX_SUBMIT_VALUE_AS`` assign one of the @@ -58,7 +60,7 @@ the 'max_choices' field, the user can choose only or less choices. For example: -.. code-block:: none +.. code-block:: text 1 2 diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/README.rst b/src/fobi/contrib/plugins/form_elements/fields/slider/README.rst index 51ca5adc..da99ebbd 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. @@ -29,15 +29,23 @@ Installation 4. Ranges are specified within the given min/max values. The default values are: - - INITIAL: 50 - - MIN_VALUE: 0 - - MAX_VALUE: 100 - - STEP: 1 + .. code-block:: text + + - INITIAL: 50 + - INITIAL_MAX_VALUE: 100 + - INITIAL_MIN_VALUE: 0 + - MIN_VALUE: 0 + - MAX_VALUE: 100 + - STEP: 1 However, you can override each of them in the settings of your project by prefixing correspondent names with `FOBI_FORM_ELEMENT_SLIDER_`: - - FOBI_FORM_ELEMENT_SLIDER_INITIAL - - FOBI_FORM_ELEMENT_SLIDER_MIN_VALUE - - FOBI_FORM_ELEMENT_SLIDER_MAX_VALUE - - FOBI_FORM_ELEMENT_SLIDER_STEP + .. code-block:: text + + - FOBI_FORM_ELEMENT_SLIDER_INITIAL + - FOBI_FORM_ELEMENT_SLIDER_INITIAL_MAX_VALUE + - FOBI_FORM_ELEMENT_SLIDER_INITIAL_MIN_VALUE + - FOBI_FORM_ELEMENT_SLIDER_MIN_VALUE + - FOBI_FORM_ELEMENT_SLIDER_MAX_VALUE + - FOBI_FORM_ELEMENT_SLIDER_STEP diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/constants.py b/src/fobi/contrib/plugins/form_elements/fields/slider/constants.py index 8110629f..c453aca5 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/constants.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/constants.py @@ -27,7 +27,7 @@ __all__ = ( SLIDER_TOOLTIP_SHOW = 'show' SLIDER_TOOLTIP_HIDE = 'hide' SLIDER_TOOLTIP_ALWAYS = 'always' -SLIDER_DEFAULT_TOOLTIP = SLIDER_TOOLTIP_HIDE +SLIDER_DEFAULT_TOOLTIP = SLIDER_TOOLTIP_SHOW SLIDER_TOOLTIP_CHOICES = ( (SLIDER_TOOLTIP_SHOW, _("Show")), diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/defaults.py b/src/fobi/contrib/plugins/form_elements/fields/slider/defaults.py index 42436b9b..4e48f2f1 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/defaults.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/defaults.py @@ -4,12 +4,16 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ( 'INITIAL', + 'INITIAL_MAX_VALUE', + 'INITIAL_MIN_VALUE', 'MAX_VALUE', 'MIN_VALUE', 'STEP', ) INITIAL = 50 +INITIAL_MIN_VALUE = 0 +INITIAL_MAX_VALUE = 100 MIN_VALUE = 0 MAX_VALUE = 5000 STEP = 1 diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py index fe26e7be..a1e0d73f 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py @@ -1,18 +1,20 @@ from six import text_type from django.forms.fields import ChoiceField -from django.forms.utils import flatatt + from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ +from nine import versions + from fobi.base import ( FormFieldPlugin, form_element_plugin_registry, get_theme ) from fobi.helpers import get_select_field_choices -from fobi.widgets import RichSelect +from fobi.widgets import RichSelectInverseQuotes from . import UID from .constants import ( @@ -24,7 +26,19 @@ from .constants import ( ) from .forms import SliderInputForm from .helpers import generate_ticks -from .settings import INITIAL, MAX_VALUE, MIN_VALUE, STEP +from .settings import ( + INITIAL, + INITIAL_MAX_VALUE, + INITIAL_MIN_VALUE, + # MAX_VALUE, + # MIN_VALUE, + STEP +) + +if versions.DJANGO_GTE_1_7: + from django.forms.utils import flatatt +else: + from django.forms.util import flatatt __title__ = 'fobi.contrib.plugins.form_elements.fields.slider.' \ 'fobi_form_elements' @@ -49,8 +63,12 @@ class SliderInputPlugin(FormFieldPlugin): form_element_entries=None, **kwargs): """Get form field instances.""" initial = self.data.initial if self.data.initial else INITIAL - max_value = self.data.max_value if self.data.max_value else MAX_VALUE - min_value = self.data.min_value if self.data.min_value else MIN_VALUE + max_value = self.data.max_value \ + if self.data.max_value \ + else INITIAL_MAX_VALUE + min_value = self.data.min_value \ + if self.data.min_value \ + else INITIAL_MIN_VALUE step = self.data.step if self.data.step else STEP tooltip = self.data.tooltip \ if self.data.tooltip \ @@ -186,7 +204,7 @@ class SliderInputPlugin(FormFieldPlugin): 'initial': initial, 'required': self.data.required, 'choices': choices, - 'widget': RichSelect(**widget_kwargs), + 'widget': RichSelectInverseQuotes(**widget_kwargs), } return [(self.data.name, ChoiceField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/forms.py b/src/fobi/contrib/plugins/form_elements/fields/slider/forms.py index 99f82ef9..04082491 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/forms.py @@ -18,7 +18,14 @@ from .constants import ( SLIDER_SHOW_ENDPOINTS_AS_TICKS ) -from .settings import INITIAL, MAX_VALUE, MIN_VALUE, STEP +from .settings import ( + INITIAL, + INITIAL_MAX_VALUE, + INITIAL_MIN_VALUE, + MAX_VALUE, + MIN_VALUE, + STEP +) __title__ = 'fobi.contrib.plugins.form_elements.fields.slider.forms' __author__ = 'Artur Barseghyan ' @@ -36,8 +43,8 @@ class SliderInputForm(forms.Form, BaseFormFieldPluginForm): ("label", ""), ("name", ""), ("initial", INITIAL), - ("min_value", MIN_VALUE), - ("max_value", MAX_VALUE), + ("min_value", INITIAL_MIN_VALUE), + ("max_value", INITIAL_MAX_VALUE), ("step", STEP), ("tooltip", SLIDER_DEFAULT_TOOLTIP), ("handle", SLIDER_DEFAULT_HANDLE), @@ -75,6 +82,7 @@ class SliderInputForm(forms.Form, BaseFormFieldPluginForm): min_value = forms.IntegerField( label=_("Min value"), required=True, + initial=INITIAL_MIN_VALUE, widget=NumberInput(attrs={'class': theme.form_element_html_class}), min_value=MIN_VALUE, max_value=MAX_VALUE @@ -82,6 +90,7 @@ class SliderInputForm(forms.Form, BaseFormFieldPluginForm): max_value = forms.IntegerField( label=_("Max value"), required=True, + initial=INITIAL_MAX_VALUE, widget=NumberInput(attrs={'class': theme.form_element_html_class}), min_value=MIN_VALUE, max_value=MAX_VALUE diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/helpers.py b/src/fobi/contrib/plugins/form_elements/fields/slider/helpers.py index 303f6e15..60b7402d 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/helpers.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/helpers.py @@ -1,6 +1,6 @@ from six import text_type -from django.utils.safestring import mark_safe +from django.utils.html import format_html __title__ = 'fobi.contrib.plugins.form_elements.fields.slider.helpers' __author__ = 'Artur Barseghyan ' @@ -32,8 +32,8 @@ def generate_ticks(choices, empty_labels=False): values.append(text_type(k).encode('utf8')) ticks = { - 'data-slider-ticks': mark_safe(str(keys)), - 'data-slider-ticks-labels': mark_safe(str(values)), + 'data-slider-ticks': format_html(str(keys)), + 'data-slider-ticks-labels': format_html(str(values).replace("'", '"')), } return ticks diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/settings.py b/src/fobi/contrib/plugins/form_elements/fields/slider/settings.py index bd3ca811..7efae34e 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/settings.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/settings.py @@ -6,6 +6,8 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ( 'INITIAL', + 'INITIAL_MAX_VALUE', + 'INITIAL_MIN_VALUE', 'MAX_VALUE', 'MIN_VALUE', 'STEP', @@ -13,6 +15,10 @@ __all__ = ( INITIAL = get_setting('INITIAL') +INITIAL_MAX_VALUE = get_setting('INITIAL_MAX_VALUE') + +INITIAL_MIN_VALUE = get_setting('INITIAL_MIN_VALUE') + MAX_VALUE = get_setting('MAX_VALUE') MIN_VALUE = get_setting('MIN_VALUE') diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/widgets.py b/src/fobi/contrib/plugins/form_elements/fields/slider/widgets.py index 5d29edb2..5eaaef17 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/widgets.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/widgets.py @@ -8,7 +8,9 @@ __title__ = 'fobi.contrib.plugins.form_elements.fields.slider.widgets' __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' -__all__ = ('BaseSliderPluginWidget', ) +__all__ = ( + 'BaseSliderPluginWidget', +) class BaseSliderPluginWidget(FormElementPluginWidget): diff --git a/src/fobi/contrib/plugins/form_elements/fields/slug/README.rst b/src/fobi/contrib/plugins/form_elements/fields/slug/README.rst index a842be28..f4963bbd 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slug/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/slug/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/text/README.rst b/src/fobi/contrib/plugins/form_elements/fields/text/README.rst index ff50c177..499f236f 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/text/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/text/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/textarea/README.rst b/src/fobi/contrib/plugins/form_elements/fields/textarea/README.rst index ba664f48..a7e6ec26 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/textarea/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/textarea/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/time/README.rst b/src/fobi/contrib/plugins/form_elements/fields/time/README.rst index cf90fc58..94a39685 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/time/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/time/README.rst @@ -20,9 +20,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/fields/url/README.rst b/src/fobi/contrib/plugins/form_elements/fields/url/README.rst index e70596d7..595fb703 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/url/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/url/README.rst @@ -20,9 +20,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/security/captcha/README.rst b/src/fobi/contrib/plugins/form_elements/security/captcha/README.rst index b8d24ff9..425d30da 100644 --- a/src/fobi/contrib/plugins/form_elements/security/captcha/README.rst +++ b/src/fobi/contrib/plugins/form_elements/security/captcha/README.rst @@ -14,9 +14,9 @@ Taken from django-simple-captcha `installation instructions 1. Download ``django-simple-captcha`` using pip by running: -.. code-block:: none +.. code-block:: sh - $ pip install django-simple-captcha + pip install django-simple-captcha 2. Add ``captcha`` to the ``INSTALLED_APPS`` in your ``settings.py``. @@ -47,9 +47,9 @@ Install `fobi` Captcha plugin 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/security/honeypot/README.rst b/src/fobi/contrib/plugins/form_elements/security/honeypot/README.rst index 0bda21df..894dcdb7 100644 --- a/src/fobi/contrib/plugins/form_elements/security/honeypot/README.rst +++ b/src/fobi/contrib/plugins/form_elements/security/honeypot/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_elements/security/recaptcha/README.rst b/src/fobi/contrib/plugins/form_elements/security/recaptcha/README.rst index 179c362b..6dff9873 100644 --- a/src/fobi/contrib/plugins/form_elements/security/recaptcha/README.rst +++ b/src/fobi/contrib/plugins/form_elements/security/recaptcha/README.rst @@ -11,9 +11,9 @@ Install `django-recaptcha` -------------------------- 1. Download ``django-recaptcha`` using pip by running: -.. code-block:: none +.. code-block:: sh - $ pip install django-recaptcha + pip install django-recaptcha 2. Add ``captcha`` to the ``INSTALLED_APPS`` in your ``settings.py``. @@ -36,15 +36,17 @@ Install `fobi` ReCAPTCHA plugin 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. 4. Specify the following ReCAPTCHA credentials in your settings. +.. code-block:: text + - ``RECAPTCHA_PUBLIC_KEY`` - ``RECAPTCHA_PRIVATE_KEY`` diff --git a/src/fobi/contrib/plugins/form_elements/test/dummy/README.rst b/src/fobi/contrib/plugins/form_elements/test/dummy/README.rst index 12552731..fc8bcf22 100644 --- a/src/fobi/contrib/plugins/form_elements/test/dummy/README.rst +++ b/src/fobi/contrib/plugins/form_elements/test/dummy/README.rst @@ -18,9 +18,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_handlers/db_store/README.rst b/src/fobi/contrib/plugins/form_handlers/db_store/README.rst index ec46ea88..281817bb 100644 --- a/src/fobi/contrib/plugins/form_handlers/db_store/README.rst +++ b/src/fobi/contrib/plugins/form_handlers/db_store/README.rst @@ -25,11 +25,11 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py syncdb + ./manage.py migrate - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. @@ -49,8 +49,8 @@ For form wizards do: .. code-block:: python urlpatterns = [ - # DB Store plugin URLs - url(r'^fobi/plugins/form-wizard-handlers/db-store/', - include('fobi.contrib.plugins.form_handlers.db_store.urls.' - 'form_wizard_handlers')), - ] + # DB Store plugin URLs + url(r'^fobi/plugins/form-wizard-handlers/db-store/', + include('fobi.contrib.plugins.form_handlers.db_store.urls.' + 'form_wizard_handlers')), + ] diff --git a/src/fobi/contrib/plugins/form_handlers/http_repost/README.rst b/src/fobi/contrib/plugins/form_handlers/http_repost/README.rst index 737c57f8..1296c478 100644 --- a/src/fobi/contrib/plugins/form_handlers/http_repost/README.rst +++ b/src/fobi/contrib/plugins/form_handlers/http_repost/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/plugins/form_handlers/mail/README.rst b/src/fobi/contrib/plugins/form_handlers/mail/README.rst index 5810ec0a..e189b224 100644 --- a/src/fobi/contrib/plugins/form_handlers/mail/README.rst +++ b/src/fobi/contrib/plugins/form_handlers/mail/README.rst @@ -19,9 +19,9 @@ Installation 2. In the terminal type: -.. code-block:: none +.. code-block:: sh - $ ./manage.py fobi_sync_plugins + ./manage.py fobi_sync_plugins 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. diff --git a/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/date_bootstrap3_widget/README.rst b/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/date_bootstrap3_widget/README.rst index bcbc6379..69cd45be 100644 --- a/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/date_bootstrap3_widget/README.rst +++ b/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/date_bootstrap3_widget/README.rst @@ -6,7 +6,7 @@ theme). Installation ============ -1. Add ``fobi.contrib.themes.bootstrap3.widgets.form_elements.date_bootstrap3_widget`` +1. Add ``fobi.contrib.themes.bootstrap3.widgets.form_elements.date_bootstrap3_widget`` to the ``INSTALLED_APPS`` in your ``settings.py``. .. code-block:: python diff --git a/src/fobi/contrib/themes/djangocms_admin_style_theme/README.rst b/src/fobi/contrib/themes/djangocms_admin_style_theme/README.rst index 165c79da..3fbab0a8 100644 --- a/src/fobi/contrib/themes/djangocms_admin_style_theme/README.rst +++ b/src/fobi/contrib/themes/djangocms_admin_style_theme/README.rst @@ -15,9 +15,9 @@ See the original `installation instructions 1. Install the ``djangocms-admin-style`` package. -.. code-block:: none +.. code-block:: sh - $ pip install djangocms-admin-style + pip install djangocms-admin-style 2. Add 'djangocms_admin_style' to your INSTALLED_APPS just before 'django.contrib.admin'. diff --git a/src/fobi/helpers.py b/src/fobi/helpers.py index 78d5455f..67a34d7e 100644 --- a/src/fobi/helpers.py +++ b/src/fobi/helpers.py @@ -19,6 +19,7 @@ from django.core.files.base import File from django.contrib.contenttypes.models import ContentType from django.db.utils import DatabaseError from django.utils.encoding import force_text +from django.utils.html import format_html_join from django import forms from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import AnonymousUser @@ -50,6 +51,7 @@ __all__ = ( 'do_slugify', 'empty_string', 'ensure_unique_filename', + 'flatatt_inverse_quotes', 'get_app_label_and_model_name', 'get_form_element_entries_for_form_wizard_entry', 'get_model_name_for_object', @@ -883,3 +885,34 @@ def get_wizard_form_field_value_from_request(request, return value +# ***************************************************************************** +# ***************************************************************************** +# ******************************** Export related ***************************** +# ***************************************************************************** +# ***************************************************************************** + + +def flatatt_inverse_quotes(attrs): + """Convert a dictionary of attributes to a single string. + + The returned string will contain a leading space followed by key="value", + XML-style pairs. In the case of a boolean value, the key will appear + without a value. It is assumed that the keys do not need to be + XML-escaped. If the passed dictionary is empty, then return an empty + string. + + The result is passed through 'mark_safe' (by way of 'format_html_join'). + """ + key_value_attrs = [] + boolean_attrs = [] + for attr, value in attrs.items(): + if isinstance(value, bool): + if value: + boolean_attrs.append((attr,)) + else: + key_value_attrs.append((attr, value)) + + return ( + format_html_join("", " {}='{}'", sorted(key_value_attrs)) + + format_html_join("", " {}", sorted(boolean_attrs)) + ) diff --git a/src/fobi/widgets.py b/src/fobi/widgets.py index b557a6f6..2ab800d3 100644 --- a/src/fobi/widgets.py +++ b/src/fobi/widgets.py @@ -3,6 +3,8 @@ from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ +from .helpers import flatatt_inverse_quotes + # Safe import of ``NumberInput`` try: from django.forms.widgets import NumberInput @@ -22,6 +24,7 @@ __all__ = ( 'NumberInput', 'BooleanRadioSelect', 'RichSelect', + 'RichSelectInverseQuotes', ) @@ -96,3 +99,24 @@ class RichSelect(Select): format_html(self.append_html) ]) ) + + +class RichSelectInverseQuotes(RichSelect): + """Almost same as original, but uses alternative flatatt function. + + Uses inverse quotes. + """ + + def render(self, name, value, attrs=None): + if value is None: + value = '' + final_attrs = self.build_attrs(attrs, name=name) + output = [format_html( + '', + flatatt_inverse_quotes(final_attrs) + )] + options = self.render_options([value]) + if options: + output.append(options) + output.append('') + return mark_safe('\n'.join(output)) From fb205dcd3f4ec9dba3ff56b0a38b4654c325c3c9 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Tue, 1 Nov 2016 01:37:29 +0100 Subject: [PATCH 10/39] prepare 0.9.11; fixes --- CHANGELOG.rst | 6 +++++ setup.py | 2 +- src/fobi/__init__.py | 2 +- src/fobi/widgets.py | 62 ++++++++++++++++++++++++++++++++++---------- 4 files changed, 57 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9e55e9b5..afc8d757 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,12 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.9.11 +------ +2016-11-01 + +- Fixes. + 0.9.10 ------ 2016-11-01 diff --git a/setup.py b/setup.py index 984f0499..99575981 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.9.10' +version = '0.9.11' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index ab797b25..3f42cbaa 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,5 +1,5 @@ __title__ = 'django-fobi' -__version__ = '0.9.10' +__version__ = '0.9.11' __build__ = 0x00006c __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' diff --git a/src/fobi/widgets.py b/src/fobi/widgets.py index 2ab800d3..eb3aaaeb 100644 --- a/src/fobi/widgets.py +++ b/src/fobi/widgets.py @@ -3,6 +3,8 @@ from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ +from nine import versions + from .helpers import flatatt_inverse_quotes # Safe import of ``NumberInput`` @@ -106,17 +108,51 @@ class RichSelectInverseQuotes(RichSelect): Uses inverse quotes. """ + if versions.DJANGO_GTE_1_10: + def render(self, name, value, attrs=None): + if self.override_name is not None: + name = self.override_name - def render(self, name, value, attrs=None): - if value is None: - value = '' - final_attrs = self.build_attrs(attrs, name=name) - output = [format_html( - '', - flatatt_inverse_quotes(final_attrs) - )] - options = self.render_options([value]) - if options: - output.append(options) - output.append('') - return mark_safe('\n'.join(output)) + if value is None: + value = '' + final_attrs = self.build_attrs(attrs, name=name) + output = [ + format_html('', flatatt_inverse_quotes(final_attrs)) + ] + options = self.render_options([value]) + if options: + output.append(options) + output.append('') + rendered_select = mark_safe('\n'.join(output)) + + return mark_safe( + '\n'.join([ + format_html(self.prepend_html), + rendered_select, + format_html(self.append_html) + ]) + ) + else: + def render(self, name, value, attrs=None, choices=()): + if self.override_name is not None: + name = self.override_name + + if value is None: + value = '' + final_attrs = self.build_attrs(attrs, name=name) + output = [ + format_html('', flatatt_inverse_quotes(final_attrs)) + ] + options = self.render_options(choices, [value]) + if options: + output.append(options) + output.append('') + rendered_select = mark_safe('\n'.join(output)) + + return mark_safe( + '\n'.join([ + format_html(self.prepend_html), + rendered_select, + format_html(self.append_html) + ]) + ) From 77de5452fcdf13fff803ee30bc54007be755f9e5 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Wed, 2 Nov 2016 23:48:15 +0100 Subject: [PATCH 11/39] prepare 0.9.12; add missing feincms example migrations for django > 1.7; better debugging; minor fixes --- CHANGELOG.rst | 7 + docs/index.rst | 6 +- .../{feincms.txt => feincms_1_10.txt} | 0 examples/requirements/feincms_1_12.txt | 5 + .../simple/page/migrations/0001_initial.py | 237 ++++++++---------- .../page/south_migrations/0001_initial.py | 133 ++++++++++ ...language__add_field_page_translation_of.py | 0 ...to__add_richtextcontent__add_rawcontent.py | 0 ...form_template_name__add_field_fobiformw.py | 0 .../simple/page/south_migrations/__init__.py | 0 ...p3-theme-django-1-9-feincms_integration.sh | 1 + .../bootstrap3_theme_django_1_9_feincms.py | 30 +++ scripts/install_django_1_7_feincms.sh | 3 +- scripts/install_django_1_9_feincms.sh | 8 + scripts/reinstall_django_1_9_feincms.sh | 3 + setup.py | 2 +- src/fobi/__init__.py | 4 +- src/fobi/base.py | 46 ++-- src/fobi/models.py | 4 + src/fobi/views.py | 2 +- 20 files changed, 334 insertions(+), 157 deletions(-) rename examples/requirements/{feincms.txt => feincms_1_10.txt} (100%) create mode 100644 examples/requirements/feincms_1_12.txt create mode 100644 examples/simple/page/south_migrations/0001_initial.py rename examples/simple/page/{migrations => south_migrations}/0002_auto__add_field_page_language__add_field_page_translation_of.py (100%) rename examples/simple/page/{migrations => south_migrations}/0003_auto__add_richtextcontent__add_rawcontent.py (100%) rename examples/simple/page/{migrations => south_migrations}/0004_auto__add_field_fobiformwidget_form_template_name__add_field_fobiformw.py (100%) create mode 100644 examples/simple/page/south_migrations/__init__.py create mode 100755 examples/simple/runserver/bootstrap3-theme-django-1-9-feincms_integration.sh create mode 100644 examples/simple/settings/bootstrap3_theme_django_1_9_feincms.py create mode 100755 scripts/install_django_1_9_feincms.sh create mode 100755 scripts/reinstall_django_1_9_feincms.sh diff --git a/CHANGELOG.rst b/CHANGELOG.rst index afc8d757..db162389 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,13 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.9.12 +------ +2016-11-02 + +- Better debugging. +- Upgrade example FeinCMS integration to work with 1.12. + 0.9.11 ------ 2016-11-01 diff --git a/docs/index.rst b/docs/index.rst index 84d40669..54712daa 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1985,8 +1985,8 @@ element- and form handler- plugins. shown in case of missing form element handlers, set this to False in your settings module. Default value is True. -Tests -===== +Testing +======= Project is covered by test (functional- and browser-tests). To test type: @@ -2000,7 +2000,7 @@ install the test requirements: .. code:: sh - pip install -r examples/simple/requirements/common_test_requirements.txt + pip install -r examples/requirements/common_test_requirements.txt Selenium -------- diff --git a/examples/requirements/feincms.txt b/examples/requirements/feincms_1_10.txt similarity index 100% rename from examples/requirements/feincms.txt rename to examples/requirements/feincms_1_10.txt diff --git a/examples/requirements/feincms_1_12.txt b/examples/requirements/feincms_1_12.txt new file mode 100644 index 00000000..dc5b3403 --- /dev/null +++ b/examples/requirements/feincms_1_12.txt @@ -0,0 +1,5 @@ +-r django_1_9.txt + +FeinCMS==1.12.1 +django-mptt==0.8.6 +django-tinymce==2.4.0 diff --git a/examples/simple/page/migrations/0001_initial.py b/examples/simple/page/migrations/0001_initial.py index 7638ed71..04a0ac8d 100644 --- a/examples/simple/page/migrations/0001_initial.py +++ b/examples/simple/page/migrations/0001_initial.py @@ -1,133 +1,116 @@ # -*- coding: utf-8 -*- -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models +# Generated by Django 1.9.10 on 2016-10-17 20:45 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import feincms.contrib.richtext +import feincms.extensions.base +import feincms.module.mixins +import fobi.integration.processors -class Migration(SchemaMigration): +class Migration(migrations.Migration): - def forwards(self, orm): - # Adding model 'Page' - db.create_table(u'page_page', ( - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - (u'lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), - (u'rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), - (u'tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), - (u'level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), - ('active', self.gf('django.db.models.fields.BooleanField')(default=True)), - ('title', self.gf('django.db.models.fields.CharField')(max_length=200)), - ('slug', self.gf('django.db.models.fields.SlugField')(max_length=150)), - ('parent', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name=u'children', null=True, to=orm['page.Page'])), - ('in_navigation', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('override_url', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), - ('redirect_to', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), - ('_cached_url', self.gf('django.db.models.fields.CharField')(default=u'', max_length=255, db_index=True, blank=True)), - (u'template_key', self.gf('django.db.models.fields.CharField')(default='page_base', max_length=255)), - )) - db.send_create_signal(u'page', ['Page']) + initial = True - # Adding model 'FobiFormWidget' - db.create_table(u'page_page_fobiformwidget', ( - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('form_entry', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['fobi.FormEntry'])), - (u'parent', self.gf('django.db.models.fields.related.ForeignKey')(related_name=u'fobiformwidget_set', to=orm['page.Page'])), - (u'region', self.gf('django.db.models.fields.CharField')(max_length=255)), - (u'ordering', self.gf('django.db.models.fields.IntegerField')(default=0)), - )) - db.send_create_signal(u'page', ['FobiFormWidget']) + dependencies = [ + ('fobi', '0010_formwizardhandler'), + ] - - def backwards(self, orm): - # Deleting model 'Page' - db.delete_table(u'page_page') - - # Deleting model 'FobiFormWidget' - db.delete_table(u'page_page_fobiformwidget') - - - models = { - u'auth.group': { - 'Meta': {'object_name': 'Group'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - u'auth.permission': { - 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - u'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - u'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - u'fobi.formentry': { - 'Meta': {'unique_together': "(('user', 'slug'), ('user', 'name'))", 'object_name': 'FormEntry'}, - 'form_wizard_entry': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['fobi.FormWizardEntry']", 'null': 'True', 'blank': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_cloneable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'position': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}), - 'slug': ('autoslug.fields.AutoSlugField', [], {'unique': 'True', 'max_length': '50', 'populate_from': "'name'", 'unique_with': '()'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) - }, - u'fobi.formwizardentry': { - 'Meta': {'unique_together': "(('user', 'slug'), ('user', 'name'))", 'object_name': 'FormWizardEntry'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_cloneable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'slug': ('autoslug.fields.AutoSlugField', [], {'unique': 'True', 'max_length': '50', 'populate_from': "'name'", 'unique_with': '()'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) - }, - u'page.fobiformwidget': { - 'Meta': {'ordering': "[u'ordering']", 'object_name': 'FobiFormWidget', 'db_table': "u'page_page_fobiformwidget'"}, - 'form_entry': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['fobi.FormEntry']"}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - u'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - u'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'fobiformwidget_set'", 'to': u"orm['page.Page']"}), - u'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}) - }, - u'page.page': { - 'Meta': {'ordering': "[u'tree_id', u'lft']", 'object_name': 'Page'}, - '_cached_url': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True', 'blank': 'True'}), - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_navigation': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - u'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), - u'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), - 'override_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'children'", 'null': 'True', 'to': u"orm['page.Page']"}), - 'redirect_to': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), - u'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), - 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '150'}), - u'template_key': ('django.db.models.fields.CharField', [], {'default': "'page_base'", 'max_length': '255'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), - u'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) - } - } - - complete_apps = ['page'] \ No newline at end of file + operations = [ + migrations.CreateModel( + name='FobiFormWidget', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('form_template_name', models.CharField(blank=True, choices=[(b'fobi/bootstrap3_extras/view_embed_form_entry_ajax.html', b'Custom bootstrap3 embed form view template')], help_text='Template to render the form with.', max_length=255, null=True, verbose_name='Form template name')), + ('hide_form_title', models.BooleanField(default=False, help_text='If checked, no form title is shown.', verbose_name='Hide form title')), + ('form_title', models.CharField(blank=True, help_text='Overrides the default form title.', max_length=255, null=True, verbose_name='Form title')), + ('form_submit_button_text', models.CharField(blank=True, help_text='Overrides the default form submit button text.', max_length=255, null=True, verbose_name='Submit button text')), + ('success_page_template_name', models.CharField(blank=True, choices=[(b'fobi/bootstrap3_extras/embed_form_entry_submitted_ajax.html', b'Custom bootstrap3 embed form entry submitted template')], help_text='Template to render the success page with.', max_length=255, null=True, verbose_name='Success page template name')), + ('hide_success_page_title', models.BooleanField(default=False, help_text='If checked, no success page title is shown.', verbose_name='Hide success page title')), + ('success_page_title', models.CharField(blank=True, help_text='Overrides the default success page title.', max_length=255, null=True, verbose_name='Succes page title')), + ('success_page_text', models.TextField(blank=True, help_text='Overrides the default success page text.', null=True, verbose_name='Succes page text')), + ('region', models.CharField(max_length=255)), + ('ordering', models.IntegerField(default=0, verbose_name='ordering')), + ('form_entry', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fobi.FormEntry', verbose_name='Form')), + ], + options={ + 'ordering': ['ordering'], + 'abstract': False, + 'verbose_name_plural': 'fobi form widgets', + 'db_table': 'page_page_fobiformwidget', + 'verbose_name': 'fobi form widget', + 'permissions': [], + }, + bases=(models.Model, fobi.integration.processors.IntegrationProcessor), + ), + migrations.CreateModel( + name='Page', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('active', models.BooleanField(default=True, verbose_name='active')), + ('title', models.CharField(help_text='This title is also used for navigation menu items.', max_length=200, verbose_name='title')), + ('slug', models.SlugField(help_text='This is used to build the URL for this page', max_length=150, verbose_name='slug')), + ('in_navigation', models.BooleanField(default=False, verbose_name='in navigation')), + ('override_url', models.CharField(blank=True, help_text="Override the target URL. Be sure to include slashes at the beginning and at the end if it is a local URL. This affects both the navigation and subpages' URLs.", max_length=255, verbose_name='override URL')), + ('redirect_to', models.CharField(blank=True, help_text='Target URL for automatic redirects or the primary key of a page.', max_length=255, verbose_name='redirect to')), + ('_cached_url', models.CharField(blank=True, db_index=True, default='', editable=False, max_length=255, verbose_name='Cached URL')), + ('lft', models.PositiveIntegerField(db_index=True, editable=False)), + ('rght', models.PositiveIntegerField(db_index=True, editable=False)), + ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)), + ('level', models.PositiveIntegerField(db_index=True, editable=False)), + ('language', models.CharField(choices=[(b'en', b'English'), (b'hy', b'Armenian'), (b'nl', b'Dutch'), (b'ru', b'Russian'), (b'de', b'German')], default=b'en', max_length=10, verbose_name='language')), + ('template_key', models.CharField(choices=[(b'page_base', 'Base template')], default=b'page_base', max_length=255, verbose_name='template')), + ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='page.Page', verbose_name='Parent')), + ('translation_of', models.ForeignKey(blank=True, help_text='Leave this empty for entries in the primary language.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='translations', to='page.Page', verbose_name='translation of')), + ], + options={ + 'ordering': ['tree_id', 'lft'], + 'verbose_name': 'page', + 'verbose_name_plural': 'pages', + }, + bases=(models.Model, feincms.extensions.base.ExtensionsMixin, feincms.module.mixins.ContentModelMixin), + ), + migrations.CreateModel( + name='RawContent', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.TextField(blank=True, verbose_name='content')), + ('region', models.CharField(max_length=255)), + ('ordering', models.IntegerField(default=0, verbose_name='ordering')), + ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rawcontent_set', to='page.Page')), + ], + options={ + 'ordering': ['ordering'], + 'abstract': False, + 'verbose_name_plural': 'raw contents', + 'db_table': 'page_page_rawcontent', + 'verbose_name': 'raw content', + 'permissions': [], + }, + ), + migrations.CreateModel( + name='RichTextContent', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('region', models.CharField(max_length=255)), + ('ordering', models.IntegerField(default=0, verbose_name='ordering')), + ('text', feincms.contrib.richtext.RichTextField(blank=True, verbose_name='text')), + ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='richtextcontent_set', to='page.Page')), + ], + options={ + 'ordering': ['ordering'], + 'abstract': False, + 'verbose_name_plural': 'rich texts', + 'db_table': 'page_page_richtextcontent', + 'verbose_name': 'rich text', + 'permissions': [], + }, + ), + migrations.AddField( + model_name='fobiformwidget', + name='parent', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='fobiformwidget_set', to='page.Page'), + ), + ] diff --git a/examples/simple/page/south_migrations/0001_initial.py b/examples/simple/page/south_migrations/0001_initial.py new file mode 100644 index 00000000..7638ed71 --- /dev/null +++ b/examples/simple/page/south_migrations/0001_initial.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Page' + db.create_table(u'page_page', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + (u'lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + (u'rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + (u'tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + (u'level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)), + ('active', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=200)), + ('slug', self.gf('django.db.models.fields.SlugField')(max_length=150)), + ('parent', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name=u'children', null=True, to=orm['page.Page'])), + ('in_navigation', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('override_url', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('redirect_to', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('_cached_url', self.gf('django.db.models.fields.CharField')(default=u'', max_length=255, db_index=True, blank=True)), + (u'template_key', self.gf('django.db.models.fields.CharField')(default='page_base', max_length=255)), + )) + db.send_create_signal(u'page', ['Page']) + + # Adding model 'FobiFormWidget' + db.create_table(u'page_page_fobiformwidget', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('form_entry', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['fobi.FormEntry'])), + (u'parent', self.gf('django.db.models.fields.related.ForeignKey')(related_name=u'fobiformwidget_set', to=orm['page.Page'])), + (u'region', self.gf('django.db.models.fields.CharField')(max_length=255)), + (u'ordering', self.gf('django.db.models.fields.IntegerField')(default=0)), + )) + db.send_create_signal(u'page', ['FobiFormWidget']) + + + def backwards(self, orm): + # Deleting model 'Page' + db.delete_table(u'page_page') + + # Deleting model 'FobiFormWidget' + db.delete_table(u'page_page_fobiformwidget') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'fobi.formentry': { + 'Meta': {'unique_together': "(('user', 'slug'), ('user', 'name'))", 'object_name': 'FormEntry'}, + 'form_wizard_entry': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['fobi.FormWizardEntry']", 'null': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_cloneable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'position': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'slug': ('autoslug.fields.AutoSlugField', [], {'unique': 'True', 'max_length': '50', 'populate_from': "'name'", 'unique_with': '()'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'fobi.formwizardentry': { + 'Meta': {'unique_together': "(('user', 'slug'), ('user', 'name'))", 'object_name': 'FormWizardEntry'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_cloneable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'slug': ('autoslug.fields.AutoSlugField', [], {'unique': 'True', 'max_length': '50', 'populate_from': "'name'", 'unique_with': '()'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}) + }, + u'page.fobiformwidget': { + 'Meta': {'ordering': "[u'ordering']", 'object_name': 'FobiFormWidget', 'db_table': "u'page_page_fobiformwidget'"}, + 'form_entry': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['fobi.FormEntry']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + u'ordering': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + u'parent': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "u'fobiformwidget_set'", 'to': u"orm['page.Page']"}), + u'region': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + u'page.page': { + 'Meta': {'ordering': "[u'tree_id', u'lft']", 'object_name': 'Page'}, + '_cached_url': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True', 'blank': 'True'}), + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'in_navigation': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + u'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'override_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'children'", 'null': 'True', 'to': u"orm['page.Page']"}), + 'redirect_to': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + u'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '150'}), + u'template_key': ('django.db.models.fields.CharField', [], {'default': "'page_base'", 'max_length': '255'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + u'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + } + } + + complete_apps = ['page'] \ No newline at end of file diff --git a/examples/simple/page/migrations/0002_auto__add_field_page_language__add_field_page_translation_of.py b/examples/simple/page/south_migrations/0002_auto__add_field_page_language__add_field_page_translation_of.py similarity index 100% rename from examples/simple/page/migrations/0002_auto__add_field_page_language__add_field_page_translation_of.py rename to examples/simple/page/south_migrations/0002_auto__add_field_page_language__add_field_page_translation_of.py diff --git a/examples/simple/page/migrations/0003_auto__add_richtextcontent__add_rawcontent.py b/examples/simple/page/south_migrations/0003_auto__add_richtextcontent__add_rawcontent.py similarity index 100% rename from examples/simple/page/migrations/0003_auto__add_richtextcontent__add_rawcontent.py rename to examples/simple/page/south_migrations/0003_auto__add_richtextcontent__add_rawcontent.py diff --git a/examples/simple/page/migrations/0004_auto__add_field_fobiformwidget_form_template_name__add_field_fobiformw.py b/examples/simple/page/south_migrations/0004_auto__add_field_fobiformwidget_form_template_name__add_field_fobiformw.py similarity index 100% rename from examples/simple/page/migrations/0004_auto__add_field_fobiformwidget_form_template_name__add_field_fobiformw.py rename to examples/simple/page/south_migrations/0004_auto__add_field_fobiformwidget_form_template_name__add_field_fobiformw.py diff --git a/examples/simple/page/south_migrations/__init__.py b/examples/simple/page/south_migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/examples/simple/runserver/bootstrap3-theme-django-1-9-feincms_integration.sh b/examples/simple/runserver/bootstrap3-theme-django-1-9-feincms_integration.sh new file mode 100755 index 00000000..da4363f1 --- /dev/null +++ b/examples/simple/runserver/bootstrap3-theme-django-1-9-feincms_integration.sh @@ -0,0 +1 @@ +./manage.py runserver 0.0.0.0:8000 --traceback -v 3 --settings=settings.bootstrap3_theme_django_1_7_feincms --traceback -v 3 diff --git a/examples/simple/settings/bootstrap3_theme_django_1_9_feincms.py b/examples/simple/settings/bootstrap3_theme_django_1_9_feincms.py new file mode 100644 index 00000000..032a0ba0 --- /dev/null +++ b/examples/simple/settings/bootstrap3_theme_django_1_9_feincms.py @@ -0,0 +1,30 @@ +from .base import * + +INSTALLED_APPS = list(INSTALLED_APPS) + +try: + INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None + # INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.dashboard') \ + if 'admin_tools.dashboard' in INSTALLED_APPS \ + else None + + INSTALLED_APPS += [ + 'feincms', # FeinCMS + + 'fobi.contrib.apps.feincms_integration', # Fobi FeinCMS app + + 'page', # Example + ] +except Exception as e: + pass + + +FEINCMS_RICHTEXT_INIT_CONTEXT = { + 'TINYMCE_JS_URL': STATIC_URL + 'tiny_mce/tiny_mce.js', +} + +MIGRATION_MODULES = { + 'fobi': 'fobi.migrations', + 'db_store': 'fobi.contrib.plugins.form_handlers.db_store.migrations', +} diff --git a/scripts/install_django_1_7_feincms.sh b/scripts/install_django_1_7_feincms.sh index 758bba07..8dac1868 100755 --- a/scripts/install_django_1_7_feincms.sh +++ b/scripts/install_django_1_7_feincms.sh @@ -1,5 +1,4 @@ -#pip install -r examples/requirements/django_1_7.txt -pip install -r examples/requirements/feincms.txt +pip install -r examples/requirements/feincms_1_10.txt python setup.py install mkdir -p examples/logs examples/db examples/media examples/media/static examples/media/fobi_plugins/content_image mkdir -p examples/media/fobi_plugins/file diff --git a/scripts/install_django_1_9_feincms.sh b/scripts/install_django_1_9_feincms.sh new file mode 100755 index 00000000..c7322d41 --- /dev/null +++ b/scripts/install_django_1_9_feincms.sh @@ -0,0 +1,8 @@ +pip install -r examples/requirements/feincms_1_12.txt +python setup.py install +mkdir -p examples/logs examples/db examples/media examples/media/static examples/media/fobi_plugins/content_image +mkdir -p examples/media/fobi_plugins/file +python examples/simple/manage.py collectstatic --noinput --settings=settings.bootstrap3_theme_django_1_9_feincms --traceback -v 3 +python examples/simple/manage.py syncdb --noinput --settings=settings.bootstrap3_theme_django_1_9_feincms --traceback -v 3 +python examples/simple/manage.py migrate --noinput --settings=settings.bootstrap3_theme_django_1_9_feincms --traceback -v 3 +python examples/simple/manage.py fobi_create_test_data --settings=settings.bootstrap3_theme_django_1_9_feincms --traceback -v 3 diff --git a/scripts/reinstall_django_1_9_feincms.sh b/scripts/reinstall_django_1_9_feincms.sh new file mode 100755 index 00000000..e1a1e115 --- /dev/null +++ b/scripts/reinstall_django_1_9_feincms.sh @@ -0,0 +1,3 @@ +reset +./scripts/uninstall.sh +./scripts/install_django_1_9_feincms.sh \ No newline at end of file diff --git a/setup.py b/setup.py index 99575981..2611d186 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.9.11' +version = '0.9.12' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index 3f42cbaa..82177d4f 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.9.11' -__build__ = 0x00006c +__version__ = '0.9.12' +__build__ = 0x00006d __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/base.py b/src/fobi/base.py index 9481bf63..7f3edacf 100644 --- a/src/fobi/base.py +++ b/src/fobi/base.py @@ -1055,15 +1055,13 @@ class BasePlugin(object): plugin_form = self.get_form() if plugin_form: try: - plugin_form = self.get_form() - if plugin_form: - kwargs = { - 'data': data, - 'files': files, - } - if initial_data: - kwargs.update({'initial': initial_data}) - return plugin_form(**kwargs) + kwargs = { + 'data': data, + 'files': files, + } + if initial_data: + kwargs.update({'initial': initial_data}) + return plugin_form(**kwargs) except Exception as e: if DEBUG: logger.debug(e) @@ -1610,24 +1608,30 @@ class FormHandlerPlugin(BasePlugin): if not form_element_entries: form_element_entries = form_entry.formelemententry_set.all()[:] - try: + if FAIL_ON_ERRORS_IN_FORM_HANDLER_PLUGINS: response = self.run(form_entry, request, form, form_element_entries) if response: return response else: return (True, None) - except Exception as err: - if FAIL_ON_ERRORS_IN_FORM_HANDLER_PLUGINS: - raise err.__class__("Exception: {0}. {1}" - "".format(str(err), - traceback.format_exc())) - logger.error( - "Error in class {0}. Details: " - "{1}. Full trace: {2}".format(self.__class__.__name__, - str(err), traceback.format_exc()) - ) - return (False, err) + else: + try: + response = self.run(form_entry, request, form, + form_element_entries) + if response: + return response + else: + return (True, None) + except Exception as err: + logger.error( + "Error in class {0}. Details: " + "{1}. Full trace: {2}".format( + self.__class__.__name__, + str(err), traceback.format_exc() + ) + ) + return (False, err) def run(self, form_entry, request, form, form_element_entries=None): """Run. diff --git a/src/fobi/models.py b/src/fobi/models.py index 21195027..71516b65 100644 --- a/src/fobi/models.py +++ b/src/fobi/models.py @@ -387,6 +387,7 @@ class FormEntry(models.Model): return reverse('fobi.view_form_entry', kwargs={'slug': self.slug}) +@python_2_unicode_compatible class FormWizardFormEntry(models.Model): """Form wizard form entry. @@ -410,6 +411,9 @@ class FormWizardFormEntry(models.Model): ordering = ['position'] unique_together = (('form_wizard_entry', 'form_entry'),) + def __str__(self): + return "{0} - {1}".format(self.form_wizard_entry, self.form_entry) + @python_2_unicode_compatible class FormFieldsetEntry(models.Model): diff --git a/src/fobi/views.py b/src/fobi/views.py index 67b26724..b6f94820 100644 --- a/src/fobi/views.py +++ b/src/fobi/views.py @@ -669,7 +669,7 @@ def add_form_element_entry(request, 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. From 0512850415ce0ff97768a8cd74bacfead345a54b Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Sat, 5 Nov 2016 23:34:51 +0100 Subject: [PATCH 12/39] prepare 0.9.13; minor backwards compatibility changes of slider and range_select plugins with django versions 1.5 and 1.6; announcing dropping of support for those versions --- CHANGELOG.rst | 11 +++++++++++ setup.py | 2 +- src/fobi/__init__.py | 4 ++-- src/fobi/base.py | 5 +++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index db162389..e6f936e0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,17 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.9.13 +------ +2016-11-05 + +Officially announcing dropping support for Django 1.5 and 1.6. At the +moment everything is still backwards compatible with versions 1.5 and 1.6, +but in future versions compatibility with those versions would be wiped out. + +- Fix backwards compatibility of `slider` and `range_select` plugins with + Django versions 1.5 and 1.6. + 0.9.12 ------ 2016-11-02 diff --git a/setup.py b/setup.py index 2611d186..ab503e37 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.9.12' +version = '0.9.13' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index 82177d4f..a46e9bcd 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.9.12' -__build__ = 0x00006d +__version__ = '0.9.13' +__build__ = 0x00006e __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/base.py b/src/fobi/base.py index 7f3edacf..f5d5ac65 100644 --- a/src/fobi/base.py +++ b/src/fobi/base.py @@ -787,6 +787,11 @@ class BaseFormFieldPluginForm(BasePluginForm): return True + if not DJANGO_GTE_1_7: + def add_error(self, field, error): + """Backwards compatibility hack.""" + raise forms.ValidationError(error, 'invalid') + # ***************************************************************************** # ***************************************************************************** # ******************************** Plugins ************************************ From cb5ce7f5d22d7ec1f8cc4d60b32847e20a0072c9 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Mon, 7 Nov 2016 22:41:52 +0100 Subject: [PATCH 13/39] prepare 0.9.14; minor fixes --- CHANGELOG.rst | 6 ++++ setup.py | 2 +- src/fobi/__init__.py | 4 +-- .../content/content_text/conf.py | 34 +++++++++++++++++++ .../content/content_text/defaults.py | 28 +++++++++++++++ .../content/content_text/settings.py | 13 +++++++ 6 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 src/fobi/contrib/plugins/form_elements/content/content_text/conf.py create mode 100644 src/fobi/contrib/plugins/form_elements/content/content_text/defaults.py create mode 100644 src/fobi/contrib/plugins/form_elements/content/content_text/settings.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e6f936e0..25698c82 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,12 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.9.14 +------ +2016-11-07 + +- Minor fixes. + 0.9.13 ------ 2016-11-05 diff --git a/setup.py b/setup.py index ab503e37..3403f4f5 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.9.13' +version = '0.9.14' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index a46e9bcd..c5b6fd4b 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.9.13' -__build__ = 0x00006e +__version__ = '0.9.14' +__build__ = 0x00006f __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/contrib/plugins/form_elements/content/content_text/conf.py b/src/fobi/contrib/plugins/form_elements/content/content_text/conf.py new file mode 100644 index 00000000..e0ddb414 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/content/content_text/conf.py @@ -0,0 +1,34 @@ +from django.conf import settings + +from . import defaults + +__title__ = 'fobi.contrib.plugins.form_elements.content.content_text.conf' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('get_setting',) + + +def get_setting(setting, override=None): + """Get setting. + + Get a setting from + ``fobi.contrib.plugins.form_elements.content.content_text`` conf module, + falling back to the default. + + If override is not None, it will be used instead of the setting. + + :param setting: String with setting name + :param override: Value to use when no setting is available. Defaults to + None. + :return: Setting value. + """ + if override is not None: + return override + if hasattr(settings, 'FOBI_PLUGIN_CONTENT_TEXT_{0}'.format(setting)): + return getattr( + settings, + 'FOBI_PLUGIN_CONTENT_TEXT_{0}'.format(setting) + ) + else: + return getattr(defaults, setting) diff --git a/src/fobi/contrib/plugins/form_elements/content/content_text/defaults.py b/src/fobi/contrib/plugins/form_elements/content/content_text/defaults.py new file mode 100644 index 00000000..920920f1 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/content/content_text/defaults.py @@ -0,0 +1,28 @@ +__title__ = 'fobi.contrib.plugins.form_elements.content.content_text.defaults' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ( + 'ALLOWED_TAGS', + 'ALLOWED_ATTRIBUTES', +) + +ALLOWED_TAGS = [ + 'a', + 'abbr', + 'acronym', + 'b', + 'blockquote', + 'code', + 'em', + 'i', + 'li', + 'ol', + 'strong', + 'ul', +] + +ALLOWED_ATTRIBUTES = { + 'a': ['href', 'title'], + 'img': ['src'] +} diff --git a/src/fobi/contrib/plugins/form_elements/content/content_text/settings.py b/src/fobi/contrib/plugins/form_elements/content/content_text/settings.py new file mode 100644 index 00000000..4d3ff635 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/content/content_text/settings.py @@ -0,0 +1,13 @@ +from .conf import get_setting + +__title__ = 'fobi.contrib.plugins.form_elements.content.content_text.settings' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ( + 'ALLOWED_TAGS', + 'ALLOWED_ATTRIBUTES', +) + +ALLOWED_TAGS = get_setting('ALLOWED_TAGS') +ALLOWED_ATTRIBUTES = get_setting('ALLOWED_ATTRIBUTES') From 8e937ab0f52145283c4b229ced0bd293e93eed6e Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Mon, 7 Nov 2016 22:46:10 +0100 Subject: [PATCH 14/39] 0.9.14; add missing files --- .../content/content_text/README.rst | 39 +++++++++++++++++++ .../content/content_text/forms.py | 22 +++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst b/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst index ac981477..e7248238 100644 --- a/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst +++ b/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst @@ -24,3 +24,42 @@ Installation 3. Assign appropriate permissions to the target users/groups to be using the plugin if ``FOBI_RESTRICT_PLUGIN_ACCESS`` is set to True. + +4. Additionally, for the fine tuning, see the + ``fobi.contrib.plugins.form_elements.content.content_text.defaults`` + module. If necessary, override the settings by prepending + ``FOBI_PLUGIN_CONTENT_TEXT_`` to the desired variable name from the + above mentioned ``defaults`` module. + + By default the text field is stripped (using the awesome `bleach + `_ library. To configure the strip + behaviour, two settings are introduced: + +.. code-block:: text + + - ALLOWED_TAGS: + - ALLOWED_ATTRIBUTES: + +The default values are: + +.. code-block:: python + + ALLOWED_TAGS = [ + 'a', + 'abbr', + 'acronym', + 'b', + 'blockquote', + 'code', + 'em', + 'i', + 'li', + 'ol', + 'strong', + 'ul', + ] + + ALLOWED_ATTRIBUTES = { + 'a': ['href', 'title'], + 'img': ['src'] + } diff --git a/src/fobi/contrib/plugins/form_elements/content/content_text/forms.py b/src/fobi/contrib/plugins/form_elements/content/content_text/forms.py index b23de7fc..71559d4f 100644 --- a/src/fobi/contrib/plugins/form_elements/content/content_text/forms.py +++ b/src/fobi/contrib/plugins/form_elements/content/content_text/forms.py @@ -1,9 +1,18 @@ from django import forms from django.forms.widgets import Textarea +from django.utils.html import strip_tags from django.utils.translation import ugettext_lazy as _ from fobi.base import BasePluginForm, get_theme +from .settings import ALLOWED_TAGS, ALLOWED_ATTRIBUTES + +try: + import bleach + BLEACH_INSTALLED = True +except ImportError as err: + BLEACH_INSTALLED = False + __title__ = 'fobi.contrib.plugins.form_elements.content.content_text.forms' __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' @@ -26,3 +35,16 @@ class ContentTextForm(forms.Form, BasePluginForm): required=True, widget=Textarea(attrs={'class': theme.form_element_html_class}) ) + + def clean_text(self): + """Clean text value.""" + if BLEACH_INSTALLED: + return bleach.clean( + text=self.cleaned_data['text'], + tags=ALLOWED_TAGS, + attributes=ALLOWED_ATTRIBUTES, + strip=True, + strip_comments=True + ) + else: + return strip_tags(self.cleaned_data['text']) From bae4e1477a0ebc4442e25ac3a5d1328abf105c5e Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Mon, 7 Nov 2016 22:48:33 +0100 Subject: [PATCH 15/39] readme update --- .../plugins/form_elements/content/content_text/README.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst b/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst index e7248238..11ee8167 100644 --- a/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst +++ b/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst @@ -31,9 +31,10 @@ Installation ``FOBI_PLUGIN_CONTENT_TEXT_`` to the desired variable name from the above mentioned ``defaults`` module. - By default the text field is stripped (using the awesome `bleach - `_ library. To configure the strip - behaviour, two settings are introduced: + By default the text field is stripped using the either the awesome `bleach + `_ library or if bleach is not installed + just Django's own `strip_tags` function. To configure the strip behaviour, + two settings are introduced: .. code-block:: text From f2e223d4b44ee8c5980785ea634ca7e294aac4ac Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Mon, 7 Nov 2016 23:02:31 +0100 Subject: [PATCH 16/39] mark completed todos as done --- TODOS.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/TODOS.rst b/TODOS.rst index a8341c5d..469ff7ab 100644 --- a/TODOS.rst +++ b/TODOS.rst @@ -34,7 +34,7 @@ Regarding the form wizards + Ideally, it would be great to support data-slider-handle="square" (or "round", "triangle") options of the bootstrap-slider plugin. See the first issue in "Uncategorised". -- Rethink the new navigation of forms and form wizards. ++ Rethink the new navigation of forms and form wizards. - Add support for form wizard conditions. + Fixed broken dependencies for docs. - Add FeinCMS integration app for form wizards. @@ -55,7 +55,7 @@ Roadmap Uncategorised ------------- - Rethink templating of the integration packages (feincms_integration, - djangocms_integration, mezzanine_intergration), as now they are a bit + djangocms_integration, mezzanine_integration), as now they are a bit of a mess. Document integration properly, if not yet done. - Add tests for import/export of forms. - Add tests for export of plugin data (db_store). @@ -106,9 +106,9 @@ Uncategorised validation method there, which accepts the request, the form and the form_entry object for validation. Also, in the BaseFormFieldPlugin, there should be `name`, `required`, `help_text`, `label` fields to be present ( - scheck other fields of Django formfield). In formfield plugins, subclass + check other fields of Django formfield). In formfield plugins, subclass from BaseFormFieldPlugin, instead of the BaseFormElementPlugin. -+ In the view, validate the form fields (if they are sublcass of ++ In the view, validate the form fields (if they are subclass of BaseFormFieldPlugin). + Actually, if plugin doesn't have a form, save it immediately. Do not wait for POST. @@ -308,7 +308,7 @@ Uncategorised + Check if it's safe to use the initial dynamic values. + In the updated GUI (bootstrap3), if form names are too long, the layout doesn't look nice anymore. -- Somehow, the drag and drop of the form elements got broken. Fix ASAP. ++ Somehow, the drag and drop of the form elements got broken. Fix ASAP. - Since tests have been made quite general, create them for all contrib form elements and handlers (not yet for things like CAPTCHA). - Translate German and Russian URLs. From 8660591e8f5132d73855e96e3ffaf7e53f09d1d9 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Mon, 7 Nov 2016 23:40:01 +0100 Subject: [PATCH 17/39] prepare 0.9.15; minor fixes --- CHANGELOG.rst | 6 ++++++ setup.py | 2 +- src/fobi/__init__.py | 4 ++-- .../plugins/form_elements/content/content_text/defaults.py | 5 +++-- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 25698c82..682c5903 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,12 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.9.15 +------ +2016-11-07 + +- Minor fixes. + 0.9.14 ------ 2016-11-07 diff --git a/setup.py b/setup.py index 3403f4f5..5d02cada 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.9.14' +version = '0.9.15' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index c5b6fd4b..6211ff44 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.9.14' -__build__ = 0x00006f +__version__ = '0.9.15' +__build__ = 0x000070 __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/contrib/plugins/form_elements/content/content_text/defaults.py b/src/fobi/contrib/plugins/form_elements/content/content_text/defaults.py index 920920f1..233e87f4 100644 --- a/src/fobi/contrib/plugins/form_elements/content/content_text/defaults.py +++ b/src/fobi/contrib/plugins/form_elements/content/content_text/defaults.py @@ -4,7 +4,7 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ( 'ALLOWED_TAGS', - 'ALLOWED_ATTRIBUTES', + 'ALLOWED_TAGS', ) ALLOWED_TAGS = [ @@ -24,5 +24,6 @@ ALLOWED_TAGS = [ ALLOWED_ATTRIBUTES = { 'a': ['href', 'title'], - 'img': ['src'] + 'abbr': ['title'], + 'acronym': ['title'], } From 6c098d59adcee1a84021d1dfc798afa66ce03c35 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Tue, 8 Nov 2016 09:19:20 +0100 Subject: [PATCH 18/39] Update README.rst --- .../form_elements/content/content_text/README.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst b/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst index 11ee8167..b773461b 100644 --- a/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst +++ b/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst @@ -31,10 +31,10 @@ Installation ``FOBI_PLUGIN_CONTENT_TEXT_`` to the desired variable name from the above mentioned ``defaults`` module. - By default the text field is stripped using the either the awesome `bleach - `_ library or if bleach is not installed - just Django's own `strip_tags` function. To configure the strip behaviour, - two settings are introduced: + By default the content of the text field is stripped using either the + awesome `bleach `_ library or if bleach + is not installed just Django's own `strip_tags` function. To configure + the strip (bleach only)behaviour, two settings are introduced: .. code-block:: text @@ -62,5 +62,6 @@ The default values are: ALLOWED_ATTRIBUTES = { 'a': ['href', 'title'], - 'img': ['src'] + 'abbr': ['title'], + 'acronym': ['title'], } From 51eae155e854086c3f81acab165ee4ff2370df84 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Tue, 8 Nov 2016 09:20:10 +0100 Subject: [PATCH 19/39] Update README.rst --- .../plugins/form_elements/content/content_text/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst b/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst index b773461b..5f7354a6 100644 --- a/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst +++ b/src/fobi/contrib/plugins/form_elements/content/content_text/README.rst @@ -34,7 +34,7 @@ Installation By default the content of the text field is stripped using either the awesome `bleach `_ library or if bleach is not installed just Django's own `strip_tags` function. To configure - the strip (bleach only)behaviour, two settings are introduced: + the strip (bleach only) behaviour, two settings are introduced: .. code-block:: text From 936393db3699b049a7d0123d5fc14acffa0eecbb Mon Sep 17 00:00:00 2001 From: Marcos Amorim Date: Wed, 9 Nov 2016 16:21:45 +0000 Subject: [PATCH 20/39] Verify if min/max are a valid range and if initial is inside that range --- .../form_elements/fields/decimal/forms.py | 29 +++++++++++++++++++ .../form_elements/fields/float/forms.py | 29 +++++++++++++++++++ .../form_elements/fields/integer/forms.py | 29 +++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/src/fobi/contrib/plugins/form_elements/fields/decimal/forms.py b/src/fobi/contrib/plugins/form_elements/fields/decimal/forms.py index 9f955199..468bc902 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/decimal/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/decimal/forms.py @@ -91,3 +91,32 @@ class DecimalInputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_html_class} ) ) + + def clean(self): + """Validating the values.""" + super(DecimalInputForm, self).clean() + + max_value = self.cleaned_data['max_value'] + min_value = self.cleaned_data['min_value'] + initial = self.cleaned_data['initial'] + + if ( + max_value is not None and min_value is not None and + max_value < min_value + ): + self.add_error( + 'max_value', + _("`max_value` should be > than `min_value`.") + ) + + if max_value is not None and initial and max_value < initial: + self.add_error( + 'initial', + _("`max_value` should be >= than `initial`.") + ) + + if min_value is not None and initial and min_value > initial: + self.add_error( + 'min_value', + _("`initial` should be >= than `min_value`.") + ) diff --git a/src/fobi/contrib/plugins/form_elements/fields/float/forms.py b/src/fobi/contrib/plugins/form_elements/fields/float/forms.py index ec469d87..a52c3eb7 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/float/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/float/forms.py @@ -77,3 +77,32 @@ class FloatInputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_html_class} ) ) + + def clean(self): + """Validating the values.""" + super(FloatInputForm, self).clean() + + max_value = self.cleaned_data['max_value'] + min_value = self.cleaned_data['min_value'] + initial = self.cleaned_data['initial'] + + if ( + max_value is not None and min_value is not None and + max_value < min_value + ): + self.add_error( + 'max_value', + _("`max_value` should be > than `min_value`.") + ) + + if max_value is not None and initial and max_value < initial: + self.add_error( + 'initial', + _("`max_value` should be >= than `initial`.") + ) + + if min_value is not None and initial and min_value > initial: + self.add_error( + 'min_value', + _("`initial` should be >= than `min_value`.") + ) diff --git a/src/fobi/contrib/plugins/form_elements/fields/integer/forms.py b/src/fobi/contrib/plugins/form_elements/fields/integer/forms.py index 9d4ee8ed..47e9bb21 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/integer/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/integer/forms.py @@ -77,3 +77,32 @@ class IntegerInputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_html_class} ) ) + + def clean(self): + """Validating the values.""" + super(IntegerInputForm, self).clean() + + max_value = self.cleaned_data['max_value'] + min_value = self.cleaned_data['min_value'] + initial = self.cleaned_data['initial'] + + if ( + max_value is not None and min_value is not None and + max_value < min_value + ): + self.add_error( + 'max_value', + _("`max_value` should be > than `min_value`.") + ) + + if max_value is not None and initial and max_value < initial: + self.add_error( + 'initial', + _("`max_value` should be >= than `initial`.") + ) + + if min_value is not None and initial and min_value > initial: + self.add_error( + 'min_value', + _("`initial` should be >= than `min_value`.") + ) From 369c2b620f89ce055f11d6423ae1332e713b507e Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 10 Nov 2016 01:44:33 +0100 Subject: [PATCH 21/39] prepare 0.9.16; introduced form titles shown in the templates; improved navigation of the form wizards --- CHANGELOG.rst | 7 ++++ examples/requirements/common_python2.txt | 1 - examples/requirements/django_1_10.txt | 1 + examples/requirements/django_1_5.txt | 1 + examples/requirements/django_1_6.txt | 1 + examples/requirements/django_1_7.txt | 1 + examples/requirements/django_1_8.txt | 1 + examples/requirements/django_1_9.txt | 3 +- examples/simple/settings/base.py | 11 +++-- .../simple/settings/local_settings.example | 3 ++ examples/simple/settings/test.py | 2 + pytest.ini | 18 ++++++++ runtests.py | 14 +++++++ scripts/make_migrations.sh | 9 ++++ setup.py | 2 +- src/fobi/__init__.py | 4 +- .../checkbox_select_multiple/README.rst | 2 +- .../form_elements/fields/slider/README.rst | 28 ++++++------- .../bootstrap3/snippets/form_wizard_ajax.html | 42 ++++++++++++++++++- src/fobi/forms.py | 19 +++++++-- src/fobi/integration/processors.py | 6 ++- src/fobi/migrations/0011_formentry_title.py | 20 +++++++++ .../migrations/0012_auto_20161109_1550.py | 25 +++++++++++ ...wizardentry_show_all_navigation_buttons.py | 20 +++++++++ src/fobi/models.py | 15 +++++-- .../generic/snippets/form_wizard_ajax.html | 7 +++- .../snippets/form_wizard_view_ajax.html | 1 + .../fobi/generic/view_form_entry.html | 2 +- .../fobi/generic/view_form_wizard_entry.html | 2 +- .../generic/view_form_wizard_entry_ajax.html | 2 +- src/fobi/views.py | 29 ++++++++++--- 31 files changed, 257 insertions(+), 42 deletions(-) create mode 100644 pytest.ini create mode 100644 runtests.py create mode 100755 scripts/make_migrations.sh create mode 100644 src/fobi/migrations/0011_formentry_title.py create mode 100644 src/fobi/migrations/0012_auto_20161109_1550.py create mode 100644 src/fobi/migrations/0013_formwizardentry_show_all_navigation_buttons.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 682c5903..41fc03a4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,13 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.9.16 +------ +2016-11-10 + +- Introduced form titles (shown in view templates). +- Improved navigation of the form wizards. + 0.9.15 ------ 2016-11-07 diff --git a/examples/requirements/common_python2.txt b/examples/requirements/common_python2.txt index 173a05bd..8a64c212 100644 --- a/examples/requirements/common_python2.txt +++ b/examples/requirements/common_python2.txt @@ -31,7 +31,6 @@ six==1.10.0 snowballstemmer==1.2.0 Sphinx==1.3.1 sphinx-rtd-theme==0.1.9 -sqlparse==0.1.17 traitlets==4.0.0 #Unidecode==0.4.18 virtualenv==13.1.2 diff --git a/examples/requirements/django_1_10.txt b/examples/requirements/django_1_10.txt index fbdbfad2..cb2d975c 100644 --- a/examples/requirements/django_1_10.txt +++ b/examples/requirements/django_1_10.txt @@ -10,3 +10,4 @@ django-debug-toolbar==1.5 django-registration-redux>=1.4 #easy-thumbnails==2.3 #vishap>=0.1.5 +sqlparse==0.2.2 diff --git a/examples/requirements/django_1_5.txt b/examples/requirements/django_1_5.txt index 3f60da62..d671e119 100644 --- a/examples/requirements/django_1_5.txt +++ b/examples/requirements/django_1_5.txt @@ -11,3 +11,4 @@ django-localeurl>=2.0.2 django-registration-redux==1.2 #easy-thumbnails==2.3 #vishap>=0.1.5 +sqlparse==0.1.9 diff --git a/examples/requirements/django_1_6.txt b/examples/requirements/django_1_6.txt index 71effcf5..9213495c 100644 --- a/examples/requirements/django_1_6.txt +++ b/examples/requirements/django_1_6.txt @@ -11,3 +11,4 @@ django-localeurl>=2.0.2 django-registration-redux==1.2 #easy-thumbnails==2.3 #vishap>=0.1.5 +sqlparse==0.1.9 diff --git a/examples/requirements/django_1_7.txt b/examples/requirements/django_1_7.txt index fc1bd010..1d7dc808 100644 --- a/examples/requirements/django_1_7.txt +++ b/examples/requirements/django_1_7.txt @@ -10,3 +10,4 @@ django-localeurl>=2.0.2 django-registration-redux==1.3 #easy-thumbnails==2.3 #vishap>=0.1.5 +sqlparse==0.1.9 \ No newline at end of file diff --git a/examples/requirements/django_1_8.txt b/examples/requirements/django_1_8.txt index d273f90c..47223f35 100644 --- a/examples/requirements/django_1_8.txt +++ b/examples/requirements/django_1_8.txt @@ -11,3 +11,4 @@ django-formtools django-registration-redux>=1.4 #easy-thumbnails==2.3 #vishap>=0.1.5 +sqlparse==0.1.9 \ No newline at end of file diff --git a/examples/requirements/django_1_9.txt b/examples/requirements/django_1_9.txt index 197fa953..0f7a1757 100644 --- a/examples/requirements/django_1_9.txt +++ b/examples/requirements/django_1_9.txt @@ -3,7 +3,7 @@ Django>=1.9,<1.10 django-admin-tools>=0.7.1 django-autoslug==1.9.3 -django-debug-toolbar==0.11.0 +django-debug-toolbar==1.5 django-formtools==1.0 django-localeurl==2.0.2 django-nine>=0.1.10 @@ -11,3 +11,4 @@ django-nonefield>=0.1 django-registration-redux>=1.4 easy-thumbnails==2.3 vishap>=0.1.5 +sqlparse==0.2.2 \ No newline at end of file diff --git a/examples/simple/settings/base.py b/examples/simple/settings/base.py index 96aadfdc..58415c6a 100644 --- a/examples/simple/settings/base.py +++ b/examples/simple/settings/base.py @@ -105,6 +105,11 @@ STATICFILES_FINDERS = ( # Make this unique, and don't share it with anybody. SECRET_KEY = '97818c*w97Zi8a-m^1coRRrmurMI6+q5_kyn*)s@(*_Pk6q423' +try: + from .local_settings import DEBUG_TEMPLATE +except Exception as err: + DEBUG_TEMPLATE = False + if DJANGO_GTE_1_10: TEMPLATES = [ { @@ -130,7 +135,7 @@ if DJANGO_GTE_1_10: 'django.template.loaders.eggs.Loader', 'admin_tools.template_loaders.Loader', ], - 'debug': DEBUG, + 'debug': DEBUG_TEMPLATE, } }, ] @@ -159,12 +164,12 @@ elif DJANGO_GTE_1_8: 'django.template.loaders.eggs.Loader', 'admin_tools.template_loaders.Loader', ], - 'debug': DEBUG, + 'debug': DEBUG_TEMPLATE, } }, ] else: - TEMPLATE_DEBUG = DEBUG + TEMPLATE_DEBUG = DEBUG_TEMPLATE # List of callables that know how to import templates from various sources. TEMPLATE_LOADERS = [ diff --git a/examples/simple/settings/local_settings.example b/examples/simple/settings/local_settings.example index 4c9c8906..6287e98c 100644 --- a/examples/simple/settings/local_settings.example +++ b/examples/simple/settings/local_settings.example @@ -4,6 +4,9 @@ PROJECT_DIR = lambda base : os.path.abspath(os.path.join(os.path.dirname(__file_ DEBUG = True DEBUG_TOOLBAR = not True TEMPLATE_DEBUG = not True + +DEBUG_TEMPLATE = True + DEV = True os.environ.setdefault( 'FOBI_SOURCE_PATH', diff --git a/examples/simple/settings/test.py b/examples/simple/settings/test.py index d306633c..e750c4d6 100644 --- a/examples/simple/settings/test.py +++ b/examples/simple/settings/test.py @@ -93,3 +93,5 @@ elif versions.DJANGO_1_10: if 'admin_tools.dashboard' in INSTALLED_APPS else None except Exception as e: pass + +LOGGING = {} diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..354d9bd8 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,18 @@ +[pytest] +norecursedirs= + *.egg + .git + .tox + .env + _sass + build + dist + migrations +python_files = + test_*.py + tests.py +DJANGO_SETTINGS_MODULE=settings.test +addopts= + --cov=fobi + --ignore=.tox + --ignore=requirements diff --git a/runtests.py b/runtests.py new file mode 100644 index 00000000..536a5ded --- /dev/null +++ b/runtests.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +import os +import sys +import pytest + + +def main(): + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.test") + sys.path.insert(0, "examples/simple") + return pytest.main() + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/scripts/make_migrations.sh b/scripts/make_migrations.sh new file mode 100755 index 00000000..09cabfb6 --- /dev/null +++ b/scripts/make_migrations.sh @@ -0,0 +1,9 @@ +echo 'Making messages for django-fobi...' +cd examples/simple/ +./manage.py makemigrations fobi + +echo 'Making messages for example projects...' +./manage.py makemigrations + +echo 'Applying migrations...' +./manage.py migrate diff --git a/setup.py b/setup.py index 5d02cada..9c4cf149 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.9.15' +version = '0.9.16' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index 6211ff44..23765cba 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.9.15' -__build__ = 0x000070 +__version__ = '0.9.16' +__build__ = 0x000071 __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/README.rst b/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/README.rst index 350bd64c..7295bb29 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/README.rst @@ -29,7 +29,7 @@ Installation 4. By default, the submitted form value of `select_multiple` elements is label (human readable representation of the value chosen). - However, that part of the bahaviour has been made configurable. You can + However, that part of the behaviour has been made configurable. You can choose between the following options: Consider the following list of (value, label) choices (the first element in diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/README.rst b/src/fobi/contrib/plugins/form_elements/fields/slider/README.rst index da99ebbd..95c0397c 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/README.rst +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/README.rst @@ -29,23 +29,23 @@ Installation 4. Ranges are specified within the given min/max values. The default values are: - .. code-block:: text +.. code-block:: text - - INITIAL: 50 - - INITIAL_MAX_VALUE: 100 - - INITIAL_MIN_VALUE: 0 - - MIN_VALUE: 0 - - MAX_VALUE: 100 - - STEP: 1 + - INITIAL: 50 + - INITIAL_MAX_VALUE: 100 + - INITIAL_MIN_VALUE: 0 + - MIN_VALUE: 0 + - MAX_VALUE: 100 + - STEP: 1 However, you can override each of them in the settings of your project by prefixing correspondent names with `FOBI_FORM_ELEMENT_SLIDER_`: - .. code-block:: text +.. code-block:: text - - FOBI_FORM_ELEMENT_SLIDER_INITIAL - - FOBI_FORM_ELEMENT_SLIDER_INITIAL_MAX_VALUE - - FOBI_FORM_ELEMENT_SLIDER_INITIAL_MIN_VALUE - - FOBI_FORM_ELEMENT_SLIDER_MIN_VALUE - - FOBI_FORM_ELEMENT_SLIDER_MAX_VALUE - - FOBI_FORM_ELEMENT_SLIDER_STEP + - FOBI_FORM_ELEMENT_SLIDER_INITIAL + - FOBI_FORM_ELEMENT_SLIDER_INITIAL_MAX_VALUE + - FOBI_FORM_ELEMENT_SLIDER_INITIAL_MIN_VALUE + - FOBI_FORM_ELEMENT_SLIDER_MIN_VALUE + - FOBI_FORM_ELEMENT_SLIDER_MAX_VALUE + - FOBI_FORM_ELEMENT_SLIDER_STEP diff --git a/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/snippets/form_wizard_ajax.html b/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/snippets/form_wizard_ajax.html index cb0e55ae..df4134e2 100644 --- a/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/snippets/form_wizard_ajax.html +++ b/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/snippets/form_wizard_ajax.html @@ -1,5 +1,5 @@ {% extends "fobi/generic/snippets/form_wizard_ajax.html" %} - +{% load i18n %} {% block form_page_header_html_class %}page-header{% endblock %} {% block form_html_class %}form-horizontal{% endblock %} @@ -9,3 +9,43 @@ {% block form_button_wrapper_html_class %}controls{% endblock %} {% block form_primary_button_html_class %}btn btn-primary{% endblock %} + +{% block form_wizard_previous_button_html_class %}btn btn-primary{% endblock %} + +{% block form_wizard_first_button_html_class %}btn btn-primary{% endblock %} + +{% block form_wizard_first_button_text %}{% trans "First" %}{% endblock %} + +{% block form_primary_button_text %}{% trans "Next" %}{% endblock %} + +{% block form_wizard_previous_button_text %}{% trans "Previous" %}{% endblock %} + +{% block form_page_sub_title_wrapper %} + +{% endblock form_page_sub_title_wrapper %} \ No newline at end of file diff --git a/src/fobi/forms.py b/src/fobi/forms.py index 5bec08ec..6eb14b86 100644 --- a/src/fobi/forms.py +++ b/src/fobi/forms.py @@ -70,7 +70,7 @@ class FormEntryForm(forms.ModelForm): """Meta class.""" model = FormEntry - fields = ('name', 'is_public', 'success_page_title', + fields = ('name', 'title', 'is_public', 'success_page_title', 'success_page_message', 'action',) # 'is_cloneable', def __init__(self, *args, **kwargs): @@ -89,6 +89,10 @@ class FormEntryForm(forms.ModelForm): attrs={'class': theme.form_element_html_class} ) + self.fields['title'].widget = forms.widgets.TextInput( + attrs={'class': theme.form_element_html_class} + ) + self.fields['success_page_title'].widget = forms.widgets.TextInput( attrs={'class': theme.form_element_html_class} ) @@ -315,8 +319,8 @@ class FormWizardEntryForm(forms.ModelForm): """Meta class.""" model = FormWizardEntry - fields = ('name', 'is_public', 'success_page_title', - 'success_page_message',) + fields = ('name', 'title', 'is_public', 'success_page_title', + 'success_page_message', 'show_all_navigation_buttons',) # 'wizard_type' # 'action', # 'is_cloneable', @@ -337,6 +341,15 @@ class FormWizardEntryForm(forms.ModelForm): attrs={'class': theme.form_element_html_class} ) + self.fields['title'].widget = forms.widgets.TextInput( + attrs={'class': theme.form_element_html_class} + ) + + self.fields['show_all_navigation_buttons'].widget = \ + forms.widgets.CheckboxInput( + attrs={'data-customforms': 'disabled'} + ) + self.fields['success_page_title'].widget = forms.widgets.TextInput( attrs={'class': theme.form_element_html_class} ) diff --git a/src/fobi/integration/processors.py b/src/fobi/integration/processors.py index 4c76ff2e..1ece3d5c 100644 --- a/src/fobi/integration/processors.py +++ b/src/fobi/integration/processors.py @@ -209,12 +209,16 @@ class IntegrationProcessor(object): theme = get_theme(request=request, as_instance=True) theme.collect_plugin_media(form_element_entries) + form_title = instance.form_title \ + if instance.form_title \ + else instance.form_entry.title + context = self.get_context_data( request=request, instance=instance, form=form, fobi_theme=theme, - fobi_form_title=instance.form_title, + fobi_form_title=form_title, fobi_hide_form_title=instance.hide_form_title, fobi_form_submit_button_text=instance.form_submit_button_text ) diff --git a/src/fobi/migrations/0011_formentry_title.py b/src/fobi/migrations/0011_formentry_title.py new file mode 100644 index 00000000..e69b6b6b --- /dev/null +++ b/src/fobi/migrations/0011_formentry_title.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2016-11-08 21:53 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fobi', '0010_formwizardhandler'), + ] + + operations = [ + migrations.AddField( + model_name='formentry', + name='title', + field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Title'), + ), + ] diff --git a/src/fobi/migrations/0012_auto_20161109_1550.py b/src/fobi/migrations/0012_auto_20161109_1550.py new file mode 100644 index 00000000..ba607d3d --- /dev/null +++ b/src/fobi/migrations/0012_auto_20161109_1550.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.11 on 2016-11-09 21:50 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fobi', '0011_formentry_title'), + ] + + operations = [ + migrations.AddField( + model_name='formwizardentry', + name='title', + field=models.CharField(blank=True, help_text='Shown in templates ifavailable.', max_length=255, null=True, verbose_name='Title'), + ), + migrations.AlterField( + model_name='formentry', + name='title', + field=models.CharField(blank=True, help_text='Shown in templates ifavailable.', max_length=255, null=True, verbose_name='Title'), + ), + ] diff --git a/src/fobi/migrations/0013_formwizardentry_show_all_navigation_buttons.py b/src/fobi/migrations/0013_formwizardentry_show_all_navigation_buttons.py new file mode 100644 index 00000000..c7eccc3b --- /dev/null +++ b/src/fobi/migrations/0013_formwizardentry_show_all_navigation_buttons.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2016-11-09 23:40 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fobi', '0012_auto_20161109_1550'), + ] + + operations = [ + migrations.AddField( + model_name='formwizardentry', + name='show_all_navigation_buttons', + field=models.BooleanField(default=False, help_text='Show all navigation buttons.', verbose_name='Show all navigation buttons?'), + ), + ] diff --git a/src/fobi/models.py b/src/fobi/models.py index 71516b65..2bc422c9 100644 --- a/src/fobi/models.py +++ b/src/fobi/models.py @@ -256,6 +256,9 @@ class FormWizardEntry(models.Model): user = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_("User")) name = models.CharField(_("Name"), max_length=255) + title = models.CharField(_("Title"), max_length=255, null=True, + blank=True, help_text=_("Shown in templates if" + "available.")) slug = AutoSlugField(populate_from='name', verbose_name=_("Slug"), unique=True) is_public = models.BooleanField( @@ -276,6 +279,10 @@ class FormWizardEntry(models.Model): help_text=_("Custom message text to display after valid form is " "submitted") ) + show_all_navigation_buttons = models.BooleanField( + _("Show all navigation buttons?"), default=False, + help_text=_("Show all navigation buttons.") + ) # action = models.CharField( # _("Action"), max_length=255, null=True, blank=True, # help_text=_("Custom form action; don't fill this field, unless " @@ -319,20 +326,20 @@ class FormEntry(models.Model): :Properties: - `user` (django.contrib.auth.models.User: User owning the plugin. - - `wizard` (str): Form wizard to which the form entry belongs to. - `name` (str): Form name. + - `title` (str): Form title - used in templates. - `slug` (str): Form slug. - `description` (str): Form description. - `is_public` (bool): If set to True, is visible to public. - `is_cloneable` (bool): If set to True, is cloneable. - `position` (int): Ordering position in the wizard. """ - # form_wizard_entry = models.ForeignKey( - # FormWizardEntry, verbose_name=_("Form wizard"), null=True, blank=True - # ) user = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_("User")) name = models.CharField(_("Name"), max_length=255) + title = models.CharField(_("Title"), max_length=255, null=True, + blank=True, help_text=_("Shown in templates if" + "available.")) slug = AutoSlugField( populate_from='name', verbose_name=_("Slug"), unique=True ) diff --git a/src/fobi/templates/fobi/generic/snippets/form_wizard_ajax.html b/src/fobi/templates/fobi/generic/snippets/form_wizard_ajax.html index 6e47c6bc..5cee60bd 100644 --- a/src/fobi/templates/fobi/generic/snippets/form_wizard_ajax.html +++ b/src/fobi/templates/fobi/generic/snippets/form_wizard_ajax.html @@ -1,6 +1,7 @@ {% block form_page_header_wrapper %}
    {% block form_page_title_wrapper %}

    {% block form_page_title %}{% endblock %}

    {% endblock form_page_title_wrapper %} + {% block form_page_sub_title_wrapper %}{% endblock form_page_sub_title_wrapper %}
    {% endblock form_page_header_wrapper %} @@ -14,7 +15,11 @@
    {% block form_buttons %} - + {% if form_wizard_entry.show_all_navigation_buttons %} + {% block form_wizard_first_button_wrapper %}{% endblock form_wizard_first_button_wrapper %} + {% block form_wizard_previous_button_wrapper %}{% endblock form_wizard_previous_button_wrapper %} + {% endif %} + {% block form_wizard_next_button_wrapper %}{% endblock form_wizard_next_button_wrapper %} {% endblock form_buttons %}
    diff --git a/src/fobi/templates/fobi/generic/snippets/form_wizard_view_ajax.html b/src/fobi/templates/fobi/generic/snippets/form_wizard_view_ajax.html index cae6facb..853d23b0 100644 --- a/src/fobi/templates/fobi/generic/snippets/form_wizard_view_ajax.html +++ b/src/fobi/templates/fobi/generic/snippets/form_wizard_view_ajax.html @@ -1,6 +1,7 @@ {% block form_page_header_wrapper %}
    {% block form_page_title_wrapper %}

    {% block form_page_title %}{% endblock form_page_title %}

    {% endblock form_page_title_wrapper %} + {% block form_page_sub_title_wrapper %}{% block form_page_sub_title %}{% endblock form_page_sub_title %}{% endblock form_page_sub_title_wrapper %}
    {% endblock form_page_header_wrapper %} diff --git a/src/fobi/templates/fobi/generic/view_form_entry.html b/src/fobi/templates/fobi/generic/view_form_entry.html index 647c2881..b57580fe 100644 --- a/src/fobi/templates/fobi/generic/view_form_entry.html +++ b/src/fobi/templates/fobi/generic/view_form_entry.html @@ -2,7 +2,7 @@ {% load i18n %} -{% block page-title %}{% trans "View form" %}{% endblock page-title %} +{% block page-title %}{% if form_entry.title %}{{ form_entry.title }}{% else %}{% trans "View form" %}{% endif %}{% endblock page-title %} {% block navbar-menu-content %}
  • {% trans "Edit" %}
  • diff --git a/src/fobi/templates/fobi/generic/view_form_wizard_entry.html b/src/fobi/templates/fobi/generic/view_form_wizard_entry.html index 37955387..1b6052dd 100644 --- a/src/fobi/templates/fobi/generic/view_form_wizard_entry.html +++ b/src/fobi/templates/fobi/generic/view_form_wizard_entry.html @@ -2,7 +2,7 @@ {% load i18n %} -{% block page-title %}{% trans "View form wizard" %}{% endblock page-title %} +{% block page-title %}{% if fobi_form_wizard_title %}{{ fobi_form_wizard_title }}{% else %}{% trans "View form wizard" %}{% endif %}{% endblock page-title %} {% block dashboard-menu-item %} {{ fobi_theme.project_name }} diff --git a/src/fobi/templates/fobi/generic/view_form_wizard_entry_ajax.html b/src/fobi/templates/fobi/generic/view_form_wizard_entry_ajax.html index 0f3a9202..012042d6 100644 --- a/src/fobi/templates/fobi/generic/view_form_wizard_entry_ajax.html +++ b/src/fobi/templates/fobi/generic/view_form_wizard_entry_ajax.html @@ -6,7 +6,7 @@ {% if fobi_form_title %}{{ fobi_form_title }}{% else %}{% trans "View form" %}{% endif %} {% endblock form_page_title %} -{% block form_primary_button_text %}{% if fobi_form_submit_button_text %}{{ fobi_form_submit_button_text }}{% else %}{% trans "Submit" %}{% endif %}{% endblock %} +{% block form_primary_button_text %}{% if fobi_form_submit_button_text %}{{ fobi_form_submit_button_text }}{% else %}{% trans "Next" %}{% endif %}{% endblock %} {% block form_buttons %} {{ block.super }} {% endblock form_buttons %} diff --git a/src/fobi/views.py b/src/fobi/views.py index b6f94820..23431e92 100644 --- a/src/fobi/views.py +++ b/src/fobi/views.py @@ -1407,15 +1407,23 @@ class FormWizardView(DynamicSessionWizardView): context_data = super(FormWizardView, self).get_context_data( form=form, **kwargs ) - + form_entry = self.get_form_entry_for_step(self.steps.step0) context_data.update({ 'form_wizard_entry': self.form_wizard_entry, 'form_wizard_mode': True, 'fobi_theme': self.fobi_theme, + 'fobi_form_title': form_entry.title, + 'fobi_form_wizard_title': self.form_wizard_entry.title, + 'steps_range': range(self.steps.step1, self.steps.count+1) }) return context_data + def get_form_entry_for_step(self, step): + """Get form entry title for step.""" + form_slug = self.form_list[self.steps.step0][0] + return self.form_entry_mapping[form_slug] + def get_initial_wizard_data(self, request, *args, **kwargs): """Get initial wizard data.""" try: @@ -1511,8 +1519,12 @@ class FormWizardView(DynamicSessionWizardView): # Get current form entry form_entry = self.form_entry_mapping[self.steps.current] # Fire plugin processors - form = submit_plugin_form_data(form_entry=form_entry, - request=self.request, form=form) + form = submit_plugin_form_data( + form_entry=form_entry, + request=self.request, + form=form, + # **{'': ''} # TODO + ) # Form wizards make use of form.data instead of form.cleaned_data. # Therefore, we update the form.data with values from # form.cleaned_data. @@ -1582,7 +1594,8 @@ class FormWizardView(DynamicSessionWizardView): form_obj = submit_plugin_form_data( form_entry=form_entry, request=self.request, - form=form_obj + form=form_obj, + # **{'': ''} # TODO ) final_forms[form_key] = form_obj @@ -2123,8 +2136,11 @@ def view_form_entry(request, form_entry_slug, theme=None, template_name=None): ) # Fire plugin processors - form = submit_plugin_form_data(form_entry=form_entry, - request=request, form=form) + 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, @@ -2194,6 +2210,7 @@ def view_form_entry(request, form_entry_slug, theme=None, template_name=None): 'form': form, 'form_entry': form_entry, 'fobi_theme': theme, + 'fobi_form_title': form_entry.title, } if not template_name: From 3dcbeb01a8145a1a3887187c3d54704748bcbf0a Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 10 Nov 2016 01:49:35 +0100 Subject: [PATCH 22/39] use first step --- src/fobi/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fobi/views.py b/src/fobi/views.py index 23431e92..5a8fad1d 100644 --- a/src/fobi/views.py +++ b/src/fobi/views.py @@ -1414,7 +1414,7 @@ class FormWizardView(DynamicSessionWizardView): 'fobi_theme': self.fobi_theme, 'fobi_form_title': form_entry.title, 'fobi_form_wizard_title': self.form_wizard_entry.title, - 'steps_range': range(self.steps.step1, self.steps.count+1) + 'steps_range': range(self.steps.first, self.steps.count+1) }) return context_data From 586ed95f2b08d8989986b1d80e13a9ae5347b809 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 10 Nov 2016 01:51:05 +0100 Subject: [PATCH 23/39] fix --- src/fobi/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fobi/views.py b/src/fobi/views.py index 5a8fad1d..59467101 100644 --- a/src/fobi/views.py +++ b/src/fobi/views.py @@ -1414,7 +1414,7 @@ class FormWizardView(DynamicSessionWizardView): 'fobi_theme': self.fobi_theme, 'fobi_form_title': form_entry.title, 'fobi_form_wizard_title': self.form_wizard_entry.title, - 'steps_range': range(self.steps.first, self.steps.count+1) + 'steps_range': range(1, self.steps.count+1) }) return context_data From 541928c5e1272d8f713a2f7ab1fad264b7a47534 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 10 Nov 2016 02:02:57 +0100 Subject: [PATCH 24/39] check if last step --- .../bootstrap3/snippets/form_wizard_ajax.html | 2 +- src/fobi/views.py | 2 +- src/fobi/wizard/views/dynamic.py | 11 ++++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/snippets/form_wizard_ajax.html b/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/snippets/form_wizard_ajax.html index df4134e2..9af8c564 100644 --- a/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/snippets/form_wizard_ajax.html +++ b/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/snippets/form_wizard_ajax.html @@ -16,7 +16,7 @@ {% block form_wizard_first_button_text %}{% trans "First" %}{% endblock %} -{% block form_primary_button_text %}{% trans "Next" %}{% endblock %} +{% block form_primary_button_text %}{% if wizard.steps.is_last_step %}{% trans "Submit" %}{% else %}{% trans "Next" %}{% endif %}{% endblock %} {% block form_wizard_previous_button_text %}{% trans "Previous" %}{% endblock %} diff --git a/src/fobi/views.py b/src/fobi/views.py index 59467101..f91a6694 100644 --- a/src/fobi/views.py +++ b/src/fobi/views.py @@ -1414,7 +1414,7 @@ class FormWizardView(DynamicSessionWizardView): 'fobi_theme': self.fobi_theme, 'fobi_form_title': form_entry.title, 'fobi_form_wizard_title': self.form_wizard_entry.title, - 'steps_range': range(1, self.steps.count+1) + 'steps_range': range(1, self.steps.count+1), }) return context_data diff --git a/src/fobi/wizard/views/dynamic.py b/src/fobi/wizard/views/dynamic.py index 253e546c..d00d49d2 100644 --- a/src/fobi/wizard/views/dynamic.py +++ b/src/fobi/wizard/views/dynamic.py @@ -107,9 +107,14 @@ class StepsHelper(object): @property def index(self): - """Return the index for the current step.""" + """Return the index for the current step (0 based).""" return self._wizard.get_step_index() + @property + def index1(self): + """Return the index for the current step (1 based).""" + return self.index + 1 + @property def step0(self): """Step 0.""" @@ -120,6 +125,10 @@ class StepsHelper(object): """Step 1.""" return int(self.index) + 1 + def is_last_step(self): + """Check if last step.""" + return self.index1 == self.count + # class DynamicTemplateView(TemplateView): # """Dynamic template view.""" From d6bb5c20fb822c43967c418764b449dc52be2a1a Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 10 Nov 2016 02:05:12 +0100 Subject: [PATCH 25/39] fixes --- src/fobi/wizard/views/dynamic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fobi/wizard/views/dynamic.py b/src/fobi/wizard/views/dynamic.py index d00d49d2..e3a58b59 100644 --- a/src/fobi/wizard/views/dynamic.py +++ b/src/fobi/wizard/views/dynamic.py @@ -125,6 +125,7 @@ class StepsHelper(object): """Step 1.""" return int(self.index) + 1 + @property def is_last_step(self): """Check if last step.""" return self.index1 == self.count From 29d9543eb75bd37f2af947ba7e9a72305b40b9ce Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 10 Nov 2016 02:15:08 +0100 Subject: [PATCH 26/39] fixes --- src/fobi/base.py | 31 ++++++++++++++----- .../bootstrap3/snippets/form_wizard_ajax.html | 2 +- .../generic/snippets/form_wizard_ajax.html | 2 +- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/fobi/base.py b/src/fobi/base.py index f5d5ac65..2f7236c5 100644 --- a/src/fobi/base.py +++ b/src/fobi/base.py @@ -1535,7 +1535,8 @@ class FormElementPlugin(BasePlugin): logger.debug(str(err)) return {} - def _submit_plugin_form_data(self, form_entry, request, form): + def _submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): """Submit plugin form data (internal method). Do not override this method. Use ``submit_plugin_form_data``, @@ -1551,17 +1552,26 @@ class FormElementPlugin(BasePlugin): """ if DEBUG: return self.submit_plugin_form_data( - form_entry=form_entry, request=request, form=form + form_entry=form_entry, + request=request, + form=form, + form_element_entries=None, + **kwargs ) else: try: return self.submit_plugin_form_data( - form_entry=form_entry, request=request, form=form + form_entry=form_entry, + request=request, + form=form, + form_element_entries=None, + **kwargs ) except Exception as e: logger.debug(str(e)) - def submit_plugin_form_data(self, form_entry, request, form): + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): """Submit plugin form data. Called on form submission (when user actually @@ -2408,7 +2418,8 @@ def validate_form_element_plugin_uid(plugin_uid): return validate_plugin_uid(form_element_plugin_registry, plugin_uid) -def submit_plugin_form_data(form_entry, request, form): +def submit_plugin_form_data(form_entry, request, form, + form_element_entries=None, **kwargs): """Submit plugin form data for all plugins. :param fobi.models.FormEntry form_entry: Instance of @@ -2416,11 +2427,17 @@ def submit_plugin_form_data(form_entry, request, form): :param django.http.HttpRequest request: :param django.forms.Form form: """ - for form_element_entry in form_entry.formelemententry_set.all(): + if not form_element_entries: + form_element_entries = form_entry.formelemententry_set.all() + for form_element_entry in form_element_entries: # Get the plugin. form_element_plugin = form_element_entry.get_plugin(request=request) updated_form = form_element_plugin._submit_plugin_form_data( - form_entry=form_entry, request=request, form=form + form_entry=form_entry, + request=request, + form=form, + form_element_entries=form_element_entries, + **kwargs ) if updated_form: form = updated_form diff --git a/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/snippets/form_wizard_ajax.html b/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/snippets/form_wizard_ajax.html index 9af8c564..d4950264 100644 --- a/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/snippets/form_wizard_ajax.html +++ b/src/fobi/contrib/themes/bootstrap3/templates/bootstrap3/snippets/form_wizard_ajax.html @@ -16,7 +16,7 @@ {% block form_wizard_first_button_text %}{% trans "First" %}{% endblock %} -{% block form_primary_button_text %}{% if wizard.steps.is_last_step %}{% trans "Submit" %}{% else %}{% trans "Next" %}{% endif %}{% endblock %} +{% block form_wizard_primary_button_text %}{% if wizard.steps.is_last_step %}{% trans "Submit" %}{% else %}{% trans "Next" %}{% endif %}{% endblock %} {% block form_wizard_previous_button_text %}{% trans "Previous" %}{% endblock %} diff --git a/src/fobi/templates/fobi/generic/snippets/form_wizard_ajax.html b/src/fobi/templates/fobi/generic/snippets/form_wizard_ajax.html index 5cee60bd..bbf1aa81 100644 --- a/src/fobi/templates/fobi/generic/snippets/form_wizard_ajax.html +++ b/src/fobi/templates/fobi/generic/snippets/form_wizard_ajax.html @@ -19,7 +19,7 @@ {% block form_wizard_first_button_wrapper %}{% endblock form_wizard_first_button_wrapper %} {% block form_wizard_previous_button_wrapper %}{% endblock form_wizard_previous_button_wrapper %} {% endif %} - {% block form_wizard_next_button_wrapper %}{% endblock form_wizard_next_button_wrapper %} + {% block form_wizard_next_button_wrapper %}{% endblock form_wizard_next_button_wrapper %} {% endblock form_buttons %}
    From fbdfc69dbbd4280c9226d891969d6c6bfd20a30c Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 10 Nov 2016 02:21:09 +0100 Subject: [PATCH 27/39] fixes --- src/fobi/base.py | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/fobi/base.py b/src/fobi/base.py index 2f7236c5..dcd38858 100644 --- a/src/fobi/base.py +++ b/src/fobi/base.py @@ -1535,8 +1535,9 @@ class FormElementPlugin(BasePlugin): logger.debug(str(err)) return {} - def _submit_plugin_form_data(self, form_entry, request, form, - form_element_entries=None, **kwargs): + # def _submit_plugin_form_data(self, form_entry, request, form, + # form_element_entries=None, **kwargs): + def _submit_plugin_form_data(self, form_entry, request, form): """Submit plugin form data (internal method). Do not override this method. Use ``submit_plugin_form_data``, @@ -1555,8 +1556,8 @@ class FormElementPlugin(BasePlugin): form_entry=form_entry, request=request, form=form, - form_element_entries=None, - **kwargs + # form_element_entries=None, + # **kwargs ) else: try: @@ -1564,14 +1565,15 @@ class FormElementPlugin(BasePlugin): form_entry=form_entry, request=request, form=form, - form_element_entries=None, - **kwargs + # form_element_entries=None, + # **kwargs ) except Exception as e: logger.debug(str(e)) - def submit_plugin_form_data(self, form_entry, request, form, - form_element_entries=None, **kwargs): + # def submit_plugin_form_data(self, form_entry, request, form, + # form_element_entries=None, **kwargs): + def submit_plugin_form_data(self, form_entry, request, form): """Submit plugin form data. Called on form submission (when user actually @@ -2418,8 +2420,9 @@ def validate_form_element_plugin_uid(plugin_uid): return validate_plugin_uid(form_element_plugin_registry, plugin_uid) -def submit_plugin_form_data(form_entry, request, form, - form_element_entries=None, **kwargs): +# def submit_plugin_form_data(form_entry, request, form, +# form_element_entries=None, **kwargs): +def submit_plugin_form_data(form_entry, request, form): """Submit plugin form data for all plugins. :param fobi.models.FormEntry form_entry: Instance of @@ -2427,17 +2430,19 @@ def submit_plugin_form_data(form_entry, request, form, :param django.http.HttpRequest request: :param django.forms.Form form: """ - if not form_element_entries: - form_element_entries = form_entry.formelemententry_set.all() - for form_element_entry in form_element_entries: + # if not form_element_entries: + # form_element_entries = form_entry.formelemententry_set.all() + # for form_element_entry in form_element_entries: + + for form_element_entry in form_entry.formelemententry_set.all(): # Get the plugin. form_element_plugin = form_element_entry.get_plugin(request=request) updated_form = form_element_plugin._submit_plugin_form_data( form_entry=form_entry, request=request, form=form, - form_element_entries=form_element_entries, - **kwargs + # form_element_entries=form_element_entries, + # **kwargs ) if updated_form: form = updated_form From 3b821e8e81316dffdb1c9ec68ecc616e57ced7e7 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 10 Nov 2016 02:35:53 +0100 Subject: [PATCH 28/39] pytest fixes --- examples/simple/settings/test.py | 2 ++ pytest.ini | 1 + runtests.py | 0 tox.ini | 9 +++++---- 4 files changed, 8 insertions(+), 4 deletions(-) mode change 100644 => 100755 runtests.py diff --git a/examples/simple/settings/test.py b/examples/simple/settings/test.py index e750c4d6..3070d432 100644 --- a/examples/simple/settings/test.py +++ b/examples/simple/settings/test.py @@ -95,3 +95,5 @@ elif versions.DJANGO_1_10: pass LOGGING = {} + +DEBUG_TOOLBAR = False diff --git a/pytest.ini b/pytest.ini index 354d9bd8..8d19bc98 100644 --- a/pytest.ini +++ b/pytest.ini @@ -16,3 +16,4 @@ addopts= --cov=fobi --ignore=.tox --ignore=requirements + --ignore=release diff --git a/runtests.py b/runtests.py old mode 100644 new mode 100755 diff --git a/tox.ini b/tox.ini index 08c27163..21722f2e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - py{27,33,34}-{django15,django16}, +# py{27,33,34}-{django15,django16}, py{27,33,34}-{django17,django18} py{27,34}-{django17,django18} py{27,34}-{django19} @@ -12,14 +12,15 @@ envlist = envlogdir=examples/logs/ passenv = * deps = - django15: -r{toxinidir}/examples/requirements/django_1_5.txt - django16: -r{toxinidir}/examples/requirements/django_1_6.txt +# django15: -r{toxinidir}/examples/requirements/django_1_5.txt +# django16: -r{toxinidir}/examples/requirements/django_1_6.txt django17: -r{toxinidir}/examples/requirements/django_1_7.txt django18: -r{toxinidir}/examples/requirements/django_1_8.txt django19: -r{toxinidir}/examples/requirements/django_1_9.txt django110: -r{toxinidir}/examples/requirements/django_1_10.txt commands = - {envpython} examples/simple/manage.py test {posargs:fobi} --settings=settings.test --traceback -v 3 +# {envpython} examples/simple/manage.py test {posargs:fobi} --settings=settings.test --traceback -v 3 + {envpython} runtests.py #[testenv:flake8] #basepython = python3.5 From 257ac59be511b12d05eccc0510c941769bedcf0c Mon Sep 17 00:00:00 2001 From: Marcos Amorim Date: Thu, 10 Nov 2016 11:34:41 +0000 Subject: [PATCH 29/39] Validation for `max_length` value; Validation for `initial` according to `max_length` value --- .../form_elements/fields/email/forms.py | 25 +++++++++++++++--- .../form_elements/fields/file/forms.py | 25 +++++++++++++++--- .../form_elements/fields/hidden/forms.py | 25 +++++++++++++++--- .../form_elements/fields/input/forms.py | 25 +++++++++++++++--- .../form_elements/fields/ip_address/forms.py | 26 +++++++++++++++---- .../form_elements/fields/password/forms.py | 25 +++++++++++++++--- .../form_elements/fields/regex/forms.py | 25 +++++++++++++++--- .../form_elements/fields/slug/forms.py | 25 +++++++++++++++--- .../form_elements/fields/text/forms.py | 25 +++++++++++++++--- .../plugins/form_elements/fields/url/forms.py | 25 +++++++++++++++--- src/fobi/defaults.py | 1 + src/fobi/settings.py | 2 ++ 12 files changed, 213 insertions(+), 41 deletions(-) diff --git a/src/fobi/contrib/plugins/form_elements/fields/email/forms.py b/src/fobi/contrib/plugins/form_elements/fields/email/forms.py index 31dc4fe4..c5e249e9 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/email/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/email/forms.py @@ -2,9 +2,10 @@ from __future__ import absolute_import from django import forms from django.utils.translation import ugettext_lazy as _ +from django.core.validators import MinValueValidator from fobi.base import BaseFormFieldPluginForm, get_theme -from fobi.settings import DEFAULT_MAX_LENGTH +from fobi.settings import DEFAULT_MAX_LENGTH, DEFAULT_MIN_LENGTH from fobi.widgets import NumberInput __title__ = 'fobi.contrib.plugins.form_elements.email.forms' @@ -24,7 +25,7 @@ class EmailInputForm(forms.Form, BaseFormFieldPluginForm): ("name", ""), ("help_text", ""), ("initial", ""), - ("max_length", "255"), + ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False), ("placeholder", ""), ] @@ -60,8 +61,10 @@ class EmailInputForm(forms.Form, BaseFormFieldPluginForm): max_length = forms.IntegerField( label=_("Max length"), required=True, - widget=NumberInput(attrs={'class': theme.form_element_html_class}), - initial=DEFAULT_MAX_LENGTH + widget=NumberInput(attrs={'class': theme.form_element_html_class, + 'min': str(DEFAULT_MIN_LENGTH)}), + initial=DEFAULT_MAX_LENGTH, + validators=[MinValueValidator(DEFAULT_MIN_LENGTH)] ) required = forms.BooleanField( label=_("Required"), @@ -78,6 +81,20 @@ class EmailInputForm(forms.Form, BaseFormFieldPluginForm): ) ) + def clean(self): + super(EmailInputForm, self).clean() + + max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) + + if self.cleaned_data['initial']: + len_initial = len(self.cleaned_data['initial']) + if len_initial > max_length: + self.add_error( + 'initial', + _("Ensure this value has at most {0} characters " + "(it has {1}).".format(max_length, len_initial)) + ) + # For backwards compatibility EmailForm = EmailInputForm diff --git a/src/fobi/contrib/plugins/form_elements/fields/file/forms.py b/src/fobi/contrib/plugins/form_elements/fields/file/forms.py index 597b885d..d3e08f09 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/file/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/file/forms.py @@ -1,8 +1,9 @@ from django import forms from django.utils.translation import ugettext_lazy as _ +from django.core.validators import MinValueValidator from fobi.base import BaseFormFieldPluginForm, get_theme -from fobi.settings import DEFAULT_MAX_LENGTH +from fobi.settings import DEFAULT_MAX_LENGTH, DEFAULT_MIN_LENGTH from fobi.widgets import NumberInput __title__ = 'fobi.contrib.plugins.form_elements.fields.file.forms' @@ -22,7 +23,7 @@ class FileInputForm(forms.Form, BaseFormFieldPluginForm): ("name", ""), ("help_text", ""), ("initial", ""), - ("max_length", "255"), + ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False) ] @@ -57,8 +58,10 @@ class FileInputForm(forms.Form, BaseFormFieldPluginForm): max_length = forms.IntegerField( label=_("Max length"), required=True, - widget=NumberInput(attrs={'class': theme.form_element_html_class}), - initial=DEFAULT_MAX_LENGTH + widget=NumberInput(attrs={'class': theme.form_element_html_class, + 'min': str(DEFAULT_MIN_LENGTH)}), + initial=DEFAULT_MAX_LENGTH, + validators=[MinValueValidator(DEFAULT_MIN_LENGTH)] ) required = forms.BooleanField( label=_("Required"), @@ -67,3 +70,17 @@ class FileInputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_checkbox_html_class} ) ) + + def clean(self): + super(FileInputForm, self).clean() + + max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) + + if self.cleaned_data['initial']: + len_initial = len(self.cleaned_data['initial']) + if len_initial > max_length: + self.add_error( + 'initial', + _("Ensure this value has at most {0} characters " + "(it has {1}).".format(max_length, len_initial)) + ) diff --git a/src/fobi/contrib/plugins/form_elements/fields/hidden/forms.py b/src/fobi/contrib/plugins/form_elements/fields/hidden/forms.py index 713fa410..c574d425 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/hidden/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/hidden/forms.py @@ -1,8 +1,9 @@ from django import forms from django.utils.translation import ugettext_lazy as _ +from django.core.validators import MinValueValidator from fobi.base import BaseFormFieldPluginForm, get_theme -from fobi.settings import DEFAULT_MAX_LENGTH +from fobi.settings import DEFAULT_MAX_LENGTH, DEFAULT_MIN_LENGTH from fobi.widgets import NumberInput __title__ = 'fobi.contrib.plugins.form_elements.fields.hidden.forms' @@ -21,7 +22,7 @@ class HiddenInputForm(forms.Form, BaseFormFieldPluginForm): ("label", ""), ("name", ""), ("initial", ""), - ("max_length", "255"), + ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False) ] @@ -49,8 +50,10 @@ class HiddenInputForm(forms.Form, BaseFormFieldPluginForm): max_length = forms.IntegerField( label=_("Max length"), required=True, - widget=NumberInput(attrs={'class': theme.form_element_html_class}), - initial=DEFAULT_MAX_LENGTH + widget=NumberInput(attrs={'class': theme.form_element_html_class, + 'min': str(DEFAULT_MIN_LENGTH)}), + initial=DEFAULT_MAX_LENGTH, + validators=[MinValueValidator(DEFAULT_MIN_LENGTH)] ) required = forms.BooleanField( label=_("Required"), @@ -59,3 +62,17 @@ class HiddenInputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_checkbox_html_class} ) ) + + def clean(self): + super(HiddenInputForm, self).clean() + + max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) + + if self.cleaned_data['initial']: + len_initial = len(self.cleaned_data['initial']) + if len_initial > max_length: + self.add_error( + 'initial', + _("Ensure this value has at most {0} characters " + "(it has {1}).".format(max_length, len_initial)) + ) diff --git a/src/fobi/contrib/plugins/form_elements/fields/input/forms.py b/src/fobi/contrib/plugins/form_elements/fields/input/forms.py index 8ba28a85..5134b324 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/input/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/input/forms.py @@ -1,8 +1,9 @@ from django import forms from django.utils.translation import ugettext_lazy as _ +from django.core.validators import MinValueValidator from fobi.base import BaseFormFieldPluginForm, get_theme -from fobi.settings import DEFAULT_MAX_LENGTH +from fobi.settings import DEFAULT_MAX_LENGTH, DEFAULT_MIN_LENGTH from fobi.widgets import NumberInput from .constants import FORM_FIELD_TYPE_CHOICES @@ -24,7 +25,7 @@ class InputForm(forms.Form, BaseFormFieldPluginForm): ("name", ""), ("help_text", ""), ("initial", ""), - ("max_length", "255"), + ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False), ("placeholder", ""), @@ -79,8 +80,10 @@ class InputForm(forms.Form, BaseFormFieldPluginForm): max_length = forms.IntegerField( label=_("Max length"), required=True, - widget=NumberInput(attrs={'class': theme.form_element_html_class}), - initial=DEFAULT_MAX_LENGTH + widget=NumberInput(attrs={'class': theme.form_element_html_class, + 'min': str(DEFAULT_MIN_LENGTH)}), + initial=DEFAULT_MAX_LENGTH, + validators=[MinValueValidator(DEFAULT_MIN_LENGTH)] ) required = forms.BooleanField( label=_("Required"), @@ -181,3 +184,17 @@ class InputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_html_class} ) ) + + def clean(self): + super(InputForm, self).clean() + + max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) + + if self.cleaned_data['initial']: + len_initial = len(self.cleaned_data['initial']) + if len_initial > max_length: + self.add_error( + 'initial', + _("Ensure this value has at most {0} characters " + "(it has {1}).".format(max_length, len_initial)) + ) diff --git a/src/fobi/contrib/plugins/form_elements/fields/ip_address/forms.py b/src/fobi/contrib/plugins/form_elements/fields/ip_address/forms.py index 27031d22..4d3a3909 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/ip_address/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/ip_address/forms.py @@ -1,9 +1,9 @@ from django import forms -from django.core.validators import ip_address_validator_map +from django.core.validators import ip_address_validator_map, MinValueValidator from django.utils.translation import ugettext_lazy as _ from fobi.base import BaseFormFieldPluginForm, get_theme -from fobi.settings import DEFAULT_MAX_LENGTH +from fobi.settings import DEFAULT_MAX_LENGTH, DEFAULT_MIN_LENGTH from fobi.widgets import NumberInput __title__ = 'fobi.contrib.plugins.form_elements.fields.ip_address.forms' @@ -25,7 +25,7 @@ class IPAddressInputForm(forms.Form, BaseFormFieldPluginForm): ("initial", ""), ("protocol", ""), ("unpack_ipv4", False), - ("max_length", "255"), + ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False), ("placeholder", ""), ] @@ -76,8 +76,10 @@ class IPAddressInputForm(forms.Form, BaseFormFieldPluginForm): max_length = forms.IntegerField( label=_("Max length"), required=True, - widget=NumberInput(attrs={'class': theme.form_element_html_class}), - initial=DEFAULT_MAX_LENGTH + widget=NumberInput(attrs={'class': theme.form_element_html_class, + 'min': str(DEFAULT_MIN_LENGTH)}), + initial=DEFAULT_MAX_LENGTH, + validators=[MinValueValidator(DEFAULT_MIN_LENGTH)] ) required = forms.BooleanField( label=_("Required"), @@ -93,3 +95,17 @@ class IPAddressInputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_html_class} ) ) + + def clean(self): + super(IPAddressInputForm, self).clean() + + max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) + + if self.cleaned_data['initial']: + len_initial = len(self.cleaned_data['initial']) + if len_initial > max_length: + self.add_error( + 'initial', + _("Ensure this value has at most {0} characters " + "(it has {1}).".format(max_length, len_initial)) + ) diff --git a/src/fobi/contrib/plugins/form_elements/fields/password/forms.py b/src/fobi/contrib/plugins/form_elements/fields/password/forms.py index f105be5b..b8272312 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/password/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/password/forms.py @@ -1,8 +1,9 @@ from django import forms from django.utils.translation import ugettext_lazy as _ +from django.core.validators import MinValueValidator from fobi.base import BaseFormFieldPluginForm, get_theme -from fobi.settings import DEFAULT_MAX_LENGTH +from fobi.settings import DEFAULT_MAX_LENGTH, DEFAULT_MIN_LENGTH from fobi.widgets import NumberInput __title__ = 'fobi.contrib.plugins.form_elements.fields.password.forms' @@ -22,7 +23,7 @@ class PasswordInputForm(forms.Form, BaseFormFieldPluginForm): ("name", ""), ("help_text", ""), ("initial", ""), - ("max_length", "255"), + ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False), ("placeholder", ""), ] @@ -58,8 +59,10 @@ class PasswordInputForm(forms.Form, BaseFormFieldPluginForm): max_length = forms.IntegerField( label=_("Max length"), required=True, - widget=NumberInput(attrs={'class': theme.form_element_html_class}), - initial=DEFAULT_MAX_LENGTH + widget=NumberInput(attrs={'class': theme.form_element_html_class, + 'min': str(DEFAULT_MIN_LENGTH)}), + initial=DEFAULT_MAX_LENGTH, + validators=[MinValueValidator(DEFAULT_MIN_LENGTH)] ) required = forms.BooleanField( label=_("Required"), @@ -75,3 +78,17 @@ class PasswordInputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_html_class} ) ) + + def clean(self): + super(PasswordInputForm, self).clean() + + max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) + + if self.cleaned_data['initial']: + len_initial = len(self.cleaned_data['initial']) + if len_initial > max_length: + self.add_error( + 'initial', + _("Ensure this value has at most {0} characters " + "(it has {1}).".format(max_length, len_initial)) + ) diff --git a/src/fobi/contrib/plugins/form_elements/fields/regex/forms.py b/src/fobi/contrib/plugins/form_elements/fields/regex/forms.py index 91ac5a91..85ad6be0 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/regex/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/regex/forms.py @@ -2,9 +2,10 @@ from __future__ import absolute_import from django import forms from django.utils.translation import ugettext_lazy as _ +from django.core.validators import MinValueValidator from fobi.base import BaseFormFieldPluginForm, get_theme -from fobi.settings import DEFAULT_MAX_LENGTH +from fobi.settings import DEFAULT_MAX_LENGTH, DEFAULT_MIN_LENGTH from fobi.widgets import NumberInput __title__ = 'fobi.contrib.plugins.form_elements.fields.regex.forms' @@ -25,7 +26,7 @@ class RegexInputForm(forms.Form, BaseFormFieldPluginForm): ("help_text", ""), ("initial", ""), ("regex", ""), - ("max_length", "255"), + ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False), ("placeholder", ""), ] @@ -78,8 +79,10 @@ class RegexInputForm(forms.Form, BaseFormFieldPluginForm): max_length = forms.IntegerField( label=_("Max length"), required=True, - widget=NumberInput(attrs={'class': theme.form_element_html_class}), - initial=DEFAULT_MAX_LENGTH + widget=NumberInput(attrs={'class': theme.form_element_html_class, + 'min': str(DEFAULT_MIN_LENGTH)}), + initial=DEFAULT_MAX_LENGTH, + validators=[MinValueValidator(DEFAULT_MIN_LENGTH)] ) required = forms.BooleanField( label=_("Required"), @@ -95,3 +98,17 @@ class RegexInputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_html_class} ) ) + + def clean(self): + super(RegexInputForm, self).clean() + + max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) + + if self.cleaned_data['initial']: + len_initial = len(self.cleaned_data['initial']) + if len_initial > max_length: + self.add_error( + 'initial', + _("Ensure this value has at most {0} characters " + "(it has {1}).".format(max_length, len_initial)) + ) \ No newline at end of file diff --git a/src/fobi/contrib/plugins/form_elements/fields/slug/forms.py b/src/fobi/contrib/plugins/form_elements/fields/slug/forms.py index b4bf2310..90d13a03 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slug/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slug/forms.py @@ -1,8 +1,9 @@ from django import forms from django.utils.translation import ugettext_lazy as _ +from django.core.validators import MinValueValidator from fobi.base import BaseFormFieldPluginForm, get_theme -from fobi.settings import DEFAULT_MAX_LENGTH +from fobi.settings import DEFAULT_MAX_LENGTH, DEFAULT_MIN_LENGTH from fobi.widgets import NumberInput __title__ = 'fobi.contrib.plugins.form_elements.fields.slug.forms' @@ -22,7 +23,7 @@ class SlugInputForm(forms.Form, BaseFormFieldPluginForm): ("name", ""), ("help_text", ""), ("initial", ""), - ("max_length", "255"), + ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False), ("placeholder", ""), ] @@ -58,8 +59,10 @@ class SlugInputForm(forms.Form, BaseFormFieldPluginForm): max_length = forms.IntegerField( label=_("Max length"), required=True, - widget=NumberInput(attrs={'class': theme.form_element_html_class}), - initial=DEFAULT_MAX_LENGTH + widget=NumberInput(attrs={'class': theme.form_element_html_class, + 'min': str(DEFAULT_MIN_LENGTH)}), + initial=DEFAULT_MAX_LENGTH, + validators=[MinValueValidator(DEFAULT_MIN_LENGTH)] ) required = forms.BooleanField( label=_("Required"), @@ -75,3 +78,17 @@ class SlugInputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_html_class} ) ) + + def clean(self): + super(SlugInputForm, self).clean() + + max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) + + if self.cleaned_data['initial']: + len_initial = len(self.cleaned_data['initial']) + if len_initial > max_length: + self.add_error( + 'initial', + _("Ensure this value has at most {0} characters " + "(it has {1}).".format(max_length, len_initial)) + ) diff --git a/src/fobi/contrib/plugins/form_elements/fields/text/forms.py b/src/fobi/contrib/plugins/form_elements/fields/text/forms.py index 6424c247..a0f23483 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/text/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/text/forms.py @@ -1,8 +1,9 @@ from django import forms from django.utils.translation import ugettext_lazy as _ +from django.core.validators import MinValueValidator from fobi.base import BaseFormFieldPluginForm, get_theme -from fobi.settings import DEFAULT_MAX_LENGTH +from fobi.settings import DEFAULT_MAX_LENGTH, DEFAULT_MIN_LENGTH from fobi.widgets import NumberInput __title__ = 'fobi.contrib.plugins.form_elements.fields.text.forms' @@ -22,7 +23,7 @@ class TextInputForm(forms.Form, BaseFormFieldPluginForm): ("name", ""), ("help_text", ""), ("initial", ""), - ("max_length", "255"), + ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False), ("placeholder", ""), ] @@ -58,8 +59,10 @@ class TextInputForm(forms.Form, BaseFormFieldPluginForm): max_length = forms.IntegerField( label=_("Max length"), required=True, - widget=NumberInput(attrs={'class': theme.form_element_html_class}), - initial=DEFAULT_MAX_LENGTH + widget=NumberInput(attrs={'class': theme.form_element_html_class, + 'min': str(DEFAULT_MIN_LENGTH)}), + initial=DEFAULT_MAX_LENGTH, + validators=[MinValueValidator(DEFAULT_MIN_LENGTH)] ) required = forms.BooleanField( label=_("Required"), @@ -75,3 +78,17 @@ class TextInputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_html_class} ) ) + + def clean(self): + super(TextInputForm, self).clean() + + max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) + + if self.cleaned_data['initial']: + len_initial = len(self.cleaned_data['initial']) + if len_initial > max_length: + self.add_error( + 'initial', + _("Ensure this value has at most {0} characters " + "(it has {1}).".format(max_length, len_initial)) + ) \ No newline at end of file diff --git a/src/fobi/contrib/plugins/form_elements/fields/url/forms.py b/src/fobi/contrib/plugins/form_elements/fields/url/forms.py index d70ec735..c820c5cf 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/url/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/url/forms.py @@ -1,8 +1,9 @@ from django import forms from django.utils.translation import ugettext_lazy as _ +from django.core.validators import MinValueValidator from fobi.base import BaseFormFieldPluginForm, get_theme -from fobi.settings import DEFAULT_MAX_LENGTH +from fobi.settings import DEFAULT_MAX_LENGTH, DEFAULT_MIN_LENGTH from fobi.widgets import NumberInput __title__ = 'fobi.contrib.plugins.form_elements.fields.url.forms' @@ -22,7 +23,7 @@ class URLInputForm(forms.Form, BaseFormFieldPluginForm): ("name", ""), ("help_text", ""), ("initial", ""), - ("max_length", "255"), + ("max_length", str(DEFAULT_MAX_LENGTH)), ("required", False), ("placeholder", ""), ] @@ -58,8 +59,10 @@ class URLInputForm(forms.Form, BaseFormFieldPluginForm): max_length = forms.IntegerField( label=_("Max length"), required=True, - widget=NumberInput(attrs={'class': theme.form_element_html_class}), - initial=DEFAULT_MAX_LENGTH + widget=NumberInput(attrs={'class': theme.form_element_html_class, + 'min': str(DEFAULT_MIN_LENGTH)}), + initial=DEFAULT_MAX_LENGTH, + validators=[MinValueValidator(DEFAULT_MIN_LENGTH)] ) required = forms.BooleanField( label=_("Required"), @@ -75,3 +78,17 @@ class URLInputForm(forms.Form, BaseFormFieldPluginForm): attrs={'class': theme.form_element_html_class} ) ) + + def clean(self): + super(URLInputForm, self).clean() + + max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) + + if self.cleaned_data['initial']: + len_initial = len(self.cleaned_data['initial']) + if len_initial > max_length: + self.add_error( + 'initial', + _("Ensure this value has at most {0} characters " + "(it has {1}).".format(max_length, len_initial)) + ) diff --git a/src/fobi/defaults.py b/src/fobi/defaults.py index 44e346ab..204d5b4d 100644 --- a/src/fobi/defaults.py +++ b/src/fobi/defaults.py @@ -86,6 +86,7 @@ THEME_FOOTER_TEXT = '© django-fobi example site 2014' # ************************************************************** DEFAULT_MAX_LENGTH = 255 +DEFAULT_MIN_LENGTH = 1 FORM_HANDLER_PLUGINS_EXECUTION_ORDER = ( 'http_repost', diff --git a/src/fobi/settings.py b/src/fobi/settings.py index 572c9502..6cfbc142 100644 --- a/src/fobi/settings.py +++ b/src/fobi/settings.py @@ -38,6 +38,7 @@ __all__ = ( 'CUSTOM_THEME_DATA', 'THEME_FOOTER_TEXT', + 'DEFAULT_MIN_LENGTH', 'DEFAULT_MAX_LENGTH', 'FORM_HANDLER_PLUGINS_EXECUTION_ORDER', 'FORM_WIZARD_HANDLER_PLUGINS_EXECUTION_ORDER', @@ -101,6 +102,7 @@ THEME_FOOTER_TEXT = get_setting('THEME_FOOTER_TEXT') # ************************************************************** # ************************************************************** +DEFAULT_MIN_LENGTH = get_setting('DEFAULT_MIN_LENGTH') DEFAULT_MAX_LENGTH = get_setting('DEFAULT_MAX_LENGTH') FORM_HANDLER_PLUGINS_EXECUTION_ORDER = \ From 2b632353234760baa17abf950a458fe869bcf630 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 10 Nov 2016 23:00:48 +0100 Subject: [PATCH 30/39] add additional settings and scripts for foundation5 --- TODOS.rst | 16 ++++----- docs/fobi.contrib.apps.rst | 2 +- ...ins.form_elements.content.content_text.rst | 24 ++++++++++++++ ...ib.plugins.form_elements.fields.slider.rst | 8 +++++ docs/fobi.migrations.rst | 24 ++++++++++++++ .../foundation5-theme-django-1-10.sh | 1 + .../runserver/foundation5-theme-django-1-8.sh | 1 + .../runserver/foundation5-theme-django-1-9.sh | 1 + .../settings/foundation5_theme_django_1_10.py | 32 ++++++++++++++++++ .../settings/foundation5_theme_django_1_8.py | 31 +++++++++++++++++ .../settings/foundation5_theme_django_1_9.py | 33 +++++++++++++++++++ 11 files changed, 164 insertions(+), 9 deletions(-) create mode 100755 examples/simple/runserver/foundation5-theme-django-1-10.sh create mode 100755 examples/simple/runserver/foundation5-theme-django-1-8.sh create mode 100755 examples/simple/runserver/foundation5-theme-django-1-9.sh create mode 100644 examples/simple/settings/foundation5_theme_django_1_10.py create mode 100644 examples/simple/settings/foundation5_theme_django_1_8.py create mode 100644 examples/simple/settings/foundation5_theme_django_1_9.py diff --git a/TODOS.rst b/TODOS.rst index 469ff7ab..12ea98a3 100644 --- a/TODOS.rst +++ b/TODOS.rst @@ -54,6 +54,8 @@ Roadmap Uncategorised ------------- +- Implement the clone form functionality. +- Implement the clone form wizard functionality. - Rethink templating of the integration packages (feincms_integration, djangocms_integration, mezzanine_integration), as now they are a bit of a mess. Document integration properly, if not yet done. @@ -316,9 +318,7 @@ Uncategorised admin) as much generic so that change between versions doesn't cause styling issues. - Make sure the existing "simple" theme works very well (in looks) in - Django 1.6. -- Make sure the existing "simple" theme works very well (in looks) in - Django 1.7. + Django 1.8, 1.9 and 1.10. - Nicer styling for the radio button (Foundation 5 theme). - Nicer styling for the radio button (Simple theme). - Make it possible to provide an alternative rendering of the form field @@ -330,7 +330,7 @@ Uncategorised part). - Split the ``FOBI_RESTRICT_PLUGIN_ACCESS`` into two: one for form elements and one for form handlers. -- Improve the "simple" theme for Django 1.6 and Django 1.7 (tiny bits of +- Improve the "simple" theme for Django 1.8, 1.9 and 1.10 (tiny bits of styling). - Edit form test. - Edit form element tests. @@ -346,7 +346,7 @@ Uncategorised with the latest versions of the packages. - Add support for `imageurl` and `birthday` fields of MailChimp (they are ignored at the moment). -- Fix layout issue on step 2 of the MailChimp import (step 2 of the wizard). ++ Fix layout issue on step 2 of the MailChimp import (step 2 of the wizard). - Properly document the form importers API. - django-rest-framework integration. @@ -400,7 +400,7 @@ Should haves re-created form from saved JSON sa well. - Add `django-treebeard` field as an alternative (vs MPTT fields). - Make sure that all views are 100% AJAX ready. -- Wagtail integration. +- Wagtail integration (in progress since October 2016). - Document the changes. - Find out why subclassing the ``select_model_object`` plugin didn't work. - Rename the ``simple`` theme into ``django_admin_style_theme``. @@ -454,7 +454,7 @@ Could haves least the FeinCMS). - Make sure that the form view return can be overridden? - Add datetime range and date range fields. -- Configure defaults values of each plugin in projects' settings module. ++ Configure defaults values of each plugin in projects' settings module. - TinyMCE form element cosmetic plugin. - In the cosmetic image plugin, render the sized image. - Add Armenian translation. @@ -470,7 +470,7 @@ Could haves Would haves =========== - Conditional inputs. -- Form wizards (combine forms with each other, having one at a step, finally - ++ Form wizards (combine forms with each other, having one at a step, finally - send it all as one). - Perhaps, completely re-write the base template for the foundation 5 theme? - Make it possible to design a form based on existing models. diff --git a/docs/fobi.contrib.apps.rst b/docs/fobi.contrib.apps.rst index e2492825..ec91225f 100644 --- a/docs/fobi.contrib.apps.rst +++ b/docs/fobi.contrib.apps.rst @@ -9,7 +9,7 @@ Subpackages fobi.contrib.apps.djangocms_integration fobi.contrib.apps.feincms_integration fobi.contrib.apps.mezzanine_integration - fobi.contrib.apps.wagtail_integration + fobi.contrib.apps.wagtail_integration_ Module contents --------------- diff --git a/docs/fobi.contrib.plugins.form_elements.content.content_text.rst b/docs/fobi.contrib.plugins.form_elements.content.content_text.rst index 255b485f..75599544 100644 --- a/docs/fobi.contrib.plugins.form_elements.content.content_text.rst +++ b/docs/fobi.contrib.plugins.form_elements.content.content_text.rst @@ -12,6 +12,22 @@ fobi.contrib.plugins.form_elements.content.content_text.apps module :undoc-members: :show-inheritance: +fobi.contrib.plugins.form_elements.content.content_text.conf module +------------------------------------------------------------------- + +.. automodule:: fobi.contrib.plugins.form_elements.content.content_text.conf + :members: + :undoc-members: + :show-inheritance: + +fobi.contrib.plugins.form_elements.content.content_text.defaults module +----------------------------------------------------------------------- + +.. automodule:: fobi.contrib.plugins.form_elements.content.content_text.defaults + :members: + :undoc-members: + :show-inheritance: + fobi.contrib.plugins.form_elements.content.content_text.fobi_form_elements module --------------------------------------------------------------------------------- @@ -28,6 +44,14 @@ fobi.contrib.plugins.form_elements.content.content_text.forms module :undoc-members: :show-inheritance: +fobi.contrib.plugins.form_elements.content.content_text.settings module +----------------------------------------------------------------------- + +.. automodule:: fobi.contrib.plugins.form_elements.content.content_text.settings + :members: + :undoc-members: + :show-inheritance: + Module contents --------------- diff --git a/docs/fobi.contrib.plugins.form_elements.fields.slider.rst b/docs/fobi.contrib.plugins.form_elements.fields.slider.rst index f413d96e..702229a6 100644 --- a/docs/fobi.contrib.plugins.form_elements.fields.slider.rst +++ b/docs/fobi.contrib.plugins.form_elements.fields.slider.rst @@ -52,6 +52,14 @@ fobi.contrib.plugins.form_elements.fields.slider.forms module :undoc-members: :show-inheritance: +fobi.contrib.plugins.form_elements.fields.slider.helpers module +--------------------------------------------------------------- + +.. automodule:: fobi.contrib.plugins.form_elements.fields.slider.helpers + :members: + :undoc-members: + :show-inheritance: + fobi.contrib.plugins.form_elements.fields.slider.settings module ---------------------------------------------------------------- diff --git a/docs/fobi.migrations.rst b/docs/fobi.migrations.rst index 67a38f37..8580f06a 100644 --- a/docs/fobi.migrations.rst +++ b/docs/fobi.migrations.rst @@ -84,6 +84,30 @@ fobi.migrations.0010_formwizardhandler module :undoc-members: :show-inheritance: +fobi.migrations.0011_formentry_title module +------------------------------------------- + +.. automodule:: fobi.migrations.0011_formentry_title + :members: + :undoc-members: + :show-inheritance: + +fobi.migrations.0012_auto_20161109_1550 module +---------------------------------------------- + +.. automodule:: fobi.migrations.0012_auto_20161109_1550 + :members: + :undoc-members: + :show-inheritance: + +fobi.migrations.0013_formwizardentry_show_all_navigation_buttons module +----------------------------------------------------------------------- + +.. automodule:: fobi.migrations.0013_formwizardentry_show_all_navigation_buttons + :members: + :undoc-members: + :show-inheritance: + Module contents --------------- diff --git a/examples/simple/runserver/foundation5-theme-django-1-10.sh b/examples/simple/runserver/foundation5-theme-django-1-10.sh new file mode 100755 index 00000000..b59057b3 --- /dev/null +++ b/examples/simple/runserver/foundation5-theme-django-1-10.sh @@ -0,0 +1 @@ +./manage.py runserver 0.0.0.0:8001 --traceback -v 3 --settings=settings.foundation5_theme_django_1_10 --traceback -v 3 diff --git a/examples/simple/runserver/foundation5-theme-django-1-8.sh b/examples/simple/runserver/foundation5-theme-django-1-8.sh new file mode 100755 index 00000000..5f1c2fb5 --- /dev/null +++ b/examples/simple/runserver/foundation5-theme-django-1-8.sh @@ -0,0 +1 @@ +./manage.py runserver 0.0.0.0:8001 --traceback -v 3 --settings=settings.foundation5_theme_django_1_8 --traceback -v 3 diff --git a/examples/simple/runserver/foundation5-theme-django-1-9.sh b/examples/simple/runserver/foundation5-theme-django-1-9.sh new file mode 100755 index 00000000..e51eb1d4 --- /dev/null +++ b/examples/simple/runserver/foundation5-theme-django-1-9.sh @@ -0,0 +1 @@ +./manage.py runserver 0.0.0.0:8001 --traceback -v 3 --settings=settings.foundation5_theme_django_1_9 --traceback -v 3 diff --git a/examples/simple/settings/foundation5_theme_django_1_10.py b/examples/simple/settings/foundation5_theme_django_1_10.py new file mode 100644 index 00000000..26ebe70e --- /dev/null +++ b/examples/simple/settings/foundation5_theme_django_1_10.py @@ -0,0 +1,32 @@ +from .base import * + +INSTALLED_APPS = list(INSTALLED_APPS) + +try: + INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None + INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None + INSTALLED_APPS.remove('localeurl') if 'localeurl' in INSTALLED_APPS else None +except Exception as e: + pass + +try: + INSTALLED_APPS.remove('admin_tools') \ + if 'admin_tools' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.menu') \ + if 'admin_tools.menu' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.dashboard') \ + if 'admin_tools.dashboard' in INSTALLED_APPS else None +except Exception as e: + pass + +FOBI_DEFAULT_THEME = 'foundation5' + +INSTALLED_APPS = list(INSTALLED_APPS) + +INSTALLED_APPS.append( + 'fobi.contrib.themes.foundation5.widgets.form_elements.date_foundation5_widget' +) +INSTALLED_APPS.append( + 'fobi.contrib.themes.foundation5.widgets.form_elements.datetime_foundation5_widget' +) + diff --git a/examples/simple/settings/foundation5_theme_django_1_8.py b/examples/simple/settings/foundation5_theme_django_1_8.py new file mode 100644 index 00000000..1e0fb6d1 --- /dev/null +++ b/examples/simple/settings/foundation5_theme_django_1_8.py @@ -0,0 +1,31 @@ +from .base import * + +INSTALLED_APPS = list(INSTALLED_APPS) + +try: + INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None + INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None +except Exception as e: + pass + +try: + INSTALLED_APPS.remove('admin_tools') \ + if 'admin_tools' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.menu') \ + if 'admin_tools.menu' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.dashboard') \ + if 'admin_tools.dashboard' in INSTALLED_APPS else None +except Exception as e: + pass + +FOBI_DEFAULT_THEME = 'foundation5' + +INSTALLED_APPS = list(INSTALLED_APPS) + +INSTALLED_APPS.append( + 'fobi.contrib.themes.foundation5.widgets.form_elements.date_foundation5_widget' +) +INSTALLED_APPS.append( + 'fobi.contrib.themes.foundation5.widgets.form_elements.datetime_foundation5_widget' +) + diff --git a/examples/simple/settings/foundation5_theme_django_1_9.py b/examples/simple/settings/foundation5_theme_django_1_9.py new file mode 100644 index 00000000..1f4d4a0e --- /dev/null +++ b/examples/simple/settings/foundation5_theme_django_1_9.py @@ -0,0 +1,33 @@ +from .base import * + +INSTALLED_APPS = list(INSTALLED_APPS) + +try: + INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None + INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None + INSTALLED_APPS.remove( + 'localeurl') if 'localeurl' in INSTALLED_APPS else None +except Exception as e: + pass + +try: + INSTALLED_APPS.remove('admin_tools') \ + if 'admin_tools' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.menu') \ + if 'admin_tools.menu' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.dashboard') \ + if 'admin_tools.dashboard' in INSTALLED_APPS else None +except Exception as e: + pass + +FOBI_DEFAULT_THEME = 'foundation5' + +INSTALLED_APPS = list(INSTALLED_APPS) + +INSTALLED_APPS.append( + 'fobi.contrib.themes.foundation5.widgets.form_elements.date_foundation5_widget' +) +INSTALLED_APPS.append( + 'fobi.contrib.themes.foundation5.widgets.form_elements.datetime_foundation5_widget' +) + From bd229270c1b75cdbb40884640cb86485d6c81fd3 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 10 Nov 2016 23:10:27 +0100 Subject: [PATCH 31/39] changes in tox --- tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 21722f2e..049bd366 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,9 @@ [tox] envlist = # py{27,33,34}-{django15,django16}, - py{27,33,34}-{django17,django18} - py{27,34}-{django17,django18} - py{27,34}-{django19} +# py{27,33,34}-{django17,django18} +# py{27,34}-{django17,django18} + py{27,34,35}-{django18,django19} py{27,35}-{django110} #flake8, #isort From 501f6c2c38726a3ca075ab52aaecb53c27b3399f Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 10 Nov 2016 23:14:00 +0100 Subject: [PATCH 32/39] changelog and credits updated --- CHANGELOG.rst | 6 ++++++ CREDITS.rst | 3 +++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 41fc03a4..1a22128d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,12 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.9.17 +------ +yyyy-mm-dd (not released yet) + +- Value validations for Integer and Text Fields. + 0.9.16 ------ 2016-11-10 diff --git a/CREDITS.rst b/CREDITS.rst index a9997b54..0916da9f 100644 --- a/CREDITS.rst +++ b/CREDITS.rst @@ -32,3 +32,6 @@ Thanks to the following people for their contributions: - `Michal Dabski `_ for minor fixes. +- `Marcos Amorim + `_ + for number of validation improvements. From c763ee4edea8280b278e039f719b2db53a5e94d9 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 11 Nov 2016 01:08:11 +0100 Subject: [PATCH 33/39] readme fixes --- README.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 1004756b..ee45ca15 100644 --- a/README.rst +++ b/README.rst @@ -1989,16 +1989,22 @@ Testing ======= Project is covered by test (functional- and browser-tests). -To test type: +To test with all supported Python/Django versions type: -.. code:: sh +.. code-block:: sh tox +To test just your working environment type: + +.. code-block:: sh + + ./runtests.py + It's assumed that you have all the requirements installed. If not, first install the test requirements: -.. code:: sh +.. code-block:: sh pip install -r examples/requirements/common_test_requirements.txt @@ -2018,7 +2024,7 @@ Set up Firefox 47 2. Specify the full path to your Firefox in ``FIREFOX_BIN_PATH`` setting. Example: - .. code:: python + .. code-block:: python FIREFOX_BIN_PATH = '/usr/lib/firefox47/firefox' From 0e32ccecfa24f899888daa64f2892ef42fbbd5a3 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Sun, 13 Nov 2016 00:19:51 +0100 Subject: [PATCH 34/39] prepare 0.9.17 --- CHANGELOG.rst | 13 ++- CREDITS.rst | 4 +- README.rst | 79 +++++++++++-------- examples/simple/urls.py | 28 +++++-- setup.py | 2 +- src/fobi/__init__.py | 4 +- .../generic/snippets/form_wizard_ajax.html | 2 +- tox.ini | 2 +- 8 files changed, 84 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1a22128d..3d35479b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,9 +17,14 @@ are used for versioning (schema follows below): 0.9.17 ------ -yyyy-mm-dd (not released yet) +2016-11-13 + +Announcing dropping support of Python 2.6 and Django 1.7. As of 0.9.17 +everything is still backwards compatible with Django 1.7, but in future +versions it will be wiped out. - Value validations for Integer and Text Fields. +- Hide previous button in form wizard template for bootstrap3 on first step. 0.9.16 ------ @@ -44,9 +49,9 @@ yyyy-mm-dd (not released yet) ------ 2016-11-05 -Officially announcing dropping support for Django 1.5 and 1.6. At the -moment everything is still backwards compatible with versions 1.5 and 1.6, -but in future versions compatibility with those versions would be wiped out. +Announcing dropping support of Django 1.5 and 1.6. As of 0.9.17 everything is +still backwards compatible with versions 1.5 and 1.6, but in future versions +compatibility with these versions will be wiped out. - Fix backwards compatibility of `slider` and `range_select` plugins with Django versions 1.5 and 1.6. diff --git a/CREDITS.rst b/CREDITS.rst index 0916da9f..47d75aea 100644 --- a/CREDITS.rst +++ b/CREDITS.rst @@ -33,5 +33,5 @@ Thanks to the following people for their contributions: `_ for minor fixes. - `Marcos Amorim - `_ - for number of validation improvements. + `_ + for number of validation improvements. diff --git a/README.rst b/README.rst index ee45ca15..03ba6e19 100644 --- a/README.rst +++ b/README.rst @@ -10,8 +10,21 @@ handling the submitted form data). Prerequisites ============= -- Django 1.5, 1.6, 1.7, 1.8, 1.9, 1.10 -- Python >= 2.6.8, >= 2.7, >= 3.3 +Current +------- +- Django 1.8, 1.9, 1.10 +- Python >= 2.7, >= 3.3 + +Past +---- +- Dropping support of Django 1.5, 1.6 has been announced in version + 0.9.13. Dropping support of Django 1.7 has been announced in version 0.9.17. + As of 0.9.17 everything is still backwards compatible with versions 1.5, 1.6 + and 1.7, but in future versions compatibility with these versions will be + wiped out. +- Dropping support of Python 2.6 has been announced in version 0.9.17. + As of 0.9.17 everything is still backwards compatible with Python 2.6, but + in future versions compatibility with it will be wiped out. Key concepts ============ @@ -1783,56 +1796,58 @@ Note, that you should not provide the `fobi_dynamic_values.` as a prefix. Currently, the following variables are available in the `fobi.context_processors.dynamic_values` context processor: -- request: Stripped HttpRequest object. +.. code-block:: text - - request.path: A string representing the full path to the requested page, - not including the scheme or domain. + - request: Stripped HttpRequest object. - - request.get_full_path(): Returns the path, plus an appended query string, - if applicable. + - request.path: A string representing the full path to the requested page, + not including the scheme or domain. - - request.is_secure(): Returns True if the request is secure; that is, if - it was made with HTTPS. + - request.get_full_path(): Returns the path, plus an appended query string, + if applicable. - - request.is_ajax(): Returns True if the request was made via an - XMLHttpRequest, by checking the HTTP_X_REQUESTED_WITH header for the - string 'XMLHttpRequest'. + - request.is_secure(): Returns True if the request is secure; that is, if + it was made with HTTPS. - - request.META: A stripped down standard Python dictionary containing the - available HTTP headers. + - request.is_ajax(): Returns True if the request was made via an + XMLHttpRequest, by checking the HTTP_X_REQUESTED_WITH header for the + string 'XMLHttpRequest'. - - HTTP_ACCEPT_ENCODING: Acceptable encodings for the response. + - request.META: A stripped down standard Python dictionary containing the + available HTTP headers. - - HTTP_ACCEPT_LANGUAGE: Acceptable languages for the response. + - HTTP_ACCEPT_ENCODING: Acceptable encodings for the response. - - HTTP_HOST: The HTTP Host header sent by the client. + - HTTP_ACCEPT_LANGUAGE: Acceptable languages for the response. - - HTTP_REFERER: The referring page, if any. + - HTTP_HOST: The HTTP Host header sent by the client. - - HTTP_USER_AGENT: The client’s user-agent string. + - HTTP_REFERER: The referring page, if any. - - QUERY_STRING: The query string, as a single (unparsed) string. + - HTTP_USER_AGENT: The client’s user-agent string. - - REMOTE_ADDR: The IP address of the client. + - QUERY_STRING: The query string, as a single (unparsed) string. - - request.user: Authenticated user. + - REMOTE_ADDR: The IP address of the client. - - request.user.email: + - request.user: Authenticated user. - - request.user.get_username(): Returns the username for the user. Since - the User model can be swapped out, you should use this method - instead of referencing the username attribute directly. + - request.user.email: - - request.user.get_full_name(): Returns the first_name plus the - last_name, with a space in between. + - request.user.get_username(): Returns the username for the user. Since + the User model can be swapped out, you should use this method + instead of referencing the username attribute directly. - - request.user.get_short_name(): Returns the first_name. + - request.user.get_full_name(): Returns the first_name plus the + last_name, with a space in between. - - request.user.is_anonymous(): + - request.user.get_short_name(): Returns the first_name. -- now: datetime.datetime.now() + - request.user.is_anonymous(): -- today: datetime.date.today() + - now: datetime.datetime.now() + + - today: datetime.date.today() Submitted form element plugins values ===================================== diff --git a/examples/simple/urls.py b/examples/simple/urls.py index 43eaf7ac..94165112 100644 --- a/examples/simple/urls.py +++ b/examples/simple/urls.py @@ -8,6 +8,8 @@ from django.views.generic import TemplateView from fobi.settings import DEFAULT_THEME +from nine import versions + admin.autodiscover() # Mapping. @@ -29,7 +31,7 @@ if DEFAULT_THEME in ('simple', 'djangocms_admin_style_theme'): urlpatterns = [] -urlpatterns += i18n_patterns( +url_patterns_args = [ # DB Store plugin URLs # namespace='fobi' url(r'^fobi/plugins/form-handlers/db-store/', @@ -59,7 +61,12 @@ urlpatterns += i18n_patterns( # django-fobi public forms contrib app: # url(r'^', include('fobi.contrib.apps.public_forms.urls')), -) +] + +if versions.DJANGO_LTE_1_7: + urlpatterns += i18n_patterns('', *url_patterns_args) +else: + urlpatterns += i18n_patterns(*url_patterns_args) # Serving media and static in debug/developer mode. if settings.DEBUG: @@ -72,17 +79,24 @@ if settings.DEBUG: if 'feincms' in settings.INSTALLED_APPS: from page.models import Page Page - urlpatterns += i18n_patterns( + url_patterns_args = [ url(r'^pages/', include('feincms.urls')), - - ) + ] + if versions.DJANGO_LTE_1_7: + urlpatterns += i18n_patterns('', *url_patterns_args) + else: + urlpatterns += i18n_patterns(*url_patterns_args) # Conditionally including DjangoCMS URls in case if # DjangoCMS in installed apps. if 'cms' in settings.INSTALLED_APPS: - urlpatterns += i18n_patterns( + url_patterns_args = [ url(r'^cms-pages/', include('cms.urls')), - ) + ] + if versions.DJANGO_LTE_1_7: + urlpatterns += i18n_patterns('', *url_patterns_args) + else: + urlpatterns += i18n_patterns(*url_patterns_args) # Conditionally including Captcha URls in case if # Captcha in installed apps. diff --git a/setup.py b/setup.py index 9c4cf149..ceb289c9 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.9.16' +version = '0.9.17' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index 23765cba..9f80bdc3 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.9.16' -__build__ = 0x000071 +__version__ = '0.9.17' +__build__ = 0x000072 __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/templates/fobi/generic/snippets/form_wizard_ajax.html b/src/fobi/templates/fobi/generic/snippets/form_wizard_ajax.html index bbf1aa81..101a6790 100644 --- a/src/fobi/templates/fobi/generic/snippets/form_wizard_ajax.html +++ b/src/fobi/templates/fobi/generic/snippets/form_wizard_ajax.html @@ -15,7 +15,7 @@
    {% block form_buttons %} - {% if form_wizard_entry.show_all_navigation_buttons %} + {% if form_wizard_entry.show_all_navigation_buttons and wizard.steps.prev %} {% block form_wizard_first_button_wrapper %}{% endblock form_wizard_first_button_wrapper %} {% block form_wizard_previous_button_wrapper %}{% endblock form_wizard_previous_button_wrapper %} {% endif %} diff --git a/tox.ini b/tox.ini index 049bd366..09e60123 100644 --- a/tox.ini +++ b/tox.ini @@ -14,7 +14,7 @@ passenv = * deps = # django15: -r{toxinidir}/examples/requirements/django_1_5.txt # django16: -r{toxinidir}/examples/requirements/django_1_6.txt - django17: -r{toxinidir}/examples/requirements/django_1_7.txt +# django17: -r{toxinidir}/examples/requirements/django_1_7.txt django18: -r{toxinidir}/examples/requirements/django_1_8.txt django19: -r{toxinidir}/examples/requirements/django_1_9.txt django110: -r{toxinidir}/examples/requirements/django_1_10.txt From d3232ff071eab0e2a276aee15d250792c58440cd Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Mon, 14 Nov 2016 21:39:10 +0100 Subject: [PATCH 35/39] docs updated --- docs/index.rst | 93 +++++++++++++++++++++++-------------- scripts/build_docs.sh | 3 +- scripts/compile_messages.sh | 3 -- scripts/touch_docs.sh | 1 + 4 files changed, 59 insertions(+), 41 deletions(-) create mode 100755 scripts/touch_docs.sh diff --git a/docs/index.rst b/docs/index.rst index 54712daa..f7a15489 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -10,8 +10,21 @@ handling the submitted form data). Prerequisites ============= -- Django 1.5, 1.6, 1.7, 1.8, 1.9, 1.10 -- Python >= 2.6.8, >= 2.7, >= 3.3 +Current +------- +- Django 1.8, 1.9, 1.10 +- Python >= 2.7, >= 3.3 + +Past +---- +- Dropping support of Django 1.5, 1.6 has been announced in version + 0.9.13. Dropping support of Django 1.7 has been announced in version 0.9.17. + As of 0.9.17 everything is still backwards compatible with versions 1.5, 1.6 + and 1.7, but in future versions compatibility with these versions will be + wiped out. +- Dropping support of Python 2.6 has been announced in version 0.9.17. + As of 0.9.17 everything is still backwards compatible with Python 2.6, but + in future versions compatibility with it will be wiped out. Key concepts ============ @@ -1783,56 +1796,58 @@ Note, that you should not provide the `fobi_dynamic_values.` as a prefix. Currently, the following variables are available in the `fobi.context_processors.dynamic_values` context processor: -- request: Stripped HttpRequest object. +.. code-block:: text - - request.path: A string representing the full path to the requested page, - not including the scheme or domain. + - request: Stripped HttpRequest object. - - request.get_full_path(): Returns the path, plus an appended query string, - if applicable. + - request.path: A string representing the full path to the requested page, + not including the scheme or domain. - - request.is_secure(): Returns True if the request is secure; that is, if - it was made with HTTPS. + - request.get_full_path(): Returns the path, plus an appended query string, + if applicable. - - request.is_ajax(): Returns True if the request was made via an - XMLHttpRequest, by checking the HTTP_X_REQUESTED_WITH header for the - string 'XMLHttpRequest'. + - request.is_secure(): Returns True if the request is secure; that is, if + it was made with HTTPS. - - request.META: A stripped down standard Python dictionary containing the - available HTTP headers. + - request.is_ajax(): Returns True if the request was made via an + XMLHttpRequest, by checking the HTTP_X_REQUESTED_WITH header for the + string 'XMLHttpRequest'. - - HTTP_ACCEPT_ENCODING: Acceptable encodings for the response. + - request.META: A stripped down standard Python dictionary containing the + available HTTP headers. - - HTTP_ACCEPT_LANGUAGE: Acceptable languages for the response. + - HTTP_ACCEPT_ENCODING: Acceptable encodings for the response. - - HTTP_HOST: The HTTP Host header sent by the client. + - HTTP_ACCEPT_LANGUAGE: Acceptable languages for the response. - - HTTP_REFERER: The referring page, if any. + - HTTP_HOST: The HTTP Host header sent by the client. - - HTTP_USER_AGENT: The client’s user-agent string. + - HTTP_REFERER: The referring page, if any. - - QUERY_STRING: The query string, as a single (unparsed) string. + - HTTP_USER_AGENT: The client’s user-agent string. - - REMOTE_ADDR: The IP address of the client. + - QUERY_STRING: The query string, as a single (unparsed) string. - - request.user: Authenticated user. + - REMOTE_ADDR: The IP address of the client. - - request.user.email: + - request.user: Authenticated user. - - request.user.get_username(): Returns the username for the user. Since - the User model can be swapped out, you should use this method - instead of referencing the username attribute directly. + - request.user.email: - - request.user.get_full_name(): Returns the first_name plus the - last_name, with a space in between. + - request.user.get_username(): Returns the username for the user. Since + the User model can be swapped out, you should use this method + instead of referencing the username attribute directly. - - request.user.get_short_name(): Returns the first_name. + - request.user.get_full_name(): Returns the first_name plus the + last_name, with a space in between. - - request.user.is_anonymous(): + - request.user.get_short_name(): Returns the first_name. -- now: datetime.datetime.now() + - request.user.is_anonymous(): -- today: datetime.date.today() + - now: datetime.datetime.now() + + - today: datetime.date.today() Submitted form element plugins values ===================================== @@ -1989,16 +2004,22 @@ Testing ======= Project is covered by test (functional- and browser-tests). -To test type: +To test with all supported Python/Django versions type: -.. code:: sh +.. code-block:: sh tox +To test just your working environment type: + +.. code-block:: sh + + ./runtests.py + It's assumed that you have all the requirements installed. If not, first install the test requirements: -.. code:: sh +.. code-block:: sh pip install -r examples/requirements/common_test_requirements.txt @@ -2018,7 +2039,7 @@ Set up Firefox 47 2. Specify the full path to your Firefox in ``FIREFOX_BIN_PATH`` setting. Example: - .. code:: python + .. code-block:: python FIREFOX_BIN_PATH = '/usr/lib/firefox47/firefox' diff --git a/scripts/build_docs.sh b/scripts/build_docs.sh index 6ffead85..c4a09fcb 100755 --- a/scripts/build_docs.sh +++ b/scripts/build_docs.sh @@ -1,8 +1,7 @@ ./scripts/uninstall.sh ./scripts/install.sh -#cd .. cat README.rst SCREENSHOTS.rst docs/documentation.rst.distrib > docs/index.rst cat QUICK_START.rst > docs/quickstart.rst sphinx-build -n -a -b html docs builddocs cd builddocs && zip -r ../builddocs.zip . -x ".*" && cd .. -#cd scripts + diff --git a/scripts/compile_messages.sh b/scripts/compile_messages.sh index 064f3662..eddf8aff 100755 --- a/scripts/compile_messages.sh +++ b/scripts/compile_messages.sh @@ -1,4 +1,3 @@ -#cd .. echo 'Compiling messages for django-fobi...' cd src/fobi/ #django-admin.py compilemessages -l hy @@ -12,5 +11,3 @@ cd ../../examples/simple/ django-admin.py compilemessages -l de django-admin.py compilemessages -l nl django-admin.py compilemessages -l ru - -#cd ../../scripts \ No newline at end of file diff --git a/scripts/touch_docs.sh b/scripts/touch_docs.sh new file mode 100755 index 00000000..92975c0c --- /dev/null +++ b/scripts/touch_docs.sh @@ -0,0 +1 @@ +cat README.rst SCREENSHOTS.rst docs/documentation.rst.distrib > docs/index.rst From 4cf22a9ceef1f8fa385c29473ffc57e58d8cfb91 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 17 Nov 2016 00:07:06 +0100 Subject: [PATCH 36/39] prepare 0.10; added additional args to submit_plugin_form_data; added tests for mailchimp importer plugin; moving plugins to base submodules, having them only registered in fobi_form_elements submodule; disable google analytics in tests; helper scripts updated; multiple pep8 fixes; minor fixes --- CHANGELOG.rst | 27 ++ README.rst | 8 +- ROADMAP.rst | 2 +- TODOS.rst | 2 + docs/index.rst | 8 +- .../simple/admin_tools_dashboard/__init__.py | 137 ++++--- examples/simple/admin_tools_dashboard/conf.py | 16 +- examples/simple/admin_tools_dashboard/menu.py | 57 +-- examples/simple/bar/models.py | 2 +- examples/simple/context_processors.py | 9 +- examples/simple/customauth/__init__.py | 2 +- examples/simple/customauth/admin.py | 8 +- examples/simple/foo/fobi_form_callbacks.py | 2 +- .../fobi_form_elements.py | 3 +- .../fobi_form_elements.py | 3 +- .../override_simple_theme/fobi_themes.py | 2 +- examples/simple/settings/base.py | 147 ++++---- .../settings/bootstrap3_theme_captcha.py | 6 +- .../settings/bootstrap3_theme_django_1_10.py | 5 +- .../bootstrap3_theme_django_1_7_captcha.py | 4 +- .../bootstrap3_theme_django_1_7_djangocms.py | 26 +- .../bootstrap3_theme_django_1_7_feincms.py | 14 +- .../settings/bootstrap3_theme_django_1_8.py | 4 +- .../settings/bootstrap3_theme_djangocms.py | 26 +- .../settings/bootstrap3_theme_djangocms_2.py | 41 ++- .../settings/bootstrap3_theme_feincms.py | 19 +- .../simple/settings/bootstrap3_theme_mptt.py | 12 +- .../bootstrap3_theme_python_3_django_1_8.py | 15 +- .../settings/bootstrap3_theme_recaptcha.py | 12 +- .../djangocms_admin_style_theme_djangocms.py | 19 +- examples/simple/settings/foundation5.py | 6 +- .../settings/foundation5_theme_django_1_10.py | 12 +- .../settings/foundation5_theme_django_1_8.py | 11 +- .../settings/foundation5_theme_django_1_9.py | 13 +- .../settings/foundation5_theme_feincms.py | 6 +- examples/simple/settings/settings_test.py | 19 +- examples/simple/settings/simple.py | 6 +- examples/simple/settings/test.py | 28 +- .../simple/templates/bootstrap3/base.html | 4 +- scripts/pycodestyle.sh | 2 + scripts/pycodestyle_example.sh | 2 + setup.py | 2 +- src/fobi/__init__.py | 4 +- src/fobi/base.py | 38 +- .../content/content_image/base.py | 86 +++++ .../content_image/fobi_form_elements.py | 79 +--- .../content/content_text/base.py | 46 +++ .../content_text/fobi_form_elements.py | 39 +- .../content/content_video/base.py | 51 +++ .../content_video/fobi_form_elements.py | 44 +-- .../form_elements/fields/boolean/base.py | 34 ++ .../fields/boolean/fobi_form_elements.py | 29 +- .../fields/checkbox_select_multiple/base.py | 91 +++++ .../fobi_form_elements.py | 86 +---- .../plugins/form_elements/fields/date/base.py | 72 ++++ .../fields/date/fobi_form_elements.py | 64 +--- .../fields/date_drop_down/base.py | 54 +++ .../date_drop_down/fobi_form_elements.py | 46 +-- .../form_elements/fields/datetime/base.py | 73 ++++ .../fields/datetime/fobi_form_elements.py | 64 +--- .../form_elements/fields/decimal/base.py | 60 +++ .../fields/decimal/fobi_form_elements.py | 52 +-- .../form_elements/fields/email/base.py | 53 +++ .../fields/email/fobi_form_elements.py | 44 +-- .../plugins/form_elements/fields/file/base.py | 74 ++++ .../fields/file/fobi_form_elements.py | 66 +--- .../form_elements/fields/float/base.py | 52 +++ .../fields/float/fobi_form_elements.py | 45 +-- .../form_elements/fields/hidden/base.py | 45 +++ .../fields/hidden/fobi_form_elements.py | 38 +- .../form_elements/fields/input/base.py | 88 +++++ .../fields/input/fobi_form_elements.py | 81 +--- .../form_elements/fields/integer/base.py | 52 +++ .../fields/integer/fobi_form_elements.py | 45 +-- .../form_elements/fields/ip_address/base.py | 47 +++ .../fields/ip_address/fobi_form_elements.py | 42 +-- .../form_elements/fields/null_boolean/base.py | 42 +++ .../fields/null_boolean/fobi_form_elements.py | 35 +- .../form_elements/fields/password/base.py | 47 +++ .../fields/password/fobi_form_elements.py | 40 +- .../form_elements/fields/radio/base.py | 88 +++++ .../fields/radio/fobi_form_elements.py | 79 +--- .../form_elements/fields/range_select/base.py | 61 +++ .../fields/range_select/fobi_form_elements.py | 54 +-- .../form_elements/fields/regex/base.py | 49 +++ .../fields/regex/fobi_form_elements.py | 42 +-- .../form_elements/fields/regex/forms.py | 3 +- .../form_elements/fields/select/base.py | 87 +++++ .../fields/select/fobi_form_elements.py | 78 +--- .../fields/select_model_object/base.py | 107 ++++++ .../select_model_object/fobi_form_elements.py | 97 +---- .../fields/select_mptt_model_object/base.py | 107 ++++++ .../fobi_form_elements.py | 97 +---- .../fields/select_multiple/base.py | 98 +++++ .../select_multiple/fobi_form_elements.py | 88 +---- .../select_multiple_model_objects/base.py | 118 ++++++ .../fobi_form_elements.py | 108 +----- .../base.py | 118 ++++++ .../fobi_form_elements.py | 108 +----- .../fields/select_multiple_with_max/base.py | 99 +++++ .../fobi_form_elements.py | 89 +---- .../form_elements/fields/slider/base.py | 210 +++++++++++ .../fields/slider/fobi_form_elements.py | 204 +--------- .../plugins/form_elements/fields/slug/base.py | 47 +++ .../fields/slug/fobi_form_elements.py | 40 +- .../plugins/form_elements/fields/text/base.py | 47 +++ .../fields/text/fobi_form_elements.py | 40 +- .../form_elements/fields/text/forms.py | 3 +- .../form_elements/fields/textarea/base.py | 44 +++ .../fields/textarea/fobi_form_elements.py | 37 +- .../plugins/form_elements/fields/time/base.py | 72 ++++ .../fields/time/fobi_form_elements.py | 64 +--- .../plugins/form_elements/fields/url/base.py | 58 +++ .../fields/url/fobi_form_elements.py | 51 +-- .../security/captcha/fobi_form_elements.py | 2 + .../form_elements/security/honeypot/base.py | 48 +++ .../security/honeypot/fobi_form_elements.py | 43 +-- .../security/recaptcha/fobi_form_elements.py | 2 + .../plugins/form_elements/test/dummy/base.py | 46 +++ .../test/dummy/fobi_form_elements.py | 39 +- src/fobi/helpers.py | 1 + src/fobi/models.py | 4 +- src/fobi/tests/data.py | 347 ++++++++++++++---- src/fobi/tests/helpers.py | 74 ++-- .../tests/test_browser_build_dynamic_forms.py | 72 ++-- src/fobi/tests/test_core.py | 13 +- src/fobi/tests/test_dynamic_forms.py | 9 +- .../tests/test_form_importers_mailchimp.py | 263 +++---------- src/fobi/tests/test_sortable_dict.py | 2 +- src/fobi/validators.py | 6 +- src/fobi/views.py | 17 +- 131 files changed, 3592 insertions(+), 2885 deletions(-) create mode 100755 scripts/pycodestyle.sh create mode 100755 scripts/pycodestyle_example.sh create mode 100644 src/fobi/contrib/plugins/form_elements/content/content_image/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/content/content_text/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/content/content_video/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/boolean/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/date/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/date_drop_down/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/datetime/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/decimal/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/email/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/file/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/float/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/hidden/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/input/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/integer/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/ip_address/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/null_boolean/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/password/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/radio/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/range_select/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/regex/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/select/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/select_model_object/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/select_mptt_model_object/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/select_multiple/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/select_multiple_model_objects/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/select_multiple_mptt_model_objects/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/select_multiple_with_max/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/slider/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/slug/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/text/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/textarea/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/time/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/fields/url/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/security/honeypot/base.py create mode 100644 src/fobi/contrib/plugins/form_elements/test/dummy/base.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3d35479b..e5b875c4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,33 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.10 +---- +2016-11-16 + +Note, that this release contains minor backwards incompatible changes, that may +break your code. Two additional arguments have been added to the +`submit_plugin_form_data` method of the form element plugins. If you have +written custom form element plugins - update your code. + +Note, that this release contain minor backwards incompatible changes, that +may break your existing code (your data is left intact). If you have written +custom form element plugins you should update your code! + +- Added `form_entry_elements` and `kwargs` to the `submit_plugin_form_data` + method of the form element plugins. Make sure to update your custom + plugins if you have written any. +- Added tests for mailchimp integration plugin. +- Moving all plugins to base submodules of the correspondent sub + packages. +- Add missing whitespace toe the `help_text` of the `title` field of + `FormEntry` and `FormWizardEntry` models. +- Disable GoogleAnalytics while testing (guess what - this change speeds up + selenium tests twice). +- Docs updated. +- Helper scripts updated. +- Multiple pep8 fixes. + 0.9.17 ------ 2016-11-13 diff --git a/README.rst b/README.rst index 03ba6e19..77fe5550 100644 --- a/README.rst +++ b/README.rst @@ -102,7 +102,7 @@ Roadmap ======= Some of the upcoming/in-development features/improvements are: -- Integration with `django-rest-framework` (in version 0.10). +- Integration with `django-rest-framework` (in version 0.11). See the `TODOS `_ for the full list of planned-, pending- in-development- or to-be-implemented @@ -429,12 +429,16 @@ following arguments: - `request` (django.http.HttpRequest): The Django HTTP request. - `form` (django.forms.Form): Form object (a valid one, which contains the ``cleaned_data`` attribute). +- `form_element_entries` (fobi.models.FormElementEntry): Form element entries + for the `form_entry` given. +- **kwargs: Additional arguments. Example (taken from fobi.contrib.plugins.form_elements.fields.file): .. code-block:: python - def submit_plugin_form_data(self, form_entry, request, form): + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): """Submit plugin form data.""" # Get the file path file_path = form.cleaned_data.get(self.data.name, None) diff --git a/ROADMAP.rst b/ROADMAP.rst index bc9bf6e7..131679c7 100644 --- a/ROADMAP.rst +++ b/ROADMAP.rst @@ -1,6 +1,6 @@ Roadmap of upcoming releases ============================ -0.10 +0.11 ---- yyyy-mm-ddd (upcoming). diff --git a/TODOS.rst b/TODOS.rst index 12ea98a3..6b38a5b6 100644 --- a/TODOS.rst +++ b/TODOS.rst @@ -45,6 +45,8 @@ Regarding the form wizards - Add selenium tests for form wizards. - Make `foundation5` and `django-admin-theme` themes to reflect the latest GUI changes (form wizards). +- Make sure captcha plugins are usable with form wizards (at the moment they + are being invalidated on the last step). Roadmap ------- diff --git a/docs/index.rst b/docs/index.rst index f7a15489..f8c82521 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -102,7 +102,7 @@ Roadmap ======= Some of the upcoming/in-development features/improvements are: -- Integration with `django-rest-framework` (in version 0.10). +- Integration with `django-rest-framework` (in version 0.11). See the `TODOS `_ for the full list of planned-, pending- in-development- or to-be-implemented @@ -429,12 +429,16 @@ following arguments: - `request` (django.http.HttpRequest): The Django HTTP request. - `form` (django.forms.Form): Form object (a valid one, which contains the ``cleaned_data`` attribute). +- `form_element_entries` (fobi.models.FormElementEntry): Form element entries + for the `form_entry` given. +- **kwargs: Additional arguments. Example (taken from fobi.contrib.plugins.form_elements.fields.file): .. code-block:: python - def submit_plugin_form_data(self, form_entry, request, form): + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): """Submit plugin form data.""" # Get the file path file_path = form.cleaned_data.get(self.data.name, None) diff --git a/examples/simple/admin_tools_dashboard/__init__.py b/examples/simple/admin_tools_dashboard/__init__.py index d34f6eb5..2acccc1e 100644 --- a/examples/simple/admin_tools_dashboard/__init__.py +++ b/examples/simple/admin_tools_dashboard/__init__.py @@ -1,5 +1,5 @@ """ -This file was generated with the customdashboard management command, it +This file was generated with the custom dashboard management command, it contains the two classes for the main dashboard and app index dashboard. You can customize these classes as you want. @@ -7,83 +7,110 @@ To activate your index dashboard add the following to your settings.py:: ADMIN_TOOLS_INDEX_DASHBOARD = 'admin_tools_dashboard.CustomIndexDashboard' And to activate the app index dashboard:: - ADMIN_TOOLS_APP_INDEX_DASHBOARD = 'admin_tools_dashboard.CustomAppIndexDashboard' + ADMIN_TOOLS_APP_INDEX_DASHBOARD = \ + 'admin_tools_dashboard.CustomAppIndexDashboard' """ - from django.conf import settings -from django.utils.translation import ugettext, ugettext_lazy as _ +from django.utils.translation import ugettext_lazy as _ from admin_tools.dashboard import modules, Dashboard, AppIndexDashboard -from admin_tools.utils import get_admin_site_name +# from admin_tools.utils import get_admin_site_name from . import conf + class CustomIndexDashboard(Dashboard): - """ - Custom index dashboard. - """ + """Custom index dashboard.""" + columns = 3 def init_with_context(self, context): - ## Foo - #self.children.append(modules.ModelList(_('Foo'), - # models = conf.foo_apps, - # collapsible = False, - # deletable = False - #)) + # Foo + # self.children.append( + # modules.ModelList( + # _('Foo'), + # models=conf.foo_apps, + # collapsible=False, + # deletable=False + # ) + # ) # Fobi - self.children.append(modules.Group( - title = _('Fobi'), - display = 'stacked', - children = [ - modules.ModelList(_('Plugins'), models=conf.fobi_plugins, collapsible=False, deletable=False), - modules.ModelList(_('Forms'), models=conf.fobi_forms, collapsible=False, deletable=False), - modules.ModelList(_('Data'), models=conf.fobi_data, collapsible=False, deletable=False), - ] - )) + self.children.append( + modules.Group( + title=_('Fobi'), + display='stacked', + children=[ + modules.ModelList( + _('Plugins'), + models=conf.fobi_plugins, + collapsible=False, + deletable=False + ), + modules.ModelList( + _('Forms'), + models=conf.fobi_forms, + collapsible=False, + deletable=False + ), + modules.ModelList( + _('Data'), + models=conf.fobi_data, + collapsible=False, + deletable=False + ), + ] + ) + ) if 'feincms' in settings.INSTALLED_APPS: # FeinCMS pages - self.children.append(modules.AppList( - _('FeinCMS Pages'), - models = conf.feincms_pages, - collapsible = False, - deletable = False - )) + self.children.append( + modules.AppList( + _('FeinCMS Pages'), + models=conf.feincms_pages, + collapsible=False, + deletable=False + ) + ) if 'cms' in settings.INSTALLED_APPS: # DjangoCMS pages - self.children.append(modules.AppList( - _('DjangoCMS Pages'), - models = conf.djangocms_pages, - collapsible = False, - deletable = False - )) + self.children.append( + modules.AppList( + _('DjangoCMS Pages'), + models=conf.djangocms_pages, + collapsible=False, + deletable=False + ) + ) # Append an app list module for "Administration" - self.children.append(modules.AppList( - _('Administration'), - models = conf.django_contrib_apps, - collapsible = False, - deletable = False - )) + self.children.append( + modules.AppList( + _('Administration'), + models=conf.django_contrib_apps, + collapsible=False, + deletable=False + ) + ) # Append an app list module for "Administration" - self.children.append(modules.AppList( - _('Other apps'), - models = conf.other_apps, - collapsible = False, - deletable = False - )) + self.children.append( + modules.AppList( + _('Other apps'), + models=conf.other_apps, + collapsible=False, + deletable=False + ) + ) # Append a recent actions module self.children.append(modules.RecentActions(_('Recent Actions'), 10)) + class CustomAppIndexDashboard(AppIndexDashboard): - """ - Custom app index dashboard for netcommunities. - """ + """Custom app index dashboard.""" # We disable title because its redundant with the model list module title = '' @@ -91,14 +118,14 @@ class CustomAppIndexDashboard(AppIndexDashboard): def __init__(self, *args, **kwargs): AppIndexDashboard.__init__(self, *args, **kwargs) - self.children.append(modules.RecentActions( + self.children.append( + modules.RecentActions( _('Recent Actions'), include_list=self.get_app_content_types(), limit=10 - )) + ) + ) def init_with_context(self, context): - """ - Use this method if you need to access the request context. - """ + """Use this method if you need to access the request context.""" return super(CustomAppIndexDashboard, self).init_with_context(context) diff --git a/examples/simple/admin_tools_dashboard/conf.py b/examples/simple/admin_tools_dashboard/conf.py index 780111a7..193e9d83 100644 --- a/examples/simple/admin_tools_dashboard/conf.py +++ b/examples/simple/admin_tools_dashboard/conf.py @@ -2,19 +2,23 @@ # ************ Foo ************** # ******************************* foo_apps = [ - 'foo.models.*', 'bar.models.*', + 'foo.models.*', + 'bar.models.*', ] # ******************************* # ************ Fobi ************* # ******************************* fobi_plugins = [ - 'fobi.models.FormElement', 'fobi.models.FormHandler' + 'fobi.models.FormElement', + 'fobi.models.FormHandler' ] fobi_forms = [ - 'fobi.models.FormWizardEntry', 'fobi.models.FormEntry', - 'fobi.models.FormElementEntry', 'fobi.models.FormFieldsetEntry', + 'fobi.models.FormWizardEntry', + 'fobi.models.FormEntry', + 'fobi.models.FormElementEntry', + 'fobi.models.FormFieldsetEntry', 'fobi.models.FormHandlerEntry', ] @@ -33,5 +37,7 @@ djangocms_pages = [ # ******************************* # ************ Django *********** # ******************************* -django_contrib_apps = ['django.contrib.*',] +django_contrib_apps = [ + 'django.contrib.*', +] other_apps = foo_apps diff --git a/examples/simple/admin_tools_dashboard/menu.py b/examples/simple/admin_tools_dashboard/menu.py index 3a7e268c..157e8153 100644 --- a/examples/simple/admin_tools_dashboard/menu.py +++ b/examples/simple/admin_tools_dashboard/menu.py @@ -27,39 +27,50 @@ class CustomMenu(Menu): ] # Foo - self.children.append(items.ModelList(_('Foo'), - models=conf.foo_apps - )) + self.children.append( + items.ModelList( + _('Foo'), + models=conf.foo_apps + ) + ) # Fobi - self.children.append(items.MenuItem( - _('Fobi'), - children=[ - items.ModelList(_('Plugins'), models=conf.fobi_plugins), - items.ModelList(_('Forms'), models=conf.fobi_forms), - items.ModelList(_('Data'), models=conf.fobi_data), - ] - )) + self.children.append( + items.MenuItem( + _('Fobi'), + children=[ + items.ModelList(_('Plugins'), models=conf.fobi_plugins), + items.ModelList(_('Forms'), models=conf.fobi_forms), + items.ModelList(_('Data'), models=conf.fobi_data), + ] + ) + ) if 'feincms' in settings.INSTALLED_APPS: # FeinCMS pages integration - self.children.append(items.AppList( - _('FeinCMS Pages'), - models=conf.feincms_pages - )) + self.children.append( + items.AppList( + _('FeinCMS Pages'), + models=conf.feincms_pages + ) + ) if 'cms' in settings.INSTALLED_APPS: # DjangoCMS pages integration - self.children.append(items.AppList( - _('DjangoCMS Pages'), - models=conf.djangocms_pages - )) + self.children.append( + items.AppList( + _('DjangoCMS Pages'), + models=conf.djangocms_pages + ) + ) # append an app list module for "Administration" - self.children.append(items.AppList( - _('Administration'), - models=['django.contrib.*',] - )) + self.children.append( + items.AppList( + _('Administration'), + models=['django.contrib.*'] + ) + ) def init_with_context(self, context): """Use this method if you need to access the request context.""" diff --git a/examples/simple/bar/models.py b/examples/simple/bar/models.py index c509b8db..a96a4317 100644 --- a/examples/simple/bar/models.py +++ b/examples/simple/bar/models.py @@ -19,7 +19,7 @@ class Genre(MPTTModel): """MPTT meta.""" # level_attr = 'mptt_level' - order_insertion_by=['name'] + order_insertion_by = ['name'] def __str__(self): return self.name diff --git a/examples/simple/context_processors.py b/examples/simple/context_processors.py index 0e0620ba..25aad7c5 100644 --- a/examples/simple/context_processors.py +++ b/examples/simple/context_processors.py @@ -1,6 +1,13 @@ -__all__ = ('disable_admin_tools',) +from django.conf import settings + +__all__ = ('disable_admin_tools', 'testing',) def disable_admin_tools(request): """Disable admin tools.""" return {'ADMIN_TOOLS_DISABLED': True} + + +def testing(request): + """Put `testing` into context.""" + return {'testing': settings.TESTING} diff --git a/examples/simple/customauth/__init__.py b/examples/simple/customauth/__init__.py index 512b7328..1800d4bf 100644 --- a/examples/simple/customauth/__init__.py +++ b/examples/simple/customauth/__init__.py @@ -1 +1 @@ -from customauth.models import MyUser \ No newline at end of file +from .models import MyUser diff --git a/examples/simple/customauth/admin.py b/examples/simple/customauth/admin.py index 7f7f74e3..56aea2a9 100644 --- a/examples/simple/customauth/admin.py +++ b/examples/simple/customauth/admin.py @@ -93,11 +93,9 @@ class MyUserAdmin(UserAdmin): # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin # overrides get_fieldsets to use this attribute when creating a user. add_fieldsets = ( - (None, { - 'classes': ('wide',), - 'fields': ('username', 'email', 'first_name', 'last_name', - 'date_of_birth', 'password1', 'password2')} - ) + (None, {'classes': ('wide',), + 'fields': ('username', 'email', 'first_name', 'last_name', + 'date_of_birth', 'password1', 'password2')}), ) search_fields = ('email',) ordering = ('email',) diff --git a/examples/simple/foo/fobi_form_callbacks.py b/examples/simple/foo/fobi_form_callbacks.py index 1e09b81e..3f3eb10a 100644 --- a/examples/simple/foo/fobi_form_callbacks.py +++ b/examples/simple/foo/fobi_form_callbacks.py @@ -13,7 +13,7 @@ from fobi.constants import ( logger = logging.getLogger('fobi') -__all__= ( +__all__ = ( 'SaveAsFooItem', 'DummyInvalidCallback', ) diff --git a/examples/simple/override_radio_plugin/fobi_form_elements.py b/examples/simple/override_radio_plugin/fobi_form_elements.py index 347221fb..9d21a1e1 100644 --- a/examples/simple/override_radio_plugin/fobi_form_elements.py +++ b/examples/simple/override_radio_plugin/fobi_form_elements.py @@ -38,7 +38,8 @@ class RadioInputPlugin(FormFieldPlugin): return [(self.data.name, ChoiceField, field_kwargs)] - def submit_plugin_form_data(self, form_entry, request, form): + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): """Submit plugin form data/process. :param fobi.models.FormEntry form_entry: Instance of diff --git a/examples/simple/override_select_model_object_plugin/fobi_form_elements.py b/examples/simple/override_select_model_object_plugin/fobi_form_elements.py index 2353f2d3..0123ec17 100644 --- a/examples/simple/override_select_model_object_plugin/fobi_form_elements.py +++ b/examples/simple/override_select_model_object_plugin/fobi_form_elements.py @@ -40,7 +40,8 @@ class SelectModelObjectInputPlugin(FormFieldPlugin): return [(self.data.name, ModelChoiceField, field_kwargs)] - def submit_plugin_form_data(self, form_entry, request, form): + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): """Submit plugin form data/process. :param fobi.models.FormEntry form_entry: Instance of diff --git a/examples/simple/override_simple_theme/fobi_themes.py b/examples/simple/override_simple_theme/fobi_themes.py index 752f425a..67c9b143 100644 --- a/examples/simple/override_simple_theme/fobi_themes.py +++ b/examples/simple/override_simple_theme/fobi_themes.py @@ -8,7 +8,7 @@ __all__ = ('MySimpleTheme',) class MySimpleTheme(SimpleTheme): """Overriding the "simple" theme.""" - html_classes = ['my-simple-theme',] + html_classes = ['my-simple-theme'] base_view_template = 'override_simple_theme/base_view.html' form_ajax = 'override_simple_theme/snippets/form_ajax.html' form_snippet_template_name = \ diff --git a/examples/simple/settings/base.py b/examples/simple/settings/base.py index 58415c6a..5b46b8a0 100644 --- a/examples/simple/settings/base.py +++ b/examples/simple/settings/base.py @@ -4,8 +4,18 @@ from nine.versions import ( DJANGO_GTE_1_7, DJANGO_GTE_1_8, DJANGO_LTE_1_7, DJANGO_GTE_1_9, DJANGO_GTE_1_10 ) -PROJECT_DIR = lambda base : os.path.abspath(os.path.join(os.path.dirname(__file__), base).replace('\\','/')) -gettext = lambda s: s + + +def project_dir(base): + return os.path.abspath( + os.path.join(os.path.dirname(__file__), base).replace('\\', '/') + ) + +PROJECT_DIR = project_dir + + +def gettext(s): + return s # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(__file__)) @@ -22,13 +32,18 @@ MANAGERS = ADMINS DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': PROJECT_DIR('../../db/example.db'), # Or path to database file if using sqlite3. + # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + 'ENGINE': 'django.db.backends.sqlite3', + # Or path to database file if using sqlite3. + 'NAME': PROJECT_DIR('../../db/example.db'), # The following settings are not used with sqlite3: 'USER': '', 'PASSWORD': '', - 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': '', # Set to empty string for default. + # Empty for localhost through domain sockets or '127.0.0.1' for + # localhost through TCP. + 'HOST': '', + # Set to empty string for default. + 'PORT': '', } } @@ -47,7 +62,7 @@ TIME_ZONE = 'America/Chicago' LANGUAGE_CODE = 'en' LANGUAGES = ( - ('en', gettext("English")), # Main language! + ('en', gettext("English")), # Main language! ('hy', gettext("Armenian")), ('nl', gettext("Dutch")), ('ru', gettext("Russian")), @@ -67,7 +82,8 @@ USE_L10N = True # If you set this to False, Django will not use timezone-aware datetimes. USE_TZ = True -# Absolute filesystem path to the directory that will hold user-uploaded files. +# Absolute filesystem path to the directory that will hold user-uploaded +# files. # Example: "/var/www/example.com/media/" MEDIA_ROOT = PROJECT_DIR(os.path.join('..', '..', 'media')) @@ -115,7 +131,7 @@ if DJANGO_GTE_1_10: { 'BACKEND': 'django.template.backends.django.DjangoTemplates', # 'APP_DIRS': True, - 'DIRS': [PROJECT_DIR(os.path.join('..', 'templates')),], + 'DIRS': [PROJECT_DIR(os.path.join('..', 'templates'))], 'OPTIONS': { 'context_processors': [ "django.template.context_processors.debug", @@ -128,6 +144,7 @@ if DJANGO_GTE_1_10: "django.contrib.messages.context_processors.messages", "fobi.context_processors.theme", # Important! "fobi.context_processors.dynamic_values", # Optional + "context_processors.testing", # Testing ], 'loaders': [ 'django.template.loaders.filesystem.Loader', @@ -144,7 +161,7 @@ elif DJANGO_GTE_1_8: { 'BACKEND': 'django.template.backends.django.DjangoTemplates', # 'APP_DIRS': True, - 'DIRS': [PROJECT_DIR(os.path.join('..', 'templates')),], + 'DIRS': [PROJECT_DIR(os.path.join('..', 'templates'))], 'OPTIONS': { 'context_processors': [ "django.contrib.auth.context_processors.auth", @@ -155,8 +172,9 @@ elif DJANGO_GTE_1_8: "django.template.context_processors.tz", "django.contrib.messages.context_processors.messages", "django.template.context_processors.request", - "fobi.context_processors.theme", # Important! - "fobi.context_processors.dynamic_values", # Optional + "fobi.context_processors.theme", # Important! + "fobi.context_processors.dynamic_values", # Optional + "context_processors.testing", # Testing ], 'loaders': [ 'django.template.loaders.filesystem.Loader', @@ -171,7 +189,8 @@ elif DJANGO_GTE_1_8: else: TEMPLATE_DEBUG = DEBUG_TEMPLATE - # List of callables that know how to import templates from various sources. + # List of callables that know how to import templates from various + # sources. TEMPLATE_LOADERS = [ 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', @@ -190,12 +209,14 @@ else: "django.core.context_processors.tz", "django.contrib.messages.context_processors.messages", "django.core.context_processors.request", - "fobi.context_processors.theme", # Important! - "fobi.context_processors.dynamic_values", # Optional + "fobi.context_processors.theme", # Important! + "fobi.context_processors.dynamic_values", # Optional + "context_processors.testing", # Testing ) TEMPLATE_DIRS = ( - # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". + # Put strings here, like "/home/html/django_templates" or + # "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. PROJECT_DIR(os.path.join('..', 'templates')), @@ -203,7 +224,6 @@ else: MIDDLEWARE_CLASSES = [ 'django.contrib.sessions.middleware.SessionMiddleware', - # 'localeurl.middleware.LocaleURLMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -212,9 +232,6 @@ MIDDLEWARE_CLASSES = [ # 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] -# if DJANGO_GTE_1_8: -# MIDDLEWARE_CLASSES.remove('localeurl.middleware.LocaleURLMiddleware') - ROOT_URLCONF = 'urls' # Python dotted path to the WSGI application used by Django's runserver. @@ -245,7 +262,6 @@ INSTALLED_APPS = [ # 'tinymce', # TinyMCE 'easy_thumbnails', # Thumbnailer 'registration', # Auth views and registration app - # 'localeurl', # Locale URL # *********************************************************************** # *********************************************************************** @@ -339,17 +355,23 @@ INSTALLED_APPS = [ # *********************************************************************** 'fobi.contrib.themes.bootstrap3', # Bootstrap 3 theme # DateTime widget - 'fobi.contrib.themes.bootstrap3.widgets.form_elements.datetime_bootstrap3_widget', - 'fobi.contrib.themes.bootstrap3.widgets.form_elements.date_bootstrap3_widget', + 'fobi.contrib.themes.bootstrap3.widgets.form_elements.' + 'datetime_bootstrap3_widget', + + 'fobi.contrib.themes.bootstrap3.widgets.form_elements.' + 'date_bootstrap3_widget', # SliderPercentage widget - 'fobi.contrib.themes.bootstrap3.widgets.form_elements.slider_bootstrap3_widget', + 'fobi.contrib.themes.bootstrap3.widgets.form_elements.' + 'slider_bootstrap3_widget', # *********************************************************************** # ************************ Foundation 5 theme *************************** # *********************************************************************** 'fobi.contrib.themes.foundation5', # Foundation 5 theme - 'fobi.contrib.themes.foundation5.widgets.form_handlers.db_store_foundation5_widget', + + 'fobi.contrib.themes.foundation5.widgets.form_handlers.' + 'db_store_foundation5_widget', # *********************************************************************** # **************************** Simple theme ***************************** @@ -374,9 +396,6 @@ INSTALLED_APPS = [ if DJANGO_LTE_1_7: INSTALLED_APPS.append('south') -# if DJANGO_GTE_1_8: -# INSTALLED_APPS.remove('localeurl') - # LOGIN_URL = '/accounts/login/' # LOGIN_REDIRECT_URL = '/fobi/' # Important for passing the selenium tests @@ -384,23 +403,12 @@ if DJANGO_LTE_1_7: LOGIN_URL = '/en/accounts/login/' LOGIN_REDIRECT_URL = '/en/fobi/' # Important for passing the selenium tests -#LOGIN_URL = '/accounts/login/' -#LOGIN_ERROR_URL = '/accounts/login/' -#LOGOUT_URL = '/accounts/logout/' +# LOGIN_URL = '/accounts/login/' +# LOGIN_ERROR_URL = '/accounts/login/' +# LOGOUT_URL = '/accounts/logout/' -# if not DJANGO_GTE_1_8: -# # Tell localeurl to use sessions for language store. -# LOCALEURL_USE_SESSION = True -# -# # localeurl locale independent paths (language code won't be appended) -# LOCALE_INDEPENDENT_PATHS = ( -# r'^/sitemap.*\.xml$', # Global regex for all XML sitemaps -# r'^/admin/', -# #r'^/dashboard/', -# ) - -PACKAGE_NAME_FILEBROWSER = "filebrowser_safe" # Just for tests -PACKAGE_NAME_GRAPPELLI = "grappelli_safe" # Just for tests +PACKAGE_NAME_FILEBROWSER = "filebrowser_safe" # Just for tests +PACKAGE_NAME_GRAPPELLI = "grappelli_safe" # Just for tests MIGRATION_MODULES = { 'fobi': 'migrations', @@ -431,8 +439,10 @@ FOBI_CUSTOM_THEME_DATA = { ], 'success_page_template_choices': [ ( - 'fobi/bootstrap3_extras/embed_form_entry_submitted_ajax.html', - gettext("Custom bootstrap3 embed form entry submitted template") + 'fobi/bootstrap3_extras/embed_form_entry_' + 'submitted_ajax.html', + gettext("Custom bootstrap3 embed form entry submitted " + "template") ), ], }, @@ -445,8 +455,10 @@ FOBI_CUSTOM_THEME_DATA = { ], 'success_page_template_choices': [ ( - 'fobi/bootstrap3_extras/embed_form_entry_submitted_ajax.html', - gettext("Custom bootstrap3 embed form entry submitted template") + 'fobi/bootstrap3_extras/embed_form_entry_submitted_' + 'ajax.html', + gettext("Custom bootstrap3 embed form entry submitted " + "template") ), ], }, @@ -467,8 +479,10 @@ FOBI_CUSTOM_THEME_DATA = { ], 'success_page_template_choices': [ ( - 'fobi/foundation5_extras/embed_form_entry_submitted_ajax.html', - gettext("Custom foundation5 embed form entry submitted template") + 'fobi/foundation5_extras/embed_form_entry_submitted_' + 'ajax.html', + gettext("Custom foundation5 embed form entry submitted " + "template") ), ], }, @@ -481,8 +495,10 @@ FOBI_CUSTOM_THEME_DATA = { ], 'success_page_template_choices': [ ( - 'fobi/foundation5_extras/embed_form_entry_submitted_ajax.html', - gettext("Custom foundation5 embed form entry submitted template") + 'fobi/foundation5_extras/embed_form_entry_submitted_' + 'ajax.html', + gettext("Custom foundation5 embed form entry submitted " + "template") ), ], }, @@ -505,7 +521,8 @@ FOBI_THEME_FOOTER_TEXT = gettext('© django-fobi example site 2014-2015') # django-admin-tools custom dashboard ADMIN_TOOLS_INDEX_DASHBOARD = 'admin_tools_dashboard.CustomIndexDashboard' -ADMIN_TOOLS_APP_INDEX_DASHBOARD = 'admin_tools_dashboard.CustomAppIndexDashboard' +ADMIN_TOOLS_APP_INDEX_DASHBOARD = \ + 'admin_tools_dashboard.CustomAppIndexDashboard' ADMIN_TOOLS_MENU = 'admin_tools_dashboard.menu.CustomMenu' SOUTH_MIGRATION_MODULES = { @@ -537,7 +554,8 @@ LOGGING = { }, 'formatters': { 'verbose': { - 'format': '\n%(levelname)s %(asctime)s [%(pathname)s:%(lineno)s] %(message)s' + 'format': '\n%(levelname)s %(asctime)s [%(pathname)s:%(lineno)s] ' + '%(message)s' }, 'simple': { 'format': '\n%(levelname)s %(message)s' @@ -555,32 +573,32 @@ LOGGING = { 'formatter': 'verbose' }, 'all_log': { - 'level':'DEBUG', - 'class':'logging.handlers.RotatingFileHandler', + 'level': 'DEBUG', + 'class': 'logging.handlers.RotatingFileHandler', 'filename': PROJECT_DIR("../../logs/all.log"), 'maxBytes': 1048576, 'backupCount': 99, 'formatter': 'verbose', }, 'django_log': { - 'level':'DEBUG', - 'class':'logging.handlers.RotatingFileHandler', + 'level': 'DEBUG', + 'class': 'logging.handlers.RotatingFileHandler', 'filename': PROJECT_DIR("../../logs/django.log"), 'maxBytes': 1048576, 'backupCount': 99, 'formatter': 'verbose', }, 'django_request_log': { - 'level':'DEBUG', - 'class':'logging.handlers.RotatingFileHandler', + 'level': 'DEBUG', + 'class': 'logging.handlers.RotatingFileHandler', 'filename': PROJECT_DIR("../../logs/django_request.log"), 'maxBytes': 1048576, 'backupCount': 99, 'formatter': 'verbose', }, 'fobi_log': { - 'level':'DEBUG', - 'class':'logging.handlers.RotatingFileHandler', + 'level': 'DEBUG', + 'class': 'logging.handlers.RotatingFileHandler', 'filename': PROJECT_DIR("../../logs/fobi.log"), 'maxBytes': 1048576, 'backupCount': 99, @@ -635,6 +653,9 @@ if DJANGO_GTE_1_7 or DJANGO_GTE_1_8: # For Selenium tests FIREFOX_BIN_PATH = '' +# Testing mode +TESTING = False + # Do not put any settings below this line try: from .local_settings import * @@ -665,7 +686,7 @@ if DEBUG: try: # Make sure the django-template-debug is installed. You can then # in templates use it as follows: - # + # # {% load debug_tags %} # {% set_trace %} import template_debug diff --git a/examples/simple/settings/bootstrap3_theme_captcha.py b/examples/simple/settings/bootstrap3_theme_captcha.py index 2794b9c4..2d8ed0dd 100644 --- a/examples/simple/settings/bootstrap3_theme_captcha.py +++ b/examples/simple/settings/bootstrap3_theme_captcha.py @@ -4,8 +4,10 @@ INSTALLED_APPS = list(INSTALLED_APPS) try: INSTALLED_APPS.append('captcha') - INSTALLED_APPS.append('fobi.contrib.plugins.form_elements.security.captcha') + INSTALLED_APPS.append( + 'fobi.contrib.plugins.form_elements.security.captcha' + ) except Exception as e: pass -#FOBI_DEFAULT_THEME = 'simple' +# FOBI_DEFAULT_THEME = 'simple' diff --git a/examples/simple/settings/bootstrap3_theme_django_1_10.py b/examples/simple/settings/bootstrap3_theme_django_1_10.py index e1b4f27c..4a5d0b53 100644 --- a/examples/simple/settings/bootstrap3_theme_django_1_10.py +++ b/examples/simple/settings/bootstrap3_theme_django_1_10.py @@ -5,8 +5,7 @@ INSTALLED_APPS = list(INSTALLED_APPS) try: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None - INSTALLED_APPS.remove('localeurl') if 'localeurl' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass try: @@ -16,5 +15,5 @@ try: if 'admin_tools.menu' in INSTALLED_APPS else None INSTALLED_APPS.remove('admin_tools.dashboard') \ if 'admin_tools.dashboard' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass diff --git a/examples/simple/settings/bootstrap3_theme_django_1_7_captcha.py b/examples/simple/settings/bootstrap3_theme_django_1_7_captcha.py index 73b1f4c3..0a479970 100755 --- a/examples/simple/settings/bootstrap3_theme_django_1_7_captcha.py +++ b/examples/simple/settings/bootstrap3_theme_django_1_7_captcha.py @@ -6,6 +6,8 @@ try: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None INSTALLED_APPS.append('captcha') - INSTALLED_APPS.append('fobi.contrib.plugins.form_elements.security.captcha') + INSTALLED_APPS.append( + 'fobi.contrib.plugins.form_elements.security.captcha' + ) except Exception as e: pass diff --git a/examples/simple/settings/bootstrap3_theme_django_1_7_djangocms.py b/examples/simple/settings/bootstrap3_theme_django_1_7_djangocms.py index 458af220..b955c070 100644 --- a/examples/simple/settings/bootstrap3_theme_django_1_7_djangocms.py +++ b/examples/simple/settings/bootstrap3_theme_django_1_7_djangocms.py @@ -2,40 +2,40 @@ from .base import * INSTALLED_APPS = list(INSTALLED_APPS) INSTALLED_APPS += [ - 'cms', # DjangoCMS + 'cms', # DjangoCMS 'mptt', 'menus', 'sekizai', - #'djangocms_admin_style', + # 'djangocms_admin_style', # Some plugins 'djangocms_picture', 'djangocms_snippet', - 'fobi.contrib.apps.djangocms_integration', # Fobi DjangoCMS app + 'fobi.contrib.apps.djangocms_integration', # Fobi DjangoCMS app - #'djangocms_page', # Example + # 'djangocms_page', # Example ] try: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None - #INSTALLED_APPS.remove('admin_tools') \ + # INSTALLED_APPS.remove('admin_tools') \ # if 'admin_tools' in INSTALLED_APPS else None - #INSTALLED_APPS.remove('admin_tools.menu') \ + # INSTALLED_APPS.remove('admin_tools.menu') \ # if 'admin_tools.menu' in INSTALLED_APPS else None INSTALLED_APPS.remove('admin_tools.dashboard') \ if 'admin_tools.dashboard' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass MIDDLEWARE_CLASSES = list(MIDDLEWARE_CLASSES) MIDDLEWARE_CLASSES += [ - #'django.middleware.cache.UpdateCacheMiddleware', + # 'django.middleware.cache.UpdateCacheMiddleware', 'cms.middleware.page.CurrentPageMiddleware', 'cms.middleware.user.CurrentUserMiddleware', 'cms.middleware.toolbar.ToolbarMiddleware', 'cms.middleware.language.LanguageCookieMiddleware', - #'django.middleware.cache.FetchFromCacheMiddleware', + # 'django.middleware.cache.FetchFromCacheMiddleware', ] TEMPLATE_CONTEXT_PROCESSORS = list(TEMPLATE_CONTEXT_PROCESSORS) @@ -46,8 +46,8 @@ TEMPLATE_CONTEXT_PROCESSORS += [ ] FOBI_DEFAULT_THEME = 'bootstrap3' -#FOBI_DEFAULT_THEME = 'foundation5' -#FOBI_DEFAULT_THEME = 'simple' +# FOBI_DEFAULT_THEME = 'foundation5' +# FOBI_DEFAULT_THEME = 'simple' CMS_TEMPLATES = ( ('cms_page/{0}/page_with_sidebar.html'.format(FOBI_DEFAULT_THEME), @@ -63,6 +63,6 @@ MIGRATION_MODULES = { LANGUAGE_CODE = 'en' -#FEINCMS_RICHTEXT_INIT_CONTEXT = { +# FEINCMS_RICHTEXT_INIT_CONTEXT = { # 'TINYMCE_JS_URL': STATIC_URL + 'tiny_mce/tiny_mce.js', -#} +# } diff --git a/examples/simple/settings/bootstrap3_theme_django_1_7_feincms.py b/examples/simple/settings/bootstrap3_theme_django_1_7_feincms.py index 212b37d2..13371298 100644 --- a/examples/simple/settings/bootstrap3_theme_django_1_7_feincms.py +++ b/examples/simple/settings/bootstrap3_theme_django_1_7_feincms.py @@ -4,17 +4,19 @@ INSTALLED_APPS = list(INSTALLED_APPS) try: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None - #INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None - INSTALLED_APPS.remove('admin_tools.dashboard') if 'admin_tools.dashboard' in INSTALLED_APPS else None + # INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None + INSTALLED_APPS.remove('admin_tools.dashboard') \ + if 'admin_tools.dashboard' in INSTALLED_APPS \ + else None INSTALLED_APPS += [ - 'feincms', # FeinCMS + 'feincms', # FeinCMS - 'fobi.contrib.apps.feincms_integration', # Fobi FeinCMS app + 'fobi.contrib.apps.feincms_integration', # Fobi FeinCMS app - 'page', # Example + 'page', # Example ] -except Exception as e: +except Exception as err: pass diff --git a/examples/simple/settings/bootstrap3_theme_django_1_8.py b/examples/simple/settings/bootstrap3_theme_django_1_8.py index 780c3631..4a5d0b53 100644 --- a/examples/simple/settings/bootstrap3_theme_django_1_8.py +++ b/examples/simple/settings/bootstrap3_theme_django_1_8.py @@ -5,7 +5,7 @@ INSTALLED_APPS = list(INSTALLED_APPS) try: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass try: @@ -15,5 +15,5 @@ try: if 'admin_tools.menu' in INSTALLED_APPS else None INSTALLED_APPS.remove('admin_tools.dashboard') \ if 'admin_tools.dashboard' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass diff --git a/examples/simple/settings/bootstrap3_theme_djangocms.py b/examples/simple/settings/bootstrap3_theme_djangocms.py index 2cb234c8..b2025f47 100644 --- a/examples/simple/settings/bootstrap3_theme_djangocms.py +++ b/examples/simple/settings/bootstrap3_theme_djangocms.py @@ -2,39 +2,39 @@ from .base import * INSTALLED_APPS = list(INSTALLED_APPS) INSTALLED_APPS += [ - 'cms', # DjangoCMS + 'cms', # DjangoCMS 'mptt', 'menus', 'sekizai', - #'djangocms_admin_style', + # 'djangocms_admin_style', # Some plugins 'djangocms_picture', 'djangocms_snippet', - 'fobi.contrib.apps.djangocms_integration', # Fobi DjangoCMS app + 'fobi.contrib.apps.djangocms_integration', # Fobi DjangoCMS app - #'djangocms_page', # Example + # 'djangocms_page', # Example ] try: - #INSTALLED_APPS.remove('admin_tools') \ + # INSTALLED_APPS.remove('admin_tools') \ # if 'admin_tools' in INSTALLED_APPS else None - #INSTALLED_APPS.remove('admin_tools.menu') \ + # INSTALLED_APPS.remove('admin_tools.menu') \ # if 'admin_tools.menu' in INSTALLED_APPS else None INSTALLED_APPS.remove('admin_tools.dashboard') \ if 'admin_tools.dashboard' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass MIDDLEWARE_CLASSES = list(MIDDLEWARE_CLASSES) MIDDLEWARE_CLASSES += [ - #'django.middleware.cache.UpdateCacheMiddleware', + # 'django.middleware.cache.UpdateCacheMiddleware', 'cms.middleware.page.CurrentPageMiddleware', 'cms.middleware.user.CurrentUserMiddleware', 'cms.middleware.toolbar.ToolbarMiddleware', 'cms.middleware.language.LanguageCookieMiddleware', - #'django.middleware.cache.FetchFromCacheMiddleware', + # 'django.middleware.cache.FetchFromCacheMiddleware', ] TEMPLATE_CONTEXT_PROCESSORS = list(TEMPLATE_CONTEXT_PROCESSORS) @@ -45,8 +45,8 @@ TEMPLATE_CONTEXT_PROCESSORS += [ ] FOBI_DEFAULT_THEME = 'bootstrap3' -#FOBI_DEFAULT_THEME = 'foundation5' -#FOBI_DEFAULT_THEME = 'simple' +# FOBI_DEFAULT_THEME = 'foundation5' +# FOBI_DEFAULT_THEME = 'simple' CMS_TEMPLATES = ( ('cms_page/{0}/page_with_sidebar.html'.format(FOBI_DEFAULT_THEME), @@ -62,6 +62,6 @@ MIGRATION_MODULES = { LANGUAGE_CODE = 'en' -#FEINCMS_RICHTEXT_INIT_CONTEXT = { +# FEINCMS_RICHTEXT_INIT_CONTEXT = { # 'TINYMCE_JS_URL': STATIC_URL + 'tiny_mce/tiny_mce.js', -#} +# } diff --git a/examples/simple/settings/bootstrap3_theme_djangocms_2.py b/examples/simple/settings/bootstrap3_theme_djangocms_2.py index 8652f926..bb8a476b 100644 --- a/examples/simple/settings/bootstrap3_theme_djangocms_2.py +++ b/examples/simple/settings/bootstrap3_theme_djangocms_2.py @@ -2,63 +2,68 @@ from .base import * DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': PROJECT_DIR('../db/example_djangocms_2.db'), # Or path to database file if using sqlite3. + # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + 'ENGINE': 'django.db.backends.sqlite3', + # Or path to database file if using sqlite3. + 'NAME': PROJECT_DIR('../db/example_djangocms_2.db'), # The following settings are not used with sqlite3: 'USER': '', 'PASSWORD': '', - 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': '', # Set to empty string for default. + # Empty for localhost through domain sockets or '127.0.0.1' for + # localhost through TCP. + 'HOST': '', + # Set to empty string for default. + 'PORT': '', } } INSTALLED_APPS = list(INSTALLED_APPS) INSTALLED_APPS += [ - 'cms', # DjangoCMS + 'cms', # DjangoCMS 'mptt', 'menus', 'sekizai', - #'djangocms_admin_style', + # 'djangocms_admin_style', # Some plugins 'cms.plugins.picture', 'cms.plugins.snippet', - 'fobi.contrib.apps.djangocms_integration', # Fobi DjangoCMS app + 'fobi.contrib.apps.djangocms_integration', # Fobi DjangoCMS app - #'djangocms_page', # Example + # 'djangocms_page', # Example ] try: - #INSTALLED_APPS.remove('admin_tools') \ + # INSTALLED_APPS.remove('admin_tools') \ # if 'admin_tools' in INSTALLED_APPS else None - #INSTALLED_APPS.remove('admin_tools.menu') \ + # INSTALLED_APPS.remove('admin_tools.menu') \ # if 'admin_tools.menu' in INSTALLED_APPS else None INSTALLED_APPS.remove('admin_tools.dashboard') \ if 'admin_tools.dashboard' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass MIDDLEWARE_CLASSES = list(MIDDLEWARE_CLASSES) MIDDLEWARE_CLASSES += [ - #'django.middleware.cache.UpdateCacheMiddleware', + # 'django.middleware.cache.UpdateCacheMiddleware', 'cms.middleware.page.CurrentPageMiddleware', 'cms.middleware.user.CurrentUserMiddleware', 'cms.middleware.toolbar.ToolbarMiddleware', 'cms.middleware.language.LanguageCookieMiddleware', - #'django.middleware.cache.FetchFromCacheMiddleware', + # 'django.middleware.cache.FetchFromCacheMiddleware', ] TEMPLATE_CONTEXT_PROCESSORS = list(TEMPLATE_CONTEXT_PROCESSORS) TEMPLATE_CONTEXT_PROCESSORS += [ 'cms.context_processors.media', 'sekizai.context_processors.sekizai', - #'cms.context_processors.cms_settings', + # 'cms.context_processors.cms_settings', ] FOBI_DEFAULT_THEME = 'bootstrap3' -#FOBI_DEFAULT_THEME = 'foundation5' -#FOBI_DEFAULT_THEME = 'simple' +# FOBI_DEFAULT_THEME = 'foundation5' +# FOBI_DEFAULT_THEME = 'simple' CMS_TEMPLATES = ( ('cms_page/{0}/page_with_sidebar.html'.format(FOBI_DEFAULT_THEME), @@ -74,6 +79,6 @@ MIGRATION_MODULES = { LANGUAGE_CODE = 'en' -#FEINCMS_RICHTEXT_INIT_CONTEXT = { +# FEINCMS_RICHTEXT_INIT_CONTEXT = { # 'TINYMCE_JS_URL': STATIC_URL + 'tiny_mce/tiny_mce.js', -#} +# } diff --git a/examples/simple/settings/bootstrap3_theme_feincms.py b/examples/simple/settings/bootstrap3_theme_feincms.py index 254797b2..92d2beae 100644 --- a/examples/simple/settings/bootstrap3_theme_feincms.py +++ b/examples/simple/settings/bootstrap3_theme_feincms.py @@ -2,18 +2,23 @@ from .base import * INSTALLED_APPS = list(INSTALLED_APPS) INSTALLED_APPS += [ - 'feincms', # FeinCMS + 'feincms', # FeinCMS - 'fobi.contrib.apps.feincms_integration', # Fobi FeinCMS app + 'fobi.contrib.apps.feincms_integration', # Fobi FeinCMS app - 'page', # Example + 'page', # Example ] try: - #INSTALLED_APPS.remove('admin_tools') if 'admin_tools' in INSTALLED_APPS else None - #INSTALLED_APPS.remove('admin_tools.menu') if 'admin_tools.menu' in INSTALLED_APPS else None - INSTALLED_APPS.remove('admin_tools.dashboard') if 'admin_tools.dashboard' in INSTALLED_APPS else None -except Exception as e: + # INSTALLED_APPS.remove('admin_tools') \ + # if 'admin_tools' in INSTALLED_APPS \ + # else None + # INSTALLED_APPS.remove('admin_tools.menu') \ + # if 'admin_tools.menu' in INSTALLED_APPS \ + # else None + INSTALLED_APPS.remove('admin_tools.dashboard') \ + if 'admin_tools.dashboard' in INSTALLED_APPS else None +except Exception as err: pass FEINCMS_RICHTEXT_INIT_CONTEXT = { diff --git a/examples/simple/settings/bootstrap3_theme_mptt.py b/examples/simple/settings/bootstrap3_theme_mptt.py index fe705e9d..0d091236 100644 --- a/examples/simple/settings/bootstrap3_theme_mptt.py +++ b/examples/simple/settings/bootstrap3_theme_mptt.py @@ -5,7 +5,13 @@ INSTALLED_APPS = list(INSTALLED_APPS) try: INSTALLED_APPS.append('mptt') INSTALLED_APPS.append('bar') - INSTALLED_APPS.append('fobi.contrib.plugins.form_elements.fields.select_mptt_model_object') - INSTALLED_APPS.append('fobi.contrib.plugins.form_elements.fields.select_multiple_mptt_model_objects') -except Exception as e: + INSTALLED_APPS.append( + 'fobi.contrib.plugins.form_elements.fields.' + 'select_mptt_model_object' + ) + INSTALLED_APPS.append( + 'fobi.contrib.plugins.form_elements.fields.' + 'select_multiple_mptt_model_objects' + ) +except Exception as err: pass diff --git a/examples/simple/settings/bootstrap3_theme_python_3_django_1_8.py b/examples/simple/settings/bootstrap3_theme_python_3_django_1_8.py index ba1a5d2d..f9dd3f48 100644 --- a/examples/simple/settings/bootstrap3_theme_python_3_django_1_8.py +++ b/examples/simple/settings/bootstrap3_theme_python_3_django_1_8.py @@ -5,7 +5,7 @@ INSTALLED_APPS = list(INSTALLED_APPS) try: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass try: @@ -15,11 +15,12 @@ try: if 'admin_tools.menu' in INSTALLED_APPS else None INSTALLED_APPS.remove('admin_tools.dashboard') \ if 'admin_tools.dashboard' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass -#INSTALLED_APPS.remove('fobi.contrib.plugins.form_handlers.http_repost') -#INSTALLED_APPS.remove('fobi.contrib.plugins.form_handlers.mail') -#INSTALLED_APPS.remove('fobi.contrib.themes.foundation5') -#INSTALLED_APPS.remove('fobi.contrib.themes.foundation5.widgets.form_handlers.db_store_foundation5_widget') -#INSTALLED_APPS.remove('fobi.contrib.themes.simple') +# INSTALLED_APPS.remove('fobi.contrib.plugins.form_handlers.http_repost') +# INSTALLED_APPS.remove('fobi.contrib.plugins.form_handlers.mail') +# INSTALLED_APPS.remove('fobi.contrib.themes.foundation5') +# INSTALLED_APPS.remove('fobi.contrib.themes.foundation5.widgets.' +# 'form_handlers.db_store_foundation5_widget') +# INSTALLED_APPS.remove('fobi.contrib.themes.simple') diff --git a/examples/simple/settings/bootstrap3_theme_recaptcha.py b/examples/simple/settings/bootstrap3_theme_recaptcha.py index 218f2ec3..57d0de82 100644 --- a/examples/simple/settings/bootstrap3_theme_recaptcha.py +++ b/examples/simple/settings/bootstrap3_theme_recaptcha.py @@ -4,11 +4,13 @@ INSTALLED_APPS = list(INSTALLED_APPS) try: INSTALLED_APPS.append('captcha') - INSTALLED_APPS.append('fobi.contrib.plugins.form_elements.security.recaptcha') -except Exception as e: + INSTALLED_APPS.append( + 'fobi.contrib.plugins.form_elements.security.recaptcha' + ) +except Exception as err: pass -#RECAPTCHA_PUBLIC_KEY = '' -#RECAPTCHA_PRIVATE_KEY = '' +# RECAPTCHA_PUBLIC_KEY = '' +# RECAPTCHA_PRIVATE_KEY = '' RECAPTCHA_USE_SSL = True -#FOBI_DEFAULT_THEME = 'simple' +# FOBI_DEFAULT_THEME = 'simple' diff --git a/examples/simple/settings/djangocms_admin_style_theme_djangocms.py b/examples/simple/settings/djangocms_admin_style_theme_djangocms.py index 7198d115..43a1202e 100644 --- a/examples/simple/settings/djangocms_admin_style_theme_djangocms.py +++ b/examples/simple/settings/djangocms_admin_style_theme_djangocms.py @@ -1,20 +1,22 @@ +from nine.versions import DJANGO_GTE_1_8 + from .base import * INSTALLED_APPS = list(INSTALLED_APPS) INSTALLED_APPS.remove('django.contrib.admin') INSTALLED_APPS += [ - 'cms', # DjangoCMS + 'cms', # DjangoCMS 'mptt', 'menus', 'sekizai', - #'djangocms_admin_style', + # 'djangocms_admin_style', # Some plugins 'djangocms_picture', 'djangocms_snippet', 'treebeard', - 'fobi.contrib.apps.djangocms_integration', # Fobi DjangoCMS app + 'fobi.contrib.apps.djangocms_integration', # Fobi DjangoCMS app # Django-CMS admin style 'djangocms_admin_style', @@ -34,15 +36,14 @@ except Exception as e: MIDDLEWARE_CLASSES = list(MIDDLEWARE_CLASSES) MIDDLEWARE_CLASSES += [ - #'django.middleware.cache.UpdateCacheMiddleware', + # 'django.middleware.cache.UpdateCacheMiddleware', 'cms.middleware.page.CurrentPageMiddleware', 'cms.middleware.user.CurrentUserMiddleware', 'cms.middleware.toolbar.ToolbarMiddleware', 'cms.middleware.language.LanguageCookieMiddleware', - #'django.middleware.cache.FetchFromCacheMiddleware', + # 'django.middleware.cache.FetchFromCacheMiddleware', ] -from nine.versions import DJANGO_GTE_1_8 if DJANGO_GTE_1_8: TEMPLATES[0]['OPTIONS']['context_processors'] += [ 'cms.context_processors.cms_settings', @@ -57,9 +58,9 @@ else: 'cms.context_processors.cms_settings', ] -#FOBI_DEFAULT_THEME = 'bootstrap3' -#FOBI_DEFAULT_THEME = 'foundation5' -#FOBI_DEFAULT_THEME = 'simple' +# FOBI_DEFAULT_THEME = 'bootstrap3' +# FOBI_DEFAULT_THEME = 'foundation5' +# FOBI_DEFAULT_THEME = 'simple' FOBI_DEFAULT_THEME = 'djangocms_admin_style_theme' CMS_TEMPLATES = ( diff --git a/examples/simple/settings/foundation5.py b/examples/simple/settings/foundation5.py index 822e422d..0399c27f 100644 --- a/examples/simple/settings/foundation5.py +++ b/examples/simple/settings/foundation5.py @@ -5,8 +5,10 @@ FOBI_DEFAULT_THEME = 'foundation5' INSTALLED_APPS = list(INSTALLED_APPS) INSTALLED_APPS.append( - 'fobi.contrib.themes.foundation5.widgets.form_elements.date_foundation5_widget' + 'fobi.contrib.themes.foundation5.widgets.form_elements.' + 'date_foundation5_widget' ) INSTALLED_APPS.append( - 'fobi.contrib.themes.foundation5.widgets.form_elements.datetime_foundation5_widget' + 'fobi.contrib.themes.foundation5.widgets.form_elements.' + 'datetime_foundation5_widget' ) diff --git a/examples/simple/settings/foundation5_theme_django_1_10.py b/examples/simple/settings/foundation5_theme_django_1_10.py index 26ebe70e..1fd04236 100644 --- a/examples/simple/settings/foundation5_theme_django_1_10.py +++ b/examples/simple/settings/foundation5_theme_django_1_10.py @@ -5,8 +5,7 @@ INSTALLED_APPS = list(INSTALLED_APPS) try: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None - INSTALLED_APPS.remove('localeurl') if 'localeurl' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass try: @@ -16,7 +15,7 @@ try: if 'admin_tools.menu' in INSTALLED_APPS else None INSTALLED_APPS.remove('admin_tools.dashboard') \ if 'admin_tools.dashboard' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass FOBI_DEFAULT_THEME = 'foundation5' @@ -24,9 +23,10 @@ FOBI_DEFAULT_THEME = 'foundation5' INSTALLED_APPS = list(INSTALLED_APPS) INSTALLED_APPS.append( - 'fobi.contrib.themes.foundation5.widgets.form_elements.date_foundation5_widget' + 'fobi.contrib.themes.foundation5.widgets.form_elements.' + 'date_foundation5_widget' ) INSTALLED_APPS.append( - 'fobi.contrib.themes.foundation5.widgets.form_elements.datetime_foundation5_widget' + 'fobi.contrib.themes.foundation5.widgets.form_elements.' + 'datetime_foundation5_widget' ) - diff --git a/examples/simple/settings/foundation5_theme_django_1_8.py b/examples/simple/settings/foundation5_theme_django_1_8.py index 1e0fb6d1..1fd04236 100644 --- a/examples/simple/settings/foundation5_theme_django_1_8.py +++ b/examples/simple/settings/foundation5_theme_django_1_8.py @@ -5,7 +5,7 @@ INSTALLED_APPS = list(INSTALLED_APPS) try: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass try: @@ -15,7 +15,7 @@ try: if 'admin_tools.menu' in INSTALLED_APPS else None INSTALLED_APPS.remove('admin_tools.dashboard') \ if 'admin_tools.dashboard' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass FOBI_DEFAULT_THEME = 'foundation5' @@ -23,9 +23,10 @@ FOBI_DEFAULT_THEME = 'foundation5' INSTALLED_APPS = list(INSTALLED_APPS) INSTALLED_APPS.append( - 'fobi.contrib.themes.foundation5.widgets.form_elements.date_foundation5_widget' + 'fobi.contrib.themes.foundation5.widgets.form_elements.' + 'date_foundation5_widget' ) INSTALLED_APPS.append( - 'fobi.contrib.themes.foundation5.widgets.form_elements.datetime_foundation5_widget' + 'fobi.contrib.themes.foundation5.widgets.form_elements.' + 'datetime_foundation5_widget' ) - diff --git a/examples/simple/settings/foundation5_theme_django_1_9.py b/examples/simple/settings/foundation5_theme_django_1_9.py index 1f4d4a0e..1fd04236 100644 --- a/examples/simple/settings/foundation5_theme_django_1_9.py +++ b/examples/simple/settings/foundation5_theme_django_1_9.py @@ -5,9 +5,7 @@ INSTALLED_APPS = list(INSTALLED_APPS) try: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None - INSTALLED_APPS.remove( - 'localeurl') if 'localeurl' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass try: @@ -17,7 +15,7 @@ try: if 'admin_tools.menu' in INSTALLED_APPS else None INSTALLED_APPS.remove('admin_tools.dashboard') \ if 'admin_tools.dashboard' in INSTALLED_APPS else None -except Exception as e: +except Exception as err: pass FOBI_DEFAULT_THEME = 'foundation5' @@ -25,9 +23,10 @@ FOBI_DEFAULT_THEME = 'foundation5' INSTALLED_APPS = list(INSTALLED_APPS) INSTALLED_APPS.append( - 'fobi.contrib.themes.foundation5.widgets.form_elements.date_foundation5_widget' + 'fobi.contrib.themes.foundation5.widgets.form_elements.' + 'date_foundation5_widget' ) INSTALLED_APPS.append( - 'fobi.contrib.themes.foundation5.widgets.form_elements.datetime_foundation5_widget' + 'fobi.contrib.themes.foundation5.widgets.form_elements.' + 'datetime_foundation5_widget' ) - diff --git a/examples/simple/settings/foundation5_theme_feincms.py b/examples/simple/settings/foundation5_theme_feincms.py index b6d7ff33..479d2857 100644 --- a/examples/simple/settings/foundation5_theme_feincms.py +++ b/examples/simple/settings/foundation5_theme_feincms.py @@ -2,11 +2,11 @@ from .base import * INSTALLED_APPS = list(INSTALLED_APPS) INSTALLED_APPS += [ - 'feincms', # FeinCMS + 'feincms', # FeinCMS - 'fobi.contrib.apps.feincms_integration', # Fobi FeinCMS app + 'fobi.contrib.apps.feincms_integration', # Fobi FeinCMS app - 'page', # Example + 'page', # Example ] FEINCMS_RICHTEXT_INIT_CONTEXT = { diff --git a/examples/simple/settings/settings_test.py b/examples/simple/settings/settings_test.py index aeb277b3..1aaa3285 100644 --- a/examples/simple/settings/settings_test.py +++ b/examples/simple/settings/settings_test.py @@ -19,7 +19,8 @@ LOGGING = { }, 'formatters': { 'verbose': { - 'format': '\n%(levelname)s %(asctime)s [%(pathname)s:%(lineno)s] %(message)s' + 'format': '\n%(levelname)s %(asctime)s [%(pathname)s:%(lineno)s] ' + '%(message)s' }, 'simple': { 'format': '\n%(levelname)s %(message)s' @@ -37,32 +38,32 @@ LOGGING = { 'formatter': 'verbose' }, 'all_log': { - 'level':'ERROR', - 'class':'logging.handlers.RotatingFileHandler', + 'level': 'ERROR', + 'class': 'logging.handlers.RotatingFileHandler', 'filename': PROJECT_DIR("../../logs/all.log"), 'maxBytes': 1048576, 'backupCount': 99, 'formatter': 'verbose', }, 'django_log': { - 'level':'ERROR', - 'class':'logging.handlers.RotatingFileHandler', + 'level': 'ERROR', + 'class': 'logging.handlers.RotatingFileHandler', 'filename': PROJECT_DIR("../../logs/django.log"), 'maxBytes': 1048576, 'backupCount': 99, 'formatter': 'verbose', }, 'django_request_log': { - 'level':'ERROR', - 'class':'logging.handlers.RotatingFileHandler', + 'level': 'ERROR', + 'class': 'logging.handlers.RotatingFileHandler', 'filename': PROJECT_DIR("../../logs/django_request.log"), 'maxBytes': 1048576, 'backupCount': 99, 'formatter': 'verbose', }, 'fobi_log': { - 'level':'ERROR', - 'class':'logging.handlers.RotatingFileHandler', + 'level': 'ERROR', + 'class': 'logging.handlers.RotatingFileHandler', 'filename': PROJECT_DIR("../../logs/fobi.log"), 'maxBytes': 1048576, 'backupCount': 99, diff --git a/examples/simple/settings/simple.py b/examples/simple/settings/simple.py index 5c26bab1..e9e0828b 100644 --- a/examples/simple/settings/simple.py +++ b/examples/simple/settings/simple.py @@ -3,6 +3,6 @@ from .base import * FOBI_DEFAULT_THEME = 'simple' INSTALLED_APPS = list(INSTALLED_APPS) -#INSTALLED_APPS.remove('admin_tools') -#INSTALLED_APPS.remove('admin_tools.menu') -#INSTALLED_APPS.remove('admin_tools.dashboard') +# INSTALLED_APPS.remove('admin_tools') +# INSTALLED_APPS.remove('admin_tools.menu') +# INSTALLED_APPS.remove('admin_tools.dashboard') diff --git a/examples/simple/settings/test.py b/examples/simple/settings/test.py index 3070d432..c03406ce 100644 --- a/examples/simple/settings/test.py +++ b/examples/simple/settings/test.py @@ -1,18 +1,18 @@ # Use in `tox`. +from nine import versions from .base import * +TESTING = True + INSTALLED_APPS = list(INSTALLED_APPS) -from nine import versions - - if versions.DJANGO_1_5: try: INSTALLED_APPS.append( 'south') if 'south' not in INSTALLED_APPS else None - except Exception as e: + except Exception as err: pass elif versions.DJANGO_1_6: @@ -20,7 +20,7 @@ elif versions.DJANGO_1_6: try: INSTALLED_APPS.append( 'south') if 'south' not in INSTALLED_APPS else None - except Exception as e: + except Exception as err: pass @@ -30,7 +30,7 @@ elif versions.DJANGO_1_7: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None INSTALLED_APPS.remove( 'tinymce') if 'tinymce' in INSTALLED_APPS else None - except Exception as e: + except Exception as err: pass elif versions.DJANGO_1_8: @@ -39,7 +39,7 @@ elif versions.DJANGO_1_8: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None INSTALLED_APPS.remove( 'tinymce') if 'tinymce' in INSTALLED_APPS else None - except Exception as e: + except Exception as err: pass try: @@ -49,7 +49,7 @@ elif versions.DJANGO_1_8: if 'admin_tools.menu' in INSTALLED_APPS else None INSTALLED_APPS.remove('admin_tools.dashboard') \ if 'admin_tools.dashboard' in INSTALLED_APPS else None - except Exception as e: + except Exception as err: pass elif versions.DJANGO_1_9: @@ -58,9 +58,7 @@ elif versions.DJANGO_1_9: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None INSTALLED_APPS.remove( 'tinymce') if 'tinymce' in INSTALLED_APPS else None - INSTALLED_APPS.remove( - 'localeurl') if 'localeurl' in INSTALLED_APPS else None - except Exception as e: + except Exception as err: pass try: @@ -70,7 +68,7 @@ elif versions.DJANGO_1_9: if 'admin_tools.menu' in INSTALLED_APPS else None INSTALLED_APPS.remove('admin_tools.dashboard') \ if 'admin_tools.dashboard' in INSTALLED_APPS else None - except Exception as e: + except Exception as err: pass elif versions.DJANGO_1_10: @@ -79,9 +77,7 @@ elif versions.DJANGO_1_10: INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None INSTALLED_APPS.remove( 'tinymce') if 'tinymce' in INSTALLED_APPS else None - INSTALLED_APPS.remove( - 'localeurl') if 'localeurl' in INSTALLED_APPS else None - except Exception as e: + except Exception as err: pass try: @@ -91,7 +87,7 @@ elif versions.DJANGO_1_10: if 'admin_tools.menu' in INSTALLED_APPS else None INSTALLED_APPS.remove('admin_tools.dashboard') \ if 'admin_tools.dashboard' in INSTALLED_APPS else None - except Exception as e: + except Exception as err: pass LOGGING = {} diff --git a/examples/simple/templates/bootstrap3/base.html b/examples/simple/templates/bootstrap3/base.html index 513ea1aa..2776fd3d 100644 --- a/examples/simple/templates/bootstrap3/base.html +++ b/examples/simple/templates/bootstrap3/base.html @@ -2,5 +2,5 @@ {% block theme-javascripts %} {{ block.super }} - {% include "google_analytics.html" %} -{% endblock theme-javascripts %} \ No newline at end of file + {% if not testing %}{% include "google_analytics.html" %}{% endif %} +{% endblock theme-javascripts %} diff --git a/scripts/pycodestyle.sh b/scripts/pycodestyle.sh new file mode 100755 index 00000000..1290c9a6 --- /dev/null +++ b/scripts/pycodestyle.sh @@ -0,0 +1,2 @@ +reset +pycodestyle src/fobi/ --exclude src/fobi/migrations/,src/fobi/south_migrations/,src/fobi/contrib/plugins/form_handlers/db_store/migrations/ diff --git a/scripts/pycodestyle_example.sh b/scripts/pycodestyle_example.sh new file mode 100755 index 00000000..e0094c32 --- /dev/null +++ b/scripts/pycodestyle_example.sh @@ -0,0 +1,2 @@ +reset +pycodestyle examples/simple/ --exclude examples/simple/page/migrations/,examples/simple/page/south_migrations/,examples/simple/lund/fobi_addons/migrations/,examples/simple/wsgi.py diff --git a/setup.py b/setup.py index ceb289c9..4c9aef20 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.9.17' +version = '0.10' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index 9f80bdc3..08f09df0 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.9.17' -__build__ = 0x000072 +__version__ = '0.10' +__build__ = 0x000073 __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/base.py b/src/fobi/base.py index dcd38858..5c53501d 100644 --- a/src/fobi/base.py +++ b/src/fobi/base.py @@ -1535,9 +1535,8 @@ class FormElementPlugin(BasePlugin): logger.debug(str(err)) return {} - # def _submit_plugin_form_data(self, form_entry, request, form, - # form_element_entries=None, **kwargs): - def _submit_plugin_form_data(self, form_entry, request, form): + def _submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): """Submit plugin form data (internal method). Do not override this method. Use ``submit_plugin_form_data``, @@ -1550,14 +1549,15 @@ class FormElementPlugin(BasePlugin): ``fobi.models.FormEntry``. :param django.http.HttpRequest request: :param django.forms.Form form: + :param iterable form_element_entries: """ if DEBUG: return self.submit_plugin_form_data( form_entry=form_entry, request=request, form=form, - # form_element_entries=None, - # **kwargs + form_element_entries=form_element_entries, + **kwargs ) else: try: @@ -1565,15 +1565,14 @@ class FormElementPlugin(BasePlugin): form_entry=form_entry, request=request, form=form, - # form_element_entries=None, - # **kwargs + form_element_entries=form_element_entries, + **kwargs ) except Exception as e: logger.debug(str(e)) - # def submit_plugin_form_data(self, form_entry, request, form, - # form_element_entries=None, **kwargs): - def submit_plugin_form_data(self, form_entry, request, form): + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): """Submit plugin form data. Called on form submission (when user actually @@ -1583,6 +1582,7 @@ class FormElementPlugin(BasePlugin): ``fobi.models.FormEntry``. :param django.http.HttpRequest request: :param django.forms.Form form: + :param iterable form_element_entries: """ @@ -2420,29 +2420,27 @@ def validate_form_element_plugin_uid(plugin_uid): return validate_plugin_uid(form_element_plugin_registry, plugin_uid) -# def submit_plugin_form_data(form_entry, request, form, -# form_element_entries=None, **kwargs): -def submit_plugin_form_data(form_entry, request, form): +def submit_plugin_form_data(form_entry, request, form, + form_element_entries=None, **kwargs): """Submit plugin form data for all plugins. :param fobi.models.FormEntry form_entry: Instance of ``fobi.models.FormEntry``. :param django.http.HttpRequest request: :param django.forms.Form form: + :param iterable form_element_entries: """ - # if not form_element_entries: - # form_element_entries = form_entry.formelemententry_set.all() - # for form_element_entry in form_element_entries: - - for form_element_entry in form_entry.formelemententry_set.all(): + if not form_element_entries: + form_element_entries = form_entry.formelemententry_set.all() + for form_element_entry in form_element_entries: # Get the plugin. form_element_plugin = form_element_entry.get_plugin(request=request) updated_form = form_element_plugin._submit_plugin_form_data( form_entry=form_entry, request=request, form=form, - # form_element_entries=form_element_entries, - # **kwargs + form_element_entries=form_element_entries, + **kwargs ) if updated_form: form = updated_form diff --git a/src/fobi/contrib/plugins/form_elements/content/content_image/base.py b/src/fobi/contrib/plugins/form_elements/content/content_image/base.py new file mode 100644 index 00000000..73413aee --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/content/content_image/base.py @@ -0,0 +1,86 @@ +from __future__ import absolute_import + +from uuid import uuid4 + +from django.conf import settings +from django.template.loader import render_to_string +from django.utils.translation import ugettext_lazy as _ + +from nonefield.fields import NoneField + +from fobi.base import FormElementPlugin +from fobi.helpers import delete_file, clone_file + +from . import UID +from .forms import ContentImageForm +from .helpers import get_crop_filter +from .settings import ( + FIT_METHOD_FIT_WIDTH, FIT_METHOD_FIT_HEIGHT, IMAGES_UPLOAD_DIR +) + +__title__ = 'fobi.contrib.plugins.form_elements.content.content_image.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('ContentImagePlugin',) + + +class ContentImagePlugin(FormElementPlugin): + """Content image plugin.""" + + uid = UID + name = _("Content image") + group = _("Content") + form = ContentImageForm + + def post_processor(self): + """Post process data. + + Always the same. + """ + self.data.name = "{0}_{1}".format(self.uid, uuid4()) + + def delete_plugin_data(self): + """Delete uploaded file.""" + delete_file(self.data.file) + + def clone_plugin_data(self, entry): + """Clone plugin data. + + Clone plugin data, which means we make a copy of the original image. + + TODO: Perhaps rely more on data of ``form_element_entry``? + """ + cloned_image = clone_file( + IMAGES_UPLOAD_DIR, self.data.file, relative_path=True + ) + return self.get_cloned_plugin_data(update={'file': cloned_image}) + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + width, height = self.data.size.split('x') + crop = get_crop_filter(self.data.fit_method) + + if FIT_METHOD_FIT_WIDTH == self.data.fit_method: + thumb_size = (width, 0) + elif FIT_METHOD_FIT_HEIGHT == self.data.fit_method: + thumb_size = (0, height) + else: + thumb_size = (width, height) + + context = { + 'plugin': self, + 'MEDIA_URL': settings.MEDIA_URL, + 'crop': crop, + 'thumb_size': thumb_size + } + rendered_image = render_to_string('content_image/render.html', context) + + field_kwargs = { + 'initial': rendered_image, + 'required': False, + 'label': '', + } + + return [(self.data.name, NoneField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/content/content_image/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/content/content_image/fobi_form_elements.py index e23c9377..2f5f7358 100644 --- a/src/fobi/contrib/plugins/form_elements/content/content_image/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/content/content_image/fobi_form_elements.py @@ -1,20 +1,8 @@ -from uuid import uuid4 +from __future__ import absolute_import -from django.conf import settings -from django.template.loader import render_to_string -from django.utils.translation import ugettext_lazy as _ +from fobi.base import form_element_plugin_registry -from nonefield.fields import NoneField - -from fobi.base import FormElementPlugin, form_element_plugin_registry -from fobi.helpers import delete_file, clone_file - -from . import UID -from .forms import ContentImageForm -from .helpers import get_crop_filter -from .settings import ( - FIT_METHOD_FIT_WIDTH, FIT_METHOD_FIT_HEIGHT, IMAGES_UPLOAD_DIR -) +from .base import ContentImagePlugin __title__ = 'fobi.contrib.plugins.form_elements.content.content_image.' \ 'fobi_form_elements' @@ -24,65 +12,4 @@ __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('ContentImagePlugin',) -class ContentImagePlugin(FormElementPlugin): - """Content image plugin.""" - - uid = UID - name = _("Content image") - group = _("Content") - form = ContentImageForm - - def post_processor(self): - """Post process data. - - Always the same. - """ - self.data.name = "{0}_{1}".format(self.uid, uuid4()) - - def delete_plugin_data(self): - """Delete uploaded file.""" - delete_file(self.data.file) - - def clone_plugin_data(self, entry): - """Clone plugin data. - - Clone plugin data, which means we make a copy of the original image. - - TODO: Perhaps rely more on data of ``form_element_entry``? - """ - cloned_image = clone_file( - IMAGES_UPLOAD_DIR, self.data.file, relative_path=True - ) - return self.get_cloned_plugin_data(update={'file': cloned_image}) - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - width, height = self.data.size.split('x') - crop = get_crop_filter(self.data.fit_method) - - if FIT_METHOD_FIT_WIDTH == self.data.fit_method: - thumb_size = (width, 0) - elif FIT_METHOD_FIT_HEIGHT == self.data.fit_method: - thumb_size = (0, height) - else: - thumb_size = (width, height) - - context = { - 'plugin': self, - 'MEDIA_URL': settings.MEDIA_URL, - 'crop': crop, - 'thumb_size': thumb_size - } - rendered_image = render_to_string('content_image/render.html', context) - - field_kwargs = { - 'initial': rendered_image, - 'required': False, - 'label': '', - } - - return [(self.data.name, NoneField, field_kwargs)] - - form_element_plugin_registry.register(ContentImagePlugin) diff --git a/src/fobi/contrib/plugins/form_elements/content/content_text/base.py b/src/fobi/contrib/plugins/form_elements/content/content_text/base.py new file mode 100644 index 00000000..062b2d18 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/content/content_text/base.py @@ -0,0 +1,46 @@ +from __future__ import absolute_import + +from uuid import uuid4 + +from django.utils.encoding import smart_str +from django.utils.translation import ugettext_lazy as _ + +from nonefield.fields import NoneField + +from fobi.base import FormElementPlugin + +from . import UID +from .forms import ContentTextForm + +__title__ = 'fobi.contrib.plugins.form_elements.content.content_text.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('ContentTextPlugin',) + + +class ContentTextPlugin(FormElementPlugin): + """Content text plugin.""" + + uid = UID + name = _("Content text") + group = _("Content") + form = ContentTextForm + + def post_processor(self): + """Post process data. + + Always the same. + """ + self.data.name = "{0}_{1}".format(self.uid, uuid4()) + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + field_kwargs = { + 'initial': "

    {0}

    ".format(smart_str(self.data.text)), + 'required': False, + 'label': '', + } + + return [(self.data.name, NoneField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/content/content_text/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/content/content_text/fobi_form_elements.py index ca854754..268bd5b2 100644 --- a/src/fobi/contrib/plugins/form_elements/content/content_text/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/content/content_text/fobi_form_elements.py @@ -1,14 +1,8 @@ -from uuid import uuid4 +from __future__ import absolute_import -from django.utils.encoding import smart_str -from django.utils.translation import ugettext_lazy as _ +from fobi.base import form_element_plugin_registry -from nonefield.fields import NoneField - -from fobi.base import FormElementPlugin, form_element_plugin_registry - -from . import UID -from .forms import ContentTextForm +from .base import ContentTextPlugin __title__ = 'fobi.contrib.plugins.form_elements.content.content_text.' \ 'fobi_form_elements' @@ -18,31 +12,4 @@ __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('ContentTextPlugin',) -class ContentTextPlugin(FormElementPlugin): - """Content text plugin.""" - - uid = UID - name = _("Content text") - group = _("Content") - form = ContentTextForm - - def post_processor(self): - """Post process data. - - Always the same. - """ - self.data.name = "{0}_{1}".format(self.uid, uuid4()) - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - field_kwargs = { - 'initial': "

    {0}

    ".format(smart_str(self.data.text)), - 'required': False, - 'label': '', - } - - return [(self.data.name, NoneField, field_kwargs)] - - form_element_plugin_registry.register(ContentTextPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/content/content_video/base.py b/src/fobi/contrib/plugins/form_elements/content/content_video/base.py new file mode 100644 index 00000000..2032e057 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/content/content_video/base.py @@ -0,0 +1,51 @@ +from __future__ import absolute_import + +from uuid import uuid4 + +from django.utils.translation import ugettext_lazy as _ + +from vishap import render_video + +from nonefield.fields import NoneField + +from fobi.base import FormElementPlugin + +from . import UID +from .forms import ContentVideoForm + +__title__ = 'fobi.contrib.plugins.form_elements.content.content_video.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('ContentVideoPlugin',) + + +class ContentVideoPlugin(FormElementPlugin): + """Content video plugin.""" + + uid = UID + name = _("Content video") + group = _("Content") + form = ContentVideoForm + + def post_processor(self): + """Process plugin data. + + Always the same. + """ + self.data.name = "{0}_{1}".format(self.uid, uuid4()) + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + width, height = self.data.size.split('x') + + field_kwargs = { + 'initial': '
    {0}
    '.format( + render_video(self.data.url, width, height) + ), + 'required': False, + 'label': '', + } + + return [(self.data.name, NoneField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/content/content_video/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/content/content_video/fobi_form_elements.py index c9465ebc..91da92b8 100644 --- a/src/fobi/contrib/plugins/form_elements/content/content_video/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/content/content_video/fobi_form_elements.py @@ -1,15 +1,8 @@ -from uuid import uuid4 +from __future__ import absolute_import -from django.utils.translation import ugettext_lazy as _ +from fobi.base import form_element_plugin_registry -from vishap import render_video - -from nonefield.fields import NoneField - -from fobi.base import FormElementPlugin, form_element_plugin_registry - -from . import UID -from .forms import ContentVideoForm +from .base import ContentVideoPlugin __title__ = 'fobi.contrib.plugins.form_elements.content.content_video.' \ 'fobi_form_elements' @@ -19,35 +12,4 @@ __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('ContentVideoPlugin',) -class ContentVideoPlugin(FormElementPlugin): - """Content video plugin.""" - - uid = UID - name = _("Content video") - group = _("Content") - form = ContentVideoForm - - def post_processor(self): - """Process plugin data. - - Always the same. - """ - self.data.name = "{0}_{1}".format(self.uid, uuid4()) - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - width, height = self.data.size.split('x') - - field_kwargs = { - 'initial': '
    {0}
    '.format( - render_video(self.data.url, width, height) - ), - 'required': False, - 'label': '', - } - - return [(self.data.name, NoneField, field_kwargs)] - - form_element_plugin_registry.register(ContentVideoPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/boolean/base.py b/src/fobi/contrib/plugins/form_elements/fields/boolean/base.py new file mode 100644 index 00000000..1a5ce71f --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/boolean/base.py @@ -0,0 +1,34 @@ +from django.forms.fields import BooleanField +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin + +from . import UID +from .forms import BooleanSelectForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.boolean.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('BooleanSelectPlugin',) + + +class BooleanSelectPlugin(FormFieldPlugin): + """Boolean select plugin.""" + + uid = UID + name = _("Boolean") + group = _("Fields") + form = BooleanSelectForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + } + + return [(self.data.name, BooleanField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/boolean/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/boolean/fobi_form_elements.py index af42d223..a36623f2 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/boolean/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/boolean/fobi_form_elements.py @@ -1,10 +1,8 @@ -from django.forms.fields import BooleanField -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import BooleanSelectForm +from .base import BooleanSelectPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.boolean.' \ 'fobi_form_elements' @@ -14,25 +12,4 @@ __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('BooleanSelectPlugin',) -class BooleanSelectPlugin(FormFieldPlugin): - """Boolean select plugin.""" - - uid = UID - name = _("Boolean") - group = _("Fields") - form = BooleanSelectForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - } - - return [(self.data.name, BooleanField, field_kwargs)] - - form_element_plugin_registry.register(BooleanSelectPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/base.py b/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/base.py new file mode 100644 index 00000000..a13cac3a --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/base.py @@ -0,0 +1,91 @@ +from django.forms.fields import MultipleChoiceField +from django.forms.widgets import CheckboxSelectMultiple +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme +from fobi.constants import SUBMIT_VALUE_AS_VAL, SUBMIT_VALUE_AS_REPR +from fobi.helpers import get_select_field_choices, safe_text + +from . import UID +from .forms import CheckboxSelectMultipleInputForm +from .settings import SUBMIT_VALUE_AS + +theme = get_theme(request=None, as_instance=True) + +__title__ = 'fobi.contrib.plugins.form_elements.fields.' \ + 'checkbox_select_multiple.fobi_form_elements' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('CheckboxSelectMultipleInputPlugin',) + + +class CheckboxSelectMultipleInputPlugin(FormFieldPlugin): + """Checkbox select multiple field plugin.""" + + uid = UID + name = _("Checkbox select multiple") + group = _("Fields") + form = CheckboxSelectMultipleInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + choices = get_select_field_choices(self.data.choices) + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'choices': choices, + 'widget': CheckboxSelectMultiple( + attrs={'class': theme.form_element_html_class} + ), + } + + return [(self.data.name, MultipleChoiceField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """Submit plugin form data/process. + + :param fobi.models.FormEntry form_entry: Instance of + ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # In case if we should submit value as is, we don't return anything. + # In other cases, we proceed further. + if SUBMIT_VALUE_AS != SUBMIT_VALUE_AS_VAL: + # Get the object + values = form.cleaned_data.get(self.data.name, None) + + # Get choices + choices = dict(get_select_field_choices(self.data.choices)) + + # Returned value + ret_values = [] + + for value in values: + # Handle the submitted form value + + if value in choices: + label = safe_text(choices.get(value)) + + # Should be returned as repr + if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: + value = label + # Should be returned as mix + else: + value = "{0} ({1})".format(label, value) + + ret_values.append(value) + + # Overwrite ``cleaned_data`` of the ``form`` with object + # qualifier. + form.cleaned_data[self.data.name] = ret_values + + # It's critically important to return the ``form`` with updated + # ``cleaned_data`` + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/fobi_form_elements.py index 2834aa69..12ae2c15 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/checkbox_select_multiple/fobi_form_elements.py @@ -1,18 +1,8 @@ -from django.forms.fields import MultipleChoiceField -from django.forms.widgets import CheckboxSelectMultiple -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.constants import ( - SUBMIT_VALUE_AS_VAL, SUBMIT_VALUE_AS_REPR -) -from fobi.helpers import get_select_field_choices, safe_text +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import CheckboxSelectMultipleInputForm -from .settings import SUBMIT_VALUE_AS - -theme = get_theme(request=None, as_instance=True) +from .base import CheckboxSelectMultipleInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'checkbox_select_multiple.fobi_form_elements' @@ -22,74 +12,4 @@ __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('CheckboxSelectMultipleInputPlugin',) -class CheckboxSelectMultipleInputPlugin(FormFieldPlugin): - """Checkbox select multiple field plugin.""" - - uid = UID - name = _("Checkbox select multiple") - group = _("Fields") - form = CheckboxSelectMultipleInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - choices = get_select_field_choices(self.data.choices) - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'choices': choices, - 'widget': CheckboxSelectMultiple( - attrs={'class': theme.form_element_html_class} - ), - } - - return [(self.data.name, MultipleChoiceField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """Submit plugin form data/process. - - :param fobi.models.FormEntry form_entry: Instance of - ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # In case if we should submit value as is, we don't return anything. - # In other cases, we proceed further. - if SUBMIT_VALUE_AS != SUBMIT_VALUE_AS_VAL: - # Get the object - values = form.cleaned_data.get(self.data.name, None) - - # Get choices - choices = dict(get_select_field_choices(self.data.choices)) - - # Returned value - ret_values = [] - - for value in values: - # Handle the submitted form value - - if value in choices: - label = safe_text(choices.get(value)) - - # Should be returned as repr - if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: - value = label - # Should be returned as mix - else: - value = "{0} ({1})".format(label, value) - - ret_values.append(value) - - # Overwrite ``cleaned_data`` of the ``form`` with object - # qualifier. - form.cleaned_data[self.data.name] = ret_values - - # It's critically important to return the ``form`` with updated - # ``cleaned_data`` - return form - - form_element_plugin_registry.register(CheckboxSelectMultipleInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/date/base.py b/src/fobi/contrib/plugins/form_elements/fields/date/base.py new file mode 100644 index 00000000..4027644d --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/date/base.py @@ -0,0 +1,72 @@ +from __future__ import absolute_import + +from django.forms.fields import DateField +from django.forms.widgets import DateInput +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import DateInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.date.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('DateInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class DateInputPlugin(FormFieldPlugin): + """Date field plugin.""" + + uid = UID + name = _("Date") + group = _("Fields") + form = DateInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'type': 'date', + } + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + # 'input_formats': self.data.input_formats, + 'required': self.data.required, + 'widget': DateInput(attrs=widget_attrs), + } + # if self.data.input_formats: + # kwargs['input_formats'] = self.data.input_formats + + return [(self.data.name, DateField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """Submit plugin form data/process. + + :param fobi.models.FormEntry form_entry: Instance of + ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # In case if we should submit value as is, we don't return anything. + # In other cases, we proceed further. + + # Get the object + value = form.cleaned_data.get(self.data.name, None) + try: + value = value.strftime("%Y-%m-%d") + except Exception as err: + pass + + # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. + form.cleaned_data[self.data.name] = value + + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/date/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/date/fobi_form_elements.py index 9fe33b04..95e96704 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/date/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/date/fobi_form_elements.py @@ -1,13 +1,8 @@ from __future__ import absolute_import -from django.forms.fields import DateField -from django.forms.widgets import DateInput -from django.utils.translation import ugettext_lazy as _ +from fobi.base import form_element_plugin_registry -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme - -from . import UID -from .forms import DateInputForm +from .base import DateInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.date.fobi_form_elements' __author__ = 'Artur Barseghyan ' @@ -15,60 +10,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('DateInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class DateInputPlugin(FormFieldPlugin): - """Date field plugin.""" - - uid = UID - name = _("Date") - group = _("Fields") - form = DateInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'type': 'date', - } - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - # 'input_formats': self.data.input_formats, - 'required': self.data.required, - 'widget': DateInput(attrs=widget_attrs), - } - # if self.data.input_formats: - # kwargs['input_formats'] = self.data.input_formats - - return [(self.data.name, DateField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """Submit plugin form data/process. - - :param fobi.models.FormEntry form_entry: Instance of - ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # In case if we should submit value as is, we don't return anything. - # In other cases, we proceed further. - - # Get the object - value = form.cleaned_data.get(self.data.name, None) - try: - value = value.strftime("%Y-%m-%d") - except Exception as err: - pass - - # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. - form.cleaned_data[self.data.name] = value - - return form - form_element_plugin_registry.register(DateInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/date_drop_down/base.py b/src/fobi/contrib/plugins/form_elements/fields/date_drop_down/base.py new file mode 100644 index 00000000..383c2ebc --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/date_drop_down/base.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import + +from django.forms.extras.widgets import SelectDateWidget +from django.forms.fields import DateField +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import DateDropDownInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.' \ + 'date_drop_down.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('DateDropDownInputPlugin',) + + +theme = get_theme(request=None, as_instance=True) + + +class DateDropDownInputPlugin(FormFieldPlugin): + """Date drop down field plugin.""" + + uid = UID + name = _("Date drop down") + group = _("Fields") + form = DateDropDownInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'type': 'date', + } + + years = None + if self.data.year_min and self.data.year_max: + years = range(self.data.year_min, self.data.year_max) + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + # 'input_formats': self.data.input_formats, + 'required': self.data.required, + 'widget': SelectDateWidget(attrs=widget_attrs, years=years), + } + # if self.data.input_formats: + # kwargs['input_formats'] = self.data.input_formats + + return [(self.data.name, DateField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/date_drop_down/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/date_drop_down/fobi_form_elements.py index a007664c..573d0c48 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/date_drop_down/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/date_drop_down/fobi_form_elements.py @@ -1,11 +1,8 @@ -from django.forms.extras.widgets import SelectDateWidget -from django.forms.fields import DateField -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import DateDropDownInputForm +from .base import DateDropDownInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'date_drop_down.fobi_form_elements' @@ -15,41 +12,4 @@ __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('DateDropDownInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class DateDropDownInputPlugin(FormFieldPlugin): - """Date drop down field plugin.""" - - uid = UID - name = _("Date drop down") - group = _("Fields") - form = DateDropDownInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'type': 'date', - } - - years = None - if self.data.year_min and self.data.year_max: - years = range(self.data.year_min, self.data.year_max) - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - # 'input_formats': self.data.input_formats, - 'required': self.data.required, - 'widget': SelectDateWidget(attrs=widget_attrs, years=years), - } - # if self.data.input_formats: - # kwargs['input_formats'] = self.data.input_formats - - return [(self.data.name, DateField, field_kwargs)] - - form_element_plugin_registry.register(DateDropDownInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/datetime/base.py b/src/fobi/contrib/plugins/form_elements/fields/datetime/base.py new file mode 100644 index 00000000..00c4502b --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/datetime/base.py @@ -0,0 +1,73 @@ +from __future__ import absolute_import + +from django.forms.fields import DateTimeField +from django.forms.widgets import DateTimeInput +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import DateTimeInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.' \ + 'datetime.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('DateTimeInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class DateTimeInputPlugin(FormFieldPlugin): + """DateTime field plugin.""" + + uid = UID + name = _("DateTime") + group = _("Fields") + form = DateTimeInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'type': 'datetime', + } + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + # 'input_formats': self.data.input_formats, + 'required': self.data.required, + 'widget': DateTimeInput(attrs=widget_attrs), + } + # if self.data.input_formats: + # kwargs['input_formats'] = self.data.input_formats + + return [(self.data.name, DateTimeField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """Submit plugin form data/process. + + :param fobi.models.FormEntry form_entry: Instance of + ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # In case if we should submit value as is, we don't return anything. + # In other cases, we proceed further. + + # Get the object + value = form.cleaned_data.get(self.data.name, None) + try: + value = value.strftime("%Y-%m-%d %H:%M:%S") + except Exception as err: + pass + + # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. + form.cleaned_data[self.data.name] = value + + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/datetime/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/datetime/fobi_form_elements.py index 44df3f82..55726982 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/datetime/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/datetime/fobi_form_elements.py @@ -1,13 +1,8 @@ from __future__ import absolute_import -from django.forms.fields import DateTimeField -from django.forms.widgets import DateTimeInput -from django.utils.translation import ugettext_lazy as _ +from fobi.base import form_element_plugin_registry -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme - -from . import UID -from .forms import DateTimeInputForm +from .base import DateTimeInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'datetime.fobi_form_elements' @@ -16,60 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('DateTimeInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class DateTimeInputPlugin(FormFieldPlugin): - """DateTime field plugin.""" - - uid = UID - name = _("DateTime") - group = _("Fields") - form = DateTimeInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'type': 'datetime', - } - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - # 'input_formats': self.data.input_formats, - 'required': self.data.required, - 'widget': DateTimeInput(attrs=widget_attrs), - } - # if self.data.input_formats: - # kwargs['input_formats'] = self.data.input_formats - - return [(self.data.name, DateTimeField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """Submit plugin form data/process. - - :param fobi.models.FormEntry form_entry: Instance of - ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # In case if we should submit value as is, we don't return anything. - # In other cases, we proceed further. - - # Get the object - value = form.cleaned_data.get(self.data.name, None) - try: - value = value.strftime("%Y-%m-%d %H:%M:%S") - except Exception as err: - pass - - # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. - form.cleaned_data[self.data.name] = value - - return form - form_element_plugin_registry.register(DateTimeInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/decimal/base.py b/src/fobi/contrib/plugins/form_elements/fields/decimal/base.py new file mode 100644 index 00000000..be12489b --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/decimal/base.py @@ -0,0 +1,60 @@ +from __future__ import absolute_import + +from django.forms.fields import DecimalField +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme +from fobi.widgets import NumberInput + +from . import UID +from .forms import DecimalInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.' \ + 'decimal.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('DecimalInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class DecimalInputPlugin(FormFieldPlugin): + """Decimal input plugin.""" + + uid = UID + name = _("Decimal") + group = _("Fields") + form = DecimalInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'type': 'number', + 'placeholder': self.data.placeholder, + } + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + } + if self.data.max_value: + field_kwargs['max_value'] = self.data.max_value + widget_attrs['max'] = self.data.max_value + if self.data.min_value: + field_kwargs['min_value'] = self.data.min_value + widget_attrs['min'] = self.data.min_value + + if self.data.max_digits: + field_kwargs['max_digits'] = self.data.max_digits + widget_attrs['max'] = self.data.max_value + if self.data.decimal_places: + field_kwargs['decimal_places'] = self.data.decimal_places + widget_attrs['min'] = self.data.min_value + + field_kwargs['widget'] = NumberInput(attrs=widget_attrs) + + return [(self.data.name, DecimalField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/decimal/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/decimal/fobi_form_elements.py index 21b45b08..6fe2c7e4 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/decimal/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/decimal/fobi_form_elements.py @@ -1,13 +1,8 @@ from __future__ import absolute_import -from django.forms.fields import DecimalField -from django.utils.translation import ugettext_lazy as _ +from fobi.base import form_element_plugin_registry -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.widgets import NumberInput - -from . import UID -from .forms import DecimalInputForm +from .base import DecimalInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'decimal.fobi_form_elements' @@ -16,48 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('DecimalInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class DecimalInputPlugin(FormFieldPlugin): - """Decimal input plugin.""" - - uid = UID - name = _("Decimal") - group = _("Fields") - form = DecimalInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'type': 'number', - 'placeholder': self.data.placeholder, - } - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - } - if self.data.max_value: - field_kwargs['max_value'] = self.data.max_value - widget_attrs['max'] = self.data.max_value - if self.data.min_value: - field_kwargs['min_value'] = self.data.min_value - widget_attrs['min'] = self.data.min_value - - if self.data.max_digits: - field_kwargs['max_digits'] = self.data.max_digits - widget_attrs['max'] = self.data.max_value - if self.data.decimal_places: - field_kwargs['decimal_places'] = self.data.decimal_places - widget_attrs['min'] = self.data.min_value - - field_kwargs['widget'] = NumberInput(attrs=widget_attrs) - - return [(self.data.name, DecimalField, field_kwargs)] - form_element_plugin_registry.register(DecimalInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/email/base.py b/src/fobi/contrib/plugins/form_elements/fields/email/base.py new file mode 100644 index 00000000..f8980558 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/email/base.py @@ -0,0 +1,53 @@ +from __future__ import absolute_import + +from django.forms.fields import EmailField +from django.forms.widgets import TextInput +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import EmailInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.' \ + 'email.fobi_form_elements' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('EmailInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class EmailInputPlugin(FormFieldPlugin): + """Email input plugin.""" + + uid = UID + name = _("Email") + group = _("Fields") + form = EmailInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'type': 'email', + 'placeholder': self.data.placeholder, + } + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'widget': TextInput(attrs=widget_attrs), + } + if self.data.max_length: + field_kwargs['max_length'] = self.data.max_length + + return [(self.data.name, EmailField, field_kwargs)] + + +# For backwards compatibility +EmailPlugin = EmailInputPlugin diff --git a/src/fobi/contrib/plugins/form_elements/fields/email/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/email/fobi_form_elements.py index aadeb46c..3da5bdd1 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/email/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/email/fobi_form_elements.py @@ -1,13 +1,8 @@ from __future__ import absolute_import -from django.forms.fields import EmailField -from django.forms.widgets import TextInput -from django.utils.translation import ugettext_lazy as _ +from fobi.base import form_element_plugin_registry -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme - -from . import UID -from .forms import EmailInputForm +from .base import EmailInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'email.fobi_form_elements' @@ -16,40 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('EmailInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class EmailInputPlugin(FormFieldPlugin): - """Email input plugin.""" - - uid = UID - name = _("Email") - group = _("Fields") - form = EmailInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'type': 'email', - 'placeholder': self.data.placeholder, - } - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'widget': TextInput(attrs=widget_attrs), - } - if self.data.max_length: - field_kwargs['max_length'] = self.data.max_length - - return [(self.data.name, EmailField, field_kwargs)] - - -# For backwards compatibility -EmailPlugin = EmailInputPlugin form_element_plugin_registry.register(EmailInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/file/base.py b/src/fobi/contrib/plugins/form_elements/fields/file/base.py new file mode 100644 index 00000000..172dc3f2 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/file/base.py @@ -0,0 +1,74 @@ +from __future__ import absolute_import + +import os + +from django.forms.fields import FileField +from django.forms.widgets import ClearableFileInput +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings + +from fobi.base import FormFieldPlugin +from fobi.helpers import handle_uploaded_file + +from . import UID +from .forms import FileInputForm +from .settings import FILES_UPLOAD_DIR + +__title__ = 'fobi.contrib.plugins.form_elements.fields.file.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('FileInputPlugin',) + + +class FileInputPlugin(FormFieldPlugin): + """File field plugin.""" + + uid = UID + name = _("File") + group = _("Fields") + form = FileInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'widget': ClearableFileInput(attrs={}), + } + if self.data.max_length: + field_kwargs['max_length'] = self.data.max_length + + return [(self.data.name, FileField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """Submit plugin form data/process file upload. + + Handling the posted data for file plugin when form is submitted. + This method affects the original form and that's why it returns it. + + :param fobi.models.FormEntry form_entry: Instance + of ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # Get the file path + file_path = form.cleaned_data.get(self.data.name, None) + if file_path: + # Handle the upload + saved_file = handle_uploaded_file(FILES_UPLOAD_DIR, file_path) + # Overwrite ``cleaned_data`` of the ``form`` with path to moved + # file. + file_relative_url = saved_file.replace(os.path.sep, '/') + form.cleaned_data[self.data.name] = "{0}{1}".format( + settings.MEDIA_URL, + file_relative_url + ) + + # It's critically important to return the ``form`` with updated + # ``cleaned_data`` + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/file/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/file/fobi_form_elements.py index 354e9786..c442bbf2 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/file/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/file/fobi_form_elements.py @@ -1,16 +1,8 @@ -import os +from __future__ import absolute_import -from django.forms.fields import FileField -from django.forms.widgets import ClearableFileInput -from django.utils.translation import ugettext_lazy as _ -from django.conf import settings +from fobi.base import form_element_plugin_registry -from fobi.base import FormFieldPlugin, form_element_plugin_registry -from fobi.helpers import handle_uploaded_file - -from . import UID -from .forms import FileInputForm -from .settings import FILES_UPLOAD_DIR +from .base import FileInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.file.fobi_form_elements' __author__ = 'Artur Barseghyan ' @@ -19,56 +11,4 @@ __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('FileInputPlugin',) -class FileInputPlugin(FormFieldPlugin): - """File field plugin.""" - - uid = UID - name = _("File") - group = _("Fields") - form = FileInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'widget': ClearableFileInput(attrs={}), - } - if self.data.max_length: - field_kwargs['max_length'] = self.data.max_length - - return [(self.data.name, FileField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """Submit plugin form data/process file upload. - - Handling the posted data for file plugin when form is submitted. - This method affects the original form and that's why it returns it. - - :param fobi.models.FormEntry form_entry: Instance - of ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # Get the file path - file_path = form.cleaned_data.get(self.data.name, None) - if file_path: - # Handle the upload - saved_file = handle_uploaded_file(FILES_UPLOAD_DIR, file_path) - # Overwrite ``cleaned_data`` of the ``form`` with path to moved - # file. - file_relative_url = saved_file.replace(os.path.sep, '/') - form.cleaned_data[self.data.name] = "{0}{1}".format( - settings.MEDIA_URL, - file_relative_url - ) - - # It's critically important to return the ``form`` with updated - # ``cleaned_data`` - return form - - form_element_plugin_registry.register(FileInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/float/base.py b/src/fobi/contrib/plugins/form_elements/fields/float/base.py new file mode 100644 index 00000000..96b6d71b --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/float/base.py @@ -0,0 +1,52 @@ +from __future__ import absolute_import + +from django.forms.fields import FloatField +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme +from fobi.widgets import NumberInput + +from . import UID +from .forms import FloatInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.float.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('FloatInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class FloatInputPlugin(FormFieldPlugin): + """Float input plugin.""" + + uid = UID + name = _("Float") + group = _("Fields") + form = FloatInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'type': 'number', + 'placeholder': self.data.placeholder, + } + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + } + if self.data.max_value: + field_kwargs['max_value'] = self.data.max_value + widget_attrs['max'] = self.data.max_value + if self.data.min_value: + field_kwargs['min_value'] = self.data.min_value + widget_attrs['min'] = self.data.min_value + + field_kwargs['widget'] = NumberInput(attrs=widget_attrs) + + return [(self.data.name, FloatField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/float/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/float/fobi_form_elements.py index 096c1ad6..ed62aba5 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/float/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/float/fobi_form_elements.py @@ -1,11 +1,8 @@ -from django.forms.fields import FloatField -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.widgets import NumberInput +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import FloatInputForm +from .base import FloatInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'float.fobi_form_elements' @@ -14,41 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('FloatInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class FloatInputPlugin(FormFieldPlugin): - """Float input plugin.""" - - uid = UID - name = _("Float") - group = _("Fields") - form = FloatInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'type': 'number', - 'placeholder': self.data.placeholder, - } - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - } - if self.data.max_value: - field_kwargs['max_value'] = self.data.max_value - widget_attrs['max'] = self.data.max_value - if self.data.min_value: - field_kwargs['min_value'] = self.data.min_value - widget_attrs['min'] = self.data.min_value - - field_kwargs['widget'] = NumberInput(attrs=widget_attrs) - - return [(self.data.name, FloatField, field_kwargs)] - form_element_plugin_registry.register(FloatInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/hidden/base.py b/src/fobi/contrib/plugins/form_elements/fields/hidden/base.py new file mode 100644 index 00000000..c79837c9 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/hidden/base.py @@ -0,0 +1,45 @@ +from __future__ import absolute_import + +from django.forms.fields import CharField +from django.forms.widgets import HiddenInput +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import HiddenInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.hidden.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('HiddenInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class HiddenInputPlugin(FormFieldPlugin): + """Hidden field plugin.""" + + uid = UID + name = _("Hidden") + group = _("Fields") + form = HiddenInputForm + is_hidden = True + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + field_kwargs = { + 'label': self.data.label, + 'initial': self.data.initial, + 'required': self.data.required, + 'widget': HiddenInput( + attrs={'class': theme.form_element_html_class} + ), + } + if self.data.max_length: + field_kwargs['max_length'] = self.data.max_length + + return [(self.data.name, CharField, field_kwargs)] + # return [(self.data.name, (CharField, TextInput), kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/hidden/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/hidden/fobi_form_elements.py index 98f5b33e..23cf99e1 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/hidden/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/hidden/fobi_form_elements.py @@ -1,11 +1,8 @@ -from django.forms.fields import CharField -from django.forms.widgets import HiddenInput # , TextInput -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import HiddenInputForm +from .base import HiddenInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'hidden.fobi_form_elements' @@ -14,34 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('HiddenInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class HiddenInputPlugin(FormFieldPlugin): - """Hidden field plugin.""" - - uid = UID - name = _("Hidden") - group = _("Fields") - form = HiddenInputForm - is_hidden = True - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - field_kwargs = { - 'label': self.data.label, - 'initial': self.data.initial, - 'required': self.data.required, - 'widget': HiddenInput( - attrs={'class': theme.form_element_html_class} - ), - } - if self.data.max_length: - field_kwargs['max_length'] = self.data.max_length - - return [(self.data.name, CharField, field_kwargs)] - # return [(self.data.name, (CharField, TextInput), kwargs)] - form_element_plugin_registry.register(HiddenInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/input/base.py b/src/fobi/contrib/plugins/form_elements/fields/input/base.py new file mode 100644 index 00000000..ff6c2409 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/input/base.py @@ -0,0 +1,88 @@ +from __future__ import absolute_import + +from django.forms.fields import Field +from django.forms.widgets import TextInput +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import InputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.input.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('InputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class InputPlugin(FormFieldPlugin): + """Input field plugin.""" + + uid = UID + name = _("Input") + group = _("Fields") + form = InputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'placeholder': self.data.placeholder, + 'type': self.data.type_value, + } + + if self.data.autocomplete_value: + widget_attrs.update({'autocomplete': 'on'}) + + if self.data.autofocus_value: + widget_attrs.update({'autofocus': 'autofocus'}) + + if self.data.disabled_value: + widget_attrs.update({'disabled': 'disabled'}) + + # if self.data.formnovalidate_value: + # widget_attrs.update({'formnovalidate': 'formnovalidate'}) + + if self.data.list_value: + widget_attrs.update({'list': self.data.list_value}) + + if self.data.max_value: + widget_attrs.update({'max': self.data.max_value}) + + if self.data.min_value: + widget_attrs.update({'min': self.data.min_value}) + + if self.data.multiple_value: + widget_attrs.update({'multiple': 'multiple'}) + + if self.data.pattern_value: + widget_attrs.update({'pattern': self.data.pattern_value}) + + if self.data.readonly_value: + widget_attrs.update({'readonly': 'readonly'}) + + if self.data.step_value: + widget_attrs.update({'step': self.data.step_value}) + + if self.data.type_value and self.data.type_value in ('submit', + 'button', + 'reset',): + widget_attrs.update({'value': self.data.label}) + + field_kwargs = { + 'label': self.data.label + if self.data.type_value not in ('submit', 'button', 'reset',) + else '', + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'widget': TextInput(attrs=widget_attrs), + } + # if self.data.max_length: + # kwargs['max_length'] = self.data.max_length + + return [(self.data.name, Field, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/input/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/input/fobi_form_elements.py index 7825b6bb..191aca0e 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/input/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/input/fobi_form_elements.py @@ -1,11 +1,8 @@ -from django.forms.fields import Field -from django.forms.widgets import TextInput -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import InputForm +from .base import InputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'input.fobi_form_elements' @@ -14,77 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('InputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class InputPlugin(FormFieldPlugin): - """Input field plugin.""" - - uid = UID - name = _("Input") - group = _("Fields") - form = InputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'placeholder': self.data.placeholder, - 'type': self.data.type_value, - } - - if self.data.autocomplete_value: - widget_attrs.update({'autocomplete': 'on'}) - - if self.data.autofocus_value: - widget_attrs.update({'autofocus': 'autofocus'}) - - if self.data.disabled_value: - widget_attrs.update({'disabled': 'disabled'}) - - # if self.data.formnovalidate_value: - # widget_attrs.update({'formnovalidate': 'formnovalidate'}) - - if self.data.list_value: - widget_attrs.update({'list': self.data.list_value}) - - if self.data.max_value: - widget_attrs.update({'max': self.data.max_value}) - - if self.data.min_value: - widget_attrs.update({'min': self.data.min_value}) - - if self.data.multiple_value: - widget_attrs.update({'multiple': 'multiple'}) - - if self.data.pattern_value: - widget_attrs.update({'pattern': self.data.pattern_value}) - - if self.data.readonly_value: - widget_attrs.update({'readonly': 'readonly'}) - - if self.data.step_value: - widget_attrs.update({'step': self.data.step_value}) - - if self.data.type_value and self.data.type_value in ('submit', - 'button', - 'reset',): - widget_attrs.update({'value': self.data.label}) - - field_kwargs = { - 'label': self.data.label - if self.data.type_value not in ('submit', 'button', 'reset',) - else '', - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'widget': TextInput(attrs=widget_attrs), - } - # if self.data.max_length: - # kwargs['max_length'] = self.data.max_length - - return [(self.data.name, Field, field_kwargs)] - form_element_plugin_registry.register(InputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/integer/base.py b/src/fobi/contrib/plugins/form_elements/fields/integer/base.py new file mode 100644 index 00000000..5f9430d5 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/integer/base.py @@ -0,0 +1,52 @@ +from __future__ import absolute_import + +from django.forms.fields import IntegerField +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme +from fobi.widgets import NumberInput + +from . import UID +from .forms import IntegerInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.integer.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('IntegerInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class IntegerInputPlugin(FormFieldPlugin): + """Integer input plugin.""" + + uid = UID + name = _("Integer") + group = _("Fields") + form = IntegerInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'type': 'number', + 'placeholder': self.data.placeholder, + } + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + } + if self.data.max_value: + field_kwargs['max_value'] = self.data.max_value + widget_attrs['max'] = self.data.max_value + if self.data.min_value: + field_kwargs['min_value'] = self.data.min_value + widget_attrs['min'] = self.data.min_value + + field_kwargs['widget'] = NumberInput(attrs=widget_attrs) + + return [(self.data.name, IntegerField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/integer/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/integer/fobi_form_elements.py index 97eb49a6..f065bed5 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/integer/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/integer/fobi_form_elements.py @@ -1,11 +1,8 @@ -from django.forms.fields import IntegerField # , DecimalField, FloatField -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.widgets import NumberInput +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import IntegerInputForm +from .base import IntegerInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'integer.fobi_form_elements' @@ -14,41 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('IntegerInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class IntegerInputPlugin(FormFieldPlugin): - """Integer input plugin.""" - - uid = UID - name = _("Integer") - group = _("Fields") - form = IntegerInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'type': 'number', - 'placeholder': self.data.placeholder, - } - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - } - if self.data.max_value: - field_kwargs['max_value'] = self.data.max_value - widget_attrs['max'] = self.data.max_value - if self.data.min_value: - field_kwargs['min_value'] = self.data.min_value - widget_attrs['min'] = self.data.min_value - - field_kwargs['widget'] = NumberInput(attrs=widget_attrs) - - return [(self.data.name, IntegerField, field_kwargs)] - form_element_plugin_registry.register(IntegerInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/ip_address/base.py b/src/fobi/contrib/plugins/form_elements/fields/ip_address/base.py new file mode 100644 index 00000000..44e612ca --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/ip_address/base.py @@ -0,0 +1,47 @@ +from __future__ import absolute_import + +from django.forms.fields import GenericIPAddressField +from django.forms.widgets import TextInput +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import IPAddressInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.ip_address.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('IPAddressInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class IPAddressInputPlugin(FormFieldPlugin): + """IP address field plugin.""" + + uid = UID + name = _("IP address") + group = _("Fields") + form = IPAddressInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'placeholder': self.data.placeholder, + } + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'widget': TextInput(attrs=widget_attrs), + } + if self.data.max_length: + field_kwargs['max_length'] = self.data.max_length + + return [(self.data.name, GenericIPAddressField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/ip_address/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/ip_address/fobi_form_elements.py index 45d50c0b..3abc01ce 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/ip_address/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/ip_address/fobi_form_elements.py @@ -1,13 +1,8 @@ +from __future__ import absolute_import +from fobi.base import form_element_plugin_registry -from django.forms.fields import GenericIPAddressField -from django.forms.widgets import TextInput -from django.utils.translation import ugettext_lazy as _ - -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme - -from . import UID -from .forms import IPAddressInputForm +from .base import IPAddressInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'ip_address.fobi_form_elements' @@ -16,36 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('IPAddressInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class IPAddressInputPlugin(FormFieldPlugin): - """IP address field plugin.""" - - uid = UID - name = _("IP address") - group = _("Fields") - form = IPAddressInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'placeholder': self.data.placeholder, - } - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'widget': TextInput(attrs=widget_attrs), - } - if self.data.max_length: - field_kwargs['max_length'] = self.data.max_length - - return [(self.data.name, GenericIPAddressField, field_kwargs)] - form_element_plugin_registry.register(IPAddressInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/null_boolean/base.py b/src/fobi/contrib/plugins/form_elements/fields/null_boolean/base.py new file mode 100644 index 00000000..aa74e1a5 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/null_boolean/base.py @@ -0,0 +1,42 @@ +from __future__ import absolute_import + +from django.forms.fields import NullBooleanField +from django.forms.widgets import NullBooleanSelect +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import NullBooleanSelectForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.null_boolean.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('NullBooleanSelectPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class NullBooleanSelectPlugin(FormFieldPlugin): + """Null boolean select plugin.""" + + uid = UID + name = _("Null boolean") + group = _("Fields") + form = NullBooleanSelectForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'widget': NullBooleanSelect( + attrs={'class': theme.form_element_html_class} + ), + } + + return [(self.data.name, NullBooleanField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/null_boolean/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/null_boolean/fobi_form_elements.py index fec42fdd..0ffa2428 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/null_boolean/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/null_boolean/fobi_form_elements.py @@ -1,11 +1,8 @@ -from django.forms.fields import NullBooleanField -from django.forms.widgets import NullBooleanSelect -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import NullBooleanSelectForm +from .base import NullBooleanSelectPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'null_boolean.fobi_form_elements' @@ -14,31 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('NullBooleanSelectPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class NullBooleanSelectPlugin(FormFieldPlugin): - """Null boolean select plugin.""" - - uid = UID - name = _("Null boolean") - group = _("Fields") - form = NullBooleanSelectForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'widget': NullBooleanSelect( - attrs={'class': theme.form_element_html_class} - ), - } - - return [(self.data.name, NullBooleanField, field_kwargs)] - form_element_plugin_registry.register(NullBooleanSelectPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/password/base.py b/src/fobi/contrib/plugins/form_elements/fields/password/base.py new file mode 100644 index 00000000..0e9ffdc8 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/password/base.py @@ -0,0 +1,47 @@ +from __future__ import absolute_import + +from django.forms.fields import CharField +from django.forms.widgets import PasswordInput +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import PasswordInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.password.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('PasswordInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class PasswordInputPlugin(FormFieldPlugin): + """Password field plugin.""" + + uid = UID + name = _("Password") + group = _("Fields") + form = PasswordInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'placeholder': self.data.placeholder, + } + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'widget': PasswordInput(attrs=widget_attrs), + } + if self.data.max_length: + field_kwargs['max_length'] = self.data.max_length + + return [(self.data.name, CharField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/password/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/password/fobi_form_elements.py index 84cebb6a..39727b93 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/password/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/password/fobi_form_elements.py @@ -1,11 +1,8 @@ -from django.forms.fields import CharField -from django.forms.widgets import PasswordInput -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import PasswordInputForm +from .base import PasswordInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'password.fobi_form_elements' @@ -14,36 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('PasswordInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class PasswordInputPlugin(FormFieldPlugin): - """Password field plugin.""" - - uid = UID - name = _("Password") - group = _("Fields") - form = PasswordInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'placeholder': self.data.placeholder, - } - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'widget': PasswordInput(attrs=widget_attrs), - } - if self.data.max_length: - field_kwargs['max_length'] = self.data.max_length - - return [(self.data.name, CharField, field_kwargs)] - form_element_plugin_registry.register(PasswordInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/radio/base.py b/src/fobi/contrib/plugins/form_elements/fields/radio/base.py new file mode 100644 index 00000000..4579fce2 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/radio/base.py @@ -0,0 +1,88 @@ +from __future__ import absolute_import + +from django.forms.fields import ChoiceField +from django.forms.widgets import RadioSelect +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme +from fobi.constants import ( + SUBMIT_VALUE_AS_VAL, + SUBMIT_VALUE_AS_REPR +) +from fobi.helpers import get_select_field_choices, safe_text + +from . import UID +from .forms import RadioInputForm +from .settings import SUBMIT_VALUE_AS + +__title__ = 'fobi.contrib.plugins.form_elements.fields.radio.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('RadioInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class RadioInputPlugin(FormFieldPlugin): + """Radio field plugin.""" + + uid = UID + name = _("Radio") + group = _("Fields") + form = RadioInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + choices = get_select_field_choices(self.data.choices) + + widget_attrs = {'class': theme.form_radio_element_html_class} + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'choices': choices, + 'widget': RadioSelect(attrs=widget_attrs), + } + + return [(self.data.name, ChoiceField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """Submit plugin form data/process. + + :param fobi.models.FormEntry form_entry: Instance of + ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # In case if we should submit value as is, we don't return anything. + # In other cases, we proceed further. + if SUBMIT_VALUE_AS != SUBMIT_VALUE_AS_VAL: + # Get the object + value = form.cleaned_data.get(self.data.name, None) + + # Get choices + choices = dict(get_select_field_choices(self.data.choices)) + + if value in choices: + # Handle the submitted form value + + label = safe_text(choices.get(value)) + + # Should be returned as repr + if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: + value = label + # Should be returned as mix + else: + value = "{0} ({1})".format(label, value) + + # Overwrite ``cleaned_data`` of the ``form`` with object + # qualifier. + form.cleaned_data[self.data.name] = value + + # It's critically important to return the ``form`` with updated + # ``cleaned_data`` + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/radio/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/radio/fobi_form_elements.py index 96d57032..854dfd2e 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/radio/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/radio/fobi_form_elements.py @@ -1,16 +1,8 @@ -from django.forms.fields import ChoiceField -from django.forms.widgets import RadioSelect -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.constants import ( - SUBMIT_VALUE_AS_VAL, SUBMIT_VALUE_AS_REPR -) -from fobi.helpers import get_select_field_choices, safe_text +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import RadioInputForm -from .settings import SUBMIT_VALUE_AS +from .base import RadioInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'radio.fobi_form_elements' @@ -19,70 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('RadioInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class RadioInputPlugin(FormFieldPlugin): - """Radio field plugin.""" - - uid = UID - name = _("Radio") - group = _("Fields") - form = RadioInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - choices = get_select_field_choices(self.data.choices) - - widget_attrs = {'class': theme.form_radio_element_html_class} - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'choices': choices, - 'widget': RadioSelect(attrs=widget_attrs), - } - - return [(self.data.name, ChoiceField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """Submit plugin form data/process. - - :param fobi.models.FormEntry form_entry: Instance of - ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # In case if we should submit value as is, we don't return anything. - # In other cases, we proceed further. - if SUBMIT_VALUE_AS != SUBMIT_VALUE_AS_VAL: - # Get the object - value = form.cleaned_data.get(self.data.name, None) - - # Get choices - choices = dict(get_select_field_choices(self.data.choices)) - - if value in choices: - # Handle the submitted form value - - label = safe_text(choices.get(value)) - - # Should be returned as repr - if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: - value = label - # Should be returned as mix - else: - value = "{0} ({1})".format(label, value) - - # Overwrite ``cleaned_data`` of the ``form`` with object - # qualifier. - form.cleaned_data[self.data.name] = value - - # It's critically important to return the ``form`` with updated - # ``cleaned_data`` - return form - form_element_plugin_registry.register(RadioInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/range_select/base.py b/src/fobi/contrib/plugins/form_elements/fields/range_select/base.py new file mode 100644 index 00000000..9114ccce --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/range_select/base.py @@ -0,0 +1,61 @@ +from __future__ import absolute_import + +from django.forms.fields import ChoiceField +from django.forms.widgets import Select +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import RangeSelectInputForm +from .settings import ( + INITIAL, + INITIAL_MAX_VALUE, + INITIAL_MIN_VALUE, + # MAX_VALUE, + # MIN_VALUE, + STEP +) + +__title__ = 'fobi.contrib.plugins.form_elements.fields.range_select.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('RangeSelectInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class RangeSelectInputPlugin(FormFieldPlugin): + """Range select input plugin.""" + + uid = UID + name = _("Range select") + group = _("Fields") + form = RangeSelectInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + initial = self.data.initial if self.data.initial else INITIAL + max_value = self.data.max_value \ + if self.data.max_value \ + else INITIAL_MAX_VALUE + min_value = self.data.min_value \ + if self.data.min_value \ + else INITIAL_MIN_VALUE + step = self.data.step if self.data.step else STEP + + _choices = range(min_value, max_value+1, step) + choices = zip(_choices, _choices) + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': initial, + 'required': self.data.required, + 'choices': choices, + 'widget': Select(attrs={'class': theme.form_element_html_class}), + } + + return [(self.data.name, ChoiceField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/range_select/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/range_select/fobi_form_elements.py index 84a8966e..36718e20 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/range_select/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/range_select/fobi_form_elements.py @@ -1,19 +1,8 @@ -from django.forms.fields import ChoiceField -from django.forms.widgets import Select -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import RangeSelectInputForm -from .settings import ( - INITIAL, - INITIAL_MAX_VALUE, - INITIAL_MIN_VALUE, - # MAX_VALUE, - # MIN_VALUE, - STEP -) +from .base import RangeSelectInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.range_select.' \ 'fobi_form_elements' @@ -22,42 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('RangeSelectInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class RangeSelectInputPlugin(FormFieldPlugin): - """Range select input plugin.""" - - uid = UID - name = _("Range select") - group = _("Fields") - form = RangeSelectInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - initial = self.data.initial if self.data.initial else INITIAL - max_value = self.data.max_value \ - if self.data.max_value \ - else INITIAL_MAX_VALUE - min_value = self.data.min_value \ - if self.data.min_value \ - else INITIAL_MIN_VALUE - step = self.data.step if self.data.step else STEP - - _choices = range(min_value, max_value+1, step) - choices = zip(_choices, _choices) - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': initial, - 'required': self.data.required, - 'choices': choices, - 'widget': Select(attrs={'class': theme.form_element_html_class}), - } - - return [(self.data.name, ChoiceField, field_kwargs)] - form_element_plugin_registry.register(RangeSelectInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/regex/base.py b/src/fobi/contrib/plugins/form_elements/fields/regex/base.py new file mode 100644 index 00000000..03e16db2 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/regex/base.py @@ -0,0 +1,49 @@ +from __future__ import absolute_import + +from django.forms.fields import RegexField +from django.forms.widgets import TextInput +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import RegexInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.regex.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('RegexInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class RegexInputPlugin(FormFieldPlugin): + """Regex field plugin.""" + + uid = UID + name = _("Regex") + group = _("Fields") + form = RegexInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'placeholder': self.data.placeholder, + } + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'regex': self.data.regex, + 'initial': self.data.initial, + 'required': self.data.required, + 'widget': TextInput(attrs=widget_attrs), + } + + if self.data.max_length: + field_kwargs['max_length'] = self.data.max_length + + return [(self.data.name, RegexField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/regex/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/regex/fobi_form_elements.py index 4f281f4c..69ef11c9 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/regex/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/regex/fobi_form_elements.py @@ -1,13 +1,8 @@ from __future__ import absolute_import -from django.forms.fields import RegexField -from django.forms.widgets import TextInput -from django.utils.translation import ugettext_lazy as _ +from fobi.base import form_element_plugin_registry -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme - -from . import UID -from .forms import RegexInputForm +from .base import RegexInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'regex.fobi_form_elements' @@ -16,38 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('RegexInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class RegexInputPlugin(FormFieldPlugin): - """Regex field plugin.""" - - uid = UID - name = _("Regex") - group = _("Fields") - form = RegexInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'placeholder': self.data.placeholder, - } - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'regex': self.data.regex, - 'initial': self.data.initial, - 'required': self.data.required, - 'widget': TextInput(attrs=widget_attrs), - } - - if self.data.max_length: - field_kwargs['max_length'] = self.data.max_length - - return [(self.data.name, RegexField, field_kwargs)] - form_element_plugin_registry.register(RegexInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/regex/forms.py b/src/fobi/contrib/plugins/form_elements/fields/regex/forms.py index 85ad6be0..38e3829e 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/regex/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/regex/forms.py @@ -100,6 +100,7 @@ class RegexInputForm(forms.Form, BaseFormFieldPluginForm): ) def clean(self): + """Validation.""" super(RegexInputForm, self).clean() max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) @@ -111,4 +112,4 @@ class RegexInputForm(forms.Form, BaseFormFieldPluginForm): 'initial', _("Ensure this value has at most {0} characters " "(it has {1}).".format(max_length, len_initial)) - ) \ No newline at end of file + ) diff --git a/src/fobi/contrib/plugins/form_elements/fields/select/base.py b/src/fobi/contrib/plugins/form_elements/fields/select/base.py new file mode 100644 index 00000000..1380a097 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/select/base.py @@ -0,0 +1,87 @@ +from __future__ import absolute_import + +from django.forms.fields import ChoiceField +from django.forms.widgets import Select +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme +from fobi.constants import ( + SUBMIT_VALUE_AS_VAL, + SUBMIT_VALUE_AS_REPR +) +from fobi.helpers import get_select_field_choices, safe_text + +from . import UID +from .forms import SelectInputForm +from .settings import SUBMIT_VALUE_AS + +__title__ = 'fobi.contrib.plugins.form_elements.fields.select.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('SelectInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class SelectInputPlugin(FormFieldPlugin): + """Select field plugin.""" + + uid = UID + name = _("Select") + group = _("Fields") + form = SelectInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + choices = get_select_field_choices(self.data.choices) + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'choices': choices, + 'widget': Select(attrs={'class': theme.form_element_html_class}), + } + + return [(self.data.name, ChoiceField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """Submit plugin form data/process. + + :param fobi.models.FormEntry form_entry: Instance of + ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # In case if we should submit value as is, we don't return anything. + # In other cases, we proceed further. + if SUBMIT_VALUE_AS != SUBMIT_VALUE_AS_VAL: + # Get the object + value = form.cleaned_data.get(self.data.name, None) + + # Get choices + choices = dict(get_select_field_choices(self.data.choices)) + + if value in choices: + # Handle the submitted form value + + label = safe_text(choices.get(value)) + + # Should be returned as repr + if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: + value = label + # Should be returned as mix + else: + value = "{0} ({1})".format(label, value) + + # Overwrite ``cleaned_data`` of the ``form`` with object + # qualifier. + form.cleaned_data[self.data.name] = value + + # It's critically important to return the ``form`` with + # updated ``cleaned_data`` + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/select/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/select/fobi_form_elements.py index c0f77614..0db1d61f 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/select/fobi_form_elements.py @@ -1,16 +1,8 @@ -from django.forms.fields import ChoiceField -from django.forms.widgets import Select -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.constants import ( - SUBMIT_VALUE_AS_VAL, SUBMIT_VALUE_AS_REPR -) -from fobi.helpers import get_select_field_choices, safe_text +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import SelectInputForm -from .settings import SUBMIT_VALUE_AS +from .base import SelectInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'select.fobi_form_elements' @@ -19,69 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('SelectInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class SelectInputPlugin(FormFieldPlugin): - """Select field plugin.""" - - uid = UID - name = _("Select") - group = _("Fields") - form = SelectInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - choices = get_select_field_choices(self.data.choices) - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'choices': choices, - 'widget': Select(attrs={'class': theme.form_element_html_class}), - } - - return [(self.data.name, ChoiceField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """Submit plugin form data/process. - - :param fobi.models.FormEntry form_entry: Instance of - ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # In case if we should submit value as is, we don't return anything. - # In other cases, we proceed further. - if SUBMIT_VALUE_AS != SUBMIT_VALUE_AS_VAL: - # Get the object - value = form.cleaned_data.get(self.data.name, None) - - # Get choices - choices = dict(get_select_field_choices(self.data.choices)) - - if value in choices: - # Handle the submitted form value - - label = safe_text(choices.get(value)) - - # Should be returned as repr - if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: - value = label - # Should be returned as mix - else: - value = "{0} ({1})".format(label, value) - - # Overwrite ``cleaned_data`` of the ``form`` with object - # qualifier. - form.cleaned_data[self.data.name] = value - - # It's critically important to return the ``form`` with - # updated ``cleaned_data`` - return form - form_element_plugin_registry.register(SelectInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_model_object/base.py b/src/fobi/contrib/plugins/form_elements/fields/select_model_object/base.py new file mode 100644 index 00000000..76230d20 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/select_model_object/base.py @@ -0,0 +1,107 @@ +from __future__ import absolute_import + +from django.forms.models import ModelChoiceField +from django.forms.widgets import Select +from django.utils.translation import ugettext_lazy as _ + +from nine.versions import DJANGO_GTE_1_7 + +from fobi.base import FormFieldPlugin, get_theme +from fobi.constants import ( + SUBMIT_VALUE_AS_VAL, + SUBMIT_VALUE_AS_REPR +) +from fobi.helpers import ( + safe_text, + get_app_label_and_model_name, + get_model_name_for_object +) + +from . import UID +from .forms import SelectModelObjectInputForm +from .settings import SUBMIT_VALUE_AS + +if DJANGO_GTE_1_7: + from django.apps import apps + + get_model = apps.get_model +else: + from django.db.models import get_model + +__title__ = 'fobi.contrib.plugins.form_elements.fields.' \ + 'select_model_object.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('SelectModelObjectInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class SelectModelObjectInputPlugin(FormFieldPlugin): + """Select model object field plugin.""" + + uid = UID + name = _("Select model object") + group = _("Fields") + form = SelectModelObjectInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + app_label, model_name = get_app_label_and_model_name(self.data.model) + model = get_model(app_label, model_name) + queryset = model._default_manager.all() + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'queryset': queryset, + 'widget': Select(attrs={'class': theme.form_element_html_class}), + } + + return [(self.data.name, ModelChoiceField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """Submit plugin form data/process. + + :param fobi.models.FormEntry form_entry: Instance of + ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # In case if we should submit value as is, we don't return anything. + # In other cases, we proceed further. + + # Get the object + obj = form.cleaned_data.get(self.data.name, None) + if obj: + value = None + # Should be returned as repr + if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: + value = safe_text(obj) + elif SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_VAL: + value = '{0}.{1}.{2}'.format( + obj._meta.app_label, + get_model_name_for_object(obj), + obj.pk + ) + else: + # Handle the submitted form value + value = '{0}.{1}.{2}.{3}'.format( + obj._meta.app_label, + get_model_name_for_object(obj), + obj.pk, + safe_text(obj) + ) + + # Overwrite ``cleaned_data`` of the ``form`` with object + # qualifier. + form.cleaned_data[self.data.name] = value + + # It's critically important to return the ``form`` with updated + # ``cleaned_data`` + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_model_object/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/select_model_object/fobi_form_elements.py index b24bf424..d0ac88e5 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select_model_object/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/select_model_object/fobi_form_elements.py @@ -1,29 +1,8 @@ -from django.forms.models import ModelChoiceField -from django.forms.widgets import Select -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from nine.versions import DJANGO_GTE_1_7 +from fobi.base import form_element_plugin_registry -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.constants import ( - SUBMIT_VALUE_AS_VAL, SUBMIT_VALUE_AS_REPR -) -from fobi.helpers import ( - safe_text, - get_app_label_and_model_name, - get_model_name_for_object -) - -from . import UID -from .forms import SelectModelObjectInputForm -from .settings import SUBMIT_VALUE_AS - -if DJANGO_GTE_1_7: - from django.apps import apps - - get_model = apps.get_model -else: - from django.db.models import get_model +from .base import SelectModelObjectInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'select_model_object.fobi_form_elements' @@ -32,75 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('SelectModelObjectInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class SelectModelObjectInputPlugin(FormFieldPlugin): - """Select model object field plugin.""" - - uid = UID - name = _("Select model object") - group = _("Fields") - form = SelectModelObjectInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - app_label, model_name = get_app_label_and_model_name(self.data.model) - model = get_model(app_label, model_name) - queryset = model._default_manager.all() - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'queryset': queryset, - 'widget': Select(attrs={'class': theme.form_element_html_class}), - } - - return [(self.data.name, ModelChoiceField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """Submit plugin form data/process. - - :param fobi.models.FormEntry form_entry: Instance of - ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # In case if we should submit value as is, we don't return anything. - # In other cases, we proceed further. - - # Get the object - obj = form.cleaned_data.get(self.data.name, None) - if obj: - value = None - # Should be returned as repr - if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: - value = safe_text(obj) - elif SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_VAL: - value = '{0}.{1}.{2}'.format( - obj._meta.app_label, - get_model_name_for_object(obj), - obj.pk - ) - else: - # Handle the submitted form value - value = '{0}.{1}.{2}.{3}'.format( - obj._meta.app_label, - get_model_name_for_object(obj), - obj.pk, - safe_text(obj) - ) - - # Overwrite ``cleaned_data`` of the ``form`` with object - # qualifier. - form.cleaned_data[self.data.name] = value - - # It's critically important to return the ``form`` with updated - # ``cleaned_data`` - return form - form_element_plugin_registry.register(SelectModelObjectInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_mptt_model_object/base.py b/src/fobi/contrib/plugins/form_elements/fields/select_mptt_model_object/base.py new file mode 100644 index 00000000..01d77437 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/select_mptt_model_object/base.py @@ -0,0 +1,107 @@ +from __future__ import absolute_import + +from django.forms.widgets import Select +from django.utils.translation import ugettext_lazy as _ + +from mptt.fields import TreeNodeChoiceField + +from fobi.base import FormFieldPlugin, get_theme +from fobi.constants import ( + SUBMIT_VALUE_AS_VAL, + SUBMIT_VALUE_AS_REPR +) +from fobi.helpers import ( + safe_text, + get_app_label_and_model_name, + get_model_name_for_object +) + +from nine.versions import DJANGO_GTE_1_7 + +from . import UID +from .forms import SelectMPTTModelObjectInputForm +from .settings import SUBMIT_VALUE_AS + +if DJANGO_GTE_1_7: + from django.apps import apps + + get_model = apps.get_model +else: + from django.db.models import get_model + +__title__ = 'fobi.contrib.plugins.form_elements.fields.' \ + 'select_mptt_model_object.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('SelectMPTTModelObjectInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class SelectMPTTModelObjectInputPlugin(FormFieldPlugin): + """Select MPTT model object field plugin.""" + + uid = UID + name = _("Select MPTT model object") + group = _("Fields") + form = SelectMPTTModelObjectInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + app_label, model_name = get_app_label_and_model_name(self.data.model) + model = get_model(app_label, model_name) + queryset = model._default_manager.all() + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'queryset': queryset, + 'widget': Select(attrs={'class': theme.form_element_html_class}), + } + + return [(self.data.name, TreeNodeChoiceField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """Submit plugin form data/process. + + :param fobi.models.FormEntry form_entry: Instance of + ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # In case if we should submit value as is, we don't return anything. + # In other cases, we proceed further. + + # Get the object + obj = form.cleaned_data.get(self.data.name, None) + if obj: + value = None + # Should be returned as repr + if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: + value = safe_text(obj) + elif SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_VAL: + value = '{0}.{1}.{2}'.format( + obj._meta.app_label, + get_model_name_for_object(obj), + obj.pk + ) + else: + # Handle the submitted form value + value = '{0}.{1}.{2}.{3}'.format( + obj._meta.app_label, + get_model_name_for_object(obj), + obj.pk, + safe_text(obj) + ) + + # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. + form.cleaned_data[self.data.name] = value + + # It's critically important to return the ``form`` with updated + # ``cleaned_data`` + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_mptt_model_object/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/select_mptt_model_object/fobi_form_elements.py index 033367df..76d740b7 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select_mptt_model_object/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/select_mptt_model_object/fobi_form_elements.py @@ -1,30 +1,8 @@ -from django.forms.widgets import Select -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from mptt.fields import TreeNodeChoiceField +from fobi.base import form_element_plugin_registry -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.constants import ( - SUBMIT_VALUE_AS_VAL, SUBMIT_VALUE_AS_REPR -) -from fobi.helpers import ( - safe_text, - get_app_label_and_model_name, - get_model_name_for_object -) - -from nine.versions import DJANGO_GTE_1_7 - -from . import UID -from .forms import SelectMPTTModelObjectInputForm -from .settings import SUBMIT_VALUE_AS - -if DJANGO_GTE_1_7: - from django.apps import apps - - get_model = apps.get_model -else: - from django.db.models import get_model +from .base import SelectMPTTModelObjectInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'select_mptt_model_object.fobi_form_elements' @@ -33,74 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('SelectMPTTModelObjectInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class SelectMPTTModelObjectInputPlugin(FormFieldPlugin): - """Select MPTT model object field plugin.""" - - uid = UID - name = _("Select MPTT model object") - group = _("Fields") - form = SelectMPTTModelObjectInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - app_label, model_name = get_app_label_and_model_name(self.data.model) - model = get_model(app_label, model_name) - queryset = model._default_manager.all() - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'queryset': queryset, - 'widget': Select(attrs={'class': theme.form_element_html_class}), - } - - return [(self.data.name, TreeNodeChoiceField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """Submit plugin form data/process. - - :param fobi.models.FormEntry form_entry: Instance of - ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # In case if we should submit value as is, we don't return anything. - # In other cases, we proceed further. - - # Get the object - obj = form.cleaned_data.get(self.data.name, None) - if obj: - value = None - # Should be returned as repr - if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: - value = safe_text(obj) - elif SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_VAL: - value = '{0}.{1}.{2}'.format( - obj._meta.app_label, - get_model_name_for_object(obj), - obj.pk - ) - else: - # Handle the submitted form value - value = '{0}.{1}.{2}.{3}'.format( - obj._meta.app_label, - get_model_name_for_object(obj), - obj.pk, - safe_text(obj) - ) - - # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. - form.cleaned_data[self.data.name] = value - - # It's critically important to return the ``form`` with updated - # ``cleaned_data`` - return form - form_element_plugin_registry.register(SelectMPTTModelObjectInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_multiple/base.py b/src/fobi/contrib/plugins/form_elements/fields/select_multiple/base.py new file mode 100644 index 00000000..1a977691 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/select_multiple/base.py @@ -0,0 +1,98 @@ +from __future__ import absolute_import + +from django.forms.fields import MultipleChoiceField +from django.forms.widgets import SelectMultiple +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme +from fobi.constants import ( + SUBMIT_VALUE_AS_VAL, + SUBMIT_VALUE_AS_REPR +) +from fobi.helpers import get_select_field_choices, safe_text + +from . import UID +from .forms import SelectMultipleInputForm +from .settings import SUBMIT_VALUE_AS + +__title__ = 'fobi.contrib.plugins.form_elements.fields.' \ + 'select_multiple.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('SelectMultipleInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class SelectMultipleInputPlugin(FormFieldPlugin): + """Select multiple field plugin.""" + + uid = UID + name = _("Select multiple") + group = _("Fields") + form = SelectMultipleInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + choices = get_select_field_choices(self.data.choices) + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'choices': choices, + 'widget': SelectMultiple( + attrs={'class': theme.form_element_html_class} + ), + } + + return [(self.data.name, MultipleChoiceField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """ + Submit plugin form data/process. + + :param fobi.models.FormEntry form_entry: Instance of + ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # In case if we should submit value as is, we don't return anything. + # In other cases, we proceed further. + if SUBMIT_VALUE_AS != SUBMIT_VALUE_AS_VAL: + # Get the object + values = form.cleaned_data.get(self.data.name, None) + + # Get choices + choices = dict(get_select_field_choices(self.data.choices)) + + # Returned value + ret_values = [] + + for value in values: + # Handle the submitted form value + + if value in choices: + label = safe_text(choices.get(value)) + + # Should be returned as repr + if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: + value = label + # Should be returned as mix + else: + value = "{0} ({1})".format(label, value) + + ret_values.append(value) + + # Overwrite ``cleaned_data`` of the ``form`` with object + # qualifier. + if ret_values: + form.cleaned_data[self.data.name] = ret_values + + # It's critically important to return the ``form`` with updated + # ``cleaned_data`` + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_multiple/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/select_multiple/fobi_form_elements.py index b8e1f45d..af262108 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select_multiple/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/select_multiple/fobi_form_elements.py @@ -1,16 +1,8 @@ -from django.forms.fields import MultipleChoiceField -from django.forms.widgets import SelectMultiple -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.constants import ( - SUBMIT_VALUE_AS_VAL, SUBMIT_VALUE_AS_REPR -) -from fobi.helpers import get_select_field_choices, safe_text +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import SelectMultipleInputForm -from .settings import SUBMIT_VALUE_AS +from .base import SelectMultipleInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'select_multiple.fobi_form_elements' @@ -19,79 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('SelectMultipleInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class SelectMultipleInputPlugin(FormFieldPlugin): - """Select multiple field plugin.""" - - uid = UID - name = _("Select multiple") - group = _("Fields") - form = SelectMultipleInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - choices = get_select_field_choices(self.data.choices) - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'choices': choices, - 'widget': SelectMultiple( - attrs={'class': theme.form_element_html_class} - ), - } - - return [(self.data.name, MultipleChoiceField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """ - Submit plugin form data/process. - - :param fobi.models.FormEntry form_entry: Instance of - ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # In case if we should submit value as is, we don't return anything. - # In other cases, we proceed further. - if SUBMIT_VALUE_AS != SUBMIT_VALUE_AS_VAL: - # Get the object - values = form.cleaned_data.get(self.data.name, None) - - # Get choices - choices = dict(get_select_field_choices(self.data.choices)) - - # Returned value - ret_values = [] - - for value in values: - # Handle the submitted form value - - if value in choices: - label = safe_text(choices.get(value)) - - # Should be returned as repr - if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: - value = label - # Should be returned as mix - else: - value = "{0} ({1})".format(label, value) - - ret_values.append(value) - - # Overwrite ``cleaned_data`` of the ``form`` with object - # qualifier. - if ret_values: - form.cleaned_data[self.data.name] = ret_values - - # It's critically important to return the ``form`` with updated - # ``cleaned_data`` - return form - form_element_plugin_registry.register(SelectMultipleInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_model_objects/base.py b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_model_objects/base.py new file mode 100644 index 00000000..24b714d0 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_model_objects/base.py @@ -0,0 +1,118 @@ +from __future__ import absolute_import + +import simplejson as json + +from django.forms.models import ModelMultipleChoiceField +from django.forms.widgets import SelectMultiple +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme +from fobi.constants import ( + SUBMIT_VALUE_AS_VAL, + SUBMIT_VALUE_AS_REPR +) +from fobi.helpers import ( + safe_text, + get_app_label_and_model_name, + get_model_name_for_object +) + +from nine.versions import DJANGO_GTE_1_7 + +from . import UID +from .forms import SelectMultipleModelObjectsInputForm +from .settings import SUBMIT_VALUE_AS + +if DJANGO_GTE_1_7: + from django.apps import apps + get_model = apps.get_model +else: + from django.db.models import get_model + +__title__ = 'fobi.contrib.plugins.form_elements.fields.' \ + 'select_multiple_model_objects.fobi_form_elements' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('SelectMultipleModelObjectsInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class SelectMultipleModelObjectsInputPlugin(FormFieldPlugin): + """Select multiple model objects field plugin.""" + + uid = UID + name = _("Select multiple model objects") + group = _("Fields") + form = SelectMultipleModelObjectsInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + app_label, model_name = get_app_label_and_model_name(self.data.model) + model = get_model(app_label, model_name) + queryset = model._default_manager.all() + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'queryset': queryset, + 'widget': SelectMultiple( + attrs={'class': theme.form_element_html_class} + ), + } + + return [(self.data.name, ModelMultipleChoiceField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """ + Submit plugin form data/process. + + :param fobi.models.FormEntry form_entry: Instance of + ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # In case if we should submit value as is, we don't return anything. + # In other cases, we proceed further. + + # Get the object + objs = form.cleaned_data.get(self.data.name, []) + + values = [] + + for obj in objs: + if obj: + value = None + # Should be returned as repr + if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: + value = safe_text(obj) + elif SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_VAL: + value = '{0}.{1}.{2}'.format( + obj._meta.app_label, + get_model_name_for_object(obj), + obj.pk + ) + else: + # Handle the submitted form value + value = '{0}.{1}.{2}.{3}'.format( + obj._meta.app_label, + get_model_name_for_object(obj), + obj.pk, + safe_text(obj) + ) + values.append(value) + + # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. + if values: + form.cleaned_data[self.data.name] = json.dumps(values) + else: + del form.cleaned_data[self.data.name] + + # It's critically important to return the ``form`` with updated + # ``cleaned_data`` + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_model_objects/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_model_objects/fobi_form_elements.py index 0debdf35..da043ad8 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_model_objects/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_model_objects/fobi_form_elements.py @@ -1,30 +1,8 @@ -import simplejson as json +from __future__ import absolute_import -from django.forms.models import ModelMultipleChoiceField -from django.forms.widgets import SelectMultiple -from django.utils.translation import ugettext_lazy as _ +from fobi.base import form_element_plugin_registry -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.constants import ( - SUBMIT_VALUE_AS_VAL, SUBMIT_VALUE_AS_REPR -) -from fobi.helpers import ( - safe_text, - get_app_label_and_model_name, - get_model_name_for_object -) - -from nine.versions import DJANGO_GTE_1_7 - -from . import UID -from .forms import SelectMultipleModelObjectsInputForm -from .settings import SUBMIT_VALUE_AS - -if DJANGO_GTE_1_7: - from django.apps import apps - get_model = apps.get_model -else: - from django.db.models import get_model +from .base import SelectMultipleModelObjectsInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'select_multiple_model_objects.fobi_form_elements' @@ -33,85 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('SelectMultipleModelObjectsInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class SelectMultipleModelObjectsInputPlugin(FormFieldPlugin): - """Select multiple model objects field plugin.""" - - uid = UID - name = _("Select multiple model objects") - group = _("Fields") - form = SelectMultipleModelObjectsInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - app_label, model_name = get_app_label_and_model_name(self.data.model) - model = get_model(app_label, model_name) - queryset = model._default_manager.all() - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'queryset': queryset, - 'widget': SelectMultiple( - attrs={'class': theme.form_element_html_class} - ), - } - - return [(self.data.name, ModelMultipleChoiceField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """ - Submit plugin form data/process. - - :param fobi.models.FormEntry form_entry: Instance of - ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # In case if we should submit value as is, we don't return anything. - # In other cases, we proceed further. - - # Get the object - objs = form.cleaned_data.get(self.data.name, []) - - values = [] - - for obj in objs: - if obj: - value = None - # Should be returned as repr - if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: - value = safe_text(obj) - elif SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_VAL: - value = '{0}.{1}.{2}'.format( - obj._meta.app_label, - get_model_name_for_object(obj), - obj.pk - ) - else: - # Handle the submitted form value - value = '{0}.{1}.{2}.{3}'.format( - obj._meta.app_label, - get_model_name_for_object(obj), - obj.pk, - safe_text(obj) - ) - values.append(value) - - # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. - if values: - form.cleaned_data[self.data.name] = json.dumps(values) - else: - del form.cleaned_data[self.data.name] - - # It's critically important to return the ``form`` with updated - # ``cleaned_data`` - return form - form_element_plugin_registry.register(SelectMultipleModelObjectsInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_mptt_model_objects/base.py b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_mptt_model_objects/base.py new file mode 100644 index 00000000..72529cde --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_mptt_model_objects/base.py @@ -0,0 +1,118 @@ +from __future__ import absolute_import + +import simplejson as json + +from django.forms.widgets import SelectMultiple +from django.utils.translation import ugettext_lazy as _ + +from mptt.fields import TreeNodeMultipleChoiceField + +from fobi.base import FormFieldPlugin, get_theme +from fobi.constants import ( + SUBMIT_VALUE_AS_VAL, + SUBMIT_VALUE_AS_REPR +) +from fobi.helpers import ( + safe_text, + get_app_label_and_model_name, + get_model_name_for_object +) + +from nine.versions import DJANGO_GTE_1_7 + +from . import UID +from .forms import SelectMultipleMPTTModelObjectsInputForm +from .settings import SUBMIT_VALUE_AS + +if DJANGO_GTE_1_7: + from django.apps import apps + get_model = apps.get_model +else: + from django.db.models import get_model + +__title__ = 'fobi.contrib.plugins.form_elements.fields.' \ + 'select_multiple_mptt_model_objects.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('SelectMultipleMPTTModelObjectsInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class SelectMultipleMPTTModelObjectsInputPlugin(FormFieldPlugin): + """Select multiple MPTT model object field plugin.""" + + uid = UID + name = _("Select multiple MPTT model objects") + group = _("Fields") + form = SelectMultipleMPTTModelObjectsInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + app_label, model_name = get_app_label_and_model_name(self.data.model) + model = get_model(app_label, model_name) + queryset = model._default_manager.all() + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'queryset': queryset, + 'widget': SelectMultiple( + attrs={'class': theme.form_element_html_class} + ), + } + + return [(self.data.name, TreeNodeMultipleChoiceField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """Submit plugin form data/process. + + :param fobi.models.FormEntry form_entry: Instance of + ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # In case if we should submit value as is, we don't return anything. + # In other cases, we proceed further. + + # Get the object + objs = form.cleaned_data.get(self.data.name, []) + + values = [] + + for obj in objs: + if obj: + value = None + # Should be returned as repr + if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: + value = safe_text(obj) + elif SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_VAL: + value = '{0}.{1}.{2}'.format( + obj._meta.app_label, + get_model_name_for_object(obj), + obj.pk + ) + else: + # Handle the submitted form value + value = '{0}.{1}.{2}.{3}'.format( + obj._meta.app_label, + get_model_name_for_object(obj), + obj.pk, + safe_text(obj) + ) + values.append(value) + + # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. + if values: + form.cleaned_data[self.data.name] = json.dumps(values) + else: + del form.cleaned_data[self.data.name] + + # It's critically important to return the ``form`` with updated + # ``cleaned_data`` + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_mptt_model_objects/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_mptt_model_objects/fobi_form_elements.py index 94d0c2c1..f67cf7f2 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_mptt_model_objects/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_mptt_model_objects/fobi_form_elements.py @@ -1,31 +1,8 @@ -import simplejson as json +from __future__ import absolute_import -from django.forms.widgets import SelectMultiple -from django.utils.translation import ugettext_lazy as _ +from fobi.base import form_element_plugin_registry -from mptt.fields import TreeNodeMultipleChoiceField - -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.constants import ( - SUBMIT_VALUE_AS_VAL, SUBMIT_VALUE_AS_REPR - ) -from fobi.helpers import ( - safe_text, - get_app_label_and_model_name, - get_model_name_for_object -) - -from nine.versions import DJANGO_GTE_1_7 - -from . import UID -from .forms import SelectMultipleMPTTModelObjectsInputForm -from .settings import SUBMIT_VALUE_AS - -if DJANGO_GTE_1_7: - from django.apps import apps - get_model = apps.get_model -else: - from django.db.models import get_model +from .base import SelectMultipleMPTTModelObjectsInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'select_multiple_mptt_model_objects.fobi_form_elements' @@ -34,85 +11,6 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('SelectMultipleMPTTModelObjectsInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class SelectMultipleMPTTModelObjectsInputPlugin(FormFieldPlugin): - """Select multiple MPTT model object field plugin.""" - - uid = UID - name = _("Select multiple MPTT model objects") - group = _("Fields") - form = SelectMultipleMPTTModelObjectsInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - app_label, model_name = get_app_label_and_model_name(self.data.model) - model = get_model(app_label, model_name) - queryset = model._default_manager.all() - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'queryset': queryset, - 'widget': SelectMultiple( - attrs={'class': theme.form_element_html_class} - ), - } - - return [(self.data.name, TreeNodeMultipleChoiceField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """Submit plugin form data/process. - - :param fobi.models.FormEntry form_entry: Instance of - ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # In case if we should submit value as is, we don't return anything. - # In other cases, we proceed further. - - # Get the object - objs = form.cleaned_data.get(self.data.name, []) - - values = [] - - for obj in objs: - if obj: - value = None - # Should be returned as repr - if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: - value = safe_text(obj) - elif SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_VAL: - value = '{0}.{1}.{2}'.format( - obj._meta.app_label, - get_model_name_for_object(obj), - obj.pk - ) - else: - # Handle the submitted form value - value = '{0}.{1}.{2}.{3}'.format( - obj._meta.app_label, - get_model_name_for_object(obj), - obj.pk, - safe_text(obj) - ) - values.append(value) - - # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. - if values: - form.cleaned_data[self.data.name] = json.dumps(values) - else: - del form.cleaned_data[self.data.name] - - # It's critically important to return the ``form`` with updated - # ``cleaned_data`` - return form - form_element_plugin_registry.register( SelectMultipleMPTTModelObjectsInputPlugin diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_with_max/base.py b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_with_max/base.py new file mode 100644 index 00000000..006b78be --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_with_max/base.py @@ -0,0 +1,99 @@ +from __future__ import absolute_import + +from django.forms.widgets import SelectMultiple +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme +from fobi.constants import ( + SUBMIT_VALUE_AS_VAL, + SUBMIT_VALUE_AS_REPR +) +from fobi.helpers import get_select_field_choices, safe_text + +from . import UID +from .fields import MultipleChoiceWithMaxField +from .forms import SelectMultipleWithMaxInputForm +from .settings import SUBMIT_VALUE_AS + +__title__ = 'fobi.contrib.plugins.form_elements.fields.' \ + 'select_multiple_with_max.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('SelectMultipleWithMaxInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class SelectMultipleWithMaxInputPlugin(FormFieldPlugin): + """Select multiple with max field plugin.""" + + uid = UID + name = _("Select multiple with max") + group = _("Fields") + form = SelectMultipleWithMaxInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + choices = get_select_field_choices(self.data.choices) + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'choices': choices, + 'widget': SelectMultiple( + attrs={'class': theme.form_element_html_class} + ), + } + + if self.data.max_choices: + field_kwargs['max_choices'] = self.data.max_choices + + return [(self.data.name, MultipleChoiceWithMaxField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """Submit plugin form data/process. + + :param fobi.models.FormEntry form_entry: Instance of + ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # In case if we should submit value as is, we don't return anything. + # In other cases, we proceed further. + if SUBMIT_VALUE_AS != SUBMIT_VALUE_AS_VAL: + # Get the object + values = form.cleaned_data.get(self.data.name, None) + + # Get choices + choices = dict(get_select_field_choices(self.data.choices)) + + # Returned value + ret_values = [] + + for value in values: + # Handle the submitted form value + + if value in choices: + label = safe_text(choices.get(value)) + + # Should be returned as repr + if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: + value = label + # Should be returned as mix + else: + value = "{0} ({1})".format(label, value) + + ret_values.append(value) + + # Overwrite ``cleaned_data`` of the ``form`` with object + # qualifier. + form.cleaned_data[self.data.name] = ret_values + + # It's critically important to return the ``form`` with updated + # ``cleaned_data`` + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_with_max/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_with_max/fobi_form_elements.py index 2fbab69a..8f2dd1f3 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/select_multiple_with_max/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/select_multiple_with_max/fobi_form_elements.py @@ -1,16 +1,8 @@ -from django.forms.widgets import SelectMultiple -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.constants import ( - SUBMIT_VALUE_AS_VAL, SUBMIT_VALUE_AS_REPR -) -from fobi.helpers import get_select_field_choices, safe_text +from fobi.base import form_element_plugin_registry -from . import UID -from .fields import MultipleChoiceWithMaxField -from .forms import SelectMultipleWithMaxInputForm -from .settings import SUBMIT_VALUE_AS +from .base import SelectMultipleWithMaxInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'select_multiple_with_max.fobi_form_elements' @@ -19,80 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('SelectMultipleWithMaxInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class SelectMultipleWithMaxInputPlugin(FormFieldPlugin): - """Select multiple with max field plugin.""" - - uid = UID - name = _("Select multiple with max") - group = _("Fields") - form = SelectMultipleWithMaxInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - choices = get_select_field_choices(self.data.choices) - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'choices': choices, - 'widget': SelectMultiple( - attrs={'class': theme.form_element_html_class} - ), - } - - if self.data.max_choices: - field_kwargs['max_choices'] = self.data.max_choices - - return [(self.data.name, MultipleChoiceWithMaxField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """Submit plugin form data/process. - - :param fobi.models.FormEntry form_entry: Instance of - ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # In case if we should submit value as is, we don't return anything. - # In other cases, we proceed further. - if SUBMIT_VALUE_AS != SUBMIT_VALUE_AS_VAL: - # Get the object - values = form.cleaned_data.get(self.data.name, None) - - # Get choices - choices = dict(get_select_field_choices(self.data.choices)) - - # Returned value - ret_values = [] - - for value in values: - # Handle the submitted form value - - if value in choices: - label = safe_text(choices.get(value)) - - # Should be returned as repr - if SUBMIT_VALUE_AS == SUBMIT_VALUE_AS_REPR: - value = label - # Should be returned as mix - else: - value = "{0} ({1})".format(label, value) - - ret_values.append(value) - - # Overwrite ``cleaned_data`` of the ``form`` with object - # qualifier. - form.cleaned_data[self.data.name] = ret_values - - # It's critically important to return the ``form`` with updated - # ``cleaned_data`` - return form - form_element_plugin_registry.register(SelectMultipleWithMaxInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/base.py b/src/fobi/contrib/plugins/form_elements/fields/slider/base.py new file mode 100644 index 00000000..2f2dc1a6 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/base.py @@ -0,0 +1,210 @@ +from __future__ import absolute_import + +from six import text_type + +from django.forms.fields import ChoiceField + +from django.utils.html import format_html +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext_lazy as _ + +from nine import versions + +from fobi.base import ( + FormFieldPlugin, + get_theme +) +from fobi.helpers import get_select_field_choices +from fobi.widgets import RichSelectInverseQuotes + +from . import UID +from .constants import ( + SLIDER_DEFAULT_TOOLTIP, + SLIDER_DEFAULT_HANDLE, + SLIDER_SHOW_ENDPOINTS_AS_LABELED_TICKS, + SLIDER_SHOW_ENDPOINTS_AS_TICKS, + SLIDER_DEFAULT_SHOW_ENDPOINTS_AS +) +from .forms import SliderInputForm +from .helpers import generate_ticks +from .settings import ( + INITIAL, + INITIAL_MAX_VALUE, + INITIAL_MIN_VALUE, + # MAX_VALUE, + # MIN_VALUE, + STEP +) + +if versions.DJANGO_GTE_1_7: + from django.forms.utils import flatatt +else: + from django.forms.util import flatatt + +__title__ = 'fobi.contrib.plugins.form_elements.fields.slider.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('SliderInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class SliderInputPlugin(FormFieldPlugin): + """Slider field plugin.""" + + uid = UID + name = _("Slider") + group = _("Fields") + form = SliderInputForm + html_classes = ['slider'] + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + initial = self.data.initial if self.data.initial else INITIAL + max_value = self.data.max_value \ + if self.data.max_value \ + else INITIAL_MAX_VALUE + min_value = self.data.min_value \ + if self.data.min_value \ + else INITIAL_MIN_VALUE + step = self.data.step if self.data.step else STEP + tooltip = self.data.tooltip \ + if self.data.tooltip \ + else SLIDER_DEFAULT_TOOLTIP + handle = self.data.handle \ + if self.data.handle \ + else SLIDER_DEFAULT_HANDLE + + custom_ticks = get_select_field_choices(self.data.custom_ticks, + key_type=int, + value_type=text_type) \ + if self.data.custom_ticks \ + else [] + + _choices = range(min_value, max_value+1, step) + choices = zip(_choices, _choices) + + # slider_html_class = "slider-no-background" \ + # if self.data.disable_slider_background \ + # else "slider" + slider_html_class = "slider" + + widget_attrs = { + 'class': "{0} {1}".format( + slider_html_class, + theme.form_element_html_class + ), + 'data-slider-min': min_value, + 'data-slider-max': max_value, + 'data-slider-step': step, + 'data-slider-value': initial, + 'data-slider-tooltip': tooltip, + 'data-slider-handle': handle, + } + + show_endpoints_as = self.data.show_endpoints_as \ + if self.data.show_endpoints_as \ + else SLIDER_DEFAULT_SHOW_ENDPOINTS_AS + + prepend_html_list = [] + append_html_list = [] + + # Show endpoints as labeled ticks + if SLIDER_SHOW_ENDPOINTS_AS_LABELED_TICKS == show_endpoints_as: + + if custom_ticks: + ticks_data = generate_ticks(custom_ticks) + else: + ticks_data = generate_ticks([ + (min_value, self.data.label_start), + (max_value, self.data.label_end), + ]) + # label_start = self.data.label_start \ + # if self.data.label_start \ + # else text_type(min_value) + # + # label_end = self.data.label_end \ + # if self.data.label_end \ + # else text_type(max_value) + + # widget_attrs.update({ + # 'data-slider-ticks': "[{0}, {1}]".format( + # min_value, max_value + # ), + # 'data-slider-ticks-labels': '["{0!s}", "{1!s}"]'.format( + # label_start.encode('utf8'), label_end.encode('utf8') + # ), + # }) + + widget_attrs.update(ticks_data) + + # Show endpoints as ticks + elif SLIDER_SHOW_ENDPOINTS_AS_TICKS == show_endpoints_as: + + if custom_ticks: + ticks_data = generate_ticks(custom_ticks, empty_labels=True) + else: + ticks_data = generate_ticks([ + (min_value, ""), + (max_value, ""), + ]) + + # widget_attrs.update({ + # 'data-slider-ticks': "[{0}, {1}]".format( + # min_value, max_value + # ), + # 'data-slider-ticks-labels': '["{0}", "{1}"]'.format( + # "", "" + # ), + # }) + + widget_attrs.update(ticks_data) + + # Show endpoints as labels + else: + + if self.data.label_start: + prepend_html_list.append( + format_html( + " ", + flatatt({'class': "slider-endpoint-label-start"}) + ) + ) + prepend_html_list.append(format_html(self.data.label_start)) + prepend_html_list.append(format_html(" ")) + + if self.data.label_end: + append_html_list.append( + format_html( + " ", + flatatt({'class': "slider-endpoint-label-end"}) + ) + ) + append_html_list.append(format_html(self.data.label_end)) + append_html_list.append(format_html(" ")) + + widget_kwargs = {'attrs': widget_attrs} + + # For showing endpoints as labels + if prepend_html_list: + widget_kwargs.update({ + 'prepend_html': mark_safe(''.join(prepend_html_list)), + }) + + if append_html_list: + widget_kwargs.update({ + 'append_html': mark_safe(''.join(append_html_list)), + }) + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': initial, + 'required': self.data.required, + 'choices': choices, + 'widget': RichSelectInverseQuotes(**widget_kwargs), + } + + return [(self.data.name, ChoiceField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py index a1e0d73f..b290bbb5 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py @@ -1,44 +1,8 @@ -from six import text_type +from __future__ import absolute_import -from django.forms.fields import ChoiceField +from fobi.base import form_element_plugin_registry -from django.utils.html import format_html -from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _ - -from nine import versions - -from fobi.base import ( - FormFieldPlugin, - form_element_plugin_registry, - get_theme -) -from fobi.helpers import get_select_field_choices -from fobi.widgets import RichSelectInverseQuotes - -from . import UID -from .constants import ( - SLIDER_DEFAULT_TOOLTIP, - SLIDER_DEFAULT_HANDLE, - SLIDER_SHOW_ENDPOINTS_AS_LABELED_TICKS, - SLIDER_SHOW_ENDPOINTS_AS_TICKS, - SLIDER_DEFAULT_SHOW_ENDPOINTS_AS -) -from .forms import SliderInputForm -from .helpers import generate_ticks -from .settings import ( - INITIAL, - INITIAL_MAX_VALUE, - INITIAL_MIN_VALUE, - # MAX_VALUE, - # MIN_VALUE, - STEP -) - -if versions.DJANGO_GTE_1_7: - from django.forms.utils import flatatt -else: - from django.forms.util import flatatt +from .base import SliderInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.slider.' \ 'fobi_form_elements' @@ -47,167 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('SliderInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class SliderInputPlugin(FormFieldPlugin): - """Slider field plugin.""" - - uid = UID - name = _("Slider") - group = _("Fields") - form = SliderInputForm - html_classes = ['slider'] - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - initial = self.data.initial if self.data.initial else INITIAL - max_value = self.data.max_value \ - if self.data.max_value \ - else INITIAL_MAX_VALUE - min_value = self.data.min_value \ - if self.data.min_value \ - else INITIAL_MIN_VALUE - step = self.data.step if self.data.step else STEP - tooltip = self.data.tooltip \ - if self.data.tooltip \ - else SLIDER_DEFAULT_TOOLTIP - handle = self.data.handle \ - if self.data.handle \ - else SLIDER_DEFAULT_HANDLE - - custom_ticks = get_select_field_choices(self.data.custom_ticks, - key_type=int, - value_type=text_type) \ - if self.data.custom_ticks \ - else [] - - _choices = range(min_value, max_value+1, step) - choices = zip(_choices, _choices) - - # slider_html_class = "slider-no-background" \ - # if self.data.disable_slider_background \ - # else "slider" - slider_html_class = "slider" - - widget_attrs = { - 'class': "{0} {1}".format( - slider_html_class, - theme.form_element_html_class - ), - 'data-slider-min': min_value, - 'data-slider-max': max_value, - 'data-slider-step': step, - 'data-slider-value': initial, - 'data-slider-tooltip': tooltip, - 'data-slider-handle': handle, - } - - show_endpoints_as = self.data.show_endpoints_as \ - if self.data.show_endpoints_as \ - else SLIDER_DEFAULT_SHOW_ENDPOINTS_AS - - prepend_html_list = [] - append_html_list = [] - - # Show endpoints as labeled ticks - if SLIDER_SHOW_ENDPOINTS_AS_LABELED_TICKS == show_endpoints_as: - - if custom_ticks: - ticks_data = generate_ticks(custom_ticks) - else: - ticks_data = generate_ticks([ - (min_value, self.data.label_start), - (max_value, self.data.label_end), - ]) - # label_start = self.data.label_start \ - # if self.data.label_start \ - # else text_type(min_value) - # - # label_end = self.data.label_end \ - # if self.data.label_end \ - # else text_type(max_value) - - # widget_attrs.update({ - # 'data-slider-ticks': "[{0}, {1}]".format( - # min_value, max_value - # ), - # 'data-slider-ticks-labels': '["{0!s}", "{1!s}"]'.format( - # label_start.encode('utf8'), label_end.encode('utf8') - # ), - # }) - - widget_attrs.update(ticks_data) - - # Show endpoints as ticks - elif SLIDER_SHOW_ENDPOINTS_AS_TICKS == show_endpoints_as: - - if custom_ticks: - ticks_data = generate_ticks(custom_ticks, empty_labels=True) - else: - ticks_data = generate_ticks([ - (min_value, ""), - (max_value, ""), - ]) - - # widget_attrs.update({ - # 'data-slider-ticks': "[{0}, {1}]".format( - # min_value, max_value - # ), - # 'data-slider-ticks-labels': '["{0}", "{1}"]'.format( - # "", "" - # ), - # }) - - widget_attrs.update(ticks_data) - - # Show endpoints as labels - else: - - if self.data.label_start: - prepend_html_list.append( - format_html( - " ", - flatatt({'class': "slider-endpoint-label-start"}) - ) - ) - prepend_html_list.append(format_html(self.data.label_start)) - prepend_html_list.append(format_html(" ")) - - if self.data.label_end: - append_html_list.append( - format_html( - " ", - flatatt({'class': "slider-endpoint-label-end"}) - ) - ) - append_html_list.append(format_html(self.data.label_end)) - append_html_list.append(format_html(" ")) - - widget_kwargs = {'attrs': widget_attrs} - - # For showing endpoints as labels - if prepend_html_list: - widget_kwargs.update({ - 'prepend_html': mark_safe(''.join(prepend_html_list)), - }) - - if append_html_list: - widget_kwargs.update({ - 'append_html': mark_safe(''.join(append_html_list)), - }) - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': initial, - 'required': self.data.required, - 'choices': choices, - 'widget': RichSelectInverseQuotes(**widget_kwargs), - } - - return [(self.data.name, ChoiceField, field_kwargs)] - form_element_plugin_registry.register(SliderInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/slug/base.py b/src/fobi/contrib/plugins/form_elements/fields/slug/base.py new file mode 100644 index 00000000..b65bd0fc --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/slug/base.py @@ -0,0 +1,47 @@ +from __future__ import absolute_import + +from django.forms.fields import SlugField +from django.forms.widgets import TextInput +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import SlugInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.slug.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('SlugInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class SlugInputPlugin(FormFieldPlugin): + """Slug field plugin.""" + + uid = UID + name = _("Slug") + group = _("Fields") + form = SlugInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'placeholder': self.data.placeholder, + } + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'widget': TextInput(attrs=widget_attrs), + } + if self.data.max_length: + field_kwargs['max_length'] = self.data.max_length + + return [(self.data.name, SlugField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/slug/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/slug/fobi_form_elements.py index 26ac9610..f3dcadfc 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slug/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slug/fobi_form_elements.py @@ -1,11 +1,8 @@ -from django.forms.fields import SlugField -from django.forms.widgets import TextInput -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import SlugInputForm +from .base import SlugInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.slug.fobi_form_elements' __author__ = 'Artur Barseghyan ' @@ -13,36 +10,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('SlugInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class SlugInputPlugin(FormFieldPlugin): - """Slug field plugin.""" - - uid = UID - name = _("Slug") - group = _("Fields") - form = SlugInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'placeholder': self.data.placeholder, - } - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'widget': TextInput(attrs=widget_attrs), - } - if self.data.max_length: - field_kwargs['max_length'] = self.data.max_length - - return [(self.data.name, SlugField, field_kwargs)] - form_element_plugin_registry.register(SlugInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/text/base.py b/src/fobi/contrib/plugins/form_elements/fields/text/base.py new file mode 100644 index 00000000..3e89f02b --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/text/base.py @@ -0,0 +1,47 @@ +from __future__ import absolute_import + +from django.forms.fields import CharField +from django.forms.widgets import TextInput +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import TextInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.text.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('TextInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class TextInputPlugin(FormFieldPlugin): + """Text field plugin.""" + + uid = UID + name = _("Text") + group = _("Fields") + form = TextInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'placeholder': self.data.placeholder, + } + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'widget': TextInput(attrs=widget_attrs), + } + if self.data.max_length: + field_kwargs['max_length'] = self.data.max_length + + return [(self.data.name, CharField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/text/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/text/fobi_form_elements.py index 9ab469f3..4e07e2e5 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/text/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/text/fobi_form_elements.py @@ -1,11 +1,8 @@ -from django.forms.fields import CharField -from django.forms.widgets import TextInput -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import TextInputForm +from .base import TextInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.text.fobi_form_elements' __author__ = 'Artur Barseghyan ' @@ -13,36 +10,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('TextInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class TextInputPlugin(FormFieldPlugin): - """Text field plugin.""" - - uid = UID - name = _("Text") - group = _("Fields") - form = TextInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'placeholder': self.data.placeholder, - } - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'widget': TextInput(attrs=widget_attrs), - } - if self.data.max_length: - field_kwargs['max_length'] = self.data.max_length - - return [(self.data.name, CharField, field_kwargs)] - form_element_plugin_registry.register(TextInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/text/forms.py b/src/fobi/contrib/plugins/form_elements/fields/text/forms.py index a0f23483..8d53d0c7 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/text/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/text/forms.py @@ -80,6 +80,7 @@ class TextInputForm(forms.Form, BaseFormFieldPluginForm): ) def clean(self): + """Validation.""" super(TextInputForm, self).clean() max_length = self.cleaned_data.get('max_length', DEFAULT_MAX_LENGTH) @@ -91,4 +92,4 @@ class TextInputForm(forms.Form, BaseFormFieldPluginForm): 'initial', _("Ensure this value has at most {0} characters " "(it has {1}).".format(max_length, len_initial)) - ) \ No newline at end of file + ) diff --git a/src/fobi/contrib/plugins/form_elements/fields/textarea/base.py b/src/fobi/contrib/plugins/form_elements/fields/textarea/base.py new file mode 100644 index 00000000..9f2a1e3a --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/textarea/base.py @@ -0,0 +1,44 @@ +from __future__ import absolute_import + +from django.forms.fields import CharField +from django.forms.widgets import Textarea +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import TextareaForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.textarea.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('TextInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class TextareaPlugin(FormFieldPlugin): + """Textarea field plugin.""" + + uid = UID + name = _("Textarea") + group = _("Fields") + form = TextareaForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'placeholder': self.data.placeholder, + } + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'widget': Textarea(attrs=widget_attrs) + } + + return [(self.data.name, CharField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/textarea/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/textarea/fobi_form_elements.py index 3f99ecc5..219159dd 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/textarea/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/textarea/fobi_form_elements.py @@ -1,11 +1,8 @@ -from django.forms.fields import CharField -from django.forms.widgets import Textarea -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme +from fobi.base import form_element_plugin_registry -from . import UID -from .forms import TextareaForm +from .base import TextareaPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'textarea.fobi_form_elements' @@ -14,33 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('TextInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class TextareaPlugin(FormFieldPlugin): - """Textarea field plugin.""" - - uid = UID - name = _("Textarea") - group = _("Fields") - form = TextareaForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'placeholder': self.data.placeholder, - } - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'widget': Textarea(attrs=widget_attrs) - } - - return [(self.data.name, CharField, field_kwargs)] - form_element_plugin_registry.register(TextareaPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/time/base.py b/src/fobi/contrib/plugins/form_elements/fields/time/base.py new file mode 100644 index 00000000..2ef918e3 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/time/base.py @@ -0,0 +1,72 @@ +from __future__ import absolute_import + +from django.forms.fields import TimeField +from django.forms.widgets import TextInput +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import TimeInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.time.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('TimeInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class TimeInputPlugin(FormFieldPlugin): + """Time field plugin.""" + + uid = UID + name = _("Time") + group = _("Fields") + form = TimeInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'type': 'time', + } + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + # 'input_formats': self.data.input_formats, + 'required': self.data.required, + 'widget': TextInput(attrs=widget_attrs), + } + # if self.data.input_formats: + # kwargs['input_formats'] = self.data.input_formats + + return [(self.data.name, TimeField, field_kwargs)] + + def submit_plugin_form_data(self, form_entry, request, form, + form_element_entries=None, **kwargs): + """Submit plugin form data/process. + + :param fobi.models.FormEntry form_entry: Instance of + ``fobi.models.FormEntry``. + :param django.http.HttpRequest request: + :param django.forms.Form form: + """ + # In case if we should submit value as is, we don't return anything. + # In other cases, we proceed further. + + # Get the object + value = form.cleaned_data.get(self.data.name, None) + try: + value = value.strftime("%H:%M:%S") + except Exception as err: + pass + + # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. + form.cleaned_data[self.data.name] = value + + return form diff --git a/src/fobi/contrib/plugins/form_elements/fields/time/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/time/fobi_form_elements.py index cfe280ac..b38ca229 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/time/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/time/fobi_form_elements.py @@ -1,13 +1,8 @@ from __future__ import absolute_import -from django.forms.fields import TimeField -from django.forms.widgets import TextInput -from django.utils.translation import ugettext_lazy as _ +from fobi.base import form_element_plugin_registry -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme - -from . import UID -from .forms import TimeInputForm +from .base import TimeInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.' \ 'time.fobi_form_elements' @@ -16,60 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('TimeInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class TimeInputPlugin(FormFieldPlugin): - """Time field plugin.""" - - uid = UID - name = _("Time") - group = _("Fields") - form = TimeInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'type': 'time', - } - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - # 'input_formats': self.data.input_formats, - 'required': self.data.required, - 'widget': TextInput(attrs=widget_attrs), - } - # if self.data.input_formats: - # kwargs['input_formats'] = self.data.input_formats - - return [(self.data.name, TimeField, field_kwargs)] - - def submit_plugin_form_data(self, form_entry, request, form): - """Submit plugin form data/process. - - :param fobi.models.FormEntry form_entry: Instance of - ``fobi.models.FormEntry``. - :param django.http.HttpRequest request: - :param django.forms.Form form: - """ - # In case if we should submit value as is, we don't return anything. - # In other cases, we proceed further. - - # Get the object - value = form.cleaned_data.get(self.data.name, None) - try: - value = value.strftime("%H:%M:%S") - except Exception as err: - pass - - # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. - form.cleaned_data[self.data.name] = value - - return form - form_element_plugin_registry.register(TimeInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/fields/url/base.py b/src/fobi/contrib/plugins/form_elements/fields/url/base.py new file mode 100644 index 00000000..4494fb06 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/url/base.py @@ -0,0 +1,58 @@ +from __future__ import absolute_import + +from django.forms.fields import URLField + +try: + from django.forms.widgets import URLInput +except ImportError: + from django.forms.widgets import TextInput + + class URLInput(TextInput): + """URL input.""" + + input_type = 'url' + +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormFieldPlugin, get_theme + +from . import UID +from .forms import URLInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.fields.url.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('URLInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class URLInputPlugin(FormFieldPlugin): + """URL input plugin.""" + + uid = UID + name = _("URL") + group = _("Fields") + form = URLInputForm + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + widget_attrs = { + 'class': theme.form_element_html_class, + 'type': 'url', + 'placeholder': self.data.placeholder, + } + + field_kwargs = { + 'label': self.data.label, + 'help_text': self.data.help_text, + 'initial': self.data.initial, + 'required': self.data.required, + 'widget': URLInput(attrs=widget_attrs), + } + if self.data.max_length: + field_kwargs['max_length'] = self.data.max_length + + return [(self.data.name, URLField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/url/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/url/fobi_form_elements.py index 88b7608e..eee5cd3b 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/url/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/url/fobi_form_elements.py @@ -1,21 +1,8 @@ -from django.forms.fields import URLField +from __future__ import absolute_import -try: - from django.forms.widgets import URLInput -except ImportError: - from django.forms.widgets import TextInput +from fobi.base import form_element_plugin_registry - class URLInput(TextInput): - """URL input.""" - - input_type = 'url' - -from django.utils.translation import ugettext_lazy as _ - -from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme - -from . import UID -from .forms import URLInputForm +from .base import URLInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.fields.url.fobi_form_elements' __author__ = 'Artur Barseghyan ' @@ -23,37 +10,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('URLInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class URLInputPlugin(FormFieldPlugin): - """URL input plugin.""" - - uid = UID - name = _("URL") - group = _("Fields") - form = URLInputForm - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - widget_attrs = { - 'class': theme.form_element_html_class, - 'type': 'url', - 'placeholder': self.data.placeholder, - } - - field_kwargs = { - 'label': self.data.label, - 'help_text': self.data.help_text, - 'initial': self.data.initial, - 'required': self.data.required, - 'widget': URLInput(attrs=widget_attrs), - } - if self.data.max_length: - field_kwargs['max_length'] = self.data.max_length - - return [(self.data.name, URLField, field_kwargs)] - form_element_plugin_registry.register(URLInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/security/captcha/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/security/captcha/fobi_form_elements.py index 29c71c57..b995851c 100644 --- a/src/fobi/contrib/plugins/form_elements/security/captcha/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/security/captcha/fobi_form_elements.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import logging from django.utils.translation import ugettext_lazy as _ diff --git a/src/fobi/contrib/plugins/form_elements/security/honeypot/base.py b/src/fobi/contrib/plugins/form_elements/security/honeypot/base.py new file mode 100644 index 00000000..ea42dcf2 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/security/honeypot/base.py @@ -0,0 +1,48 @@ +from __future__ import absolute_import + +from django.forms.widgets import HiddenInput +from django.utils.translation import ugettext_lazy as _ + +from fobi.base import FormElementPlugin, get_theme + +from . import UID +from .fields import HoneypotField +from .forms import HoneypotInputForm + +__title__ = 'fobi.contrib.plugins.form_elements.security.honeypot.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('HoneypotInputPlugin',) + +theme = get_theme(request=None, as_instance=True) + + +class HoneypotInputPlugin(FormElementPlugin): + """Honeypot field plugin.""" + + uid = UID + name = _("Honeypot") + group = _("Security") + form = HoneypotInputForm + is_hidden = True + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + + field_kwargs = { + 'label': self.data.label, + 'initial': self.data.initial, + # 'help_text': self.data.help_text, + 'required': self.data.required, + 'widget': HiddenInput( + attrs={'class': theme.form_element_html_class} + ), + } + + if self.data.max_length: + field_kwargs['max_length'] = self.data.max_length + + # return [(self.data.name, (HoneypotField, TextInput), kwargs)] + return [(self.data.name, HoneypotField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/security/honeypot/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/security/honeypot/fobi_form_elements.py index b1e04de8..9f2a6458 100644 --- a/src/fobi/contrib/plugins/form_elements/security/honeypot/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/security/honeypot/fobi_form_elements.py @@ -1,13 +1,8 @@ -from django.forms.widgets import HiddenInput -from django.utils.translation import ugettext_lazy as _ +from __future__ import absolute_import -from fobi.base import ( - FormElementPlugin, form_element_plugin_registry, get_theme -) +from fobi.base import form_element_plugin_registry -from . import UID -from .fields import HoneypotField -from .forms import HoneypotInputForm +from .base import HoneypotInputPlugin __title__ = 'fobi.contrib.plugins.form_elements.security.' \ 'honeypot.fobi_form_elements' @@ -16,37 +11,5 @@ __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('HoneypotInputPlugin',) -theme = get_theme(request=None, as_instance=True) - - -class HoneypotInputPlugin(FormElementPlugin): - """Honeypot field plugin.""" - - uid = UID - name = _("Honeypot") - group = _("Security") - form = HoneypotInputForm - is_hidden = True - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - - field_kwargs = { - 'label': self.data.label, - 'initial': self.data.initial, - # 'help_text': self.data.help_text, - 'required': self.data.required, - 'widget': HiddenInput( - attrs={'class': theme.form_element_html_class} - ), - } - - if self.data.max_length: - field_kwargs['max_length'] = self.data.max_length - - # return [(self.data.name, (HoneypotField, TextInput), kwargs)] - return [(self.data.name, HoneypotField, field_kwargs)] - form_element_plugin_registry.register(HoneypotInputPlugin) diff --git a/src/fobi/contrib/plugins/form_elements/security/recaptcha/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/security/recaptcha/fobi_form_elements.py index 4674f119..01964285 100644 --- a/src/fobi/contrib/plugins/form_elements/security/recaptcha/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/security/recaptcha/fobi_form_elements.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import + import logging from django.utils.translation import ugettext_lazy as _ diff --git a/src/fobi/contrib/plugins/form_elements/test/dummy/base.py b/src/fobi/contrib/plugins/form_elements/test/dummy/base.py new file mode 100644 index 00000000..be4db2f4 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/test/dummy/base.py @@ -0,0 +1,46 @@ +from __future__ import absolute_import + +from uuid import uuid4 + +from django.utils.translation import ugettext, ugettext_lazy as _ + +from nonefield.fields import NoneField + +from fobi.base import FormElementPlugin +from fobi.helpers import safe_text + +from . import UID + +__title__ = 'fobi.contrib.plugins.form_elements.test.dummy.base' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('DummyPlugin',) + + +class DummyPlugin(FormElementPlugin): + """Dummy plugin.""" + + uid = UID + name = _("Dummy") + group = _("Testing") + + def post_processor(self): + """Post process data. + + Always the same. + """ + self.data.name = "{0}_{1}".format(self.uid, uuid4()) + + def get_form_field_instances(self, request=None, form_entry=None, + form_element_entries=None, **kwargs): + """Get form field instances.""" + field_kwargs = { + 'initial': "

    {0}

    ".format( + safe_text(ugettext("Dummy content")) + ), + 'required': False, + 'label': '', + } + + return[(self.data.name, NoneField, field_kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/test/dummy/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/test/dummy/fobi_form_elements.py index e33a3832..7e71a199 100644 --- a/src/fobi/contrib/plugins/form_elements/test/dummy/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/test/dummy/fobi_form_elements.py @@ -1,13 +1,8 @@ -from uuid import uuid4 +from __future__ import absolute_import -from django.utils.translation import ugettext, ugettext_lazy as _ +from fobi.base import form_element_plugin_registry -from nonefield.fields import NoneField - -from fobi.base import FormElementPlugin, form_element_plugin_registry -from fobi.helpers import safe_text - -from . import UID +from .base import DummyPlugin __title__ = 'fobi.contrib.plugins.form_elements.test.dummy.fobi_form_elements' __author__ = 'Artur Barseghyan ' @@ -16,32 +11,4 @@ __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ('DummyPlugin',) -class DummyPlugin(FormElementPlugin): - """Dummy plugin.""" - - uid = UID - name = _("Dummy") - group = _("Testing") - - def post_processor(self): - """Post process data. - - Always the same. - """ - self.data.name = "{0}_{1}".format(self.uid, uuid4()) - - def get_form_field_instances(self, request=None, form_entry=None, - form_element_entries=None, **kwargs): - """Get form field instances.""" - field_kwargs = { - 'initial': "

    {0}

    ".format( - safe_text(ugettext("Dummy content")) - ), - 'required': False, - 'label': '', - } - - return[(self.data.name, NoneField, field_kwargs)] - - form_element_plugin_registry.register(DummyPlugin) diff --git a/src/fobi/helpers.py b/src/fobi/helpers.py index 67a34d7e..06c36afd 100644 --- a/src/fobi/helpers.py +++ b/src/fobi/helpers.py @@ -666,6 +666,7 @@ class StrippedRequest(object): # ***************************************************************************** # ***************************************************************************** + class JSONDataExporter(object): """Exporting the data into JSON.""" diff --git a/src/fobi/models.py b/src/fobi/models.py index 2bc422c9..ff393e28 100644 --- a/src/fobi/models.py +++ b/src/fobi/models.py @@ -257,7 +257,7 @@ class FormWizardEntry(models.Model): user = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_("User")) name = models.CharField(_("Name"), max_length=255) title = models.CharField(_("Title"), max_length=255, null=True, - blank=True, help_text=_("Shown in templates if" + blank=True, help_text=_("Shown in templates if " "available.")) slug = AutoSlugField(populate_from='name', verbose_name=_("Slug"), unique=True) @@ -338,7 +338,7 @@ class FormEntry(models.Model): user = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_("User")) name = models.CharField(_("Name"), max_length=255) title = models.CharField(_("Title"), max_length=255, null=True, - blank=True, help_text=_("Shown in templates if" + blank=True, help_text=_("Shown in templates if " "available.")) slug = AutoSlugField( populate_from='name', verbose_name=_("Slug"), unique=True diff --git a/src/fobi/tests/data.py b/src/fobi/tests/data.py index 029bc025..d026deea 100644 --- a/src/fobi/tests/data.py +++ b/src/fobi/tests/data.py @@ -3,70 +3,72 @@ import datetime from django.utils.text import force_text -# from fobi.contrib.plugins.form_elements.content.content_image.fobi_form_elements \ -# import ContentImagePlugin -# from fobi.contrib.plugins.form_elements.content.content_text.fobi_form_elements \ -# import ContentTextPlugin -# from fobi.contrib.plugins.form_elements.content.content_video.fobi_form_elements \ -# import ContentVideoPlugin +# from fobi.contrib.plugins.form_elements.content \ +# .content_image.fobi_form_elements import ContentImagePlugin +# from fobi.contrib.plugins.form_elements.content \ +# .content_text.fobi_form_elements import ContentTextPlugin +# from fobi.contrib.plugins.form_elements.content \ +# .content_video.fobi_form_elements import ContentVideoPlugin -from fobi.contrib.plugins.form_elements.fields.boolean.fobi_form_elements \ - import BooleanSelectPlugin -# from fobi.contrib.plugins.form_elements.fields.checkbox_select_multiple.fobi_form_elements \ -# import CheckboxSelectMultipleInputPlugin -from fobi.contrib.plugins.form_elements.fields.date.fobi_form_elements \ - import DateInputPlugin -# from fobi.contrib.plugins.form_elements.fields.date_drop_down.fobi_form_elements \ -# import DateDropDownInputPlugin -from fobi.contrib.plugins.form_elements.fields.datetime.fobi_form_elements \ - import DateTimeInputPlugin -from fobi.contrib.plugins.form_elements.fields.decimal.fobi_form_elements \ - import DecimalInputPlugin -from fobi.contrib.plugins.form_elements.fields.email.fobi_form_elements \ - import EmailInputPlugin -# from fobi.contrib.plugins.form_elements.fields.file.fobi_form_elements \ -# import FileInputPlugin -from fobi.contrib.plugins.form_elements.fields.float.fobi_form_elements \ - import FloatInputPlugin -# from fobi.contrib.plugins.form_elements.fields.hidden.fobi_form_elements \ -# import HiddenInputPlugin -# from fobi.contrib.plugins.form_elements.fields.hidden_model_object.fobi_form_elements \ -# import HiddenModelObjectInputPlugin -from fobi.contrib.plugins.form_elements.fields.integer.fobi_form_elements \ - import IntegerInputPlugin -from fobi.contrib.plugins.form_elements.fields.ip_address.fobi_form_elements \ - import IPAddressInputPlugin -from fobi.contrib.plugins.form_elements.fields.null_boolean.fobi_form_elements \ - import NullBooleanSelectPlugin -from fobi.contrib.plugins.form_elements.fields.select.fobi_form_elements \ - import SelectInputPlugin -from fobi.contrib.plugins.form_elements.fields.select_model_object.fobi_form_elements \ - import SelectModelObjectInputPlugin -from fobi.contrib.plugins.form_elements.fields.select_multiple.fobi_form_elements \ - import SelectMultipleInputPlugin -from fobi.contrib.plugins.form_elements.fields.slug.fobi_form_elements \ - import SlugInputPlugin -from fobi.contrib.plugins.form_elements.fields.text.fobi_form_elements \ - import TextInputPlugin -from fobi.contrib.plugins.form_elements.fields.textarea.fobi_form_elements \ - import TextareaPlugin -from fobi.contrib.plugins.form_elements.fields.url.fobi_form_elements \ - import URLInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .boolean.fobi_form_elements import BooleanSelectPlugin +# from fobi.contrib.plugins.form_elements.fields.checkbox_select_multiple \ +# .fobi_form_elements import CheckboxSelectMultipleInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .date.fobi_form_elements import DateInputPlugin +# from fobi.contrib.plugins.form_elements.fields \ +# .date_drop_down.fobi_form_elements import DateDropDownInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .datetime.fobi_form_elements import DateTimeInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .decimal.fobi_form_elements import DecimalInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .email.fobi_form_elements import EmailInputPlugin +# from fobi.contrib.plugins.form_elements.fields \ +# .file.fobi_form_elements import FileInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .float.fobi_form_elements import FloatInputPlugin +# from fobi.contrib.plugins.form_elements.fields \ +# .hidden.fobi_form_elements import HiddenInputPlugin +# from fobi.contrib.plugins.form_elements.fields.hidden_model_object \ +# .fobi_form_elements import HiddenModelObjectInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .integer.fobi_form_elements import IntegerInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .ip_address.fobi_form_elements import IPAddressInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .null_boolean.fobi_form_elements import NullBooleanSelectPlugin +from fobi.contrib.plugins.form_elements.fields \ + .select.fobi_form_elements import SelectInputPlugin +from fobi.contrib.plugins.form_elements.fields.select_model_object \ + .fobi_form_elements import SelectModelObjectInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .select_multiple.fobi_form_elements import SelectMultipleInputPlugin +from fobi.contrib.plugins.form_elements.fields.slug \ + .fobi_form_elements import SlugInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .text.fobi_form_elements import TextInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .textarea.fobi_form_elements import TextareaPlugin +from fobi.contrib.plugins.form_elements.fields \ + .url.fobi_form_elements import URLInputPlugin -from fobi.contrib.plugins.form_handlers.db_store.fobi_form_handlers \ - import DBStoreHandlerPlugin -from fobi.contrib.plugins.form_handlers.mail.fobi_form_handlers \ - import MailHandlerPlugin -from fobi.contrib.plugins.form_handlers.http_repost.fobi_form_handlers \ - import HTTPRepostHandlerPlugin +from fobi.contrib.plugins.form_handlers \ + .db_store.fobi_form_handlers import DBStoreHandlerPlugin +from fobi.contrib.plugins.form_handlers \ + .mail.fobi_form_handlers import MailHandlerPlugin +from fobi.contrib.plugins.form_handlers \ + .http_repost.fobi_form_handlers import HTTPRepostHandlerPlugin __title__ = 'fobi.tests.data' __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ( - 'TEST_FORM_ELEMENT_PLUGIN_DATA', 'TEST_FORM_FIELD_DATA', + 'TEST_FORM_ELEMENT_PLUGIN_DATA', + 'TEST_FORM_FIELD_DATA', 'TEST_FORM_HANDLER_PLUGIN_DATA', + 'TEST_MAILCHIMP_IMPORTER_FORM_DATA' ) TEST_FORM_ELEMENT_PLUGIN_DATA = { @@ -84,14 +86,14 @@ TEST_FORM_ELEMENT_PLUGIN_DATA = { # 'required': False, # }, - # Add a "Date" input form elelement + # Add a "Date" input form element force_text(DateInputPlugin.name): { 'label': "Test date input", 'help_text': "Lorem ipsum select multiple input", 'required': False, }, - # Add a "DateTime" input form elelement + # Add a "DateTime" input form element force_text(DateTimeInputPlugin.name): { 'label': "Test datetime input", 'help_text': "Lorem ipsum select multiple input", @@ -113,7 +115,7 @@ TEST_FORM_ELEMENT_PLUGIN_DATA = { }, # TODO: Add file test. - # Add a "File" (file) form elelement + # Add a "File" (file) form element # force_text(FileInputPlugin.name): { # 'label': "Test file input", # #'name': "test_file_input", @@ -129,7 +131,7 @@ TEST_FORM_ELEMENT_PLUGIN_DATA = { }, # TODO: Find out why selenium fails here! - # Add a "Hidden" (boolean) form elelement + # Add a "Hidden" (boolean) form element # force_text(HiddenInputPlugin.name): { # 'label': "Test hidden input", # #'name': "test_hidden_input", @@ -137,70 +139,70 @@ TEST_FORM_ELEMENT_PLUGIN_DATA = { # 'required': True, # }, - # Add a "Integer" (text input) form elelement + # Add a "Integer" (text input) form element force_text(IntegerInputPlugin.name): { 'label': "Test integer", 'help_text': "Lorem ipsum text input", 'required': True, }, - # Add a "IP address" (text input) form elelement + # Add a "IP address" (text input) form element force_text(IPAddressInputPlugin.name): { 'label': "Test IP address", 'help_text': "Lorem ipsum text input", 'required': True, }, - # Add a "null boolean" form elelement + # Add a "null boolean" form element force_text(NullBooleanSelectPlugin.name): { 'label': "Test null boolean", 'help_text': "Lorem ipsum text input", 'required': True, }, - # Add a "Select Input" (select input) form elelement + # Add a "Select Input" (select input) form element force_text(SelectInputPlugin.name): { 'label': "Test select", 'help_text': "Lorem ipsum text input", 'required': False, }, - # Add a "Select model object" (select input) form elelement + # Add a "Select model object" (select input) form element force_text(SelectModelObjectInputPlugin.name): { 'label': "Test select model object", 'help_text': "Lorem ipsum select model object input", 'required': False, }, - # Add a "Select multiple" (select multiple input) form elelement + # Add a "Select multiple" (select multiple input) form element force_text(SelectMultipleInputPlugin.name): { 'label': "Test select multiple input", 'help_text': "Lorem ipsum select multiple input", 'required': False, }, - # Add a "Select multiple" (select multiple input) form elelement + # Add a "Select multiple" (select multiple input) form element force_text(SlugInputPlugin.name): { 'label': "Test slug input", 'help_text': "Lorem ipsum select multiple input", 'required': False, }, - # Add a "Text" (text input) form elelement + # Add a "Text" (text input) form element force_text(TextInputPlugin.name): { 'label': "Test text", 'help_text': "Lorem ipsum text input", 'required': True, }, - # Add a "Textarea" (text area) form elelement + # Add a "Textarea" (text area) form element force_text(TextareaPlugin.name): { 'label': "Test text area", 'help_text': "Lorem ipsum text area", 'required': True, }, - # Add a "URL input" form elelement + # Add a "URL input" form element force_text(URLInputPlugin.name): { 'label': "Test URL input", 'help_text': "Lorem ipsum text area", @@ -246,3 +248,210 @@ TEST_FORM_HANDLER_PLUGIN_DATA = { 'endpoint_url': 'http://dev.example.com' } } + + +TEST_MAILCHIMP_IMPORTER_FORM_DATA = [ + { + u'default': u'', + u'field_type': u'email', + u'helptext': u'', + u'id': 0, + u'name': u'Email Address', + u'order': u'1', + u'public': True, + u'req': True, + u'show': True, + u'size': u'25', + u'tag': u'EMAIL' + }, + { + u'default': u'', + u'field_type': u'text', + u'helptext': u'', + u'id': 1, + u'name': u'First Name', + u'order': u'2', + u'public': True, + u'req': False, + u'show': True, + u'size': u'25', + u'tag': u'FNAME' + }, + { + u'default': u'', + u'field_type': u'text', + u'helptext': u'', + u'id': 2, + u'name': u'Last Name', + u'order': u'3', + u'public': True, + u'req': False, + u'show': True, + u'size': u'25', + u'tag': u'LNAME' + }, + { + u'default': u'', + u'field_type': u'text', + u'helptext': u'', + u'id': 3, + u'name': u'Organisation', + u'order': u'4', + u'public': True, + u'req': False, + u'show': True, + u'size': u'25', + u'tag': u'ORG' + }, + { + u'default': u'Type Text Default Value', + u'field_type': u'text', + u'helptext': u'Type Text Help Text', + u'id': 4, + u'name': u'type_text', + u'order': u'5', + u'public': True, + u'req': True, + u'show': True, + u'size': u'25', + u'tag': u'TYPE_TEXT' + }, + { + u'default': u'1', + u'field_type': u'number', + u'helptext': u'Type Number Help Text', + u'id': 5, + u'name': u'type_number', + u'order': u'6', + u'public': True, + u'req': False, + u'show': True, + u'size': u'25', + u'tag': u'TYPE_NUMBE' + }, + { + u'choices': [u'First Choice', u'Second Choice', u'Third Choice'], + u'default': u'Second Choice', + u'field_type': u'radio', + u'helptext': u'Type Radio Buttons Help Text', + u'id': 6, + u'name': u'type_radio_buttons', + u'order': u'7', + u'public': True, + u'req': True, + u'show': True, + u'size': u'25', + u'tag': u'TYPE_RADIO' + }, + { + u'choices': [u'First Choice', u'Second Choice', u'Third Choice'], + u'default': u'Third Choice', + u'field_type': u'dropdown', + u'helptext': u'Drop Down Help Text', + u'id': 7, + u'name': u'type_drop_down', + u'order': u'9', + u'public': True, + u'req': True, + u'show': True, + u'size': u'25', + u'tag': u'TYPE_DROPD' + }, + { + u'dateformat': u'MM/DD/YYYY', + u'default': u'', + u'field_type': u'date', + u'helptext': u'Type Date Help Text', + u'id': 8, + u'name': u'type_date', + u'order': u'10', + u'public': True, + u'req': True, + u'show': True, + u'size': u'25', + u'tag': u'TYPE_DATE' + }, + { + u'dateformat': u'MM/DD', + u'default': u'', + u'field_type': u'birthday', + u'helptext': u'Type Birthday Help Text', + u'id': 9, + u'name': u'type_birthday', + u'order': u'11', + u'public': True, + u'req': True, + u'show': True, + u'size': u'25', + u'tag': u'TYPE_BIRTH' + }, + { + u'default': u'', + u'defaultcountry': u'109', + u'defaultcountry_cc': u'NL', + u'defaultcountry_name': u'Netherlands', + u'field_type': u'address', + u'helptext': u'Type Address Help Text', + u'id': 10, + u'name': u'type_address', + u'order': u'12', + u'public': True, + u'req': False, + u'show': True, + u'size': u'25', + u'tag': u'TYPE_ADDRE' + }, + { + u'default': u'', + u'field_type': u'zip', + u'helptext': u'Type Zip Code Help Text', + u'id': 11, + u'name': u'type_zip_code', + u'order': u'13', + u'public': True, + u'req': False, + u'show': True, + u'size': u'25', + u'tag': u'TYPE_ZIP_C' + }, + { + u'default': u'', + u'field_type': u'phone', + u'helptext': u'Type Phone Help Text', + u'id': 12, + u'name': u'type_phone', + u'order': u'14', + u'phoneformat': u'none', + u'public': True, + u'req': False, + u'show': True, + u'size': u'25', + u'tag': u'TYPE_PHONE' + }, + { + u'default': u'', + u'field_type': u'url', + u'helptext': u'Type Website Help Text', + u'id': 13, + u'name': u'type_website', + u'order': u'15', + u'public': True, + u'req': True, + u'show': True, + u'size': u'25', + u'tag': u'TYPE_WEBSI' + }, + { + u'default': u'', + u'field_type': u'imageurl', + u'helptext': u'Type Image Help Text', + u'id': 14, + u'name': u'type_image', + u'order': u'16', + u'public': True, + u'req': False, + u'show': True, + u'size': u'25', + u'tag': u'TYPE_IMAGE' + } +] diff --git a/src/fobi/tests/helpers.py b/src/fobi/tests/helpers.py index 63606f31..9dcddb60 100644 --- a/src/fobi/tests/helpers.py +++ b/src/fobi/tests/helpers.py @@ -4,37 +4,37 @@ from django.core.exceptions import ObjectDoesNotExist from django.core.management import call_command from fobi.models import FormEntry, FormElementEntry, FormHandlerEntry -from \ - fobi.contrib.plugins.form_elements.content.content_text.fobi_form_elements \ - import ContentTextPlugin -from \ - fobi.contrib.plugins.form_elements.content.content_image.fobi_form_elements \ - import ContentImagePlugin +from fobi.contrib.plugins.form_elements.content \ + .content_text.fobi_form_elements import ContentTextPlugin +from fobi.contrib.plugins.form_elements.content \ + .content_image.fobi_form_elements import ContentImagePlugin -from fobi.contrib.plugins.form_elements.fields.boolean.fobi_form_elements \ - import BooleanSelectPlugin -from fobi.contrib.plugins.form_elements.fields.email.fobi_form_elements \ - import EmailInputPlugin -from fobi.contrib.plugins.form_elements.fields.hidden.fobi_form_elements \ - import HiddenInputPlugin -from fobi.contrib.plugins.form_elements.fields.integer.fobi_form_elements \ - import IntegerInputPlugin -from fobi.contrib.plugins.form_elements.fields.text.fobi_form_elements \ - import TextInputPlugin -from fobi.contrib.plugins.form_elements.fields.textarea.fobi_form_elements \ - import TextareaPlugin +from fobi.contrib.plugins.form_elements.fields \ + .boolean.fobi_form_elements import BooleanSelectPlugin +from fobi.contrib.plugins.form_elements.fields \ + .email.fobi_form_elements import EmailInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .hidden.fobi_form_elements import HiddenInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .integer.fobi_form_elements import IntegerInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .text.fobi_form_elements import TextInputPlugin +from fobi.contrib.plugins.form_elements.fields \ + .textarea.fobi_form_elements import TextareaPlugin -from fobi.contrib.plugins.form_handlers.db_store.fobi_form_handlers \ - import DBStoreHandlerPlugin -from fobi.contrib.plugins.form_handlers.mail.fobi_form_handlers \ - import MailHandlerPlugin +from fobi.contrib.plugins.form_handlers \ + .db_store.fobi_form_handlers import DBStoreHandlerPlugin +from fobi.contrib.plugins.form_handlers \ + .mail.fobi_form_handlers import MailHandlerPlugin -from fobi.tests.base import ( +from .base import ( is_fobi_setup_completed, mark_fobi_setup_as_completed ) -from fobi.tests.constants import ( - FOBI_TEST_USER_USERNAME, FOBI_TEST_USER_PASSWORD, - TEST_FORM_NAME, TEST_FORM_SLUG +from .constants import ( + FOBI_TEST_USER_USERNAME, + FOBI_TEST_USER_PASSWORD, + TEST_FORM_NAME, + TEST_FORM_SLUG ) __title__ = 'fobi.tests.helpers' @@ -42,8 +42,10 @@ __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' __all__ = ( - 'get_or_create_admin_user', 'get_or_create_admin_user', - 'create_form_with_entries', 'db_clean_up', + 'get_or_create_admin_user', + 'get_or_create_admin_user', + 'create_form_with_entries', + 'db_clean_up', ) # **************************************************************************** @@ -126,9 +128,9 @@ def create_form_with_entries(user=None, create_entries_if_form_exist=True): ) form_entry.save() - # ************************************************************************* - # ******************************** Form elements ************************** - # ************************************************************************* + # ************************************************************************ + # ******************************** Form elements ************************* + # ************************************************************************ position = 1 # Text input form_element_entry = FormElementEntry( @@ -225,8 +227,8 @@ def create_form_with_entries(user=None, create_entries_if_form_exist=True): '{"text": "Suspendisse potenti. Etiam in nunc sodales, ' 'congue lectus ut, suscipit massa. In commodo fringilla ' 'orci, in varius eros gravida a! Aliquam erat volutpat. ' - 'Donec sodales orci nec massa aliquam bibendum. Aenean sed ' - 'condimentum velit. Mauris luctus bibendum nulla vel ' + 'Donec sodales orci nec massa aliquam bibendum. Aenean ' + 'sed condimentum velit. Mauris luctus bibendum nulla vel ' 'tempus. Integer tempor condimentum ligula sed feugiat. ' 'Aenean scelerisque ultricies vulputate. Donec semper ' 'lorem rhoncus sem cras amet."}', @@ -235,9 +237,9 @@ def create_form_with_entries(user=None, create_entries_if_form_exist=True): form_element_entry.save() position += 1 - # ************************************************************************* - # ******************************** Form handlers ************************** - # ************************************************************************* + # ************************************************************************ + # ******************************** Form handlers ************************* + # ************************************************************************ # DB save form_handler_entry = FormHandlerEntry( diff --git a/src/fobi/tests/test_browser_build_dynamic_forms.py b/src/fobi/tests/test_browser_build_dynamic_forms.py index a9d85371..ba85dfa3 100644 --- a/src/fobi/tests/test_browser_build_dynamic_forms.py +++ b/src/fobi/tests/test_browser_build_dynamic_forms.py @@ -17,15 +17,19 @@ from django.conf import settings from fobi.models import FormEntry -from fobi.tests.base import print_info, skip # , BaseBrowserTest -from fobi.tests.helpers import ( - setup_fobi, get_or_create_admin_user, db_clean_up -) -from fobi.tests import constants -from fobi.tests.data import ( - TEST_FORM_ELEMENT_PLUGIN_DATA, TEST_FORM_FIELD_DATA, +from . import constants +from .base import print_info, skip +from .data import ( + TEST_FORM_ELEMENT_PLUGIN_DATA, + TEST_FORM_FIELD_DATA, TEST_FORM_HANDLER_PLUGIN_DATA ) +from .helpers import ( + setup_fobi, + get_or_create_admin_user, + db_clean_up +) + __title__ = 'fobi.tests.test_browser_build_dynamic_forms' __author__ = 'Artur Barseghyan ' @@ -239,7 +243,8 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): self.selenium.find_element_by_xpath('//button[@type="submit"]').click() logger.debug( - """//div[contains(text(), 'Form {0} was created successfully.') and contains(@class, "alert-info")]""".format( + """//div[contains(text(), 'Form {0} was created """ + """successfully.') and contains(@class, "alert-info")]""".format( constants.TEST_FORM_NAME ) ) @@ -247,7 +252,9 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Wait until the fobi page opens with the form element in WebDriverWait(self.selenium, timeout=TIMEOUT).until( lambda driver: driver.find_element_by_xpath( - """//div[contains(text(), 'Form {0} was created successfully.') and contains(@class, "alert-info")]""".format( + """//div[contains(text(), 'Form {0} was created """ + """successfully.') """ + """and contains(@class, "alert-info")]""".format( constants.TEST_FORM_NAME ) ) @@ -272,7 +279,8 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Click the add form element button to add a new form element to the # form. add_form_element_link = self.selenium.find_element_by_xpath( - """//a[contains(text(), 'Choose form element to add') and contains(@class, "dropdown-toggle")]""" + """//a[contains(text(), 'Choose form element to add') and """ + """contains(@class, "dropdown-toggle")]""" ) self._scroll_to(0, 0) @@ -290,7 +298,8 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Click on the element we want form_element_to_add = \ - add_form_element_available_elements_container.find_element_by_xpath( + add_form_element_available_elements_container \ + .find_element_by_xpath( '//a[text()="{0}"]'.format(form_element_name) ) @@ -303,7 +312,8 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Wait until the add widget view opens WebDriverWait(self.selenium, timeout=TIMEOUT).until( lambda driver: driver.find_element_by_xpath( - """//h1[contains(text(), 'Add "{0}" element to the form')]""".format( + """//h1[contains(text(), 'Add "{0}" element to """ + """the form')]""".format( form_element_name ) ) @@ -323,7 +333,9 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Wait until the fobi page opens with the form element in. WebDriverWait(self.selenium, timeout=TIMEOUT).until( lambda driver: driver.find_element_by_xpath( - """//div[contains(text(), 'The form element plugin "{0}" was added successfully.') and contains(@class, "alert-info")]""".format( + """//div[contains(text(), 'The form element plugin "{0}" """ + """was added successfully.') """ + """and contains(@class, "alert-info")]""".format( form_element_name ) ) @@ -364,7 +376,8 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Get the label of the given form element in order to delete it later # from the form. delete_form_element_label = self.selenium.find_element_by_xpath( - """//label[contains(text(), '({0})') and contains(@class, "control-label")]""".format( + """//label[contains(text(), '({0})') """ + """and contains(@class, "control-label")]""".format( form_element_name ) ) @@ -376,7 +389,8 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Click the add form element button to add a new form element to the # form. delete_form_element_link = \ - delete_form_element_label_parent_container.find_element_by_partial_link_text( + delete_form_element_label_parent_container \ + .find_element_by_partial_link_text( 'Delete' ) delete_form_element_link.click() @@ -387,7 +401,9 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Wait until the fobi page opens with the form element in. WebDriverWait(self.selenium, timeout=LONG_TIMEOUT).until( lambda driver: driver.find_element_by_xpath( - """//div[contains(text(), 'The form element plugin "{0}" was deleted successfully.') and contains(@class, "alert-info")]""".format( + """//div[contains(text(), 'The form element plugin "{0}" """ + """was deleted successfully.') """ + """and contains(@class, "alert-info")]""".format( form_element_name ) ) @@ -424,7 +440,8 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Click the add form element button to add a new form element to the # form. add_form_handler_link = self.selenium.find_element_by_xpath( - """//a[contains(text(), 'Choose form handler to add') and contains(@class, "dropdown-toggle")]""" + """//a[contains(text(), 'Choose form handler to add') """ + """and contains(@class, "dropdown-toggle")]""" ) add_form_handler_link.click() @@ -440,7 +457,8 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Click on the element we want form_handler_to_add = \ - add_form_handler_available_elements_container.find_element_by_xpath( + add_form_handler_available_elements_container \ + .find_element_by_xpath( '//a[text()="{0}"]'.format(form_handler_name) ) form_handler_to_add.click() @@ -450,7 +468,8 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Wait until the add widget view opens WebDriverWait(self.selenium, timeout=TIMEOUT).until( lambda driver: driver.find_element_by_xpath( - """//h1[contains(text(), 'Add "{0}" handler to the form')]""".format( + """//h1[contains(text(), 'Add "{0}" handler to """ + """the form')]""".format( form_handler_name ) ) @@ -469,7 +488,9 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Wait until the fobi page opens with the form element in. WebDriverWait(self.selenium, timeout=TIMEOUT).until( lambda driver: driver.find_element_by_xpath( - """//div[contains(text(), 'The form handler plugin "{0}" was added successfully.') and contains(@class, "alert-info")]""".format( + """//div[contains(text(), 'The form handler plugin "{0}" """ + """was added successfully.') """ + """and contains(@class, "alert-info")]""".format( form_handler_name ) ) @@ -529,7 +550,8 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Click the add form element button to add a new form element to the # form. delete_form_handler_link = \ - delete_form_handler_label_parent_container.find_element_by_partial_link_text( + delete_form_handler_label_parent_container \ + .find_element_by_partial_link_text( 'Delete' ) delete_form_handler_link.click() @@ -539,7 +561,9 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Wait until the fobi page opens with the form element in. WebDriverWait(self.selenium, timeout=TIMEOUT).until( lambda driver: driver.find_element_by_xpath( - """//div[contains(text(), 'The form handler plugin "{0}" was deleted successfully.') and contains(@class, "alert-info")]""".format( + """//div[contains(text(), 'The form handler plugin "{0}" """ + """was deleted successfully.') """ + """and contains(@class, "alert-info")]""".format( form_handler_name ) ) @@ -652,7 +676,9 @@ class BaseFobiBrowserBuldDynamicFormsTest(LiveServerTestCase): # Wait until the submit success page opens a clear success message. WebDriverWait(self.selenium, timeout=TIMEOUT).until( lambda driver: driver.find_element_by_xpath( - """//div[contains(text(), 'Form {0} was submitted successfully.') and contains(@class, "alert-info")]""".format( + """//div[contains(text(), 'Form {0} was submitted """ + """successfully.') """ + """and contains(@class, "alert-info")]""".format( constants.TEST_FORM_NAME ) ) diff --git a/src/fobi/tests/test_core.py b/src/fobi/tests/test_core.py index 416cdd1b..a0d1fd1c 100644 --- a/src/fobi/tests/test_core.py +++ b/src/fobi/tests/test_core.py @@ -3,14 +3,17 @@ import unittest from django.test import TestCase, RequestFactory from fobi.base import ( - get_registered_form_element_plugins, get_registered_form_handler_plugins, - get_registered_themes, get_registered_form_callbacks + get_registered_form_element_plugins, + get_registered_form_handler_plugins, + get_registered_themes, + get_registered_form_callbacks ) from fobi.models import FormEntry from fobi.forms import FormEntryForm -from fobi.tests.constants import TEST_FORM_NAME, TEST_FORM_SLUG -from fobi.tests.base import print_info -from fobi.tests.helpers import setup_fobi, get_or_create_admin_user + +from .base import print_info +from .constants import TEST_FORM_NAME, TEST_FORM_SLUG +from .helpers import setup_fobi, get_or_create_admin_user __title__ = 'fobi.tests.test_core' __author__ = 'Artur Barseghyan ' diff --git a/src/fobi/tests/test_dynamic_forms.py b/src/fobi/tests/test_dynamic_forms.py index aec68b32..1979177d 100644 --- a/src/fobi/tests/test_dynamic_forms.py +++ b/src/fobi/tests/test_dynamic_forms.py @@ -3,9 +3,12 @@ import unittest from django.test import TestCase from fobi.dynamic import assemble_form_class -from fobi.tests.base import print_info -from fobi.tests.helpers import ( - setup_fobi, get_or_create_admin_user, create_form_with_entries + +from .base import print_info +from .helpers import ( + setup_fobi, + get_or_create_admin_user, + create_form_with_entries ) __title__ = 'fobi.tests.test_dynamic_forms' diff --git a/src/fobi/tests/test_form_importers_mailchimp.py b/src/fobi/tests/test_form_importers_mailchimp.py index b160c544..7dc8c1c4 100644 --- a/src/fobi/tests/test_form_importers_mailchimp.py +++ b/src/fobi/tests/test_form_importers_mailchimp.py @@ -1,227 +1,54 @@ +import unittest + from django.contrib.auth import get_user_model +from django.test import TestCase -from \ - fobi.contrib.plugins.form_importers.mailchimp_importer.fobi_form_importers \ - import MailChimpImporter +from fobi.contrib.plugins.form_importers \ + .mailchimp_importer.fobi_form_importers import MailChimpImporter +from fobi.models import FormEntry, FormElementEntry -test_form_data = [ - { - u'default': u'', - u'field_type': u'email', - u'helptext': u'', - u'id': 0, - u'name': u'Email Address', - u'order': u'1', - u'public': True, - u'req': True, - u'show': True, - u'size': u'25', - u'tag': u'EMAIL' - }, - { - u'default': u'', - u'field_type': u'text', - u'helptext': u'', - u'id': 1, - u'name': u'First Name', - u'order': u'2', - u'public': True, - u'req': False, - u'show': True, - u'size': u'25', - u'tag': u'FNAME' - }, - { - u'default': u'', - u'field_type': u'text', - u'helptext': u'', - u'id': 2, - u'name': u'Last Name', - u'order': u'3', - u'public': True, - u'req': False, - u'show': True, - u'size': u'25', - u'tag': u'LNAME' - }, - { - u'default': u'', - u'field_type': u'text', - u'helptext': u'', - u'id': 3, - u'name': u'Organisation', - u'order': u'4', - u'public': True, - u'req': False, - u'show': True, - u'size': u'25', - u'tag': u'ORG' - }, - { - u'default': u'Type Text Default Value', - u'field_type': u'text', - u'helptext': u'Type Text Help Text', - u'id': 4, - u'name': u'type_text', - u'order': u'5', - u'public': True, - u'req': True, - u'show': True, - u'size': u'25', - u'tag': u'TYPE_TEXT' - }, - { - u'default': u'1', - u'field_type': u'number', - u'helptext': u'Type Number Help Text', - u'id': 5, - u'name': u'type_number', - u'order': u'6', - u'public': True, - u'req': False, - u'show': True, - u'size': u'25', - u'tag': u'TYPE_NUMBE' - }, - { - u'choices': [u'First Choice', u'Second Choice', u'Third Choice'], - u'default': u'Second Choice', - u'field_type': u'radio', - u'helptext': u'Type Radio Buttons Help Text', - u'id': 6, - u'name': u'type_radio_buttons', - u'order': u'7', - u'public': True, - u'req': True, - u'show': True, - u'size': u'25', - u'tag': u'TYPE_RADIO' - }, - { - u'choices': [u'First Choice', u'Second Choice', u'Third Choice'], - u'default': u'Third Choice', - u'field_type': u'dropdown', - u'helptext': u'Drop Down Help Text', - u'id': 7, - u'name': u'type_drop_down', - u'order': u'9', - u'public': True, - u'req': True, - u'show': True, - u'size': u'25', - u'tag': u'TYPE_DROPD' - }, - { - u'dateformat': u'MM/DD/YYYY', - u'default': u'', - u'field_type': u'date', - u'helptext': u'Type Date Help Text', - u'id': 8, - u'name': u'type_date', - u'order': u'10', - u'public': True, - u'req': True, - u'show': True, - u'size': u'25', - u'tag': u'TYPE_DATE' - }, - { - u'dateformat': u'MM/DD', - u'default': u'', - u'field_type': u'birthday', - u'helptext': u'Type Birthday Help Text', - u'id': 9, - u'name': u'type_birthday', - u'order': u'11', - u'public': True, - u'req': True, - u'show': True, - u'size': u'25', - u'tag': u'TYPE_BIRTH' - }, - { - u'default': u'', - u'defaultcountry': u'109', - u'defaultcountry_cc': u'NL', - u'defaultcountry_name': u'Netherlands', - u'field_type': u'address', - u'helptext': u'Type Address Help Text', - u'id': 10, - u'name': u'type_address', - u'order': u'12', - u'public': True, - u'req': False, - u'show': True, - u'size': u'25', - u'tag': u'TYPE_ADDRE' - }, - { - u'default': u'', - u'field_type': u'zip', - u'helptext': u'Type Zip Code Help Text', - u'id': 11, - u'name': u'type_zip_code', - u'order': u'13', - u'public': True, - u'req': False, - u'show': True, - u'size': u'25', - u'tag': u'TYPE_ZIP_C' - }, - { - u'default': u'', - u'field_type': u'phone', - u'helptext': u'Type Phone Help Text', - u'id': 12, - u'name': u'type_phone', - u'order': u'14', - u'phoneformat': u'none', - u'public': True, - u'req': False, - u'show': True, - u'size': u'25', - u'tag': u'TYPE_PHONE' - }, - { - u'default': u'', - u'field_type': u'url', - u'helptext': u'Type Website Help Text', - u'id': 13, - u'name': u'type_website', - u'order': u'15', - u'public': True, - u'req': True, - u'show': True, - u'size': u'25', - u'tag': u'TYPE_WEBSI' - }, - { - u'default': u'', - u'field_type': u'imageurl', - u'helptext': u'Type Image Help Text', - u'id': 14, - u'name': u'type_image', - u'order': u'16', - u'public': True, - u'req': False, - u'show': True, - u'size': u'25', - u'tag': u'TYPE_IMAGE' - } -] +from .base import print_info +from .data import TEST_MAILCHIMP_IMPORTER_FORM_DATA +from .helpers import setup_fobi, get_or_create_admin_user + +__title__ = 'fobi.tests.test_form_importers_mailchimp' +__author__ = 'Artur Barseghyan ' +__copyright__ = '2014-2016 Artur Barseghyan' +__license__ = 'GPL 2.0/LGPL 2.1' +__all__ = ('FormImpotersMailchimpTest',) -def do(): - """Do test. +class FormImpotersMailchimpTest(TestCase): + """Tests of form importers mailchimp functionality.""" - TODO: Make a normal test out of this. - """ - User = get_user_model() - kwargs = {User.USERNAME_FIELD: 'test_user'} - user = User.objects.get(**kwargs) + def setUp(self): + """Set up.""" + setup_fobi(fobi_sync_plugins=True) - form_properties = {'name': 'Test mailchimp form', 'user': user} + @print_info + def test_01_test_mailchimp_impoter(self): + """Test mailchimp impoter.""" + user = get_or_create_admin_user() - importer = MailChimpFormImporter() + form_properties = { + 'name': 'Test mailchimp form', + 'user': user + } - importer.import_data(form_properties, test_form_data) + importer = MailChimpImporter( + form_entry_cls=FormEntry, + form_element_entry_cls=FormElementEntry + ) + + importer.import_data( + form_properties=form_properties, + form_data=TEST_MAILCHIMP_IMPORTER_FORM_DATA + ) + + form_entry = FormEntry.objects.get(**form_properties) + + self.assertIsNotNone(form_entry.pk) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/fobi/tests/test_sortable_dict.py b/src/fobi/tests/test_sortable_dict.py index 366b65da..8ed7b014 100644 --- a/src/fobi/tests/test_sortable_dict.py +++ b/src/fobi/tests/test_sortable_dict.py @@ -6,7 +6,7 @@ from django.test import TestCase from fobi.data_structures import SortableDict -from fobi.tests.base import print_info +from .base import print_info __title__ = 'fobi.tests.test_dynamic_forms' __author__ = 'Artur Barseghyan ' diff --git a/src/fobi/validators.py b/src/fobi/validators.py index e5b1e315..0d5b55dd 100644 --- a/src/fobi/validators.py +++ b/src/fobi/validators.py @@ -1,7 +1,11 @@ import requests from requests.exceptions import ( - ConnectionError, ConnectTimeout, ReadTimeout, SSLError, ProxyError, + ConnectionError, + ConnectTimeout, + ReadTimeout, + SSLError, + ProxyError, RetryError ) diff --git a/src/fobi/views.py b/src/fobi/views.py index f91a6694..f4fe0623 100644 --- a/src/fobi/views.py +++ b/src/fobi/views.py @@ -1445,6 +1445,7 @@ class FormWizardView(DynamicSessionWizardView): ] form_list = [] form_entry_mapping = {} + form_element_entry_mapping = {} wizard_form_element_entries = [] for creation_counter, form_entry in enumerate(form_entries): # Using frozen queryset to minimize query usage @@ -1463,6 +1464,7 @@ class FormWizardView(DynamicSessionWizardView): (form_entry.slug, form_cls) ) form_entry_mapping[form_entry.slug] = form_entry + form_element_entry_mapping[form_entry.slug] = form_element_entries if 0 == len(form_list): raise Http404( @@ -1478,6 +1480,7 @@ class FormWizardView(DynamicSessionWizardView): 'form_wizard_entry': form_wizard_entry, 'wizard_form_element_entries': wizard_form_element_entries, 'form_entry_mapping': form_entry_mapping, + 'form_element_entry_mapping': form_element_entry_mapping, 'fobi_theme': theme, } @@ -1518,12 +1521,16 @@ class FormWizardView(DynamicSessionWizardView): if form.is_valid(): # Get current form entry form_entry = self.form_entry_mapping[self.steps.current] + # Get form elements for the current form entry + form_element_entries = \ + self.form_element_entry_mapping[self.steps.current] # Fire plugin processors form = submit_plugin_form_data( form_entry=form_entry, request=self.request, form=form, - # **{'': ''} # TODO + form_element_entries=form_element_entries, + **{'form_wizard_entry': self.form_wizard_entry} ) # Form wizards make use of form.data instead of form.cleaned_data. # Therefore, we update the form.data with values from @@ -1590,12 +1597,18 @@ class FormWizardView(DynamicSessionWizardView): **kwargs) # Fire plugin processors + # Get current form entry form_entry = self.form_entry_mapping[form_key] + # Get form elements for the current form entry + form_element_entries = \ + self.form_element_entry_mapping[self.steps.current] + form_obj = submit_plugin_form_data( form_entry=form_entry, request=self.request, form=form_obj, - # **{'': ''} # TODO + form_element_entries=form_element_entries, + **{'form_wizard_entry': self.form_wizard_entry} ) final_forms[form_key] = form_obj From 14890a68ddae50305d355c89743b53d7ef7ef4fd Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 17 Nov 2016 00:19:01 +0100 Subject: [PATCH 37/39] readme fix --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 77fe5550..6c1092aa 100644 --- a/README.rst +++ b/README.rst @@ -431,7 +431,7 @@ following arguments: the ``cleaned_data`` attribute). - `form_element_entries` (fobi.models.FormElementEntry): Form element entries for the `form_entry` given. -- **kwargs: Additional arguments. +- (**)kwargs : Additional arguments. Example (taken from fobi.contrib.plugins.form_elements.fields.file): From 55f4c37e1cd499475b47635656dc52827953ef24 Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 17 Nov 2016 01:28:14 +0100 Subject: [PATCH 38/39] prepare 0.10.1; fix captcha issues with form wizards --- CHANGELOG.rst | 6 +++++ .../bootstrap3-theme-django-1-9-captcha.sh | 1 + .../bootstrap3_theme_django_1_9_captcha.py | 13 ++++++++++ setup.py | 2 +- src/fobi/__init__.py | 4 +-- .../form_elements/security/captcha/README.rst | 8 ++++++ src/fobi/views.py | 26 ++++++++++++++++--- 7 files changed, 54 insertions(+), 6 deletions(-) create mode 100755 examples/simple/runserver/bootstrap3-theme-django-1-9-captcha.sh create mode 100755 examples/simple/settings/bootstrap3_theme_django_1_9_captcha.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e5b875c4..53fcdd2c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,12 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.10.1 +------ +2016-11-17 + +- Fixed captcha and re-captcha issues in form wizards. + 0.10 ---- 2016-11-16 diff --git a/examples/simple/runserver/bootstrap3-theme-django-1-9-captcha.sh b/examples/simple/runserver/bootstrap3-theme-django-1-9-captcha.sh new file mode 100755 index 00000000..83f80bcb --- /dev/null +++ b/examples/simple/runserver/bootstrap3-theme-django-1-9-captcha.sh @@ -0,0 +1 @@ +./manage.py runserver 0.0.0.0:8000 --traceback -v 3 --settings=settings.bootstrap3_theme_django_1_9_captcha --traceback -v 3 diff --git a/examples/simple/settings/bootstrap3_theme_django_1_9_captcha.py b/examples/simple/settings/bootstrap3_theme_django_1_9_captcha.py new file mode 100755 index 00000000..27bb5ed2 --- /dev/null +++ b/examples/simple/settings/bootstrap3_theme_django_1_9_captcha.py @@ -0,0 +1,13 @@ +from .base import * + +INSTALLED_APPS = list(INSTALLED_APPS) + +try: + INSTALLED_APPS.remove('south') if 'south' in INSTALLED_APPS else None + INSTALLED_APPS.remove('tinymce') if 'tinymce' in INSTALLED_APPS else None + INSTALLED_APPS.append('captcha') + INSTALLED_APPS.append( + 'fobi.contrib.plugins.form_elements.security.captcha' + ) +except Exception as err: + pass diff --git a/setup.py b/setup.py index 4c9aef20..4130a5e0 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ import sys from distutils.version import LooseVersion from setuptools import setup, find_packages -version = '0.10' +version = '0.10.1' # *************************************************************************** # ************************** Django version ********************************* diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index 08f09df0..0097cc8f 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.10' -__build__ = 0x000073 +__version__ = '0.10.1' +__build__ = 0x000074 __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/contrib/plugins/form_elements/security/captcha/README.rst b/src/fobi/contrib/plugins/form_elements/security/captcha/README.rst index 425d30da..f3443236 100644 --- a/src/fobi/contrib/plugins/form_elements/security/captcha/README.rst +++ b/src/fobi/contrib/plugins/form_elements/security/captcha/README.rst @@ -5,6 +5,14 @@ A `CAPTCHA `_ form field plugin. Makes use of the `django-simple-captcha `_. +Prerequisites +============= +You will need `libfreetype6`, otherwise `django-captcha` won't work. + +.. code-block:: sh + + sudo apt-get install libfreetype6-dev + Installation ============ Install `django-simple-captcha` diff --git a/src/fobi/views.py b/src/fobi/views.py index f4fe0623..41a9bfb1 100644 --- a/src/fobi/views.py +++ b/src/fobi/views.py @@ -1573,6 +1573,18 @@ class FormWizardView(DynamicSessionWizardView): return self.render_next_step(form) return self.render(form) + def get_ignorable_field_names(self, form_element_entries): + """Get ignorable field names.""" + ignorable_field_names = [] + for form_element_entry in form_element_entries: + plugin = form_element_entry.get_plugin() + # If plugin doesn't have a value, we don't need to have it + # on the last step (otherwise validation issues may arise, as + # it happens with captcha/re-captcha). + if not plugin.has_value: + ignorable_field_names.append(plugin.data.name) + return ignorable_field_names + def render_done(self, form, **kwargs): """Render done. @@ -1591,6 +1603,17 @@ class FormWizardView(DynamicSessionWizardView): files=self.storage.get_step_files(form_key) ) + # Get form elements for the current form entry + form_element_entries = \ + self.form_element_entry_mapping[form_key] + + ignorable_field_names = self.get_ignorable_field_names( + form_element_entries + ) + + for ignorable_field_name in ignorable_field_names: + form_obj.fields.pop(ignorable_field_name) + if not form_obj.is_valid(): return self.render_revalidation_failure(form_key, form_obj, @@ -1599,9 +1622,6 @@ class FormWizardView(DynamicSessionWizardView): # Fire plugin processors # Get current form entry form_entry = self.form_entry_mapping[form_key] - # Get form elements for the current form entry - form_element_entries = \ - self.form_element_entry_mapping[self.steps.current] form_obj = submit_plugin_form_data( form_entry=form_entry, From 1a31819278f6af88dde32dbc8ed1e85bfdcc1e6b Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Thu, 17 Nov 2016 01:44:12 +0100 Subject: [PATCH 39/39] updated docs --- README.rst | 10 ---------- docs/index.rst | 12 +----------- scripts/prepare_docs.sh | 2 ++ .../form_elements/security/captcha/README.rst | 6 ------ .../form_elements/security/recaptcha/README.rst | 6 ------ 5 files changed, 3 insertions(+), 33 deletions(-) create mode 100755 scripts/prepare_docs.sh diff --git a/README.rst b/README.rst index 6c1092aa..5355547b 100644 --- a/README.rst +++ b/README.rst @@ -1503,16 +1503,6 @@ README.rst file in directory of each plugin for details. `__: Send the form data by email. -Limitations ------------ -- At the moment, if you have used `django-simple-captcha` or - `django-recaptcha` plugins in one of the forms of the wizard, the wizard - becomes invalid at the end and sends you back to the form which used - captcha (see the issue `here - `__ and `here - `__). Therefore, - you're not recommended to use captcha solutions in wizard forms (yet). - Permissions =========== Plugin system allows administrators to specify the access rights to every diff --git a/docs/index.rst b/docs/index.rst index f8c82521..724a1dbb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -431,7 +431,7 @@ following arguments: the ``cleaned_data`` attribute). - `form_element_entries` (fobi.models.FormElementEntry): Form element entries for the `form_entry` given. -- **kwargs: Additional arguments. +- (**)kwargs : Additional arguments. Example (taken from fobi.contrib.plugins.form_elements.fields.file): @@ -1503,16 +1503,6 @@ README.rst file in directory of each plugin for details. `__: Send the form data by email. -Limitations ------------ -- At the moment, if you have used `django-simple-captcha` or - `django-recaptcha` plugins in one of the forms of the wizard, the wizard - becomes invalid at the end and sends you back to the form which used - captcha (see the issue `here - `__ and `here - `__). Therefore, - you're not recommended to use captcha solutions in wizard forms (yet). - Permissions =========== Plugin system allows administrators to specify the access rights to every diff --git a/scripts/prepare_docs.sh b/scripts/prepare_docs.sh new file mode 100755 index 00000000..b5491e4d --- /dev/null +++ b/scripts/prepare_docs.sh @@ -0,0 +1,2 @@ +cat README.rst SCREENSHOTS.rst docs/documentation.rst.distrib > docs/index.rst +cat QUICK_START.rst > docs/quickstart.rst diff --git a/src/fobi/contrib/plugins/form_elements/security/captcha/README.rst b/src/fobi/contrib/plugins/form_elements/security/captcha/README.rst index f3443236..03bf3fd4 100644 --- a/src/fobi/contrib/plugins/form_elements/security/captcha/README.rst +++ b/src/fobi/contrib/plugins/form_elements/security/captcha/README.rst @@ -74,12 +74,6 @@ packages. That limitation is likely to be solved in future in the ``django-recaptcha`` package. Until then, you should choose either one or another, but not both on the same time. -In form wizards ---------------- -At the moment, captcha fields do not work in form wizards, as they are -invalidated on the last step, which breaks the cycle. Therefore, it's not -recommended to use captcha plugins in form wizards. - Usage ===== Note, that unlike most of the other form element plugins, default diff --git a/src/fobi/contrib/plugins/form_elements/security/recaptcha/README.rst b/src/fobi/contrib/plugins/form_elements/security/recaptcha/README.rst index 6dff9873..810dfa91 100644 --- a/src/fobi/contrib/plugins/form_elements/security/recaptcha/README.rst +++ b/src/fobi/contrib/plugins/form_elements/security/recaptcha/README.rst @@ -68,12 +68,6 @@ invalid", make sure to have defined (and filled in properly) the See the `following `_ thread for more information. -In form wizards ---------------- -At the moment, captcha fields do not work in form wizards, as they are -invalidated on the last step, which breaks the cycle. Therefore, it's not -recommended to use captcha plugins in form wizards. - Usage ===== Note, that unlike most of the other form element plugins, default