clear-skies 1.22.10__py3-none-any.whl → 2.0.23__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 (368) hide show
  1. clear_skies-2.0.23.dist-info/METADATA +76 -0
  2. clear_skies-2.0.23.dist-info/RECORD +265 -0
  3. {clear_skies-1.22.10.dist-info → clear_skies-2.0.23.dist-info}/WHEEL +1 -1
  4. clearskies/__init__.py +37 -21
  5. clearskies/action.py +7 -0
  6. clearskies/authentication/__init__.py +8 -39
  7. clearskies/authentication/authentication.py +44 -0
  8. clearskies/authentication/authorization.py +14 -8
  9. clearskies/authentication/authorization_pass_through.py +14 -10
  10. clearskies/authentication/jwks.py +135 -58
  11. clearskies/authentication/public.py +3 -26
  12. clearskies/authentication/secret_bearer.py +515 -44
  13. clearskies/autodoc/formats/oai3_json/__init__.py +2 -2
  14. clearskies/autodoc/formats/oai3_json/oai3_json.py +11 -9
  15. clearskies/autodoc/formats/oai3_json/parameter.py +6 -3
  16. clearskies/autodoc/formats/oai3_json/request.py +7 -5
  17. clearskies/autodoc/formats/oai3_json/response.py +7 -4
  18. clearskies/autodoc/formats/oai3_json/schema/object.py +10 -1
  19. clearskies/autodoc/request/__init__.py +2 -0
  20. clearskies/autodoc/request/header.py +4 -6
  21. clearskies/autodoc/request/json_body.py +4 -6
  22. clearskies/autodoc/request/parameter.py +8 -0
  23. clearskies/autodoc/request/request.py +16 -4
  24. clearskies/autodoc/request/url_parameter.py +4 -6
  25. clearskies/autodoc/request/url_path.py +4 -6
  26. clearskies/autodoc/schema/__init__.py +4 -2
  27. clearskies/autodoc/schema/array.py +5 -6
  28. clearskies/autodoc/schema/boolean.py +4 -10
  29. clearskies/autodoc/schema/date.py +0 -3
  30. clearskies/autodoc/schema/datetime.py +1 -4
  31. clearskies/autodoc/schema/double.py +0 -3
  32. clearskies/autodoc/schema/enum.py +4 -2
  33. clearskies/autodoc/schema/integer.py +4 -9
  34. clearskies/autodoc/schema/long.py +0 -3
  35. clearskies/autodoc/schema/number.py +4 -9
  36. clearskies/autodoc/schema/object.py +5 -7
  37. clearskies/autodoc/schema/password.py +0 -3
  38. clearskies/autodoc/schema/schema.py +11 -0
  39. clearskies/autodoc/schema/string.py +4 -10
  40. clearskies/backends/__init__.py +55 -20
  41. clearskies/backends/api_backend.py +1118 -280
  42. clearskies/backends/backend.py +54 -85
  43. clearskies/backends/cursor_backend.py +246 -191
  44. clearskies/backends/memory_backend.py +514 -208
  45. clearskies/backends/secrets_backend.py +68 -31
  46. clearskies/column.py +1221 -0
  47. clearskies/columns/__init__.py +71 -0
  48. clearskies/columns/audit.py +306 -0
  49. clearskies/columns/belongs_to_id.py +478 -0
  50. clearskies/columns/belongs_to_model.py +129 -0
  51. clearskies/columns/belongs_to_self.py +109 -0
  52. clearskies/columns/boolean.py +110 -0
  53. clearskies/columns/category_tree.py +273 -0
  54. clearskies/columns/category_tree_ancestors.py +51 -0
  55. clearskies/columns/category_tree_children.py +126 -0
  56. clearskies/columns/category_tree_descendants.py +48 -0
  57. clearskies/columns/created.py +92 -0
  58. clearskies/columns/created_by_authorization_data.py +114 -0
  59. clearskies/columns/created_by_header.py +103 -0
  60. clearskies/columns/created_by_ip.py +90 -0
  61. clearskies/columns/created_by_routing_data.py +102 -0
  62. clearskies/columns/created_by_user_agent.py +89 -0
  63. clearskies/columns/date.py +232 -0
  64. clearskies/columns/datetime.py +284 -0
  65. clearskies/columns/email.py +78 -0
  66. clearskies/columns/float.py +149 -0
  67. clearskies/columns/has_many.py +529 -0
  68. clearskies/columns/has_many_self.py +62 -0
  69. clearskies/columns/has_one.py +21 -0
  70. clearskies/columns/integer.py +158 -0
  71. clearskies/columns/json.py +126 -0
  72. clearskies/columns/many_to_many_ids.py +335 -0
  73. clearskies/columns/many_to_many_ids_with_data.py +274 -0
  74. clearskies/columns/many_to_many_models.py +156 -0
  75. clearskies/columns/many_to_many_pivots.py +132 -0
  76. clearskies/columns/phone.py +162 -0
  77. clearskies/columns/select.py +95 -0
  78. clearskies/columns/string.py +102 -0
  79. clearskies/columns/timestamp.py +164 -0
  80. clearskies/columns/updated.py +107 -0
  81. clearskies/columns/uuid.py +83 -0
  82. clearskies/configs/README.md +105 -0
  83. clearskies/configs/__init__.py +170 -0
  84. clearskies/configs/actions.py +43 -0
  85. clearskies/configs/any.py +15 -0
  86. clearskies/configs/any_dict.py +24 -0
  87. clearskies/configs/any_dict_or_callable.py +25 -0
  88. clearskies/configs/authentication.py +23 -0
  89. clearskies/configs/authorization.py +23 -0
  90. clearskies/configs/boolean.py +18 -0
  91. clearskies/configs/boolean_or_callable.py +20 -0
  92. clearskies/configs/callable_config.py +20 -0
  93. clearskies/configs/columns.py +34 -0
  94. clearskies/configs/conditions.py +30 -0
  95. clearskies/configs/config.py +26 -0
  96. clearskies/configs/datetime.py +20 -0
  97. clearskies/configs/datetime_or_callable.py +21 -0
  98. clearskies/configs/email.py +10 -0
  99. clearskies/configs/email_list.py +17 -0
  100. clearskies/configs/email_list_or_callable.py +17 -0
  101. clearskies/configs/email_or_email_list_or_callable.py +59 -0
  102. clearskies/configs/endpoint.py +23 -0
  103. clearskies/configs/endpoint_list.py +29 -0
  104. clearskies/configs/float.py +18 -0
  105. clearskies/configs/float_or_callable.py +20 -0
  106. clearskies/configs/headers.py +28 -0
  107. clearskies/configs/integer.py +18 -0
  108. clearskies/configs/integer_or_callable.py +20 -0
  109. clearskies/configs/joins.py +30 -0
  110. clearskies/configs/list_any_dict.py +32 -0
  111. clearskies/configs/list_any_dict_or_callable.py +33 -0
  112. clearskies/configs/model_class.py +35 -0
  113. clearskies/configs/model_column.py +67 -0
  114. clearskies/configs/model_columns.py +58 -0
  115. clearskies/configs/model_destination_name.py +26 -0
  116. clearskies/configs/model_to_id_column.py +45 -0
  117. clearskies/configs/readable_model_column.py +11 -0
  118. clearskies/configs/readable_model_columns.py +11 -0
  119. clearskies/configs/schema.py +23 -0
  120. clearskies/configs/searchable_model_columns.py +11 -0
  121. clearskies/configs/security_headers.py +39 -0
  122. clearskies/configs/select.py +28 -0
  123. clearskies/configs/select_list.py +49 -0
  124. clearskies/configs/string.py +31 -0
  125. clearskies/configs/string_dict.py +34 -0
  126. clearskies/configs/string_list.py +47 -0
  127. clearskies/configs/string_list_or_callable.py +48 -0
  128. clearskies/configs/string_or_callable.py +18 -0
  129. clearskies/configs/timedelta.py +20 -0
  130. clearskies/configs/timezone.py +20 -0
  131. clearskies/configs/url.py +25 -0
  132. clearskies/configs/validators.py +45 -0
  133. clearskies/configs/writeable_model_column.py +11 -0
  134. clearskies/configs/writeable_model_columns.py +11 -0
  135. clearskies/configurable.py +78 -0
  136. clearskies/contexts/__init__.py +8 -8
  137. clearskies/contexts/cli.py +129 -43
  138. clearskies/contexts/context.py +93 -56
  139. clearskies/contexts/wsgi.py +79 -33
  140. clearskies/contexts/wsgi_ref.py +87 -0
  141. clearskies/cursors/__init__.py +7 -0
  142. clearskies/cursors/cursor.py +166 -0
  143. clearskies/cursors/from_environment/__init__.py +5 -0
  144. clearskies/cursors/from_environment/mysql.py +51 -0
  145. clearskies/cursors/from_environment/postgresql.py +49 -0
  146. clearskies/cursors/from_environment/sqlite.py +35 -0
  147. clearskies/cursors/mysql.py +61 -0
  148. clearskies/cursors/postgresql.py +61 -0
  149. clearskies/cursors/sqlite.py +62 -0
  150. clearskies/decorators.py +33 -0
  151. clearskies/decorators.pyi +10 -0
  152. clearskies/di/__init__.py +11 -7
  153. clearskies/di/additional_config.py +115 -4
  154. clearskies/di/additional_config_auto_import.py +12 -0
  155. clearskies/di/di.py +714 -125
  156. clearskies/di/inject/__init__.py +23 -0
  157. clearskies/di/inject/akeyless_sdk.py +16 -0
  158. clearskies/di/inject/by_class.py +24 -0
  159. clearskies/di/inject/by_name.py +22 -0
  160. clearskies/di/inject/di.py +16 -0
  161. clearskies/di/inject/environment.py +15 -0
  162. clearskies/di/inject/input_output.py +19 -0
  163. clearskies/di/inject/now.py +16 -0
  164. clearskies/di/inject/requests.py +16 -0
  165. clearskies/di/inject/secrets.py +15 -0
  166. clearskies/di/inject/utcnow.py +16 -0
  167. clearskies/di/inject/uuid.py +16 -0
  168. clearskies/di/injectable.py +32 -0
  169. clearskies/di/injectable_properties.py +131 -0
  170. clearskies/end.py +219 -0
  171. clearskies/endpoint.py +1303 -0
  172. clearskies/endpoint_group.py +333 -0
  173. clearskies/endpoints/__init__.py +25 -0
  174. clearskies/endpoints/advanced_search.py +519 -0
  175. clearskies/endpoints/callable.py +382 -0
  176. clearskies/endpoints/create.py +201 -0
  177. clearskies/endpoints/delete.py +133 -0
  178. clearskies/endpoints/get.py +267 -0
  179. clearskies/endpoints/health_check.py +181 -0
  180. clearskies/endpoints/list.py +567 -0
  181. clearskies/endpoints/restful_api.py +417 -0
  182. clearskies/endpoints/schema.py +185 -0
  183. clearskies/endpoints/simple_search.py +279 -0
  184. clearskies/endpoints/update.py +188 -0
  185. clearskies/environment.py +7 -3
  186. clearskies/exceptions/__init__.py +19 -0
  187. clearskies/{handlers/exceptions/input_error.py → exceptions/input_errors.py} +1 -1
  188. clearskies/exceptions/missing_dependency.py +2 -0
  189. clearskies/exceptions/moved_permanently.py +3 -0
  190. clearskies/exceptions/moved_temporarily.py +3 -0
  191. clearskies/functional/__init__.py +2 -2
  192. clearskies/functional/json.py +47 -0
  193. clearskies/functional/routing.py +92 -0
  194. clearskies/functional/string.py +19 -11
  195. clearskies/functional/validations.py +61 -9
  196. clearskies/input_outputs/__init__.py +9 -7
  197. clearskies/input_outputs/cli.py +135 -160
  198. clearskies/input_outputs/exceptions/__init__.py +6 -1
  199. clearskies/input_outputs/headers.py +54 -0
  200. clearskies/input_outputs/input_output.py +77 -123
  201. clearskies/input_outputs/programmatic.py +62 -0
  202. clearskies/input_outputs/wsgi.py +36 -48
  203. clearskies/model.py +1874 -193
  204. clearskies/query/__init__.py +12 -0
  205. clearskies/query/condition.py +228 -0
  206. clearskies/query/join.py +136 -0
  207. clearskies/query/query.py +193 -0
  208. clearskies/query/sort.py +27 -0
  209. clearskies/schema.py +82 -0
  210. clearskies/secrets/__init__.py +4 -31
  211. clearskies/secrets/additional_configs/mysql_connection_dynamic_producer.py +15 -4
  212. clearskies/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py +11 -5
  213. clearskies/secrets/akeyless.py +421 -155
  214. clearskies/secrets/exceptions/__init__.py +7 -1
  215. clearskies/secrets/exceptions/not_found_error.py +2 -0
  216. clearskies/secrets/exceptions/permissions_error.py +2 -0
  217. clearskies/secrets/secrets.py +12 -11
  218. clearskies/security_header.py +17 -0
  219. clearskies/security_headers/__init__.py +8 -8
  220. clearskies/security_headers/cache_control.py +47 -109
  221. clearskies/security_headers/cors.py +38 -92
  222. clearskies/security_headers/csp.py +76 -150
  223. clearskies/security_headers/hsts.py +14 -15
  224. clearskies/typing.py +11 -0
  225. clearskies/validator.py +36 -0
  226. clearskies/validators/__init__.py +33 -0
  227. clearskies/validators/after_column.py +61 -0
  228. clearskies/validators/before_column.py +15 -0
  229. clearskies/validators/in_the_future.py +29 -0
  230. clearskies/validators/in_the_future_at_least.py +13 -0
  231. clearskies/validators/in_the_future_at_most.py +12 -0
  232. clearskies/validators/in_the_past.py +29 -0
  233. clearskies/validators/in_the_past_at_least.py +12 -0
  234. clearskies/validators/in_the_past_at_most.py +12 -0
  235. clearskies/validators/maximum_length.py +25 -0
  236. clearskies/validators/maximum_value.py +28 -0
  237. clearskies/validators/minimum_length.py +25 -0
  238. clearskies/validators/minimum_value.py +28 -0
  239. clearskies/{input_requirements → validators}/required.py +18 -9
  240. clearskies/validators/timedelta.py +58 -0
  241. clearskies/validators/unique.py +28 -0
  242. clear_skies-1.22.10.dist-info/METADATA +0 -47
  243. clear_skies-1.22.10.dist-info/RECORD +0 -213
  244. clearskies/application.py +0 -29
  245. clearskies/authentication/auth0_jwks.py +0 -118
  246. clearskies/authentication/auth_exception.py +0 -2
  247. clearskies/authentication/jwks_jwcrypto.py +0 -51
  248. clearskies/backends/api_get_only_backend.py +0 -48
  249. clearskies/backends/example_backend.py +0 -43
  250. clearskies/backends/file_backend.py +0 -48
  251. clearskies/backends/json_backend.py +0 -7
  252. clearskies/backends/restful_api_advanced_search_backend.py +0 -103
  253. clearskies/binding_config.py +0 -16
  254. clearskies/column_types/__init__.py +0 -203
  255. clearskies/column_types/audit.py +0 -249
  256. clearskies/column_types/belongs_to.py +0 -271
  257. clearskies/column_types/boolean.py +0 -60
  258. clearskies/column_types/category_tree.py +0 -304
  259. clearskies/column_types/column.py +0 -373
  260. clearskies/column_types/created.py +0 -26
  261. clearskies/column_types/created_by_authorization_data.py +0 -26
  262. clearskies/column_types/created_by_header.py +0 -24
  263. clearskies/column_types/created_by_ip.py +0 -17
  264. clearskies/column_types/created_by_routing_data.py +0 -25
  265. clearskies/column_types/created_by_user_agent.py +0 -17
  266. clearskies/column_types/created_micro.py +0 -26
  267. clearskies/column_types/datetime.py +0 -109
  268. clearskies/column_types/datetime_micro.py +0 -13
  269. clearskies/column_types/email.py +0 -18
  270. clearskies/column_types/float.py +0 -43
  271. clearskies/column_types/has_many.py +0 -179
  272. clearskies/column_types/has_one.py +0 -58
  273. clearskies/column_types/integer.py +0 -41
  274. clearskies/column_types/json.py +0 -25
  275. clearskies/column_types/many_to_many.py +0 -278
  276. clearskies/column_types/many_to_many_with_data.py +0 -162
  277. clearskies/column_types/phone.py +0 -48
  278. clearskies/column_types/select.py +0 -11
  279. clearskies/column_types/string.py +0 -24
  280. clearskies/column_types/timestamp.py +0 -73
  281. clearskies/column_types/updated.py +0 -26
  282. clearskies/column_types/updated_micro.py +0 -26
  283. clearskies/column_types/uuid.py +0 -25
  284. clearskies/columns.py +0 -123
  285. clearskies/condition_parser.py +0 -172
  286. clearskies/contexts/build_context.py +0 -54
  287. clearskies/contexts/convert_to_application.py +0 -190
  288. clearskies/contexts/extract_handler.py +0 -37
  289. clearskies/contexts/test.py +0 -94
  290. clearskies/decorators/__init__.py +0 -39
  291. clearskies/decorators/auth0_jwks.py +0 -22
  292. clearskies/decorators/authorization.py +0 -10
  293. clearskies/decorators/binding_classes.py +0 -9
  294. clearskies/decorators/binding_modules.py +0 -9
  295. clearskies/decorators/bindings.py +0 -9
  296. clearskies/decorators/create.py +0 -10
  297. clearskies/decorators/delete.py +0 -10
  298. clearskies/decorators/docs.py +0 -14
  299. clearskies/decorators/get.py +0 -10
  300. clearskies/decorators/jwks.py +0 -26
  301. clearskies/decorators/merge.py +0 -124
  302. clearskies/decorators/patch.py +0 -10
  303. clearskies/decorators/post.py +0 -10
  304. clearskies/decorators/public.py +0 -11
  305. clearskies/decorators/response_headers.py +0 -10
  306. clearskies/decorators/return_raw_response.py +0 -9
  307. clearskies/decorators/schema.py +0 -10
  308. clearskies/decorators/secret_bearer.py +0 -24
  309. clearskies/decorators/security_headers.py +0 -10
  310. clearskies/di/standard_dependencies.py +0 -151
  311. clearskies/di/test_module/__init__.py +0 -6
  312. clearskies/di/test_module/another_module/__init__.py +0 -2
  313. clearskies/di/test_module/module_class.py +0 -5
  314. clearskies/handlers/__init__.py +0 -41
  315. clearskies/handlers/advanced_search.py +0 -271
  316. clearskies/handlers/base.py +0 -479
  317. clearskies/handlers/callable.py +0 -191
  318. clearskies/handlers/create.py +0 -35
  319. clearskies/handlers/crud_by_method.py +0 -18
  320. clearskies/handlers/database_connector.py +0 -32
  321. clearskies/handlers/delete.py +0 -61
  322. clearskies/handlers/exceptions/__init__.py +0 -5
  323. clearskies/handlers/exceptions/not_found.py +0 -3
  324. clearskies/handlers/get.py +0 -156
  325. clearskies/handlers/health_check.py +0 -59
  326. clearskies/handlers/input_processing.py +0 -79
  327. clearskies/handlers/list.py +0 -530
  328. clearskies/handlers/mygrations.py +0 -82
  329. clearskies/handlers/request_method_routing.py +0 -47
  330. clearskies/handlers/restful_api.py +0 -218
  331. clearskies/handlers/routing.py +0 -62
  332. clearskies/handlers/schema_helper.py +0 -128
  333. clearskies/handlers/simple_routing.py +0 -206
  334. clearskies/handlers/simple_routing_route.py +0 -192
  335. clearskies/handlers/simple_search.py +0 -136
  336. clearskies/handlers/update.py +0 -96
  337. clearskies/handlers/write.py +0 -193
  338. clearskies/input_requirements/__init__.py +0 -78
  339. clearskies/input_requirements/after.py +0 -36
  340. clearskies/input_requirements/before.py +0 -36
  341. clearskies/input_requirements/in_the_future_at_least.py +0 -19
  342. clearskies/input_requirements/in_the_future_at_most.py +0 -19
  343. clearskies/input_requirements/in_the_past_at_least.py +0 -19
  344. clearskies/input_requirements/in_the_past_at_most.py +0 -19
  345. clearskies/input_requirements/maximum_length.py +0 -19
  346. clearskies/input_requirements/maximum_value.py +0 -19
  347. clearskies/input_requirements/minimum_length.py +0 -22
  348. clearskies/input_requirements/minimum_value.py +0 -19
  349. clearskies/input_requirements/requirement.py +0 -25
  350. clearskies/input_requirements/time_delta.py +0 -38
  351. clearskies/input_requirements/unique.py +0 -18
  352. clearskies/mocks/__init__.py +0 -7
  353. clearskies/mocks/input_output.py +0 -124
  354. clearskies/mocks/models.py +0 -142
  355. clearskies/models.py +0 -350
  356. clearskies/security_headers/base.py +0 -12
  357. clearskies/tests/simple_api/models/__init__.py +0 -2
  358. clearskies/tests/simple_api/models/status.py +0 -23
  359. clearskies/tests/simple_api/models/user.py +0 -21
  360. clearskies/tests/simple_api/users_api.py +0 -64
  361. {clear_skies-1.22.10.dist-info → clear_skies-2.0.23.dist-info/licenses}/LICENSE +0 -0
  362. /clearskies/{contexts/bash.py → autodoc/py.typed} +0 -0
  363. /clearskies/{handlers/exceptions → exceptions}/authentication.py +0 -0
  364. /clearskies/{handlers/exceptions → exceptions}/authorization.py +0 -0
  365. /clearskies/{handlers/exceptions → exceptions}/client_error.py +0 -0
  366. /clearskies/{secrets/exceptions → exceptions}/not_found.py +0 -0
  367. /clearskies/{tests/__init__.py → input_outputs/py.typed} +0 -0
  368. /clearskies/{tests/simple_api/__init__.py → py.typed} +0 -0
