flask-appbuilder 3.2.1rc1__py3-none-any.whl → 5.0.2rc1__py3-none-any.whl

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 (228) hide show
  1. flask_appbuilder/__init__.py +2 -3
  2. flask_appbuilder/_compat.py +0 -1
  3. flask_appbuilder/actions.py +14 -14
  4. flask_appbuilder/api/__init__.py +741 -527
  5. flask_appbuilder/api/convert.py +104 -98
  6. flask_appbuilder/api/manager.py +14 -8
  7. flask_appbuilder/api/schemas.py +12 -1
  8. flask_appbuilder/babel/manager.py +12 -16
  9. flask_appbuilder/base.py +353 -280
  10. flask_appbuilder/basemanager.py +1 -1
  11. flask_appbuilder/baseviews.py +241 -164
  12. flask_appbuilder/charts/jsontools.py +10 -10
  13. flask_appbuilder/charts/views.py +56 -60
  14. flask_appbuilder/cli.py +115 -70
  15. flask_appbuilder/const.py +52 -52
  16. flask_appbuilder/exceptions.py +67 -5
  17. flask_appbuilder/fields.py +32 -23
  18. flask_appbuilder/fieldwidgets.py +34 -27
  19. flask_appbuilder/filemanager.py +33 -45
  20. flask_appbuilder/filters.py +11 -13
  21. flask_appbuilder/forms.py +31 -35
  22. flask_appbuilder/hooks.py +90 -0
  23. flask_appbuilder/menu.py +35 -10
  24. flask_appbuilder/models/base.py +47 -57
  25. flask_appbuilder/models/decorators.py +13 -13
  26. flask_appbuilder/models/filters.py +42 -38
  27. flask_appbuilder/models/generic/__init__.py +29 -29
  28. flask_appbuilder/models/generic/filters.py +11 -3
  29. flask_appbuilder/models/generic/interface.py +1 -3
  30. flask_appbuilder/models/group.py +37 -39
  31. flask_appbuilder/models/mixins.py +22 -18
  32. flask_appbuilder/models/sqla/__init__.py +19 -72
  33. flask_appbuilder/models/sqla/base.py +24 -0
  34. flask_appbuilder/models/sqla/base_legacy.py +132 -0
  35. flask_appbuilder/models/sqla/filters.py +132 -19
  36. flask_appbuilder/models/sqla/interface.py +390 -276
  37. flask_appbuilder/security/api.py +31 -35
  38. flask_appbuilder/security/decorators.py +181 -83
  39. flask_appbuilder/security/forms.py +20 -31
  40. flask_appbuilder/security/manager.py +715 -489
  41. flask_appbuilder/security/registerviews.py +29 -112
  42. flask_appbuilder/security/schemas.py +43 -0
  43. flask_appbuilder/security/sqla/apis/__init__.py +8 -0
  44. flask_appbuilder/security/sqla/apis/group/__init__.py +1 -0
  45. flask_appbuilder/security/sqla/apis/group/api.py +227 -0
  46. flask_appbuilder/security/sqla/apis/group/schema.py +73 -0
  47. flask_appbuilder/security/sqla/apis/permission/__init__.py +1 -0
  48. flask_appbuilder/security/sqla/apis/permission/api.py +19 -0
  49. flask_appbuilder/security/sqla/apis/permission_view_menu/__init__.py +1 -0
  50. flask_appbuilder/security/sqla/apis/permission_view_menu/api.py +16 -0
  51. flask_appbuilder/security/sqla/apis/role/__init__.py +1 -0
  52. flask_appbuilder/security/sqla/apis/role/api.py +306 -0
  53. flask_appbuilder/security/sqla/apis/role/schema.py +27 -0
  54. flask_appbuilder/security/sqla/apis/user/__init__.py +1 -0
  55. flask_appbuilder/security/sqla/apis/user/api.py +292 -0
  56. flask_appbuilder/security/sqla/apis/user/schema.py +97 -0
  57. flask_appbuilder/security/sqla/apis/user/validator.py +27 -0
  58. flask_appbuilder/security/sqla/apis/view_menu/__init__.py +1 -0
  59. flask_appbuilder/security/sqla/apis/view_menu/api.py +18 -0
  60. flask_appbuilder/security/sqla/manager.py +421 -203
  61. flask_appbuilder/security/sqla/models.py +192 -57
  62. flask_appbuilder/security/utils.py +9 -0
  63. flask_appbuilder/security/views.py +232 -229
  64. flask_appbuilder/static/.DS_Store +0 -0
  65. flask_appbuilder/static/appbuilder/css/ab.css +20 -12
  66. flask_appbuilder/static/appbuilder/css/bootstrap-datepicker/bootstrap-datepicker3.min.css +7 -0
  67. flask_appbuilder/static/appbuilder/css/bootstrap.min.css.map +1 -0
  68. flask_appbuilder/static/appbuilder/css/flags/flags16.css +249 -245
  69. flask_appbuilder/static/appbuilder/css/fontawesome/all.min.css +6 -0
  70. flask_appbuilder/static/appbuilder/css/fontawesome/brands.min.css +6 -0
  71. flask_appbuilder/static/appbuilder/css/fontawesome/fontawesome.min.css +6 -0
  72. flask_appbuilder/static/appbuilder/css/fontawesome/regular.min.css +6 -0
  73. flask_appbuilder/static/appbuilder/css/fontawesome/solid.min.css +6 -0
  74. flask_appbuilder/static/appbuilder/css/fontawesome/svg-with-js.min.css +6 -0
  75. flask_appbuilder/static/appbuilder/css/fontawesome/v4-font-face.min.css +6 -0
  76. flask_appbuilder/static/appbuilder/css/fontawesome/v4-shims.min.css +6 -0
  77. flask_appbuilder/static/appbuilder/css/fontawesome/v5-font-face.min.css +6 -0
  78. flask_appbuilder/static/appbuilder/css/images/flags16.png +0 -0
  79. flask_appbuilder/static/appbuilder/css/select2/select2-bootstrap.min.css +7 -0
  80. flask_appbuilder/static/appbuilder/css/select2/select2.min.css +1 -0
  81. flask_appbuilder/static/appbuilder/css/swagger/swagger-ui.css +3 -0
  82. flask_appbuilder/static/appbuilder/css/webfonts/fa-brands-400.ttf +0 -0
  83. flask_appbuilder/static/appbuilder/css/webfonts/fa-brands-400.woff2 +0 -0
  84. flask_appbuilder/static/appbuilder/css/webfonts/fa-regular-400.ttf +0 -0
  85. flask_appbuilder/static/appbuilder/css/webfonts/fa-regular-400.woff2 +0 -0
  86. flask_appbuilder/static/appbuilder/css/webfonts/fa-solid-900.ttf +0 -0
  87. flask_appbuilder/static/appbuilder/css/webfonts/fa-solid-900.woff2 +0 -0
  88. flask_appbuilder/static/appbuilder/css/webfonts/fa-v4compatibility.ttf +0 -0
  89. flask_appbuilder/static/appbuilder/css/webfonts/fa-v4compatibility.woff2 +0 -0
  90. flask_appbuilder/static/appbuilder/js/ab.js +33 -23
  91. flask_appbuilder/static/appbuilder/js/ab_filters.js +91 -84
  92. flask_appbuilder/static/appbuilder/js/bootstrap-datepicker/bootstrap-datepicker.min.js +8 -0
  93. flask_appbuilder/static/appbuilder/js/jquery-latest.js +2 -2
  94. flask_appbuilder/static/appbuilder/js/select2/select2.min.js +2 -0
  95. flask_appbuilder/static/appbuilder/js/swagger-ui-bundle.js +3 -0
  96. flask_appbuilder/templates/appbuilder/baselib.html +9 -3
  97. flask_appbuilder/templates/appbuilder/general/lib.html +60 -34
  98. flask_appbuilder/templates/appbuilder/general/model/edit.html +1 -1
  99. flask_appbuilder/templates/appbuilder/general/model/edit_cascade.html +1 -1
  100. flask_appbuilder/templates/appbuilder/general/model/search.html +3 -2
  101. flask_appbuilder/templates/appbuilder/general/model/show.html +1 -1
  102. flask_appbuilder/templates/appbuilder/general/model/show_cascade.html +1 -1
  103. flask_appbuilder/templates/appbuilder/general/security/login_db.html +7 -7
  104. flask_appbuilder/templates/appbuilder/general/security/login_ldap.html +5 -5
  105. flask_appbuilder/templates/appbuilder/general/security/login_oauth.html +24 -49
  106. flask_appbuilder/templates/appbuilder/general/widgets/base_list.html +2 -1
  107. flask_appbuilder/templates/appbuilder/general/widgets/chart.html +4 -2
  108. flask_appbuilder/templates/appbuilder/general/widgets/direct_chart.html +4 -3
  109. flask_appbuilder/templates/appbuilder/general/widgets/multiple_chart.html +3 -2
  110. flask_appbuilder/templates/appbuilder/general/widgets/search.html +11 -10
  111. flask_appbuilder/templates/appbuilder/init.html +37 -43
  112. flask_appbuilder/templates/appbuilder/navbar_menu.html +1 -1
  113. flask_appbuilder/templates/appbuilder/navbar_right.html +2 -2
  114. flask_appbuilder/templates/appbuilder/swagger/swagger.html +22 -19
  115. flask_appbuilder/translations/de/LC_MESSAGES/messages.mo +0 -0
  116. flask_appbuilder/translations/de/LC_MESSAGES/messages.po +305 -161
  117. flask_appbuilder/translations/fa/LC_MESSAGES/messages.mo +0 -0
  118. flask_appbuilder/translations/fa/LC_MESSAGES/messages.po +802 -0
  119. flask_appbuilder/translations/fr/LC_MESSAGES/messages.po +461 -319
  120. flask_appbuilder/translations/pt_BR/LC_MESSAGES/messages.po +650 -650
  121. flask_appbuilder/translations/ru/LC_MESSAGES/messages.po +1 -1
  122. flask_appbuilder/translations/sl/LC_MESSAGES/messages.mo +0 -0
  123. flask_appbuilder/translations/sl/LC_MESSAGES/messages.po +690 -0
  124. flask_appbuilder/translations/tr/LC_MESSAGES/messages.mo +0 -0
  125. flask_appbuilder/translations/tr/LC_MESSAGES/messages.po +1015 -0
  126. flask_appbuilder/upload.py +20 -22
  127. flask_appbuilder/urltools.py +39 -19
  128. flask_appbuilder/utils/base.py +76 -0
  129. flask_appbuilder/utils/legacy.py +33 -0
  130. flask_appbuilder/utils/limit.py +20 -0
  131. flask_appbuilder/validators.py +73 -14
  132. flask_appbuilder/views.py +75 -424
  133. flask_appbuilder/widgets.py +50 -51
  134. {Flask_AppBuilder-3.2.1rc1.dist-info → flask_appbuilder-5.0.2rc1.dist-info}/METADATA +36 -76
  135. flask_appbuilder-5.0.2rc1.dist-info/RECORD +240 -0
  136. {Flask_AppBuilder-3.2.1rc1.dist-info → flask_appbuilder-5.0.2rc1.dist-info}/WHEEL +1 -1
  137. flask_appbuilder-5.0.2rc1.dist-info/entry_points.txt +2 -0
  138. Flask_AppBuilder-3.2.1rc1.dist-info/RECORD +0 -270
  139. Flask_AppBuilder-3.2.1rc1.dist-info/entry_points.txt +0 -6
  140. flask_appbuilder/console.py +0 -426
  141. flask_appbuilder/models/mongoengine/__init__.py +0 -0
  142. flask_appbuilder/models/mongoengine/fields.py +0 -65
  143. flask_appbuilder/models/mongoengine/filters.py +0 -145
  144. flask_appbuilder/models/mongoengine/interface.py +0 -328
  145. flask_appbuilder/security/mongoengine/__init__.py +0 -0
  146. flask_appbuilder/security/mongoengine/manager.py +0 -402
  147. flask_appbuilder/security/mongoengine/models.py +0 -120
  148. flask_appbuilder/static/appbuilder/css/font-awesome.min.css +0 -4
  149. flask_appbuilder/static/appbuilder/datepicker/bootstrap-datepicker.css +0 -9
  150. flask_appbuilder/static/appbuilder/datepicker/bootstrap-datepicker.js +0 -28
  151. flask_appbuilder/static/appbuilder/fonts/FontAwesome.otf +0 -0
  152. flask_appbuilder/static/appbuilder/fonts/fontawesome-webfont.eot +0 -0
  153. flask_appbuilder/static/appbuilder/fonts/fontawesome-webfont.svg +0 -2671
  154. flask_appbuilder/static/appbuilder/fonts/fontawesome-webfont.ttf +0 -0
  155. flask_appbuilder/static/appbuilder/fonts/fontawesome-webfont.woff +0 -0
  156. flask_appbuilder/static/appbuilder/fonts/fontawesome-webfont.woff2 +0 -0
  157. flask_appbuilder/static/appbuilder/img/aol.png +0 -0
  158. flask_appbuilder/static/appbuilder/img/flags/flags16.png +0 -0
  159. flask_appbuilder/static/appbuilder/img/flickr.png +0 -0
  160. flask_appbuilder/static/appbuilder/img/google.png +0 -0
  161. flask_appbuilder/static/appbuilder/img/myopenid.png +0 -0
  162. flask_appbuilder/static/appbuilder/img/yahoo.png +0 -0
  163. flask_appbuilder/static/appbuilder/js/_google_charts.js +0 -39
  164. flask_appbuilder/static/appbuilder/js/html5shiv.js +0 -8
  165. flask_appbuilder/static/appbuilder/js/respond.min.js +0 -6
  166. flask_appbuilder/static/appbuilder/select2/select2-spinner.gif +0 -0
  167. flask_appbuilder/static/appbuilder/select2/select2.css +0 -1205
  168. flask_appbuilder/static/appbuilder/select2/select2.js +0 -23
  169. flask_appbuilder/static/appbuilder/select2/select2.png +0 -0
  170. flask_appbuilder/static/appbuilder/select2/select2x2.png +0 -0
  171. flask_appbuilder/templates/appbuilder/general/security/login_oid.html +0 -129
  172. flask_appbuilder/templates/appbuilder/general/security/resetpassword.html +0 -29
  173. flask_appbuilder/tests/__init__.py +0 -0
  174. flask_appbuilder/tests/__pycache__/__init__.cpython-36.pyc +0 -0
  175. flask_appbuilder/tests/__pycache__/__init__.cpython-37.pyc +0 -0
  176. flask_appbuilder/tests/__pycache__/_test_auth_ldap.cpython-37.pyc +0 -0
  177. flask_appbuilder/tests/__pycache__/_test_auth_oauth.cpython-37.pyc +0 -0
  178. flask_appbuilder/tests/__pycache__/_test_ldapsearch.cpython-36.pyc +0 -0
  179. flask_appbuilder/tests/__pycache__/_test_oauth_registration_role.cpython-36.pyc +0 -0
  180. flask_appbuilder/tests/__pycache__/base.cpython-36.pyc +0 -0
  181. flask_appbuilder/tests/__pycache__/base.cpython-37.pyc +0 -0
  182. flask_appbuilder/tests/__pycache__/config_api.cpython-36.pyc +0 -0
  183. flask_appbuilder/tests/__pycache__/config_api.cpython-37.pyc +0 -0
  184. flask_appbuilder/tests/__pycache__/const.cpython-36.pyc +0 -0
  185. flask_appbuilder/tests/__pycache__/const.cpython-37.pyc +0 -0
  186. flask_appbuilder/tests/__pycache__/test_0_fixture.cpython-36.pyc +0 -0
  187. flask_appbuilder/tests/__pycache__/test_0_fixture.cpython-37.pyc +0 -0
  188. flask_appbuilder/tests/__pycache__/test_api.cpython-36.pyc +0 -0
  189. flask_appbuilder/tests/__pycache__/test_api.cpython-37.pyc +0 -0
  190. flask_appbuilder/tests/__pycache__/test_fab_cli.cpython-36.pyc +0 -0
  191. flask_appbuilder/tests/__pycache__/test_fab_cli.cpython-37.pyc +0 -0
  192. flask_appbuilder/tests/__pycache__/test_menu.cpython-36.pyc +0 -0
  193. flask_appbuilder/tests/__pycache__/test_menu.cpython-37.pyc +0 -0
  194. flask_appbuilder/tests/__pycache__/test_mongoengine.cpython-36.pyc +0 -0
  195. flask_appbuilder/tests/__pycache__/test_mvc.cpython-36.pyc +0 -0
  196. flask_appbuilder/tests/__pycache__/test_mvc.cpython-37.pyc +0 -0
  197. flask_appbuilder/tests/__pycache__/test_sqlalchemy.cpython-36.pyc +0 -0
  198. flask_appbuilder/tests/__pycache__/test_sqlalchemy.cpython-37.pyc +0 -0
  199. flask_appbuilder/tests/_test_auth_ldap.py +0 -1045
  200. flask_appbuilder/tests/_test_auth_oauth.py +0 -419
  201. flask_appbuilder/tests/_test_ldapsearch.py +0 -135
  202. flask_appbuilder/tests/_test_oauth_registration_role.py +0 -59
  203. flask_appbuilder/tests/app.db +0 -0
  204. flask_appbuilder/tests/base.py +0 -90
  205. flask_appbuilder/tests/config_api.py +0 -21
  206. flask_appbuilder/tests/const.py +0 -9
  207. flask_appbuilder/tests/mongoengine/__init__.py +0 -0
  208. flask_appbuilder/tests/mongoengine/__pycache__/__init__.cpython-36.pyc +0 -0
  209. flask_appbuilder/tests/mongoengine/__pycache__/__init__.cpython-37.pyc +0 -0
  210. flask_appbuilder/tests/mongoengine/__pycache__/models.cpython-36.pyc +0 -0
  211. flask_appbuilder/tests/mongoengine/models.py +0 -41
  212. flask_appbuilder/tests/sqla/__init__.py +0 -0
  213. flask_appbuilder/tests/sqla/__pycache__/__init__.cpython-36.pyc +0 -0
  214. flask_appbuilder/tests/sqla/__pycache__/__init__.cpython-37.pyc +0 -0
  215. flask_appbuilder/tests/sqla/__pycache__/models.cpython-36.pyc +0 -0
  216. flask_appbuilder/tests/sqla/__pycache__/models.cpython-37.pyc +0 -0
  217. flask_appbuilder/tests/sqla/models.py +0 -340
  218. flask_appbuilder/tests/test_0_fixture.py +0 -39
  219. flask_appbuilder/tests/test_api.py +0 -2790
  220. flask_appbuilder/tests/test_fab_cli.py +0 -72
  221. flask_appbuilder/tests/test_menu.py +0 -122
  222. flask_appbuilder/tests/test_mongoengine.py +0 -572
  223. flask_appbuilder/tests/test_mvc.py +0 -1710
  224. flask_appbuilder/tests/test_sqlalchemy.py +0 -24
  225. flask_appbuilder/translations/__pycache__/__init__.cpython-36.pyc +0 -0
  226. flask_appbuilder/translations/es/LC_MESSAGES/messages.po~ +0 -582
  227. {Flask_AppBuilder-3.2.1rc1.dist-info → flask_appbuilder-5.0.2rc1.dist-info}/LICENSE +0 -0
  228. {Flask_AppBuilder-3.2.1rc1.dist-info → flask_appbuilder-5.0.2rc1.dist-info}/top_level.txt +0 -0
