Flask-Exts 0.2.1__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. {flask_exts-0.2.1 → flask_exts-0.2.2}/CHANGES.rst +13 -0
  2. {flask_exts-0.2.1 → flask_exts-0.2.2}/PKG-INFO +7 -4
  3. {flask_exts-0.2.1 → flask_exts-0.2.2}/README.rst +3 -3
  4. {flask_exts-0.2.1 → flask_exts-0.2.2}/docs/configure.rst +0 -12
  5. {flask_exts-0.2.1 → flask_exts-0.2.2}/docs/index.rst +8 -1
  6. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap4/app.py +1 -3
  7. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap5/app.py +3 -4
  8. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/admin_views.py +8 -8
  9. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/build_sample.py +12 -2
  10. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/make_app.py +8 -14
  11. flask_exts-0.2.2/examples/demo/models/__init__.py +12 -0
  12. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/models/user.py +3 -3
  13. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/models/user_keyword.py +4 -4
  14. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/views/author_view.py +2 -4
  15. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/views/keyword_view.py +1 -2
  16. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/views/post_view.py +8 -2
  17. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/views/tag_view.py +1 -2
  18. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/views/tree_view.py +15 -8
  19. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/views/user_view.py +2 -3
  20. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/fileadmin/make_app.py +7 -1
  21. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/rediscli.py +2 -1
  22. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/sqla-custom-inline-forms/make_app.py +18 -13
  23. flask_exts-0.2.2/examples/sqla-custom-inline-forms/models/__init__.py +1 -0
  24. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/sqla-custom-inline-forms/views/image_view.py +1 -3
  25. {flask_exts-0.2.1 → flask_exts-0.2.2}/pyproject.toml +7 -0
  26. flask_exts-0.2.2/src/flask_exts/__about__.py +1 -0
  27. flask_exts-0.2.2/src/flask_exts/admin/admin.py +117 -0
  28. flask_exts-0.2.2/src/flask_exts/admin/menu.py +280 -0
  29. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/model/filters.py +27 -72
  30. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/model/typefmt.py +4 -5
  31. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/model/view.py +7 -15
  32. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/sqla/ajax.py +42 -20
  33. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/sqla/form.py +20 -45
  34. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/sqla/typefmt.py +0 -12
  35. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/sqla/view.py +334 -273
  36. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/view.py +22 -33
  37. flask_exts-0.2.2/src/flask_exts/commands.py +34 -0
  38. flask_exts-0.2.2/src/flask_exts/datastore/sqla/__init__.py +9 -0
  39. flask_exts-0.2.2/src/flask_exts/datastore/sqla/models/role.py +16 -0
  40. flask_exts-0.2.2/src/flask_exts/datastore/sqla/models/user.py +38 -0
  41. flask_exts-0.2.2/src/flask_exts/datastore/sqla/models/user_role.py +11 -0
  42. flask_exts-0.2.2/src/flask_exts/datastore/sqla/models/webauthn.py +37 -0
  43. flask_exts-0.2.2/src/flask_exts/datastore/sqla/orm.py +14 -0
  44. flask_exts-0.2.2/src/flask_exts/decorators/__init__.py +2 -0
  45. flask_exts-0.2.2/src/flask_exts/decorators/auth_required_decorator.py +47 -0
  46. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/fields/__init__.py +2 -1
  47. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/fields/datetime.py +6 -2
  48. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/fields/sqla.py +2 -2
  49. flask_exts-0.2.2/src/flask_exts/manager.py +74 -0
  50. flask_exts-0.2.2/src/flask_exts/proxies.py +17 -0
  51. flask_exts-0.2.2/src/flask_exts/security/__init__.py +6 -0
  52. flask_exts-0.2.2/src/flask_exts/security/authorize/__init__.py +1 -0
  53. flask_exts-0.2.2/src/flask_exts/security/authorize/base.py +21 -0
  54. flask_exts-0.2.2/src/flask_exts/security/authorize/casbin_authorizer.py +118 -0
  55. flask_exts-0.2.2/src/flask_exts/security/authorize/casbin_sqlalchemy_adapter/__init__.py +1 -0
  56. flask_exts-0.2.2/src/flask_exts/security/authorize/casbin_sqlalchemy_adapter/adapter.py +245 -0
  57. flask_exts-0.2.2/src/flask_exts/security/core.py +43 -0
  58. {flask_exts-0.2.1/src/flask_exts/users → flask_exts-0.2.2/src/flask_exts/security}/forms/login.py +1 -1
  59. {flask_exts-0.2.1/src/flask_exts/users → flask_exts-0.2.2/src/flask_exts/security}/forms/profile.py +1 -1
  60. {flask_exts-0.2.1/src/flask_exts/users → flask_exts-0.2.2/src/flask_exts/security}/forms/register.py +1 -1
  61. flask_exts-0.2.2/src/flask_exts/security/mixins/webauthn_mixin.py +9 -0
  62. flask_exts-0.2.2/src/flask_exts/security/principal/identity.py +37 -0
  63. flask_exts-0.2.2/src/flask_exts/security/principal/identity_context.py +52 -0
  64. flask_exts-0.2.2/src/flask_exts/security/principal/permission.py +297 -0
  65. flask_exts-0.2.2/src/flask_exts/security/principal/principal.py +197 -0
  66. flask_exts-0.2.2/src/flask_exts/security/usercenter/base.py +21 -0
  67. flask_exts-0.2.1/src/flask_exts/users/default_usercenter.py → flask_exts-0.2.2/src/flask_exts/security/usercenter/memory_usercenter.py +20 -12
  68. flask_exts-0.2.2/src/flask_exts/security/usercenter/sqla_usercenter.py +88 -0
  69. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/js/filters.js +18 -8
  70. flask_exts-0.2.2/src/flask_exts/static/js/form.js +680 -0
  71. flask_exts-0.2.2/src/flask_exts/static/js/helper.js +7 -0
  72. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/js/modal.js +4 -1
  73. flask_exts-0.2.2/src/flask_exts/static/js/security/base64.js +127 -0
  74. flask_exts-0.2.2/src/flask_exts/static/js/security/webauthn.js +193 -0
  75. {flask_exts-0.2.1/src/flask_exts/static/vendor/x-editable → flask_exts-0.2.2/src/flask_exts/static/vendor/vanilla-editor}/css/bootstrap-editable.css +0 -4
  76. flask_exts-0.2.2/src/flask_exts/static/vendor/vanilla-editor/js/bootstrap-editable.min.js +1 -0
  77. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/admin/base.html +11 -6
  78. flask_exts-0.2.2/src/flask_exts/templates/admin/index.html +11 -0
  79. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/admin/model/list.html +3 -10
  80. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/admin/model/modals/create.html +0 -3
  81. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/admin/model/modals/details.html +0 -1
  82. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/admin/model/modals/edit.html +0 -5
  83. flask_exts-0.2.2/src/flask_exts/templates/index.html +22 -0
  84. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/macro/actions.html +1 -4
  85. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/macro/inline.html +2 -2
  86. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/macro/layout.html +1 -3
  87. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/macro/menu.html +11 -19
  88. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/macro/row_actions.html +5 -5
  89. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/macro/vendor.html +2 -2
  90. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/views/file/list.html +4 -9
  91. flask_exts-0.2.1/src/flask_exts/_types.py → flask_exts-0.2.2/src/flask_exts/types.py +1 -1
  92. flask_exts-0.2.2/src/flask_exts/utils/authorize.py +21 -0
  93. flask_exts-0.2.2/src/flask_exts/utils/jwt.py +34 -0
  94. flask_exts-0.2.2/src/flask_exts/utils/request_user.py +64 -0
  95. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/utils/sqla.py +0 -5
  96. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/views/file_view/base_file_view.py +2 -4
  97. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/views/index_view.py +5 -5
  98. flask_exts-0.2.2/src/flask_exts/views/rediscli_view.py +190 -0
  99. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/views/user_view.py +15 -26
  100. flask_exts-0.2.2/tests/__init__.py +1 -0
  101. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/admin/sqla/test_basic.py +292 -558
  102. flask_exts-0.2.2/tests/admin/sqla/test_form_rules.py +93 -0
  103. flask_exts-0.2.2/tests/admin/sqla/test_inlineform.py +196 -0
  104. flask_exts-0.2.2/tests/admin/sqla/test_multi_pk.py +135 -0
  105. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/admin/sqla/test_translation.py +8 -8
  106. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/admin/test_base.py +127 -60
  107. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/admin/test_model.py +1 -2
  108. flask_exts-0.2.2/tests/conftest.py +40 -0
  109. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/forms/test_fields.py +2 -2
  110. flask_exts-0.2.2/tests/models/__init__.py +6 -0
  111. flask_exts-0.2.2/tests/models/message.py +15 -0
  112. flask_exts-0.2.2/tests/models/model1.py +175 -0
  113. flask_exts-0.2.2/tests/models/multpk.py +7 -0
  114. flask_exts-0.2.2/tests/models/polymorphic.py +35 -0
  115. flask_exts-0.2.2/tests/models/tree.py +7 -0
  116. flask_exts-0.2.2/tests/models/user.py +41 -0
  117. flask_exts-0.2.2/tests/security/authorize/casbin_adapter/rbac_model.conf +14 -0
  118. flask_exts-0.2.2/tests/security/authorize/casbin_adapter/rbac_policy.csv +6 -0
  119. flask_exts-0.2.2/tests/security/authorize/casbin_adapter/test_sqlalchemy_adapter.py +392 -0
  120. flask_exts-0.2.2/tests/security/authorize/casbin_files/authz_policy.csv +11 -0
  121. flask_exts-0.2.2/tests/security/authorize/casbin_files/rbac_model.conf +14 -0
  122. flask_exts-0.2.2/tests/security/authorize/casbin_files/rbac_policy.csv +8 -0
  123. flask_exts-0.2.2/tests/security/authorize/test_casbin_auth.py +146 -0
  124. flask_exts-0.2.2/tests/security/test_principal.py +705 -0
  125. flask_exts-0.2.2/tests/template/__init__.py +0 -0
  126. flask_exts-0.2.2/tests/template/bootstrap4/__init__.py +0 -0
  127. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap4/test_render_pager.py +3 -8
  128. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap4/test_render_pagination.py +3 -7
  129. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap4/test_render_table.py +3 -60
  130. flask_exts-0.2.2/tests/template/bootstrap5/__init__.py +0 -0
  131. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap5/conftest.py +0 -4
  132. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap5/test_render_pagination.py +3 -7
  133. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/test_base.py +5 -4
  134. flask_exts-0.2.2/tests/utils/test_request_user.py +80 -0
  135. flask_exts-0.2.2/tests/views/files/dummy.txt +0 -0
  136. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/views/test_user_view.py +3 -1
  137. flask_exts-0.2.1/examples/demo/models/__init__.py +0 -24
  138. flask_exts-0.2.1/examples/demo/templates/admin/index.html +0 -4
  139. flask_exts-0.2.1/examples/demo/user_center.py +0 -54
  140. flask_exts-0.2.1/examples/multiple_admins/app.py +0 -34
  141. flask_exts-0.2.1/examples/multiple_admins/templates/admin/index.html +0 -7
  142. flask_exts-0.2.1/examples/multiple_admins/templates/first.html +0 -4
  143. flask_exts-0.2.1/examples/multiple_admins/templates/second.html +0 -4
  144. flask_exts-0.2.1/examples/sqla-custom-inline-forms/models/__init__.py +0 -14
  145. flask_exts-0.2.1/src/flask_exts/__about__.py +0 -1
  146. flask_exts-0.2.1/src/flask_exts/admin/admin.py +0 -263
  147. flask_exts-0.2.1/src/flask_exts/admin/menu.py +0 -168
  148. flask_exts-0.2.1/src/flask_exts/manager.py +0 -39
  149. flask_exts-0.2.1/src/flask_exts/static/js/form.js +0 -665
  150. flask_exts-0.2.1/src/flask_exts/static/js/helpers.js +0 -12
  151. flask_exts-0.2.1/src/flask_exts/static/vendor/x-editable/js/bootstrap-editable.min.js +0 -2
  152. flask_exts-0.2.1/src/flask_exts/templates/admin/admin.html +0 -5
  153. flask_exts-0.2.1/src/flask_exts/templates/admin/index.html +0 -6
  154. flask_exts-0.2.1/src/flask_exts/users/__init__.py +0 -15
  155. flask_exts-0.2.1/src/flask_exts/users/usercenter.py +0 -19
  156. flask_exts-0.2.1/src/flask_exts/views/rediscli_view.py +0 -191
  157. flask_exts-0.2.1/tests/admin/sqla/conftest.py +0 -20
  158. flask_exts-0.2.1/tests/admin/sqla/test_form_rules.py +0 -96
  159. flask_exts-0.2.1/tests/admin/sqla/test_inlineform.py +0 -289
  160. flask_exts-0.2.1/tests/admin/sqla/test_multi_pk.py +0 -173
  161. flask_exts-0.2.1/tests/conftest.py +0 -33
  162. flask_exts-0.2.1/tests/template/bootstrap4/conftest.py +0 -17
  163. {flask_exts-0.2.1 → flask_exts-0.2.2}/.github/workflows/release.yml +0 -0
  164. {flask_exts-0.2.1 → flask_exts-0.2.2}/.gitignore +0 -0
  165. {flask_exts-0.2.1 → flask_exts-0.2.2}/.readthedocs.yaml +0 -0
  166. {flask_exts-0.2.1 → flask_exts-0.2.2}/LICENSE.rst +0 -0
  167. {flask_exts-0.2.1 → flask_exts-0.2.2}/babel/babel.cfg +0 -0
  168. {flask_exts-0.2.1 → flask_exts-0.2.2}/babel/babel.sh +0 -0
  169. {flask_exts-0.2.1 → flask_exts-0.2.2}/babel/messages.pot +0 -0
  170. {flask_exts-0.2.1 → flask_exts-0.2.2}/docs/Makefile +0 -0
  171. {flask_exts-0.2.1 → flask_exts-0.2.2}/docs/_static/logo.png +0 -0
  172. {flask_exts-0.2.1 → flask_exts-0.2.2}/docs/changes.rst +0 -0
  173. {flask_exts-0.2.1 → flask_exts-0.2.2}/docs/conf.py +0 -0
  174. {flask_exts-0.2.1 → flask_exts-0.2.2}/docs/develop.rst +0 -0
  175. {flask_exts-0.2.1 → flask_exts-0.2.2}/docs/examples.rst +0 -0
  176. {flask_exts-0.2.1 → flask_exts-0.2.2}/docs/make.bat +0 -0
  177. {flask_exts-0.2.1 → flask_exts-0.2.2}/docs/requirements.txt +0 -0
  178. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/README.rst +0 -0
  179. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap4/static/favicon.ico +0 -0
  180. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap4/templates/bootswatch.html +0 -0
  181. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap4/templates/flash.html +0 -0
  182. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap4/templates/form.html +0 -0
  183. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap4/templates/icon.html +0 -0
  184. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap4/templates/icons.html +0 -0
  185. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap4/templates/index.html +0 -0
  186. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap4/templates/mybase.html +0 -0
  187. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap4/templates/nav.html +0 -0
  188. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap4/templates/pagination.html +0 -0
  189. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap4/templates/table.html +0 -0
  190. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap5/static/favicon.ico +0 -0
  191. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap5/templates/bootswatch.html +0 -0
  192. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap5/templates/flash.html +0 -0
  193. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap5/templates/form.html +0 -0
  194. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap5/templates/icon.html +0 -0
  195. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap5/templates/icons.html +0 -0
  196. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap5/templates/index.html +0 -0
  197. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap5/templates/mybase.html +0 -0
  198. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap5/templates/nav.html +0 -0
  199. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap5/templates/pagination.html +0 -0
  200. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/bootstrap5/templates/table.html +0 -0
  201. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/__init__.py +0 -0
  202. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/models/author.py +0 -0
  203. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/models/keyword.py +0 -0
  204. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/models/post.py +0 -0
  205. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/models/post_tag.py +0 -0
  206. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/models/tag.py +0 -0
  207. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/models/tree.py +0 -0
  208. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/templates/my/index.html +0 -0
  209. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/templates/tree_list.html +0 -0
  210. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/demo/views/my_view.py +0 -0
  211. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/fileadmin/__init__.py +0 -0
  212. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/fileadmin/file_view.py +0 -0
  213. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/fileadmin/tmp/bbb/a.txt +0 -0
  214. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/simple.py +0 -0
  215. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/sqla-custom-inline-forms/__init__.py +0 -0
  216. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/sqla-custom-inline-forms/data.py +0 -0
  217. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/sqla-custom-inline-forms/models/model.py +0 -0
  218. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/sqla-custom-inline-forms/templates/admin/admin.html +0 -0
  219. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/sqla-custom-inline-forms/templates/field_list.html +0 -0
  220. {flask_exts-0.2.1 → flask_exts-0.2.2}/examples/sqla-custom-inline-forms/templates/locations.html +0 -0
  221. {flask_exts-0.2.1 → flask_exts-0.2.2}/requirements/build.in +0 -0
  222. {flask_exts-0.2.1 → flask_exts-0.2.2}/requirements/test.in +0 -0
  223. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/__init__.py +0 -0
  224. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/__init__.py +0 -0
  225. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/actions.py +0 -0
  226. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/model/__init__.py +0 -0
  227. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/model/ajax.py +0 -0
  228. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/model/form.py +0 -0
  229. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/row_action.py +0 -0
  230. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/sqla/__init__.py +0 -0
  231. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/admin/sqla/filters.py +0 -0
  232. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/babel/__init__.py +0 -0
  233. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/babel/selector.py +0 -0
  234. {flask_exts-0.2.1/src/flask_exts/translations → flask_exts-0.2.2/src/flask_exts/datastore}/__init__.py +0 -0
  235. {flask_exts-0.2.1/tests/admin → flask_exts-0.2.2/src/flask_exts/datastore/sqla/models}/__init__.py +0 -0
  236. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/__init__.py +0 -0
  237. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/fields/ajax_select.py +0 -0
  238. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/fields/file.py +0 -0
  239. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/fields/inline.py +0 -0
  240. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/fields/json.py +0 -0
  241. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/fields/recaptcha.py +0 -0
  242. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/fields/select.py +0 -0
  243. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/fields/switch.py +0 -0
  244. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/fields/taglist.py +0 -0
  245. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/form/__init__.py +0 -0
  246. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/form/base_form.py +0 -0
  247. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/form/csrf.py +0 -0
  248. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/form/flask_form.py +0 -0
  249. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/form/meta.py +0 -0
  250. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/form/session_csrf.py +0 -0
  251. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/rules.py +0 -0
  252. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/utils.py +0 -0
  253. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/validators/__init__.py +0 -0
  254. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/validators/field_list.py +0 -0
  255. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/validators/file.py +0 -0
  256. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/validators/recaptcha.py +0 -0
  257. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/validators/sqla.py +0 -0
  258. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/widgets/__init__.py +0 -0
  259. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/widgets/checkbox.py +0 -0
  260. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/widgets/datetime.py +0 -0
  261. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/widgets/file.py +0 -0
  262. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/widgets/inline.py +0 -0
  263. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/widgets/recaptcha.py +0 -0
  264. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/widgets/render_template.py +0 -0
  265. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/widgets/select.py +0 -0
  266. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/forms/widgets/xeditable.py +0 -0
  267. {flask_exts-0.2.1/src/flask_exts/users → flask_exts-0.2.2/src/flask_exts/security}/forms/__init__.py +0 -0
  268. {flask_exts-0.2.1/src/flask_exts/users → flask_exts-0.2.2/src/flask_exts/security}/forms/mixins.py +0 -0
  269. {flask_exts-0.2.1/tests/admin/sqla → flask_exts-0.2.2/src/flask_exts/security/usercenter}/__init__.py +0 -0
  270. {flask_exts-0.2.1/tests → flask_exts-0.2.2/src/flask_exts/security/utils}/__init__.py +0 -0
  271. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/css/admin.css +0 -0
  272. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/css/rediscli.css +0 -0
  273. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/js/actions.js +0 -0
  274. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/js/details_filter.js +0 -0
  275. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/js/rediscli.js +0 -0
  276. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/logo.png +0 -0
  277. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/bootstrap-icons/bootstrap-icons.svg +0 -0
  278. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/bootstrap-icons/font/bootstrap-icons.css +0 -0
  279. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/bootstrap-icons/font/bootstrap-icons.json +0 -0
  280. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/bootstrap-icons/font/bootstrap-icons.min.css +0 -0
  281. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/bootstrap-icons/font/bootstrap-icons.scss +0 -0
  282. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/bootstrap-icons/font/fonts/bootstrap-icons.woff +0 -0
  283. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/bootstrap-icons/font/fonts/bootstrap-icons.woff2 +0 -0
  284. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/bootstrap4/bootstrap.bundle.min.js +0 -0
  285. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/bootstrap4/bootstrap.min.css +0 -0
  286. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/bootstrap5/bootstrap.bundle.min.js +0 -0
  287. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/bootstrap5/bootstrap.min.css +0 -0
  288. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/daterangepicker/daterangepicker.css +0 -0
  289. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/daterangepicker/daterangepicker.js +0 -0
  290. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/jquery/jquery.min.js +0 -0
  291. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/moment.min.js +0 -0
  292. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/select2/select2.min.css +0 -0
  293. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/static/vendor/select2/select2.min.js +0 -0
  294. {flask_exts-0.2.1/src/flask_exts/static/vendor/x-editable → flask_exts-0.2.2/src/flask_exts/static/vendor/vanilla-editor}/img/clear.png +0 -0
  295. {flask_exts-0.2.1/src/flask_exts/static/vendor/x-editable → flask_exts-0.2.2/src/flask_exts/static/vendor/vanilla-editor}/img/loading.gif +0 -0
  296. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/template/__init__.py +0 -0
  297. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/template/theme.py +0 -0
  298. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/template/utils.py +0 -0
  299. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/admin/master.html +0 -0
  300. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/admin/model/create.html +0 -0
  301. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/admin/model/details.html +0 -0
  302. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/admin/model/edit.html +0 -0
  303. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/base.html +0 -0
  304. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/bootstrap4/form.html +0 -0
  305. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/bootstrap4/message.html +0 -0
  306. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/bootstrap4/pagination.html +0 -0
  307. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/bootstrap5/form.html +0 -0
  308. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/bootstrap5/message.html +0 -0
  309. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/layout.html +0 -0
  310. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/macro/form.html +0 -0
  311. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/macro/icon.html +0 -0
  312. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/macro/message.html +0 -0
  313. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/macro/nav.html +0 -0
  314. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/macro/pagination.html +0 -0
  315. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/macro/table.html +0 -0
  316. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/views/file/form.html +0 -0
  317. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/views/file/modals/form.html +0 -0
  318. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/views/rediscli/console.html +0 -0
  319. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/views/rediscli/response.html +0 -0
  320. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/views/user/index.html +0 -0
  321. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/views/user/list.html +0 -0
  322. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/views/user/login.html +0 -0
  323. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/views/user/register.html +0 -0
  324. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/widgets/inline_field_list.html +0 -0
  325. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/templates/widgets/inline_form.html +0 -0
  326. {flask_exts-0.2.1/tests/template → flask_exts-0.2.2/src/flask_exts/translations}/__init__.py +0 -0
  327. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/translations/en/LC_MESSAGES/messages.mo +0 -0
  328. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/translations/en/LC_MESSAGES/messages.po +0 -0
  329. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/translations/zh_CN/LC_MESSAGES/messages.mo +0 -0
  330. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/translations/zh_CN/LC_MESSAGES/messages.po +0 -0
  331. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/utils/__init__.py +0 -0
  332. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/utils/flask.py +0 -0
  333. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/utils/tools.py +0 -0
  334. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/utils/url.py +0 -0
  335. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/views/file_view/__init__.py +0 -0
  336. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/views/file_view/local_file_storage.py +0 -0
  337. {flask_exts-0.2.1 → flask_exts-0.2.2}/src/flask_exts/views/file_view/local_file_view.py +0 -0
  338. {flask_exts-0.2.1/tests/template/bootstrap4 → flask_exts-0.2.2/tests/admin}/__init__.py +0 -0
  339. {flask_exts-0.2.1/tests/template/bootstrap5 → flask_exts-0.2.2/tests/admin/sqla}/__init__.py +0 -0
  340. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/admin/sqla/templates/another_macro.html +0 -0
  341. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/admin/sqla/templates/macro.html +0 -0
  342. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/data/copyleft.gif +0 -0
  343. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/data/copyleft.jpeg +0 -0
  344. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/data/copyleft.jpg +0 -0
  345. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/data/copyleft.png +0 -0
  346. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/data/copyleft.tiff +0 -0
  347. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/forms/test_filefield.py +0 -0
  348. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/forms/test_form.py +0 -0
  349. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/forms/test_uploadfile.py +0 -0
  350. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/funcs.py +0 -0
  351. /flask_exts-0.2.1/tests/views/files/dummy.txt → /flask_exts-0.2.2/tests/security/authorize/__init__.py +0 -0
  352. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap4/test_render_field.py +0 -0
  353. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap4/test_render_form.py +0 -0
  354. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap4/test_render_form_row.py +0 -0
  355. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap4/test_render_hidden_errors.py +0 -0
  356. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap4/test_render_icon_sprite.py +0 -0
  357. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap4/test_render_messages.py +0 -0
  358. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap5/test_base.py +0 -0
  359. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap5/test_render_form.py +0 -0
  360. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap5/test_render_form_row.py +0 -0
  361. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/bootstrap5/test_render_messages.py +0 -0
  362. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/conftest.py +0 -0
  363. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/macros/test_render_breadcrumb_item.py +0 -0
  364. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/macros/test_render_nav_item.py +0 -0
  365. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/template/test_base.py +0 -0
  366. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/templates/method.html +0 -0
  367. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/templates/mock.html +0 -0
  368. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/test_babel.py +0 -0
  369. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/translations/en/LC_MESSAGES/messages.mo +0 -0
  370. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/translations/en/LC_MESSAGES/messages.po +0 -0
  371. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/translations/zh_CN/LC_MESSAGES/messages.po +0 -0
  372. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/utils/test_url.py +0 -0
  373. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/views/test_file_view.py +0 -0
  374. {flask_exts-0.2.1 → flask_exts-0.2.2}/tests/views/test_rediscli_view.py +0 -0
