Skip to content

Commit 7336e95

Browse files
committed
Added extension options to handle view & edit transitions permissions
1 parent 5add649 commit 7336e95

File tree

4 files changed

+62
-11
lines changed

4 files changed

+62
-11
lines changed

src/Admin/Extension/WorkflowExtension.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Sonata\AdminBundle\Admin\AdminInterface;
88
use Sonata\AdminBundle\Route\RouteCollection;
99
use Symfony\Component\OptionsResolver\OptionsResolver;
10+
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
1011
use Symfony\Component\Workflow\Exception\InvalidArgumentException;
1112
use Symfony\Component\Workflow\Registry;
1213
use Symfony\Component\Workflow\Transition;
@@ -81,6 +82,12 @@ public function configureSideMenu(
8182
return;
8283
}
8384

85+
try {
86+
$admin->checkAccess('viewTransitions', $subject);
87+
} catch (AccessDeniedException $exception) {
88+
return;
89+
}
90+
8491
try {
8592
$workflow = $this->getWorkflow($subject, $this->options['workflow_name']);
8693
} catch (InvalidArgumentException $exception) {
@@ -96,6 +103,17 @@ public function configureSideMenu(
96103
}
97104
}
98105

106+
/**
107+
* @inheritdoc
108+
*/
109+
public function getAccessMapping(AdminInterface $admin)
110+
{
111+
return [
112+
'viewTransitions' => $this->options['view_transitions_role'],
113+
'applyTransitions' => $this->options['apply_transitions_role'],
114+
];
115+
}
116+
99117
/**
100118
* @param object $subject
101119
* @param string|null $workflowName
@@ -124,6 +142,8 @@ protected function configureOptions(OptionsResolver $resolver)
124142
'dropdown_transitions_icon' => 'fa fa-code-fork',
125143
'transitions_default_icon' => null,
126144
'transitions_icons' => [],
145+
'view_transitions_role' => 'EDIT',
146+
'apply_transitions_role' => 'EDIT',
127147
])
128148
->setAllowedTypes('render_actions', ['string[]'])
129149
->setAllowedTypes('workflow_name', ['string', 'null'])
@@ -134,6 +154,8 @@ protected function configureOptions(OptionsResolver $resolver)
134154
->setAllowedTypes('dropdown_transitions_icon', ['string', 'null'])
135155
->setAllowedTypes('transitions_default_icon', ['string', 'null'])
136156
->setAllowedTypes('transitions_icons', ['array'])
157+
->setAllowedTypes('view_transitions_role', ['string'])
158+
->setAllowedTypes('apply_transitions_role', ['string'])
137159
;
138160
}
139161

src/Controller/WorkflowControllerTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public function workflowApplyTransitionAction(Request $request)
6464
}
6565

6666
$this->admin->setSubject($existingObject);
67-
$this->admin->checkAccess('edit', $existingObject);
67+
$this->admin->checkAccess('applyTransitions', $existingObject);
6868

6969
$objectId = $this->admin->getNormalizedIdentifier($existingObject);
7070

tests/Admin/Extension/WorkflowExtensionTest.php

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Sonata\AdminBundle\Route\RouteCollection;
1010
use Sonata\AdminBundle\Translator\LabelTranslatorStrategyInterface;
1111
use Symfony\Component\Routing\Route;
12+
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
1213
use Symfony\Component\Workflow\Registry;
1314
use Symfony\Component\Workflow\StateMachine;
1415
use Yokai\SonataWorkflow\Admin\Extension\WorkflowExtension;
@@ -35,7 +36,8 @@ public function testConfigureRoutes()
3536
self::assertSame('/pull-request/{id}/workflow/transition/{transition}/apply', $route->getPath());
3637
self::assertNotEmpty($defaults = $route->getDefaults());
3738
self::assertArrayHasKey('_controller', $defaults);
38-
self::assertSame(WorkflowController::class.'::workflowApplyTransitionAction', $defaults['_controller']);
39+
self::assertStringStartsWith(WorkflowController::class, $defaults['_controller']);
40+
self::assertStringEndsWith('workflowApplyTransitionAction', $defaults['_controller']);
3941
self::assertArrayHasKey('_sonata_admin', $defaults);
4042
self::assertSame('pull_request', $defaults['_sonata_admin']);
4143
}
@@ -68,6 +70,18 @@ public function testAlterNewInstance()
6870
self::assertSame('opened', $pullRequest->getMarking());
6971
}
7072

73+
public function testAccessMapping()
74+
{
75+
/** @var AdminInterface|ObjectProphecy $admin */
76+
$admin = $this->prophesize(AdminInterface::class);
77+
78+
$extension = new WorkflowExtension(new Registry());
79+
self::assertSame(
80+
['viewTransitions' => 'EDIT', 'applyTransitions' => 'EDIT'],
81+
$extension->getAccessMapping($admin->reveal())
82+
);
83+
}
84+
7185
public function testConfigureSideMenuWithoutSubject()
7286
{
7387
/** @var AdminInterface|ObjectProphecy $admin */
@@ -80,11 +94,25 @@ public function testConfigureSideMenuWithoutSubject()
8094
self::assertFalse($menu->hasChildren());
8195
}
8296

