Skip to content

Commit 9582c8f

Browse files
committed
feat: implement authorization gateway for article publishing actions
1 parent 745e532 commit 9582c8f

File tree

5 files changed

+73
-31
lines changed

5 files changed

+73
-31
lines changed

contexts/ArticlePublishing/Application/Coordinators/ArticlePublishingCoordinator.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Contexts\ArticlePublishing\Application\DTOs\CreateArticleDTO;
1111
use Contexts\ArticlePublishing\Application\DTOs\GetArticleListDTO;
1212
use Contexts\ArticlePublishing\Application\DTOs\UpdateArticleDTO;
13+
use Contexts\ArticlePublishing\Domain\Gateway\AuthorizationGateway;
1314
use Contexts\ArticlePublishing\Domain\Gateway\CategoryGateway;
1415
use Contexts\ArticlePublishing\Domain\Models\Article;
1516
use Contexts\ArticlePublishing\Domain\Models\ArticleId;
@@ -21,11 +22,14 @@ class ArticlePublishingCoordinator extends BaseCoordinator
2122
{
2223
public function __construct(
2324
private ArticleRepository $repository,
24-
private CategoryGateway $categoryGateway
25+
private CategoryGateway $categoryGateway,
26+
private AuthorizationGateway $authorizationGateway
2527
) {}
2628

2729
public function create(CreateArticleDTO $data): Article
2830
{
31+
$this->authorizationGateway->canPerformAction('publish_article');
32+
2933
$article = match ($data->status) {
3034
'draft' => $this->createDraft($data),
3135
'published' => $this->createPublished($data),
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Contexts\ArticlePublishing\Domain\Gateway;
6+
7+
interface AuthorizationGateway
8+
{
9+
public function canPerformAction(string $action): bool;
10+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Contexts\ArticlePublishing\Infrastructure\Adapters;
6+
7+
use Contexts\ArticlePublishing\Domain\Gateway\AuthorizationGateway;
8+
use Contexts\Authorization\Domain\Services\PolicyFactory;
9+
10+
class AuthorizationAdapter implements AuthorizationGateway
11+
{
12+
public function __construct(
13+
private PolicyFactory $policyFactory
14+
) {}
15+
16+
public function canPerformAction(string $action): bool
17+
{
18+
$policy = $this->policyFactory
19+
->forContext('article_publishing')
20+
->action($action);
21+
22+
return $policy->evaluate();
23+
}
24+
}

contexts/ArticlePublishing/Infrastructure/ServiceProvider.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
namespace Contexts\ArticlePublishing\Infrastructure;
66

77
use Contexts\ArticlePublishing\Domain\Events\ArticlePublishedEvent;
8+
use Contexts\ArticlePublishing\Domain\Gateway\AuthorizationGateway;
89
use Contexts\ArticlePublishing\Domain\Gateway\CategoryGateway;
10+
use Contexts\ArticlePublishing\Infrastructure\Adapters\AuthorizationAdapter;
911
use Contexts\ArticlePublishing\Infrastructure\Adapters\CategoryAdapter;
1012
use Contexts\ArticlePublishing\Infrastructure\EventListeners\ConsoleOutputListener;
1113
use Contexts\CategoryManagement\Application\Coordinators\CategoryManagementCoordinator;
@@ -45,6 +47,8 @@ public function map(): void
4547
$this->app->bind(CategoryGateway::class, function ($app) {
4648
return new CategoryAdapter($app->make(CategoryManagementCoordinator::class));
4749
});
50+
51+
$this->app->bind(AuthorizationGateway::class, AuthorizationAdapter::class);
4852
}
4953

5054
public function provides(): array

contexts/ArticlePublishing/Tests/Feature/ArticlePublishingTest.php

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,25 @@
33
declare(strict_types=1);
44

55
use Contexts\ArticlePublishing\Domain\Events\ArticlePublishedEvent;
6+
use Contexts\ArticlePublishing\Domain\Gateway\AuthorizationGateway;
67
use Contexts\CategoryManagement\Infrastructure\Records\CategoryRecord;
7-
use Illuminate\Database\Eloquent\Collection;
88

9-
function createTestCategories(): Collection
10-
{
11-
$category = CategoryRecord::factory(2)->create();
9+
beforeEach(function () {
10+
$mockAuthGateway = mock(AuthorizationGateway::class);
11+
$mockAuthGateway->shouldReceive('canPerformAction')
12+
->with('publish_article')
13+
->andReturn(true);
14+
$this->app->instance(AuthorizationGateway::class, $mockAuthGateway);
1215

13-
return $category;
14-
}
16+
$this->categories = CategoryRecord::factory(2)->create();
17+
});
1518

1619
it('can publish aritcle drafts via api', function () {
17-
$categories = createTestCategories();
1820
$response = $this->postJson('articles', [
1921
'title' => 'My Article',
2022
'body' => 'This is my article body',
2123
'status' => 'draft',
22-
'category_ids' => $categories->pluck('id')->toArray(),
24+
'category_ids' => $this->categories->pluck('id')->toArray(),
2325
]);
2426

2527
$response->assertStatus(201);
@@ -29,18 +31,17 @@ function createTestCategories(): Collection
2931
'title' => 'My Article',
3032
'body' => 'This is my article body',
3133
'status' => 'draft',
32-
'categories' => $categories->only(['id', 'label'])->toArray(),
34+
'categories' => $this->categories->only(['id', 'label'])->toArray(),
3335
],
3436
]);
3537
});
3638