@@ -1,3 +1,16 @@
1
+ v0.2.2
2
+ ------
3
+
4
+ Released 2025-04-09
5
+
6
+ - fix datetimepicker
7
+ - set session = db.session as default if ModelView of sqla init session is None
8
+ - set session = db.session as default if QueryAjaxModelLoader init session is None
9
+ - fix select.ajax for select2@4.1.0
10
+ - fix select in modal
11
+ - add casbin
12
+ - add module: security
13
+
1
14
  v0.2.1
2
15
  ------
3
16
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Flask-Exts
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Flask extensions with admin, SQLAlchemy, babel, forms, fields, widgets, and so on.
5
5
  Project-URL: Documentation, https://flask-exts.readthedocs.io
6
6
  Project-URL: Source, https://github.com/ojso/flask-exts
@@ -41,11 +41,14 @@ Classifier: Programming Language :: Python :: 3.10
41
41
  Classifier: Programming Language :: Python :: 3.11
42
42
  Classifier: Topic :: Software Development :: Build Tools
43
43
  Requires-Python: >=3.10
44
+ Requires-Dist: casbin>=1.0
44
45
  Requires-Dist: flask-babel>=4.0
45
46
  Requires-Dist: flask-login>=0.6
46
47
  Requires-Dist: flask-sqlalchemy>=3.0
47
48
  Requires-Dist: flask>=3.0
49
+ Requires-Dist: pyjwt>=2.0
48
50
  Requires-Dist: tablib>=3.0
51
+ Requires-Dist: webauthn>=2.0
49
52
  Requires-Dist: wtforms>=3.0
50
53
  Provides-Extra: rediscli
51
54
  Requires-Dist: redis>=4.0.0; extra == 'rediscli'
@@ -56,10 +59,10 @@ Flask Exts
56
59
 
57
60
  Flask-Exts is mainly inspired by:
58
61
 
59
- - `WTForms <https://github.com/wtforms/wtforms/>`_
60
- - `Flask-Admin <https://github.com/flask-admin/flask-admin/>`_
62
+ - `Flask-Admin <https://github.com/pallets-eco/flask-admin/>`_
63
+ - `Flask-Security <https://github.com/pallets-eco/flask-security/>`_
61
64
 
62
- Flask-Exts is part rewrited from above and well tested.
65
+ Flask-Exts is partially rewrited from above and well tested.
63
66
 
64
67
  License
65
68
  -------
@@ -3,10 +3,10 @@ Flask Exts
3
3
 
4
4
  Flask-Exts is mainly inspired by:
5
5
 
6
- - `WTForms <https://github.com/wtforms/wtforms/>`_
7
- - `Flask-Admin <https://github.com/flask-admin/flask-admin/>`_
6
+ - `Flask-Admin <https://github.com/pallets-eco/flask-admin/>`_
7
+ - `Flask-Security <https://github.com/pallets-eco/flask-security/>`_
8
8
 
9
- Flask-Exts is part rewrited from above and well tested.
9
+ Flask-Exts is partially rewrited from above and well tested.
10
10
 
11
11
  License
12
12
  -------
@@ -6,8 +6,6 @@ Configuration
6
6
  ==============
7
7
 
8
8
  ========================== =====================================================================
9
- ``BABEL_ENABLED`` Set to ``False`` to disable babel extension.
10
- Default is ``True``.
11
9
  ``BABEL_ACCEPT_LANGUAGES`` Set to ``en;zh`` to bebel's accept languages.
12
10
  Default is ``None``.
13
11
  ``BABEL_DEFAULT_TIMEZONE`` Set to ``Asia/Shanghai`` to babel's default timezone.
@@ -20,17 +18,7 @@ Configuration
20
18
  Default is ``csrf_token``.
21
19
  ``CSRF_TIME_LIMIT`` Max age in seconds for CSRF tokens.
22
20
  Default is ``1800``.
23
- ``TEMPLATE_ENABLED`` Set to ``False`` to disable templating extension.
24
- Default is ``True``.
25
21
  ``TEMPLATE_THEME`` Set to ``theme`` to create custom theme
26
22
  Default is ``template.theme.BootstrapTheme(4)``
27
- ``USER_ENABLED`` Set to ``False`` to disable ``User`` support.
28
- Default is ``True``.
29
- ``ADMIN_ENABLED`` Set to ``False`` to disable ``Admin`` support.
30
- Default is ``True``.
31
- ``USER_CENTER`` set to ``user center`` to create custom user_center
32
- Default is ``users.user_center.DefaultUserCenter()``
33
- ``FLASK_LOGIN_ENABLED`` Set to ``False`` to disable ``Flask-Login``.
34
- Default is ``True``.
35
23
  ========================== =====================================================================
36
24
 
@@ -6,7 +6,14 @@
6
6
  Welcome to Flask-Exts's documentation!
7
7
  ======================================
8
8
 
9
- **Flask-Exts** is a Flask extensions with admin, SQLAlchemy, babel, forms, fields, widgets, and so on.
9
+ **Flask-Exts** is a Flask extensions with SQLAlchemy, babel, forms, fields, widgets, and so on.
10
+
11
+ Flask-Exts is mainly inspired by:
12
+
13
+ - `Flask-Admin <https://github.com/pallets-eco/flask-admin/>`_
14
+ - `Flask-Security <https://github.com/pallets-eco/flask-security/>`_
15
+
16
+ Flask-Exts is partially rewrited from above and well tested.
10
17
 
11
18
  .. _installation:
12
19
 
@@ -1,13 +1,12 @@
1
- # -*- coding: utf-8 -*-
2
1
  from enum import Enum
3
2
  from flask import Flask, render_template, request, flash, redirect, url_for
4
3
  from markupsafe import Markup
5
4
  from wtforms.validators import DataRequired, Length, Regexp
6
5
  from wtforms.fields import *
7
- from flask_sqlalchemy import SQLAlchemy
8
6
  from flask_exts.forms.form import FlaskForm
9
7
  from flask_exts.forms.fields import SwitchField
10
8
  from flask_exts import Manager
9
+ from flask_exts.datastore.sqla import db
11
10
 
12
11
  manager = Manager()
13
12
 
@@ -16,7 +15,6 @@ app.secret_key = 'dev'
16
15
  app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
17
16
  app.config['ADMIN_ENABLED'] = False
18
17
  manager.init_app(app)
19
- db = SQLAlchemy(app)
20
18
 
21
19
  class ExampleForm(FlaskForm):
22
20
  """An example form that contains all the supported bootstrap style form fields."""
@@ -1,19 +1,17 @@
1
1
  from enum import Enum