flask_appbuilder/const.py CHANGED
@@ -17,111 +17,105 @@ from flask_babel import lazy_gettext
17
17
 
18
18
  """
19
19
 
20
- LOGMSG_ERR_SEC_ACCESS_DENIED = "Access is Denied for: {0} on: {1}"
20
+ LOGMSG_ERR_SEC_ACCESS_DENIED = "Access is Denied for: %s on: %s"
21
21
  """ Access denied log message, format with user and view/resource """
22
- LOGMSG_WAR_SEC_LOGIN_FAILED = "Login Failed for user: {0}"
23
- LOGMSG_ERR_SEC_CREATE_DB = "DB Creation and initialization failed: {0}"
22
+ LOGMSG_WAR_SEC_LOGIN_FAILED = "Login Failed for user: %s"
23
+ LOGMSG_ERR_SEC_CREATE_DB = "DB Creation and initialization failed: %s"
24
24
  """ security models creation fails, format with error message """
25
- LOGMSG_ERR_SEC_ADD_ROLE = "Add Role: {0}"
25
+ LOGMSG_ERR_SEC_ADD_ROLE = "Add Role: %s"
26
26
  """ Error adding role, format with err message """
27
- LOGMSG_ERR_SEC_ADD_PERMISSION = "Add Permission: {0}"
27
+ LOGMSG_ERR_SEC_ADD_GROUP = "Add Group: %s"
28
+ """ Error adding group, format with err message """
29
+ LOGMSG_ERR_SEC_ADD_PERMISSION = "Add Permission: %s"
28
30
  """ Error adding permission, format with err message """
29
- LOGMSG_ERR_SEC_ADD_VIEWMENU = "Add View Menu Error: {0}"
31
+ LOGMSG_ERR_SEC_ADD_VIEWMENU = "Add View Menu Error: %s"
30
32
  """ Error adding view menu, format with err message """
31
- LOGMSG_ERR_SEC_DEL_PERMISSION = "Del Permission Error: {0}"
33
+ LOGMSG_ERR_SEC_DEL_PERMISSION = "Del Permission Error: %s"
32
34
  """ Error deleting permission, format with err message """
33
- LOGMSG_ERR_SEC_ADD_PERMVIEW = "Creation of Permission View Error: {0}"
35
+ LOGMSG_ERR_SEC_ADD_PERMVIEW = "Creation of Permission View Error: %s"
34
36
  """ Error adding permission view, format with err message """
35
- LOGMSG_ERR_SEC_DEL_PERMVIEW = "Remove Permission from View Error: {0}"
37
+ LOGMSG_ERR_SEC_DEL_PERMVIEW = "Remove Permission from View Error: %s"
36
38
  """ Error deleting permission view, format with err message """
37
39
  LOGMSG_WAR_SEC_DEL_PERMVIEW = (
38
- "Refused to delete permission view, assoc with role exists {}.{} {}"
40
+ "Refused to delete permission view, assoc with role exists %s.%s %s"
39
41
  )
40
- LOGMSG_WAR_SEC_DEL_PERMISSION = "Refused to delete, permission {} does not exist"
41
- LOGMSG_WAR_SEC_DEL_VIEWMENU = "Refused to delete, view menu {} does not exist"
42
- LOGMSG_WAR_SEC_DEL_PERM_PVM = "Refused to delete permission {}, PVM exists {}"
43
- LOGMSG_WAR_SEC_DEL_VIEWMENU_PVM = "Refused to delete view menu {}, PVM exists {}"
44
- LOGMSG_ERR_SEC_ADD_PERMROLE = "Add Permission to Role Error: {0}"
42
+ LOGMSG_WAR_SEC_DEL_PERMISSION = "Refused to delete, permission %s does not exist"
43
+ LOGMSG_WAR_SEC_DEL_VIEWMENU = "Refused to delete, view menu %s does not exist"
44
+ LOGMSG_WAR_SEC_DEL_PERM_PVM = "Refused to delete permission %s, PVM exists %s"
45
+ LOGMSG_WAR_SEC_DEL_VIEWMENU_PVM = "Refused to delete view menu %s, PVM exists %s"
46
+ LOGMSG_ERR_SEC_ADD_PERMROLE = "Add Permission to Role Error: %s"
45
47
  """ Error adding permission to role, format with err message """
46
- LOGMSG_ERR_SEC_DEL_PERMROLE = "Remove Permission to Role Error: {0}"
48
+ LOGMSG_ERR_SEC_DEL_PERMROLE = "Remove Permission to Role Error: %s"
47
49
  """ Error deleting permission to role, format with err message """
48
- LOGMSG_ERR_SEC_ADD_REGISTER_USER = "Add Register User Error: {0}"
50
+ LOGMSG_ERR_SEC_ADD_REGISTER_USER = "Add Register User Error: %s"
49
51
  """ Error adding registered user, format with err message """
50
- LOGMSG_ERR_SEC_DEL_REGISTER_USER = "Remove Register User Error: {0}"
52
+ LOGMSG_ERR_SEC_DEL_REGISTER_USER = "Remove Register User Error: %s"
51
53
  """ Error deleting registered user, format with err message """
52
- LOGMSG_ERR_SEC_NO_REGISTER_HASH = "Attempt to activate user with false hash: {0}"
54
+ LOGMSG_ERR_SEC_NO_REGISTER_HASH = "Attempt to activate user with false hash: %s"
53
55
  """ Attempt to activate user with not registered hash, format with hash """
54
- LOGMSG_ERR_SEC_AUTH_LDAP = "LDAP Error {0}"
56
+ LOGMSG_ERR_SEC_AUTH_LDAP = "LDAP Error %s"
55
57
  """ Generic LDAP error, format with err message """
56
58
  LOGMSG_ERR_SEC_AUTH_LDAP_TLS = (
57
- "LDAP Could not activate TLS on established connection with {0}"
59
+ "LDAP Could not activate TLS on established connection with %s"
58
60
  )
59
61
  """ LDAP Could not activate TLS on established connection with server """
60
- LOGMSG_ERR_SEC_ADD_USER = "Error adding new user to database. {0}"
62
+ LOGMSG_ERR_SEC_ADD_USER = "Error adding new user to database. %s"
61
63
  """ Error adding user, format with err message """
62
- LOGMSG_ERR_SEC_UPD_USER = "Error updating user to database. {0} "
64
+ LOGMSG_ERR_SEC_UPD_USER = "Error updating user to database. %s "
63
65
  """ Error updating user, format with err message """
64
66
  LOGMSG_WAR_SEC_NO_USER = "No user yet created, use flask fab command to do it."
65
67
  """ Warning when app starts if no user exists on db """
66
- LOGMSG_WAR_SEC_NOLDAP_OBJ = "No LDAP object found for: {0}"
68
+ LOGMSG_WAR_SEC_NOLDAP_OBJ = "No LDAP object found for: %s"
67
69
 
68
- LOGMSG_INF_SEC_ADD_PERMVIEW = "Created Permission View: {0}"
70
+ LOGMSG_INF_SEC_ADD_PERMVIEW = "Created Permission View: %s"
69
71
  """ Info when adding permission view, format with permission view class string """
70
- LOGMSG_INF_SEC_DEL_PERMVIEW = "Removed Permission View: {0} on {1}"
72
+ LOGMSG_INF_SEC_DEL_PERMVIEW = "Removed Permission View: %s on %s"
71
73
  """ Info when deleting permission view, format with permission name and view name """
72
- LOGMSG_INF_SEC_ADD_PERMROLE = "Added Permission {0} to role {1}"
74
+ LOGMSG_INF_SEC_ADD_PERMROLE = "Added Permission %s to role %s"
73
75
  """ Info when adding permission to role,
