Flask-Exts 0.3.0__tar.gz → 0.3.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.
- {flask_exts-0.3.0 → flask_exts-0.3.1}/.gitignore +1 -1
- flask_exts-0.3.1/CHANGES.rst +39 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/Makefile +1 -1
- flask_exts-0.3.1/PKG-INFO +111 -0
- flask_exts-0.3.1/README.rst +69 -0
- flask_exts-0.3.1/docs/advanced/database.rst +123 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/pyproject.toml +37 -26
- flask_exts-0.3.1/src/flask_exts/__about__.py +1 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/filter_mixin.py +2 -3
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/view.py +11 -12
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/builtin_extensions/__init__.py +2 -2
- flask_exts-0.3.1/src/flask_exts/builtin_extensions/portal_ext.py +14 -0
- flask_exts-0.3.1/src/flask_exts/builtin_extensions/security_ext.py +24 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/builtin_extensions/usercenter_ext.py +2 -8
- flask_exts-0.3.1/src/flask_exts/datastore/sqla/database.py +154 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/datastore/sqla/query.py +4 -3
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/extension_core/base.py +9 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/extension_core/manager.py +12 -1
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/extension_core/registry.py +1 -1
- flask_exts-0.3.1/src/flask_exts/frontend/plugins/modal_plugin.py +41 -0
- flask_exts-0.3.1/src/flask_exts/portal/index_view.py +25 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/authorizer/simple_authorizer.py +1 -3
- flask_exts-0.3.1/src/flask_exts/static/js/modal.js +621 -0
- flask_exts-0.3.1/src/flask_exts/templates/macro/modal.html +15 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/profile.html +23 -4
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/setup_tfa.html +8 -5
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/show_tfa.html +8 -5
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/verify_tfa.html +1 -1
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/user_view.py +47 -21
- flask_exts-0.3.1/tests/datastore/sqla/test_db.py +171 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/extension_core/test_manager.py +0 -11
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/extension_core/test_registry.py +1 -2
- flask_exts-0.3.1/tests/frontend/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/security/test_authorizer.py +22 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/test_builtin_exts.py +23 -16
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/usercenter/test_user_view.py +41 -18
- flask_exts-0.3.0/CHANGES.rst +0 -32
- flask_exts-0.3.0/PKG-INFO +0 -96
- flask_exts-0.3.0/README.rst +0 -40
- flask_exts-0.3.0/docs/advanced/database.rst +0 -10
- flask_exts-0.3.0/src/flask_exts/__about__.py +0 -1
- flask_exts-0.3.0/src/flask_exts/builtin_extensions/security_ext.py +0 -15
- flask_exts-0.3.0/src/flask_exts/builtin_extensions/startup_ext.py +0 -62
- flask_exts-0.3.0/src/flask_exts/datastore/sqla/database.py +0 -85
- flask_exts-0.3.0/src/flask_exts/frontend/plugins/admin_modal_plugin.py +0 -12
- flask_exts-0.3.0/src/flask_exts/static/js/modal.js +0 -49
- flask_exts-0.3.0/src/flask_exts/templates/macro/modal.html +0 -11
- flask_exts-0.3.0/src/flask_exts/templates/user/verify_tfa_modal.html +0 -13
- flask_exts-0.3.0/tests/datastore/sqla/test_db.py +0 -87
- flask_exts-0.3.0/tests/test_db.py +0 -20
- {flask_exts-0.3.0 → flask_exts-0.3.1}/.editorconfig +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/.github/workflows/docs.yml +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/.github/workflows/release.yml +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/.readthedocs.yaml +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/.vscode/settings.json +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/LICENSE.rst +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/babel/babel.cfg +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/babel/babel.sh +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/babel/messages.pot +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/Makefile +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/_static/logo.png +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/advanced/index.rst +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/api.rst +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/changes.rst +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/conf.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/configure.rst +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/develop.rst +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/examples.rst +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/index.rst +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/make.bat +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/quickstart.rst +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/docs/requirements.txt +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/README.rst +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/admin_views.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/build_sample.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/file_op.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/make_app.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/models/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/models/author.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/models/post.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/models/post_tag.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/models/tag.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/models/tree.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/static/favicon.ico +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/templates/field_list.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/templates/locations.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/templates/tree_list.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/views/author_view.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/views/post_view.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/views/tag_view.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/demo/views/tree_view.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/examples/simple/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/package.json +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/requirements/build.in +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/requirements/develop.in +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/requirements/test.in +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/scripts/copy-vendor.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/base.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/exposer.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/menu.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/actions_mixin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/ajax.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/base.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/core/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/core/columns.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/core/forms.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/core/pagination.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/core/sorting.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/core/values.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/filter.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/operations/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/operations/create.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/operations/delete.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/operations/export.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/operations/read.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/operations/update.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/row_actions.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/type_formatters.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/model/types.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/ajax.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/filter/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/filter/filter_converter.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/filter/filters.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/form/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/form/field_converters.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/form/inline_form.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/form/inline_model_convert.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/form/model_field_convert.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/form/utils.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/sqla_view/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/sqla_view/pagination_handler.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/sqla_view/query_handler.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/sqla_view/relationships_handler.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/sqla_view/sorting_handler.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/type_formatters.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/sqla/view.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/admin/view.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/builtin_extensions/admin_ext.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/builtin_extensions/babel_ext.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/builtin_extensions/database_ext.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/builtin_extensions/emailer_ext.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/builtin_extensions/frontend_ext.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/builtin_extensions/login_ext.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/builtin_extensions/userstore_ext.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/commands.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/constants.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/datastore/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/datastore/sqla/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/datastore/sqla/_db.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/datastore/sqla/query_builders/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/datastore/sqla/query_builders/filter_builder.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/datastore/sqla/query_builders/join_builder.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/datastore/sqla/query_builders/pagination_builder.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/datastore/sqla/query_builders/sort_builder.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/datastore/sqla/utils/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/datastore/sqla/utils/model_mapper.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/datastore/sqla/utils/orm.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/emailer/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/emailer/base.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/emailer/reset_password_sender.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/emailer/sender.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/emailer/smtp.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/emailer/verify_email_sender.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/extension_core/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/fields/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/fields/ajax_select.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/fields/datetime.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/fields/file.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/fields/inline.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/fields/json.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/fields/recaptcha.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/fields/select.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/fields/sqla.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/fields/switch.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/fields/taglist.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/form/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/form/base_form.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/form/csrf.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/form/flask_form.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/form/meta.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/form/session_csrf.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/form/utils.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/validators/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/validators/field_list.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/validators/file.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/validators/recaptcha.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/validators/sqla.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/widgets/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/widgets/checkbox.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/widgets/datetime.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/widgets/editable.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/widgets/file.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/widgets/inline.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/widgets/recaptcha.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/forms/widgets/select.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugin_base.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugin_manager.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/admin_detail_filter_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/admin_filters_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/admin_form_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/admin_list_action_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/admin_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/bootstrap5_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/clipboard_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/copybutton_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/dayjs_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/editable_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/flatpickr_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/qrcode_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/rediscli_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/sphinx_copybutton_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/plugins/tom_select_plugin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/template.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/frontend/theme.py +0 -0
- {flask_exts-0.3.0/src/flask_exts/security/authorizer → flask_exts-0.3.1/src/flask_exts/portal}/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/proxies.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/__init__.py +0 -0
- {flask_exts-0.3.0/src/flask_exts/translations → flask_exts-0.3.1/src/flask_exts/security/authorizer}/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/authorizer/base.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/core.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/exceptions.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/hasher.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/keys.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/plugins/email_change.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/plugins/email_verification.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/plugins/reset_password.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/plugins/two_factor_authentication.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/registry.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/serializer.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/token_action.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/urls.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/security/user_mixin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/signals.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/css/admin.css +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/css/editable.css +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/css/rediscli.css +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/js/copybutton.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/js/detail_filter.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/js/editable.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/js/field-registry.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/js/filters.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/js/form.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/js/list_action.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/js/qrcode.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/js/rediscli.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/js/security/base64.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/js/security/webauthn.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/js/ui-factory.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/logo.png +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/vendor/bootstrap5/bootstrap.bundle.min.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/vendor/bootstrap5/bootstrap.min.css +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/vendor/clipboard/clipboard.min.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/vendor/dayjs/dayjs.min.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/vendor/dayjs/timezone.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/vendor/dayjs/utc.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/vendor/flatpickr/flatpickr.min.css +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/vendor/flatpickr/flatpickr.min.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/vendor/sphinx-copybutton/sphinx-copybutton.css +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/vendor/sphinx-copybutton/sphinx-copybutton.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/vendor/tom-select/tom-select.bootstrap5.min.css +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/static/vendor/tom-select/tom-select.complete.min.js +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/admin/index.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/admin/master.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/admin/model/create.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/admin/model/details.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/admin/model/edit.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/admin/model/list.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/base.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/index.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/layout.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/macro/form.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/macro/icon.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/macro/layout.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/macro/menu.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/macro/message.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/macro/nav.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/macro/pagination.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/change_password.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/email_change.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/forgot_password.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/index.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/list.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/login.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/recovery.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/recovery_codes.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/register.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/reset_password.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/templates/user/verify_email.html +0 -0
- {flask_exts-0.3.0/src/flask_exts/usercenter → flask_exts-0.3.1/src/flask_exts/translations}/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/translations/en/LC_MESSAGES/messages.mo +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/translations/en/LC_MESSAGES/messages.po +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/translations/zh_CN/LC_MESSAGES/messages.mo +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/translations/zh_CN/LC_MESSAGES/messages.po +0 -0
- {flask_exts-0.3.0/tests/admin → flask_exts-0.3.1/src/flask_exts/usercenter}/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/auth_requires.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/core.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/forms/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/forms/change_password.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/forms/email_change.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/forms/forgot_password.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/forms/login.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/forms/recovery.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/forms/register.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/forms/resend_verification.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/forms/reset_password.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/usercenter/forms/two_factor.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/userstore/base.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/userstore/exceptions.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/userstore/sqla/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/userstore/sqla/models/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/userstore/sqla/models/role.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/userstore/sqla/models/user.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/userstore/sqla/models/user_profile.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/userstore/sqla/models/user_role.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/src/flask_exts/userstore/sqla/userstore.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/__init__.py +0 -0
- {flask_exts-0.3.0/tests/extension_core → flask_exts-0.3.1/tests/admin}/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/model/core/test_columns.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/model/test_action_mixin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/model/test_model_view.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/model/test_model_view_csrf.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/sqla/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/sqla/custom_sqla_model_view.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/sqla/templates/another_macro.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/sqla/templates/macro.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/sqla/test_basic.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/sqla/test_filter.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/sqla/test_form.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/sqla/test_inline_model.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/sqla/test_multi_pk.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/sqla/test_primary_string.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/sqla/test_translation.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/test_admin.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/admin/test_view.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/conftest.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/data/copyleft.gif +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/data/copyleft.jpeg +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/data/copyleft.jpg +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/data/copyleft.png +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/data/copyleft.tiff +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/datastore/sqla/test_query.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/emailer/test_base.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/emailer/test_smtp.py +0 -0
- {flask_exts-0.3.0/tests/frontend → flask_exts-0.3.1/tests/extension_core}/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/forms/common.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/forms/fields/test_datetime.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/forms/fields/test_filefield.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/forms/fields/test_inline.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/forms/fields/test_json.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/forms/fields/test_uploadfile.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/forms/fields/test_wtforms.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/forms/form/test_form.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/frontend/conftest.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/frontend/macros/test_render_breadcrumb_item.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/frontend/macros/test_render_nav_item.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/frontend/test_base.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/frontend/test_plugin_manager.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/helper.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/models/__init__.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/models/demo.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/models/multpk.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/models/primary_string_model.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/models/relations.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/models/simple.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/models/tree.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/models/unique.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/security/test_core.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/security/test_tfa.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/security/test_urls.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/templates/method.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/templates/mock.html +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/test_babel.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/test_login.py +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/translations/en/LC_MESSAGES/messages.mo +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/translations/en/LC_MESSAGES/messages.po +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/translations/messages.pot +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/translations/zh_CN/LC_MESSAGES/messages.mo +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/translations/zh_CN/LC_MESSAGES/messages.po +0 -0
- {flask_exts-0.3.0 → flask_exts-0.3.1}/tests/userstore/test_sqla_userstore.py +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
v0.3.1
|
|
2
|
+
------
|
|
3
|
+
|
|
4
|
+
Released 2026-10-11
|
|
5
|
+
|
|
6
|
+
- Improve SQLAlchemy lifecycle management, session configuration, and in-memory SQLite support.
|
|
7
|
+
- Add reusable modal form flows and improve two-factor authentication setup.
|
|
8
|
+
- Allow extensions to provide admin views for automatic registration, and clarify duplicate extension-name errors.
|
|
9
|
+
|
|
10
|
+
v0.3.0
|
|
11
|
+
------
|
|
12
|
+
|
|
13
|
+
Released 2026-10-07
|
|
14
|
+
|
|
15
|
+
- Add user registration, login, logout, profile management, and user-center views.
|
|
16
|
+
- Add email verification, email change, password reset, and recovery workflows.
|
|
17
|
+
- Add a SQLAlchemy-backed user store with user profiles and role management.
|
|
18
|
+
- Add authentication and role-based authorization.
|
|
19
|
+
- Add TOTP-based two-factor authentication and recovery codes.
|
|
20
|
+
|
|
21
|
+
v0.2.0
|
|
22
|
+
------
|
|
23
|
+
|
|
24
|
+
Released 2026-01-07
|
|
25
|
+
|
|
26
|
+
- Add an extension system with registration, dependency management, and lifecycle hooks.
|
|
27
|
+
- Add an admin interface with model views, CRUD operations, filtering, sorting, pagination, and data export.
|
|
28
|
+
- Add SQLAlchemy integration for database access, model forms, relationships, and queries.
|
|
29
|
+
- Add form fields, widgets, validators, and CSRF protection.
|
|
30
|
+
- Add email delivery and notification support.
|
|
31
|
+
- Add frontend plugin management and Bootstrap-based components.
|
|
32
|
+
- Add Babel integration for localization.
|
|
33
|
+
|
|
34
|
+
v0.1.0
|
|
35
|
+
------
|
|
36
|
+
|
|
37
|
+
Released 2024-03-20
|
|
38
|
+
|
|
39
|
+
- Initial release of the Flask-Exts package and documentation.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: Flask-Exts
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Flask extensions with admin, SQLAlchemy, Babel, forms, fields, widgets, and more.
|
|
5
|
+
Project-URL: Documentation, https://flask-exts.readthedocs.io
|
|
6
|
+
Project-URL: Source, https://github.com/ojso/flask-exts
|
|
7
|
+
Project-URL: Homepage, https://github.com/ojso/flask-exts
|
|
8
|
+
Project-URL: Issues, https://github.com/ojso/flask-exts/issues
|
|
9
|
+
Project-URL: Changelog, https://flask-exts.readthedocs.io/en/latest/changes.html
|
|
10
|
+
Author-email: David Hua <david.dong.hua@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE.rst
|
|
13
|
+
Keywords: admin,babel,flask,form,sqlalchemy,widget
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Environment :: Web Environment
|
|
16
|
+
Classifier: Framework :: Flask
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Requires-Dist: email-validator>=2.0
|
|
29
|
+
Requires-Dist: flask-babel>=4.0
|
|
30
|
+
Requires-Dist: flask-login>=0.6
|
|
31
|
+
Requires-Dist: flask>=3.0
|
|
32
|
+
Requires-Dist: pyjwt>=2.0
|
|
33
|
+
Requires-Dist: pyotp>=2.0
|
|
34
|
+
Requires-Dist: sqlalchemy>=2.0
|
|
35
|
+
Requires-Dist: tablib>=3.0
|
|
36
|
+
Requires-Dist: wtforms>=3.0
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: djlint; extra == 'dev'
|
|
39
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
40
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
41
|
+
Description-Content-Type: text/x-rst
|
|
42
|
+
|
|
43
|
+
Flask-Exts
|
|
44
|
+
==========
|
|
45
|
+
|
|
46
|
+
Flask-Exts is a toolkit for building Flask applications with an integrated
|
|
47
|
+
admin interface, SQLAlchemy support, forms, localization, and user-account
|
|
48
|
+
features. It brings common application components together behind a
|
|
49
|
+
dependency-aware extension system. The project is inspired by
|
|
50
|
+
`Flask-Admin <https://github.com/pallets-eco/flask-admin/>`_ and
|
|
51
|
+
`Bootstrap <https://getbootstrap.com/>`_.
|
|
52
|
+
|
|
53
|
+
Highlights
|
|
54
|
+
----------
|
|
55
|
+
|
|
56
|
+
- **Modern frontend:** Uses Bootstrap 5 and native browser APIs, with no
|
|
57
|
+
jQuery dependency or Bootstrap 4 frontend.
|
|
58
|
+
- **Composable extensions:** Initializes extensions in dependency order and
|
|
59
|
+
lets extensions contribute views to the admin interface.
|
|
60
|
+
- **Built-in account features:** Provides authentication, email verification
|
|
61
|
+
and recovery flows, TOTP-based two-factor authentication, and recovery
|
|
62
|
+
codes.
|
|
63
|
+
- **Integrated admin and data tools:** Includes SQLAlchemy integration,
|
|
64
|
+
model management, forms, filtering, and data export.
|
|
65
|
+
- **Localization support:** Integrates Babel for translating application
|
|
66
|
+
interfaces.
|
|
67
|
+
|
|
68
|
+
Installation
|
|
69
|
+
------------
|
|
70
|
+
|
|
71
|
+
Flask-Exts requires Python 3.10 or later. Install it with pip:
|
|
72
|
+
|
|
73
|
+
.. code-block:: console
|
|
74
|
+
|
|
75
|
+
pip install flask-exts
|
|
76
|
+
|
|
77
|
+
Quick start
|
|
78
|
+
-----------
|
|
79
|
+
|
|
80
|
+
Create a Flask application and initialize the extension manager:
|
|
81
|
+
|
|
82
|
+
.. code-block:: python
|
|
83
|
+
|
|
84
|
+
from flask import Flask
|
|
85
|
+
from flask_exts import ExtensionManager
|
|
86
|
+
|
|
87
|
+
app = Flask(__name__)
|
|
88
|
+
app.config["SECRET_KEY"] = "change-this-for-local-development"
|
|
89
|
+
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///app.sqlite"
|
|
90
|
+
|
|
91
|
+
extensions = ExtensionManager()
|
|
92
|
+
extensions.init_app(app)
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
app.run(debug=True)
|
|
96
|
+
|
|
97
|
+
For a complete example with a custom admin view and database setup, see
|
|
98
|
+
``examples/simple``.
|
|
99
|
+
|
|
100
|
+
Documentation
|
|
101
|
+
-------------
|
|
102
|
+
|
|
103
|
+
- `Documentation <https://flask-exts.readthedocs.io/>`_
|
|
104
|
+
- `Runnable examples <https://github.com/ojso/flask-exts/tree/main/examples>`_
|
|
105
|
+
- `Changelog <https://flask-exts.readthedocs.io/en/latest/changes.html>`_
|
|
106
|
+
|
|
107
|
+
License
|
|
108
|
+
-------
|
|
109
|
+
|
|
110
|
+
Flask-Exts is distributed under the terms of the
|
|
111
|
+
`MIT License <https://opensource.org/licenses/MIT>`_.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Flask-Exts
|
|
2
|
+
==========
|
|
3
|
+
|
|
4
|
+
Flask-Exts is a toolkit for building Flask applications with an integrated
|
|
5
|
+
admin interface, SQLAlchemy support, forms, localization, and user-account
|
|
6
|
+
features. It brings common application components together behind a
|
|
7
|
+
dependency-aware extension system. The project is inspired by
|
|
8
|
+
`Flask-Admin <https://github.com/pallets-eco/flask-admin/>`_ and
|
|
9
|
+
`Bootstrap <https://getbootstrap.com/>`_.
|
|
10
|
+
|
|
11
|
+
Highlights
|
|
12
|
+
----------
|
|
13
|
+
|
|
14
|
+
- **Modern frontend:** Uses Bootstrap 5 and native browser APIs, with no
|
|
15
|
+
jQuery dependency or Bootstrap 4 frontend.
|
|
16
|
+
- **Composable extensions:** Initializes extensions in dependency order and
|
|
17
|
+
lets extensions contribute views to the admin interface.
|
|
18
|
+
- **Built-in account features:** Provides authentication, email verification
|
|
19
|
+
and recovery flows, TOTP-based two-factor authentication, and recovery
|
|
20
|
+
codes.
|
|
21
|
+
- **Integrated admin and data tools:** Includes SQLAlchemy integration,
|
|
22
|
+
model management, forms, filtering, and data export.
|
|
23
|
+
- **Localization support:** Integrates Babel for translating application
|
|
24
|
+
interfaces.
|
|
25
|
+
|
|
26
|
+
Installation
|
|
27
|
+
------------
|
|
28
|
+
|
|
29
|
+
Flask-Exts requires Python 3.10 or later. Install it with pip:
|
|
30
|
+
|
|
31
|
+
.. code-block:: console
|
|
32
|
+
|
|
33
|
+
pip install flask-exts
|
|
34
|
+
|
|
35
|
+
Quick start
|
|
36
|
+
-----------
|
|
37
|
+
|
|
38
|
+
Create a Flask application and initialize the extension manager:
|
|
39
|
+
|
|
40
|
+
.. code-block:: python
|
|
41
|
+
|
|
42
|
+
from flask import Flask
|
|
43
|
+
from flask_exts import ExtensionManager
|
|
44
|
+
|
|
45
|
+
app = Flask(__name__)
|
|
46
|
+
app.config["SECRET_KEY"] = "change-this-for-local-development"
|
|
47
|
+
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///app.sqlite"
|
|
48
|
+
|
|
49
|
+
extensions = ExtensionManager()
|
|
50
|
+
extensions.init_app(app)
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
app.run(debug=True)
|
|
54
|
+
|
|
55
|
+
For a complete example with a custom admin view and database setup, see
|
|
56
|
+
``examples/simple``.
|
|
57
|
+
|
|
58
|
+
Documentation
|
|
59
|
+
-------------
|
|
60
|
+
|
|
61
|
+
- `Documentation <https://flask-exts.readthedocs.io/>`_
|
|
62
|
+
- `Runnable examples <https://github.com/ojso/flask-exts/tree/main/examples>`_
|
|
63
|
+
- `Changelog <https://flask-exts.readthedocs.io/en/latest/changes.html>`_
|
|
64
|
+
|
|
65
|
+
License
|
|
66
|
+
-------
|
|
67
|
+
|
|
68
|
+
Flask-Exts is distributed under the terms of the
|
|
69
|
+
`MIT License <https://opensource.org/licenses/MIT>`_.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
Database
|
|
2
|
+
========
|
|
3
|
+
|
|
4
|
+
This page documents the database helpers and SQLAlchemy integration used by Flask-Exts.
|
|
5
|
+
|
|
6
|
+
Overview
|
|
7
|
+
--------
|
|
8
|
+
|
|
9
|
+
Flask-Exts ships a small SQLAlchemy wrapper, :class:`~flask_exts.datastore.sqla.database.SqlaDb`,
|
|
10
|
+
instead of depending on Flask-SQLAlchemy. A ready-to-use singleton is
|
|
11
|
+
exposed as ``db``::
|
|
12
|
+
|
|
13
|
+
from flask_exts.datastore.sqla import db
|
|
14
|
+
|
|
15
|
+
``db`` is created at import time but stays unbound (``db.engine`` and
|
|
16
|
+
``db.session`` are ``None``) until :meth:`~flask_exts.datastore.sqla.database.SqlaDb.init_app`
|
|
17
|
+
runs -- which happens automatically when the built-in ``database`` extension
|
|
18
|
+
initializes. This two-step lifecycle is what lets model modules do::
|
|
19
|
+
|
|
20
|
+
from flask_exts.datastore.sqla import db
|
|
21
|
+
|
|
22
|
+
class User(db.Model):
|
|
23
|
+
__tablename__ = "users"
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
at import time, before any Flask application exists yet.
|
|
27
|
+
|
|
28
|
+
.. warning::
|
|
29
|
+
|
|
30
|
+
``db`` is a **single-application** singleton. Calling ``init_app()``
|
|
31
|
+
while it is still bound to an application -- whether that's the same
|
|
32
|
+
app again or a different one -- raises ``RuntimeError`` rather than
|
|
33
|
+
silently swapping out ``db.engine``/``db.session``. Call
|
|
34
|
+
:meth:`~flask_exts.datastore.sqla.database.SqlaDb.dispose` first if you
|
|
35
|
+
genuinely intend to rebind this instance to a different app (this is
|
|
36
|
+
how the test suite reuses one ``db`` across many short-lived apps,
|
|
37
|
+
calling ``dispose()`` in each test's teardown). For a long-running
|
|
38
|
+
process that serves more than one Flask application at once, create a
|
|
39
|
+
separate ``SqlaDb()`` instance per application instead.
|
|
40
|
+
|
|
41
|
+
Configuration
|
|
42
|
+
-------------
|
|
43
|
+
|
|
44
|
+
.. list-table:: Database configuration options
|
|
45
|
+
:header-rows: 1
|
|
46
|
+
:widths: 28 72
|
|
47
|
+
|
|
48
|
+
* - Name
|
|
49
|
+
- Description
|
|
50
|
+
* - ``SQLALCHEMY_DATABASE_URI``
|
|
51
|
+
- **Required.** SQLAlchemy connection URL, e.g.
|
|
52
|
+
``"sqlite:///app.db"`` or ``"postgresql+psycopg://user:pass@host/db"``.
|
|
53
|
+
``init_app()`` raises ``RuntimeError`` if this is unset.
|
|
54
|
+
* - ``SQLALCHEMY_ECHO``
|
|
55
|
+
- Set to ``True`` to log every SQL statement. Default is ``False``.
|
|
56
|
+
* - ``SQLALCHEMY_ENGINE_OPTIONS``
|
|
57
|
+
- Dict of keyword arguments forwarded to SQLAlchemy's
|
|
58
|
+
``create_engine()``. Use this for ``pool_size``, ``pool_recycle``,
|
|
59
|
+
``pool_pre_ping``, etc. Takes precedence over the two options above
|
|
60
|
+
when keys overlap.
|
|
61
|
+
* - ``SQLALCHEMY_SESSION_OPTIONS``
|
|
62
|
+
- Dict of keyword arguments forwarded to ``sessionmaker()``, e.g.
|
|
63
|
+
``{"expire_on_commit": False}``. Default is ``{}``.
|
|
64
|
+
|
|
65
|
+
In-memory SQLite
|
|
66
|
+
-----------------
|
|
67
|
+
|
|
68
|
+
When ``SQLALCHEMY_DATABASE_URI`` points at an in-memory SQLite database
|
|
69
|
+
(``"sqlite://"`` or any URI containing ``":memory:"``), ``init_app()``
|
|
70
|
+
automatically pins the engine to a single shared connection
|
|
71
|
+
(``poolclass=StaticPool``, ``connect_args={"check_same_thread": False}``).
|
|
72
|
+
|
|
73
|
+
This matters because SQLite's default pooling for in-memory databases hands
|
|
74
|
+
each thread its *own*, separately empty, in-memory database -- so without
|
|
75
|
+
this override, a request served on a different thread than the one that
|
|
76
|
+
created the schema would see no tables at all. This is the same workaround
|
|
77
|
+
Flask-SQLAlchemy applies for this case.
|
|
78
|
+
|
|
79
|
+
You can override the pool explicitly via ``SQLALCHEMY_ENGINE_OPTIONS`` if
|
|
80
|
+
you need different behavior.
|
|
81
|
+
|
|
82
|
+
Long-lived connections (MySQL/PostgreSQL)
|
|
83
|
+
------------------------------------------
|
|
84
|
+
|
|
85
|
+
Database servers often close idle connections after a timeout (MySQL's
|
|
86
|
+
``wait_timeout`` is a common culprit). If your process keeps a connection
|
|
87
|
+
pool open across requests, configure ``pool_pre_ping`` and/or
|
|
88
|
+
``pool_recycle`` to avoid "server has gone away"-style errors::
|
|
89
|
+
|
|
90
|
+
app.config["SQLALCHEMY_ENGINE_OPTIONS"] = {
|
|
91
|
+
"pool_pre_ping": True,
|
|
92
|
+
"pool_recycle": 280,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
Session scope
|
|
96
|
+
-------------
|
|
97
|
+
|
|
98
|
+
``db.session`` is a SQLAlchemy ``scoped_session`` keyed on the current Flask
|
|
99
|
+
application context, matching Flask-SQLAlchemy's behavior: accessing
|
|
100
|
+
``db.session`` inside a request (or any ``with app.app_context():`` block)
|
|
101
|
+
always returns the same session object for that context, and a fresh one
|
|
102
|
+
once the context ends. The session is removed automatically via
|
|
103
|
+
``teardown_appcontext``.
|
|
104
|
+
|
|
105
|
+
Shutdown
|
|
106
|
+
--------
|
|
107
|
+
|
|
108
|
+
:meth:`~flask_exts.datastore.sqla.database.SqlaDb.dispose` releases the
|
|
109
|
+
session registry and the engine's connection pool, and marks the instance
|
|
110
|
+
unbound again (``db.app`` becomes ``None``), allowing a subsequent
|
|
111
|
+
``init_app()`` call with a different app. It tolerates being called with
|
|
112
|
+
no active application context (e.g. from a shutdown hook that isn't
|
|
113
|
+
running inside a request), in which case it skips removing the session
|
|
114
|
+
registry entry (there's nothing addressable without a context) but still
|
|
115
|
+
disposes the engine.
|
|
116
|
+
|
|
117
|
+
API reference
|
|
118
|
+
--------------
|
|
119
|
+
|
|
120
|
+
.. automodule:: flask_exts.datastore.sqla._db
|
|
121
|
+
|
|
122
|
+
.. automodule:: flask_exts.datastore.sqla.database
|
|
123
|
+
:members:
|
|
@@ -5,10 +5,11 @@ build-backend = "hatchling.build"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "Flask-Exts"
|
|
7
7
|
dynamic = ["version"]
|
|
8
|
-
description =
|
|
8
|
+
description = "Flask extensions with admin, SQLAlchemy, Babel, forms, fields, widgets, and more."
|
|
9
9
|
readme = "README.rst"
|
|
10
|
-
license =
|
|
11
|
-
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE.rst"]
|
|
12
|
+
keywords = ["flask", "admin", "sqlalchemy", "babel", "form", "widget"]
|
|
12
13
|
authors = [
|
|
13
14
|
{ name = "David Hua", email = "david.dong.hua@gmail.com" },
|
|
14
15
|
]
|
|
@@ -17,8 +18,9 @@ classifiers = [
|
|
|
17
18
|
"Environment :: Web Environment",
|
|
18
19
|
"Framework :: Flask",
|
|
19
20
|
"Intended Audience :: Developers",
|
|
20
|
-
"
|
|
21
|
-
"Topic :: Software Development ::
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
23
|
+
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
|
22
24
|
"Programming Language :: Python",
|
|
23
25
|
"Programming Language :: Python :: 3",
|
|
24
26
|
"Programming Language :: Python :: 3.10",
|
|
@@ -28,40 +30,49 @@ classifiers = [
|
|
|
28
30
|
]
|
|
29
31
|
requires-python = ">=3.10"
|
|
30
32
|
dependencies = [
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
"Flask>=3.0",
|
|
34
|
+
"WTForms>=3.0",
|
|
35
|
+
"SQLAlchemy>=2.0",
|
|
36
|
+
"flask-babel>=4.0",
|
|
37
|
+
"Flask-Login>=0.6",
|
|
38
|
+
"tablib>=3.0",
|
|
39
|
+
"PyJWT>=2.0",
|
|
40
|
+
"pyotp>=2.0",
|
|
41
|
+
"email-validator>=2.0",
|
|
40
42
|
]
|
|
41
43
|
|
|
44
|
+
[project.optional-dependencies]
|
|
45
|
+
dev = ["pytest", "djlint", "ruff"]
|
|
46
|
+
|
|
42
47
|
[project.urls]
|
|
43
48
|
Documentation = "https://flask-exts.readthedocs.io"
|
|
44
49
|
Source = "https://github.com/ojso/flask-exts"
|
|
45
50
|
Homepage = "https://github.com/ojso/flask-exts"
|
|
46
51
|
Issues = "https://github.com/ojso/flask-exts/issues"
|
|
47
|
-
|
|
48
|
-
[tool.hatch.version]
|
|
49
|
-
path = "src/flask_exts/__about__.py"
|
|
52
|
+
Changelog = "https://flask-exts.readthedocs.io/en/latest/changes.html"
|
|
50
53
|
|
|
51
54
|
[project.entry-points."flask.commands"]
|
|
52
55
|
security = "flask_exts.commands:security_cli"
|
|
53
56
|
datastore = "flask_exts.commands:datastore_cli"
|
|
54
57
|
|
|
58
|
+
[tool.hatch.version]
|
|
59
|
+
path = "src/flask_exts/__about__.py"
|
|
60
|
+
source = "code"
|
|
61
|
+
|
|
62
|
+
[tool.hatch.build.targets.wheel]
|
|
63
|
+
packages = ["src/flask_exts"]
|
|
64
|
+
|
|
55
65
|
[tool.djlint]
|
|
56
|
-
profile="jinja"
|
|
57
|
-
indent=2
|
|
58
|
-
no_indent_inner_html=true
|
|
59
|
-
max_attribute_length=180
|
|
60
|
-
max_line_length=180
|
|
61
|
-
sort_attributes=true
|
|
62
|
-
preserve_blank_lines=true
|
|
63
|
-
ignore="T003"
|
|
66
|
+
profile = "jinja"
|
|
67
|
+
indent = 2
|
|
68
|
+
no_indent_inner_html = true
|
|
69
|
+
max_attribute_length = 180
|
|
70
|
+
max_line_length = 180
|
|
71
|
+
sort_attributes = true
|
|
72
|
+
preserve_blank_lines = true
|
|
73
|
+
ignore = "T003"
|
|
64
74
|
|
|
65
75
|
[tool.pytest.ini_options]
|
|
76
|
+
minversion = "8.0"
|
|
66
77
|
testpaths = ["tests"]
|
|
67
|
-
addopts = "-ra"
|
|
78
|
+
addopts = "-ra --strict-markers --strict-config"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.1"
|
|
@@ -119,7 +119,6 @@ class FilterMixin:
|
|
|
119
119
|
name:
|
|
120
120
|
Name of the field
|
|
121
121
|
"""
|
|
122
|
-
return None
|
|
123
122
|
|
|
124
123
|
def _get_filter_arg(self, index, flt):
|
|
125
124
|
"""
|
|
@@ -148,8 +147,8 @@ class FilterMixin:
|
|
|
148
147
|
|
|
149
148
|
if active_filters:
|
|
150
149
|
for i, pair in enumerate(active_filters):
|
|
151
|
-
idx,
|
|
152
|
-
key = "flt
|
|
150
|
+
idx, _flt_name, value = pair
|
|
151
|
+
key = f"flt{i}_{self._get_filter_arg(idx, self._filters[idx])}"
|
|
153
152
|
kwargs[key] = value
|
|
154
153
|
|
|
155
154
|
return kwargs
|
|
@@ -10,8 +10,8 @@ from flask import (
|
|
|
10
10
|
)
|
|
11
11
|
from flask_babel import gettext, ngettext
|
|
12
12
|
|
|
13
|
-
from ..exposer import expose_url
|
|
14
13
|
from ...security.urls import safe_redirect_target
|
|
14
|
+
from ..exposer import expose_url
|
|
15
15
|
from .base import BaseModelView
|
|
16
16
|
from .type_formatters import BASE_FORMATTERS, DETAIL_FORMATTERS, EXPORT_FORMATTERS
|
|
17
17
|
|
|
@@ -315,17 +315,16 @@ class ModelView(BaseModelView):
|
|
|
315
315
|
|
|
316
316
|
form = self._edit_form_class(obj=model)
|
|
317
317
|
|
|
318
|
-
if form.validate_on_submit():
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
return redirect(self.get_save_return_url(model, is_created=False))
|
|
318
|
+
if form.validate_on_submit() and self.update_model(form, model):
|
|
319
|
+
flash(gettext("Record was successfully saved."), "success")
|
|
320
|
+
if "_add_another" in request.form:
|
|
321
|
+
return redirect(self.get_url(".create_view", url=return_url))
|
|
322
|
+
elif "_continue_editing" in request.form:
|
|
323
|
+
return redirect(
|
|
324
|
+
self.get_url(".edit_view", id=self.get_pk_value(model))
|
|
325
|
+
)
|
|
326
|
+
else:
|
|
327
|
+
return redirect(self.get_save_return_url(model, is_created=False))
|
|
329
328
|
|
|
330
329
|
form_opts = {"widget_args": self.form_widget_args}
|
|
331
330
|
|
|
@@ -4,8 +4,8 @@ from .database_ext import DatabaseExtension
|
|
|
4
4
|
from .emailer_ext import EmailerExtension
|
|
5
5
|
from .frontend_ext import FrontendExtension
|
|
6
6
|
from .login_ext import LoginExtension
|
|
7
|
+
from .portal_ext import PortalExtension
|
|
7
8
|
from .security_ext import SecurityExtension
|
|
8
|
-
from .startup_ext import StartupExtension
|
|
9
9
|
from .usercenter_ext import UserCenterExtension
|
|
10
10
|
from .userstore_ext import UserStoreExtension
|
|
11
11
|
|
|
@@ -19,7 +19,7 @@ BUILTIN_EXTENSIONS = (
|
|
|
19
19
|
UserCenterExtension,
|
|
20
20
|
UserStoreExtension,
|
|
21
21
|
AdminExtension,
|
|
22
|
-
|
|
22
|
+
PortalExtension,
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from ..extension_core.base import Extension
|
|
2
|
+
from ..portal.index_view import IndexView
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class PortalExtension(Extension):
|
|
6
|
+
@property
|
|
7
|
+
def name(self) -> str:
|
|
8
|
+
return "portal"
|
|
9
|
+
|
|
10
|
+
def init_app(self, app):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
def get_admin_views(self):
|
|
14
|
+
return [(IndexView(), False)]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from ..extension_core.base import Extension
|
|
2
|
+
from ..security.core import Security
|
|
3
|
+
from ..signals import user_registered
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SecurityExtension(Extension):
|
|
7
|
+
@property
|
|
8
|
+
def name(self) -> str:
|
|
9
|
+
return "security"
|
|
10
|
+
|
|
11
|
+
def init_app(self, app):
|
|
12
|
+
self._security = Security()
|
|
13
|
+
self._security.init_app(app)
|
|
14
|
+
self._subscribe_signals(app)
|
|
15
|
+
|
|
16
|
+
def get_security(self):
|
|
17
|
+
return self._security
|
|
18
|
+
|
|
19
|
+
def _subscribe_signals(self, app):
|
|
20
|
+
@user_registered.connect_via(app)
|
|
21
|
+
def on_user_registered(sender, user, **extra):
|
|
22
|
+
"""Send an email-verification token to freshly registered users."""
|
|
23
|
+
if user.email and not user.email_verified:
|
|
24
|
+
self._security.get_plugin("email_verification").send_token(user)
|
|
@@ -8,15 +8,9 @@ class UserCenterExtension(Extension):
|
|
|
8
8
|
def name(self) -> str:
|
|
9
9
|
return "usercenter"
|
|
10
10
|
|
|
11
|
-
@property
|
|
12
|
-
def dependencies(self) -> list[str]:
|
|
13
|
-
return ["admin"]
|
|
14
|
-
|
|
15
11
|
def init_app(self, app):
|
|
16
12
|
self._usercenter = UserCenter()
|
|
17
13
|
self._usercenter.init_app(app)
|
|
18
|
-
self.register_views(app)
|
|
19
14
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
admin.register_view(UserView(), is_menu=False)
|
|
15
|
+
def get_admin_views(self):
|
|
16
|
+
return [(UserView(), False)]
|