From fd55569ab0a087e5518e235c770ae86244257baf Mon Sep 17 00:00:00 2001 From: Akihiro Motoki Date: Mon, 17 Apr 2017 08:09:31 +0000 Subject: [PATCH] Support allowed() in workflows.Step There are cases where we want to display workflow Step conditionally. Change-Id: I71ae3ed270d9472190430ac5b4a34682ce3b3f29 Closes-Bug: #1683262 --- horizon/test/tests/workflows.py | 25 +++++++++++++++++++ horizon/workflows/base.py | 13 +++++++++- ...step-allowed-support-d0a770da1d30efb7.yaml | 7 ++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/workflow-step-allowed-support-d0a770da1d30efb7.yaml diff --git a/horizon/test/tests/workflows.py b/horizon/test/tests/workflows.py index cccf394b4e..fd9350e3bd 100644 --- a/horizon/test/tests/workflows.py +++ b/horizon/test/tests/workflows.py @@ -82,6 +82,14 @@ class AdminAction(workflows.Action): permissions = ("horizon.test",) +class TestDisabledAction(workflows.Action): + disabled_id = forms.CharField(label="Disabled") + + class Meta(object): + name = "Test Action Disabled" + slug = "test_action_disabled" + + class AdminForbiddenAction(workflows.Action): admin_id = forms.CharField(label="Admin forbidden") @@ -121,6 +129,14 @@ class AdminStep(workflows.Step): before = TestStepTwo +class TestDisabledStep(workflows.Step): + action_class = TestDisabledAction + contributes = ("disabled_id",) + + def allowed(self, request): + return False + + class AdminForbiddenStep(workflows.Step): action_class = AdminForbiddenAction @@ -312,6 +328,15 @@ class WorkflowsTests(test.TestCase): '', '']) + def test_has_allowed(self): + TestWorkflow.register(TestDisabledStep) + flow = TestWorkflow(self.request) + # Check TestDisabledStep is not included + # even though TestDisabledStep is registered. + self.assertQuerysetEqual(flow.steps, + ['', + '']) + def test_step_is_hidden_on_policy(self): self.policy_patcher.stop() diff --git a/horizon/workflows/base.py b/horizon/workflows/base.py index 508bf7bd6f..9546a4feac 100644 --- a/horizon/workflows/base.py +++ b/horizon/workflows/base.py @@ -465,6 +465,16 @@ class Step(object): """Returns True if action contains any required fields.""" return any(field.required for field in self.action.fields.values()) + def allowed(self, request): + """Determines whether or not the step is displayed. + + Step instances can override this method to specify conditions under + which this tab should not be shown at all by returning ``False``. + + The default behavior is to return ``True`` for all cases. + """ + return True + class WorkflowMetaclass(type): def __new__(mcs, name, bases, attrs): @@ -694,7 +704,8 @@ class Workflow(html.HTMLElement): for step_class in ordered_step_classes: cls = self._registry[step_class] if (has_permissions(self.request.user, cls) and - policy.check(cls.policy_rules, self.request)): + policy.check(cls.policy_rules, self.request) and + cls.allowed(self.request)): self._ordered_steps.append(cls) def _order_steps(self): diff --git a/releasenotes/notes/workflow-step-allowed-support-d0a770da1d30efb7.yaml b/releasenotes/notes/workflow-step-allowed-support-d0a770da1d30efb7.yaml new file mode 100644 index 0000000000..3b00ab75c4 --- /dev/null +++ b/releasenotes/notes/workflow-step-allowed-support-d0a770da1d30efb7.yaml @@ -0,0 +1,7 @@ +--- +features: + - Horizon workflow Step now support allowed() method to determine + the step should be displayed conditionally. + The workflow Step class already support policy check and permission + mechanism to decide the step should be displayed, but allowed() is used + to support more complex or dynamic condition.