74
76
  format with permission view class string and role name """
75
- LOGMSG_INF_SEC_DEL_PERMROLE = "Removed Permission {0} to role {1}"
77
+ LOGMSG_INF_SEC_DEL_PERMROLE = "Removed Permission %s to role %s"
76
78
  """ Info when deleting permission to role,
77
79
  format with permission view class string and role name """
78
- LOGMSG_INF_SEC_ADD_ROLE = "Inserted Role: {0}"
80
+ LOGMSG_INF_SEC_ADD_ROLE = "Inserted Role: %s"
79
81
  """ Info when added role, format with role name """
80
82
  LOGMSG_INF_SEC_NO_DB = "Security DB not found Creating all Models from Base"
81
83
  LOGMSG_INF_SEC_ADD_DB = "Security DB Created"
82
- LOGMSG_INF_SEC_ADD_USER = "Added user {0}"
84
+ LOGMSG_INF_SEC_ADD_USER = "Added user %s"
83
85
  """ User added, format with username """
84
- LOGMSG_INF_SEC_UPD_USER = "Updated user {0}"
86
+ LOGMSG_INF_SEC_UPD_USER = "Updated user %s"
85
87
  """ User updated, format with username """
86
- LOGMSG_INF_SEC_UPD_ROLE = "Updated role {0}"
88
+ LOGMSG_INF_SEC_UPD_ROLE = "Updated role %s"
87
89
  """ Role updated, format with role name """
88
- LOGMSG_ERR_SEC_UPD_ROLE = "An error occurred updating role {0}"
90
+ LOGMSG_ERR_SEC_UPD_ROLE = "An error occurred updating role %s"
89
91
  """ Role updated Error, format with role name """
90
92
 
91
- LOGMSG_INF_FAB_ADDON_ADDED = "Registered AddOn: {0}"
93
+ LOGMSG_INF_FAB_ADDON_ADDED = "Registered AddOn: %s"
92
94
  """ Addon imported and registered """
93
- LOGMSG_ERR_FAB_ADDON_IMPORT = "An error occurred when importing declared addon {0}: {1}"
95
+ LOGMSG_ERR_FAB_ADDON_IMPORT = "An error occurred when importing declared addon %s: %s"
94
96
  """ Error on addon import, format with addon class path and error message """
95
- LOGMSG_ERR_FAB_ADDON_PROCESS = (
96
- "An error occurred when processing declared addon {0}: {1}"
97
- )
97
+ LOGMSG_ERR_FAB_ADDON_PROCESS = "An error occurred when processing declared addon %s: %s"
98
98
  """ Error on addon processing (pre, register, post),
