From c2c6cc1e12fb56752520998030f220819af2ace4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20M=C3=B6ller?= Date: Wed, 20 Mar 2024 17:31:55 +0100 Subject: [PATCH 1/4] adapter.http: update AAS submodel refs path --- basyx/aas/adapter/http.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basyx/aas/adapter/http.py b/basyx/aas/adapter/http.py index 7095d13a2..20c54f651 100644 --- a/basyx/aas/adapter/http.py +++ b/basyx/aas/adapter/http.py @@ -419,7 +419,7 @@ def __init__(self, object_store: model.AbstractObjectStore): Rule("/", methods=["DELETE"], endpoint=self.delete_aas), Rule("/asset-information", methods=["GET"], endpoint=self.get_aas_asset_information), Rule("/asset-information", methods=["PUT"], endpoint=self.put_aas_asset_information), - Submount("/submodels", [ + Submount("/submodel-refs", [ Rule("/", methods=["GET"], endpoint=self.get_aas_submodel_refs), Rule("/", methods=["POST"], endpoint=self.post_aas_submodel_refs), Rule("//", methods=["DELETE"], From 30e739d688a0f147ed575626335a4b7ba77c9ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20M=C3=B6ller?= Date: Wed, 20 Mar 2024 17:33:39 +0100 Subject: [PATCH 2/4] adapter.http: update AAS submodel refs `DELETE` route The route now uses the submodel identifier instead of the submodel reference. --- basyx/aas/adapter/http.py | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/basyx/aas/adapter/http.py b/basyx/aas/adapter/http.py index 20c54f651..fd66c3935 100644 --- a/basyx/aas/adapter/http.py +++ b/basyx/aas/adapter/http.py @@ -356,28 +356,6 @@ def request_body(cls, request: Request, expect_type: Type[T], stripped: bool) -> return cls.xml(request.get_data(), expect_type, stripped) -class Base64UrlJsonConverter(werkzeug.routing.UnicodeConverter): - - def __init__(self, url_map, t: str): - super().__init__(url_map) - self.type: type - if t == "ModelReference": - self.type = model.ModelReference - else: - raise ValueError(f"invalid value t={t}") - - def to_url(self, value: object) -> str: - return super().to_url(base64url_encode(json.dumps(value, cls=AASToJsonEncoder))) - - def to_python(self, value: str) -> object: - value = super().to_python(value) - decoded = base64url_decode(super().to_python(value)) - try: - return HTTPApiDecoder.json(decoded, self.type, False) - except json.JSONDecodeError: - raise BadRequest(f"{decoded} is not a valid json string!") - - class IdentifierConverter(werkzeug.routing.UnicodeConverter): def to_url(self, value: model.Identifier) -> str: @@ -422,7 +400,7 @@ def __init__(self, object_store: model.AbstractObjectStore): Submount("/submodel-refs", [ Rule("/", methods=["GET"], endpoint=self.get_aas_submodel_refs), Rule("/", methods=["POST"], endpoint=self.post_aas_submodel_refs), - Rule("//", methods=["DELETE"], + Rule("/", methods=["DELETE"], endpoint=self.delete_aas_submodel_refs_specific) ]) ]) @@ -489,8 +467,7 @@ def __init__(self, object_store: model.AbstractObjectStore): ]) ], converters={ "identifier": IdentifierConverter, - "id_short_path": IdShortPathConverter, - "base64url_json": Base64UrlJsonConverter + "id_short_path": IdShortPathConverter }) # TODO: the parameters can be typed via builtin wsgiref with Python 3.11+ @@ -683,11 +660,11 @@ def delete_aas_submodel_refs_specific(self, request: Request, url_args: Dict, ** aas = self._get_obj_ts(url_args["aas_id"], model.AssetAdministrationShell) aas.update() for sm_ref in aas.submodel: - if sm_ref == url_args["submodel_ref"]: + if sm_ref.get_identifier() == url_args["submodel_id"]: aas.submodel.remove(sm_ref) aas.commit() return response_t() - raise NotFound(f"The AAS {aas!r} doesn't have the reference {url_args['submodel_ref']!r}!") + raise NotFound(f"The AAS {aas!r} doesn't have a submodel reference to {url_args['submodel_id']!r}!") # ------ SUBMODEL REPO ROUTES ------- def get_submodel_all(self, request: Request, url_args: Dict, **_kwargs) -> Response: From 990b7f91b1133fa056be74fb3d635ae147f47abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20M=C3=B6ller?= Date: Wed, 20 Mar 2024 22:00:55 +0100 Subject: [PATCH 3/4] adapter.http: suffix submodel refs deletion route with a slash --- basyx/aas/adapter/http.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basyx/aas/adapter/http.py b/basyx/aas/adapter/http.py index fd66c3935..ca9ea8bf6 100644 --- a/basyx/aas/adapter/http.py +++ b/basyx/aas/adapter/http.py @@ -400,7 +400,7 @@ def __init__(self, object_store: model.AbstractObjectStore): Submount("/submodel-refs", [ Rule("/", methods=["GET"], endpoint=self.get_aas_submodel_refs), Rule("/", methods=["POST"], endpoint=self.post_aas_submodel_refs), - Rule("/", methods=["DELETE"], + Rule("//", methods=["DELETE"], endpoint=self.delete_aas_submodel_refs_specific) ]) ]) From b88db588a2823004d1b8e683adb85f007dcacc24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20M=C3=B6ller?= Date: Wed, 20 Mar 2024 22:02:32 +0100 Subject: [PATCH 4/4] adapter.http: refactor submodel ref access as separate function --- basyx/aas/adapter/http.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/basyx/aas/adapter/http.py b/basyx/aas/adapter/http.py index ca9ea8bf6..2a95ebda3 100644 --- a/basyx/aas/adapter/http.py +++ b/basyx/aas/adapter/http.py @@ -531,6 +531,16 @@ def _namespace_submodel_element_op(cls, namespace: model.UniqueIdShortNamespace, except KeyError as e: raise NotFound(f"Submodel element with id_short {arg} not found in {namespace!r}") from e + @classmethod + def _get_submodel_reference(cls, aas: model.AssetAdministrationShell, submodel_id: model.NameType) \ + -> model.ModelReference[model.Submodel]: + # TODO: this is currently O(n), could be O(1) as aas.submodel, but keys would have to precisely match, as they + # are hashed including their KeyType + for ref in aas.submodel: + if ref.get_identifier() == submodel_id: + return ref + raise NotFound(f"The AAS {aas!r} doesn't have a submodel reference to {submodel_id!r}!") + def _get_submodels(self, request: Request) -> Iterator[model.Submodel]: submodels: Iterator[model.Submodel] = self._get_all_obj_of_type(model.Submodel) id_short = request.args.get("idShort") @@ -659,12 +669,9 @@ def delete_aas_submodel_refs_specific(self, request: Request, url_args: Dict, ** response_t = get_response_type(request) aas = self._get_obj_ts(url_args["aas_id"], model.AssetAdministrationShell) aas.update() - for sm_ref in aas.submodel: - if sm_ref.get_identifier() == url_args["submodel_id"]: - aas.submodel.remove(sm_ref) - aas.commit() - return response_t() - raise NotFound(f"The AAS {aas!r} doesn't have a submodel reference to {url_args['submodel_id']!r}!") + aas.submodel.remove(self._get_submodel_reference(aas, url_args["submodel_id"])) + aas.commit() + return response_t() # ------ SUBMODEL REPO ROUTES ------- def get_submodel_all(self, request: Request, url_args: Dict, **_kwargs) -> Response: