clear-skies 1.19.22__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 (362) 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.19.22.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 +9 -38
  7. clearskies/authentication/authentication.py +44 -0
  8. clearskies/authentication/authorization.py +14 -8
  9. clearskies/authentication/authorization_pass_through.py +22 -0
  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 +56 -17
  41. clearskies/backends/api_backend.py +1128 -166
  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 +117 -3
  154. clearskies/di/additional_config_auto_import.py +12 -0
  155. clearskies/di/di.py +717 -126
  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 -152
  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 +1894 -199
  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.19.22.dist-info/METADATA +0 -46
  243. clear_skies-1.19.22.dist-info/RECORD +0 -206
  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 -39
  248. clearskies/backends/example_backend.py +0 -43
  249. clearskies/backends/file_backend.py +0 -48
  250. clearskies/backends/json_backend.py +0 -7
  251. clearskies/backends/restful_api_advanced_search_backend.py +0 -138
  252. clearskies/binding_config.py +0 -16
  253. clearskies/column_types/__init__.py +0 -184
  254. clearskies/column_types/audit.py +0 -235
  255. clearskies/column_types/belongs_to.py +0 -250
  256. clearskies/column_types/boolean.py +0 -60
  257. clearskies/column_types/category_tree.py +0 -226
  258. clearskies/column_types/column.py +0 -373
  259. clearskies/column_types/created.py +0 -26
  260. clearskies/column_types/created_by_authorization_data.py +0 -26
  261. clearskies/column_types/created_by_header.py +0 -24
  262. clearskies/column_types/created_by_ip.py +0 -17
  263. clearskies/column_types/created_by_routing_data.py +0 -25
  264. clearskies/column_types/created_by_user_agent.py +0 -17
  265. clearskies/column_types/created_micro.py +0 -26
  266. clearskies/column_types/datetime.py +0 -108
  267. clearskies/column_types/datetime_micro.py +0 -12
  268. clearskies/column_types/email.py +0 -18
  269. clearskies/column_types/float.py +0 -43
  270. clearskies/column_types/has_many.py +0 -139
  271. clearskies/column_types/integer.py +0 -41
  272. clearskies/column_types/json.py +0 -25
  273. clearskies/column_types/many_to_many.py +0 -278
  274. clearskies/column_types/many_to_many_with_data.py +0 -162
  275. clearskies/column_types/select.py +0 -11
  276. clearskies/column_types/string.py +0 -24
  277. clearskies/column_types/updated.py +0 -24
  278. clearskies/column_types/updated_micro.py +0 -24
  279. clearskies/column_types/uuid.py +0 -25
  280. clearskies/columns.py +0 -123
  281. clearskies/condition_parser.py +0 -172
  282. clearskies/contexts/build_context.py +0 -54
  283. clearskies/contexts/convert_to_application.py +0 -190
  284. clearskies/contexts/extract_handler.py +0 -37
  285. clearskies/contexts/test.py +0 -94
  286. clearskies/decorators/__init__.py +0 -39
  287. clearskies/decorators/auth0_jwks.py +0 -22
  288. clearskies/decorators/authorization.py +0 -10
  289. clearskies/decorators/binding_classes.py +0 -9
  290. clearskies/decorators/binding_modules.py +0 -9
  291. clearskies/decorators/bindings.py +0 -9
  292. clearskies/decorators/create.py +0 -10
  293. clearskies/decorators/delete.py +0 -10
  294. clearskies/decorators/docs.py +0 -14
  295. clearskies/decorators/get.py +0 -10
  296. clearskies/decorators/jwks.py +0 -26
  297. clearskies/decorators/merge.py +0 -124
  298. clearskies/decorators/patch.py +0 -10
  299. clearskies/decorators/post.py +0 -10
  300. clearskies/decorators/public.py +0 -11
  301. clearskies/decorators/response_headers.py +0 -10
  302. clearskies/decorators/return_raw_response.py +0 -9
  303. clearskies/decorators/schema.py +0 -10
  304. clearskies/decorators/secret_bearer.py +0 -24
  305. clearskies/decorators/security_headers.py +0 -10
  306. clearskies/di/standard_dependencies.py +0 -140
  307. clearskies/di/test_module/__init__.py +0 -6
  308. clearskies/di/test_module/another_module/__init__.py +0 -2
  309. clearskies/di/test_module/module_class.py +0 -5
  310. clearskies/handlers/__init__.py +0 -41
  311. clearskies/handlers/advanced_search.py +0 -271
  312. clearskies/handlers/base.py +0 -473
  313. clearskies/handlers/callable.py +0 -189
  314. clearskies/handlers/create.py +0 -35
  315. clearskies/handlers/crud_by_method.py +0 -18
  316. clearskies/handlers/database_connector.py +0 -32
  317. clearskies/handlers/delete.py +0 -61
  318. clearskies/handlers/exceptions/__init__.py +0 -5
  319. clearskies/handlers/exceptions/not_found.py +0 -3
  320. clearskies/handlers/get.py +0 -156
  321. clearskies/handlers/health_check.py +0 -59
  322. clearskies/handlers/input_processing.py +0 -79
  323. clearskies/handlers/list.py +0 -530
  324. clearskies/handlers/mygrations.py +0 -82
  325. clearskies/handlers/request_method_routing.py +0 -47
  326. clearskies/handlers/restful_api.py +0 -218
  327. clearskies/handlers/routing.py +0 -62
  328. clearskies/handlers/schema_helper.py +0 -128
  329. clearskies/handlers/simple_routing.py +0 -204
  330. clearskies/handlers/simple_routing_route.py +0 -192
  331. clearskies/handlers/simple_search.py +0 -136
  332. clearskies/handlers/update.py +0 -96
  333. clearskies/handlers/write.py +0 -193
  334. clearskies/input_requirements/__init__.py +0 -68
  335. clearskies/input_requirements/after.py +0 -36
  336. clearskies/input_requirements/before.py +0 -36
  337. clearskies/input_requirements/in_the_future_at_least.py +0 -19
  338. clearskies/input_requirements/in_the_future_at_most.py +0 -19
  339. clearskies/input_requirements/in_the_past_at_least.py +0 -19
  340. clearskies/input_requirements/in_the_past_at_most.py +0 -19
  341. clearskies/input_requirements/maximum_length.py +0 -19
  342. clearskies/input_requirements/minimum_length.py +0 -22
  343. clearskies/input_requirements/requirement.py +0 -25
  344. clearskies/input_requirements/time_delta.py +0 -38
  345. clearskies/input_requirements/unique.py +0 -18
  346. clearskies/mocks/__init__.py +0 -7
  347. clearskies/mocks/input_output.py +0 -124
  348. clearskies/mocks/models.py +0 -142
  349. clearskies/models.py +0 -345
  350. clearskies/security_headers/base.py +0 -12
  351. clearskies/tests/simple_api/models/__init__.py +0 -2
  352. clearskies/tests/simple_api/models/status.py +0 -23
  353. clearskies/tests/simple_api/models/user.py +0 -21
  354. clearskies/tests/simple_api/users_api.py +0 -64
  355. {clear_skies-1.19.22.dist-info → clear_skies-2.0.23.dist-info/licenses}/LICENSE +0 -0
  356. /clearskies/{contexts/bash.py → autodoc/py.typed} +0 -0
  357. /clearskies/{handlers/exceptions → exceptions}/authentication.py +0 -0
  358. /clearskies/{handlers/exceptions → exceptions}/authorization.py +0 -0
  359. /clearskies/{handlers/exceptions → exceptions}/client_error.py +0 -0
  360. /clearskies/{secrets/exceptions → exceptions}/not_found.py +0 -0
  361. /clearskies/{tests/__init__.py → input_outputs/py.typed} +0 -0
  362. /clearskies/{tests/simple_api/__init__.py → py.typed} +0 -0
