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,426 +0,0 @@
1
- """
2
- Console utility to help manage F.A.B's apps
3
-
4
- use:
5
-
6
- $ fabmanager --help
7
- """
8
- from io import BytesIO
9
- import os
10
- import shutil
11
- import sys
12
- from zipfile import ZipFile
13
-
14
- import click
15
-
16
- from . import const as c
17
-
18
- try:
19
- # For Python 3.0 and later
20
- from urllib.request import urlopen
21
- except ImportError:
22
- # Fall back to Python 2's urllib2
23
- from urllib2 import urlopen
24
-
25
- click.echo(
26
- click.style(
27
- "fabmanager is going to be deprecated in 2.2.X, you can use "
28
- "the same commands on the improved 'flask fab <command>'",
29
- fg="red",
30
- )
31
- )
32
-
33
- SQLA_REPO_URL = (
34
- "https://github.com/dpgaspar/Flask-AppBuilder-Skeleton/archive/master.zip"
35
- )
36
- MONGOENGIE_REPO_URL = (
37
- "https://github.com/dpgaspar/Flask-AppBuilder-Skeleton-me/archive/master.zip"
38
- )
39
- ADDON_REPO_URL = (
40
- "https://github.com/dpgaspar/Flask-AppBuilder-Skeleton-AddOn/archive/master.zip"
41
- )
42
-
43
-
44
- def import_application(app_package, appbuilder):
45
- sys.path.append(os.getcwd())
46
- try:
47
- _app = __import__(app_package)
48
- except Exception as e:
49
- click.echo(
50
- click.style(
51
- "Was unable to import {0} Error: {1}".format(app_package, e), fg="red"
52
- )
53
- )
54
- exit(3)
55
- if hasattr(_app, appbuilder):
56
- return getattr(_app, appbuilder)
57
- else:
58
- click.echo(
59
- click.style(
60
- "There is no appbuilder var on your package, "
61
- "you can use appbuilder parameter to config",
62
- fg="red",
63
- )
64
- )
65
- exit(3)
66
-
67
-
68
- def echo_header(title):
69
- click.echo(click.style(title, fg="green"))
70
- click.echo(click.style("-" * len(title), fg="green"))
71
-
72
-
73
- @click.group()
74
- def cli_app():
75
- """
76
- This is a set of commands to ease the creation and maintenance
77
- of your flask-appbuilder applications.
78
-
79
- All commands that import your app will assume by default that
80
- you're running on your projects directory just before the app directory.
81
- They will also assume that __init__.py initializes AppBuilder
82
- like this (using a var named appbuilder) just like the skeleton app::
83
-
84
- appbuilder = AppBuilder(......)
85
-
86
- If you're using different namings use app and appbuilder parameters.
87
- """
88
- pass
89
-
90
-
91
- @cli_app.command("reset-password")
92
- @click.option("--app", default="app", help="Your application init directory (package)")
93
- @click.option("--appbuilder", default="appbuilder", help="your AppBuilder object")
94
- @click.option(
95
- "--username",
96
- default="admin",
97
- prompt="The username",
98
- help="Resets the password for a particular user.",
99
- )
100
- @click.password_option()
101
- def reset_password(app, appbuilder, username, password):
102
- """
103
- Resets a user's password
104
- """
105
- _appbuilder = import_application(app, appbuilder)
106
- user = _appbuilder.sm.find_user(username=username)
107
- if not user:
108
- click.echo("User {0} not found.".format(username))
109
- else:
110
- _appbuilder.sm.reset_password(user.id, password)
111
- click.echo(click.style("User {0} reseted.".format(username), fg="green"))
112
-
113
-
114
- @cli_app.command("create-admin")
115
- @click.option("--app", default="app", help="Your application init directory (package)")
116
- @click.option("--appbuilder", default="appbuilder", help="your AppBuilder object")
117
- @click.option("--username", default="admin", prompt="Username")
118
- @click.option("--firstname", default="admin", prompt="User first name")
119
- @click.option("--lastname", default="user", prompt="User last name")
120
- @click.option("--email", default="admin@fab.org", prompt="Email")
121
- @click.password_option()
122
- def create_admin(app, appbuilder, username, firstname, lastname, email, password):
123
- """
124
- Creates an admin user
125
- """
126
- auth_type = {
127
- c.AUTH_DB: "Database Authentications",
128
- c.AUTH_OID: "OpenID Authentication",
129
- c.AUTH_LDAP: "LDAP Authentication",
130
- c.AUTH_REMOTE_USER: "WebServer REMOTE_USER Authentication",
131
- c.AUTH_OAUTH: "OAuth Authentication",
132
- }
133
- _appbuilder = import_application(app, appbuilder)
134
- click.echo(
135
- click.style(
136
- "Recognized {0}.".format(
137
- auth_type.get(_appbuilder.sm.auth_type, "No Auth method")
138
- ),
139
- fg="green",
140
- )
141
- )
142
- role_admin = _appbuilder.sm.find_role(_appbuilder.sm.auth_role_admin)
143
- user = _appbuilder.sm.add_user(
144
- username, firstname, lastname, email, role_admin, password
145
- )
146
- if user:
147
- click.echo(click.style("Admin User {0} created.".format(username), fg="green"))
148
- else:
149
- click.echo(click.style("No user created an error occured", fg="red"))
150
-
151
-
152
- @cli_app.command("create-user")
153
- @click.option("--app", default="app", help="Your application init directory (package)")
154
- @click.option("--appbuilder", default="appbuilder", help="your AppBuilder object")
155
- @click.option("--role", default="Public", prompt="Role")
156
- @click.option("--username", prompt="Username")
157
- @click.option("--firstname", prompt="User first name")
158
- @click.option("--lastname", prompt="User last name")
159
- @click.option("--email", prompt="Email")
160
- @click.password_option()
161
- def create_user(app, appbuilder, role, username, firstname, lastname, email, password):
162
- """
163
- Create a user
164
- """
165
- _appbuilder = import_application(app, appbuilder)
166
- role_object = _appbuilder.sm.find_role(role)
167
- user = _appbuilder.sm.add_user(
168
- username, firstname, lastname, email, role_object, password
169
- )
170
- if user:
171
- click.echo(click.style("User {0} created.".format(username), fg="green"))
172
- else:
173
- click.echo(click.style("Error! No user created", fg="red"))
174
-
175
-
176
- @cli_app.command("run")
177
- @click.option("--app", default="app", help="Your application init directory (package)")
178
- @click.option("--appbuilder", default="appbuilder", help="your AppBuilder object")
179
- @click.option("--host", default="0.0.0.0")
180
- @click.option("--port", default=8080)
181
- @click.option("--debug", default=True)
182
- def run(app, appbuilder, host, port, debug):
183
- """
184
- Runs Flask dev web server.
185
- """
186
- _appbuilder = import_application(app, appbuilder)
187
- _appbuilder.get_app.run(host=host, port=port, debug=debug)
188
-
189
-
190
- @cli_app.command("create-db")
191
- @click.option("--app", default="app", help="Your application init directory (package)")
192
- @click.option("--appbuilder", default="appbuilder", help="your AppBuilder object")
193
- def create_db(app, appbuilder):
194
- """
195
- Create all your database objects (SQLAlchemy specific).
196
- """
197
- from flask_appbuilder.models.sqla import Base
198
-
199
- _appbuilder = import_application(app, appbuilder)
200
- engine = _appbuilder.get_session.get_bind(mapper=None, clause=None)
201
- Base.metadata.create_all(engine)
202
- click.echo(click.style("DB objects created", fg="green"))
203
-
204
-
205
- @cli_app.command("version")
206
- @click.option("--app", default="app", help="Your application init directory (package)")
207
- @click.option("--appbuilder", default="appbuilder", help="your AppBuilder object")
208
- def version(app, appbuilder):
209
- """
210
- Flask-AppBuilder package version
211
- """
212
- _appbuilder = import_application(app, appbuilder)
213
- click.echo(
214
- click.style(
215
- "F.A.B Version: {0}.".format(_appbuilder.version), bg="blue", fg="white"
216
- )
217
- )
218
-
219
-
220
- @cli_app.command("security-cleanup")
221
- @click.option("--app", default="app", help="Your application init directory (package)")
222
- @click.option("--appbuilder", default="appbuilder", help="your AppBuilder object")
223
- def security_cleanup(app, appbuilder):
224
- """
225
- Cleanup unused permissions from views and roles.
226
- """
227
- _appbuilder = import_application(app, appbuilder)
228
- _appbuilder.security_cleanup()
229
- click.echo(click.style("Finished security cleanup", fg="green"))
230
-
231
-
232
- @cli_app.command("list-views")
233
- @click.option("--app", default="app", help="Your application init directory (package)")
234
- @click.option("--appbuilder", default="appbuilder", help="your AppBuilder object")
235
- def list_views(app, appbuilder):
236
- """
237
- List all registered views
238
- """
239
- _appbuilder = import_application(app, appbuilder)
240
- echo_header("List of registered views")
241
- for view in _appbuilder.baseviews:
242
- click.echo(
243
- "View:{0} | Route:{1} | Perms:{2}".format(
244
- view.__class__.__name__, view.route_base, view.base_permissions
245
- )
246
- )
247
-
248
-
249
- @cli_app.command("list-users")
250
- @click.option("--app", default="app", help="Your application init directory (package)")
251
- @click.option("--appbuilder", default="appbuilder", help="your AppBuilder object")
252
- def list_users(app, appbuilder):
253
- """
254
- List all users on the database
255
- """
256
- _appbuilder = import_application(app, appbuilder)
257
- echo_header("List of users")
258
- for user in _appbuilder.sm.get_all_users():
259
- click.echo(
260
- "username:{0} | email:{1} | role:{2}".format(
261
- user.username, user.email, user.roles
262
- )
263
- )
264
-
265
-
266
- @cli_app.command("babel-extract")
267
- @click.option("--config", default="./babel/babel.cfg")
268
- @click.option("--input", default=".")
269
- @click.option("--output", default="./babel/messages.pot")
270
- @click.option("--target", default="app/translations")
271
- @click.option(
272
- "--keywords", "-k", multiple=True, default=["lazy_gettext", "gettext", "_", "__"]
273
- )
274
- def babel_extract(config, input, output, target, keywords):
275
- """
276
- Babel, Extracts and updates all messages marked for translation
277
- """
278
- click.echo(
279
- click.style(
280
- "Starting Extractions config:{0} input:{1} output:{2} keywords:{3}".format(
281
- config, input, output, keywords
282
- ),
283
- fg="green",
284
- )
285
- )
286
- keywords = " -k ".join(keywords)
287
- os.popen(
288
- "pybabel extract -F {0} -k {1} -o {2} {3}".format(
289
- config, keywords, output, input
290
- )
291
- )
292
- click.echo(click.style("Starting Update target:{0}".format(target), fg="green"))
293
- os.popen("pybabel update -N -i {0} -d {1}".format(output, target))
294
- click.echo(click.style("Finish, you can start your translations", fg="green"))
295
-
296
-
297
- @cli_app.command("babel-compile")
298
- @click.option(
299
- "--target",
300
- default="app/translations",
301
- help="The target directory where translations reside",
302
- )
303
- def babel_compile(target):
304
- """
305
- Babel, Compiles all translations
306
- """
307
- click.echo(click.style("Starting Compile target:{0}".format(target), fg="green"))
308
- os.popen("pybabel compile -f -d {0}".format(target))
309
-
310
-
311
- @cli_app.command("create-app")
312
- @click.option(
313
- "--name",
314
- prompt="Your new app name",
315
- help="Your application name, directory will have this name",
316
- )
317
- @click.option(
318
- "--engine",
319
- prompt="Your engine type, SQLAlchemy or MongoEngine",
320
- type=click.Choice(["SQLAlchemy", "MongoEngine"]),
321
- default="SQLAlchemy",
322
- help="Write your engine type",
323
- )
324
- def create_app(name, engine):
325
- """
326
- Create a Skeleton application (needs internet connection to github)
327
- """
328
- try:
329
- if engine.lower() == "sqlalchemy":
330
- url = urlopen(SQLA_REPO_URL)
331
- dirname = "Flask-AppBuilder-Skeleton-master"
332
- elif engine.lower() == "mongoengine":
333
- url = urlopen(MONGOENGIE_REPO_URL)
334
- dirname = "Flask-AppBuilder-Skeleton-me-master"
335
- zipfile = ZipFile(BytesIO(url.read()))
336
- zipfile.extractall()
337
- os.rename(dirname, name)
338
- click.echo(click.style("Downloaded the skeleton app, good coding!", fg="green"))
339
- return True
340
- except Exception as e:
341
- click.echo(click.style("Something went wrong {0}".format(e), fg="red"))
342
- if engine.lower() == "sqlalchemy":
343
- click.echo(
344
- click.style(
345
- "Try downloading from {0}".format(SQLA_REPO_URL), fg="green"
346
- )
347
- )
348
- elif engine.lower() == "mongoengine":
349
- click.echo(
350
- click.style(
351
- "Try downloading from {0}".format(MONGOENGIE_REPO_URL), fg="green"
352
- )
353
- )
354
- return False
355
-
356
-
357
- @cli_app.command("create-addon")
358
- @click.option(
359
- "--name",
360
- prompt="Your new addon name",
361
- help="Your addon name will be prefixed by fab_addon_, directory will have this name",
362
- )
363
- def create_addon(name):
364
- """
365
- Create a Skeleton AddOn (needs internet connection to github)
366
- """
367
- try:
368
- full_name = "fab_addon_" + name
369
- dirname = "Flask-AppBuilder-Skeleton-AddOn-master"
370
- url = urlopen(ADDON_REPO_URL)
371
- zipfile = ZipFile(BytesIO(url.read()))
372
- zipfile.extractall()
373
- os.rename(dirname, full_name)
374
- addon_path = os.path.join(full_name, full_name)
375
- os.rename(os.path.join(full_name, "fab_addon"), addon_path)
376
- f = open(os.path.join(full_name, "config.py"), "w")
377
- f.write("ADDON_NAME='" + name + "'\n")
378
- f.write("FULL_ADDON_NAME='fab_addon_' + ADDON_NAME\n")
379
- f.close()
380
- click.echo(
381
- click.style("Downloaded the skeleton addon, good coding!", fg="green")
382
- )
383
- return True
384
- except Exception as e:
385
- click.echo(click.style("Something went wrong {0}".format(e), fg="red"))
386
- return False
387
-
388
-
389
- @cli_app.command("collect-static")
390
- @click.option(
391
- "--static_folder", default="app/static", help="Your projects static folder"
392
- )
393
- def collect_static(static_folder):
394
- """
395
- Copies flask-appbuilder static files to your projects static folder
396
- """
397
- appbuilder_static_path = os.path.join(
398
- os.path.dirname(os.path.abspath(__file__)), "static/appbuilder"
399
- )
400
- app_static_path = os.path.join(os.getcwd(), static_folder)
401
- if not os.path.isdir(app_static_path):
402
- click.echo(
403
- click.style(
404
- "Static folder does not exist creating: %s" % app_static_path,
405
- fg="green",
406
- )
407
- )
408
- os.makedirs(app_static_path)
409
- try:
410
- shutil.copytree(
411
- appbuilder_static_path, os.path.join(app_static_path, "appbuilder")
412
- )
413
- except Exception:
414
- click.echo(
415
- click.style(
416
- "Appbuilder static folder already exists on your project", fg="red"
417
- )
418
- )
419
-
420
-
421
- def cli():
422
- cli_app()
423
-
424
-
425
- if __name__ == "__main__":
426
- cli_app()
File without changes
@@ -1,65 +0,0 @@
1
- from werkzeug.datastructures import FileStorage
2
- from wtforms import fields
3
-
4
- from ...upload import BS3FileUploadFieldWidget, BS3ImageUploadFieldWidget
5
-
6
- try:
7
- from wtforms.fields.core import _unset_value as unset_value
8
- except ImportError:
9
- from wtforms.utils import unset_value
10
-
11
-
12
- def is_empty(file_object):
13
- file_object.seek(0)
14
- first_char = file_object.read(1)
15
- file_object.seek(0)
16
- return not bool(first_char)
17
-
18
-
19
- class MongoFileField(fields.FileField):
20
- """
21
- GridFS file field.
22
- """
23
-
24
- widget = BS3FileUploadFieldWidget()
25
-
26
- def __init__(self, label=None, validators=None, **kwargs):
27
- super(MongoFileField, self).__init__(label, validators, **kwargs)
28
-
29
- self._should_delete = False
30
-
31
- def process(self, formdata, data=unset_value):
32
- if formdata:
33
- marker = "_%s-delete" % self.name
34
- if marker in formdata:
35
- self._should_delete = True
36
-
37
- return super(MongoFileField, self).process(formdata, data)
38
-
39
- def populate_obj(self, obj, name):
40
- field = getattr(obj, name, None)
41
- if field is not None:
42
- # If field should be deleted, clean it up
43
- if self._should_delete:
44
- field.delete()
45
- return
46
-
47
- if isinstance(self.data, FileStorage) and not is_empty(self.data.stream):
48
- if not field.grid_id:
49
- func = field.put
50
- else:
51
- func = field.replace
52
-
53
- func(
54
- self.data.stream,
55
- filename=self.data.filename,
56
- content_type=self.data.content_type,
57
- )
58
-
59
-
60
- class MongoImageField(MongoFileField):
61
- """
62
- GridFS file field.
63
- """
64
-
65
- widget = BS3ImageUploadFieldWidget()
@@ -1,145 +0,0 @@
1
- import logging
2
-
3
- from flask_babel import lazy_gettext
4
-
5
- from ..filters import BaseFilter, BaseFilterConverter, FilterRelation
6
-
7
- log = logging.getLogger(__name__)
8
-
9
- __all__ = [
10
- "MongoEngineFilterConverter",
11
- "FilterEqual",
12
- "FilterContains",
13
- "FilterNotContains",
14
- "FilterNotStartsWith",
15
- "FilterStartsWith",
16
- "FilterRelationOneToManyEqual",
17
- "FilterRelationManyToManyEqual",
18
- ]
19
-
20
-
21
- class FilterEqual(BaseFilter):
22
- name = lazy_gettext("Equal to")
23
-
24
- def apply(self, query, value):
25
- if self.datamodel.is_boolean(self.column_name):
26
- if value == "y":
27
- value = True
28
- flt = {"%s" % self.column_name: value}
29
- return query.filter(**flt)
30
-
31
-
32
- class FilterNotEqual(BaseFilter):
33
- name = lazy_gettext("Not Equal to")
34
-
35
- def apply(self, query, value):
36
- if self.datamodel.is_boolean(self.column_name):
37
- if value == "y":
38
- value = True
39
- flt = {"%s__ne" % self.column_name: value}
40
- return query.filter(**flt)
41
-
42
-
43
- class FilterGreater(BaseFilter):
44
- name = lazy_gettext("Greater than")
45
-
46
- def apply(self, query, value):
47
- flt = {"%s__gt" % self.column_name: value}
48
- return query.filter(**flt)
49
-
50
-
51
- class FilterSmaller(BaseFilter):
52
- name = lazy_gettext("Smaller than")
53
-
54
- def apply(self, query, value):
55
- flt = {"%s__lt" % self.column_name: value}
56
- return query.filter(**flt)
57
-
58
-
59
- class FilterStartsWith(BaseFilter):
60
- name = lazy_gettext("Starts with")
61
-
62
- def apply(self, query, value):
63
- flt = {"%s__%s" % (self.column_name, "startswith"): value}
64
- return query.filter(**flt)
65
-
66
-
67
- class FilterNotStartsWith(BaseFilter):
68
- name = lazy_gettext("Not Starts with")
69
-
70
- def apply(self, query, value):
71
- flt = {"%s__not__%s" % (self.column_name, "startswith"): value}
72
- return query.filter(**flt)
73
-
74
-
75
- class FilterContains(BaseFilter):
76
- name = lazy_gettext("Contains")
77
-
78
- def apply(self, query, value):
79
- flt = {"%s__%s" % (self.column_name, "icontains"): value}
80
- return query.filter(**flt)
81
-
82
-
83
- class FilterNotContains(BaseFilter):
84
- name = lazy_gettext("Not Contains")
85
-
86
- def apply(self, query, value):
87
- flt = {"%s__not__%s" % (self.column_name, "icontains"): value}
88
- return query.filter(**flt)
89
-
90
-
91
- class FilterRelationOneToManyEqual(FilterRelation):
92
- name = lazy_gettext("Relation")
93
-
94
- def apply(self, query, value):
95
- rel_obj = self.datamodel.get_related_obj(self.column_name, value)
96
- flt = {"%s" % self.column_name: rel_obj}
97
- return query.filter(**flt)
98
-
99
-
100
- class FilterRelationManyToManyEqual(FilterRelation):
101
- name = lazy_gettext("Relation as Many")
102
-
103
- def apply(self, query, value):
104
- rel_obj = self.datamodel.get_related_obj(self.column_name, value)
105
- flt = {"%s__%s" % (self.column_name, "icontains"): rel_obj}
106
- return query.filter(**flt)
107
-
108
-
109
- class FilterEqualFunction(BaseFilter):
110
- name = "Filter view with a function"
111
-
112
- def apply(self, query, func):
113
- flt = {"%s" % self.column_name: func()}
114
- return query.filter(**flt)
115
-
116
-
117
- class MongoEngineFilterConverter(BaseFilterConverter):
118
- """
119
- Class for converting columns into a supported list of filters
120
- specific for SQLAlchemy.
121
-
122
- """
123
-
124
- conversion_table = (
125
- ("is_relation_many_to_one", [FilterRelationOneToManyEqual]),
126
- ("is_relation_one_to_one", [FilterRelationOneToManyEqual]),
127
- ("is_relation_many_to_many", [FilterRelationManyToManyEqual]),
128
- ("is_relation_one_to_many", [FilterRelationManyToManyEqual]),
129
- ("is_object_id", [FilterEqual]),
130
- (
131
- "is_string",
132
- [
133
- FilterEqual,
134
- FilterNotEqual,
135
- FilterStartsWith,
136
- FilterNotStartsWith,
137
- FilterContains,
138
- FilterNotContains,
139
- ],
140
- ),
141
- ("is_boolean", [FilterEqual, FilterNotEqual]),
142
- ("is_datetime", [FilterEqual, FilterNotEqual, FilterGreater, FilterSmaller]),
143
- ("is_integer", [FilterEqual, FilterNotEqual, FilterGreater, FilterSmaller]),
144
- ("is_float", [FilterEqual, FilterNotEqual, FilterGreater, FilterSmaller]),
145
- )