Flask-Exts 0.2.2__tar.gz → 0.2.4__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 (423) hide show
  1. {flask_exts-0.2.2 → flask_exts-0.2.4}/.gitignore +3 -0
  2. {flask_exts-0.2.2 → flask_exts-0.2.4}/CHANGES.rst +20 -0
  3. {flask_exts-0.2.2 → flask_exts-0.2.4}/PKG-INFO +4 -1
  4. {flask_exts-0.2.2 → flask_exts-0.2.4}/docs/configure.rst +3 -2
  5. {flask_exts-0.2.2 → flask_exts-0.2.4}/docs/index.rst +1 -0
  6. flask_exts-0.2.4/docs/user.rst +11 -0
  7. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap4/app.py +2 -2
  8. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap5/app.py +7 -5
  9. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap5/templates/pagination.html +1 -1
  10. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/admin_views.py +6 -1
  11. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/build_sample.py +16 -4
  12. flask_exts-0.2.4/examples/demo/file_op.py +13 -0
  13. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/make_app.py +18 -9
  14. flask_exts-0.2.2/examples/sqla-custom-inline-forms/models/model.py → flask_exts-0.2.4/examples/demo/models/location_image.py +21 -5
  15. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/models/tree.py +3 -2
  16. flask_exts-0.2.4/examples/demo/templates/my/index.html +7 -0
  17. flask_exts-0.2.2/examples/sqla-custom-inline-forms/views/image_view.py → flask_exts-0.2.4/examples/demo/views/location_image_view.py +5 -4
  18. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/fileadmin/make_app.py +2 -8
  19. flask_exts-0.2.4/examples/instance/config.py +3 -0
  20. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/rediscli.py +1 -1
  21. flask_exts-0.2.4/examples/simple.py +27 -0
  22. {flask_exts-0.2.2 → flask_exts-0.2.4}/pyproject.toml +4 -1
  23. flask_exts-0.2.4/src/flask_exts/__about__.py +1 -0
  24. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/__init__.py +0 -1
  25. flask_exts-0.2.4/src/flask_exts/admin/admin.py +15 -0
  26. flask_exts-0.2.4/src/flask_exts/admin/base_admin.py +134 -0
  27. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/model/form.py +3 -3
  28. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/model/view.py +8 -10
  29. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/sqla/form.py +18 -18
  30. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/sqla/view.py +4 -4
  31. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/view.py +19 -28
  32. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/commands.py +6 -6
  33. flask_exts-0.2.4/src/flask_exts/constants.py +6 -0
  34. flask_exts-0.2.4/src/flask_exts/datastore/sqla/__init__.py +9 -0
  35. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/datastore/sqla/models/role.py +0 -1
  36. flask_exts-0.2.4/src/flask_exts/datastore/sqla/models/user.py +75 -0
  37. flask_exts-0.2.4/src/flask_exts/datastore/sqla/models/user_profile.py +27 -0
  38. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/datastore/sqla/models/webauthn.py +9 -5
  39. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/datastore/sqla/orm.py +2 -5
  40. flask_exts-0.2.4/src/flask_exts/email/base.py +66 -0
  41. flask_exts-0.2.4/src/flask_exts/email/reset_password_sender.py +12 -0
  42. flask_exts-0.2.4/src/flask_exts/email/sender.py +6 -0
  43. flask_exts-0.2.4/src/flask_exts/email/smtp.py +41 -0
  44. flask_exts-0.2.4/src/flask_exts/email/verify_email_sender.py +12 -0
  45. flask_exts-0.2.4/src/flask_exts/manager.py +68 -0
  46. flask_exts-0.2.4/src/flask_exts/proxies.py +22 -0
  47. {flask_exts-0.2.2/src/flask_exts/security/authorize → flask_exts-0.2.4/src/flask_exts/security/authorizer}/base.py +1 -1
  48. {flask_exts-0.2.2/src/flask_exts/security/authorize → flask_exts-0.2.4/src/flask_exts/security/authorizer}/casbin_authorizer.py +10 -17
  49. flask_exts-0.2.2/src/flask_exts/security/authorize/casbin_sqlalchemy_adapter/adapter.py → flask_exts-0.2.4/src/flask_exts/security/authorizer/sqlalchemy_adapter.py +2 -2
  50. flask_exts-0.2.4/src/flask_exts/security/core.py +35 -0
  51. flask_exts-0.2.4/src/flask_exts/security/email_verification.py +84 -0
  52. flask_exts-0.2.4/src/flask_exts/security/hasher.py +22 -0
  53. flask_exts-0.2.4/src/flask_exts/security/reset_password.py +78 -0
  54. flask_exts-0.2.4/src/flask_exts/security/serializer.py +50 -0
  55. flask_exts-0.2.4/src/flask_exts/security/two_factor_authentication.py +38 -0
  56. flask_exts-0.2.4/src/flask_exts/signals.py +7 -0
  57. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/js/modal.js +1 -1
  58. flask_exts-0.2.4/src/flask_exts/static/js/qrcode.js +1945 -0
  59. flask_exts-0.2.4/src/flask_exts/template/base.py +37 -0
  60. flask_exts-0.2.4/src/flask_exts/template/dataset.py +9 -0
  61. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/fields/sqla.py +2 -2
  62. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/form/base_form.py +1 -1
  63. flask_exts-0.2.4/src/flask_exts/template/form/csrf.py +65 -0
  64. flask_exts-0.2.4/src/flask_exts/template/form/form_opts.py +6 -0
  65. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/form/meta.py +2 -25
  66. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template/form}/utils.py +0 -9
  67. flask_exts-0.2.4/src/flask_exts/template/forms/change_password.py +28 -0
  68. flask_exts-0.2.4/src/flask_exts/template/forms/forgot_password.py +19 -0
  69. flask_exts-0.2.4/src/flask_exts/template/forms/login.py +13 -0
  70. {flask_exts-0.2.2/src/flask_exts/security → flask_exts-0.2.4/src/flask_exts/template}/forms/profile.py +1 -1
  71. flask_exts-0.2.4/src/flask_exts/template/forms/recovery.py +10 -0
  72. flask_exts-0.2.2/src/flask_exts/security/forms/mixins.py → flask_exts-0.2.4/src/flask_exts/template/forms/register.py +2 -9
  73. flask_exts-0.2.4/src/flask_exts/template/forms/reset_password.py +16 -0
  74. flask_exts-0.2.4/src/flask_exts/template/forms/two_factor.py +10 -0
  75. flask_exts-0.2.4/src/flask_exts/template/funcs.py +39 -0
  76. flask_exts-0.2.4/src/flask_exts/template/plugin.py +18 -0
  77. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/template/theme.py +5 -12
  78. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/admin/base.html +5 -3
  79. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/admin/index.html +1 -1
  80. flask_exts-0.2.4/src/flask_exts/templates/admin/master.html +1 -0
  81. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/admin/model/list.html +2 -2
  82. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/base.html +4 -6
  83. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/bootstrap4/form.html +4 -4
  84. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/bootstrap5/form.html +6 -6
  85. flask_exts-0.2.4/src/flask_exts/templates/layout.html +12 -0
  86. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/macro/actions.html +2 -2
  87. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/macro/form.html +1 -1
  88. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/macro/icon.html +2 -2
  89. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/macro/menu.html +1 -1
  90. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/macro/row_actions.html +2 -2
  91. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/macro/table.html +8 -7
  92. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/macro/vendor.html +0 -3
  93. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/views/rediscli/response.html +1 -1
  94. flask_exts-0.2.4/src/flask_exts/templates/views/user/change_password.html +11 -0
  95. flask_exts-0.2.4/src/flask_exts/templates/views/user/forgot_password.html +11 -0
  96. flask_exts-0.2.4/src/flask_exts/templates/views/user/index.html +21 -0
  97. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/views/user/login.html +4 -3
  98. flask_exts-0.2.4/src/flask_exts/templates/views/user/recovery.html +10 -0
  99. flask_exts-0.2.4/src/flask_exts/templates/views/user/recovery_codes.html +32 -0
  100. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/views/user/register.html +1 -1
  101. flask_exts-0.2.4/src/flask_exts/templates/views/user/reset_password.html +11 -0
  102. flask_exts-0.2.4/src/flask_exts/templates/views/user/setup_tfa.html +44 -0
  103. flask_exts-0.2.4/src/flask_exts/templates/views/user/show_tfa.html +38 -0
  104. flask_exts-0.2.4/src/flask_exts/templates/views/user/verify_email.html +9 -0
  105. flask_exts-0.2.4/src/flask_exts/templates/views/user/verify_tfa.html +11 -0
  106. flask_exts-0.2.4/src/flask_exts/templates/views/user/verify_tfa_modal.html +17 -0
  107. flask_exts-0.2.4/src/flask_exts/usercenter/base_user.py +14 -0
  108. flask_exts-0.2.4/src/flask_exts/usercenter/base_user_store.py +29 -0
  109. flask_exts-0.2.4/src/flask_exts/usercenter/core.py +43 -0
  110. flask_exts-0.2.2/src/flask_exts/security/usercenter/sqla_usercenter.py → flask_exts-0.2.4/src/flask_exts/usercenter/sqla_user_store.py +58 -40
  111. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/utils/__init__.py +1 -1
  112. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/utils/authorize.py +4 -4
  113. flask_exts-0.2.2/src/flask_exts/decorators/auth_required_decorator.py → flask_exts-0.2.4/src/flask_exts/utils/decorators.py +2 -2
  114. flask_exts-0.2.4/src/flask_exts/utils/flask.py +16 -0
  115. flask_exts-0.2.4/src/flask_exts/utils/image.py +12 -0
  116. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/utils/request_user.py +6 -6
  117. flask_exts-0.2.2/src/flask_exts/utils/flask.py → flask_exts-0.2.4/src/flask_exts/utils/url.py +0 -14
  118. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/views/file_view/base_file_view.py +4 -3
  119. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/views/index_view.py +3 -2
  120. flask_exts-0.2.4/src/flask_exts/views/user_view.py +300 -0
  121. {flask_exts-0.2.2/tests → flask_exts-0.2.4/tests/admin/customer}/conftest.py +10 -6
  122. flask_exts-0.2.4/tests/admin/customer/test_admin.py +97 -0
  123. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/admin/sqla/test_basic.py +324 -413
  124. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/admin/sqla/test_form_rules.py +12 -19
  125. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/admin/sqla/test_inlineform.py +4 -4
  126. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/admin/sqla/test_multi_pk.py +13 -16
  127. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/admin/sqla/test_translation.py +1 -1
  128. flask_exts-0.2.4/tests/admin/test_base.py +153 -0
  129. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/admin/test_model.py +79 -77
  130. flask_exts-0.2.4/tests/conftest.py +46 -0
  131. flask_exts-0.2.4/tests/email/test_base.py +18 -0
  132. flask_exts-0.2.4/tests/email/test_smtp.py +24 -0
  133. {flask_exts-0.2.2/tests/security/authorize → flask_exts-0.2.4/tests/security/authorizer}/casbin_adapter/test_sqlalchemy_adapter.py +5 -5
  134. {flask_exts-0.2.2/tests/security/authorize → flask_exts-0.2.4/tests/security/authorizer}/test_casbin_auth.py +21 -19
  135. flask_exts-0.2.4/tests/security/test_core.py +49 -0
  136. flask_exts-0.2.4/tests/security/test_tfa.py +18 -0
  137. flask_exts-0.2.4/tests/template/bootstrap4/__init__.py +0 -0
  138. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap4/test_render_field.py +17 -21
  139. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap4/test_render_form.py +40 -48
  140. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap4/test_render_form_row.py +10 -14
  141. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap4/test_render_hidden_errors.py +3 -4
  142. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap4/test_render_icon_sprite.py +25 -30
  143. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap4/test_render_messages.py +15 -19
  144. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap4/test_render_pager.py +10 -12
  145. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap4/test_render_pagination.py +9 -11
  146. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap4/test_render_table.py +48 -55
  147. flask_exts-0.2.4/tests/template/bootstrap5/__init__.py +0 -0
  148. flask_exts-0.2.4/tests/template/bootstrap5/conftest.py +21 -0
  149. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap5/test_base.py +2 -2
  150. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap5/test_render_form.py +31 -37
  151. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap5/test_render_form_row.py +4 -5
  152. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap5/test_render_messages.py +2 -3
  153. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/bootstrap5/test_render_pagination.py +5 -6
  154. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/conftest.py +1 -1
  155. flask_exts-0.2.2/tests/forms/test_form.py → flask_exts-0.2.4/tests/template/forms/test_csrf.py +4 -3
  156. {flask_exts-0.2.2/tests → flask_exts-0.2.4/tests/template}/forms/test_fields.py +2 -2
  157. {flask_exts-0.2.2/tests → flask_exts-0.2.4/tests/template}/forms/test_filefield.py +1 -1
  158. {flask_exts-0.2.2/tests → flask_exts-0.2.4/tests/template}/forms/test_uploadfile.py +3 -3
  159. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/macros/test_render_breadcrumb_item.py +4 -6
  160. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/macros/test_render_nav_item.py +4 -6
  161. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/template/test_base.py +2 -2
  162. flask_exts-0.2.4/tests/templates/mock.html +1 -0
  163. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/test_babel.py +7 -6
  164. flask_exts-0.2.4/tests/test_base.py +27 -0
  165. flask_exts-0.2.4/tests/test_flask.py +34 -0
  166. flask_exts-0.2.4/tests/usercenter/test_sqla_usercenter.py +34 -0
  167. flask_exts-0.2.4/tests/utils/test_image.py +7 -0
  168. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/utils/test_request_user.py +2 -2
  169. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/utils/test_url.py +1 -1
  170. flask_exts-0.2.4/tests/views/files/dummy.txt +0 -0
  171. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/views/test_file_view.py +26 -28
  172. flask_exts-0.2.4/tests/views/test_user_view.py +483 -0
  173. flask_exts-0.2.2/examples/demo/templates/my/index.html +0 -7
  174. flask_exts-0.2.2/examples/simple.py +0 -13
  175. flask_exts-0.2.2/examples/sqla-custom-inline-forms/__init__.py +0 -1
  176. flask_exts-0.2.2/examples/sqla-custom-inline-forms/data.py +0 -23
  177. flask_exts-0.2.2/examples/sqla-custom-inline-forms/make_app.py +0 -88
  178. flask_exts-0.2.2/examples/sqla-custom-inline-forms/models/__init__.py +0 -1
  179. flask_exts-0.2.2/examples/sqla-custom-inline-forms/templates/admin/admin.html +0 -5
  180. flask_exts-0.2.2/src/flask_exts/__about__.py +0 -1
  181. flask_exts-0.2.2/src/flask_exts/admin/admin.py +0 -117
  182. flask_exts-0.2.2/src/flask_exts/datastore/sqla/__init__.py +0 -9
  183. flask_exts-0.2.2/src/flask_exts/datastore/sqla/models/user.py +0 -38
  184. flask_exts-0.2.2/src/flask_exts/datastore/sqla/models/user_role.py +0 -11
  185. flask_exts-0.2.2/src/flask_exts/decorators/__init__.py +0 -2
  186. flask_exts-0.2.2/src/flask_exts/forms/__init__.py +0 -3
  187. flask_exts-0.2.2/src/flask_exts/forms/form/__init__.py +0 -2
  188. flask_exts-0.2.2/src/flask_exts/forms/form/csrf.py +0 -57
  189. flask_exts-0.2.2/src/flask_exts/manager.py +0 -74
  190. flask_exts-0.2.2/src/flask_exts/proxies.py +0 -17
  191. flask_exts-0.2.2/src/flask_exts/security/authorize/__init__.py +0 -1
  192. flask_exts-0.2.2/src/flask_exts/security/authorize/casbin_sqlalchemy_adapter/__init__.py +0 -1
  193. flask_exts-0.2.2/src/flask_exts/security/core.py +0 -43
  194. flask_exts-0.2.2/src/flask_exts/security/forms/__init__.py +0 -2
  195. flask_exts-0.2.2/src/flask_exts/security/forms/login.py +0 -6
  196. flask_exts-0.2.2/src/flask_exts/security/forms/register.py +0 -6
  197. flask_exts-0.2.2/src/flask_exts/security/mixins/webauthn_mixin.py +0 -9
  198. flask_exts-0.2.2/src/flask_exts/security/usercenter/base.py +0 -21
  199. flask_exts-0.2.2/src/flask_exts/security/usercenter/memory_usercenter.py +0 -59
  200. flask_exts-0.2.2/src/flask_exts/template/__init__.py +0 -37
  201. flask_exts-0.2.2/src/flask_exts/template/utils.py +0 -51
  202. flask_exts-0.2.2/src/flask_exts/templates/admin/master.html +0 -1
  203. flask_exts-0.2.2/src/flask_exts/templates/layout.html +0 -21
  204. flask_exts-0.2.2/src/flask_exts/templates/views/user/index.html +0 -7
  205. flask_exts-0.2.2/src/flask_exts/views/user_view.py +0 -118
  206. flask_exts-0.2.2/tests/admin/test_base.py +0 -315
  207. flask_exts-0.2.2/tests/template/bootstrap5/conftest.py +0 -14
  208. flask_exts-0.2.2/tests/test_base.py +0 -19
  209. flask_exts-0.2.2/tests/views/test_user_view.py +0 -60
  210. {flask_exts-0.2.2 → flask_exts-0.2.4}/.github/workflows/release.yml +0 -0
  211. {flask_exts-0.2.2 → flask_exts-0.2.4}/.readthedocs.yaml +0 -0
  212. {flask_exts-0.2.2 → flask_exts-0.2.4}/LICENSE.rst +0 -0
  213. {flask_exts-0.2.2 → flask_exts-0.2.4}/README.rst +0 -0
  214. {flask_exts-0.2.2 → flask_exts-0.2.4}/babel/babel.cfg +0 -0
  215. {flask_exts-0.2.2 → flask_exts-0.2.4}/babel/babel.sh +0 -0
  216. {flask_exts-0.2.2 → flask_exts-0.2.4}/babel/messages.pot +0 -0
  217. {flask_exts-0.2.2 → flask_exts-0.2.4}/docs/Makefile +0 -0
  218. {flask_exts-0.2.2 → flask_exts-0.2.4}/docs/_static/logo.png +0 -0
  219. {flask_exts-0.2.2 → flask_exts-0.2.4}/docs/changes.rst +0 -0
  220. {flask_exts-0.2.2 → flask_exts-0.2.4}/docs/conf.py +0 -0
  221. {flask_exts-0.2.2 → flask_exts-0.2.4}/docs/develop.rst +0 -0
  222. {flask_exts-0.2.2 → flask_exts-0.2.4}/docs/examples.rst +0 -0
  223. {flask_exts-0.2.2 → flask_exts-0.2.4}/docs/make.bat +0 -0
  224. {flask_exts-0.2.2 → flask_exts-0.2.4}/docs/requirements.txt +0 -0
  225. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/README.rst +0 -0
  226. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap4/static/favicon.ico +0 -0
  227. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap4/templates/bootswatch.html +0 -0
  228. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap4/templates/flash.html +0 -0
  229. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap4/templates/form.html +0 -0
  230. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap4/templates/icon.html +0 -0
  231. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap4/templates/icons.html +0 -0
  232. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap4/templates/index.html +0 -0
  233. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap4/templates/mybase.html +0 -0
  234. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap4/templates/nav.html +0 -0
  235. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap4/templates/pagination.html +0 -0
  236. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap4/templates/table.html +0 -0
  237. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap5/static/favicon.ico +0 -0
  238. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap5/templates/bootswatch.html +0 -0
  239. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap5/templates/flash.html +0 -0
  240. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap5/templates/form.html +0 -0
  241. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap5/templates/icon.html +0 -0
  242. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap5/templates/icons.html +0 -0
  243. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap5/templates/index.html +0 -0
  244. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap5/templates/mybase.html +0 -0
  245. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap5/templates/nav.html +0 -0
  246. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/bootstrap5/templates/table.html +0 -0
  247. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/__init__.py +0 -0
  248. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/models/__init__.py +0 -0
  249. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/models/author.py +0 -0
  250. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/models/keyword.py +0 -0
  251. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/models/post.py +0 -0
  252. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/models/post_tag.py +0 -0
  253. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/models/tag.py +0 -0
  254. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/models/user.py +0 -0
  255. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/models/user_keyword.py +0 -0
  256. {flask_exts-0.2.2/examples/sqla-custom-inline-forms → flask_exts-0.2.4/examples/demo}/templates/field_list.html +0 -0
  257. {flask_exts-0.2.2/examples/sqla-custom-inline-forms → flask_exts-0.2.4/examples/demo}/templates/locations.html +0 -0
  258. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/templates/tree_list.html +0 -0
  259. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/views/author_view.py +0 -0
  260. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/views/keyword_view.py +0 -0
  261. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/views/my_view.py +0 -0
  262. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/views/post_view.py +0 -0
  263. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/views/tag_view.py +0 -0
  264. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/views/tree_view.py +0 -0
  265. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/demo/views/user_view.py +0 -0
  266. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/fileadmin/__init__.py +0 -0
  267. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/fileadmin/file_view.py +0 -0
  268. {flask_exts-0.2.2 → flask_exts-0.2.4}/examples/fileadmin/tmp/bbb/a.txt +0 -0
  269. {flask_exts-0.2.2 → flask_exts-0.2.4}/requirements/build.in +0 -0
  270. {flask_exts-0.2.2 → flask_exts-0.2.4}/requirements/test.in +0 -0
  271. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/__init__.py +0 -0
  272. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/actions.py +0 -0
  273. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/menu.py +0 -0
  274. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/model/__init__.py +0 -0
  275. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/model/ajax.py +0 -0
  276. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/model/filters.py +0 -0
  277. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/model/typefmt.py +0 -0
  278. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/row_action.py +0 -0
  279. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/sqla/__init__.py +0 -0
  280. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/sqla/ajax.py +0 -0
  281. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/sqla/filters.py +0 -0
  282. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/admin/sqla/typefmt.py +0 -0
  283. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/babel/__init__.py +0 -0
  284. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/babel/selector.py +0 -0
  285. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/datastore/__init__.py +0 -0
  286. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/datastore/sqla/models/__init__.py +0 -0
  287. {flask_exts-0.2.2/src/flask_exts/security/usercenter → flask_exts-0.2.4/src/flask_exts/email}/__init__.py +0 -0
  288. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/security/__init__.py +0 -0
  289. {flask_exts-0.2.2/src/flask_exts/translations → flask_exts-0.2.4/src/flask_exts/security/authorizer}/__init__.py +0 -0
  290. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/security/principal/identity.py +0 -0
  291. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/security/principal/identity_context.py +0 -0
  292. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/security/principal/permission.py +0 -0
  293. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/security/principal/principal.py +0 -0
  294. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/css/admin.css +0 -0
  295. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/css/rediscli.css +0 -0
  296. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/js/actions.js +0 -0
  297. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/js/details_filter.js +0 -0
  298. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/js/filters.js +0 -0
  299. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/js/form.js +0 -0
  300. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/js/helper.js +0 -0
  301. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/js/rediscli.js +0 -0
  302. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/js/security/base64.js +0 -0
  303. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/js/security/webauthn.js +0 -0
  304. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/logo.png +0 -0
  305. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/bootstrap-icons/bootstrap-icons.svg +0 -0
  306. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/bootstrap-icons/font/bootstrap-icons.css +0 -0
  307. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/bootstrap-icons/font/bootstrap-icons.json +0 -0
  308. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/bootstrap-icons/font/bootstrap-icons.min.css +0 -0
  309. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/bootstrap-icons/font/bootstrap-icons.scss +0 -0
  310. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/bootstrap-icons/font/fonts/bootstrap-icons.woff +0 -0
  311. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/bootstrap-icons/font/fonts/bootstrap-icons.woff2 +0 -0
  312. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/bootstrap4/bootstrap.bundle.min.js +0 -0
  313. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/bootstrap4/bootstrap.min.css +0 -0
  314. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/bootstrap5/bootstrap.bundle.min.js +0 -0
  315. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/bootstrap5/bootstrap.min.css +0 -0
  316. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/daterangepicker/daterangepicker.css +0 -0
  317. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/daterangepicker/daterangepicker.js +0 -0
  318. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/jquery/jquery.min.js +0 -0
  319. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/moment.min.js +0 -0
  320. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/select2/select2.min.css +0 -0
  321. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/select2/select2.min.js +0 -0
  322. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/vanilla-editor/css/bootstrap-editable.css +0 -0
  323. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/vanilla-editor/img/clear.png +0 -0
  324. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/vanilla-editor/img/loading.gif +0 -0
  325. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/static/vendor/vanilla-editor/js/bootstrap-editable.min.js +0 -0
  326. {flask_exts-0.2.2/src/flask_exts/security/utils → flask_exts-0.2.4/src/flask_exts/template}/__init__.py +0 -0
  327. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/fields/__init__.py +0 -0
  328. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/fields/ajax_select.py +0 -0
  329. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/fields/datetime.py +0 -0
  330. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/fields/file.py +0 -0
  331. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/fields/inline.py +0 -0
  332. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/fields/json.py +0 -0
  333. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/fields/recaptcha.py +0 -0
  334. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/fields/select.py +0 -0
  335. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/fields/switch.py +0 -0
  336. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/fields/taglist.py +0 -0
  337. {flask_exts-0.2.2/tests/admin → flask_exts-0.2.4/src/flask_exts/template/form}/__init__.py +0 -0
  338. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/form/flask_form.py +0 -0
  339. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/form/session_csrf.py +0 -0
  340. {flask_exts-0.2.2/tests/admin/sqla → flask_exts-0.2.4/src/flask_exts/template/forms}/__init__.py +0 -0
  341. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/rules.py +0 -0
  342. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/validators/__init__.py +0 -0
  343. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/validators/field_list.py +0 -0
  344. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/validators/file.py +0 -0
  345. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/validators/recaptcha.py +0 -0
  346. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/validators/sqla.py +0 -0
  347. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/widgets/__init__.py +0 -0
  348. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/widgets/checkbox.py +0 -0
  349. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/widgets/datetime.py +0 -0
  350. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/widgets/file.py +0 -0
  351. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/widgets/inline.py +0 -0
  352. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/widgets/recaptcha.py +0 -0
  353. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/widgets/render_template.py +0 -0
  354. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/widgets/select.py +0 -0
  355. {flask_exts-0.2.2/src/flask_exts/forms → flask_exts-0.2.4/src/flask_exts/template}/widgets/xeditable.py +0 -0
  356. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/admin/model/create.html +0 -0
  357. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/admin/model/details.html +0 -0
  358. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/admin/model/edit.html +0 -0
  359. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/admin/model/modals/create.html +0 -0
  360. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/admin/model/modals/details.html +0 -0
  361. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/admin/model/modals/edit.html +0 -0
  362. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/bootstrap4/message.html +0 -0
  363. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/bootstrap4/pagination.html +0 -0
  364. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/bootstrap5/message.html +0 -0
  365. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/index.html +0 -0
  366. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/macro/inline.html +0 -0
  367. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/macro/layout.html +0 -0
  368. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/macro/message.html +0 -0
  369. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/macro/nav.html +0 -0
  370. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/macro/pagination.html +0 -0
  371. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/views/file/form.html +0 -0
  372. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/views/file/list.html +0 -0
  373. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/views/file/modals/form.html +0 -0
  374. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/views/rediscli/console.html +0 -0
  375. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/views/user/list.html +0 -0
  376. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/widgets/inline_field_list.html +0 -0
  377. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/templates/widgets/inline_form.html +0 -0
  378. {flask_exts-0.2.2/tests/security/authorize → flask_exts-0.2.4/src/flask_exts/translations}/__init__.py +0 -0
  379. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/translations/en/LC_MESSAGES/messages.mo +0 -0
  380. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/translations/en/LC_MESSAGES/messages.po +0 -0
  381. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/translations/zh_CN/LC_MESSAGES/messages.mo +0 -0
  382. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/translations/zh_CN/LC_MESSAGES/messages.po +0 -0
  383. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/types.py +0 -0
  384. {flask_exts-0.2.2/tests/template → flask_exts-0.2.4/src/flask_exts/usercenter}/__init__.py +0 -0
  385. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/utils/jwt.py +0 -0
  386. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/utils/sqla.py +0 -0
  387. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/utils/tools.py +0 -0
  388. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/views/file_view/__init__.py +0 -0
  389. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/views/file_view/local_file_storage.py +0 -0
  390. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/views/file_view/local_file_view.py +0 -0
  391. {flask_exts-0.2.2 → flask_exts-0.2.4}/src/flask_exts/views/rediscli_view.py +0 -0
  392. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/__init__.py +0 -0
  393. {flask_exts-0.2.2/tests/template/bootstrap4 → flask_exts-0.2.4/tests/admin}/__init__.py +0 -0
  394. {flask_exts-0.2.2/tests → flask_exts-0.2.4/tests/admin/customer}/templates/mock.html +0 -0
  395. {flask_exts-0.2.2/tests/template/bootstrap5 → flask_exts-0.2.4/tests/admin/sqla}/__init__.py +0 -0
  396. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/admin/sqla/templates/another_macro.html +0 -0
  397. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/admin/sqla/templates/macro.html +0 -0
  398. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/data/copyleft.gif +0 -0
  399. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/data/copyleft.jpeg +0 -0
  400. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/data/copyleft.jpg +0 -0
  401. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/data/copyleft.png +0 -0
  402. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/data/copyleft.tiff +0 -0
  403. /flask_exts-0.2.2/tests/funcs.py → /flask_exts-0.2.4/tests/helper.py +0 -0
  404. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/models/__init__.py +0 -0
  405. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/models/message.py +0 -0
  406. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/models/model1.py +0 -0
  407. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/models/multpk.py +0 -0
  408. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/models/polymorphic.py +0 -0
  409. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/models/tree.py +0 -0
  410. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/models/user.py +0 -0
  411. /flask_exts-0.2.2/src/flask_exts/utils/url.py → /flask_exts-0.2.4/tests/security/authorizer/__init__.py +0 -0
  412. {flask_exts-0.2.2/tests/security/authorize → flask_exts-0.2.4/tests/security/authorizer}/casbin_adapter/rbac_model.conf +0 -0
  413. {flask_exts-0.2.2/tests/security/authorize → flask_exts-0.2.4/tests/security/authorizer}/casbin_adapter/rbac_policy.csv +0 -0
  414. {flask_exts-0.2.2/tests/security/authorize → flask_exts-0.2.4/tests/security/authorizer}/casbin_files/authz_policy.csv +0 -0
  415. {flask_exts-0.2.2/tests/security/authorize → flask_exts-0.2.4/tests/security/authorizer}/casbin_files/rbac_model.conf +0 -0
  416. {flask_exts-0.2.2/tests/security/authorize → flask_exts-0.2.4/tests/security/authorizer}/casbin_files/rbac_policy.csv +0 -0
  417. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/security/test_principal.py +0 -0
  418. /flask_exts-0.2.2/tests/views/files/dummy.txt → /flask_exts-0.2.4/tests/template/__init__.py +0 -0
  419. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/templates/method.html +0 -0
  420. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/translations/en/LC_MESSAGES/messages.mo +0 -0
  421. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/translations/en/LC_MESSAGES/messages.po +0 -0
  422. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/translations/zh_CN/LC_MESSAGES/messages.po +0 -0
  423. {flask_exts-0.2.2 → flask_exts-0.2.4}/tests/views/test_rediscli_view.py +0 -0