@@ -1,35 +0,0 @@
1
- from .write import Write
2
- from .exceptions import InputError
3
- from collections import OrderedDict
4
- from ..functional import string
5
- import json
6
-
7
-
8
- class Create(Write):
9
- _is_create = True
10
-
11
- def __init__(self, di, logging):
12
- super().__init__(di)
13
- self._logging = logging
14
-
15
- def handle(self, input_output):
16
- model = self._model.empty_model()
17
- input_data = self.request_data(input_output)
18
- self._logging.debug("Incoming request data: " + json.dumps(input_data))
19
- input_errors = {
20
- **self._extra_column_errors(input_data),
21
- **self._find_input_errors(model, input_data, input_output),
22
- }
23
- if input_errors:
24
- self._logging.debug("Request rejected due to input errors: " + json.dumps(input_errors))
25
- raise InputError(input_errors)
26
- model.save(input_data, columns=self._columns)
27
-
28
- return self.success(input_output, self._model_as_json(model, input_output))
29
-
30
- def documentation(self):
31
- nice_model = string.camel_case_to_words(self._model.__class__.__name__)
32
- return self._documentation(
33
- description=f"Create a new {nice_model}",
34
- response_description=f"The new {nice_model}",
35
- )
@@ -1,18 +0,0 @@
1
- from .request_method_routing import RequestMethodRouting
2
- from .create import Create
3
- from .update import Update
4
- from .delete import Delete
5
- from .get import Get
6
-
7
-
8
- class CRUDByMethod(RequestMethodRouting):
9
- def __init__(self, di):
10
- super().__init__(di)
11
-
12
- def method_handler_map(self):
13
- return {
14
- "CREATE": Create,
15
- "GET": Get,
16
- "PATCH": Update,
17
- "DELETE": Delete,
18
- }
@@ -1,32 +0,0 @@
1
- from .base import Base
2
- import os
3
-
4
-
5
- class DatabaseConnector(Base):
6
- _configuration_defaults = {
7
- "tunnel_only": False,
8
- "command": "mysql",
9
- }
10
-
11
- def __init__(self, di):
12
- super().__init__(di)
13
-
14
- def handle(self, input_output):
15
- connection_details = self._di.build("connection_details")
16
- request_body = input_output.json_body(required=False)
17
- if request_body and "tunnel_only" in request_body:
18
- tunnel_only = request_body["tunnel_only"]
19
- else:
20
- tunnel_only = self.configuration("tunnel_only")
21
-
22
- if tunnel_only:
23
- return self.success(input_output, {})
24
-
25
- command = self.configuration("command")
26
- port = connection_details.get("port", 3306)
27
- print("connect!")
28
- print(connection_details["host"])
29
- os.system(
30
- f"{command} -h {connection_details['host']} -u '{connection_details['username']}' -p'{connection_details['password']}' --port={port} -D {connection_details['database']}"
31
- )
32
- print("done!")
@@ -1,61 +0,0 @@
1
- from collections import OrderedDict
2
- from .base import Base
3
- from .. import autodoc
4
- from ..functional import string
5
- from .get import Get
6
-
7
-
8
- class Delete(Get):
9
- _configuration_defaults = {
10
- "model": None,
11
- "model_class": None,
12
- "readable_columns": None,
13
- "where": [],
14
- }
15
-
16
- def __init__(self, di):
17
- super().__init__(di)
18
-
19
- def handle(self, input_output):
20
- model = self.fetch_model(input_output)
21
- if type(model) == str:
22
- return self.error(input_output, model, 404)
23
-
24
- model.delete()
25
- return self.success(input_output, {})
26
-
27
- def documentation(self):
28
- nice_model = string.camel_case_to_words(self._model.__class__.__name__)
29
-
30
- authentication = self.configuration("authentication")
31
- standard_error_responses = []
32
- if not getattr(authentication, "is_public", False):
33
- standard_error_responses.append(self.documentation_access_denied_response())
34
- if getattr(authentication, "can_authorize", False):
35
- standard_error_responses.append(self.documentation_unauthorized_response())
36
-
37
- id_label = "id" if self.configuration("id_column_name") else self.id_column_name
38
- return [
39
- autodoc.request.Request(
40
- "Delete the " + nice_model + " with an " + id_label + " of {" + id_label + "}",
41
- [
42
- self.documentation_success_response(
43
- autodoc.schema.Object("data", children=[]),
44
- description=f"The {nice_model} was deleted",
45
- ),
46
- *standard_error_responses,
47
- self.documentation_not_found(),
48
- ],
49
- relative_path=self.configuration("base_url").rstrip("/") + "/{" + id_label + "}",
50
- parameters=[
51
- autodoc.request.URLPath(
52
- autodoc.schema.Integer(id_label),
53
- description=f"The {id_label} of the record to delete.",
54
- required=True,
55
- )
56
- ],
57
- root_properties={
58
- "security": self.documentation_request_security(),
59
- },
60
- )
61
- ]
@@ -1,5 +0,0 @@
1
- from .authentication import Authentication
2
- from .authorization import Authorization
3
- from .client_error import ClientError
4
- from .input_error import InputError
5
- from .not_found import NotFound
@@ -1,3 +0,0 @@
1
- class NotFound(Exception):
2
- def __init__(self, error):
3
- super().__init__(self, error)
@@ -1,156 +0,0 @@
1
- from .base import Base
2
- from collections import OrderedDict
3
- from .. import autodoc
4
- from .. import condition_parser
5
- from ..functional import string
6
- import inspect
7
-
8
-
9
- class Get(Base):
10
- _model = None
11
-
12
- _configuration_defaults = {
13
- "model": None,
14
- "model_class": None,
15
- "readable_columns": None,
16
- "where": [],
17
- }
18
-
19
- def __init__(self, di):
20
- super().__init__(di)
21
-
22
- def handle(self, input_output):
23
- model = self.fetch_model(input_output)
24
- if type(model) == str:
25
- return self.error(input_output, model, 404)
26
- return self.success(input_output, self._model_as_json(model, input_output))
27
-
28
- def get_model_id(self, input_output):
29
- routing_data = input_output.routing_data()
30
- if self.id_column_name in routing_data:
31
- return routing_data[self.id_column_name]
32
- if "id" in routing_data:
33
- return routing_data["id"]
34
- raise ValueError("I didn't receive the ID in my routing data. I am probably misconfigured.")
35
-
36
- def fetch_model(self, input_output):
37
- id = self.get_model_id(input_output)
38
- models = self._model.where(f"{self.id_column_name}={id}")
39
- for where in self.configuration("where"):
40
- if type(where) == str:
41
- models = models.where(where)
42
- else:
43
- models = self._di.call_function(
44
- where,
45
- models=models,
46
- input_output=input_output,
47
- routing_data=input_output.routing_data(),
48
- authorization_data=input_output.get_authorization_data(),
49
- )
50
- models = models.where_for_request(
51
- models,
52
- input_output.routing_data(),
53
- input_output.get_authorization_data(),
54
- input_output,
55
- )
56
- authorization = self._configuration.get("authorization", None)
57
- if authorization and hasattr(authorization, "filter_models"):
58
- models = authorization.filter_models(models, input_output.get_authorization_data(), input_output)
59
- model = models.first()
60
- if not model.exists:
61
- return "Not Found"
62
-
63
- return model
64
-
65
- def _check_configuration(self, configuration):
66
- super()._check_configuration(configuration)
67
- error_prefix = "Configuration error for %s:" % (self.__class__.__name__)
68
- has_model_class = ("model_class" in configuration) and configuration["model_class"] is not None
69
- has_model = ("model" in configuration) and configuration["model"] is not None
70
- if not has_model and not has_model_class:
71
- raise KeyError(f"{error_prefix} you must specify 'model' or 'model_class'")
72
- if has_model and has_model_class:
73
- raise KeyError(f"{error_prefix} you specified both 'model' and 'model_class', but can only provide one")
74
- if has_model and inspect.isclass(configuration["model"]):
75
- raise ValueError(
76
- "{error_prefix} you must provide a model instance in the 'model' configuration setting, but a class was provided instead"
77
- )
78
- if "where" in configuration:
79
- if not hasattr(configuration["where"], "__iter__") or type(configuration["where"]) == str:
80
- raise ValueError(
81
- f"{error_prefix} 'where' should be an iterable of coditions or callables "
82
- + ", not "
83
- + str(type(configuration["where"])),
84
- )
85
- for index, where in enumerate(configuration["where"]):
86
- if type(where) != str and not callable(where):
87
- raise ValueError(
88
- f"{error_prefix} 'where' entry should be a string with a condition or a callable that filters models "
89
- + f", but entry #{index+1} is neither of these",
90
- )
91
- self._model = self._di.build(configuration["model_class"]) if has_model_class else configuration["model"]
92
- self._columns = self._model.columns(overrides=configuration.get("column_overrides"))
93
-
94
- def _get_readable_columns(self):
95
- resolved_columns = OrderedDict()
96
- for column_name in self.configuration("readable_columns"):
97
- if column_name not in self._columns:
98
- class_name = self.__class__.__name__
99
- model_class = self._model.__class__.__name__
100
- raise ValueError(
101
- f"Handler {class_name} was configured with readable column '{column_name}' but this "
102
- + f"column doesn't exist for model {model_class}"
103
- )
104
- resolved_columns[column_name] = self._columns[column_name]
105
- return resolved_columns
106
-
107
- def documentation(self):
108
- nice_model = string.camel_case_to_words(self._model.__class__.__name__)
109
-
110
- authentication = self.configuration("authentication")
111
- standard_error_responses = []
112
- if not getattr(authentication, "is_public", False):
113
- standard_error_responses.append(self.documentation_access_denied_response())
114
- if getattr(authentication, "can_authorize", False):
115
- standard_error_responses.append(self.documentation_unauthorized_response())
116
-
117
- id_label = "id" if self.configuration("id_column_name") else self.id_column_name
118
-
119
- return [
120
- autodoc.request.Request(
121
- "Fetch the " + nice_model + " with an " + id_label + " of {" + id_label + "}",
122
- [
123
- self.documentation_success_response(
124
- autodoc.schema.Object(
125
- "data",
126
- children=self.documentation_data_schema(),
127
- model_name=string.camel_case_to_snake_case(self._model.__class__.__name__),
128
- ),
129
- description=f"The {nice_model} record",
130
- ),
131
- *standard_error_responses,
132
- self.documentation_not_found(),
133
- ],
134
- relative_path=self.configuration("base_url").rstrip("/") + "/{" + id_label + "}",
135
- parameters=[
136
- autodoc.request.URLPath(
137
- autodoc.schema.String(id_label),
138
- description=f"The {id_label} of the record to get",
139
- required=True,
140
- )
141
- ],
142
- root_properties={
143
- "security": self.documentation_request_security(),
144
- },
145
- )
146
- ]
147
-
148
- def documentation_models(self):
149
- schema_model_name = string.camel_case_to_snake_case(self._model.__class__.__name__)
150
-
151
- return {
152
- schema_model_name: autodoc.schema.Object(
153
- "data",
154
- children=self.documentation_data_schema(),
155
- ),
156
- }
@@ -1,59 +0,0 @@
1
- from .base import Base
2
- from collections import OrderedDict
3
- from .. import autodoc
4
- from .. import condition_parser
5
- from ..functional import string
6
- import inspect
7
-
8
-
9
- class HealthCheck(Base):
10
- _configuration_defaults = {
11
- "services": [],
12
- "callable": None,
13
- }
14
-
15
- def __init__(self, di):
16
- super().__init__(di)
17
-
18
- def top_level_authentication_and_authorization(self, input_output, authentication=None):
19
- pass
20
-
21
- def handle(self, input_output):
22
- services = self.configuration("services")
23
- health_callable = self.configuration("callable")
24
- try:
25
- if services:
26
- for service in services:
27
- self._di.build(service, cache=True)
28
- if health_callable and not health_callable():
29
- return self.respond(input_output, {"status": "failure"}, 500)
30
- except:
31
- return self.respond(input_output, {"status": "failure"}, 500)
32
-
33
- return self.success(input_output, {})
34
-
35
- def _check_configuration(self, configuration):
36
- error_prefix = "Configuration error for %s:" % (self.__class__.__name__)
37
- services = configuration.get("services")
38
- if services is not None and type(services) != list:
39
- raise ValueError(
40
- f'{error_prefix} "services" should be a list of names, with each name corresponding to a dependency to load'
41
- )
42
- health_callable = configuration.get("callable")
43
- if health_callable is not None and not callable(health_callable):
44
- raise ValueError(
45
- f'{error_prefix} "callable" should be a callable that returns true/false to denote health status'
46
- )
47
-
48
- def documentation(self):
49
- return [
50
- autodoc.request.Request(
51
- "Healthcheck",
52
- [
53
- self.documentation_success_response(
54
- autodoc.schema.Object("data", children=[]),
55
- ),
56
- ],
57
- relative_path=self.configuration("base_url"),
58
- )
59
- ]
@@ -1,79 +0,0 @@
1
- from .exceptions import InputError
2
- from collections import OrderedDict
3
- from abc import abstractmethod
4
-
5
-
6
- class InputProcessing:
7
- _is_create = False
8
-
9
- def _get_writeable_columns(self):
10
- if self._writeable_columns is None:
11
- self._writeable_columns = self._get_rw_columns("writeable")
12
- additional_columns = OrderedDict()
13
- for column in self._writeable_columns.values():
14
- more_columns = column.additional_write_columns(is_create=self._is_create)
15
- for additional_column_name, additional_column in more_columns.items():
16
- additional_columns[additional_column_name] = additional_column
17
- for additional_column_name, additional_column in additional_columns.items():
18
- self._writeable_columns[additional_column_name] = additional_column
19
- return self._writeable_columns
20
-
21
- def _extra_column_errors(self, input_data):
22
- input_errors = {}
23
- allowed = self._get_writeable_columns()
24
- for column_name in input_data.keys():
25
- if column_name not in allowed:
26
- input_errors[column_name] = f"Input column '{column_name}' is not an allowed column"
27
- return input_errors
28
-
29
- def _find_input_errors(self, model, input_data, input_output):
30
- input_errors = {}
31
- for column in self._get_writeable_columns().values():
32
- input_errors = {
33
- **input_errors,
34
- **column.input_errors(model, input_data),
35
- }
36
- input_error_callable = self.configuration("input_error_callable")
37
- if input_error_callable:
38
- more_input_errors = self._di.call_function(
39
- input_error_callable,
40
- input_data=input_data,
41
- request_data=input_data,
42
- input_output=input_output,
43
- routing_data=input_output.routing_data(),
44
- authorization_data=input_output.get_authorization_data(),
45
- )
46
- if type(more_input_errors) != dict:
47
- raise ValueError(
48
- "The input error callable, '"
49
- + str(input_error_callable)
50
- + "', did not return a dictionary as required"
51
- )
52
- input_errors = {
53
- **input_errors,
54
- **more_input_errors,
55
- }
56
- return input_errors
57
-
58
- def request_data(self, input_output, required=True):
59
- # we have to map from internal names to external names, because case mapping
60
- # isn't always one-to-one, so we want to do it exactly the same way that the documentation
61
- # is built.
62
- key_map = {self.auto_case_column_name(key, True): key for key in self._get_writeable_columns().keys()}
63
- # in case the id comes up in the request body
64
- key_map[self.auto_case_internal_column_name("id")] = "id"
65
-
66
- # and make sure we don't drop any data along the way, because the input validation
67
- # needs to return an error for unexpected data.
68
- request_data = {
69
- key_map.get(key, key): value for (key, value) in input_output.request_data(required=required).items()
70
- }
71
- # the parent handler should provide our resource id (we don't do any routing ourselves)
72
- # However, our update/etc handlers need to find the id easily, so I'm going to be lazy and
73
- # just dump it into the request. I'll probably regret that.
74
- routing_data = input_output.routing_data()
75
- # we don't have to worry about casing on the 'id' in routing_data because it doesn't come in from the
76
- # route with a name. Rather, it is populated by clearskies, so will always just be 'id'
77
- if "id" in routing_data:
78
- request_data["id"] = routing_data["id"]
79
- return request_data