From 3d5d265dc3b29417fb9e8b359f12aee884fb2e67 Mon Sep 17 00:00:00 2001 From: Ricardo Dias Date: Wed, 11 Apr 2018 12:43:22 +0100 Subject: [PATCH] mgr/dashboard: restcontroller: support for detail methods Signed-off-by: Ricardo Dias --- .../mgr/dashboard/controllers/__init__.py | 39 +++++++++++++++++++ .../mgr/dashboard/tests/test_rest_tasks.py | 20 ++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/pybind/mgr/dashboard/controllers/__init__.py b/src/pybind/mgr/dashboard/controllers/__init__.py index 7c36866c246..2cecd02a26f 100644 --- a/src/pybind/mgr/dashboard/controllers/__init__.py +++ b/src/pybind/mgr/dashboard/controllers/__init__.py @@ -428,6 +428,7 @@ class RESTController(BaseController): @classmethod def endpoints(cls): + # pylint: disable=too-many-branches def isfunction(m): return inspect.isfunction(m) or inspect.ismethod(m) @@ -454,6 +455,18 @@ class RESTController(BaseController): if methods: result.append((methods, None, '_element', args)) + for attr, val in inspect.getmembers(cls, predicate=isfunction): + if hasattr(val, '_collection_method_'): + result.append( + (val._collection_method_, attr, '_handle_detail_method', [])) + + for attr, val in inspect.getmembers(cls, predicate=isfunction): + if hasattr(val, '_resource_method_'): + res_params = [":{}".format(arg) for arg in args] + url_suffix = "{}/{}".format("/".join(res_params), attr) + result.append( + (val._resource_method_, url_suffix, '_handle_detail_method', [])) + return result @cherrypy.expose @@ -464,6 +477,18 @@ class RESTController(BaseController): def _element(self, *vpath, **params): return self._rest_request(True, *vpath, **params) + def _handle_detail_method(self, *vpath, **params): + method = getattr(self, cherrypy.request.path_info.split('/')[-1]) + + if cherrypy.request.method not in ['GET', 'DELETE']: + method = RESTController._takes_json(method) + + method = RESTController._returns_json(method) + + cherrypy.response.status = 200 + + return method(*vpath, **params) + def _rest_request(self, is_element, *vpath, **params): method_name, status_code = self._method_mapping[ (cherrypy.request.method, is_element)] @@ -526,3 +551,17 @@ class RESTController(BaseController): ret = func(*args, **kwargs) return json.dumps(ret).encode('utf8') return inner + + @staticmethod + def resource(methods=None): + def _wrapper(func): + func._resource_method_ = methods + return func + return _wrapper + + @staticmethod + def collection(methods=None): + def _wrapper(func): + func._collection_method_ = methods + return func + return _wrapper diff --git a/src/pybind/mgr/dashboard/tests/test_rest_tasks.py b/src/pybind/mgr/dashboard/tests/test_rest_tasks.py index 1811902c530..6f8f500f016 100644 --- a/src/pybind/mgr/dashboard/tests/test_rest_tasks.py +++ b/src/pybind/mgr/dashboard/tests/test_rest_tasks.py @@ -31,6 +31,18 @@ class TaskTest(RESTController): # pylint: disable=unused-argument time.sleep(TaskTest.sleep_time) + @Task('task/foo', ['{param}']) + @RESTController.collection(['POST']) + @RESTController.args_from_json + def foo(self, param): + return {'my_param': param} + + @Task('task/bar', ['{key}', '{param}']) + @RESTController.resource(['PUT']) + @RESTController.args_from_json + def bar(self, key, param=None): + return {'my_param': param, 'key': key} + class TaskControllerTest(ControllerTestCase): @classmethod @@ -59,3 +71,11 @@ class TaskControllerTest(ControllerTestCase): def test_delete_task(self): self._task_delete('/test/task/hello') + + def test_foo_task(self): + self._task_post('/test/task/foo', {'param': 'hello'}) + self.assertJsonBody({'my_param': 'hello'}) + + def test_bar_task(self): + self._task_put('/test/task/3/bar', {'param': 'hello'}) + self.assertJsonBody({'my_param': 'hello', 'key': '3'}) -- 2.39.5