2
2
  from flask import Flask, render_template, request, flash, redirect, url_for
3
- from flask import current_app
4
3
  from markupsafe import Markup
5
4
  from wtforms.validators import DataRequired, Length, Regexp
6
5
  from wtforms.fields import *
7
- from flask_sqlalchemy import SQLAlchemy
8
6
 
9
7
  from flask_exts.forms.form import FlaskForm
10
8
  from flask_exts.forms.fields import SwitchField
11
9
  from flask_exts import Manager
12
10
  from flask_exts.template.theme import BootstrapTheme
11
+ from flask_exts.datastore.sqla import db
13
12
 
14
13
  theme = BootstrapTheme(version=5)
15
14
 
16
- manager = Manager()
17
15
  app = Flask(__name__)
18
16
  app.secret_key = "dev"
19
17
 
@@ -22,8 +20,9 @@ app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
22
20
  # set bootstrap5
23
21
  app.config["TEMPLATE_THEME"] = theme
24
22
  app.config['ADMIN_ENABLED'] = False
23
+
24
+ manager = Manager()
25
25
  manager.init_app(app)
26
- db = SQLAlchemy(app)
27
26
 
28
27
 
29
28
  class ExampleForm(FlaskForm):
@@ -9,18 +9,18 @@ from flask_exts.admin.menu import MenuLink
9
9
 
10
10
 
11
11
  def add_views(app):
12
- admin = app.extensions["admin"][0]
12
+ admin = app.extensions["manager"].admins[0]
13
13
 
14
14
  admin.add_view(myview)
15
15
  admin.add_view(userview)
16
16
  admin.add_view(keywordview)
17
- admin.add_view(treeview)
18
17
  admin.add_view(authorview)
19
18
  admin.add_view(tagview)
20
19
  admin.add_view(postview)
21
- admin.add_link(MenuLink(name="other", url="/", category="other"))
22
- admin.add_sub_category(name="Links", parent_name="Other")
23
- admin.add_link(MenuLink(name="Back Home", url="/", category="Links"))
24
- admin.add_link(
25
- MenuLink(name="External link", url="http://www.example.com/", category="Links")
26
- )
20
+ admin.add_view(treeview)
21
+ admin.menu.add_category(name="Links")
22
+ admin.menu.add_link(MenuLink(name="Back Home", url="/", category="Links"))
23
+ admin.menu.add_sub_category(name='External',parent_name='Links')
24
+ # admin.menu.add_link(
25
+ # MenuLink(name="External link", url="http://www.example.com/", category="External")
26
+ # )
@@ -1,5 +1,6 @@
1
1
  import random
2
2
  import datetime
3
+ from flask_exts.proxies import current_usercenter
3
4
  from .models import db
4
5
  from .models.author import Author
5
6
  from .models.author import AVAILABLE_USER_TYPES
@@ -7,11 +8,19 @@ from .models.tag import Tag
7
8
  from .models.post import Post
8
9
  from .models.tree import Tree
9
10
  from .models.keyword import Keyword
10
- from .models.user import User
11
+ from .models.user import MyUser
12
+
13
+
14
+ def build_user_admin():
15
+ u, _ = current_usercenter.create_user(
16
+ username="admin", password="admin", email="admin@example.com"
17
+ )
18
+ r, _ = current_usercenter.create_role(name="admin")
19
+ current_usercenter.user_add_role(u, r)
11
20
 
12
21
 
13
22
  def build_sample_userkeyword():
14
- user_log = User()
23
+ user_log = MyUser()
15
24
  user_log.username = "log"
16
25
  user_log.email = "log"
17
26
  user_log.password = "log"
@@ -215,5 +224,6 @@ def build_sample_db():
215
224
  build_sample_userkeyword()
216
225
  build_sample_tree()
217
226
  build_sample_post()
227
+ build_user_admin()
218
228
 
219
229
  return
@@ -1,7 +1,6 @@
1
1
  import os.path as op
2
2
  from flask import Flask
3
3
  from flask_exts import Manager
4
- from .user_center import UserCenter
5
4
 
6
5
 
7
6
  def get_sqlite_path():
@@ -10,11 +9,6 @@ def get_sqlite_path():
10
9
  return database_path
11
10
 
12
11
 
13
- def register_users(app):
14
- user_center = app.config["USER_CENTER"]
15
- user_center.register_user("admin", "admin", "admin@example.com")
16
-
17
-
18
12
  def create_app():
19
13
  app = Flask(__name__)
20
14
  app.config["SECRET_KEY"] = "dev"
@@ -24,9 +18,10 @@ def create_app():
24
18
  # app.config["SQLALCHEMY_ECHO"] = True
25
19
  app.config["DATABASE_FILE"] = get_sqlite_path()
26
20
  app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + app.config["DATABASE_FILE"]
27
-
28
- app.config["USER_CENTER"] = UserCenter()
29
-
21
+ # JWT
22
+ app.config["JWT_SECRET_KEY"] = "SECRET_KEY"
23
+ app.config["JWT_HASH"] = "HS256"
24
+ # app.config["ADMIN_ACCESS_ENABLED"] = False
30
25
  init_app(app)
31
26
 
32
27
  return app
@@ -34,13 +29,13 @@ def create_app():
34
29
 
35
30
  def init_app(app: Flask):
36
31
 
37
- from .models import init_db
38
-
39
- init_db(app)
40
-
41
32
  manager = Manager()
42
33
  manager.init_app(app)
43
34
 
35
+ from .models import init_models
36
+
37
+ init_models()
38
+
44
39
  from .admin_views import add_views
45
40
 
46
41
  add_views(app)
@@ -50,4 +45,3 @@ def init_app(app: Flask):
50
45
  from .build_sample import build_sample_db
51
46
 
52
47
  build_sample_db()
53
- register_users(app)
@@ -0,0 +1,12 @@
1
+ from flask_exts.datastore.sqla import db
2
+
3
+
4
+ def init_models():
5
+ from . import user
6
+ from . import keyword
7
+ from . import user_keyword
8
+ from . import tag
9
+ from . import author
10
+ from . import post
11
+ from . import post_tag
12
+ from . import tree
@@ -5,12 +5,12 @@ from sqlalchemy.orm import mapped_column
5
5
  from sqlalchemy.orm import relationship
6
6
  from sqlalchemy.ext.associationproxy import association_proxy
7
7
  from sqlalchemy.ext.associationproxy import AssociationProxy
8
- from flask_login import UserMixin
9
8
  from . import db
10
9
  from .keyword import Keyword
11
10
  from .user_keyword import UserKeywordAssociation
12
11
 
13
- class User(db.Model, UserMixin):
12
+ class MyUser(db.Model):
13
+ __tablename__="myuser"
14
14
  id: Mapped[int] = mapped_column(primary_key=True)