@@ -32,3 +32,6 @@ docs/_build/
32
32
 
33
33
  # sqlite db
34
34
  *.sqlite
35
+
36
+ # production config
37
+ **/config_prod.py
@@ -1,3 +1,23 @@
1
+ v0.2.4
2
+ ------
3
+
4
+ Unreleased
5
+
6
+ - user change password
7
+ - user forgot password
8
+ - user 2FA with TOTP
9
+ - user recovery codes
10
+ - user recovery
11
+
12
+ v0.2.3
13
+ ------
14
+
15
+ Released 2025-08-28
16
+
17
+ - move form into template
18
+ - add folder email
19
+ - add security.email_verification
20
+
1
21
  v0.2.2
2
22
  ------
3
23
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Flask-Exts
3
- Version: 0.2.2
3
+ Version: 0.2.4
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
@@ -46,7 +46,10 @@ Requires-Dist: flask-babel>=4.0
46
46
  Requires-Dist: flask-login>=0.6
47
47
  Requires-Dist: flask-sqlalchemy>=3.0
48
48
  Requires-Dist: flask>=3.0
49
+ Requires-Dist: pillow>=11.0
49
50
  Requires-Dist: pyjwt>=2.0
51
+ Requires-Dist: pyotp>=2.0
52
+ Requires-Dist: qrcode>=8.0
50
53
  Requires-Dist: tablib>=3.0
