WuttaWeb 0.23.0__tar.gz → 0.23.2__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.
- wuttaweb-0.23.2/.pylintrc +4 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/CHANGELOG.md +70 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/PKG-INFO +4 -2
- wuttaweb-0.23.2/docs/conf.py +48 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/index.rst +6 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/pyproject.toml +3 -3
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/_version.py +4 -1
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/app.py +51 -45
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/auth.py +37 -26
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/cli/webapp.py +27 -23
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/conf.py +8 -5
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/db/continuum.py +6 -4
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/emails.py +11 -10
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/forms/base.py +120 -118
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/forms/schema.py +86 -79
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/forms/widgets.py +94 -68
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/grids/base.py +361 -304
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/grids/filters.py +165 -132
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/handler.py +22 -16
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/helpers.py +8 -4
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/menus.py +137 -129
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/progress.py +22 -20
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/static/__init__.py +7 -7
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/subscribers.py +60 -48
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/themes/butterfly/base.mako +2 -2
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/wutta-components.mako +0 -2
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/testing.py +39 -19
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/util.py +226 -135
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/views/__init__.py +3 -3
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/views/auth.py +112 -80
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/views/base.py +2 -2
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/views/batch.py +124 -129
- wuttaweb-0.23.2/src/wuttaweb/views/common.py +356 -0
- wuttaweb-0.23.2/src/wuttaweb/views/email.py +320 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/views/essential.py +15 -13
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/views/master.py +547 -395
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/views/people.py +77 -76
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/views/progress.py +14 -12
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/views/reports.py +84 -71
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/views/roles.py +93 -87
- wuttaweb-0.23.2/src/wuttaweb/views/settings.py +298 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/views/upgrades.py +142 -110
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/views/users.py +149 -118
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tasks.py +7 -7
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/cli/test_webapp.py +50 -35
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/db/test_continuum.py +7 -7
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/forms/test_base.py +288 -261
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/forms/test_schema.py +69 -65
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/forms/test_widgets.py +83 -74
- wuttaweb-0.23.2/tests/grids/test_base.py +2026 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/grids/test_filters.py +262 -198
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/test_app.py +67 -55
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/test_auth.py +43 -33
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/test_emails.py +4 -2
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/test_handler.py +57 -41
- wuttaweb-0.23.2/tests/test_menus.py +345 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/test_progress.py +9 -9
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/test_static.py +1 -1
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/test_subscribers.py +107 -88
- wuttaweb-0.23.2/tests/test_util.py +800 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/util.py +6 -3
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/views/test___init__.py +1 -1
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/views/test_auth.py +56 -51
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/views/test_base.py +7 -7
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/views/test_batch.py +155 -91
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/views/test_common.py +64 -66
- wuttaweb-0.23.2/tests/views/test_email.py +249 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/views/test_essential.py +1 -1
- wuttaweb-0.23.2/tests/views/test_master.py +1843 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/views/test_people.py +36 -27
- wuttaweb-0.23.2/tests/views/test_progress.py +62 -0
- wuttaweb-0.23.2/tests/views/test_reports.py +287 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/views/test_roles.py +88 -68
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/views/test_settings.py +15 -15
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/views/test_upgrades.py +149 -121
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/views/test_users.py +177 -141
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tox.ini +4 -0
- wuttaweb-0.23.0/docs/conf.py +0 -48
- wuttaweb-0.23.0/src/wuttaweb/views/common.py +0 -342
- wuttaweb-0.23.0/src/wuttaweb/views/email.py +0 -298
- wuttaweb-0.23.0/src/wuttaweb/views/settings.py +0 -276
- wuttaweb-0.23.0/tests/grids/test_base.py +0 -1870
- wuttaweb-0.23.0/tests/test_menus.py +0 -345
- wuttaweb-0.23.0/tests/test_util.py +0 -712
- wuttaweb-0.23.0/tests/views/test_email.py +0 -211
- wuttaweb-0.23.0/tests/views/test_master.py +0 -1741
- wuttaweb-0.23.0/tests/views/test_progress.py +0 -62
- wuttaweb-0.23.0/tests/views/test_reports.py +0 -236
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/.gitignore +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/.hgignore +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/COPYING.txt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/README.md +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/Makefile +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/_static/.keepme +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.app.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.auth.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.cli.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.cli.webapp.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.conf.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.db.continuum.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.db.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.db.sess.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.emails.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.forms.base.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.forms.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.forms.schema.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.forms.widgets.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.grids.base.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.grids.filters.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.grids.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.handler.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.helpers.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.menus.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.progress.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.static.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.subscribers.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.util.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.auth.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.base.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.batch.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.common.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.email.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.essential.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.master.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.people.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.progress.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.reports.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.roles.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.settings.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.upgrades.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/api/wuttaweb.views.users.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/glossary.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/make.bat +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/narr/cli/builtin.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/narr/cli/index.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/narr/templates/base.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/narr/templates/index.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/narr/templates/lookup.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/docs/narr/templates/overview.rst +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/__init__.py +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/cli/__init__.py +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/db/__init__.py +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/db/sess.py +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/email-templates/feedback.html.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/email-templates/feedback.txt.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/forms/__init__.py +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/grids/__init__.py +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/static/img/favicon.ico +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/static/img/logo.png +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/static/img/testing.png +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/appinfo/configure.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/appinfo/index.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/auth/change_password.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/auth/login.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/base.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/base_meta.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/batch/view.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/configure.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/checkbox.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/checkbox_choice.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/checked_password.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/dateinput.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/datetimeinput.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/moneyinput.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/password.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/permissions.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/readonly/checkbox.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/readonly/email_recips.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/readonly/filedownload.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/readonly/notes.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/readonly/objectref.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/readonly/permissions.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/readonly/rolerefs.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/select.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/textarea.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/textinput.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/deform/wutta_checked_password.pt +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/email/settings/view.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/forbidden.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/form.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/forms/vue_template.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/grids/table_element.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/grids/vue_template.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/home.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/master/configure.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/master/create.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/master/delete.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/master/edit.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/master/form.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/master/index.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/master/view.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/notfound.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/page.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/people/view_profile.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/progress.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/reports/view.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/setup.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/themes/butterfly/buefy-components.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/themes/butterfly/buefy-plugin.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/themes/butterfly/http-plugin.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/upgrade.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/upgrades/configure.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/upgrades/view.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/src/wuttaweb/templates/users/view.mako +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/__init__.py +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/cli/__init__.py +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/db/__init__.py +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/grids/__init__.py +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/libcache/bb_fontawesome_svg_core.js +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/libcache/bb_free_solid_svg_icons.js +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/libcache/bb_oruga.js +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/libcache/bb_oruga_bulma.css +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/libcache/bb_oruga_bulma.js +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/libcache/bb_vue.js +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/libcache/bb_vue_fontawesome.js +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/libcache/buefy.css +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/libcache/buefy.js +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/libcache/fontawesome.js +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/libcache/vue.js +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/libcache/vue_resource.js +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/test_helpers.py +0 -0
- {wuttaweb-0.23.0 → wuttaweb-0.23.2}/tests/views/__init__.py +0 -0
|
@@ -5,6 +5,76 @@ All notable changes to wuttaweb will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## v0.23.2 (2025-10-19)
|
|
9
|
+
|
|
10
|
+
### Fix
|
|
11
|
+
|
|
12
|
+
- require latest wuttjamaican
|
|
13
|
+
- remove unused statement in WuttaFilter component
|
|
14
|
+
- explicitly disable 'duplicate-code' false alarm
|
|
15
|
+
|
|
16
|
+
## v0.23.1 (2025-09-01)
|
|
17
|
+
|
|
18
|
+
### Fix
|
|
19
|
+
|
|
20
|
+
- fix 'duplicate-code' for pylint
|
|
21
|
+
- fix 'no-member' for pylint
|
|
22
|
+
- fix 'attribute-defined-outside-init' for pylint
|
|
23
|
+
- fix 'arguments-renamed' for pylint
|
|
24
|
+
- fix 'arguments-differ' for pylint
|
|
25
|
+
- fix 'keyword-arg-before-vararg' for pylint
|
|
26
|
+
- fix 'too-many-nested-blocks' for pylint
|
|
27
|
+
- fix 'too-many-locals' for pylint
|
|
28
|
+
- fix 'consider-using-generator' for pylint
|
|
29
|
+
- fix 'missing-function-docstring' and 'missing-module-docstring' for pylint
|
|
30
|
+
- fix 'super-init-not-called' for pylint
|
|
31
|
+
- fix 'singleton-comparison' for pylint
|
|
32
|
+
- fix 'simplifiable-if-expression' for pylint
|
|
33
|
+
- fix 'redefined-outer-name' for pylint
|
|
34
|
+
- fix 'protected-access' for pylint
|
|
35
|
+
- fix 'not-callable' for pylint
|
|
36
|
+
- fix 'no-else-raise' for pylint
|
|
37
|
+
- fix 'isinstance-second-argument-not-valid-type' for pylint
|
|
38
|
+
- fix 'consider-using-set-comprehension' for pylint
|
|
39
|
+
- fix 'consider-using-get' for pylint
|
|
40
|
+
- fix 'consider-using-dict-items' for pylint
|
|
41
|
+
- fix 'consider-using-dict-comprehension' for pylint
|
|
42
|
+
- fix 'assignment-from-no-return' for pylint
|
|
43
|
+
- fix 'abstract-method' for pylint
|
|
44
|
+
- fix 'too-few-public-methods' for pylint
|
|
45
|
+
- fix 'too-many-lines' for pylint
|
|
46
|
+
- fix 'too-many-arguments' for pylint
|
|
47
|
+
- fix 'too-many-public-methods' for pylint
|
|
48
|
+
- fix 'too-many-statements' for pylint
|
|
49
|
+
- fix 'unidiomatic-typecheck' for pylint
|
|
50
|
+
- fix 'unnecessary-comprehension' for pylint
|
|
51
|
+
- fix 'unnecessary-lambda' and 'unnecessary-lambda-assignment' for pylint
|
|
52
|
+
- fix 'unspecified-encoding' for pylint
|
|
53
|
+
- fix 'unused-argument' for pylint
|
|
54
|
+
- fix 'use-a-generator' for pylint
|
|
55
|
+
- fix 'use-dict-literal' for pylint
|
|
56
|
+
- fix 'dangerous-default-value' for pylint
|
|
57
|
+
- fix 'wildcard-import' and 'unused-wildcard-import' for pylint
|
|
58
|
+
- fix 'wrong-import-order' for pylint
|
|
59
|
+
- fix 'import-outside-toplevel' for pylint
|
|
60
|
+
- fix 'implicit-str-concat' for pylint
|
|
61
|
+
- fix 'deprecated-method' for pylint
|
|
62
|
+
- fix 'cyclic-import' for pylint
|
|
63
|
+
- fix 'bare-except' and 'broad-exception-caught' for pylint
|
|
64
|
+
- fix 'invalid-name' for pylint
|
|
65
|
+
- fix 'anomalous-backslash-in-string' for pylint
|
|
66
|
+
- bump version requirement for wuttjamaican
|
|
67
|
+
- fix 'unused-variable' for pylint
|
|
68
|
+
- fix 'unused-import' for pylint
|
|
69
|
+
- fix 'redefined-argument-from-local' for pylint
|
|
70
|
+
- fix 'empty-docstring' for pylint
|
|
71
|
+
- fix 'no-else-return' for pylint
|
|
72
|
+
- fix 'too-many-branches' for pylint
|
|
73
|
+
- fix 'too-many-return-statements' for pylint
|
|
74
|
+
- fix 'too-many-instance-attributes' for pylint
|
|
75
|
+
- fix 'inconsistent-return-statements' for pylint
|
|
76
|
+
- format all code with black
|
|
77
|
+
|
|
8
78
|
## v0.23.0 (2025-08-09)
|
|
9
79
|
|
|
10
80
|
### Feat
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: WuttaWeb
|
|
3
|
-
Version: 0.23.
|
|
3
|
+
Version: 0.23.2
|
|
4
4
|
Summary: Web App for Wutta Framework
|
|
5
5
|
Project-URL: Homepage, https://wuttaproject.org/
|
|
6
6
|
Project-URL: Repository, https://forgejo.wuttaproject.org/wutta/wuttaweb
|
|
@@ -39,7 +39,7 @@ Requires-Dist: pyramid-tm
|
|
|
39
39
|
Requires-Dist: pyramid>=2
|
|
40
40
|
Requires-Dist: waitress
|
|
41
41
|
Requires-Dist: webhelpers2
|
|
42
|
-
Requires-Dist: wuttjamaican[db]>=0.
|
|
42
|
+
Requires-Dist: wuttjamaican[db]>=0.24.0
|
|
43
43
|
Requires-Dist: zope-sqlalchemy>=1.5
|
|
44
44
|
Provides-Extra: continuum
|
|
45
45
|
Requires-Dist: wutta-continuum; extra == 'continuum'
|
|
@@ -48,6 +48,8 @@ Requires-Dist: furo; extra == 'docs'
|
|
|
48
48
|
Requires-Dist: sphinx; extra == 'docs'
|
|
49
49
|
Requires-Dist: sphinxcontrib-programoutput; extra == 'docs'
|
|
50
50
|
Provides-Extra: tests
|
|
51
|
+
Requires-Dist: pylint; extra == 'tests'
|
|
52
|
+
Requires-Dist: pytest; extra == 'tests'
|
|
51
53
|
Requires-Dist: pytest-cov; extra == 'tests'
|
|
52
54
|
Requires-Dist: tox; extra == 'tests'
|
|
53
55
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Configuration file for the Sphinx documentation builder.
|
|
2
|
+
#
|
|
3
|
+
# For the full list of built-in configuration values, see the documentation:
|
|
4
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
5
|
+
|
|
6
|
+
# -- Project information -----------------------------------------------------
|
|
7
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
|
8
|
+
|
|
9
|
+
from importlib.metadata import version as get_version
|
|
10
|
+
|
|
11
|
+
project = "WuttaWeb"
|
|
12
|
+
copyright = "2024, Lance Edgar"
|
|
13
|
+
author = "Lance Edgar"
|
|
14
|
+
release = get_version("WuttaWeb")
|
|
15
|
+
|
|
16
|
+
# -- General configuration ---------------------------------------------------
|
|
17
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
18
|
+
|
|
19
|
+
extensions = [
|
|
20
|
+
"sphinx.ext.autodoc",
|
|
21
|
+
"sphinx.ext.intersphinx",
|
|
22
|
+
"sphinx.ext.viewcode",
|
|
23
|
+
"sphinx.ext.todo",
|
|
24
|
+
"sphinxcontrib.programoutput",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
templates_path = ["_templates"]
|
|
28
|
+
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
|
29
|
+
|
|
30
|
+
intersphinx_mapping = {
|
|
31
|
+
"colander": ("https://docs.pylonsproject.org/projects/colander/en/latest/", None),
|
|
32
|
+
"deform": ("https://docs.pylonsproject.org/projects/deform/en/latest/", None),
|
|
33
|
+
"fanstatic": ("https://www.fanstatic.org/en/latest/", None),
|
|
34
|
+
"pyramid": ("https://docs.pylonsproject.org/projects/pyramid/en/latest/", None),
|
|
35
|
+
"python": ("https://docs.python.org/3/", None),
|
|
36
|
+
"rattail-manual": ("https://docs.wuttaproject.org/rattail-manual/", None),
|
|
37
|
+
"sqlalchemy": ("http://docs.sqlalchemy.org/en/latest/", None),
|
|
38
|
+
"webhelpers2": ("https://webhelpers2.readthedocs.io/en/latest/", None),
|
|
39
|
+
"wuttjamaican": ("https://docs.wuttaproject.org/wuttjamaican/", None),
|
|
40
|
+
"wutta-continuum": ("https://docs.wuttaproject.org/wutta-continuum/", None),
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# -- Options for HTML output -------------------------------------------------
|
|
45
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
|
46
|
+
|
|
47
|
+
html_theme = "furo"
|
|
48
|
+
html_static_path = ["_static"]
|
|
@@ -11,6 +11,12 @@ project.
|
|
|
11
11
|
|
|
12
12
|
.. _test coverage: https://buildbot.rattailproject.org/coverage/wuttaweb/
|
|
13
13
|
|
|
14
|
+
.. image:: https://img.shields.io/badge/linting-pylint-yellowgreen
|
|
15
|
+
:target: https://github.com/pylint-dev/pylint
|
|
16
|
+
|
|
17
|
+
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
|
18
|
+
:target: https://github.com/psf/black
|
|
19
|
+
|
|
14
20
|
However as you can see..the API should be fairly well documented but
|
|
15
21
|
the narrative docs are pretty scant. That will eventually change.
|
|
16
22
|
|
|
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "WuttaWeb"
|
|
9
|
-
version = "0.23.
|
|
9
|
+
version = "0.23.2"
|
|
10
10
|
description = "Web App for Wutta Framework"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]
|
|
@@ -44,7 +44,7 @@ dependencies = [
|
|
|
44
44
|
"pyramid_tm",
|
|
45
45
|
"waitress",
|
|
46
46
|
"WebHelpers2",
|
|
47
|
-
"WuttJamaican[db]>=0.
|
|
47
|
+
"WuttJamaican[db]>=0.24.0",
|
|
48
48
|
"zope.sqlalchemy>=1.5",
|
|
49
49
|
]
|
|
50
50
|
|
|
@@ -52,7 +52,7 @@ dependencies = [
|
|
|
52
52
|
[project.optional-dependencies]
|
|
53
53
|
continuum = ["Wutta-Continuum"]
|
|
54
54
|
docs = ["Sphinx", "furo", "sphinxcontrib-programoutput"]
|
|
55
|
-
tests = ["pytest-cov", "tox"]
|
|
55
|
+
tests = ["pylint", "pytest", "pytest-cov", "tox"]
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
[project.entry-points."fanstatic.libraries"]
|
|
@@ -48,10 +48,11 @@ class WebAppProvider(AppProvider):
|
|
|
48
48
|
registers some :term:`email templates <email template>` for the
|
|
49
49
|
app, etc.
|
|
50
50
|
"""
|
|
51
|
-
email_modules = ['wuttaweb.emails']
|
|
52
|
-
email_templates = ['wuttaweb:email-templates']
|
|
53
51
|
|
|
54
|
-
|
|
52
|
+
email_modules = ["wuttaweb.emails"]
|
|
53
|
+
email_templates = ["wuttaweb:email-templates"]
|
|
54
|
+
|
|
55
|
+
def get_web_handler(self):
|
|
55
56
|
"""
|
|
56
57
|
Get the configured "web" handler for the app.
|
|
57
58
|
|
|
@@ -64,11 +65,13 @@ class WebAppProvider(AppProvider):
|
|
|
64
65
|
|
|
65
66
|
:returns: Instance of :class:`~wuttaweb.handler.WebHandler`.
|
|
66
67
|
"""
|
|
67
|
-
if
|
|
68
|
-
spec = self.config.get(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
if "web" not in self.app.handlers:
|
|
69
|
+
spec = self.config.get(
|
|
70
|
+
f"{self.appname}.web.handler_spec",
|
|
71
|
+
default="wuttaweb.handler:WebHandler",
|
|
72
|
+
)
|
|
73
|
+
self.app.handlers["web"] = self.app.load_object(spec)(self.config)
|
|
74
|
+
return self.app.handlers["web"]
|
|
72
75
|
|
|
73
76
|
|
|
74
77
|
def make_wutta_config(settings, config_maker=None, **kwargs):
|
|
@@ -96,23 +99,25 @@ def make_wutta_config(settings, config_maker=None, **kwargs):
|
|
|
96
99
|
|
|
97
100
|
If this config file path cannot be discovered, an error is raised.
|
|
98
101
|
"""
|
|
99
|
-
wutta_config = settings.get(
|
|
102
|
+
wutta_config = settings.get("wutta_config")
|
|
100
103
|
if not wutta_config:
|
|
101
104
|
|
|
102
105
|
# validate config file path
|
|
103
|
-
path = settings.get(
|
|
106
|
+
path = settings.get("wutta.config")
|
|
104
107
|
if not path or not os.path.exists(path):
|
|
105
|
-
raise ValueError(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
+
raise ValueError(
|
|
109
|
+
"Please set 'wutta.config' in [app:main] "
|
|
110
|
+
"section of config to the path of your "
|
|
111
|
+
"config file. Lame, but necessary."
|
|
112
|
+
)
|
|
108
113
|
|
|
109
114
|
# make config, add to settings
|
|
110
115
|
config_maker = config_maker or make_config
|
|
111
116
|
wutta_config = config_maker(path, **kwargs)
|
|
112
|
-
settings[
|
|
117
|
+
settings["wutta_config"] = wutta_config
|
|
113
118
|
|
|
114
119
|
# configure database sessions
|
|
115
|
-
if hasattr(wutta_config,
|
|
120
|
+
if hasattr(wutta_config, "appdb_engine"):
|
|
116
121
|
wuttaweb.db.Session.configure(bind=wutta_config.appdb_engine)
|
|
117
122
|
|
|
118
123
|
return wutta_config
|
|
@@ -128,10 +133,11 @@ def make_pyramid_config(settings):
|
|
|
128
133
|
:returns: Instance of
|
|
129
134
|
:class:`pyramid:pyramid.config.Configurator`.
|
|
130
135
|
"""
|
|
131
|
-
settings.setdefault(
|
|
132
|
-
settings.setdefault(
|
|
133
|
-
settings.setdefault(
|
|
134
|
-
|
|
136
|
+
settings.setdefault("fanstatic.versioning", "true")
|
|
137
|
+
settings.setdefault("mako.directories", ["wuttaweb:templates"])
|
|
138
|
+
settings.setdefault(
|
|
139
|
+
"pyramid_deform.template_search_path", "wuttaweb:templates/deform"
|
|
140
|
+
)
|
|
135
141
|
|
|
136
142
|
# update settings per current theme
|
|
137
143
|
establish_theme(settings)
|
|
@@ -142,26 +148,26 @@ def make_pyramid_config(settings):
|
|
|
142
148
|
pyramid_config.set_security_policy(WuttaSecurityPolicy())
|
|
143
149
|
|
|
144
150
|
# require CSRF token for POST
|
|
145
|
-
pyramid_config.set_default_csrf_options(
|
|
146
|
-
|
|
147
|
-
|
|
151
|
+
pyramid_config.set_default_csrf_options(
|
|
152
|
+
require_csrf=True, token="_csrf", header="X-CSRF-TOKEN"
|
|
153
|
+
)
|
|
148
154
|
|
|
149
|
-
pyramid_config.include(
|
|
150
|
-
pyramid_config.include(
|
|
151
|
-
pyramid_config.include(
|
|
152
|
-
pyramid_config.include(
|
|
153
|
-
pyramid_config.include(
|
|
155
|
+
pyramid_config.include("pyramid_beaker")
|
|
156
|
+
pyramid_config.include("pyramid_deform")
|
|
157
|
+
pyramid_config.include("pyramid_fanstatic")
|
|
158
|
+
pyramid_config.include("pyramid_mako")
|
|
159
|
+
pyramid_config.include("pyramid_tm")
|
|
154
160
|
|
|
155
161
|
# add some permissions magic
|
|
156
|
-
pyramid_config.add_directive(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
162
|
+
pyramid_config.add_directive(
|
|
163
|
+
"add_wutta_permission_group", "wuttaweb.auth.add_permission_group"
|
|
164
|
+
)
|
|
165
|
+
pyramid_config.add_directive("add_wutta_permission", "wuttaweb.auth.add_permission")
|
|
160
166
|
|
|
161
167
|
return pyramid_config
|
|
162
168
|
|
|
163
169
|
|
|
164
|
-
def main(global_config, **settings):
|
|
170
|
+
def main(global_config, **settings): # pylint: disable=unused-argument
|
|
165
171
|
"""
|
|
166
172
|
Make and return the WSGI application, per given settings.
|
|
167
173
|
|
|
@@ -176,12 +182,12 @@ def main(global_config, **settings):
|
|
|
176
182
|
``poser.web.app:main``), similar to this one but with additional
|
|
177
183
|
views and other config.
|
|
178
184
|
"""
|
|
179
|
-
wutta_config = make_wutta_config(settings)
|
|
185
|
+
wutta_config = make_wutta_config(settings) # pylint: disable=unused-variable
|
|
180
186
|
pyramid_config = make_pyramid_config(settings)
|
|
181
187
|
|
|
182
|
-
pyramid_config.include(
|
|
183
|
-
pyramid_config.include(
|
|
184
|
-
pyramid_config.include(
|
|
188
|
+
pyramid_config.include("wuttaweb.static")
|
|
189
|
+
pyramid_config.include("wuttaweb.subscribers")
|
|
190
|
+
pyramid_config.include("wuttaweb.views")
|
|
185
191
|
|
|
186
192
|
return pyramid_config.make_wsgi_app()
|
|
187
193
|
|
|
@@ -226,21 +232,21 @@ def make_wsgi_app(main_app=None, config=None):
|
|
|
226
232
|
app = config.get_app()
|
|
227
233
|
|
|
228
234
|
# extract pyramid settings
|
|
229
|
-
settings = config.get_dict(
|
|
235
|
+
settings = config.get_dict("app:main")
|
|
230
236
|
|
|
231
237
|
# keep same config object
|
|
232
|
-
settings[
|
|
238
|
+
settings["wutta_config"] = config
|
|
233
239
|
|
|
234
240
|
# determine the app factory
|
|
235
241
|
if isinstance(main_app, str):
|
|
236
|
-
|
|
242
|
+
factory = app.load_object(main_app)
|
|
237
243
|
elif callable(main_app):
|
|
238
|
-
|
|
244
|
+
factory = main_app
|
|
239
245
|
else:
|
|
240
246
|
raise ValueError("main_app must be spec or callable")
|
|
241
247
|
|
|
242
248
|
# construct a pyramid app "per usual"
|
|
243
|
-
return
|
|
249
|
+
return factory({}, **settings)
|
|
244
250
|
|
|
245
251
|
|
|
246
252
|
def make_asgi_app(main_app=None, config=None):
|
|
@@ -270,15 +276,15 @@ def establish_theme(settings):
|
|
|
270
276
|
will update ``settings['mako.directories']`` such that the theme's
|
|
271
277
|
template path is listed first.
|
|
272
278
|
"""
|
|
273
|
-
config = settings[
|
|
279
|
+
config = settings["wutta_config"]
|
|
274
280
|
|
|
275
281
|
theme = get_effective_theme(config)
|
|
276
|
-
settings[
|
|
282
|
+
settings["wuttaweb.theme"] = theme
|
|
277
283
|
|
|
278
|
-
directories = settings[
|
|
284
|
+
directories = settings["mako.directories"]
|
|
279
285
|
if isinstance(directories, str):
|
|
280
286
|
directories = config.parse_list(directories)
|
|
281
287
|
|
|
282
288
|
path = get_theme_template_path(config)
|
|
283
289
|
directories.insert(0, path)
|
|
284
|
-
settings[
|
|
290
|
+
settings["mako.directories"] = directories
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
################################################################################
|
|
3
3
|
#
|
|
4
4
|
# wuttaweb -- Web App for Wutta Framework
|
|
5
|
-
# Copyright © 2024 Lance Edgar
|
|
5
|
+
# Copyright © 2024-2025 Lance Edgar
|
|
6
6
|
#
|
|
7
7
|
# This file is part of Wutta Framework.
|
|
8
8
|
#
|
|
@@ -24,8 +24,6 @@
|
|
|
24
24
|
Auth Utility Logic
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
-
import re
|
|
28
|
-
|
|
29
27
|
from pyramid.authentication import SessionAuthenticationHelper
|
|
30
28
|
from pyramid.request import RequestLocalCache
|
|
31
29
|
from pyramid.security import remember, forget
|
|
@@ -107,44 +105,53 @@ class WuttaSecurityPolicy:
|
|
|
107
105
|
self.identity_cache = RequestLocalCache(self.load_identity)
|
|
108
106
|
self.db_session = db_session or Session()
|
|
109
107
|
|
|
110
|
-
def load_identity(self, request):
|
|
111
|
-
|
|
108
|
+
def load_identity(self, request): # pylint: disable=empty-docstring
|
|
109
|
+
""" """
|
|
110
|
+
config = request.registry.settings["wutta_config"]
|
|
112
111
|
app = config.get_app()
|
|
113
112
|
model = app.model
|
|
114
113
|
|
|
115
114
|
# fetch user uuid from current session
|
|
116
115
|
uuid = self.session_helper.authenticated_userid(request)
|
|
117
116
|
if not uuid:
|
|
118
|
-
return
|
|
117
|
+
return None
|
|
119
118
|
|
|
120
119
|
# fetch user object from db
|
|
121
120
|
user = self.db_session.get(model.User, uuid)
|
|
122
121
|
if not user:
|
|
123
|
-
return
|
|
122
|
+
return None
|
|
124
123
|
|
|
125
124
|
return user
|
|
126
125
|
|
|
127
|
-
def identity(self, request):
|
|
126
|
+
def identity(self, request): # pylint: disable=empty-docstring
|
|
127
|
+
""" """
|
|
128
128
|
return self.identity_cache.get_or_create(request)
|
|
129
129
|
|
|
130
|
-
def authenticated_userid(self, request):
|
|
130
|
+
def authenticated_userid(self, request): # pylint: disable=empty-docstring
|
|
131
|
+
""" """
|
|
131
132
|
user = self.identity(request)
|
|
132
133
|
if user is not None:
|
|
133
134
|
return user.uuid
|
|
135
|
+
return None
|
|
134
136
|
|
|
135
|
-
def remember(self, request, userid, **kw):
|
|
137
|
+
def remember(self, request, userid, **kw): # pylint: disable=empty-docstring
|
|
138
|
+
""" """
|
|
136
139
|
return self.session_helper.remember(request, userid, **kw)
|
|
137
140
|
|
|
138
|
-
def forget(self, request, **kw):
|
|
141
|
+
def forget(self, request, **kw): # pylint: disable=empty-docstring
|
|
142
|
+
""" """
|
|
139
143
|
return self.session_helper.forget(request, **kw)
|
|
140
144
|
|
|
141
|
-
def permits(
|
|
145
|
+
def permits( # pylint: disable=unused-argument,empty-docstring
|
|
146
|
+
self, request, context, permission
|
|
147
|
+
):
|
|
148
|
+
""" """
|
|
142
149
|
|
|
143
150
|
# nb. root user can do anything
|
|
144
|
-
if getattr(request,
|
|
151
|
+
if getattr(request, "is_root", False):
|
|
145
152
|
return True
|
|
146
153
|
|
|
147
|
-
config = request.registry.settings[
|
|
154
|
+
config = request.registry.settings["wutta_config"]
|
|
148
155
|
app = config.get_app()
|
|
149
156
|
auth = app.get_auth_handler()
|
|
150
157
|
user = self.identity(request)
|
|
@@ -183,14 +190,16 @@ def add_permission_group(pyramid_config, groupkey, label=None, overwrite=True):
|
|
|
183
190
|
|
|
184
191
|
See also :func:`add_permission()`.
|
|
185
192
|
"""
|
|
186
|
-
config = pyramid_config.get_settings()[
|
|
193
|
+
config = pyramid_config.get_settings()["wutta_config"]
|
|
187
194
|
app = config.get_app()
|
|
195
|
+
|
|
188
196
|
def action():
|
|
189
|
-
perms = pyramid_config.get_settings().get(
|
|
197
|
+
perms = pyramid_config.get_settings().get("wutta_permissions", {})
|
|
190
198
|
if overwrite or groupkey not in perms:
|
|
191
|
-
group = perms.setdefault(groupkey, {
|
|
192
|
-
group[
|
|
193
|
-
pyramid_config.add_settings({
|
|
199
|
+
group = perms.setdefault(groupkey, {"key": groupkey})
|
|
200
|
+
group["label"] = label or app.make_title(groupkey)
|
|
201
|
+
pyramid_config.add_settings({"wutta_permissions": perms})
|
|
202
|
+
|
|
194
203
|
pyramid_config.action(None, action)
|
|
195
204
|
|
|
196
205
|
|
|
@@ -229,13 +238,15 @@ def add_permission(pyramid_config, groupkey, key, label=None):
|
|
|
229
238
|
|
|
230
239
|
See also :func:`add_permission_group()`.
|
|
231
240
|
"""
|
|
241
|
+
|
|
232
242
|
def action():
|
|
233
|
-
config = pyramid_config.get_settings()[
|
|
243
|
+
config = pyramid_config.get_settings()["wutta_config"]
|
|
234
244
|
app = config.get_app()
|
|
235
|
-
perms = pyramid_config.get_settings().get(
|
|
236
|
-
group = perms.setdefault(groupkey, {
|
|
237
|
-
group.setdefault(
|
|
238
|
-
perm = group.setdefault(
|
|
239
|
-
perm[
|
|
240
|
-
pyramid_config.add_settings({
|
|
245
|
+
perms = pyramid_config.get_settings().get("wutta_permissions", {})
|
|
246
|
+
group = perms.setdefault(groupkey, {"key": groupkey})
|
|
247
|
+
group.setdefault("label", app.make_title(groupkey))
|
|
248
|
+
perm = group.setdefault("perms", {}).setdefault(key, {"key": key})
|
|
249
|
+
perm["label"] = label or app.make_title(key)
|
|
250
|
+
pyramid_config.add_settings({"wutta_permissions": perms})
|
|
251
|
+
|
|
241
252
|
pyramid_config.action(None, action)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
################################################################################
|
|
3
3
|
#
|
|
4
4
|
# wuttaweb -- Web App for Wutta Framework
|
|
5
|
-
# Copyright © 2024 Lance Edgar
|
|
5
|
+
# Copyright © 2024-2025 Lance Edgar
|
|
6
6
|
#
|
|
7
7
|
# This file is part of Wutta Framework.
|
|
8
8
|
#
|
|
@@ -35,12 +35,12 @@ from wuttjamaican.cli import wutta_typer
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
@wutta_typer.command()
|
|
38
|
-
def webapp(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
def webapp( # pylint: disable=unused-argument
|
|
39
|
+
ctx: typer.Context,
|
|
40
|
+
auto_reload: Annotated[
|
|
41
|
+
bool,
|
|
42
|
+
typer.Option("--reload", "-r", help="Auto-reload web app when files change."),
|
|
43
|
+
] = False,
|
|
44
44
|
):
|
|
45
45
|
"""
|
|
46
46
|
Run the configured web app
|
|
@@ -52,34 +52,38 @@ def webapp(
|
|
|
52
52
|
sys.stderr.write("no config files found!\n")
|
|
53
53
|
sys.exit(1)
|
|
54
54
|
|
|
55
|
-
runner = config.get(f
|
|
56
|
-
if runner ==
|
|
55
|
+
runner = config.get(f"{config.appname}.web.app.runner", default="pserve")
|
|
56
|
+
if runner == "pserve":
|
|
57
57
|
|
|
58
58
|
# run pserve
|
|
59
|
-
argv = [
|
|
60
|
-
if ctx.params[
|
|
61
|
-
argv.append(
|
|
59
|
+
argv = ["pserve", f"file+ini:{config.files_read[0]}"]
|
|
60
|
+
if ctx.params["auto_reload"]:
|
|
61
|
+
argv.append("--reload")
|
|
62
62
|
pserve.main(argv=argv)
|
|
63
63
|
|
|
64
|
-
elif runner ==
|
|
64
|
+
elif runner == "uvicorn":
|
|
65
65
|
|
|
66
|
-
import uvicorn
|
|
66
|
+
import uvicorn # pylint: disable=import-error,import-outside-toplevel
|
|
67
67
|
|
|
68
68
|
# need service details from config
|
|
69
|
-
spec = config.require(f
|
|
69
|
+
spec = config.require(f"{config.appname}.web.app.spec")
|
|
70
70
|
kw = {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
"host": config.get(f"{config.appname}.web.app.host", default="127.0.0.1"),
|
|
72
|
+
"port": config.get_int(f"{config.appname}.web.app.port", default=8000),
|
|
73
|
+
"reload": ctx.params["auto_reload"],
|
|
74
|
+
"reload_dirs": config.get_list(f"{config.appname}.web.app.reload_dirs"),
|
|
75
|
+
"factory": config.get_bool(
|
|
76
|
+
f"{config.appname}.web.app.factory", default=False
|
|
77
|
+
),
|
|
78
|
+
"interface": config.get(
|
|
79
|
+
f"{config.appname}.web.app.interface", default="auto"
|
|
80
|
+
),
|
|
81
|
+
"root_path": config.get(f"{config.appname}.web.app.root_path", default=""),
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
# also must inject our config files to env, since there is no
|
|
81
85
|
# other way to specify when running via uvicorn
|
|
82
|
-
os.environ[
|
|
86
|
+
os.environ["WUTTA_CONFIG_FILES"] = os.pathsep.join(config.files_read)
|
|
83
87
|
|
|
84
88
|
# run uvicorn
|
|
85
89
|
uvicorn.run(spec, **kw)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
################################################################################
|
|
3
3
|
#
|
|
4
4
|
# wuttaweb -- Web App for Wutta Framework
|
|
5
|
-
# Copyright © 2024 Lance Edgar
|
|
5
|
+
# Copyright © 2024-2025 Lance Edgar
|
|
6
6
|
#
|
|
7
7
|
# This file is part of Wutta Framework.
|
|
8
8
|
#
|
|
@@ -35,9 +35,12 @@ class WuttaWebConfigExtension(WuttaConfigExtension):
|
|
|
35
35
|
only relevant if Wutta-Continuum is installed and enabled. For
|
|
36
36
|
more info see :doc:`wutta-continuum:index`.
|
|
37
37
|
"""
|
|
38
|
-
key = 'wuttaweb'
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
key = "wuttaweb"
|
|
40
|
+
|
|
41
|
+
def configure(self, config): # pylint: disable=empty-docstring
|
|
41
42
|
""" """
|
|
42
|
-
config.setdefault(
|
|
43
|
-
|
|
43
|
+
config.setdefault(
|
|
44
|
+
"wutta_continuum.wutta_plugin_spec",
|
|
45
|
+
"wuttaweb.db.continuum:WuttaWebContinuumPlugin",
|
|
46
|
+
)
|