3739
it('can publish published articles via api', function () {
38-
$categories = createTestCategories();
3940
$response = $this->postJson('articles', [
4041
'title' => 'My Article',
4142
'body' => 'This is my article body',
4243
'status' => 'published',
43-
'category_ids' => $categories->pluck('id')->toArray(),
44+
'category_ids' => $this->categories->pluck('id')->toArray(),
4445
]);
4546

4647
$response->assertStatus(201);
@@ -50,32 +51,31 @@ function createTestCategories(): Collection
5051
'title' => 'My Article',
5152
'body' => 'This is my article body',
5253
'status' => 'published',
53-
'categories' => $categories->only(['id', 'label'])->toArray(),
54+
'categories' => $this->categories->only(['id', 'label'])->toArray(),
5455
],
5556
]);
5657
});
5758

5859
it('dispatches an event when an article is published via api', function () {
5960
Event::fake();
6061

61-
$categories = createTestCategories();
6262
$this->postJson('articles', [
6363
'title' => 'My Article',
6464
'body' => 'This is my article body',
6565
'status' => 'published',
66-
'category_ids' => $categories->pluck('id')->toArray(),
66+
'category_ids' => $this->categories->pluck('id')->toArray(),
6767
]);
6868

6969
Event::assertDispatched(ArticlePublishedEvent::class);
7070
});
7171

7272
it('can publish a draft article via api', function () {
73-
$categories = createTestCategories();
73+
7474
$response = $this->postJson('articles', [
7575
'title' => 'My Article',
7676
'body' => 'This is my article body',
7777
'status' => 'draft',
78-
'category_ids' => $categories->pluck('id')->toArray(),
78+
'category_ids' => $this->categories->pluck('id')->toArray(),
7979
]);
8080

8181
$response->assertStatus(201);
@@ -88,12 +88,12 @@ function createTestCategories(): Collection
8888
});
8989

9090
it('can get an article via api', function () {
91-
$categories = createTestCategories();
91+
9292
$response = $this->postJson('articles', [
9393
'title' => 'My Article',
9494
'body' => 'This is my article body',
9595
'status' => 'draft',
96-
'category_ids' => $categories->pluck('id')->toArray(),
96+
'category_ids' => $this->categories->pluck('id')->toArray(),
9797
]);
9898

9999
$response->assertStatus(201);
@@ -109,18 +109,18 @@ function createTestCategories(): Collection
109109
'title' => 'My Article',
110110
'body' => 'This is my article body',
111111
'status' => 'draft',
112-
'categories' => $categories->only(['id', 'label'])->toArray(),
112+
'categories' => $this->categories->only(['id', 'label'])->toArray(),
113113
],
114114
]);
115115
});
116116

117117
it('can get a list of articles via api', function () {
118-
$categories = createTestCategories();
118+
119119
$response = $this->postJson('articles', [
120120
'title' => 'My Article',
121121
'body' => 'This is my article body',
122122
'status' => 'draft',
123-
'category_ids' => $categories->pluck('id')->toArray(),
123+
'category_ids' => $this->categories->pluck('id')->toArray(),
124124
]);
125125

126126
$response->assertStatus(201);
@@ -131,24 +131,24 @@ function createTestCategories(): Collection
131131
});
132132

133133
it('can update an article via api', function () {
134-
$categories = createTestCategories();
134+
135135
$response = $this->postJson('articles', [
136136
'title' => 'My Article',
137137
'body' => 'This is my article body',
138138
'status' => 'draft',
139-
'category_ids' => $categories->pluck('id')->toArray(),
139+
'category_ids' => $this->categories->pluck('id')->toArray(),
140140
]);
141141

142142
$response->assertStatus(201);
143143

144144
$id = $response->json('data.id');
145145

146-
$categories2 = createTestCategories();
146+
$this->categories2 = CategoryRecord::factory(2)->create();
147147
$response = $this->putJson("articles/{$id}", [
148148
'title' => 'My Updated Article',
149149
'body' => 'This is my updated article body',
150150
'status' => 'published',
151-
'category_ids' => $categories2->pluck('id')->toArray(),
151+
'category_ids' => $this->categories2->pluck('id')->toArray(),
152152
]);
153153

154154
$response->assertStatus(200);
@@ -158,18 +158,18 @@ function createTestCategories(): Collection
158158
'title' => 'My Updated Article',
159159
'body' => 'This is my updated article body',
160160
'status' => 'published',
161-
'categories' => $categories2->only(['id', 'label'])->toArray(),
161+
'categories' => $this->categories2->only(['id', 'label'])->toArray(),
162162
],
163163
]);
164164
});
165165

166166
it('can archive an article via api', function () {
167-
$categories = createTestCategories();
167+
168168
$response = $this->postJson('articles', [
169169
'title' => 'My Article',
170170
'body' => 'This is my article body',
171171
'status' => 'published',
172-
'category_ids' => $categories->pluck('id')->toArray(),
172+
'category_ids' => $this->categories->pluck('id')->toArray(),
173173
]);
174174

175175
$response->assertStatus(201);
@@ -182,12 +182,12 @@ function createTestCategories(): Collection
182182
});
183183

184184
it('can archive and delete an article via api', function () {
185-
$categories = createTestCategories();
185+
186186
$response = $this->postJson('articles', [
187187
'title' => 'My Article',
188188
'body' => 'This is my article body',
189189
'status' => 'published',
190-
'category_ids' => $categories->pluck('id')->toArray(),
190+
'category_ids' => $this->categories->pluck('id')->toArray(),
191191
]);
192192

193193
$response->assertStatus(201);

0 commit comments

Comments
 (0)