diff --git a/mistral/api/controllers/v2/action.py b/mistral/api/controllers/v2/action.py index d081e9b5..c9f5ef3e 100644 --- a/mistral/api/controllers/v2/action.py +++ b/mistral/api/controllers/v2/action.py @@ -113,8 +113,15 @@ class ActionsController(rest.RestController, hooks.HookController): """ definition = pecan.request.text LOG.info("Update action(s) [definition=%s]" % definition) + scope = pecan.request.GET.get('scope', 'private') - db_acts = actions.update_actions(definition) + if scope not in SCOPE_TYPES.values: + raise exc.InvalidModelException( + "Scope must be one of the following: %s; actual: " + "%s" % (SCOPE_TYPES.values, scope) + ) + + db_acts = actions.update_actions(definition, scope=scope) models_dicts = [db_act.to_dict() for db_act in db_acts] action_list = [Action.from_dict(act) for act in models_dicts] @@ -130,11 +137,18 @@ class ActionsController(rest.RestController, hooks.HookController): of multiple actions. In this case they all will be created. """ definition = pecan.request.text + scope = pecan.request.GET.get('scope', 'private') pecan.response.status = 201 + if scope not in SCOPE_TYPES.values: + raise exc.InvalidModelException( + "Scope must be one of the following: %s; actual: " + "%s" % (SCOPE_TYPES.values, scope) + ) + LOG.info("Create action(s) [definition=%s]" % definition) - db_acts = actions.create_actions(definition) + db_acts = actions.create_actions(definition, scope=scope) models_dicts = [db_act.to_dict() for db_act in db_acts] action_list = [Action.from_dict(act) for act in models_dicts] diff --git a/mistral/api/controllers/v2/workflow.py b/mistral/api/controllers/v2/workflow.py index 25565c08..105ba527 100644 --- a/mistral/api/controllers/v2/workflow.py +++ b/mistral/api/controllers/v2/workflow.py @@ -26,6 +26,7 @@ from mistral.api.controllers.v2 import types from mistral.api.controllers.v2 import validation from mistral.api.hooks import content_type as ct_hook from mistral.db.v2 import api as db_api +from mistral import exceptions as exc from mistral.services import workflows from mistral.utils import rest_utils from mistral.workbook import parser as spec_parser @@ -136,10 +137,16 @@ class WorkflowsController(rest.RestController, hooks.HookController): of multiple workflows. In this case they all will be updated. """ definition = pecan.request.text + scope = pecan.request.GET.get('scope', 'private') + if scope not in SCOPE_TYPES.values: + raise exc.InvalidModelException( + "Scope must be one of the following: %s; actual: " + "%s" % (SCOPE_TYPES.values, scope) + ) LOG.info("Update workflow(s) [definition=%s]" % definition) - db_wfs = workflows.update_workflows(definition) + db_wfs = workflows.update_workflows(definition, scope=scope) models_dicts = [db_wf.to_dict() for db_wf in db_wfs] workflow_list = [Workflow.from_dict(wf) for wf in models_dicts] @@ -155,11 +162,18 @@ class WorkflowsController(rest.RestController, hooks.HookController): of multiple workflows. In this case they all will be created. """ definition = pecan.request.text + scope = pecan.request.GET.get('scope', 'private') pecan.response.status = 201 + if scope not in SCOPE_TYPES.values: + raise exc.InvalidModelException( + "Scope must be one of the following: %s; actual: " + "%s" % (SCOPE_TYPES.values, scope) + ) + LOG.info("Create workflow(s) [definition=%s]" % definition) - db_wfs = workflows.create_workflows(definition) + db_wfs = workflows.create_workflows(definition, scope=scope) models_dicts = [db_wf.to_dict() for db_wf in db_wfs] workflow_list = [Workflow.from_dict(wf) for wf in models_dicts] diff --git a/mistral/tests/unit/api/v2/test_actions.py b/mistral/tests/unit/api/v2/test_actions.py index f93d0ce4..0f8d77bb 100644 --- a/mistral/tests/unit/api/v2/test_actions.py +++ b/mistral/tests/unit/api/v2/test_actions.py @@ -123,6 +123,24 @@ class TestActionsController(base.FunctionalTest): self.assertEqual({"actions": [UPDATED_ACTION]}, resp.json) + @mock.patch.object(db_api, "load_action_definition", MOCK_ACTION) + @mock.patch.object( + db_api, "create_or_update_action_definition") + def test_put_public(self, mock_mtd): + mock_mtd.return_value = UPDATED_ACTION_DB + + resp = self.app.put( + '/v2/actions?scope=public', + UPDATED_ACTION_DEFINITION, + headers={'Content-Type': 'text/plain'} + ) + + self.assertEqual(resp.status_int, 200) + + self.assertEqual({"actions": [UPDATED_ACTION]}, resp.json) + + self.assertEqual("public", mock_mtd.call_args[0][1]['scope']) + @mock.patch.object( db_api, "create_or_update_action_definition", MOCK_NOT_FOUND ) @@ -173,6 +191,35 @@ class TestActionsController(base.FunctionalTest): self.assertIsNotNone(spec) self.assertEqual(ACTION_DB.name, spec['name']) + @mock.patch.object(db_api, "create_action_definition") + def test_post_public(self, mock_mtd): + mock_mtd.return_value = ACTION_DB + + resp = self.app.post( + '/v2/actions?scope=public', + ACTION_DEFINITION, + headers={'Content-Type': 'text/plain'} + ) + + self.assertEqual(resp.status_int, 201) + self.assertEqual({"actions": [ACTION]}, resp.json) + + self.assertEqual("public", mock_mtd.call_args[0][0]['scope']) + + @mock.patch.object(db_api, "create_action_definition") + def test_post_wrong_scope(self, mock_mtd): + mock_mtd.return_value = ACTION_DB + + resp = self.app.post( + '/v2/actions?scope=unique', + ACTION_DEFINITION, + headers={'Content-Type': 'text/plain'}, + expect_errors=True + ) + + self.assertEqual(resp.status_int, 400) + self.assertIn("Scope must be one of the following", resp.text) + @mock.patch.object(db_api, "create_action_definition", MOCK_DUPLICATE) def test_post_dup(self): resp = self.app.post( diff --git a/mistral/tests/unit/api/v2/test_workflows.py b/mistral/tests/unit/api/v2/test_workflows.py index 66fdd7fe..5afa3eb9 100644 --- a/mistral/tests/unit/api/v2/test_workflows.py +++ b/mistral/tests/unit/api/v2/test_workflows.py @@ -184,6 +184,21 @@ class TestWorkflowsController(base.FunctionalTest): self.assertEqual(resp.status_int, 200) self.assertDictEqual({'workflows': [UPDATED_WF]}, resp.json) + @mock.patch.object(db_api, "update_workflow_definition") + def test_put_public(self, mock_update): + mock_update.return_value = UPDATED_WF_DB + + resp = self.app.put( + '/v2/workflows?scope=public', + UPDATED_WF_DEFINITION, + headers={'Content-Type': 'text/plain'} + ) + + self.assertEqual(resp.status_int, 200) + self.assertDictEqual({'workflows': [UPDATED_WF]}, resp.json) + + self.assertEqual("public", mock_update.call_args[0][1]['scope']) + @mock.patch.object( db_api, "update_workflow_definition", MOCK_WF_WITH_INPUT ) @@ -243,6 +258,35 @@ class TestWorkflowsController(base.FunctionalTest): self.assertIsNotNone(spec) self.assertEqual(WF_DB.name, spec['name']) + @mock.patch.object(db_api, "create_workflow_definition") + def test_post_public(self, mock_mtd): + mock_mtd.return_value = WF_DB + + resp = self.app.post( + '/v2/workflows?scope=public', + WF_DEFINITION, + headers={'Content-Type': 'text/plain'} + ) + + self.assertEqual(resp.status_int, 201) + self.assertEqual({"workflows": [WF]}, resp.json) + + self.assertEqual("public", mock_mtd.call_args[0][0]['scope']) + + @mock.patch.object(db_api, "create_action_definition") + def test_post_wrong_scope(self, mock_mtd): + mock_mtd.return_value = WF_DB + + resp = self.app.post( + '/v2/workflows?scope=unique', + WF_DEFINITION, + headers={'Content-Type': 'text/plain'}, + expect_errors=True + ) + + self.assertEqual(resp.status_int, 400) + self.assertIn("Scope must be one of the following", resp.text) + @mock.patch.object(db_api, "create_workflow_definition", MOCK_DUPLICATE) def test_post_dup(self): resp = self.app.post(