51
54
  Requires-Dist: webauthn>=2.0
52
55
  Requires-Dist: wtforms>=3.0
@@ -18,7 +18,8 @@ Configuration
18
18
  Default is ``csrf_token``.
19
19
  ``CSRF_TIME_LIMIT`` Max age in seconds for CSRF tokens.
20
20
  Default is ``1800``.
21
- ``TEMPLATE_THEME`` Set to ``theme`` to create custom theme
22
- Default is ``template.theme.BootstrapTheme(4)``
21
+ ``NOREPLY_EMAIL_SENDER`` Email address used to send emails.
22
+ It is a dict for smtp with keys: host,port,user,password.
23
+ Default is None.
23
24
  ========================== =====================================================================
24
25
 
@@ -42,6 +42,7 @@ More examples, please click :doc:`examples`.
42
42
 
43
43
  configure
44
44
  develop
45
+ user
45
46
  examples
46
47
  changes
47
48
 
@@ -0,0 +1,11 @@
1
+ =======
2
+ User
3
+ =======
4
+
5
+ views
6
+ =======
7
+
8
+ .. automodule:: flask_exts.views.user_view
9
+ :members:
10
+ :undoc-members:
11
+ :show-inheritance:
@@ -3,8 +3,8 @@ from flask import Flask, render_template, request, flash, redirect, url_for
3
3
  from markupsafe import Markup
