flask-appbuilder 3.2.1__py3-none-any.whl → 5.0.2__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.1.dist-info → flask_appbuilder-5.0.2.dist-info}/METADATA +36 -76
  135. flask_appbuilder-5.0.2.dist-info/RECORD +240 -0
  136. {Flask_AppBuilder-3.2.1.dist-info → flask_appbuilder-5.0.2.dist-info}/WHEEL +1 -1
  137. flask_appbuilder-5.0.2.dist-info/entry_points.txt +2 -0
  138. Flask_AppBuilder-3.2.1.dist-info/RECORD +0 -270
  139. Flask_AppBuilder-3.2.1.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.1.dist-info → flask_appbuilder-5.0.2.dist-info}/LICENSE +0 -0
  228. {Flask_AppBuilder-3.2.1.dist-info → flask_appbuilder-5.0.2.dist-info}/top_level.txt +0 -0
@@ -1,572 +0,0 @@
1
- import datetime
2
- import logging
3
- import os
4
- import random
5
- import string
6
-
7
- from flask_appbuilder.charts.views import (
8
- DirectByChartView,
9
- DirectChartView,
10
- GroupByChartView,
11
- )
12
- from flask_appbuilder.models.group import aggregate_avg, aggregate_count, aggregate_sum
13
- from flask_appbuilder.models.mongoengine.filters import FilterEqual, FilterStartsWith
14
- from flask_appbuilder.views import CompactCRUDMixin, MasterDetailView
15
- from flask_mongoengine import MongoEngine
16
- import jinja2
17
- from nose.tools import eq_, ok_
18
-
19
- from .base import FABTestCase
20
- from .mongoengine.models import Model1, Model2
21
-
22
- logging.basicConfig(format="%(asctime)s:%(levelname)s:%(name)s:%(message)s")
23
- logging.getLogger().setLevel(logging.DEBUG)
24
-
25
-
26
- """
27
- Constant english display string from framework
28
- """
29
- DEFAULT_INDEX_STRING = "Welcome"
30
- INVALID_LOGIN_STRING = "Invalid login"
31
- ACCESS_IS_DENIED = "Access is Denied"
32
- UNIQUE_VALIDATION_STRING = "Already exists"
33
- NOTNULL_VALIDATION_STRING = "This field is required"
34
- DEFAULT_ADMIN_USER = "admin"
35
- DEFAULT_ADMIN_PASSWORD = "general"
36
-
37
- log = logging.getLogger(__name__)
38
-
39
-
40
- class FlaskTestCase(FABTestCase):
41
- def setUp(self):
42
- from flask import Flask
43
- from flask_appbuilder import AppBuilder
44
- from flask_appbuilder.models.mongoengine.interface import MongoEngineInterface
45
- from flask_appbuilder import ModelView
46
- from flask_appbuilder.security.mongoengine.manager import SecurityManager
47
-
48
- self.app = Flask(__name__)
49
- self.app.jinja_env.undefined = jinja2.StrictUndefined
50
- self.basedir = os.path.abspath(os.path.dirname(__file__))
51
- self.app.config["MONGODB_SETTINGS"] = {"DB": "test"}
52
- self.app.config["CSRF_ENABLED"] = False
53
- self.app.config["SECRET_KEY"] = "thisismyscretkey"
54
- self.app.config["WTF_CSRF_ENABLED"] = False
55
-
56
- self.db = MongoEngine(self.app)
57
- self.appbuilder = AppBuilder(self.app, security_manager_class=SecurityManager)
58
-
59
- class Model2View(ModelView):
60
- datamodel = MongoEngineInterface(Model2)
61
- list_columns = [
62
- "field_integer",
63
- "field_float",
64
- "field_string",
65
- "field_method",
66
- "group.field_string",
67
- ]
68
- edit_form_query_rel_fields = {
69
- "group": [["field_string", FilterEqual, "G2"]]
70
- }
71
- add_form_query_rel_fields = {"group": [["field_string", FilterEqual, "G1"]]}
72
- add_exclude_columns = ["excluded_string"]
73
-
74
- class Model22View(ModelView):
75
- datamodel = MongoEngineInterface(Model2)
76
- list_columns = [
77
- "field_integer",
78
- "field_float",
79
- "field_string",
80
- "field_method",
81
- "group.field_string",
82
- ]
83
- add_exclude_columns = ["excluded_string"]
84
- edit_exclude_columns = ["excluded_string"]
85
- show_exclude_columns = ["excluded_string"]
86
-
87
- class Model1View(ModelView):
88
- datamodel = MongoEngineInterface(Model1)
89
- related_views = [Model2View]
90
- list_columns = ["field_string", "field_file"]
91
-
92
- class Model1CompactView(CompactCRUDMixin, ModelView):
93
- datamodel = MongoEngineInterface(Model1)
94
-
95
- class Model1Filtered1View(ModelView):
96
- datamodel = MongoEngineInterface(Model1)
97
- base_filters = [["field_string", FilterStartsWith, "a"]]
98
-
99
- class Model1MasterView(MasterDetailView):
100
- datamodel = MongoEngineInterface(Model1)
101
- related_views = [Model2View]
102
-
103
- class Model1Filtered2View(ModelView):
104
- datamodel = MongoEngineInterface(Model1)
105
- base_filters = [["field_integer", FilterEqual, 0]]
106
-
107
- class Model2GroupByChartView(GroupByChartView):
108
- datamodel = MongoEngineInterface(Model2)
109
- chart_title = "Test Model1 Chart"
110
-
111
- definitions = [
112
- {
113
- "group": "field_string",
114
- "series": [
115
- (
116
- aggregate_sum,
117
- "field_integer",
118
- aggregate_avg,
119
- "field_integer",
120
- aggregate_count,
121
- "field_integer",
122
- )
123
- ],
124
- }
125
- ]
126
-
127
- class Model2DirectByChartView(DirectByChartView):
128
- datamodel = MongoEngineInterface(Model2)
129
- chart_title = "Test Model1 Chart"
130
-
131
- definitions = [
132
- {"group": "field_string", "series": ["field_integer", "field_float"]}
133
- ]
134
-
135
- class Model2DirectChartView(DirectChartView):
136
- datamodel = MongoEngineInterface(Model2)
137
- chart_title = "Test Model1 Chart"
138
- direct_columns = {"stat1": ("group", "field_integer")}
139
-
140
- class Model1MasterChartView(MasterDetailView):
141
- datamodel = MongoEngineInterface(Model1)
142
- related_views = [Model2DirectByChartView]
143
-
144
- self.appbuilder.add_view(Model1View, "Model1", category="Model1")
145
- self.appbuilder.add_view(Model1CompactView, "Model1Compact", category="Model1")
146
- self.appbuilder.add_view(Model1MasterView, "Model1Master", category="Model1")
147
- self.appbuilder.add_view(
148
- Model1MasterChartView, "Model1MasterChart", category="Model1"
149
- )
150
- self.appbuilder.add_view(
151
- Model1Filtered1View, "Model1Filtered1", category="Model1"
152
- )
153
- self.appbuilder.add_view(
154
- Model1Filtered2View, "Model1Filtered2", category="Model1"
155
- )
156
-
157
- self.appbuilder.add_view(Model2View, "Model2")
158
- self.appbuilder.add_view(Model22View, "Model22")
159
- self.appbuilder.add_view(Model2View, "Model2 Add", href="/model2view/add")
160
- self.appbuilder.add_view(Model2GroupByChartView, "Model2 Group By Chart")
161
- self.appbuilder.add_view(Model2DirectByChartView, "Model2 Direct By Chart")
162
- self.appbuilder.add_view(Model2DirectChartView, "Model2 Direct Chart")
163
-
164
- role_admin = self.appbuilder.sm.find_role("Admin")
165
- try:
166
- self.appbuilder.sm.add_user(
167
- "admin", "admin", "user", "admin@fab.org", role_admin, "general"
168
- )
169
- except Exception:
170
- pass
171
-
172
- def tearDown(self):
173
- self.appbuilder = None
174
- self.app = None
175
- self.db = None
176
- log.debug("TEAR DOWN")
177
-
178
- """ ---------------------------------
179
- TEST HELPER FUNCTIONS
180
- ---------------------------------
181
- """
182
-
183
- def insert_data(self):
184
- for x, i in zip(string.ascii_letters[:23], range(23)):
185
- model = Model1(field_string="%stest" % (x), field_integer=i)
186
- model.save()
187
-
188
- def insert_data2(self):
189
- models1 = [
190
- Model1(field_string="G1"),
191
- Model1(field_string="G2"),
192
- Model1(field_string="G3"),
193
- ]
194
- for model1 in models1:
195
- try:
196
- model1.save()
197
- for x, i in zip(string.ascii_letters[:10], range(10)):
198
- model = Model2(
199
- field_string="%stest" % (x),
200
- field_integer=random.randint(1, 10),
201
- field_float=random.uniform(0.0, 1.0),
202
- group=model1,
203
- )
204
- year = random.choice(range(1900, 2012))
205
- month = random.choice(range(1, 12))
206
- day = random.choice(range(1, 28))
207
- model.field_date = datetime.datetime(year, month, day)
208
-
209
- model.save()
210
- except Exception as e:
211
- print("ERROR {0}".format(str(e)))
212
-
213
- def clean_data(self):
214
- Model1.drop_collection()
215
- Model2.drop_collection()
216
-
217
- def test_fab_views(self):
218
- """
219
- Test views creation and registration
220
- """
221
- eq_(len(self.appbuilder.baseviews), 26) # current minimal views are 26
222
-
223
- def test_index(self):
224
- """
225
- Test initial access and index message
226
- """
227
- client = self.app.test_client()
228
-
229
- # Check for Welcome Message
230
- rv = client.get("/")
231
- data = rv.data.decode("utf-8")
232
- ok_(DEFAULT_INDEX_STRING in data)
233
-
234
- def test_sec_login(self):
235
- """
236
- Test Security Login, Logout, invalid login, invalid access
237
- """
238
- client = self.app.test_client()
239
-
240
- # Try to List and Redirect to Login
241
- rv = client.get("/model1view/list/")
242
- eq_(rv.status_code, 302)
243
- rv = client.get("/model2view/list/")
244
- eq_(rv.status_code, 302)
245
-
246
- # Login and list with admin
247
- self.browser_login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD)
248
- rv = client.get("/model1view/list/")
249
- eq_(rv.status_code, 200)
250
- rv = client.get("/model2view/list/")
251
- eq_(rv.status_code, 200)
252
-
253
- # Logout and and try to list
254
- self.browser_logout(client)
255
- rv = client.get("/model1view/list/")
256
- eq_(rv.status_code, 302)
257
- rv = client.get("/model2view/list/")
258
- eq_(rv.status_code, 302)
259
-
260
- # Invalid Login
261
- rv = self.browser_login(client, DEFAULT_ADMIN_USER, "password")
262
- data = rv.data.decode("utf-8")
263
- ok_(INVALID_LOGIN_STRING in data)
264
-
265
- def test_sec_reset_password(self):
266
- """
267
- Test Security reset password
268
- """
269
- from flask_appbuilder.security.mongoengine.models import User
270
-
271
- client = self.app.test_client()
272
-
273
- # Try Reset My password
274
- user = User.objects.filter(**{"username": "admin"})[0]
275
- rv = client.get(
276
- "/users/action/resetmypassword/{0}".format(user.id), follow_redirects=True
277
- )
278
- # Werkzeug update to 0.15.X sends this action to wrong redirect
279
- # Old test was:
280
- # data = rv.data.decode("utf-8")
281
- # ok_(ACCESS_IS_DENIED in data)
282
- self.assertEqual(rv.status_code, 404)
283
-
284
- # Reset My password
285
- rv = self.browser_login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD)
286
- rv = client.get(
287
- "/users/action/resetmypassword/{0}".format(user.id), follow_redirects=True
288
- )
289
- data = rv.data.decode("utf-8")
290
- self.assertIn("Reset Password Form", data)
291
- rv = client.post(
292
- "/resetmypassword/form",
293
- data=dict(password="password", conf_password="password"),
294
- follow_redirects=True,
295
- )
296
- self.assertEqual(rv.status_code, 200)
297
- self.browser_logout(client)
298
- self.browser_login(client, DEFAULT_ADMIN_USER, "password")
299
- rv = client.post(
300
- "/resetmypassword/form",
301
- data=dict(
302
- password=DEFAULT_ADMIN_PASSWORD, conf_password=DEFAULT_ADMIN_PASSWORD
303
- ),
304
- follow_redirects=True,
305
- )
306
- self.assertEqual(rv.status_code, 200)
307
-
308
- # Reset Password Admin
309
- rv = client.get(
310
- "/users/action/resetpasswords/{0}".format(user.id), follow_redirects=True
311
- )
312
- data = rv.data.decode("utf-8")
313
- self.assertIn("Reset Password Form", data)
314
- rv = client.post(
315
- "/resetmypassword/form",
316
- data=dict(
317
- password=DEFAULT_ADMIN_PASSWORD, conf_password=DEFAULT_ADMIN_PASSWORD
318
- ),
319
- follow_redirects=True,
320
- )
321
- self.assertEqual(rv.status_code, 200)
322
-
323
- def test_model_crud(self):
324
- """
325
- Test Model add, delete, edit
326
- """
327
- client = self.app.test_client()
328
- rv = self.browser_login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD)
329
-
330
- rv = client.post(
331
- "/model1view/add",
332
- data=dict(
333
- field_string="test1",
334
- field_integer="1",
335
- field_float="0.12",
336
- field_date="2014-01-01 23:10:07",
337
- ),
338
- follow_redirects=True,
339
- )
340
- eq_(rv.status_code, 200)
341
-
342
- model = Model1.objects[0]
343
- eq_(model.field_string, u"test1")
344
- eq_(model.field_integer, 1)
345
-
346
- model1 = Model1.objects(field_string="test1")[0]
347
- rv = client.post(
348
- "/model1view/edit/{0}".format(model1.id),
349
- data=dict(field_string="test2", field_integer="2"),
350
- follow_redirects=True,
351
- )
352
- eq_(rv.status_code, 200)
353
-
354
- model = Model1.objects[0]
355
- eq_(model.field_string, u"test2")
356
- eq_(model.field_integer, 2)
357
-
358
- rv = client.get(
359
- "/model1view/delete/{0}".format(model.id), follow_redirects=True
360
- )
361
- eq_(rv.status_code, 200)
362
- model = Model1.objects
363
- eq_(len(model), 0)
364
- self.clean_data()
365
-
366
- def test_excluded_cols(self):
367
- """
368
- Test add_exclude_columns, edit_exclude_columns, show_exclude_columns
369
- """
370
- client = self.app.test_client()
371
- rv = self.browser_login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD)
372
- rv = client.get("/model22view/add")
373
- eq_(rv.status_code, 200)
374
- data = rv.data.decode("utf-8")
375
- ok_("field_string" in data)
376
- ok_("field_integer" in data)
377
- ok_("field_float" in data)
378
- ok_("field_date" in data)
379
- ok_("excluded_string" not in data)
380
- self.insert_data2()
381
- model2 = Model2.objects[0]
382
- rv = client.get("/model22view/edit/{0}".format(model2.id))
383
- eq_(rv.status_code, 200)
384
- data = rv.data.decode("utf-8")
385
- ok_("field_string" in data)
386
- ok_("field_integer" in data)
387
- ok_("field_float" in data)
388
- ok_("field_date" in data)
389
- ok_("excluded_string" not in data)
390
- rv = client.get("/model22view/show/{0}".format(model2.id))
391
- eq_(rv.status_code, 200)
392
- data = rv.data.decode("utf-8")
393
- ok_("Field String" in data)
394
- ok_("Field Integer" in data)
395
- ok_("Field Float" in data)
396
- ok_("Field Date" in data)
397
- ok_("Excluded String" not in data)
398
- self.clean_data()
399
-
400
- def test_query_rel_fields(self):
401
- """
402
- Test add and edit form related fields filter
403
- """
404
- client = self.app.test_client()
405
- rv = self.browser_login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD)
406
- self.insert_data2()
407
-
408
- # Base filter string starts with
409
- rv = client.get("/model2view/add")
410
- data = rv.data.decode("utf-8")
411
- ok_("G1" in data)
412
- ok_("G2" not in data)
413
-
414
- model2 = Model2.objects[0]
415
- # Base filter string starts with
416
- rv = client.get("/model2view/edit/{0}".format(model2.id))
417
- data = rv.data.decode("utf-8")
418
- ok_("G2" in data)
419
- ok_("G1" not in data)
420
- self.clean_data()
421
-
422
- def test_model_list_order(self):
423
- """
424
- Test Model order on lists
425
- """
426
- self.insert_data()
427
-
428
- client = self.app.test_client()
429
- self.browser_login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD)
430
-
431
- rv = client.post(
432
- "/model1view/list?_oc_Model1View=field_string&_od_Model1View=asc",
433
- follow_redirects=True,
434
- )
435
- # TODO: fix this 405 Method not allowed error
436
- # eq_(rv.status_code, 200)
437
- rv.data.decode("utf-8")
438
- # TODO
439
- # VALIDATE LIST IS ORDERED
440
- rv = client.post(
441
- "/model1view/list?_oc_Model1View=field_string&_od_Model1View=desc",
442
- follow_redirects=True,
443
- )
444
- # TODO: fix this 405 Method not allowed error
445
- # eq_(rv.status_code, 200)
446
- rv.data.decode("utf-8")
447
- # TODO
448
- # VALIDATE LIST IS ORDERED
449
- self.clean_data()
450
-
451
- def test_model_add_validation(self):
452
- """
453
- Test Model add validations
454
- """
455
- client = self.app.test_client()
456
- self.browser_login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD)
457
-
458
- rv = client.post(
459
- "/model1view/add",
460
- data=dict(field_string="test1", field_integer="1"),
461
- follow_redirects=True,
462
- )
463
- eq_(rv.status_code, 200)
464
-
465
- rv = client.post(
466
- "/model1view/add",
467
- data=dict(field_string="test1", field_integer="2"),
468
- follow_redirects=True,
469
- )
470
- eq_(rv.status_code, 200)
471
- data = rv.data.decode("utf-8")
472
- ok_(UNIQUE_VALIDATION_STRING in data)
473
-
474
- model = Model1.objects()
475
- eq_(len(model), 1)
476
-
477
- rv = client.post(
478
- "/model1view/add",
479
- data=dict(field_string="", field_integer="1"),
480
- follow_redirects=True,
481
- )
482
- eq_(rv.status_code, 200)
483
- data = rv.data.decode("utf-8")
484
- ok_(NOTNULL_VALIDATION_STRING in data)
485
-
486
- model = Model1.objects()
487
- eq_(len(model), 1)
488
- self.clean_data()
489
-
490
- def test_model_edit_validation(self):
491
- """
492
- Test Model edit validations
493
- """
494
- client = self.app.test_client()
495
- self.browser_login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD)
496
-
497
- client.post(
498
- "/model1view/add",
499
- data=dict(field_string="test1", field_integer="1"),
500
- follow_redirects=True,
501
- )
502
- model1 = Model1.objects(field_string="test1")[0]
503
- client.post(
504
- "/model1view/add",
505
- data=dict(field_string="test2", field_integer="1"),
506
- follow_redirects=True,
507
- )
508
- rv = client.post(
509
- "/model1view/edit/{0}".format(model1.id),
510
- data=dict(field_string="test2", field_integer="2"),
511
- follow_redirects=True,
512
- )
513
- eq_(rv.status_code, 200)
514
- data = rv.data.decode("utf-8")
515
- ok_(UNIQUE_VALIDATION_STRING in data)
516
-
517
- rv = client.post(
518
- "/model1view/edit/{0}".format(model1.id),
519
- data=dict(field_string="", field_integer="2"),
520
- follow_redirects=True,
521
- )
522
- eq_(rv.status_code, 200)
523
- data = rv.data.decode("utf-8")
524
- ok_(NOTNULL_VALIDATION_STRING in data)
525
- self.clean_data()
526
-
527
- def test_model_base_filter(self):
528
- """
529
- Test Model base filtered views
530
- """
531
- client = self.app.test_client()
532
- self.browser_login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD)
533
- self.insert_data()
534
- models = Model1.objects()
535
- eq_(len(models), 23)
536
-
537
- # Base filter string starts with
538
- rv = client.get("/model1filtered1view/list/")
539
- data = rv.data.decode("utf-8")
540
- ok_("atest" in data)
541
- ok_("btest" not in data)
542
-
543
- # Base filter integer equals
544
- rv = client.get("/model1filtered2view/list/")
545
- data = rv.data.decode("utf-8")
546
- ok_("atest" in data)
547
- ok_("btest" not in data)
548
- self.clean_data()
549
-
550
- def test_model_list_method_field(self):
551
- """
552
- Tests a model's field has a method
553
- """
554
- client = self.app.test_client()
555
- self.browser_login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD)
556
- self.insert_data2()
557
- rv = client.get("/model2view/list/")
558
- eq_(rv.status_code, 200)
559
- data = rv.data.decode("utf-8")
560
- ok_("field_method_value" in data)
561
- self.clean_data()
562
-
563
- def test_compactCRUDMixin(self):
564
- """
565
- Test CompactCRUD Mixin view
566
- """
567
- client = self.app.test_client()
568
- self.browser_login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD)
569
- self.insert_data2()
570
- rv = client.get("/model1compactview/list/")
571
- eq_(rv.status_code, 200)
572
- self.clean_data()