cherrypy-foundation 1.0.0a20__tar.gz → 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/.gitlab-ci.yml +12 -0
- cherrypy_foundation-1.0.1/MANIFEST.in +1 -0
- {cherrypy_foundation-1.0.0a20/src/cherrypy_foundation.egg-info → cherrypy_foundation-1.0.1}/PKG-INFO +1 -1
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/debian/control +8 -9
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/debian/copyright +1 -1
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/ldap.py +20 -22
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/sessions.py +29 -18
- cherrypy_foundation-1.0.1/src/cherrypy_foundation/tests/test_sessions.py +89 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/jinja2.py +59 -9
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/test_jinja2.py +1 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1/src/cherrypy_foundation.egg-info}/PKG-INFO +1 -1
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation.egg-info/SOURCES.txt +2 -1
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/tox.ini +5 -1
- cherrypy_foundation-1.0.0a20/debian/python3-cherrypy-foundation.links +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/.gitignore +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/LICENSE.md +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/README.md +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/debian/TODO +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/debian/changelog +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/debian/rules +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/debian/source/format +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/debian/upstream/metadata +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/doc/_templates/version.html +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/doc/conf.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/doc/error_page.md +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/doc/flash.md +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/doc/form.md +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/doc/index.rst +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/doc/introduction.md +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/doc/modules.rst +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/doc/url.md +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/pyproject.toml +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/setup.cfg +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/sonar-project.properties +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/__init__.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/ColorModes.jinja +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/Datatable.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/Datatable.jinja +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/Datatable.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/Field.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/Field.jinja +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/Field.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/Fields.jinja +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/Flash.jinja +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/Icon.jinja +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/LocaleSelection.jinja +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/LocaleSelection.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/SideBySideMultiSelect.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/SideBySideMultiSelect.jinja +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/SideBySideMultiSelect.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/Typeahead.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/Typeahead.jinja +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/Typeahead.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/__init__.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/tests/__init__.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/tests/test_static.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap-icons/bootstrap-icons.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap-icons/bootstrap-icons.min.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.css.map +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.min.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap5/css/bootstrap.min.css.map +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.js.map +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.min.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap5/js/bootstrap.min.js.map +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/bootstrap5/js/color-modes.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables/css/dataTables.dataTables.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables/css/dataTables.dataTables.min.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables/images/sort_asc.png +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables/images/sort_asc_disabled.png +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables/images/sort_both.png +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables/images/sort_desc.png +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables/images/sort_desc_disabled.png +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables/js/dataTables.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables/js/dataTables.min.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/Buttons/css/buttons.dataTables.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/Buttons/css/buttons.dataTables.min.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/buttons.html5.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/buttons.html5.min.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/dataTables.buttons.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/Buttons/js/dataTables.buttons.min.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/css/fixedHeader.dataTables.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/css/fixedHeader.dataTables.min.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/js/dataTables.fixedHeader.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/FixedHeader/js/dataTables.fixedHeader.min.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/JSZip/jszip.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/JSZip/jszip.min.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/Responsive/css/responsive.dataTables.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/Responsive/css/responsive.dataTables.min.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/Responsive/js/dataTables.responsive.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/Responsive/js/dataTables.responsive.min.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/pdfmake.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/pdfmake.min.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/pdfmake/build/vfs_fonts.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/css/rowGroup.dataTables.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/css/rowGroup.dataTables.min.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/js/dataTables.rowGroup.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/datatables-extensions/rowgroup/js/dataTables.rowGroup.min.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/jquery/jquery.min.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/multi/LICENSE +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/multi/README.md +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/multi/multi.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/multi/multi.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/popper/popper.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/popper/popper.min.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/typeahead/jquery.typeahead.min.css +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/components/vendor/typeahead/jquery.typeahead.min.js +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/error_page.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/flash.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/form.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/logging.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/passwd.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/__init__.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/db.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/restapi.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/scheduler.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/smtp.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/tests/__init__.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/tests/test_db.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/tests/test_ldap.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/tests/test_scheduler.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/tests/test_scheduler_db.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/tests/test_smtp.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tests/__init__.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tests/templates/test_flash.html +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tests/templates/test_form.html +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tests/templates/test_url.html +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tests/test_error_page.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tests/test_flash.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tests/test_form.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tests/test_logging.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tests/test_passwd.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tests/test_url.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/__init__.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/auth.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/auth_mfa.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/i18n.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/ratelimit.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/secure_headers.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/sessions_timeout.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/__init__.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/components/Button.jinja +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/locales/de/LC_MESSAGES/messages.mo +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/locales/de/LC_MESSAGES/messages.po +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/locales/fr/LC_MESSAGES/messages.mo +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/locales/fr/LC_MESSAGES/messages.po +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/locales/messages.pot +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/templates/test_jinja2.html +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/templates/test_jinjax.html +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/templates/test_jinjax_i18n.html +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/test_auth.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/test_auth_mfa.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/test_i18n.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/test_ratelimit.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/tests/test_secure_headers.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/url.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/widgets.py +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation.egg-info/dependency_links.txt +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation.egg-info/requires.txt +0 -0
- {cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation.egg-info/top_level.txt +0 -0
|
@@ -48,6 +48,18 @@ selenium:
|
|
|
48
48
|
trixie:
|
|
49
49
|
<<: *tox
|
|
50
50
|
|
|
51
|
+
trixie-backports:
|
|
52
|
+
<<: *tox
|
|
53
|
+
|
|
54
|
+
wrap-and-sort:
|
|
55
|
+
stage: test
|
|
56
|
+
image: buildpack-deps:stable
|
|
57
|
+
script:
|
|
58
|
+
- apt update
|
|
59
|
+
- apt -y --no-install-recommends install devscripts python3-debian
|
|
60
|
+
- CHANGES=$(wrap-and-sort -astN)
|
|
61
|
+
- if [[ ! -z "$CHANGES" ]]; then echo "$CHANGES"; exit 1; fi
|
|
62
|
+
|
|
51
63
|
package:py3:
|
|
52
64
|
stage: package
|
|
53
65
|
needs: []
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
recursive-include src/cherrypy_foundation/components *.html *.jinja *.css *.js *.woff *.woff2 *.map *.png
|
|
@@ -6,18 +6,14 @@ Build-Depends:
|
|
|
6
6
|
debhelper-compat (= 13),
|
|
7
7
|
dh-python,
|
|
8
8
|
dh-sequence-python3,
|
|
9
|
-
pybuild-plugin-pyproject,
|
|
10
|
-
python3,
|
|
11
|
-
python3-all-dev,
|
|
12
|
-
python3-pip,
|
|
13
|
-
python3-setuptools,
|
|
14
|
-
python3-setuptools-scm,
|
|
15
|
-
# Optional dependencies to execute the test test.
|
|
16
9
|
chromium-driver <!nocheck>,
|
|
17
10
|
libjs-bootstrap5 <!nocheck>,
|
|
18
11
|
libjs-jquery <!nocheck>,
|
|
19
12
|
libjs-jquery-datatables <!nocheck>,
|
|
20
13
|
libjs-jquery-datatables-extensions <!nocheck>,
|
|
14
|
+
pybuild-plugin-pyproject,
|
|
15
|
+
python3,
|
|
16
|
+
python3-all-dev,
|
|
21
17
|
python3-apscheduler <!nocheck>,
|
|
22
18
|
python3-argon2 <!nocheck>,
|
|
23
19
|
python3-babel <!nocheck>,
|
|
@@ -27,10 +23,13 @@ Build-Depends:
|
|
|
27
23
|
python3-ldap3 <!nocheck>,
|
|
28
24
|
python3-oauthlib <!nocheck>,
|
|
29
25
|
python3-parameterized <!nocheck>,
|
|
30
|
-
python3-
|
|
26
|
+
python3-pip,
|
|
27
|
+
python3-pytest <!nocheck>,
|
|
31
28
|
python3-requests <!nocheck>,
|
|
32
29
|
python3-requests-oauthlib <!nocheck>,
|
|
33
30
|
python3-selenium <!nocheck>,
|
|
31
|
+
python3-setuptools,
|
|
32
|
+
python3-setuptools-scm,
|
|
34
33
|
python3-sqlalchemy <!nocheck>,
|
|
35
34
|
python3-tz <!nocheck>,
|
|
36
35
|
python3-wtforms <!nocheck>,
|
|
@@ -47,8 +46,8 @@ Depends:
|
|
|
47
46
|
libjs-jquery,
|
|
48
47
|
libjs-jquery-datatables,
|
|
49
48
|
libjs-jquery-datatables-extensions,
|
|
50
|
-
${python3:Depends},
|
|
51
49
|
${misc:Depends},
|
|
50
|
+
${python3:Depends},
|
|
52
51
|
Suggests:
|
|
53
52
|
python3-apscheduler,
|
|
54
53
|
python3-argon2,
|
|
@@ -2,7 +2,7 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
|
|
2
2
|
Upstream-Name: cherrypy-foundation
|
|
3
3
|
Upstream-Contact: Patrik Dufresne <patrik@ikus-soft.com>
|
|
4
4
|
Source: https://gitlab.com/ikus-soft/cherrypy-foundation/-/tags
|
|
5
|
-
Files-Excluded:
|
|
5
|
+
Files-Excluded:
|
|
6
6
|
src/cherrypy_foundation/components/vendor
|
|
7
7
|
|
|
8
8
|
Files: *
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/ldap.py
RENAMED
|
@@ -77,8 +77,8 @@ class LdapPlugin(SimplePlugin):
|
|
|
77
77
|
"""
|
|
78
78
|
Used this plugin to authenticate user against an LDAP server.
|
|
79
79
|
|
|
80
|
-
`authenticate(
|
|
81
|
-
valid. Otherwise it return a tuple or
|
|
80
|
+
`authenticate(login, password)` return None if the credentials are not
|
|
81
|
+
valid. Otherwise it return a tuple or login and extra attributes.
|
|
82
82
|
The extra attribute may contains `_fullname` and `_email`.
|
|
83
83
|
"""
|
|
84
84
|
|
|
@@ -89,7 +89,7 @@ class LdapPlugin(SimplePlugin):
|
|
|
89
89
|
scope = 'subtree'
|
|
90
90
|
tls = False
|
|
91
91
|
user_filter = '(objectClass=*)'
|
|
92
|
-
|
|
92
|
+
login_attribute = ['uid']
|
|
93
93
|
required_group = None
|
|
94
94
|
group_attribute = 'member'
|
|
95
95
|
group_attribute_is_dn = False
|
|
@@ -133,14 +133,14 @@ class LdapPlugin(SimplePlugin):
|
|
|
133
133
|
self.stop()
|
|
134
134
|
self.start()
|
|
135
135
|
|
|
136
|
-
def authenticate(self,
|
|
136
|
+
def authenticate(self, login, password):
|
|
137
137
|
"""
|
|
138
138
|
Check if the given credential as valid according to LDAP.
|
|
139
139
|
Return False if invalid.
|
|
140
140
|
Return None if the plugin is unavailable to validate credentials or if the plugin is disabled.
|
|
141
|
-
Return tuple (<
|
|
141
|
+
Return tuple (<login>, <attributes>) if the credentials are valid.
|
|
142
142
|
"""
|
|
143
|
-
assert isinstance(
|
|
143
|
+
assert isinstance(login, str)
|
|
144
144
|
assert isinstance(password, str)
|
|
145
145
|
|
|
146
146
|
if not hasattr(self, '_pool'):
|
|
@@ -150,14 +150,14 @@ class LdapPlugin(SimplePlugin):
|
|
|
150
150
|
with self._pool as conn:
|
|
151
151
|
try:
|
|
152
152
|
# Search the LDAP server for user's DN.
|
|
153
|
-
|
|
154
|
-
attr_filter = ''.join([f'({_safe(attr)}={
|
|
153
|
+
safe_login = _safe(login)
|
|
154
|
+
attr_filter = ''.join([f'({_safe(attr)}={safe_login})' for attr in self.login_attribute])
|
|
155
155
|
search_filter = f"(&{self.user_filter}(|{attr_filter}))"
|
|
156
156
|
response = self._search(conn, search_filter)
|
|
157
157
|
if not response:
|
|
158
|
-
cherrypy.log(f"lookup failed
|
|
158
|
+
cherrypy.log(f"lookup failed login={login} reason=not_found", context='LDAP')
|
|
159
159
|
return False
|
|
160
|
-
cherrypy.log(f"lookup successful
|
|
160
|
+
cherrypy.log(f"lookup successful login={login}", context='LDAP')
|
|
161
161
|
user_dn = response[0]['dn']
|
|
162
162
|
|
|
163
163
|
# Use a separate connection to validate credentials
|
|
@@ -171,18 +171,18 @@ class LdapPlugin(SimplePlugin):
|
|
|
171
171
|
)
|
|
172
172
|
if not login_conn.bind():
|
|
173
173
|
cherrypy.log(
|
|
174
|
-
f'ldap authentication failed
|
|
174
|
+
f'ldap authentication failed login={login} reason=wrong_password',
|
|
175
175
|
context='LDAP',
|
|
176
176
|
severity=logging.WARNING,
|
|
177
177
|
)
|
|
178
178
|
return False
|
|
179
179
|
|
|
180
|
-
# Get
|
|
180
|
+
# Get user's login
|
|
181
181
|
attrs = response[0]['attributes']
|
|
182
|
-
|
|
183
|
-
if not
|
|
182
|
+
new_login = first_attribute(attrs, self.login_attribute[0])
|
|
183
|
+
if not new_login:
|
|
184
184
|
cherrypy.log(
|
|
185
|
-
f"object missing
|
|
185
|
+
f"object missing login attribute user_dn={user_dn} attribute={self.login_attribute[0]}",
|
|
186
186
|
context='LDAP',
|
|
187
187
|
severity=logging.WARNING,
|
|
188
188
|
)
|
|
@@ -192,7 +192,7 @@ class LdapPlugin(SimplePlugin):
|
|
|
192
192
|
if self.required_group:
|
|
193
193
|
if not isinstance(self.required_group, list):
|
|
194
194
|
self.required_group = [self.required_group]
|
|
195
|
-
user_value = user_dn if self.group_attribute_is_dn else
|
|
195
|
+
user_value = user_dn if self.group_attribute_is_dn else new_login
|
|
196
196
|
group_filter = '(&(%s=%s)(|%s)%s)' % (
|
|
197
197
|
_safe(self.group_attribute),
|
|
198
198
|
_safe(user_value),
|
|
@@ -201,13 +201,13 @@ class LdapPlugin(SimplePlugin):
|
|
|
201
201
|
)
|
|
202
202
|
# Search LDAP Server for matching groups.
|
|
203
203
|
cherrypy.log(
|
|
204
|
-
f"group check start
|
|
204
|
+
f"group check start login={user_value} required_groups={' '.join(self.required_group)}",
|
|
205
205
|
context='LDAP',
|
|
206
206
|
)
|
|
207
207
|
response = self._search(conn, group_filter, attributes=['cn'])
|
|
208
208
|
if not response:
|
|
209
209
|
cherrypy.log(
|
|
210
|
-
f"group check failed
|
|
210
|
+
f"group check failed login={user_value} required_groups={' '.join(self.required_group)}",
|
|
211
211
|
context='LDAP',
|
|
212
212
|
)
|
|
213
213
|
return False
|
|
@@ -220,13 +220,11 @@ class LdapPlugin(SimplePlugin):
|
|
|
220
220
|
firstname = first_attribute(attrs, self.firstname_attribute, '')
|
|
221
221
|
lastname = first_attribute(attrs, self.lastname_attribute, '')
|
|
222
222
|
attrs['fullname'] = ' '.join([name for name in [firstname, lastname] if name])
|
|
223
|
-
return (
|
|
223
|
+
return (new_login, attrs)
|
|
224
224
|
except LDAPInvalidCredentialsResult:
|
|
225
225
|
return False
|
|
226
226
|
except LDAPException:
|
|
227
|
-
cherrypy.log(
|
|
228
|
-
f"unexpected error username={username}", context='LDAP', severity=logging.ERROR, traceback=True
|
|
229
|
-
)
|
|
227
|
+
cherrypy.log(f"unexpected error login={login}", context='LDAP', severity=logging.ERROR, traceback=True)
|
|
230
228
|
return None
|
|
231
229
|
|
|
232
230
|
def search(self, filter, attributes=ldap3.ALL_ATTRIBUTES, search_base=None, paged_size=None):
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/sessions.py
RENAMED
|
@@ -1,20 +1,4 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Copyright (C) 2012-2026 IKUS Software
|
|
3
|
-
#
|
|
4
|
-
# This program is free software: you can redistribute it and/or modify
|
|
5
|
-
# it under the terms of the GNU General Public License as published by
|
|
6
|
-
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
-
# (at your option) any later version.
|
|
8
|
-
#
|
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
# GNU General Public License for more details.
|
|
13
|
-
#
|
|
14
|
-
# You should have received a copy of the GNU General Public License
|
|
15
|
-
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
-
|
|
17
|
-
# BFH Science Self-Service Portal
|
|
1
|
+
# Cherrypy-foundation
|
|
18
2
|
# Copyright (C) 2025-2026 IKUS Software
|
|
19
3
|
#
|
|
20
4
|
# This program is free software: you can redistribute it and/or modify
|
|
@@ -29,6 +13,10 @@
|
|
|
29
13
|
#
|
|
30
14
|
# You should have received a copy of the GNU General Public License
|
|
31
15
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
import logging
|
|
19
|
+
import os
|
|
32
20
|
import time
|
|
33
21
|
from contextlib import contextmanager
|
|
34
22
|
|
|
@@ -38,7 +26,6 @@ from cherrypy.lib import locking
|
|
|
38
26
|
from cherrypy.lib.sessions import FileSession as CPFileSession
|
|
39
27
|
|
|
40
28
|
|
|
41
|
-
# Issue in cherrypy: https://github.com/cherrypy/cherrypy/issues/2065
|
|
42
29
|
class FileSession(CPFileSession):
|
|
43
30
|
"""
|
|
44
31
|
Override implementation of cherrpy file session to improve file locking.
|
|
@@ -46,6 +33,8 @@ class FileSession(CPFileSession):
|
|
|
46
33
|
|
|
47
34
|
def acquire_lock(self, path=None):
|
|
48
35
|
"""Acquire an exclusive lock on the currently-loaded session data."""
|
|
36
|
+
# See Issue https://github.com/cherrypy/cherrypy/issues/2065
|
|
37
|
+
|
|
49
38
|
if path is None:
|
|
50
39
|
path = self._get_file_path()
|
|
51
40
|
path += self.LOCK_SUFFIX
|
|
@@ -62,6 +51,28 @@ class FileSession(CPFileSession):
|
|
|
62
51
|
if self.debug:
|
|
63
52
|
cherrypy.log('Lock acquired.', 'TOOLS.SESSIONS')
|
|
64
53
|
|
|
54
|
+
def clean_up(self):
|
|
55
|
+
"""Also clean-up left over lock files."""
|
|
56
|
+
# See Issue https://github.com/cherrypy/cherrypy/issues/1855
|
|
57
|
+
|
|
58
|
+
# Clean-up session files.
|
|
59
|
+
CPFileSession.clean_up(self)
|
|
60
|
+
|
|
61
|
+
# Then clean-up any orphane lock files.
|
|
62
|
+
suffix_len = len(self.LOCK_SUFFIX)
|
|
63
|
+
files = os.listdir(self.storage_path)
|
|
64
|
+
lock_files = [
|
|
65
|
+
fname for fname in files if fname.startswith(self.SESSION_PREFIX) and fname.endswith(self.LOCK_SUFFIX)
|
|
66
|
+
]
|
|
67
|
+
for fname in lock_files:
|
|
68
|
+
session_file = fname[:-suffix_len]
|
|
69
|
+
if session_file not in files:
|
|
70
|
+
filepath = os.path.join(self.storage_path, fname)
|
|
71
|
+
try:
|
|
72
|
+
os.unlink(filepath)
|
|
73
|
+
except Exception as e:
|
|
74
|
+
cherrypy.log(f'Error deleting {filepath}: {e}', 'TOOLS.SESSIONS', severity=logging.WARNING)
|
|
75
|
+
|
|
65
76
|
|
|
66
77
|
@contextmanager
|
|
67
78
|
def session_lock():
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Cherrypy-foundation
|
|
2
|
+
# Copyright (C) 2026 IKUS Software
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
import tempfile
|
|
19
|
+
|
|
20
|
+
import cherrypy
|
|
21
|
+
from cherrypy.test import helper
|
|
22
|
+
|
|
23
|
+
from cherrypy_foundation.sessions import FileSession, session_lock
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@cherrypy.tools.sessions(on=True, locking='explicit', storage_class=FileSession)
|
|
27
|
+
class Root:
|
|
28
|
+
|
|
29
|
+
@cherrypy.expose
|
|
30
|
+
def index(self, value='OK'):
|
|
31
|
+
if value:
|
|
32
|
+
with session_lock() as s:
|
|
33
|
+
s['value'] = value
|
|
34
|
+
return s['value']
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class FileSessionTest(helper.CPWebCase):
|
|
38
|
+
interactive = False
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def setup_class(cls):
|
|
42
|
+
cls.tempdir = tempfile.TemporaryDirectory(prefix='cherrypy-foundation-', suffix='-file-session-test')
|
|
43
|
+
cls.storage_path = cls.tempdir.name
|
|
44
|
+
super().setup_class()
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def teardown_class(cls):
|
|
48
|
+
cls.tempdir.cleanup()
|
|
49
|
+
super().teardown_class()
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def setup_server(cls):
|
|
53
|
+
cherrypy.config.update(
|
|
54
|
+
{
|
|
55
|
+
'tools.sessions.storage_path': cls.storage_path,
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
cherrypy.tree.mount(Root(), '/')
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def _session_id(self):
|
|
62
|
+
"""Return session id from cookie."""
|
|
63
|
+
if hasattr(self, 'cookies') and self.cookies:
|
|
64
|
+
for unused, value in self.cookies:
|
|
65
|
+
for part in value.split(';'):
|
|
66
|
+
key, unused, value = part.partition('=')
|
|
67
|
+
if key == 'session_id':
|
|
68
|
+
return value
|
|
69
|
+
|
|
70
|
+
def test_get_page(self):
|
|
71
|
+
# Given a page with session enabled
|
|
72
|
+
# When the page get queried
|
|
73
|
+
self.getPage("/")
|
|
74
|
+
# Then a session is created with a id
|
|
75
|
+
self.assertStatus(200)
|
|
76
|
+
self.assertTrue(self._session_id)
|
|
77
|
+
# Then this session is created on disk.
|
|
78
|
+
s = FileSession(id=self._session_id, storage_path=self.storage_path)
|
|
79
|
+
self.assertTrue(s._exists())
|
|
80
|
+
# When session timeout and get clean-up
|
|
81
|
+
s.acquire_lock()
|
|
82
|
+
s.load()
|
|
83
|
+
s.timeout = 0
|
|
84
|
+
s.save()
|
|
85
|
+
s.clean_up()
|
|
86
|
+
# Then session get deleted
|
|
87
|
+
self.assertFalse(s._exists())
|
|
88
|
+
# Lock file also get deleted.
|
|
89
|
+
self.assertFalse(os.path.exists(s._get_file_path() + FileSession.LOCK_SUFFIX))
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/jinja2.py
RENAMED
|
@@ -20,6 +20,7 @@ import time
|
|
|
20
20
|
|
|
21
21
|
import cherrypy
|
|
22
22
|
import jinja2
|
|
23
|
+
from markupsafe import Markup
|
|
23
24
|
|
|
24
25
|
# Sentinel value
|
|
25
26
|
_UNDEFINED = object()
|
|
@@ -27,6 +28,8 @@ _UNDEFINED = object()
|
|
|
27
28
|
# Capture epoch time to invalidate cache of static file.
|
|
28
29
|
_cache_invalidate = int(time.time())
|
|
29
30
|
|
|
31
|
+
_JINJAX_TOKEN = '@@JINJAX-CATALOG-TOKEN@@'
|
|
32
|
+
|
|
30
33
|
|
|
31
34
|
class Jinja2Tool(cherrypy.Tool):
|
|
32
35
|
"""
|
|
@@ -41,12 +44,47 @@ class Jinja2Tool(cherrypy.Tool):
|
|
|
41
44
|
Replace the placeholder token in the rendered HTML with the fully
|
|
42
45
|
formatted asset tags, then reset asset state for the next render.
|
|
43
46
|
"""
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
# Skip this step if render_assets() has not been called.
|
|
48
|
+
if hasattr(catalog, '_emit_assets_later') and getattr(catalog, '_emit_assets_later') is False:
|
|
49
|
+
return html
|
|
50
|
+
|
|
51
|
+
# Render Js and Css collected assets
|
|
52
|
+
if hasattr(catalog, '_format_collected_assets'):
|
|
53
|
+
# JinjaX > 0.60
|
|
54
|
+
catalog._emit_assets_later = False
|
|
55
|
+
assets_html = catalog._format_collected_assets()
|
|
56
|
+
assets_html = str(assets_html).replace('<script type="module" ', '<script ')
|
|
57
|
+
return str(html).replace(catalog._assets_placeholder, assets_html)
|
|
58
|
+
else:
|
|
59
|
+
# JinjaX<=0.60
|
|
60
|
+
html_css = []
|
|
61
|
+
rendered_urls = set()
|
|
62
|
+
|
|
63
|
+
for url in catalog.collected_css:
|
|
64
|
+
if url == _JINJAX_TOKEN:
|
|
65
|
+
continue
|
|
66
|
+
if not url.startswith(("http://", "https://")):
|
|
67
|
+
full_url = f"{catalog.root_url}{url}"
|
|
68
|
+
else:
|
|
69
|
+
full_url = url
|
|
70
|
+
|
|
71
|
+
if full_url not in rendered_urls:
|
|
72
|
+
html_css.append(f'<link rel="stylesheet" href="{full_url}">')
|
|
73
|
+
rendered_urls.add(full_url)
|
|
74
|
+
|
|
75
|
+
html_js = []
|
|
76
|
+
for url in catalog.collected_js:
|
|
77
|
+
if not url.startswith(("http://", "https://")):
|
|
78
|
+
full_url = f"{catalog.root_url}{url}"
|
|
79
|
+
else:
|
|
80
|
+
full_url = url
|
|
81
|
+
|
|
82
|
+
if full_url not in rendered_urls:
|
|
83
|
+
html_js.append(f'<script src="{full_url}"></script>')
|
|
84
|
+
rendered_urls.add(full_url)
|
|
85
|
+
|
|
86
|
+
assets_html = Markup("\n".join(html_css + html_js))
|
|
87
|
+
return str(html).replace(f'<link rel="stylesheet" href="/static/components/{_JINJAX_TOKEN}">', assets_html)
|
|
50
88
|
|
|
51
89
|
def _wrap_handler(self, env, template, extra_processor=None, debug=False):
|
|
52
90
|
|
|
@@ -147,11 +185,23 @@ class Jinja2Tool(cherrypy.Tool):
|
|
|
147
185
|
tmpl = env.select_template(names)
|
|
148
186
|
else:
|
|
149
187
|
tmpl = env.get_template(template)
|
|
188
|
+
|
|
189
|
+
# Monkey patch JinjaX catalog.render_assets() for JinjaX <= 0.60
|
|
190
|
+
catalog = env.globals.get('catalog')
|
|
191
|
+
if catalog:
|
|
192
|
+
catalog.collected_css = []
|
|
193
|
+
catalog.collected_js = []
|
|
194
|
+
if not hasattr(catalog, '_assets_placeholder'):
|
|
195
|
+
# JinjaX <= 0.60
|
|
196
|
+
# Leave a token to be replace.
|
|
197
|
+
catalog.collected_css = [_JINJAX_TOKEN]
|
|
198
|
+
|
|
199
|
+
# Render template
|
|
150
200
|
out = tmpl.render(context)
|
|
151
201
|
|
|
152
|
-
# With JinjaX
|
|
153
|
-
if
|
|
154
|
-
return self._finalize_assets(catalog=
|
|
202
|
+
# With JinjaX finalise render_assets().
|
|
203
|
+
if catalog:
|
|
204
|
+
return self._finalize_assets(catalog=catalog, html=out)
|
|
155
205
|
return out
|
|
156
206
|
|
|
157
207
|
|
|
@@ -124,6 +124,7 @@ class Jinja2Test(helper.CPWebCase, SeleniumUnitTest):
|
|
|
124
124
|
# Then the page return without error
|
|
125
125
|
self.assertStatus(200)
|
|
126
126
|
# Then the page is render dynamically using page context
|
|
127
|
+
self.assertInBody('<script src="/static/components/LocaleSelection.js"></script>')
|
|
127
128
|
if expected_lang == 'fr':
|
|
128
129
|
self.assertInBody('lang="fr"')
|
|
129
130
|
self.assertInBody('français')
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
.gitignore
|
|
2
2
|
.gitlab-ci.yml
|
|
3
3
|
LICENSE.md
|
|
4
|
+
MANIFEST.in
|
|
4
5
|
README.md
|
|
5
6
|
pyproject.toml
|
|
6
7
|
sonar-project.properties
|
|
@@ -9,7 +10,6 @@ debian/TODO
|
|
|
9
10
|
debian/changelog
|
|
10
11
|
debian/control
|
|
11
12
|
debian/copyright
|
|
12
|
-
debian/python3-cherrypy-foundation.links
|
|
13
13
|
debian/rules
|
|
14
14
|
debian/source/format
|
|
15
15
|
debian/upstream/metadata
|
|
@@ -129,6 +129,7 @@ src/cherrypy_foundation/tests/test_flash.py
|
|
|
129
129
|
src/cherrypy_foundation/tests/test_form.py
|
|
130
130
|
src/cherrypy_foundation/tests/test_logging.py
|
|
131
131
|
src/cherrypy_foundation/tests/test_passwd.py
|
|
132
|
+
src/cherrypy_foundation/tests/test_sessions.py
|
|
132
133
|
src/cherrypy_foundation/tests/test_url.py
|
|
133
134
|
src/cherrypy_foundation/tests/templates/test_flash.html
|
|
134
135
|
src/cherrypy_foundation/tests/templates/test_form.html
|
|
@@ -30,11 +30,15 @@ deps =
|
|
|
30
30
|
trixie: wtforms==3.2.1
|
|
31
31
|
trixie: CherryPy==18.10.0
|
|
32
32
|
trixie: Jinja2==3.1.6
|
|
33
|
-
|
|
33
|
+
trixie: jinjax==0.57
|
|
34
34
|
extras = test
|
|
35
35
|
commands =
|
|
36
36
|
pytest -v --debug --ignore=debian --override-ini junit_family=xunit1 --junit-xml=xunit.xml --cov=cherrypy_foundation --cov-report xml:coverage.xml
|
|
37
37
|
|
|
38
|
+
[testenv:trixie-backports]
|
|
39
|
+
deps_extra =
|
|
40
|
+
jinjax==0.60
|
|
41
|
+
|
|
38
42
|
[testenv:doc]
|
|
39
43
|
deps =
|
|
40
44
|
sphinx
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/error_page.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/logging.py
RENAMED
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/passwd.py
RENAMED
|
File without changes
|
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/db.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/plugins/smtp.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tests/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tests/test_url.py
RENAMED
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/__init__.py
RENAMED
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/auth.py
RENAMED
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/auth_mfa.py
RENAMED
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/tools/i18n.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cherrypy_foundation-1.0.0a20 → cherrypy_foundation-1.0.1}/src/cherrypy_foundation/widgets.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|