4
4
  from wtforms.validators import DataRequired, Length, Regexp
5
5
  from wtforms.fields import *
6
- from flask_exts.forms.form import FlaskForm
7
- from flask_exts.forms.fields import SwitchField
6
+ from flask_exts.template.form.flask_form import FlaskForm
7
+ from flask_exts.template.fields import SwitchField
8
8
  from flask_exts import Manager
9
9
  from flask_exts.datastore.sqla import db
10
10
 
@@ -4,13 +4,12 @@ from markupsafe import Markup
4
4
  from wtforms.validators import DataRequired, Length, Regexp
5
5
  from wtforms.fields import *
6
6
 
7
- from flask_exts.forms.form import FlaskForm
8
- from flask_exts.forms.fields import SwitchField
7
+ from flask_exts.template.form.flask_form import FlaskForm
8
+ from flask_exts.template.fields import SwitchField
9
9
  from flask_exts import Manager
10
10
  from flask_exts.template.theme import BootstrapTheme
11
11
  from flask_exts.datastore.sqla import db
12
12
 
13
- theme = BootstrapTheme(version=5)
14
13
 
15
14
  app = Flask(__name__)
16
15
  app.secret_key = "dev"
@@ -18,10 +17,13 @@ app.secret_key = "dev"
18
17
  app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
