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.
- clear_skies-2.0.23.dist-info/METADATA +76 -0
- clear_skies-2.0.23.dist-info/RECORD +265 -0
- {clear_skies-1.22.10.dist-info → clear_skies-2.0.23.dist-info}/WHEEL +1 -1
- clearskies/__init__.py +37 -21
- clearskies/action.py +7 -0
- clearskies/authentication/__init__.py +8 -39
- clearskies/authentication/authentication.py +44 -0
- clearskies/authentication/authorization.py +14 -8
- clearskies/authentication/authorization_pass_through.py +14 -10
- clearskies/authentication/jwks.py +135 -58
- clearskies/authentication/public.py +3 -26
- clearskies/authentication/secret_bearer.py +515 -44
- clearskies/autodoc/formats/oai3_json/__init__.py +2 -2
- clearskies/autodoc/formats/oai3_json/oai3_json.py +11 -9
- clearskies/autodoc/formats/oai3_json/parameter.py +6 -3
- clearskies/autodoc/formats/oai3_json/request.py +7 -5
- clearskies/autodoc/formats/oai3_json/response.py +7 -4
- clearskies/autodoc/formats/oai3_json/schema/object.py +10 -1
- clearskies/autodoc/request/__init__.py +2 -0
- clearskies/autodoc/request/header.py +4 -6
- clearskies/autodoc/request/json_body.py +4 -6
- clearskies/autodoc/request/parameter.py +8 -0
- clearskies/autodoc/request/request.py +16 -4
- clearskies/autodoc/request/url_parameter.py +4 -6
- clearskies/autodoc/request/url_path.py +4 -6
- clearskies/autodoc/schema/__init__.py +4 -2
- clearskies/autodoc/schema/array.py +5 -6
- clearskies/autodoc/schema/boolean.py +4 -10
- clearskies/autodoc/schema/date.py +0 -3
- clearskies/autodoc/schema/datetime.py +1 -4
- clearskies/autodoc/schema/double.py +0 -3
- clearskies/autodoc/schema/enum.py +4 -2
- clearskies/autodoc/schema/integer.py +4 -9
- clearskies/autodoc/schema/long.py +0 -3
- clearskies/autodoc/schema/number.py +4 -9
- clearskies/autodoc/schema/object.py +5 -7
- clearskies/autodoc/schema/password.py +0 -3
- clearskies/autodoc/schema/schema.py +11 -0
- clearskies/autodoc/schema/string.py +4 -10
- clearskies/backends/__init__.py +55 -20
- clearskies/backends/api_backend.py +1118 -280
- clearskies/backends/backend.py +54 -85
- clearskies/backends/cursor_backend.py +246 -191
- clearskies/backends/memory_backend.py +514 -208
- clearskies/backends/secrets_backend.py +68 -31
- clearskies/column.py +1221 -0
- clearskies/columns/__init__.py +71 -0
- clearskies/columns/audit.py +306 -0
- clearskies/columns/belongs_to_id.py +478 -0
- clearskies/columns/belongs_to_model.py +129 -0
- clearskies/columns/belongs_to_self.py +109 -0
- clearskies/columns/boolean.py +110 -0
- clearskies/columns/category_tree.py +273 -0
- clearskies/columns/category_tree_ancestors.py +51 -0
- clearskies/columns/category_tree_children.py +126 -0
- clearskies/columns/category_tree_descendants.py +48 -0
- clearskies/columns/created.py +92 -0
- clearskies/columns/created_by_authorization_data.py +114 -0
- clearskies/columns/created_by_header.py +103 -0
- clearskies/columns/created_by_ip.py +90 -0
- clearskies/columns/created_by_routing_data.py +102 -0
- clearskies/columns/created_by_user_agent.py +89 -0
- clearskies/columns/date.py +232 -0
- clearskies/columns/datetime.py +284 -0
- clearskies/columns/email.py +78 -0
- clearskies/columns/float.py +149 -0
- clearskies/columns/has_many.py +529 -0
- clearskies/columns/has_many_self.py +62 -0
- clearskies/columns/has_one.py +21 -0
- clearskies/columns/integer.py +158 -0
- clearskies/columns/json.py +126 -0
- clearskies/columns/many_to_many_ids.py +335 -0
- clearskies/columns/many_to_many_ids_with_data.py +274 -0
- clearskies/columns/many_to_many_models.py +156 -0
- clearskies/columns/many_to_many_pivots.py +132 -0
- clearskies/columns/phone.py +162 -0
- clearskies/columns/select.py +95 -0
- clearskies/columns/string.py +102 -0
- clearskies/columns/timestamp.py +164 -0
- clearskies/columns/updated.py +107 -0
- clearskies/columns/uuid.py +83 -0
- clearskies/configs/README.md +105 -0
- clearskies/configs/__init__.py +170 -0
- clearskies/configs/actions.py +43 -0
- clearskies/configs/any.py +15 -0
- clearskies/configs/any_dict.py +24 -0
- clearskies/configs/any_dict_or_callable.py +25 -0
- clearskies/configs/authentication.py +23 -0
- clearskies/configs/authorization.py +23 -0
- clearskies/configs/boolean.py +18 -0
- clearskies/configs/boolean_or_callable.py +20 -0
- clearskies/configs/callable_config.py +20 -0
- clearskies/configs/columns.py +34 -0
- clearskies/configs/conditions.py +30 -0
- clearskies/configs/config.py +26 -0
- clearskies/configs/datetime.py +20 -0
- clearskies/configs/datetime_or_callable.py +21 -0
- clearskies/configs/email.py +10 -0
- clearskies/configs/email_list.py +17 -0
- clearskies/configs/email_list_or_callable.py +17 -0
- clearskies/configs/email_or_email_list_or_callable.py +59 -0
- clearskies/configs/endpoint.py +23 -0
- clearskies/configs/endpoint_list.py +29 -0
- clearskies/configs/float.py +18 -0
- clearskies/configs/float_or_callable.py +20 -0
- clearskies/configs/headers.py +28 -0
- clearskies/configs/integer.py +18 -0
- clearskies/configs/integer_or_callable.py +20 -0
- clearskies/configs/joins.py +30 -0
- clearskies/configs/list_any_dict.py +32 -0
- clearskies/configs/list_any_dict_or_callable.py +33 -0
- clearskies/configs/model_class.py +35 -0
- clearskies/configs/model_column.py +67 -0
- clearskies/configs/model_columns.py +58 -0
- clearskies/configs/model_destination_name.py +26 -0
- clearskies/configs/model_to_id_column.py +45 -0
- clearskies/configs/readable_model_column.py +11 -0
- clearskies/configs/readable_model_columns.py +11 -0
- clearskies/configs/schema.py +23 -0
- clearskies/configs/searchable_model_columns.py +11 -0
- clearskies/configs/security_headers.py +39 -0
- clearskies/configs/select.py +28 -0
- clearskies/configs/select_list.py +49 -0
- clearskies/configs/string.py +31 -0
- clearskies/configs/string_dict.py +34 -0
- clearskies/configs/string_list.py +47 -0
- clearskies/configs/string_list_or_callable.py +48 -0
- clearskies/configs/string_or_callable.py +18 -0
- clearskies/configs/timedelta.py +20 -0
- clearskies/configs/timezone.py +20 -0
- clearskies/configs/url.py +25 -0
- clearskies/configs/validators.py +45 -0
- clearskies/configs/writeable_model_column.py +11 -0
- clearskies/configs/writeable_model_columns.py +11 -0
- clearskies/configurable.py +78 -0
- clearskies/contexts/__init__.py +8 -8
- clearskies/contexts/cli.py +129 -43
- clearskies/contexts/context.py +93 -56
- clearskies/contexts/wsgi.py +79 -33
- clearskies/contexts/wsgi_ref.py +87 -0
- clearskies/cursors/__init__.py +7 -0
- clearskies/cursors/cursor.py +166 -0
- clearskies/cursors/from_environment/__init__.py +5 -0
- clearskies/cursors/from_environment/mysql.py +51 -0
- clearskies/cursors/from_environment/postgresql.py +49 -0
- clearskies/cursors/from_environment/sqlite.py +35 -0
- clearskies/cursors/mysql.py +61 -0
- clearskies/cursors/postgresql.py +61 -0
- clearskies/cursors/sqlite.py +62 -0
- clearskies/decorators.py +33 -0
- clearskies/decorators.pyi +10 -0
- clearskies/di/__init__.py +11 -7
- clearskies/di/additional_config.py +115 -4
- clearskies/di/additional_config_auto_import.py +12 -0
- clearskies/di/di.py +714 -125
- clearskies/di/inject/__init__.py +23 -0
- clearskies/di/inject/akeyless_sdk.py +16 -0
- clearskies/di/inject/by_class.py +24 -0
- clearskies/di/inject/by_name.py +22 -0
- clearskies/di/inject/di.py +16 -0
- clearskies/di/inject/environment.py +15 -0
- clearskies/di/inject/input_output.py +19 -0
- clearskies/di/inject/now.py +16 -0
- clearskies/di/inject/requests.py +16 -0
- clearskies/di/inject/secrets.py +15 -0
- clearskies/di/inject/utcnow.py +16 -0
- clearskies/di/inject/uuid.py +16 -0
- clearskies/di/injectable.py +32 -0
- clearskies/di/injectable_properties.py +131 -0
- clearskies/end.py +219 -0
- clearskies/endpoint.py +1303 -0
- clearskies/endpoint_group.py +333 -0
- clearskies/endpoints/__init__.py +25 -0
- clearskies/endpoints/advanced_search.py +519 -0
- clearskies/endpoints/callable.py +382 -0
- clearskies/endpoints/create.py +201 -0
- clearskies/endpoints/delete.py +133 -0
- clearskies/endpoints/get.py +267 -0
- clearskies/endpoints/health_check.py +181 -0
- clearskies/endpoints/list.py +567 -0
- clearskies/endpoints/restful_api.py +417 -0
- clearskies/endpoints/schema.py +185 -0
- clearskies/endpoints/simple_search.py +279 -0
- clearskies/endpoints/update.py +188 -0
- clearskies/environment.py +7 -3
- clearskies/exceptions/__init__.py +19 -0
- clearskies/{handlers/exceptions/input_error.py → exceptions/input_errors.py} +1 -1
- clearskies/exceptions/missing_dependency.py +2 -0
- clearskies/exceptions/moved_permanently.py +3 -0
- clearskies/exceptions/moved_temporarily.py +3 -0
- clearskies/functional/__init__.py +2 -2
- clearskies/functional/json.py +47 -0
- clearskies/functional/routing.py +92 -0
- clearskies/functional/string.py +19 -11
- clearskies/functional/validations.py +61 -9
- clearskies/input_outputs/__init__.py +9 -7
- clearskies/input_outputs/cli.py +135 -160
- clearskies/input_outputs/exceptions/__init__.py +6 -1
- clearskies/input_outputs/headers.py +54 -0
- clearskies/input_outputs/input_output.py +77 -123
- clearskies/input_outputs/programmatic.py +62 -0
- clearskies/input_outputs/wsgi.py +36 -48
- clearskies/model.py +1874 -193
- clearskies/query/__init__.py +12 -0
- clearskies/query/condition.py +228 -0
- clearskies/query/join.py +136 -0
- clearskies/query/query.py +193 -0
- clearskies/query/sort.py +27 -0
- clearskies/schema.py +82 -0
- clearskies/secrets/__init__.py +4 -31
- clearskies/secrets/additional_configs/mysql_connection_dynamic_producer.py +15 -4
- clearskies/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py +11 -5
- clearskies/secrets/akeyless.py +421 -155
- clearskies/secrets/exceptions/__init__.py +7 -1
- clearskies/secrets/exceptions/not_found_error.py +2 -0
- clearskies/secrets/exceptions/permissions_error.py +2 -0
- clearskies/secrets/secrets.py +12 -11
- clearskies/security_header.py +17 -0
- clearskies/security_headers/__init__.py +8 -8
- clearskies/security_headers/cache_control.py +47 -109
- clearskies/security_headers/cors.py +38 -92
- clearskies/security_headers/csp.py +76 -150
- clearskies/security_headers/hsts.py +14 -15
- clearskies/typing.py +11 -0
- clearskies/validator.py +36 -0
- clearskies/validators/__init__.py +33 -0
- clearskies/validators/after_column.py +61 -0
- clearskies/validators/before_column.py +15 -0
- clearskies/validators/in_the_future.py +29 -0
- clearskies/validators/in_the_future_at_least.py +13 -0
- clearskies/validators/in_the_future_at_most.py +12 -0
- clearskies/validators/in_the_past.py +29 -0
- clearskies/validators/in_the_past_at_least.py +12 -0
- clearskies/validators/in_the_past_at_most.py +12 -0
- clearskies/validators/maximum_length.py +25 -0
- clearskies/validators/maximum_value.py +28 -0
- clearskies/validators/minimum_length.py +25 -0
- clearskies/validators/minimum_value.py +28 -0
- clearskies/{input_requirements → validators}/required.py +18 -9
- clearskies/validators/timedelta.py +58 -0
- clearskies/validators/unique.py +28 -0
- clear_skies-1.22.10.dist-info/METADATA +0 -47
- clear_skies-1.22.10.dist-info/RECORD +0 -213
- clearskies/application.py +0 -29
- clearskies/authentication/auth0_jwks.py +0 -118
- clearskies/authentication/auth_exception.py +0 -2
- clearskies/authentication/jwks_jwcrypto.py +0 -51
- clearskies/backends/api_get_only_backend.py +0 -48
- clearskies/backends/example_backend.py +0 -43
- clearskies/backends/file_backend.py +0 -48
- clearskies/backends/json_backend.py +0 -7
- clearskies/backends/restful_api_advanced_search_backend.py +0 -103
- clearskies/binding_config.py +0 -16
- clearskies/column_types/__init__.py +0 -203
- clearskies/column_types/audit.py +0 -249
- clearskies/column_types/belongs_to.py +0 -271
- clearskies/column_types/boolean.py +0 -60
- clearskies/column_types/category_tree.py +0 -304
- clearskies/column_types/column.py +0 -373
- clearskies/column_types/created.py +0 -26
- clearskies/column_types/created_by_authorization_data.py +0 -26
- clearskies/column_types/created_by_header.py +0 -24
- clearskies/column_types/created_by_ip.py +0 -17
- clearskies/column_types/created_by_routing_data.py +0 -25
- clearskies/column_types/created_by_user_agent.py +0 -17
- clearskies/column_types/created_micro.py +0 -26
- clearskies/column_types/datetime.py +0 -109
- clearskies/column_types/datetime_micro.py +0 -13
- clearskies/column_types/email.py +0 -18
- clearskies/column_types/float.py +0 -43
- clearskies/column_types/has_many.py +0 -179
- clearskies/column_types/has_one.py +0 -58
- clearskies/column_types/integer.py +0 -41
- clearskies/column_types/json.py +0 -25
- clearskies/column_types/many_to_many.py +0 -278
- clearskies/column_types/many_to_many_with_data.py +0 -162
- clearskies/column_types/phone.py +0 -48
- clearskies/column_types/select.py +0 -11
- clearskies/column_types/string.py +0 -24
- clearskies/column_types/timestamp.py +0 -73
- clearskies/column_types/updated.py +0 -26
- clearskies/column_types/updated_micro.py +0 -26
- clearskies/column_types/uuid.py +0 -25
- clearskies/columns.py +0 -123
- clearskies/condition_parser.py +0 -172
- clearskies/contexts/build_context.py +0 -54
- clearskies/contexts/convert_to_application.py +0 -190
- clearskies/contexts/extract_handler.py +0 -37
- clearskies/contexts/test.py +0 -94
- clearskies/decorators/__init__.py +0 -39
- clearskies/decorators/auth0_jwks.py +0 -22
- clearskies/decorators/authorization.py +0 -10
- clearskies/decorators/binding_classes.py +0 -9
- clearskies/decorators/binding_modules.py +0 -9
- clearskies/decorators/bindings.py +0 -9
- clearskies/decorators/create.py +0 -10
- clearskies/decorators/delete.py +0 -10
- clearskies/decorators/docs.py +0 -14
- clearskies/decorators/get.py +0 -10
- clearskies/decorators/jwks.py +0 -26
- clearskies/decorators/merge.py +0 -124
- clearskies/decorators/patch.py +0 -10
- clearskies/decorators/post.py +0 -10
- clearskies/decorators/public.py +0 -11
- clearskies/decorators/response_headers.py +0 -10
- clearskies/decorators/return_raw_response.py +0 -9
- clearskies/decorators/schema.py +0 -10
- clearskies/decorators/secret_bearer.py +0 -24
- clearskies/decorators/security_headers.py +0 -10
- clearskies/di/standard_dependencies.py +0 -151
- clearskies/di/test_module/__init__.py +0 -6
- clearskies/di/test_module/another_module/__init__.py +0 -2
- clearskies/di/test_module/module_class.py +0 -5
- clearskies/handlers/__init__.py +0 -41
- clearskies/handlers/advanced_search.py +0 -271
- clearskies/handlers/base.py +0 -479
- clearskies/handlers/callable.py +0 -191
- clearskies/handlers/create.py +0 -35
- clearskies/handlers/crud_by_method.py +0 -18
- clearskies/handlers/database_connector.py +0 -32
- clearskies/handlers/delete.py +0 -61
- clearskies/handlers/exceptions/__init__.py +0 -5
- clearskies/handlers/exceptions/not_found.py +0 -3
- clearskies/handlers/get.py +0 -156
- clearskies/handlers/health_check.py +0 -59
- clearskies/handlers/input_processing.py +0 -79
- clearskies/handlers/list.py +0 -530
- clearskies/handlers/mygrations.py +0 -82
- clearskies/handlers/request_method_routing.py +0 -47
- clearskies/handlers/restful_api.py +0 -218
- clearskies/handlers/routing.py +0 -62
- clearskies/handlers/schema_helper.py +0 -128
- clearskies/handlers/simple_routing.py +0 -206
- clearskies/handlers/simple_routing_route.py +0 -192
- clearskies/handlers/simple_search.py +0 -136
- clearskies/handlers/update.py +0 -96
- clearskies/handlers/write.py +0 -193
- clearskies/input_requirements/__init__.py +0 -78
- clearskies/input_requirements/after.py +0 -36
- clearskies/input_requirements/before.py +0 -36
- clearskies/input_requirements/in_the_future_at_least.py +0 -19
- clearskies/input_requirements/in_the_future_at_most.py +0 -19
- clearskies/input_requirements/in_the_past_at_least.py +0 -19
- clearskies/input_requirements/in_the_past_at_most.py +0 -19
- clearskies/input_requirements/maximum_length.py +0 -19
- clearskies/input_requirements/maximum_value.py +0 -19
- clearskies/input_requirements/minimum_length.py +0 -22
- clearskies/input_requirements/minimum_value.py +0 -19
- clearskies/input_requirements/requirement.py +0 -25
- clearskies/input_requirements/time_delta.py +0 -38
- clearskies/input_requirements/unique.py +0 -18
- clearskies/mocks/__init__.py +0 -7
- clearskies/mocks/input_output.py +0 -124
- clearskies/mocks/models.py +0 -142
- clearskies/models.py +0 -350
- clearskies/security_headers/base.py +0 -12
- clearskies/tests/simple_api/models/__init__.py +0 -2
- clearskies/tests/simple_api/models/status.py +0 -23
- clearskies/tests/simple_api/models/user.py +0 -21
- clearskies/tests/simple_api/users_api.py +0 -64
- {clear_skies-1.22.10.dist-info → clear_skies-2.0.23.dist-info/licenses}/LICENSE +0 -0
- /clearskies/{contexts/bash.py → autodoc/py.typed} +0 -0
- /clearskies/{handlers/exceptions → exceptions}/authentication.py +0 -0
- /clearskies/{handlers/exceptions → exceptions}/authorization.py +0 -0
- /clearskies/{handlers/exceptions → exceptions}/client_error.py +0 -0
- /clearskies/{secrets/exceptions → exceptions}/not_found.py +0 -0
- /clearskies/{tests/__init__.py → input_outputs/py.typed} +0 -0
- /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
|
clearskies/binding_config.py
DELETED
|
@@ -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
|
-
]
|
clearskies/column_types/audit.py
DELETED
|
@@ -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)
|