WuttaWeb 0.15.0__tar.gz → 0.16.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.
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/CHANGELOG.md +19 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/PKG-INFO +4 -3
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/pyproject.toml +4 -3
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/forms/schema.py +10 -1
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/grids/base.py +10 -1
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/menus.py +44 -28
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/base.mako +5 -5
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/views/master.py +29 -2
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/views/upgrades.py +1 -1
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/forms/test_widgets.py +4 -4
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/grids/test_base.py +19 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/test_auth.py +2 -1
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/test_menus.py +11 -2
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/views/test_common.py +1 -1
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/views/test_master.py +35 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/views/test_upgrades.py +2 -2
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/.gitignore +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/COPYING.txt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/README.md +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/Makefile +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/_static/.keepme +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.app.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.auth.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.conf.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.db.continuum.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.db.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.db.sess.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.forms.base.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.forms.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.forms.schema.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.forms.widgets.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.grids.base.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.grids.filters.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.grids.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.handler.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.helpers.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.menus.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.progress.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.static.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.subscribers.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.util.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.views.auth.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.views.base.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.views.common.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.views.essential.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.views.master.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.views.people.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.views.progress.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.views.roles.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.views.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.views.settings.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.views.upgrades.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/api/wuttaweb.views.users.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/conf.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/glossary.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/index.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/make.bat +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/narr/templates/base.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/narr/templates/index.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/narr/templates/lookup.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/docs/narr/templates/overview.rst +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/__init__.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/_version.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/app.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/auth.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/conf.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/db/__init__.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/db/continuum.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/db/sess.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/email/templates/feedback.html.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/email/templates/feedback.txt.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/forms/__init__.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/forms/base.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/forms/widgets.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/grids/__init__.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/grids/filters.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/handler.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/helpers.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/progress.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/static/__init__.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/static/img/favicon.ico +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/static/img/logo.png +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/static/img/testing.png +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/subscribers.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/appinfo/configure.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/appinfo/index.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/auth/change_password.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/auth/login.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/base_meta.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/configure.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/checkbox.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/checkbox_choice.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/checked_password.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/moneyinput.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/password.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/permissions.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/readonly/checkbox.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/readonly/filedownload.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/readonly/notes.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/readonly/objectref.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/readonly/permissions.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/readonly/rolerefs.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/select.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/textarea.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/deform/textinput.pt +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/forbidden.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/form.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/forms/vue_template.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/grids/table_element.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/grids/vue_template.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/home.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/master/configure.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/master/create.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/master/delete.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/master/edit.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/master/form.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/master/index.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/master/view.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/notfound.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/page.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/people/view_profile.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/progress.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/setup.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/upgrade.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/upgrades/configure.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/upgrades/view.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/templates/wutta-components.mako +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/util.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/views/__init__.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/views/auth.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/views/base.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/views/common.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/views/essential.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/views/people.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/views/progress.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/views/roles.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/views/settings.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/src/wuttaweb/views/users.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tasks.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/__init__.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/db/__init__.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/db/test_continuum.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/forms/__init__.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/forms/test_base.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/forms/test_schema.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/grids/__init__.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/grids/test_filters.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/libcache/bb_fontawesome_svg_core.js +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/libcache/bb_free_solid_svg_icons.js +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/libcache/bb_oruga.js +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/libcache/bb_oruga_bulma.css +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/libcache/bb_oruga_bulma.js +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/libcache/bb_vue.js +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/libcache/bb_vue_fontawesome.js +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/libcache/buefy.css +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/libcache/buefy.js +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/libcache/fontawesome.js +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/libcache/vue.js +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/libcache/vue_resource.js +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/test_app.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/test_handler.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/test_helpers.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/test_progress.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/test_static.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/test_subscribers.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/test_util.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/util.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/views/__init__.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/views/test___init__.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/views/test_auth.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/views/test_base.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/views/test_people.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/views/test_progress.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/views/test_roles.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/views/test_settings.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tests/views/test_users.py +0 -0
- {wuttaweb-0.15.0 → wuttaweb-0.16.1}/tox.ini +0 -0
|
@@ -5,6 +5,25 @@ 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.16.1 (2024-12-08)
|
|
9
|
+
|
|
10
|
+
### Fix
|
|
11
|
+
|
|
12
|
+
- refactor to reflect usage of proper UUID values
|
|
13
|
+
|
|
14
|
+
## v0.16.0 (2024-12-05)
|
|
15
|
+
|
|
16
|
+
### Feat
|
|
17
|
+
|
|
18
|
+
- add `get_template_context()` method for master view
|
|
19
|
+
|
|
20
|
+
### Fix
|
|
21
|
+
|
|
22
|
+
- add option for People entry in the Admin menu
|
|
23
|
+
- fix handling of `Upgrade.uuid`
|
|
24
|
+
- improve support for random objects with grid, master view
|
|
25
|
+
- hide CRUD header buttons if master view does not allow
|
|
26
|
+
|
|
8
27
|
## v0.15.0 (2024-11-24)
|
|
9
28
|
|
|
10
29
|
### Feat
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: WuttaWeb
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.1
|
|
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
|
|
7
|
+
Project-URL: Issues, https://forgejo.wuttaproject.org/wutta/wuttaweb/issues
|
|
7
8
|
Project-URL: Changelog, https://forgejo.wuttaproject.org/wutta/wuttaweb/src/branch/master/CHANGELOG.md
|
|
8
|
-
Author-email: Lance Edgar <lance@
|
|
9
|
+
Author-email: Lance Edgar <lance@wuttaproject.org>
|
|
9
10
|
License: GNU GPL v3+
|
|
10
11
|
Classifier: Development Status :: 4 - Beta
|
|
11
12
|
Classifier: Environment :: Web Environment
|
|
@@ -35,7 +36,7 @@ Requires-Dist: pyramid-tm
|
|
|
35
36
|
Requires-Dist: pyramid>=2
|
|
36
37
|
Requires-Dist: waitress
|
|
37
38
|
Requires-Dist: webhelpers2
|
|
38
|
-
Requires-Dist: wuttjamaican[db]>=0.
|
|
39
|
+
Requires-Dist: wuttjamaican[db]>=0.17.1
|
|
39
40
|
Requires-Dist: zope-sqlalchemy>=1.5
|
|
40
41
|
Provides-Extra: continuum
|
|
41
42
|
Requires-Dist: wutta-continuum; extra == 'continuum'
|
|
@@ -6,10 +6,10 @@ build-backend = "hatchling.build"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "WuttaWeb"
|
|
9
|
-
version = "0.
|
|
9
|
+
version = "0.16.1"
|
|
10
10
|
description = "Web App for Wutta Framework"
|
|
11
11
|
readme = "README.md"
|
|
12
|
-
authors = [{name = "Lance Edgar", email = "lance@
|
|
12
|
+
authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]
|
|
13
13
|
license = {text = "GNU GPL v3+"}
|
|
14
14
|
classifiers = [
|
|
15
15
|
"Development Status :: 4 - Beta",
|
|
@@ -42,7 +42,7 @@ dependencies = [
|
|
|
42
42
|
"pyramid_tm",
|
|
43
43
|
"waitress",
|
|
44
44
|
"WebHelpers2",
|
|
45
|
-
"WuttJamaican[db]>=0.
|
|
45
|
+
"WuttJamaican[db]>=0.17.1",
|
|
46
46
|
"zope.sqlalchemy>=1.5",
|
|
47
47
|
]
|
|
48
48
|
|
|
@@ -68,6 +68,7 @@ wuttaweb = "wuttaweb.conf:WuttaWebConfigExtension"
|
|
|
68
68
|
[project.urls]
|
|
69
69
|
Homepage = "https://wuttaproject.org/"
|
|
70
70
|
Repository = "https://forgejo.wuttaproject.org/wutta/wuttaweb"
|
|
71
|
+
Issues = "https://forgejo.wuttaproject.org/wutta/wuttaweb/issues"
|
|
71
72
|
Changelog = "https://forgejo.wuttaproject.org/wutta/wuttaweb/src/branch/master/CHANGELOG.md"
|
|
72
73
|
|
|
73
74
|
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
Form schema types
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
+
import uuid as _uuid
|
|
28
|
+
|
|
27
29
|
import colander
|
|
28
30
|
|
|
29
31
|
from wuttaweb.db import Session
|
|
@@ -246,7 +248,14 @@ class ObjectRef(colander.SchemaType):
|
|
|
246
248
|
|
|
247
249
|
# fetch object from DB
|
|
248
250
|
model = self.app.model
|
|
249
|
-
obj =
|
|
251
|
+
obj = None
|
|
252
|
+
if isinstance(value, _uuid.UUID):
|
|
253
|
+
obj = self.session.get(self.model_class, value)
|
|
254
|
+
else:
|
|
255
|
+
try:
|
|
256
|
+
obj = self.session.get(self.model_class, _uuid.UUID(value))
|
|
257
|
+
except ValueError:
|
|
258
|
+
pass
|
|
250
259
|
|
|
251
260
|
# raise error if not found
|
|
252
261
|
if not obj:
|
|
@@ -1940,6 +1940,15 @@ class Grid:
|
|
|
1940
1940
|
})
|
|
1941
1941
|
return filters
|
|
1942
1942
|
|
|
1943
|
+
def object_to_dict(self, obj):
|
|
1944
|
+
""" """
|
|
1945
|
+
try:
|
|
1946
|
+
dct = dict(obj)
|
|
1947
|
+
except TypeError:
|
|
1948
|
+
dct = dict(obj.__dict__)
|
|
1949
|
+
dct.pop('_sa_instance_state', None)
|
|
1950
|
+
return dct
|
|
1951
|
+
|
|
1943
1952
|
def get_vue_context(self):
|
|
1944
1953
|
"""
|
|
1945
1954
|
Returns a dict of context for the grid, for use with the Vue
|
|
@@ -1976,7 +1985,7 @@ class Grid:
|
|
|
1976
1985
|
original_record = record
|
|
1977
1986
|
|
|
1978
1987
|
# convert record to new dict
|
|
1979
|
-
record =
|
|
1988
|
+
record = self.object_to_dict(record)
|
|
1980
1989
|
|
|
1981
1990
|
# make all values safe for json
|
|
1982
1991
|
record = make_json_safe(record, warn=False)
|
|
@@ -142,38 +142,54 @@ class MenuHandler(GenericHandler):
|
|
|
142
142
|
The return value for this method should be a *single* dict,
|
|
143
143
|
which will ultimately be one element of the final list of
|
|
144
144
|
dicts as described in :class:`MenuHandler`.
|
|
145
|
+
|
|
146
|
+
:param include_people: You can pass this flag to indicate the
|
|
147
|
+
admin menu should contain an entry for the "People" view.
|
|
145
148
|
"""
|
|
149
|
+
items = []
|
|
150
|
+
|
|
151
|
+
if kwargs.get('include_people'):
|
|
152
|
+
items.extend([
|
|
153
|
+
{
|
|
154
|
+
'title': "All People",
|
|
155
|
+
'route': 'people',
|
|
156
|
+
'perm': 'people.list',
|
|
157
|
+
},
|
|
158
|
+
])
|
|
159
|
+
|
|
160
|
+
items.extend([
|
|
161
|
+
{
|
|
162
|
+
'title': "Users",
|
|
163
|
+
'route': 'users',
|
|
164
|
+
'perm': 'users.list',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
'title': "Roles",
|
|
168
|
+
'route': 'roles',
|
|
169
|
+
'perm': 'roles.list',
|
|
170
|
+
},
|
|
171
|
+
{'type': 'sep'},
|
|
172
|
+
{
|
|
173
|
+
'title': "App Info",
|
|
174
|
+
'route': 'appinfo',
|
|
175
|
+
'perm': 'appinfo.list',
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
'title': "Raw Settings",
|
|
179
|
+
'route': 'settings',
|
|
180
|
+
'perm': 'settings.list',
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
'title': "Upgrades",
|
|
184
|
+
'route': 'upgrades',
|
|
185
|
+
'perm': 'upgrades.list',
|
|
186
|
+
},
|
|
187
|
+
])
|
|
188
|
+
|
|
146
189
|
return {
|
|
147
190
|
'title': "Admin",
|
|
148
191
|
'type': 'menu',
|
|
149
|
-
'items':
|
|
150
|
-
{
|
|
151
|
-
'title': "Users",
|
|
152
|
-
'route': 'users',
|
|
153
|
-
'perm': 'users.list',
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
'title': "Roles",
|
|
157
|
-
'route': 'roles',
|
|
158
|
-
'perm': 'roles.list',
|
|
159
|
-
},
|
|
160
|
-
{'type': 'sep'},
|
|
161
|
-
{
|
|
162
|
-
'title': "App Info",
|
|
163
|
-
'route': 'appinfo',
|
|
164
|
-
'perm': 'appinfo.list',
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
'title': "Raw Settings",
|
|
168
|
-
'route': 'settings',
|
|
169
|
-
'perm': 'settings.list',
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
'title': "Upgrades",
|
|
173
|
-
'route': 'upgrades',
|
|
174
|
-
'perm': 'upgrades.list',
|
|
175
|
-
},
|
|
176
|
-
],
|
|
192
|
+
'items': items,
|
|
177
193
|
}
|
|
178
194
|
|
|
179
195
|
##############################
|
|
@@ -563,7 +563,7 @@
|
|
|
563
563
|
|
|
564
564
|
const WuttaFeedbackFormData = {
|
|
565
565
|
referrer: null,
|
|
566
|
-
userUUID: ${json.dumps(request.user.uuid if request.user else None)|n},
|
|
566
|
+
userUUID: ${json.dumps(request.user.uuid.hex if request.user else None)|n},
|
|
567
567
|
userName: ${json.dumps(str(request.user) if request.user else None)|n},
|
|
568
568
|
showDialog: false,
|
|
569
569
|
sendingFeedback: false,
|
|
@@ -682,13 +682,13 @@
|
|
|
682
682
|
<%def name="render_crud_header_buttons()">
|
|
683
683
|
% if master:
|
|
684
684
|
% if master.viewing:
|
|
685
|
-
% if instance_editable and master.has_perm('edit'):
|
|
685
|
+
% if master.editable and instance_editable and master.has_perm('edit'):
|
|
686
686
|
<wutta-button once
|
|
687
687
|
tag="a" href="${master.get_action_url('edit', instance)}"
|
|
688
688
|
icon-left="edit"
|
|
689
689
|
label="Edit This" />
|
|
690
690
|
% endif
|
|
691
|
-
% if instance_deletable and master.has_perm('delete'):
|
|
691
|
+
% if master.deletable and instance_deletable and master.has_perm('delete'):
|
|
692
692
|
<wutta-button once type="is-danger"
|
|
693
693
|
tag="a" href="${master.get_action_url('delete', instance)}"
|
|
694
694
|
icon-left="trash"
|
|
@@ -701,7 +701,7 @@
|
|
|
701
701
|
icon-left="eye"
|
|
702
702
|
label="View This" />
|
|
703
703
|
% endif
|
|
704
|
-
% if instance_deletable and master.has_perm('delete'):
|
|
704
|
+
% if master.deletable and instance_deletable and master.has_perm('delete'):
|
|
705
705
|
<wutta-button once type="is-danger"
|
|
706
706
|
tag="a" href="${master.get_action_url('delete', instance)}"
|
|
707
707
|
icon-left="trash"
|
|
@@ -714,7 +714,7 @@
|
|
|
714
714
|
icon-left="eye"
|
|
715
715
|
label="View This" />
|
|
716
716
|
% endif
|
|
717
|
-
% if instance_editable and master.has_perm('edit'):
|
|
717
|
+
% if master.editable and instance_editable and master.has_perm('edit'):
|
|
718
718
|
<wutta-button once
|
|
719
719
|
tag="a" href="${master.get_action_url('edit', instance)}"
|
|
720
720
|
icon-left="edit"
|
|
@@ -1629,6 +1629,9 @@ class MasterView(View):
|
|
|
1629
1629
|
if 'instance_deletable' not in context:
|
|
1630
1630
|
context['instance_deletable'] = self.is_deletable(instance)
|
|
1631
1631
|
|
|
1632
|
+
# supplement context further if needed
|
|
1633
|
+
context = self.get_template_context(context)
|
|
1634
|
+
|
|
1632
1635
|
# first try the template path most specific to this view
|
|
1633
1636
|
template_prefix = self.get_template_prefix()
|
|
1634
1637
|
mako_path = f'{template_prefix}/{template}.mako'
|
|
@@ -1648,6 +1651,26 @@ class MasterView(View):
|
|
|
1648
1651
|
# let that error raise on up
|
|
1649
1652
|
return render_to_response(mako_path, context, request=self.request)
|
|
1650
1653
|
|
|
1654
|
+
def get_template_context(self, context):
|
|
1655
|
+
"""
|
|
1656
|
+
This method should return the "complete" context for rendering
|
|
1657
|
+
the current view template.
|
|
1658
|
+
|
|
1659
|
+
Default logic for this method returns the given context
|
|
1660
|
+
unchanged.
|
|
1661
|
+
|
|
1662
|
+
You may wish to override to pass extra context to the view
|
|
1663
|
+
template. Check :attr:`viewing` and similar, or
|
|
1664
|
+
``request.current_route_name`` etc. in order to add extra
|
|
1665
|
+
context only for certain view templates.
|
|
1666
|
+
|
|
1667
|
+
:params: context: The context dict we have so far,
|
|
1668
|
+
auto-provided by the master view logic.
|
|
1669
|
+
|
|
1670
|
+
:returns: Final context dict for the template.
|
|
1671
|
+
"""
|
|
1672
|
+
return context
|
|
1673
|
+
|
|
1651
1674
|
def get_fallback_templates(self, template):
|
|
1652
1675
|
"""
|
|
1653
1676
|
Returns a list of "fallback" template paths which may be
|
|
@@ -1995,8 +2018,12 @@ class MasterView(View):
|
|
|
1995
2018
|
:param obj: Model instance object.
|
|
1996
2019
|
"""
|
|
1997
2020
|
route_prefix = self.get_route_prefix()
|
|
1998
|
-
|
|
1999
|
-
|
|
2021
|
+
try:
|
|
2022
|
+
kw = dict([(key, obj[key])
|
|
2023
|
+
for key in self.get_model_key()])
|
|
2024
|
+
except TypeError:
|
|
2025
|
+
kw = dict([(key, getattr(obj, key))
|
|
2026
|
+
for key in self.get_model_key()])
|
|
2000
2027
|
kw.update(kwargs)
|
|
2001
2028
|
return self.request.route_url(f'{route_prefix}.{action}', **kw)
|
|
2002
2029
|
|
|
@@ -217,7 +217,7 @@ class UpgradeView(MasterView):
|
|
|
217
217
|
|
|
218
218
|
def get_upgrade_filepath(self, upgrade, filename=None, create=True):
|
|
219
219
|
""" """
|
|
220
|
-
uuid = upgrade.uuid
|
|
220
|
+
uuid = str(upgrade.uuid)
|
|
221
221
|
path = self.app.get_appdir('data', 'upgrades', uuid[:2], uuid[2:],
|
|
222
222
|
create=create)
|
|
223
223
|
if filename:
|
|
@@ -146,14 +146,14 @@ class TestRoleRefsWidget(WebTestCase):
|
|
|
146
146
|
|
|
147
147
|
# editable values list *excludes* admin (by default)
|
|
148
148
|
html = widget.serialize(field, {admin.uuid, blokes.uuid})
|
|
149
|
-
self.assertNotIn(admin.uuid, html)
|
|
150
|
-
self.assertIn(blokes.uuid, html)
|
|
149
|
+
self.assertNotIn(str(admin.uuid), html)
|
|
150
|
+
self.assertIn(str(blokes.uuid), html)
|
|
151
151
|
|
|
152
152
|
# but admin is included for root user
|
|
153
153
|
self.request.is_root = True
|
|
154
154
|
html = widget.serialize(field, {admin.uuid, blokes.uuid})
|
|
155
|
-
self.assertIn(admin.uuid, html)
|
|
156
|
-
self.assertIn(blokes.uuid, html)
|
|
155
|
+
self.assertIn(str(admin.uuid), html)
|
|
156
|
+
self.assertIn(str(blokes.uuid), html)
|
|
157
157
|
|
|
158
158
|
|
|
159
159
|
class TestUserRefsWidget(WebTestCase):
|
|
@@ -1373,6 +1373,25 @@ class TestGrid(WebTestCase):
|
|
|
1373
1373
|
filters = grid.get_vue_filters()
|
|
1374
1374
|
self.assertEqual(len(filters), 2)
|
|
1375
1375
|
|
|
1376
|
+
def test_object_to_dict(self):
|
|
1377
|
+
grid = self.make_grid()
|
|
1378
|
+
setting = {'name': 'foo', 'value': 'bar'}
|
|
1379
|
+
|
|
1380
|
+
# new dict but with same values
|
|
1381
|
+
dct = grid.object_to_dict(setting)
|
|
1382
|
+
self.assertIsInstance(dct, dict)
|
|
1383
|
+
self.assertIsNot(dct, setting)
|
|
1384
|
+
self.assertEqual(dct, setting)
|
|
1385
|
+
|
|
1386
|
+
# random object, not iterable
|
|
1387
|
+
class MockSetting:
|
|
1388
|
+
def __init__(self, **kw):
|
|
1389
|
+
self.__dict__.update(kw)
|
|
1390
|
+
mock = MockSetting(**setting)
|
|
1391
|
+
dct = grid.object_to_dict(mock)
|
|
1392
|
+
self.assertIsInstance(dct, dict)
|
|
1393
|
+
self.assertEqual(dct, setting)
|
|
1394
|
+
|
|
1376
1395
|
def test_get_vue_context(self):
|
|
1377
1396
|
|
|
1378
1397
|
# empty if no columns defined
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8; -*-
|
|
2
2
|
|
|
3
|
+
import uuid as _uuid
|
|
3
4
|
from unittest import TestCase
|
|
4
5
|
from unittest.mock import MagicMock
|
|
5
6
|
|
|
@@ -90,7 +91,7 @@ class TestWuttaSecurityPolicy(TestCase):
|
|
|
90
91
|
|
|
91
92
|
# invalid identity yields no user
|
|
92
93
|
self.policy = self.make_policy()
|
|
93
|
-
self.policy.remember(self.request,
|
|
94
|
+
self.policy.remember(self.request, _uuid.uuid4()) # random uuid
|
|
94
95
|
user = self.policy.identity(self.request)
|
|
95
96
|
self.assertIsNone(user)
|
|
96
97
|
|
|
@@ -14,8 +14,17 @@ class TestMenuHandler(WebTestCase):
|
|
|
14
14
|
self.handler = mod.MenuHandler(self.config)
|
|
15
15
|
|
|
16
16
|
def test_make_admin_menu(self):
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
|
|
18
|
+
# no people entry by default
|
|
19
|
+
menu = self.handler.make_admin_menu(self.request)
|
|
20
|
+
self.assertIsInstance(menu, dict)
|
|
21
|
+
routes = [item.get('route') for item in menu['items']]
|
|
22
|
+
self.assertNotIn('people', routes)
|
|
23
|
+
|
|
24
|
+
# but we can request it
|
|
25
|
+
menu = self.handler.make_admin_menu(self.request, include_people=True)
|
|
26
|
+
routes = [item.get('route') for item in menu['items']]
|
|
27
|
+
self.assertIn('people', routes)
|
|
19
28
|
|
|
20
29
|
def test_make_menus(self):
|
|
21
30
|
menus = self.handler.make_menus(self.request)
|
|
@@ -88,7 +88,7 @@ class TestCommonView(WebTestCase):
|
|
|
88
88
|
|
|
89
89
|
# basic send, with user
|
|
90
90
|
self.request.user = user
|
|
91
|
-
self.request.POST['user_uuid'] = user.uuid
|
|
91
|
+
self.request.POST['user_uuid'] = str(user.uuid)
|
|
92
92
|
with patch.object(mod, 'Session', return_value=self.session):
|
|
93
93
|
context = view.feedback()
|
|
94
94
|
self.assertEqual(context, {'ok': True})
|
|
@@ -734,6 +734,41 @@ class TestMasterView(WebTestCase):
|
|
|
734
734
|
self.request.matchdict = {'name': 'blarg'}
|
|
735
735
|
self.assertRaises(HTTPNotFound, view.get_instance, session=self.session)
|
|
736
736
|
|
|
737
|
+
def test_get_action_url_for_dict(self):
|
|
738
|
+
model = self.app.model
|
|
739
|
+
setting = {'name': 'foo', 'value': 'bar'}
|
|
740
|
+
with patch.multiple(mod.MasterView, create=True,
|
|
741
|
+
model_class=model.Setting):
|
|
742
|
+
mod.MasterView.defaults(self.pyramid_config)
|
|
743
|
+
view = self.make_view()
|
|
744
|
+
url = view.get_action_url_view(setting, 0)
|
|
745
|
+
self.assertEqual(url, self.request.route_url('settings.view', name='foo'))
|
|
746
|
+
|
|
747
|
+
def test_get_action_url_for_orm_object(self):
|
|
748
|
+
model = self.app.model
|
|
749
|
+
setting = model.Setting(name='foo', value='bar')
|
|
750
|
+
self.session.add(setting)
|
|
751
|
+
self.session.commit()
|
|
752
|
+
with patch.multiple(mod.MasterView, create=True,
|
|
753
|
+
model_class=model.Setting):
|
|
754
|
+
mod.MasterView.defaults(self.pyramid_config)
|
|
755
|
+
view = self.make_view()
|
|
756
|
+
url = view.get_action_url_view(setting, 0)
|
|
757
|
+
self.assertEqual(url, self.request.route_url('settings.view', name='foo'))
|
|
758
|
+
|
|
759
|
+
def test_get_action_url_for_adhoc_object(self):
|
|
760
|
+
model = self.app.model
|
|
761
|
+
class MockSetting:
|
|
762
|
+
def __init__(self, **kw):
|
|
763
|
+
self.__dict__.update(kw)
|
|
764
|
+
setting = MockSetting(name='foo', value='bar')
|
|
765
|
+
with patch.multiple(mod.MasterView, create=True,
|
|
766
|
+
model_class=model.Setting):
|
|
767
|
+
mod.MasterView.defaults(self.pyramid_config)
|
|
768
|
+
view = self.make_view()
|
|
769
|
+
url = view.get_action_url_view(setting, 0)
|
|
770
|
+
self.assertEqual(url, self.request.route_url('settings.view', name='foo'))
|
|
771
|
+
|
|
737
772
|
def test_get_action_url_view(self):
|
|
738
773
|
model = self.app.model
|
|
739
774
|
setting = model.Setting(name='foo', value='bar')
|
|
@@ -127,7 +127,7 @@ class TestUpgradeView(WebTestCase):
|
|
|
127
127
|
self.session.commit()
|
|
128
128
|
|
|
129
129
|
view = self.make_view()
|
|
130
|
-
uuid = upgrade.uuid
|
|
130
|
+
uuid = str(upgrade.uuid)
|
|
131
131
|
|
|
132
132
|
# no filename
|
|
133
133
|
path = view.download_path(upgrade, None)
|
|
@@ -153,7 +153,7 @@ class TestUpgradeView(WebTestCase):
|
|
|
153
153
|
self.session.commit()
|
|
154
154
|
|
|
155
155
|
view = self.make_view()
|
|
156
|
-
uuid = upgrade.uuid
|
|
156
|
+
uuid = str(upgrade.uuid)
|
|
157
157
|
|
|
158
158
|
# no filename
|
|
159
159
|
path = view.get_upgrade_filepath(upgrade)
|
|
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
|
|
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
|
|
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
|