19
18
  app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
20
19
  # set bootstrap5
21
- app.config["TEMPLATE_THEME"] = theme
22
20
  app.config['ADMIN_ENABLED'] = False
23
21
 
24
- manager = Manager()
22
+ class MyManager(Manager):
23
+ def get_theme(self):
24
+ return BootstrapTheme(5)
25
+
26
+ manager = MyManager()
25
27
  manager.init_app(app)
26
28
 
27
29
 
@@ -1,5 +1,5 @@
1
1
  {% extends "mybase.html" %}
2
- {% from 'pagination4/pagination.html' import render_pager, render_pagination %}
2
+ {% from 'bootstrap4/pagination.html' import render_pager, render_pagination %}
3
3
 
4
4
  {% block content %}
5
5
  <h2>Messages</h2>
@@ -5,11 +5,12 @@ from .views.tree_view import treeview
5
5
  from .views.tag_view import tagview
6
6
  from .views.author_view import authorview
7
7
  from .views.post_view import postview
8
+ from .views.location_image_view import locationview
8
9
  from flask_exts.admin.menu import MenuLink
9
10
 
10
11
 
11
12
  def add_views(app):
12
- admin = app.extensions["manager"].admins[0]
13
+ admin = app.extensions["manager"].admin
13
14
 
14
15
  admin.add_view(myview)
