diff --git a/webthing/property.py b/webthing/property.py index ef7c049..b4f7a37 100644 --- a/webthing/property.py +++ b/webthing/property.py @@ -53,12 +53,20 @@ def as_property_description(self): """ description = deepcopy(self.metadata) - if 'links' not in description: - description['links'] = [] + if 'forms' not in description: + description['forms'] = [] - description['links'].append( + # TODO: The assumption is that all properties are at least readable - but that's probably not true + op = ['readproperty'] + if not self.metadata.get('readOnly'): + op.append('writeproperty') + + if self.metadata.get('observable'): + op.extend(('observeproperty', 'unobserveproperty')) + + description['forms'].append( { - 'rel': 'property', + 'op': op, 'href': self.href_prefix + self.href, } ) diff --git a/webthing/server.py b/webthing/server.py index 9e7edae..d79662c 100644 --- a/webthing/server.py +++ b/webthing/server.py @@ -151,7 +151,7 @@ def get(self): for thing in self.things.get_things(): description = thing.as_thing_description() description['href'] = thing.get_href() - description['links'].append({ + description['forms'].append({ 'rel': 'alternate', 'href': '{}{}'.format(ws_href, thing.get_href()), }) @@ -243,7 +243,7 @@ def get(self, thing_id='0'): ) description = self.thing.as_thing_description() - description['links'].append({ + description['forms'].append({ 'rel': 'alternate', 'href': '{}{}'.format(ws_href, self.thing.get_href()), }) @@ -437,9 +437,7 @@ def get(self, thing_id='0', property_name=None): if thing.has_property(property_name): self.set_header('Content-Type', 'application/json') - self.write(json.dumps({ - property_name: thing.get_property(property_name), - })) + self.write(json.dumps(thing.get_property(property_name))) else: self.set_status(404) @@ -456,32 +454,26 @@ def put(self, thing_id='0', property_name=None): return try: - args = json.loads(self.request.body.decode()) + value = json.loads(self.request.body.decode()) except ValueError: self.set_status(400) return - if property_name not in args: - self.set_status(400) - return - if thing.has_property(property_name): try: - thing.set_property(property_name, args[property_name]) + thing.set_property(property_name, value) except PropertyError: self.set_status(400) return self.set_header('Content-Type', 'application/json') - self.write(json.dumps({ - property_name: thing.get_property(property_name), - })) + self.write(json.dumps(thing.get_property(property_name))) else: self.set_status(404) class ActionsHandler(BaseHandler): - """Handle a request to /actions.""" + """Handle a request to /actions.""" # TODO: Should this feature be removed? def get(self, thing_id='0'): """ @@ -572,24 +564,14 @@ def post(self, thing_id='0', action_name=None): return try: - message = json.loads(self.request.body.decode()) + input_ = json.loads(self.request.body.decode()) except ValueError: self.set_status(400) return - keys = list(message.keys()) - if len(keys) != 1: - self.set_status(400) - return - - if keys[0] != action_name: - self.set_status(400) - return - - action_params = message[action_name] - input_ = None - if 'input' in action_params: - input_ = action_params['input'] + # Allow payloads wrapped inside `value` field + if 'value' in input_: + input_ = input_['value'] action = thing.perform_action(action_name, input_) if action: @@ -608,7 +590,7 @@ def post(self, thing_id='0', action_name=None): class ActionIDHandler(BaseHandler): - """Handle a request to /actions//.""" + """Handle a request to /actions//.""" # TODO: Should this feature be removed? def get(self, thing_id='0', action_name=None, action_id=None): """ diff --git a/webthing/thing.py b/webthing/thing.py index d87f922..9c4a777 100644 --- a/webthing/thing.py +++ b/webthing/thing.py @@ -46,7 +46,7 @@ def as_thing_description(self): 'properties': self.get_property_descriptions(), 'actions': {}, 'events': {}, - 'links': [ + 'forms': [ { 'rel': 'properties', 'href': '{}/properties'.format(self.href_prefix), @@ -64,26 +64,26 @@ def as_thing_description(self): for name, action in self.available_actions.items(): thing['actions'][name] = action['metadata'] - thing['actions'][name]['links'] = [ + thing['actions'][name]['forms'] = [ { - 'rel': 'action', + 'op': ['invokeaction'], 'href': '{}/actions/{}'.format(self.href_prefix, name), }, ] for name, event in self.available_events.items(): thing['events'][name] = event['metadata'] - thing['events'][name]['links'] = [ + thing['events'][name]['forms'] = [ { - 'rel': 'event', + 'op': ['subscribeevent', 'unsubscribeevent'], 'href': '{}/events/{}'.format(self.href_prefix, name), }, ] if self.ui_href is not None: - thing['links'].append({ + thing['forms'].append({ 'rel': 'alternate', - 'mediaType': 'text/html', + 'type': 'text/html', 'href': self.ui_href, })