elody 0.0.204__py3-none-any.whl → 0.0.206__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.
elody/csv.py CHANGED
@@ -274,6 +274,13 @@ class CSVMultiObject(CSVParser):
274
274
  for key, value in row.items():
275
275
  if not value:
276
276
  continue
277
+ if not key or isinstance(value, list):
278
+ if len(value) == 1 and value[0] == "":
279
+ continue
280
+ if "invalid_value" not in self.get_errors():
281
+ self.set_error("invalid_value", list())
282
+ message = f'{get_error_code(ErrorCode.INVALID_VALUE, get_write())} | value:{value} | line_number:{row_number} - The value "{value}" is invalid, most likely caused by exceeding allowed columns.'
283
+ self.get_errors()["invalid_value"].append(message)
277
284
  original_value = value
278
285
  if key != identifying_column:
279
286
  value = value.lower()
elody/error_codes.py CHANGED
@@ -75,6 +75,7 @@ class ErrorCode(Enum):
75
75
  INVALID_ACCEPT_HEADER = ("5015", [])
76
76
  INVALID_VALUE = ("5016", ["value", "options", "line_number"])
77
77
  ITEM_WITH_VALUE_FOR_KEY_NOT_FOUND = ("5017", ["key", "value", "line_number"])
78
+ ITEM_WITH_VALUE_FOR_KEY_NOT_UNIQUE = ("5018", ["key", "value", "line_number"])
78
79
 
79
80
  # Filter error codes
80
81
  NO_MATCHER_FOR_FILTER_REQUEST = ("6001", [])