15
15
  username: Mapped[str]
16
16
  email: Mapped[str]
@@ -21,7 +21,7 @@ class User(db.Model, UserMixin):
21
21
  )
22
22
 
23
23
  user_keyword_associations: Mapped[List["UserKeywordAssociation"]] = relationship(
24
- back_populates="user",
24
+ back_populates="myuser",
25
25
  cascade="all, delete-orphan",
26
26
  )
27
27
 
@@ -10,17 +10,17 @@ from .keyword import Keyword
10
10
 
11
11
  class UserKeywordAssociation(db.Model):
12
12
  __tablename__ = "user_keyword"
13
- user_id = mapped_column(ForeignKey("user.id"), primary_key=True)
13
+ myuser_id = mapped_column(ForeignKey("myuser.id"), primary_key=True)
14
14
  keyword_id = mapped_column(ForeignKey("keyword.id"), primary_key=True)
15
15
  special_key: Mapped[Optional[str]]
16
16
 
17
- user: Mapped["User"] = relationship(back_populates="user_keyword_associations")
17
+ myuser: Mapped["MyUser"] = relationship(back_populates="user_keyword_associations")
18
18
  keyword: Mapped[Keyword] = relationship()
19
19
 
20
20
  # Reference to the "keyword" column inside the "Keyword" object.
21
21
  keyword_value = association_proxy('keyword', 'keyword')
22
22
 
23
- def __init__(self, keyword=None, user=None, special_key=None):
24
- self.user = user
23
+ def __init__(self, keyword=None, myuser=None, special_key=None):
24
+ self.myuser = myuser
25
25
  self.keyword = keyword
26
26
  self.special_key = special_key
@@ -4,12 +4,10 @@ from flask_babel import gettext
4
4
  from flask_exts.admin.sqla.filters import BaseSQLAFilter
5
5
  from flask_exts.admin.sqla.filters import FilterEqual
6
6
  from flask_exts.admin.sqla import ModelView
7
- from ..models import db
8
- from ..models.author import Author,AVAILABLE_USER_TYPES
7
+ from ..models.author import Author, AVAILABLE_USER_TYPES
9
8
  from ..models.post import Post
10
9
 
11
10
 
12
-
13
11
  # Custom filter class
14
12
  class FilterLastNameBrown(BaseSQLAFilter):
15
13
  def apply(self, query, value, alias=None):
@@ -133,4 +131,4 @@ class AuthorView(ModelView):
133
131
  return form
134
132
 
135
133
 
136
- authorview = AuthorView(Author, db.session)
134
+ authorview = AuthorView(Author)
@@ -1,5 +1,4 @@
1
1
  from flask_exts.admin.sqla import ModelView
2
- from ..models import db
3
2
  from ..models.keyword import Keyword
4
3
 
5
4
 
@@ -7,4 +6,4 @@ class KeywordView(ModelView):
7
6
  column_list = ("id", "keyword")
8
7
 
9
8
 
10
- keywordview = KeywordView(Keyword, db.session)
9
+ keywordview = KeywordView(Keyword)
@@ -1,13 +1,13 @@
1
1
  from wtforms import validators
2
2
  from flask_exts.admin.sqla import ModelView
3
3
  from flask_exts.admin.sqla.filters import FilterLike
4
- from ..models import db
5
4
  from ..models.post import Post
6
5
  from ..models.author import Author
7
6
 
8
7
 
9
8
  # Customized Post model admin
10
9
  class PostView(ModelView):
10
+ can_view_details = True
11
11
  column_display_pk = True