@@ -1,103 +0,0 @@
1
- from .api_backend import ApiBackend
2
- from typing import Any, Callable, Dict, List, Tuple
3
- from .. import model
4
- from ..autodoc.schema import Integer as AutoDocInteger
5
-
6
-
7
- class RestfulApiAdvancedSearchBackend(ApiBackend):
8
- _requests = None
9
- _auth = None
10
- _records = None
11
-
12
- _allowed_configs = [
13
- "wheres",
14
- "sorts",
15
- "limit",
16
- "pagination",
17
- "table_name",
18
- "model_columns",
19
- "select_all",
20
- ]
21
-
22
- _empty_configs = [
23
- "group_by_column",
24
- "selects",
25
- "joins",
26
- ]
27
-
28
- def __init__(self, requests):
29
- self._requests = requests
30
-
31
- def configure(self, auth=None):
32
- self._auth = auth
33
-
34
- def records_url(self, configuration: Dict[str, Any]) -> str:
35
- return configuration["table_name"].rstrip("/") + "/search"
36
-
37
- def delete_url(self, id: str, model: model.Model) -> str:
38
- table_name = model.table_name().rstrip("/")
39
- return f"{table_name}/{id}"
40
-
41
- def update_url(self, id: str, model: model.Model) -> str:
42
- table_name = model.table_name().rstrip("/")
43
- return f"{table_name}/{id}"
44
-
45
- def create_url(self, data: Dict[str, Any], model: model.Model) -> str:
46
- return model.table_name().rstrip("/")
47
-
48
- def records_method(self, configuration: Dict[str, Any]) -> str:
49
- return "POST"
50
-
51
- def count_method(self, configuration: Dict[str, Any]) -> str:
52
- return "POST"
53
-
54
- def _build_delete_request(self, id, model):
55
- data = model.data
56
- (url, data) = self._finalize_url_and_data(self.delete_url(id, model), data)
57
- return [url, self.delete_method(id, model), {}, {}]
58
-
59
- def _build_count_request(self, configuration):
60
- [url, method, json_data, headers] = super()._build_count_request(configuration)
61
- json_data["count_only"] = True
62
- return [url, method, json_data, headers]
63
-
64
- def records(self, configuration, model, next_page_data={}):
65
- configuration = self._check_query_configuration(configuration)
66
- [url, method, json_data, headers] = self._build_records_request(configuration)
67
- response = self._execute_request(url, method, json=json_data, headers=headers).json()
68
- records = self._map_records_response(response)
69
- for next_page_key in ["nextPage", "NextPage", "next_page"]:
70
- if response.get("pagination", {}).get(next_page_key):
71
- for key, value in response["pagination"][next_page_key].items():
72
- next_page_data[key] = value
73
- return records
74
-
75
- def _as_post_data(self, configuration):
76
- data = {
77
- "where": list(
78
- map(lambda where: self._where_for_post(where, configuration["model_columns"]), configuration["wheres"])
79
- ),
80
- "sort": configuration["sorts"],
81
- "start": configuration["pagination"].get("start", 0),
82
- "limit": configuration["limit"],
83
- }
84
- return {key: value for (key, value) in data.items() if value}
85
-
86
- def _where_for_post(self, where, columns):
87
- prefix = ""
88
- if where.get("table"):
89
- prefix = where["table"] + "."
90
- return {
91
- "column": prefix + where["column"],
92
- "operator": where["operator"],
93
- "value": self.normalize_outgoing_value(where, columns, where["values"][0]),
94
- }
95
-
96
- def normalize_outgoing_value(self, where, columns, value):
97
- column_name = where["column"]
98
- if where.get("table") or column_name not in columns:
99
- return value
100
- normalized_data = self.column_to_backend(columns[column_name], {column_name: value})
101
- if column_name in normalized_data:
102
- return normalized_data[column_name]
103
- return value
@@ -1,16 +0,0 @@
1
- import inspect
2
-
3
-
4
- class BindingConfig:
5
- object_class = None
6
- args = None
7
- kwargs = None
8
-
9
- def __init__(self, object_class, *args, **kwargs):
10
- if not inspect.isclass(object_class):
11
- raise ValueError(
12
- f"The first parameter passed to BindingConfig must be a class, not '{object_class.__class__.__name__}'"
13
- )
14
- self.object_class = object_class
15
- self.args = args
16
- self.kwargs = kwargs
@@ -1,203 +0,0 @@
1
- from .audit import Audit
2
- from .belongs_to import BelongsTo
3
- from .boolean import Boolean
4
- from .category_tree import CategoryTree
5
- from .column import Column
6
- from .created import Created
7
- from .created_by_authorization_data import CreatedByAuthorizationData
8
- from .created_by_header import CreatedByHeader
9
- from .created_by_ip import CreatedByIp
10
- from .created_by_routing_data import CreatedByRoutingData
11
- from .created_by_user_agent import CreatedByUserAgent
12
- from .created_micro import CreatedMicro
13
- from .datetime import DateTime
14
- from .datetime_micro import DateTimeMicro
15
- from .email import Email
16
- from .float import Float
17
- from .has_many import HasMany
18
- from .has_one import HasOne
19
- from .integer import Integer
20
- from .json import JSON
21
- from .many_to_many import ManyToMany
22
- from .many_to_many_with_data import ManyToManyWithData
23
- from .phone import Phone
24
- from .select import Select
25
- from .string import String
26
- from .timestamp import Timestamp
27
- from .updated import Updated
28
- from .updated_micro import UpdatedMicro
29
- from .uuid import UUID
30
-
31
-
32
- def build_column_config(name, column_class, **kwargs):
33
- return (name, {**{"class": column_class}, **kwargs})
34
-
35
-
36
- def audit(name, **kwargs):
37
- return build_column_config(name, Audit, **kwargs)
38
-
39
-
40
- def belongs_to(name, **kwargs):
41
- return build_column_config(name, BelongsTo, **kwargs)
42
-
43
-
44
- def boolean(name, **kwargs):
45
- return build_column_config(name, Boolean, **kwargs)
46
-
47
-
48
- def category_tree(name, **kwargs):
49
- return build_column_config(name, CategoryTree, **kwargs)
50
-
51
-
52
- def created(name, **kwargs):
53
- return build_column_config(name, Created, **kwargs)
54
-
55
-
56
- def created_by_authorization_data(name, **kwargs):
57
- return build_column_config(name, CreatedByAuthorizationData, **kwargs)
58
-
59
-
60
- def created_by_header(name, **kwargs):
61
- return build_column_config(name, CreatedByHeader, **kwargs)
62
-
63
-
64
- def created_by_ip(name, **kwargs):
65
- return build_column_config(name, CreatedByIp, **kwargs)
66
-
67
-
68
- def created_by_routing_data(name, **kwargs):
69
- return build_column_config(name, CreatedByRoutingData, **kwargs)
70
-
71
-
72
- def created_by_user_agent(name, **kwargs):
73
- return build_column_config(name, CreatedByUserAgent, **kwargs)
74
-
75
-
76
- def created_micro(name, **kwargs):
77
- return build_column_config(name, CreatedMicro, **kwargs)
78
-
79
-
80
- def datetime(name, **kwargs):
81
- return build_column_config(name, DateTime, **kwargs)
82
-
83
-
84
- def datetime_micro(name, **kwargs):
85
- return build_column_config(name, DateTimeMicro, **kwargs)
86
-
87
-
88
- def email(name, **kwargs):
89
- return build_column_config(name, Email, **kwargs)
90
-
91
-
92
- def float(name, **kwargs):
93
- return build_column_config(name, Float, **kwargs)
94
-
95
-
96
- def has_many(name, **kwargs):
97
- return build_column_config(name, HasMany, **kwargs)
98
-
99
-
100
- def has_one(name, **kwargs):
101
- return build_column_config(name, HasOne, **kwargs)
102
-
103
-
104
- def integer(name, **kwargs):
105
- return build_column_config(name, Integer, **kwargs)
106
-
107
-
108
- def json(name, **kwargs):
109
- return build_column_config(name, JSON, **kwargs)
110
-
111
-
112
- def many_to_many(name, **kwargs):
113
- return build_column_config(name, ManyToMany, **kwargs)
114
-
115
-
116
- def many_to_many_with_data(name, **kwargs):
117
- return build_column_config(name, ManyToManyWithData, **kwargs)
118
-
119
-
120
- def phone(name, **kwargs):
121
- return build_column_config(name, Phone, **kwargs)
122
-
123
-
124
- def select(name, **kwargs):
125
- return build_column_config(name, Select, **kwargs)
126
-
127
-
128
- def string(name, **kwargs):
129
- return build_column_config(name, String, **kwargs)
130
-
131
-
132
- def timestamp(name, **kwargs):
133
- return build_column_config(name, Timestamp, **kwargs)
134
-
135
-
136
- def updated(name, **kwargs):
137
- return build_column_config(name, Updated, **kwargs)
138
-
139
-
140
- def updated_micro(name, **kwargs):
141
- return build_column_config(name, UpdatedMicro, **kwargs)
142
-
143
-
144
- def uuid(name, **kwargs):
145
- return build_column_config(name, UUID, **kwargs)
146
-
147
-
148
- __all__ = [
149
- "build_column_config",
150
- "audit",
151
- "Audit",
152
- "belongs_to",
153
- "BelongsTo",
154
- "boolean",
155
- "Boolean",
156
- "category_tree",
157
- "CategoryTree",
158
- "Column",
159
- "created",
160
- "created_micro",
161
- "Created",
162
- "CreatdMicro",
163
- "created_by_authorization_data",
164
- "CreatedByAuthorizationData",
165
- "created_by_ip",
166
- "CreatedByIp",
167
- "created_by_user_agent",
168
- "CreatedByUserAgent",
169
- "CreatedMicro",
170
- "created_micro",
171
- "datetime",
172
- "datetime_micro",
173
- "DateTime",
174
- "DateTimeMicro",
175
- "email",
176
- "Email",
177
- "float",
178
- "Float",
179
- "has_many",
180
- "HasMany",
181
- "has_one",
182
- "HasOne",
183
- "integer",
184
- "Integer",
185
- "json",
186
- "JSON",
187
- "many_to_many",
188
- "ManyToMany",
189
- "many_to_many_with_data",
190
- "ManyToManyWithData",
191
- "phone",
192
- "Phone",
193
- "select",
194
- "Select",
195
- "string",
196
- "String",
197
- "updated",
198
- "updated_micro",
199
- "Updated",
200
- "UpdatedMicro",
201
- "uuid",
202
- "UUID",
203
- ]
@@ -1,249 +0,0 @@
1
- from . import string, has_many
2
- from clearskies.functional.string import title_case_to_snake_case
3
-
4
-
5
- class Audit(has_many.HasMany):
6
- """
7
- Enables auditing for a model.
8
-
9
- Specif the audit class to use and attach this to your model. Everytime the model is created/updated/deleted,
10
- the audit class will record the action and the changes. Your audit model must have the following columns:
11
-
12
- | Name | type |
13
- |-------------|----------|
14
- | class | str |
15
- | resource_id | str |
16
- | action | str |
17
- | data | json |
18
- | created_at | created |
19
-
20
- The names are not currently adjustable.
21
-
22
- 1. Class is a string that records the name of the class that the action happened for. This allows you to use
23
- the same audit class for multiple, different, resources.
24
- 2. resource_id is the id of the record which the audit entry is for.
25
- 3. Action is the actual action taken (create/update/delete)
26
- 4. Data is a serialized record of what columns in the record were changed (both their previous and new values)
27
- 5. The time the audit record was created
28
-
29
- With `exclude_columns` you can specify some names of columns to ignore. If an update happens and only columns
30
- in `exclude_columns` are being set, then a history entry will not be created. Also, these columns will
31
- not be included in the audit record.
32
-
33
- With `mask_columns` you can specify the names of columns which should be noted as updated in the audit record,
34
- but the actual values (before and after) should not be recorded.
35
- """
36
-
37
- _parent_columns = None
38
-
39
- required_configs = [
40
- "audit_models_class",
41
- ]
42
-
43
- my_configs = [
44
- "child_models_class",
45
- "exclude_columns",
46
- "mask_columns",
47
- "foreign_column_name",
48
- "is_readable",
49
- "readable_child_columns",
50
- "parent_class_name",
51
- "parent_id_column_name",
52
- "where",
53
- ]
54
-
55
- def __init__(self, di):
56
- super().__init__(di)
57
-
58
- def configure(self, name, configuration, model_class):
59
- if "audit_models_class" not in configuration:
60
- raise KeyError(
61
- "Missing required configuration value 'audit_models_class' for column '{name}' in model class "
62
- + f"'{model_class.__name__}'"
63
- )
64
- self.validate_models_class(configuration["audit_models_class"])
65
- has_many_configuration = {
66
- **configuration,
67
- "child_models_class": configuration.get("audit_models_class"),
68
- "foreign_column_name": "resource_id",
69
- "is_readable": True,
70
- "readable_child_columns": ["resource_id", "action", "data", "created_at"],
71
- "parent_class_name": model_class.__name__,
72
- "exclude_columns": configuration.get("exclude_columns", []),
73
- "mask_columns": configuration.get("mask_columns", []),
74
- }
75
- super().configure(name, has_many_configuration, model_class)
76
-
77
- def _check_configuration(self, configuration):
78
- super()._check_configuration(configuration)
79
- error_prefix = f"Configuration error for '{self.name}' in '{self.model_class.__name__}':"
80
- audit_columns = self.di.build(configuration["audit_models_class"], cache=True).raw_columns_configuration()
81
- parent_columns = self.di.build(self.model_class, cache=True).raw_columns_configuration()
82
- required_audit_columns = {
83
- "class": string.String,
84
- "resource_id": True,
85
- "action": string.String,
86
- "data": True,
87
- "created_at": True,
88
- }
89
- for column_name, column_type in required_audit_columns.items():
90
- if column_name not in audit_columns:
91
- raise ValueError(f"{error_prefix} audit models class does not have the required column '{column_name}'")
92
- if column_type == True:
93
- continue
94
- if audit_columns[column_name]["class"] != column_type:
95
- raise ValueError(
96
- f"{error_prefix} the '{column_name}' column in the audit models class should have a type of "
97
- + column_type.__name__
98
- + " but it has something else"
99
- )
100
-
101
- for config_name in ["exclude_columns", "mask_columns"]:
102
- if config_name not in configuration:
103
- continue
104
-
105
- config_columns = configuration[config_name]
106
- if not hasattr(config_columns, "__iter__"):
107
- raise ValueError(f"{error_prefix} '{config_name}' should be an iterable with the list of column names.")
108
- if isinstance(config_columns, str):
109
- raise ValueError(
110
- f"{error_prefix} '{config_name}' should be an iterable " + "with a list of column names."
111
- )
112
- for column_name in config_columns:
113
- if column_name not in parent_columns:
114
- raise ValueError(
115
- f"{error_prefix} '{config_name}' references column named '{column_name}' but this"
116
- + " column does not exist in the original model class."
117
- )
118
-
119
- def provide(self, data, column_name):
120
- return super().provide(data, column_name).where("class=" + self.config("parent_class_name"))
121
-
122
- def save_finished(self, model):
123
- super().save_finished(model)
124
- old_data = model._previous_data
125
- new_data = model._data
126
- exclude_columns = self.config("exclude_columns")
127
- mask_columns = self.config("mask_columns")
128
- parent_columns = self.parent_columns
129
-
130
- if not old_data:
131
- create_data = {}
132
- for key in new_data.keys():
133
- if key in exclude_columns:
134
- continue
135
- if key in parent_columns:
136
- column_data = parent_columns[key].to_json(model)
137
- else:
138
- column_data = {key: new_data[key]}
139
-
140
- create_data = {
141
- **create_data,
142
- **column_data,
143
- }
144
- if key in mask_columns and key in create_data:
145
- create_data[key] = "****"
146
- self.record(model, "create", data=create_data)
147
- return
148
-
149
- # note that this is fairly simple logic to get started. It's not going to detect changes that happen
150
- # in other "tables". For instance, disconnecting a record by deleting an entry in a many-to-many relationship
151
- # won't be picked up by this.
152
- old_model = model.empty_model()
153
- old_model.data = old_data
154
- from_data = {}
155
- to_data = {}
156
- for column, new_value in new_data.items():
157
- if column in exclude_columns or column not in old_data:
158
- continue
159
- if old_data[column] == new_value:
160
- continue
161
- from_data = {
162
- **from_data,
163
- **(
164
- parent_columns[column].to_json(old_model)
165
- if column in parent_columns
166
- else {column: old_data.get(column)}
167
- ),
168
- }
169
- to_data = {
170
- **to_data,
171
- **(
172
- parent_columns[column].to_json(model)
173
- if column in parent_columns
174
- else {column: model._data.get(column)}
175
- ),
176
- }
177
- if column in mask_columns and column in to_data:
178
- to_data[column] = "****"
179
- from_data[column] = "****"
180
- if not from_data and not to_data:
181
- return
182
-
183
- self.record(
184
- model,
185
- "update",
186
- data={
187
- "from": from_data,
188
- "to": to_data,
189
- },
190
- )
191
-
192
- def post_delete(self, model):
193
- super().post_delete(model)
194
- exclude_columns = self.config("exclude_columns")
195
- parent_columns = self.parent_columns
196
- mask_columns = self.config("mask_columns")
197
-
198
- final_data = {}
199
- for key in model._data.keys():
200
- if key in exclude_columns:
201
- continue
202
- final_data = {
203
- **final_data,
204
- **(parent_columns[key].to_json(model) if key in parent_columns else {key: model.data.get(key)}),
205
- }
206
-
207
- for key in mask_columns:
208
- if key not in final_data:
209
- continue
210
- final_data[key] = "****"
211
-
212
- self.child_models.create(
213
- {
214
- "class": self.config("parent_class_name"),
215
- "resource_id": model.get(self.config("parent_id_column_name")),
216
- "action": "delete",
217
- "data": final_data,
218
- }
219
- )
220
-
221
- @property
222
- def parent_columns(self):
223
- if self._parent_columns == None:
224
- self._parent_columns = self.di.build(self.model_class, cache=True).columns()
225
- return self._parent_columns
226
-
227
- def record(self, model, action, data=None, record_data=None):
228
- audit_data = {
229
- "class": self.config("parent_class_name"),
230
- "resource_id": model.get(self.config("parent_id_column_name")),
231
- "action": action,
232
- }
233
- if data is not None:
234
- audit_data["data"] = data
235
- if record_data is not None:
236
- audit_data = {
237
- **audit_data,
238
- **record_data,
239
- }
240
-
241
- self.child_models.create(audit_data)
242
-
243
-
244
- def build_column_config(name, column_class, **kwargs):
245
- return (name, {**{"class": column_class}, **kwargs})
246
-
247
-
248
- def audit(name, **kwargs):
249
- return build_column_config(name, Audit, **kwargs)