99
99
  format with addon class path and error message """
100
100
 
101
101
 
102
- LOGMSG_ERR_FAB_ADD_PERMISSION_MENU = "Add Permission on Menu Error: {0}"
102
+ LOGMSG_ERR_FAB_ADD_PERMISSION_MENU = "Add Permission on Menu Error: %s"
103
103
  """ Error when adding a permission to a menu, format with err """
104
- LOGMSG_ERR_FAB_ADD_PERMISSION_VIEW = "Add Permission on View Error: {0}"
104
+ LOGMSG_ERR_FAB_ADD_PERMISSION_VIEW = "Add Permission on View Error: %s"
105
105
  """ Error when adding a permission to a menu, format with err """
106
106
 
107
- LOGMSG_ERR_DBI_ADD_GENERIC = "Add record error: {0}"
108
- """ Database add generic error, format with err message """
109
- LOGMSG_ERR_DBI_EDIT_GENERIC = "Edit record error: {0}"
110
- """ Database edit generic error, format with err message """
111
- LOGMSG_ERR_DBI_DEL_GENERIC = "Delete record error: {0}"
112
- """ Database delete generic error, format with err message """
113
107
  LOGMSG_WAR_DBI_AVG_ZERODIV = "Zero division on aggregate_avg"
114
108
 
115
- LOGMSG_WAR_FAB_VIEW_EXISTS = "View already exists {0} ignoring"
109
+ LOGMSG_WAR_FAB_VIEW_EXISTS = "View already exists %s ignoring"
116
110
  """ Attempt to add an already added view, format with view name """
117
- LOGMSG_WAR_DBI_ADD_INTEGRITY = "Add record integrity error: {0}"
111
+ LOGMSG_WAR_DBI_ADD_INTEGRITY = "Add record integrity error: %s"
118
112
  """ Dabase integrity error, format with err message """
119
- LOGMSG_WAR_DBI_EDIT_INTEGRITY = "Edit record integrity error: {0}"
113
+ LOGMSG_WAR_DBI_EDIT_INTEGRITY = "Edit record integrity error: %s"
120
114
  """ Dabase integrity error, format with err message """
121
- LOGMSG_WAR_DBI_DEL_INTEGRITY = "Delete record integrity error: {0}"
115
+ LOGMSG_WAR_DBI_DEL_INTEGRITY = "Delete record integrity error: %s"
122
116
  """ Dabase integrity error, format with err message """
123
117
 
124
- LOGMSG_INF_FAB_ADD_VIEW = "Registering class {0} on menu {1}"
118
+ LOGMSG_INF_FAB_ADD_VIEW = "Registering class %s on menu %s"
125
119
  """ Inform that view class was added, format with class name, name"""
126
120
 
127
121
 
@@ -132,7 +126,6 @@ FLAMSG_ERR_SEC_ACCESS_DENIED = lazy_gettext("Access is Denied")
132
126
  PERMISSION_PREFIX = "can_"
133
127
  """ Prefix to be concatenated to permission names, and inserted in the backend """
134
128
 
135
- AUTH_OID = 0
136
129
  AUTH_DB = 1
137
130
  AUTH_LDAP = 2
138
131
  AUTH_REMOTE_USER = 3
@@ -183,6 +176,7 @@ API_DESCRIPTION_COLUMNS_RIS_KEY = "description_columns"
183
176
  API_FILTERS_RIS_KEY = "filters"
184
177
  API_PERMISSIONS_RIS_KEY = "permissions"
185
178
  API_SELECT_COLUMNS_RIS_KEY = "columns"
179
+ API_SELECT_SEL_COLUMNS_RIS_KEY = "select_columns"
186
180
  API_SELECT_KEYS_RIS_KEY = "keys"
187
181
  API_ORDER_COLUMN_RIS_KEY = "order_column"
188
182
  API_ORDER_DIRECTION_RIS_KEY = "order_direction"
@@ -193,3 +187,9 @@ API_LIST_TITLE_RIS_KEY = "list_title"
193
187
  API_ADD_TITLE_RIS_KEY = "add_title"
194
188
  API_EDIT_TITLE_RIS_KEY = "edit_title"
195
189
  API_SHOW_TITLE_RIS_KEY = "show_title"
190
+
191
+ # -----------------------------------
192
+ # OAuth Provider Constants
193
+ # -----------------------------------
194
+
195
+ MICROSOFT_KEY_SET_URL = "https://login.microsoftonline.com/common/discovery/keys"
@@ -1,28 +1,90 @@
1
+ from typing import Optional
2
+
3
+
1
4
  class FABException(Exception):
2
5
  """Base FAB Exception"""
3
6
 
4
- pass
7
+ def __init__(self, *args, exception: Optional[Exception] = None) -> None:
8
+ self.exception = exception
9
+ super().__init__(*args)
10
+
11
+ def __str__(self):
12
+ return (
13
+ f"{self.__class__.__name__}: {self.exception.__class__.__name__}"
14
+ if self.exception
15
+ else super().__str__()
16
+ )
17
+
18
+
19
+ class DatabaseException(FABException):
20
+ """Database related exception"""
5
21
 
6
22
 
7
23
  class InvalidColumnFilterFABException(FABException):
8
24
  """Invalid column for filter"""
9
25
 
10
- pass
26
+ ...
11
27
 
12
28
 
13
29
  class InvalidOperationFilterFABException(FABException):
14
30
  """Invalid operation for filter"""
15
31
 
16
- pass
32
+ ...
17
33
 
18
34
 
19
35
  class InvalidOrderByColumnFABException(FABException):
20
36
  """Invalid order by column"""
21
37
 
22
- pass
38
+ ...
39
+
40
+
41
+ class InvalidColumnArgsFABException(FABException):
42
+ """Invalid combination of column arguments"""
43
+
44
+ ...
23
45
 
24
46
 
25
47
  class InterfaceQueryWithoutSession(FABException):
26
48
  """You need to setup a session on the interface to perform queries"""
27
49
 
28
- pass
50
+ ...
51
+
52
+
53
+ class PasswordComplexityValidationError(FABException):
54
+ """Raise this when implementing your own password complexity function"""
55
+
56
+ ...
57
+
58
+
59
+ class ApplyFilterException(FABException):
60
+ """When executing an apply filter a SQLAlchemy exception happens"""
61
+
62
+ ...
63
+
64
+
65
+ class OAuthProviderUnknown(FABException):
66
+ """
67
+ When an OAuth provider is not supported/unknown
68
+ """
69
+
70
+ ...
71
+
72
+
73
+ class InvalidLoginAttempt(FABException):
74
+ """
75
+ When the credentials entered could not be verified
76
+ """
77
+
78
+ ...
79
+
80
+
81
+ class DeleteGroupWithUsersException(FABException):
82
+ """
83
+ When trying to delete a group with users
84
+ """
85
+
86
+
87
+ class DeleteRoleWithUsersException(FABException):
88
+ """
89
+ When trying to delete a role with users
90
+ """
@@ -2,25 +2,28 @@ from __future__ import unicode_literals
2
2
 
3
3
  import operator
4
4
 
5
+ from packaging import version
6
+ import wtforms
5
7
  from wtforms import widgets
6
- from wtforms.compat import string_types, text_type
7
8
  from wtforms.fields import Field, SelectField, SelectFieldBase
8
9
  from wtforms.validators import ValidationError
9
10
 
11
+ IS_WTFORMS_LESS_THEN_3_1_0 = version.parse(wtforms.__version__) < version.parse("3.1.0")
12
+
10
13
 
11
14
  class AJAXSelectField(Field):
12
15
  """
13
- Simple class to convert primary key to ORM objects
14
- for SQLAlchemy and fab normal processing on add and update
15
- This WTF field class is prepared to be used in related views or directly on forms.
16
-
17
- :param label: The label to render on form
18
- :param validators: A list of form validators
19
- :param: datamodel: An initialized SQLAInterface with a model
20
- :param: col_name: The column that maps to the model
21
- :param: is_related:
22
- If the model column is a relationship or direct on
23
- this case use col_name with the pk
16
+ Simple class to convert primary key to ORM objects
17
+ for SQLAlchemy and fab normal processing on add and update
18
+ This WTF field class is prepared to be used in related views or directly on forms.
19
+
20
+ :param label: The label to render on form
21
+ :param validators: A list of form validators
22
+ :param: datamodel: An initialized SQLAInterface with a model
23
+ :param: col_name: The column that maps to the model
24
+ :param: is_related:
25
+ If the model column is a relationship or direct on
26
+ this case use col_name with the pk
24
27
  """
25
28
 
26
29
  def __init__(
@@ -78,7 +81,7 @@ class AJAXSelectField(Field):
78
81
 
79
82
  class QuerySelectField(SelectFieldBase):
80
83
  """
81
- Based on WTForms QuerySelectField
84
+ Based on WTForms QuerySelectField
82
85
  """
83
86
 
84
87
  widget = widgets.Select()
@@ -100,7 +103,7 @@ class QuerySelectField(SelectFieldBase):
100
103
 
101
104
  if get_label is None:
102
105
  self.get_label = lambda x: x
103
- elif isinstance(get_label, string_types):
106
+ elif isinstance(get_label, str):
104
107
  self.get_label = operator.attrgetter(get_label)
105
108
  else:
106
109
  self.get_label = get_label
@@ -126,17 +129,21 @@ class QuerySelectField(SelectFieldBase):
126
129
  def _get_object_list(self):
127
130
  if self._object_list is None:
128
131
  objs = self.query_func()
129
- self._object_list = list(
130
- (text_type(self.get_pk_func(obj)), obj) for obj in objs
131
- )
132
+ self._object_list = list((str(self.get_pk_func(obj)), obj) for obj in objs)
132
133
  return self._object_list
133
134
 
134
135
  def iter_choices(self):
135
136
  if self.allow_blank:
136
- yield ("__None", self.blank_text, self.data is None)
137
+ if IS_WTFORMS_LESS_THEN_3_1_0:
138
+ yield ("__None", self.blank_text, self.data is None)
139
+ else:
140
+ yield ("__None", self.blank_text, self.data is None, {})
137
141
 
138
142
  for pk, obj in self._get_object_list():
139
- yield (pk, self.get_label(obj), obj == self.data)
143
+ if IS_WTFORMS_LESS_THEN_3_1_0:
144
+ yield (pk, self.get_label(obj), obj == self.data)
145
+ else:
146
+ yield (pk, self.get_label(obj), obj == self.data, {})
140
147
 
141
148
  def process_formdata(self, valuelist):
142
149
  if valuelist:
@@ -206,7 +213,10 @@ class QuerySelectMultipleField(QuerySelectField):
206
213
 
207
214
  def iter_choices(self):
208
215
  for pk, obj in self._get_object_list():
209
- yield (pk, self.get_label(obj), obj in self.data)
216
+ if IS_WTFORMS_LESS_THEN_3_1_0:
217
+ yield (pk, self.get_label(obj), obj in self.data)
218
+ else:
219
+ yield (pk, self.get_label(obj), obj in self.data, {})
210
220
 
211
221
  def process_formdata(self, valuelist):
212
222
  self._formdata = set(valuelist)
@@ -243,8 +253,7 @@ class EnumField(SelectField):
243
253
  # Column(Enum(enum.Enum)) case
244
254
  if enum_class is not None:
245
255
  labels = [
246
- text_type(enum_class.__members__[enum_member].value)
247
- for enum_member in enums
256
+ str(enum_class.__members__[enum_member].value) for enum_member in enums
248
257
  ]
249
258
 
250
259
  def coerce(value):
@@ -262,7 +271,7 @@ class EnumField(SelectField):
262
271
  def coerce(value):
263
272
  if value is None:
264
273
  return None
265
- return text_type(value)
274
+ return str(value)
266
275
 
267
276
  choices = list(zip(enums, labels))
268
277
 
@@ -1,16 +1,18 @@
1
1
  from flask_babel import lazy_gettext as _
2
+ from markupsafe import Markup
2
3
  from wtforms import widgets
3
- from wtforms.widgets import html_params, HTMLString
4
+ from wtforms.widgets import html_params
4
5
 
5
6
 
6
- class DatePickerWidget(object):
7
+ class DatePickerWidget:
7
8
  """
