From e173b6104fab45c74927cbcc727f495e8f62fbee Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Thu, 18 Jun 2020 16:33:30 +0100 Subject: [PATCH] Restored W3C TD compatibility --- src/labthings/server/spec/td.py | 73 +++++++++++++++++++++++++++++++-- tests/conftest.py | 2 +- tests/test_server_spec_td.py | 1 - 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/labthings/server/spec/td.py b/src/labthings/server/spec/td.py index b9191593..620ce1cc 100644 --- a/src/labthings/server/spec/td.py +++ b/src/labthings/server/spec/td.py @@ -50,6 +50,65 @@ def find_schema_for_view(view: View): return prop_schema +def build_forms_for_view(rules: list, view: View, op: list): + """Build a W3C form description for a particular View + + Args: + rules (list): List of Flask rules + view (View): View class + op (list): List of Form operations + + Returns: + [dict]: Form description + """ + forms = [] + prop_urls = [rule_to_path(rule) for rule in rules] + + content_type = get_topmost_spec_attr(view, "_content_type") or "application/json" + + for url in prop_urls: + forms.append({"op": op, "href": url, "contentType": content_type}) + + return forms + + +def view_to_thing_property_forms(rules: list, view: View): + """Build a W3C form description for a PropertyView + + Args: + rules (list): List of Flask rules + view (View): View class + op (list): List of Form operations + + Returns: + [dict]: Form description + """ + readable = hasattr(view, "post") or hasattr(view, "put") or hasattr(view, "delete") + writeable = hasattr(view, "get") + + op = [] + if readable: + op.append("readproperty") + if writeable: + op.append("writeproperty") + + return build_forms_for_view(rules, view, op=op) + + +def view_to_thing_action_forms(rules: list, view: View): + """Build a W3C form description for an ActionView + + Args: + rules (list): List of Flask rules + view (View): View class + op (list): List of Form operations + + Returns: + [dict]: Form description + """ + return build_forms_for_view(rules, view, op=["invokeaction"]) + + class ThingDescription: def __init__(self, apispec: APISpec): self._apispec = weakref.ref(apispec) @@ -91,7 +150,10 @@ def add_link(self, view, rel, kwargs=None, params=None): def to_dict(self): return { - "@context": ["https://iot.mozilla.org/schemas/"], + "@context": [ + "https://www.w3.org/2019/wot/td/v1", + "https://iot.mozilla.org/schemas/", + ], "@type": current_labthing().types, "id": url_for("root", _external=True), "base": request.host_url, @@ -99,13 +161,15 @@ def to_dict(self): "description": current_labthing().description, "properties": self.properties, "actions": self.actions, - "events": self.events, # TODO: Enable once properly populated + # "events": self.events, # TODO: Enable once properly populated "links": self.links, + "securityDefinitions": {"nosec_sc": {"scheme": "nosec"}}, + "security": "nosec_sc", } def event_to_thing_event(self, event: Event): # TODO: Include event schema - return {} + return {"forms": []} def view_to_thing_property(self, rules: list, view: View): prop_urls = [rule_to_path(rule) for rule in rules] @@ -122,8 +186,8 @@ def view_to_thing_property(self, rules: list, view: View): hasattr(view, "post") or hasattr(view, "put") or hasattr(view, "delete") ), "writeOnly": not hasattr(view, "get"), - # TODO: Make URLs absolute "links": [{"href": f"{url}"} for url in prop_urls], + "forms": view_to_thing_property_forms(rules, view), "uriVariables": {}, **get_semantic_type(view), } @@ -181,6 +245,7 @@ def view_to_thing_action(self, rules: list, view: View): or (get_docstring(view.post) if hasattr(view, "post") else ""), # TODO: Make URLs absolute "links": [{"href": f"{url}"} for url in action_urls], + "forms": view_to_thing_action_forms(rules, view), "safe": is_safe, "idempotent": is_idempotent, } diff --git a/tests/conftest.py b/tests/conftest.py index 3d43f4e4..95c2f496 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,7 +16,7 @@ class Helpers: @staticmethod def validate_thing_description(thing_description, app_ctx, schemas_path): - schema = json.load(open(os.path.join(schemas_path, "td_schema.json"), "r")) + schema = json.load(open(os.path.join(schemas_path, "w3c_td_schema.json"), "r")) jsonschema.Draft7Validator.check_schema(schema) with app_ctx.test_request_context(): diff --git a/tests/test_server_spec_td.py b/tests/test_server_spec_td.py index d263add4..0b4acfcb 100644 --- a/tests/test_server_spec_td.py +++ b/tests/test_server_spec_td.py @@ -46,7 +46,6 @@ class ViewClass: def test_td_init(helpers, thing_description, app_ctx, schemas_path): assert thing_description - helpers.validate_thing_description(thing_description, app_ctx, schemas_path)