15
16
  admin.add_view(userview)
@@ -18,6 +19,10 @@ def add_views(app):
18
19
  admin.add_view(tagview)
19
20
  admin.add_view(postview)
20
21
  admin.add_view(treeview)
22
+ admin.add_view(locationview)
23
+ admin.menu.add_link(
24
+ MenuLink(name="locationlist", url="/locationlist", category="List")
25
+ )
21
26
  admin.menu.add_category(name="Links")
22
27
  admin.menu.add_link(MenuLink(name="Back Home", url="/", category="Links"))
23
28
  admin.menu.add_sub_category(name='External',parent_name='Links')
@@ -1,6 +1,6 @@
1
1
  import random
2
2
  import datetime
3
- from flask_exts.proxies import current_usercenter
3
+ from flask_exts.proxies import _userstore
4
4
  from .models import db
5
5
  from .models.author import Author
6
6
  from .models.author import AVAILABLE_USER_TYPES
@@ -9,14 +9,25 @@ from .models.post import Post
9
9
  from .models.tree import Tree
10
10
  from .models.keyword import Keyword
11
11
  from .models.user import MyUser
12
+ from .models.location_image import ImageType
12
13
 
13
14
 
14
15
  def build_user_admin():
15
- u, _ = current_usercenter.create_user(
16
+ u, _ = _userstore.create_user(
16
17
  username="admin", password="admin", email="admin@example.com"
17
18
  )
18
- r, _ = current_usercenter.create_role(name="admin")
19
- current_usercenter.user_add_role(u, r)
19
+ r, _ = _userstore.create_role(name="admin")
20
+ _userstore.user_add_role(u, r)
21
+
22
+
23
+ def build_sample_image_type():
24
+
25
+ # Add some image types for the form_ajax_refs inside the inline_model
26
+ image_types = ("JPEG", "PNG", "GIF")
27
+ for image_type in image_types:
28
+ itype = ImageType(name=image_type)
29
+ db.session.add(itype)
30
+ db.session.commit()
20
31
 
21
32
 
22
33
  def build_sample_userkeyword():
@@ -225,5 +236,6 @@ def build_sample_db():
225
236
  build_sample_tree()
226
237
  build_sample_post()
227
238
  build_user_admin()
239
+ build_sample_image_type()
228
240
 
229
241
  return
@@ -0,0 +1,13 @@
1
+ import os.path as op
2
+ import os
3
+
4
+ # Figure out base upload path
5
+ static_path = op.join(op.dirname(__file__), "static")
6
+
7
+
8
+ def remove_image(image_path):
9
+ os.remove(op.join(static_path, image_path))
10
+
11
+
12
+ def save_image(file_data, image_path):
13
+ file_data.save(op.join(static_path, image_path))
@@ -2,6 +2,11 @@ import os.path as op
2
2
  from flask import Flask
3
3
  from flask_exts import Manager
4
4
 
5
+ class MyManager(Manager):
6
+ def get_admin_class(self):
7
+ from flask_exts.admin.admin import Admin
8
+ return Admin
9
+
5
10
 
6
11
  def get_sqlite_path():
7
12
  app_dir = op.realpath(op.dirname(__file__))
@@ -10,26 +15,21 @@ def get_sqlite_path():
10
15
 
11
16
 
12
17
  def create_app():
13
- app = Flask(__name__)
18
+ app = Flask(__name__, instance_relative_config=True)
14
19
  app.config["SECRET_KEY"] = "dev"
15
-
20
+ app.config.from_pyfile('config.py',silent=True)
21
+ app.config.from_pyfile('config_prod.py',silent=True)
16
22
  # app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
17
23
  # app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
18
24
  # app.config["SQLALCHEMY_ECHO"] = True
19
25
  app.config["DATABASE_FILE"] = get_sqlite_path()
20
26
  app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + app.config["DATABASE_FILE"]
21
- # JWT
22
- app.config["JWT_SECRET_KEY"] = "SECRET_KEY"
23
- app.config["JWT_HASH"] = "HS256"
24
- # app.config["ADMIN_ACCESS_ENABLED"] = False
25
27
  init_app(app)
26
-
27
28
  return app
28
29
 
29
30
 
30
31
  def init_app(app: Flask):
31
-
32
- manager = Manager()
32
+ manager = MyManager()
33
33
  manager.init_app(app)
34
34
 
35
35
  from .models import init_models
@@ -40,6 +40,15 @@ def init_app(app: Flask):
40
40
 
41
41
  add_views(app)
42
42
 
43
+ @app.route("/locationlist")
44
+ def location_list():
45
+ from .models.location_image import Location
46
+ from flask import render_template
47
+ from .models import db
48
+
49
+ locations = db.session.query(Location).all()
50
+ return render_template("locations.html", locations=locations)
51
+
43
52
  if not op.exists(app.config["DATABASE_FILE"]):
44
53
  with app.app_context():
45
54
  from .build_sample import build_sample_db
@@ -1,14 +1,19 @@
1
1
  from . import db
2
2
  from typing import Optional
3
+ from typing import List
3
4
  from sqlalchemy import ForeignKey
4
5
  from sqlalchemy.orm import relationship
5
6
  from sqlalchemy.orm import Mapped
6
7
  from sqlalchemy.orm import mapped_column
7
-
8
+ from sqlalchemy import event
9
+ from ..file_op import remove_image
8
10
 
9
11
  class Location(db.Model):
10
12
  id: Mapped[int] = mapped_column(primary_key=True)
11
13
  name: Mapped[str]
14
+ images: Mapped[List["LocationImage"]] = relationship(
15
+ "LocationImage", back_populates="location", cascade="all, delete-orphan"
16
+ )
12
17
 
13
18
 
14
19
  class ImageType(db.Model):
@@ -33,10 +38,21 @@ class LocationImage(db.Model):
33
38
  alt: Mapped[str]
34
39
  path: Mapped[str]
35
40
 
36
- location_id: Mapped[int] = mapped_column(ForeignKey("location.id"))
37
- location: Mapped["Location"] = relationship(backref='images')
41
+ location_id = mapped_column(ForeignKey("location.id"))
42
+ location: Mapped["Location"] = relationship(back_populates="images")
43
+
44
+ image_type_id = mapped_column(ForeignKey("image_type.id"))
45
+ image_type: Mapped["ImageType"] = relationship()
46
+
38
47
 
39
- image_type_id: Mapped[int] = mapped_column(ForeignKey("image_type.id"))
40
- image_type: Mapped["ImageType"] = relationship(backref='images')
41
48
 
42
49
 
50
+ # Register after_delete handler which will delete image file after model gets deleted
51
+ @event.listens_for(Location, "after_delete")
52
+ def _handle_image_delete(mapper, conn, target):
53
+ for location_image in target.images:
54
+ try:
55
+ if location_image.path:
56
+ remove_image(location_image.path)
57
+ except:
58
+ pass
@@ -5,6 +5,7 @@ from sqlalchemy.orm import relationship
5
5
  from sqlalchemy.orm import Mapped
6
6
  from sqlalchemy.orm import mapped_column
7
7
 
8
+
8
9
  class Tree(db.Model):
9
10
  id: Mapped[int] = mapped_column(primary_key=True)
10
11
  name: Mapped[str]
@@ -12,7 +13,7 @@ class Tree(db.Model):
12
13
  # recursive relationship
13
14
  parent_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tree.id"))
14
15
  parent = relationship("Tree", back_populates="children", remote_side=id)
15
- children = relationship("Tree",back_populates="parent")
16
+ children = relationship("Tree", back_populates="parent")
16
17
 
17
18
  def __str__(self):
18
- return "{}".format(self.name)
19
+ return "{}".format(self.name)
@@ -0,0 +1,7 @@
1
+ {% extends 'admin/master.html' %}
2
+ {% block main %}
3
+ <div>
4
+ Demo:my:index
5
+ </div>
6
+ <div> x= {{ x }}, x'type is {{ template.funcs.type_name(x) }}.</div>
7
+ {% endblock %}
@@ -3,12 +3,13 @@ from flask import request
3
3
  from flask import current_app
4
4
  from wtforms.fields import FileField
5
5
  from flask_exts.admin.sqla.ajax import QueryAjaxModelLoader
6
- from flask_exts.forms.widgets.render_template import RenderTemplateWidget
6
+ from flask_exts.template.widgets.render_template import RenderTemplateWidget
7
7
  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
- from flask_exts.forms.fields.sqla import InlineModelFormList
11
- from ..models.model import ImageType, Location, LocationImage
10
+ from flask_exts.template.fields.sqla import InlineModelFormList
11
+ from ..models.location_image import ImageType, Location, LocationImage
12
+ from ..file_op import save_image
12
13
 
13
14
 
14
15
  # This widget uses custom template for inline field list
@@ -60,7 +61,7 @@ class LocationImageInlineModelForm(InlineFormAdmin):
60
61
 
61
62
  if file_data:
62
63
  model.path = secure_filename(file_data.filename)
63
- current_app.save_image(file_data, model.path)
64
+ save_image(file_data, model.path)
64
65
 
65
66
 
66
67
  # Administrative class
@@ -9,7 +9,7 @@ def create_app():
9
9
  app = Flask(__name__)
10
10
  app.config["SECRET_KEY"] = "dev"
11
11
  app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
12
- app.config["ADMIN_ACCESS_ENABLED"] = False
12
+
13
13
  init_app(app)
14
14
  return app
15
15
 
@@ -22,11 +22,5 @@ def init_app(app: Flask):
22
22
  # db.drop_all()
23
23
  db.create_all()
24
24
 
25
- # Flask views
26
- @app.route("/")
27
- def index():
28
-
29
- return '<a href="/admin/">Click me to get to Admin!</a>'
30
-
31
- admin = app.extensions["manager"].admins[0]
25
+ admin = manager.admins[0]
32
26
  admin.add_view(file_view)
@@ -0,0 +1,3 @@
1
+ # JWT
2
+ JWT_SECRET_KEY = "SECRET_KEY"
3
+ JWT_HASH = "HS256"
@@ -5,7 +5,7 @@ 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
9
  # Manager init
10
10
  manager = Manager()
11
11
  manager.init_app(app)
@@ -0,0 +1,27 @@
1
+ # simple.py
2
+
3
+ from flask import Flask
4
+ from flask_exts import Manager
5
+ from flask_exts.admin import expose
6
+ from flask_exts.admin import BaseView
7
+ from flask_exts.views.index_view import IndexView
8
+
9
+
10
+ class MockView(BaseView):
11
+ @expose("/")
12
+ def index(self):
13
+ return "Success!"
14
+
15
+
16
+ app = Flask(__name__)
17
+ app.config["SECRET_KEY"] = "dev"
18
+ manager = Manager()
19
+ manager.init_app(app)
20
+ # Register the index view
21
+ manager.admin.add_view(IndexView(), is_menu=False)
22
+ # Register a mock view
23
+ manager.admin.add_view(MockView())
24
+
25
+
26
+ if __name__ == "__main__":
27
+ app.run(debug=True)
@@ -33,8 +33,11 @@ dependencies = [
33
33
  "Flask-Login>=0.6",
34
34
  "tablib>=3.0",
35
35
  "casbin>=1.0",
36
- "PyJWT>=2.0",
36
+ "PyJWT>=2.0",
37
+ "pyotp>=2.0",
37
38
  "webauthn>=2.0",
39
+ "qrcode>=8.0",
40
+ "pillow>=11.0",
38
41
  ]
39
42
 
40
43
  [project.optional-dependencies]
@@ -0,0 +1 @@
1
+ __version__ = "0.2.4"
@@ -1,3 +1,2 @@
1
- from .admin import Admin
2
1
  from .view import BaseView
3
2
  from .view import expose
@@ -0,0 +1,15 @@
1
+ from .base_admin import BaseAdmin
2
+ from ..utils.authorize import authorize_allow
3
+ class Admin(BaseAdmin):
4
+
5
+ def allow(self, *args, **kwargs):
6
+ return authorize_allow(*args, **kwargs)
7
+
8
+ def init_views(self):
9
+ from ..views.index_view import IndexView
10
+ from ..views.user_view import UserView
11
+ index_view = IndexView()
12
+ self.add_view(index_view, is_menu=False)
13
+
14
+ user_view = UserView()
15
+ self.add_view(user_view, is_menu=False)
@@ -0,0 +1,134 @@
1
+ from flask import render_template
2
+ from flask import url_for
3
+ from flask import make_response
4
+ from .menu import Menu
5
+
6
+
7
+ class BaseAdmin:
8
+ """
9
+ Collection of the admin views. Also manages menu structure.
10
+ """
11
+
12
+ def __init__(self, app=None):
13
+ self.app = app
14
+ self.name = self.get_admin_name()
15
+ self.url = self.get_admin_url()
16
+ self.endpoint = self.get_admin_endpoint()
17
+ self.template_folder = self.get_admin_template_folder()
18
+ self.static_folder = self.get_admin_static_folder()
19
+ self._views = {}
20
+ self.menu = Menu(self)
21
+ self.init_views()
22
+ if app is not None:
23
+ self.init_app(app)
24
+
25
+ def init_app(self, app):
26
+ """
27
+ Constructor.
28
+
29
+ :param app:
30
+ Flask application object
31
+ :param name:
32
+ Application name. Will be displayed in the main menu and as a page title. Defaults to "Admin"
33
+ :param url:
34
+ Base URL
35
+ :param endpoint:
36
+ Base endpoint name for index view. If you use multiple instances of the `Admin` class with
37
+ a single Flask application, you have to set a unique endpoint name for each instance.
38
+
39
+ """
40
+ self.app = app
41
+
42
+ # Register views
43
+ for v in self._views.values():
44
+ app.register_blueprint(v.create_blueprint())
45
+
46
+ def get_admin_name(self):
47
+ name = "Admin"
48
+ return name
49
+
50
+ def get_admin_url(self):
51
+ url = "/admin"
52
+ if not url.startswith("/"):
53
+ raise ValueError("admin.url must startswith /")
54
+ return url
55
+
56
+ def get_admin_endpoint(self):
57
+ return "admin"
58
+
59
+ def get_admin_template_folder(self):
60
+ template_folder = "../templates"
61
+ return template_folder
62
+
63
+ def get_admin_static_folder(self):
64
+ static_folder = "../static"
65
+ return static_folder
66
+
67
+ def add_view(self, view, is_menu=True, category=None):
68
+ """
69
+ Add a view to the collection.
70
+
71
+ :param view:
72
+ View to add.
73
+ """
74
+ # attach self(admin) to view
75
+ view.admin = self
76
+
77
+ # Add to _views
78
+ view_name = view.name.lower().replace(" ", "_")
79
+
80
+ if view_name in self._views:
81
+ raise ValueError(f"View with name {view.name} already exists")
82
+
83
+ self._views[view_name] = view
84
+
85
+ # If app was provided in constructor, register view with Flask app
86
+ if self.app is not None:
87
+ self.app.register_blueprint(view.create_blueprint())
88
+
89
+ if is_menu:
90
+ self.menu.add_view(view, category)
91
+
92
+ def get_url(self, endpoint, **kwargs):
93
+ """
94
+ Generate URL for the endpoint.
95
+
96
+ :param endpoint:
97
+ Flask endpoint name
98
+ :param kwargs:
99
+ Arguments for `url_for`
100
+ """
101
+ return url_for(endpoint, **kwargs)
102
+
103
+ def allow(self, *args, **kwargs):
104
+ return True
105
+
106
+ def init_views(self):
107
+ """
108
+ Initialize views. This method can be overridden in subclasses to add custom views.
109
+ """
110
+ pass
111
+
112
+ def render(self, template, **kwargs):
113
+ """
114
+ Render template
115
+
116
+ :param template:
117
+ Template path to render
118
+ :param kwargs:
119
+ Template arguments
120
+ """
121
+ # Add admin instance to kwargs
122
+ kwargs["admin"] = self
123
+ # Add URL generation method to kwargs
124
+ kwargs["get_url"] = self.get_url
125
+
126
+ # If _headers is provided in kwargs, use make_response to set headers
127
+ if "_headers" in kwargs:
128
+ headers = kwargs.pop("_headers")
129
+ response = make_response(render_template(template, **kwargs))
130
+ for key, value in headers.items():
131
+ response.headers[key] = value
132
+ return response
133
+ else:
134
+ return render_template(template, **kwargs)
@@ -3,9 +3,9 @@ import warnings
3
3
  from wtforms.fields import HiddenField
4
4
  from wtforms.fields.core import UnboundField
5
5
  from wtforms.validators import InputRequired
6
- from ...forms.widgets import XEditableWidget
7
- from ...forms.form import BaseForm
8
- from ...forms.rules import RuleSet
6
+ from ...template.widgets import XEditableWidget
7
+ from ...template.form.base_form import BaseForm
8
+ from ...template.rules import RuleSet
9
9
 
10
10
 
11
11
  def converts(*args):