8
9
  Date Time picker from Eonasdan GitHub
9
10
 
10
11
  """
11
12
 
12
13
  data_template = (
13
- '<div class="input-group date appbuilder_date" id="datepicker">'
14
+ '<div class="input-group date appbuilder_date"'
15
+ ' data-provide="datepicker" id="datepicker">'
14
16
  '<span class="input-group-addon"><i class="fa fa-calendar cursor-hand"></i>'
15
17
  "</span>"
16
18
  '<input class="form-control" data-format="yyyy-MM-dd" %(text)s />'
@@ -24,19 +26,20 @@ class DatePickerWidget(object):
24
26
  field.data = ""
25
27
  template = self.data_template
26
28
 
27
- return HTMLString(
29
+ return Markup(
28
30
  template % {"text": html_params(type="text", value=field.data, **kwargs)}
29
31
  )
30
32
 
31
33
 
32
- class DateTimePickerWidget(object):
34
+ class DateTimePickerWidget:
33
35
  """
34
36
  Date Time picker from Eonasdan GitHub
35
37
 
36
38
  """
37
39
 
38
40
  data_template = (
39
- '<div class="input-group date appbuilder_datetime" id="datetimepicker">'
41
+ '<div class="input-group date appbuilder_datetime" '
42
+ 'data-provide="datepicker" id="datetimepicker">'
40
43
  '<span class="input-group-addon"><i class="fa fa-calendar cursor-hand"></i>'
41
44
  "</span>"
42
45
  '<input class="form-control" data-format="yyyy-MM-dd hh:mm:ss" %(text)s />'
@@ -50,14 +53,14 @@ class DateTimePickerWidget(object):
50
53
  field.data = ""
51
54
  template = self.data_template
52
55
 
53
- return HTMLString(
56
+ return Markup(
54
57
  template % {"text": html_params(type="text", value=field.data, **kwargs)}
55
58
  )
56
59
 
57
60
 
58
61
  class BS3TextFieldWidget(widgets.TextInput):
59
62
  def __call__(self, field, **kwargs):
60
- kwargs["class"] = u"form-control"
63
+ kwargs["class"] = "form-control"
61
64
  if field.label:
62
65
  kwargs["placeholder"] = field.label.text
63
66
  if "name_" in kwargs:
@@ -67,7 +70,7 @@ class BS3TextFieldWidget(widgets.TextInput):
67
70
 
68
71
  class BS3TextAreaFieldWidget(widgets.TextArea):
69
72
  def __call__(self, field, **kwargs):
70
- kwargs["class"] = u"form-control"
73
+ kwargs["class"] = "form-control"
71
74
  kwargs["rows"] = 3
72
75
  if field.label:
73
76
  kwargs["placeholder"] = field.label.text
@@ -76,25 +79,26 @@ class BS3TextAreaFieldWidget(widgets.TextArea):
76
79
 
77
80
  class BS3PasswordFieldWidget(widgets.PasswordInput):
78
81
  def __call__(self, field, **kwargs):
79
- kwargs["class"] = u"form-control"
82
+ kwargs["class"] = "form-control"
80
83
  if field.label:
81
84
  kwargs["placeholder"] = field.label.text
82
85
  return super(BS3PasswordFieldWidget, self).__call__(field, **kwargs)
83
86
 
84
87
 
85
- class Select2AJAXWidget(object):
88
+ class Select2AJAXWidget:
86
89
  data_template = "<input %(text)s />"
87
90
 
88
91
  def __init__(self, endpoint, extra_classes=None, style=None):
89
92
  self.endpoint = endpoint
90
93
  self.extra_classes = extra_classes
91
- self.style = style or u"width:250px"
94
+ self.style = style or ""
92
95
 
93
96
  def __call__(self, field, **kwargs):
94
97
  kwargs.setdefault("id", field.id)
95
98
  kwargs.setdefault("name", field.name)
96
99
  kwargs.setdefault("endpoint", self.endpoint)
97
- kwargs.setdefault("style", self.style)
100
+ if self.style:
101
+ kwargs.setdefault("style", self.style)
98
102
  input_classes = "input-group my_select2_ajax"
99
103
  if self.extra_classes:
100
104
  input_classes = input_classes + " " + self.extra_classes
@@ -103,26 +107,27 @@ class Select2AJAXWidget(object):
103
107
  field.data = ""
104
108
  template = self.data_template
105
109
 
106
- return HTMLString(
110
+ return Markup(
107
111
  template % {"text": html_params(type="text", value=field.data, **kwargs)}
108
112
  )
109
113
 
110
114
 
111
- class Select2SlaveAJAXWidget(object):
115
+ class Select2SlaveAJAXWidget:
112
116
  data_template = '<input class="input-group my_select2_ajax_slave" %(text)s />'
113
117
 
114
118
  def __init__(self, master_id, endpoint, extra_classes=None, style=None):
115
119
  self.endpoint = endpoint
116
120
  self.master_id = master_id
117
121
  self.extra_classes = extra_classes
118
- self.style = style or u"width:250px"
122
+ self.style = style or ""
119
123
 
120
124
  def __call__(self, field, **kwargs):
121
125
  kwargs.setdefault("id", field.id)
122
126
  kwargs.setdefault("name", field.name)
123
127
  kwargs.setdefault("endpoint", self.endpoint)
124
128
  kwargs.setdefault("master_id", self.master_id)
125
- kwargs.setdefault("style", self.style)
129
+ if self.style:
130
+ kwargs.setdefault("style", self.style)
126
131
  input_classes = "input-group my_select2_ajax"
127
132
  if self.extra_classes:
128
133
  input_classes = input_classes + " " + self.extra_classes
@@ -132,7 +137,7 @@ class Select2SlaveAJAXWidget(object):
132
137
  field.data = ""
133
138
  template = self.data_template
134
139
 
135
- return HTMLString(
140
+ return Markup(
136
141
  template % {"text": html_params(type="text", value=field.data, **kwargs)}
137
142
  )
138
143
 
@@ -142,14 +147,15 @@ class Select2Widget(widgets.Select):
142
147
 
143
148
  def __init__(self, extra_classes=None, style=None):
144
149
  self.extra_classes = extra_classes
145
- self.style = style or u"width:250px"
146
- return super(Select2Widget, self).__init__()
150
+ self.style = style
151
+ super(Select2Widget, self).__init__()
147
152
 
148
153
  def __call__(self, field, **kwargs):
149
- kwargs["class"] = u"my_select2 form-control"
154
+ kwargs["class"] = "my_select2 form-control"
150
155
  if self.extra_classes:
151
156
  kwargs["class"] = kwargs["class"] + " " + self.extra_classes
152
- kwargs["style"] = self.style
157
+ if self.style:
158
+ kwargs["style"] = self.style
153
159
  kwargs["data-placeholder"] = _("Select Value")
154
160
  if "name_" in kwargs:
155
161
  field.name = kwargs["name_"]
@@ -161,16 +167,17 @@ class Select2ManyWidget(widgets.Select):
161
167
 
162
168
  def __init__(self, extra_classes=None, style=None):
163
169
  self.extra_classes = extra_classes
164
- self.style = style or u"width:250px"
165
- return super(Select2ManyWidget, self).__init__()
170
+ self.style = style
171
+ super(Select2ManyWidget, self).__init__()
166
172
 
167
173
  def __call__(self, field, **kwargs):
168
- kwargs["class"] = u"my_select2 form-control"
174
+ kwargs["class"] = "my_select2 form-control"
169
175
  if self.extra_classes:
170
176
  kwargs["class"] = kwargs["class"] + " " + self.extra_classes
171
- kwargs["style"] = self.style
177
+ if self.style:
178
+ kwargs["style"] = self.style
172
179
  kwargs["data-placeholder"] = _("Select Value")
173
- kwargs["multiple"] = u"true"
180
+ kwargs["multiple"] = "true"
174
181
  if "name_" in kwargs:
175
182
  field.name = kwargs["name_"]
176
183
  return super(Select2ManyWidget, self).__call__(field, **kwargs)