97+
public function testConfigureSideMenuWithoutPermission()
98+
{
99+
/** @var AdminInterface|ObjectProphecy $admin */
100+
$admin = $this->prophesize(AdminInterface::class);
101+
$admin->getSubject()->willReturn($pullRequest = new PullRequest());
102+
$admin->checkAccess('viewTransitions', $pullRequest)->willThrow(new AccessDeniedException());
103+
104+
$extension = new WorkflowExtension(new Registry());
105+
$extension->configureSideMenu($admin->reveal(), $menu = new MenuItem('root', new MenuFactory()), 'edit');
106+
107+
self::assertFalse($menu->hasChildren());
108+
}
109+
83110
public function testConfigureSideMenuWithoutWorkflow()
84111
{
85112
/** @var AdminInterface|ObjectProphecy $admin */
86113
$admin = $this->prophesize(AdminInterface::class);
87-
$admin->getSubject()->willReturn(new PullRequest());
114+
$admin->getSubject()->willReturn($pullRequest = new PullRequest());
115+
$admin->checkAccess('viewTransitions', $pullRequest)->shouldBeCalled();
88116

89117
$extension = new WorkflowExtension(new Registry());
90118
$extension->configureSideMenu($admin->reveal(), $menu = new MenuItem('root', new MenuFactory()), 'edit');
@@ -108,6 +136,7 @@ public function testConfigureSideMenu($marking, array $transitions)
108136
$admin->getTranslationDomain()->willReturn('admin');
109137
$admin->getLabelTranslatorStrategy()->willReturn($labelStrategy->reveal());
110138
$admin->getSubject()->willReturn($pullRequest);
139+
$admin->checkAccess('viewTransitions', $pullRequest)->shouldBeCalled();
111140

112141
foreach ($transitions as $transition) {
113142
$labelStrategy->getLabel($transition, 'workflow', 'transition')

tests/Controller/WorkflowControllerTest.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public function testWorkflowApplyTransitionActionWorkflowNotFound()
124124
$this->admin->getObject(42)->shouldBeCalledTimes(1)
125125
->willReturn($subject = new PullRequest());
126126
$this->admin->setSubject($subject)->shouldBeCalledTimes(1);
127-
$this->admin->checkAccess('edit', $subject)->shouldBeCalledTimes(1);
127+
$this->admin->checkAccess('applyTransitions', $subject)->shouldBeCalledTimes(1);
128128
$this->admin->getNormalizedIdentifier($subject)->shouldBeCalledTimes(1)->willReturn(42);
129129

130130
$this->controller()->workflowApplyTransitionAction($this->request);
@@ -144,7 +144,7 @@ public function testWorkflowApplyTransitionActionMissingTransition()
144144
$this->admin->getObject(42)->shouldBeCalledTimes(1)
145145
->willReturn($subject = new PullRequest());
146146
$this->admin->setSubject($subject)->shouldBeCalledTimes(1);
147-
$this->admin->checkAccess('edit', $subject)->shouldBeCalledTimes(1);
147+
$this->admin->checkAccess('applyTransitions', $subject)->shouldBeCalledTimes(1);
148148
$this->admin->getNormalizedIdentifier($subject)->shouldBeCalledTimes(1)->willReturn(42);
149149

150150
$this->controller()->workflowApplyTransitionAction($this->request);
@@ -167,7 +167,7 @@ public function testWorkflowApplyTransitionActionTransitionException()
167167
->willReturn($subject = new PullRequest());
168168
$this->admin->toString($subject)->shouldBeCalledTimes(1)->willReturn('pr42');
169169
$this->admin->setSubject($subject)->shouldBeCalledTimes(1);
170-
$this->admin->checkAccess('edit', $subject)->shouldBeCalledTimes(1);
170+
$this->admin->checkAccess('applyTransitions', $subject)->shouldBeCalledTimes(1);
171171
$this->admin->getNormalizedIdentifier($subject)->shouldBeCalledTimes(1)->willReturn(42);
172172

173173
$this->controller()->workflowApplyTransitionAction($this->request);
@@ -189,7 +189,7 @@ public function testWorkflowApplyTransitionActionModelManagerException()
189189
$this->admin->getObject(42)->shouldBeCalledTimes(1)
190190
->willReturn($subject = new PullRequest());
191191
$this->admin->setSubject($subject)->shouldBeCalledTimes(1);
192-
$this->admin->checkAccess('edit', $subject)->shouldBeCalledTimes(1);
192+
$this->admin->checkAccess('applyTransitions', $subject)->shouldBeCalledTimes(1);
193193
$this->admin->getNormalizedIdentifier($subject)->shouldBeCalledTimes(1)->willReturn(42);
194194
$this->admin->update($subject)->shouldBeCalledTimes(1)->willThrow(new ModelManagerException('phpunit error'));
195195

@@ -213,7 +213,7 @@ public function testWorkflowApplyTransitionActionLockException()
213213
$this->admin->generateObjectUrl('edit', $subject)->shouldBeCalledTimes(1)
214214
->willReturn('/pull-request/42/edit');
215215
$this->admin->setSubject($subject)->shouldBeCalledTimes(1);
216-
$this->admin->checkAccess('edit', $subject)->shouldBeCalledTimes(1);
216+
$this->admin->checkAccess('applyTransitions', $subject)->shouldBeCalledTimes(1);
217217
$this->admin->getNormalizedIdentifier($subject)->shouldBeCalledTimes(1)->willReturn(42);
218218
$this->admin->hasRoute('edit')->shouldBeCalledTimes(1)->willReturn(false);
219219
$this->admin->hasRoute('show')->shouldBeCalledTimes(1)->willReturn(false);
@@ -248,7 +248,7 @@ public function testWorkflowApplyTransitionActionSuccessXmlHttp()
248248
->willReturn($subject = new PullRequest());
249249
$this->admin->toString($subject)->shouldBeCalledTimes(1)->willReturn('pr42');
250250
$this->admin->setSubject($subject)->shouldBeCalledTimes(1);
251-
$this->admin->checkAccess('edit', $subject)->shouldBeCalledTimes(1);
251+
$this->admin->checkAccess('applyTransitions', $subject)->shouldBeCalledTimes(1);
252252
$this->admin->getNormalizedIdentifier($subject)->shouldBeCalledTimes(1)->willReturn(42);
253253
$this->admin->update($subject)->shouldBeCalledTimes(1)->willReturn($subject);
254254

@@ -276,7 +276,7 @@ public function testWorkflowApplyTransitionActionSuccessHttp()
276276
->willReturn($subject = new PullRequest());
277277
$this->admin->toString($subject)->shouldBeCalledTimes(1)->willReturn('pr42');
278278
$this->admin->setSubject($subject)->shouldBeCalledTimes(1);
279-
$this->admin->checkAccess('edit', $subject)->shouldBeCalledTimes(1);
279+
$this->admin->checkAccess('applyTransitions', $subject)->shouldBeCalledTimes(1);
280280
$this->admin->getNormalizedIdentifier($subject)->shouldBeCalledTimes(1)->willReturn(42);
281281
$this->admin->hasRoute('edit')->shouldBeCalledTimes(1)->willReturn(false);
282282
$this->admin->hasRoute('show')->shouldBeCalledTimes(1)->willReturn(false);
@@ -311,7 +311,7 @@ public function testWorkflowApplyTransitionActionPreApply()
311311
$this->admin->getObject(42)->shouldBeCalledTimes(1)
312312
->willReturn($subject = new PullRequest());
313313
$this->admin->setSubject($subject)->shouldBeCalledTimes(1);
314-
$this->admin->checkAccess('edit', $subject)->shouldBeCalledTimes(1);
314+
$this->admin->checkAccess('applyTransitions', $subject)->shouldBeCalledTimes(1);
315315
$this->admin->getNormalizedIdentifier($subject)->shouldBeCalledTimes(1)->willReturn(42);
316316
$this->admin->update($subject)->shouldNotBeCalled();
317317

0 commit comments

Comments
 (0)