12
12
  column_list = [
13
13
  "id",
@@ -24,6 +24,8 @@ class PostView(ModelView):
24
24
  column_default_sort = ("date", True)
25
25
  create_modal = True
26
26
  # edit_modal = True
27
+ # details_modal = True
28
+
27
29
  column_sortable_list = [
28
30
  "id",
29
31
  "title",
@@ -80,8 +82,12 @@ class PostView(ModelView):
80
82
  # },
81
83
  }
82
84
 
85
+ column_descriptions = dict(
86
+ color='favorite color'
87
+ )
88
+
83
89
 
84
90
  # Add views
85
91
 
86
92
 
87
- postview = PostView(Post, db.session)
93
+ postview = PostView(Post)
@@ -1,5 +1,4 @@
1
1
  from flask_exts.admin.sqla import ModelView
2
2
  from ..models.tag import Tag
3
- from ..models import db
4
3
 
5
- tagview = ModelView(Tag, db.session)
4
+ tagview = ModelView(Tag)
@@ -1,20 +1,27 @@
1
1
  from flask_exts.admin.sqla import ModelView
2
- from ..models import db
3
2
  from ..models.tree import Tree
4
3
 
4
+
5
5
  class TreeView(ModelView):
6
- list_template = 'tree_list.html'
6
+ list_template = "tree_list.html"
7
7
  column_auto_select_related = True
8
8
  column_list = [
9
- 'id',
10
- 'name',
11
- 'parent',
9
+ "id",
10
+ "name",
11
+ "parent",
12
+ ]
13
+ form_excluded_columns = [
14
+ "children",
15
+ ]
16
+ column_filters = [
17
+ "id",
18
+ "name",
19
+ "parent",
12
20
  ]
13
- form_excluded_columns = ['children', ]
14
- column_filters = ['id', 'name', 'parent', ]
15
21
 
16
22
  # override the 'render' method to pass your own parameters to the template
17
23
  def render(self, template, **kwargs):
18
24
  return super().render(template, foo="bar", **kwargs)
19
25
 
20
- treeview = TreeView(Tree, db.session, category="tree")
26
+
27
+ treeview = TreeView(Tree)
@@ -1,6 +1,5 @@
1
1
  from flask_exts.admin.sqla import ModelView
2
- from ..models import db
3
- from ..models.user import User
2
+ from ..models.user import MyUser
4
3
 
5
4
 
6
5
  class UserView(ModelView):
@@ -11,4 +10,4 @@ class UserView(ModelView):
11
10
  can_view_details = True
12
11
 
13
12
 
14
- userview = UserView(User, db.session, endpoint="users")
13
+ userview = UserView(MyUser, name="Users", endpoint="users")
@@ -1,6 +1,7 @@
1
1
  from flask import Flask
2
2
  from flask_exts import Manager
3
3
  from .file_view import file_view
4
+ from flask_exts.datastore.sqla import db
4
5
 
5
6
 
6
7
  def create_app():
@@ -8,6 +9,7 @@ def create_app():
8
9
  app = Flask(__name__)
9
10
  app.config["SECRET_KEY"] = "dev"
10
11
  app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
12
+ app.config["ADMIN_ACCESS_ENABLED"] = False
11
13
  init_app(app)
12
14
  return app
13
15
 
@@ -16,11 +18,15 @@ def init_app(app: Flask):
16
18
  manager = Manager()
17
19
  manager.init_app(app)
18
20
 
21
+ with app.app_context():
22
+ # db.drop_all()
23
+ db.create_all()
24
+
19
25
  # Flask views
20
26
  @app.route("/")
21
27
  def index():
22
28
 
23
29
  return '<a href="/admin/">Click me to get to Admin!</a>'
24
30
 
25
- admin = app.extensions["admin"][0]
31
+ admin = app.extensions["manager"].admins[0]
26
32
  admin.add_view(file_view)
@@ -5,11 +5,12 @@ from flask_exts.views.rediscli_view import RedisCli
5
5
 
6
6
  app = Flask(__name__)
7
7
  app.config["SECRET_KEY"] = "dev"
8
+ app.config["ADMIN_ACCESS_ENABLED"] =False
8
9
  # Manager init
9
10
  manager = Manager()
10
11
  manager.init_app(app)
11
12
  # add rediscli
12
- admin = app.extensions["admin"][0]
13
+ admin = app.extensions["manager"].admins[0]
13
14
  redis_view = RedisCli(Redis())
14
15
  admin.add_view(redis_view)
15
16
 
@@ -8,6 +8,7 @@ from flask_exts.admin.menu import MenuLink
8
8
  from .models import db
9
9
 
10
10
  from .views.image_view import locationview
11
+
11
12
  # from .views.my_view import myview
12
13
  # from .views.user_view import userview
13
14
  # from .views.tree_view import treeview
@@ -15,19 +16,23 @@ from .views.image_view import locationview
15
16
  # from .views.post_view import tagview
16
17
 
17
18
  # Figure out base upload path
18
- static_path = op.join(op.dirname(__file__), 'static')
19
+ static_path = op.join(op.dirname(__file__), "static")
20
+
19
21
 
20
22
  def remove_image(image_path):
21
23
  os.remove(op.join(static_path, image_path))
22
24
 
23
- def save_image(file_data,image_path):
25
+
26
+ def save_image(file_data, image_path):
24
27
  file_data.save(op.join(static_path, image_path))
25
28
 
29
+
26
30
  def get_sqlite_path():
27
31
  app_dir = op.realpath(op.dirname(__file__))
28
32
  database_path = op.join(app_dir, "sample.sqlite")
29
33
  return database_path
30
34
 
35
+
31
36
  def create_app():
32
37
  app = Flask(__name__)
33
38
  app.config["SECRET_KEY"] = "dev"
@@ -37,23 +42,19 @@ def create_app():
37
42
  # app.config['SQLALCHEMY_ECHO'] = True
38
43
  app.config["DATABASE_FILE"] = get_sqlite_path()
39
44
  app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + app.config["DATABASE_FILE"]
45
+ app.config["ADMIN_ACCESS_ENABLED"] = False
40
46
  init_app(app)
41
47
 
42
48
  return app
43
49
 
44
50
 
45
51
  def init_app(app: Flask):
46
-
47
- from .models import init_db
48
-
49
- init_db(app)
50
-
51
52
  app.save_image = save_image
52
53
 
53
54
  from .models.model import Location
54
55
 
55
56
  # Register after_delete handler which will delete image file after model gets deleted
56
- @event.listens_for(Location, 'after_delete')
57
+ @event.listens_for(Location, "after_delete")
57
58
  def _handle_image_delete(mapper, conn, target):
58
59
  for location_image in target.images:
59
60
  try:
@@ -65,19 +66,23 @@ def init_app(app: Flask):
65
66
  manager = Manager()
66
67
  manager.init_app(app)
67
68
 
68
- admin = app.extensions["admin"][0]
69
+ admin = app.extensions["manager"].admins[0]
69
70
 
70
71
  admin.add_view(locationview)
71
- admin.add_link(MenuLink(name='locationlist', url='/locationlist', category='List'))
72
+ admin.menu.add_link(
73
+ MenuLink(name="locationlist", url="/locationlist", category="List")
74
+ )
72
75
 
73
- @app.route('/locationlist')
76
+ @app.route("/locationlist")
74
77
  def location_list():
75
78
  from .models.model import Location
76
79
  from flask import render_template
80
+
77
81
  locations = db.session.query(Location).all()
78
- return render_template('locations.html', locations=locations)
82
+ return render_template("locations.html", locations=locations)
79
83
 
80
84
  if not op.exists(app.config["DATABASE_FILE"]):
81
- with app.app_context():
85
+ with app.app_context():
82
86
  from .data import build_sample_db
87
+
83
88
  build_sample_db()
@@ -0,0 +1 @@
1
+ from flask_exts.datastore.sqla import db
@@ -8,7 +8,6 @@ from flask_exts.admin.model.form import InlineFormAdmin
8
8
  from flask_exts.admin.sqla import ModelView
9
9
  from flask_exts.admin.sqla.form import InlineModelConverter
10
10
  from flask_exts.forms.fields.sqla import InlineModelFormList
11
- from ..models import db
12
11
  from ..models.model import ImageType, Location, LocationImage
13
12
 
14
13
 
@@ -41,7 +40,6 @@ class LocationImageInlineModelForm(InlineFormAdmin):
41
40
  form_ajax_refs = {
42
41
  "image_type": QueryAjaxModelLoader(
43
42
  name="image_type",
44
- session=db.session,
45
43
  model=ImageType,
46
44
  fields=("name",),
47
45
  order_by="name",
@@ -72,7 +70,7 @@ class LocationView(ModelView):
72
70
  inline_models = (LocationImageInlineModelForm(),)
73
71
 
74
72
  def __init__(self):
75
- super().__init__(Location, db.session, name="Locations")
73
+ super().__init__(Location, name="Locations")
76
74
 
77
75
 
78
76
  locationview = LocationView()
@@ -32,6 +32,9 @@ dependencies = [
32
32
  "Flask-SQLAlchemy>=3.0",
33
33
  "Flask-Login>=0.6",
34
34
  "tablib>=3.0",
35
+ "casbin>=1.0",
36
+ "PyJWT>=2.0",
37
+ "webauthn>=2.0",
35
38
  ]
36
39
 
37
40
  [project.optional-dependencies]
@@ -45,3 +48,7 @@ Issues = "https://github.com/ojso/flask-exts/issues"
45
48
 
46
49
  [tool.hatch.version]
47
50
  path = "src/flask_exts/__about__.py"
51
+
52
+ [project.entry-points."flask.commands"]
53
+ security = "flask_exts.commands:security_cli"
54
+ datastore = "flask_exts.commands:datastore_cli"
@@ -0,0 +1 @@
1
+ __version__ = "0.2.2"