@@ -14,6 +14,7 @@ from inuits_policy_based_auth.contexts.policy_context import ( # pyright: ignor
14
14
  from inuits_policy_based_auth.contexts.user_context import ( # pyright: ignore
15
15
  UserContext,
16
16
  )
17
+ from werkzeug.exceptions import BadRequest
17
18
 
18
19
 
19
20
  class FilterGenericObjectsPolicyV2(BaseAuthorizationPolicy):
@@ -27,11 +28,8 @@ class FilterGenericObjectsPolicyV2(BaseAuthorizationPolicy):
27
28
  if not isinstance(user_context.access_restrictions.filters, list):
28
29
  user_context.access_restrictions.filters = []
29
30
  type_filter, filters = self.__split_type_filter(
30
- user_context, deepcopy(g.get("content") or request.json or [])
31
+ deepcopy(g.get("content") or request.json or [])
31
32
  )
32
- if not type_filter:
33
- policy_context.access_verdict = True
34
- return policy_context
35
33
 
36
34
  policy_context.access_verdict = False
37
35
  for role in user_context.x_tenant.roles:
@@ -59,13 +57,15 @@ class FilterGenericObjectsPolicyV2(BaseAuthorizationPolicy):
59
57
 
60
58
  return policy_context
61
59
 
62
- def __split_type_filter(self, user_context: UserContext, request_body: list):
60
+ def __split_type_filter(self, request_body: list):
63
61
  type_filter = None
64
62
  for filter in request_body:
65
63
  if filter["type"] == "type":
66
64
  type_filter = filter
65
+ break
67
66
  elif filter["type"] == "selection" and filter["key"] == "type":
68
67
  type_filter = filter
68
+ break
69
69
  elif item_types := filter.get("item_types"):
70
70
  type_filter = {
71
71
  "type": "selection",
@@ -73,22 +73,12 @@ class FilterGenericObjectsPolicyV2(BaseAuthorizationPolicy):
73
73
  "value": item_types,
74
74
  "match_exact": True,
75
75
  }
76
+ break
76
77
 
77
78
  if not type_filter:
78
- if tenant_relation_type := user_context.bag.get("tenant_relation_type"):
79
- user_context.access_restrictions.filters.append( # pyright: ignore
80
- {
81
- "type": "selection",
82
- "key": tenant_relation_type,
83
- "value": [
84
- user_context.bag.get(
85
- "tenant_defining_entity_id", user_context.x_tenant.id
86
- )
87
- ],
88
- "match_exact": True,
89
- }
90
- )
91
- return None, request_body
79
+ raise BadRequest(
80
+ "Filter with type 'type', or a filter with type 'selection' and 'key' equal to 'type' is required"
81
+ )
92
82
 
93
83
  try:
94
84
  request_body.remove(type_filter)
@@ -18,6 +18,7 @@ from inuits_policy_based_auth.contexts.policy_context import ( # pyright: ignor
18
18
  from inuits_policy_based_auth.contexts.user_context import ( # pyright: ignore
19
19
  UserContext,
20
20
  )
21
+ from werkzeug.exceptions import BadRequest
21
22
 
22
23
 
23
24
  class GenericObjectRequestPolicyV2(BaseAuthorizationPolicy):
@@ -113,28 +114,13 @@ class GetRequestRules:
113
114
  )
114
115
  filters.insert(0, {"type": "type", "value": type_query_parameter})
115
116
  else:
116
- filters.append(
117
- {
118
- "type": "selection",
119
- "key": "type",
120
- "value": allowed_item_types,
121
- "match_exact": True,
122
- }
123
- )
124
- if tenant_relation_type := user_context.bag.get("tenant_relation_type"):
125
- filters.append(
126
- {
127
- "type": "selection",
128
- "key": tenant_relation_type,
129
- "value": [
130
- "tenant:super",
131
- user_context.bag.get(
132
- "tenant_defining_entity_id", user_context.x_tenant.id
133
- ),
134
- ],
135
- "match_exact": True,
136
- }
137
- )
117
+ """
118
+ Allowing no type_query_parameter will expose following security risks:
119
+ - object_restrictions not being applied
120
+ - inability to determine collection to execute filters
121
+ => if no type_query_parameter is a business requirement, override this policy for that specific client and consider the security risks
122
+ """
123
+ raise BadRequest("Query parameter 'type' is required")
138
124
 
139
125
  user_context.access_restrictions.filters = filters
140
126
  user_context.access_restrictions.post_request_hook = (
@@ -59,7 +59,7 @@ def handle_single_item_request(
59
59
  key_to_check=None,
60
60
  ):
61
61
  try:
62
- item_in_storage_format, flat_item, object_lists, restrictions_schema = (
62
+ item, flat_item, object_lists, restrictions_schema = (
63
63
  __prepare_item_for_permission_check(item, permissions, crud)
64
64
  )
65
65
 
@@ -73,7 +73,7 @@ def handle_single_item_request(
73
73
 
74
74
  return __is_allowed_to_crud_item_keys(
75
75
  user_context,
76
- item_in_storage_format,
76
+ item,
77
77
  flat_item,
78
78
  restrictions_schema,
79
79
  crud,
@@ -84,7 +84,7 @@ def handle_single_item_request(
84
84
  except Exception as exception:
85
85
  log.debug(
86
86
  f"{exception.__class__.__name__}: {str(exception)}",
87
- item.get("storage_format", item),
87
+ item,
88
88
  )
89
89
  if crud != "read":
90
90
  log.debug(f"Request body: {request_body}", {})
@@ -97,7 +97,7 @@ def mask_protected_content_post_request_hook(user_context: UserContext, permissi
97
97
  for item in response["results"]:
98
98
  try:
99
99
  (
100
- item_in_storage_format,
100
+ item,
101
101
  flat_item,
102
102
  object_lists,
103
103
  restrictions_schema,
@@ -107,7 +107,7 @@ def mask_protected_content_post_request_hook(user_context: UserContext, permissi
107
107
 
108
108
  __is_allowed_to_crud_item_keys(
109
109
  user_context,
110
- item_in_storage_format,
110
+ item,
111
111
  flat_item,
112
112
  restrictions_schema,
113
113
  "read",
@@ -117,7 +117,7 @@ def mask_protected_content_post_request_hook(user_context: UserContext, permissi
117
117
  except Exception as exception:
118
118
  log.debug(
119
119
  f"{exception.__class__.__name__}: {str(exception)}",
120
- item.get("storage_format", item),
120
+ item,
121
121
  )
122
122
  raise exception
123
123
 
@@ -128,7 +128,6 @@ def mask_protected_content_post_request_hook(user_context: UserContext, permissi
128
128
 
129
129
 
130
130
  def __prepare_item_for_permission_check(item, permissions, crud):
131
- item = deepcopy(item.get("storage_format", item))
132
131
  if item.get("type", "") not in permissions[crud].keys():
133
132
  return item, None, None, None
134
133
 
@@ -175,7 +174,7 @@ def __is_allowed_to_crud_item(
175
174
 
176
175
  def __is_allowed_to_crud_item_keys(
177
176
  user_context: UserContext,
178
- item_in_storage_format,
177
+ item,
179
178
  flat_item,
180
179
  restrictions_schema,
181
180
  crud,
@@ -207,19 +206,17 @@ def __is_allowed_to_crud_item_keys(
207
206
  for info in keys_info:
208
207
  if info["object_list"]:
209
208
  element = __get_element_from_object_list_of_item(
210
- item_in_storage_format,
209
+ item,
211
210
  info["key"],
212
211
  info["object_key"],
213
212
  object_lists,
214
213
  )
215
214
  if element:
216
- item_in_storage_format[info["key"]].remove(element)
215
+ item[info["key"]].remove(element)
217
216
  break
218
217
  else:
219
218
  try:
220
- del item_in_storage_format[keys_info[0]["key"]][
221
- keys_info[1]["key"]
222
- ]
219
+ del item[keys_info[0]["key"]][keys_info[1]["key"]]
223
220
  except KeyError:
224
221
  pass
225
222
  if key_to_check and key_to_check == restricted_key:
@@ -228,7 +225,7 @@ def __is_allowed_to_crud_item_keys(
228
225
  if flat_request_body.get(restricted_key):
229
226
  user_context.bag["restricted_keys"].append(restricted_key)
230
227
 
231
- user_context.bag["requested_item"] = item_in_storage_format
228
+ user_context.bag["requested_item"] = item
232
229
  return len(user_context.bag["restricted_keys"]) == 0
233
230
 
234
231
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elody
3
- Version: 0.0.204
3
+ Version: 0.0.206
4
4
  Summary: elody SDK for Python
5
5
  Author-email: Inuits <developers@inuits.eu>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -1,8 +1,8 @@
1
1
  __init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  elody/__init__.py,sha256=d0Q6Fn44e7wFfLabDOBxpcJ1DPKWlFunGYDUBmO-4hA,22
3
3
  elody/client.py,sha256=15SBfnLHJXXY5Vf5BnkWdjtvkH21E_AsWTzm2-zcbf0,8799
4
- elody/csv.py,sha256=4J1KZhcisxvh0mryMPcza-sIPS7nbDkRyRO8guSFVGw,16172
5
- elody/error_codes.py,sha256=Derbr10Lb3HZcePjargz_XsYnw2SC0edD5KHZeKlp1s,4227
4
+ elody/csv.py,sha256=f8HphE-KC2OqKFzV0HiifWBgMHb3g0EA_Y82o_6JEiE,16761
5
+ elody/error_codes.py,sha256=d3wNPZU0HFMyl8xN95ciNd6QD94al1tX18h6HiqiAHo,4310
6
6
  elody/exceptions.py,sha256=5KSw2sPCZz3lDIJX4LiR2iL9n4m4KIil04D1d3X5rd0,968
7
7
  elody/job.py,sha256=3_heLwfNrWYcjIMKPG-vWsQayAAI7tyLFUUC_b1rT7w,4264
8
8
  elody/loader.py,sha256=yNakab07ja478gZaIC277n8Wf8SJ7_P3q-Z39BDdWQc,5419
@@ -17,30 +17,30 @@ elody/object_configurations/elody_configuration.py,sha256=cqduTVmdaDk3pIeHcW_Sfs
17
17
  elody/object_configurations/job_configuration.py,sha256=HMDxaRUyfqhIy0q3yQDDMH9uW5iCd7VCmqknQofXNt0,2039
18
18
  elody/policies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  elody/policies/helpers.py,sha256=LTV_Hmg8AN64e6t4glpKhZMsRNYCLN8FC-KQ0-7EmR8,2035
20
- elody/policies/permission_handler.py,sha256=dWNGzcfGoJrJjMS80-7egXzHFNaLr0UBrzXB6jwyktg,10559
20
+ elody/policies/permission_handler.py,sha256=ovQ1id67GtiEZYl3_2f_QPDn7XkCMGae6xgnpMWNHs8,10233
21
21
  elody/policies/authentication/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  elody/policies/authentication/base_user_tenant_validation_policy.py,sha256=yyGiYy-MM63itQYwUc99FPeXt6TBW5B95FeLMfjMEok,5368
23
23
  elody/policies/authentication/multi_tenant_policy.py,sha256=g4ZYUQMmCjgLg09wj0-0lGKsJsRt7h4ppI25o1VdZHw,4039
24
24
  elody/policies/authorization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  elody/policies/authorization/filter_generic_objects_policy.py,sha256=mF32moh8hRetBgG8vQW-rz4xjoRQD2yOxdI740SFSUo,6522
26
- elody/policies/authorization/filter_generic_objects_policy_v2.py,sha256=LWeLQO_arUgIahvvcSkzkHC8jiIk6_TMSbkjCXBQdqk,6936
26
+ elody/policies/authorization/filter_generic_objects_policy_v2.py,sha256=2IkESYMfne1bX1I8Yvn3yoNmlfn_Jm6zVlVBknoW1_c,6412
27
27
  elody/policies/authorization/generic_object_detail_policy.py,sha256=y6g1i3vdKMKY4xS4H2m0e1DRztrivMEomx6NkDqA0Pk,3672
28
28
  elody/policies/authorization/generic_object_mediafiles_policy.py,sha256=1-DMsV-FDkcrQCE4KL-SGlVHjTZSMPwYq1bWln2nXE4,2887
29
29
  elody/policies/authorization/generic_object_metadata_policy.py,sha256=xwtOVYmiCKgf75CydfWnV7DLI9X1yVfXPQ4-Ux0Htqk,2787
30
30
  elody/policies/authorization/generic_object_relations_policy.py,sha256=hRLeA5gXB44ufiVVaxWtAuwnXBRY1U4bLWgIadzKtmw,3712
31
31
  elody/policies/authorization/generic_object_request_policy.py,sha256=kuLczjnK5omMF2Gw5ViY_Z9MNPx_w6bNwexiMzvLiUU,4867
32
- elody/policies/authorization/generic_object_request_policy_v2.py,sha256=bD7X9zFt0AysbyVljOcvbdmbJNRQsMZRGfqs3jjHuxY,5434
32
+ elody/policies/authorization/generic_object_request_policy_v2.py,sha256=gWv8c4XJeRNhzsGO2pYA25q8cRdsi-4xQbJ9Ja_9_QI,5094
33
33
  elody/policies/authorization/mediafile_derivatives_policy.py,sha256=OwNpbS8i7-LzcQDPddMWTrXk_Y4wqZxrB12Lw1dhkr0,2671
34
34
  elody/policies/authorization/mediafile_download_policy.py,sha256=XMsKavBucmTh4W1kWOzpFWxJ_ZXgHVK1RS7JB4HjtQo,1979
35
35
  elody/policies/authorization/multi_tenant_policy.py,sha256=SA9H7SBjzuh8mY3gYN7pDG8TV7hdI3GEUtNeiZeNL3M,3164
36
36
  elody/policies/authorization/tenant_request_policy.py,sha256=dEgblwRAqwWVcE-O7Jn8hVL3OnwDlQhDEOcPlcElBrk,1185
37
- elody-0.0.204.dist-info/licenses/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
37
+ elody-0.0.206.dist-info/licenses/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
38
38
  tests/__init_.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  tests/data.py,sha256=Q3oxduf-E3m-Z5G_p3fcs8jVy6g10I7zXKL1m94UVMI,2906
40
40
  tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  tests/unit/test_csv.py,sha256=NQaOhehfQ4GuXku0Y1SA8DYjJeqqidbF50zEHAi8RZA,15923
42
42
  tests/unit/test_utils.py,sha256=g63szcEZyHhCOtrW4BnNbcgVca3oYPIOLjBdIzNwwN0,8784
43
- elody-0.0.204.dist-info/METADATA,sha256=qfe2j7dXAcarRS5vaiQOiVJy3-x2qnXuzrcDizmnSZQ,23358
44
- elody-0.0.204.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
45
- elody-0.0.204.dist-info/top_level.txt,sha256=E0mImupLj0KmtUUCXRYEoLDRaSkuiGaOIIseAa0oQ-M,21
46
- elody-0.0.204.dist-info/RECORD,,
43
+ elody-0.0.206.dist-info/METADATA,sha256=6PT9-B_W0ZT1iCmmohkbnhaYIkswEsvNvTrMIMP1Nzw,23358
44
+ elody-0.0.206.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
45
+ elody-0.0.206.dist-info/top_level.txt,sha256=E0mImupLj0KmtUUCXRYEoLDRaSkuiGaOIIseAa0oQ-M,21
46
+ elody-0.0.206.dist-info/RECORD,,