Skip to content

Commit 77afcd9

Browse files
AndrewKostkadeer-wmde
authored andcommitted
Add POST endpoint for wiki profiles (#927)
* Add POST endpoint for Wiki profiles * Require a non-empty JSON profile * Update CHANGELOG.md
1 parent 9a347bc commit 77afcd9

5 files changed

Lines changed: 234 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# api
22

3+
## 10x.19.5
4+
- Add POST endpoint for wiki profiles
5+
36
## 10x.19.4
47
- Extend wiki details with profile data
58

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace App\Http\Controllers;
4+
5+
use App\Helper\ProfileValidator;
6+
use App\Rules\NonEmptyJsonRule;
7+
use App\Wiki;
8+
use App\WikiProfile;
9+
use Illuminate\Http\Request;
10+
11+
class WikiProfileController extends Controller
12+
{
13+
private $profileValidator;
14+
15+
public function __construct(ProfileValidator $profileValidator)
16+
{
17+
$this->profileValidator = $profileValidator;
18+
}
19+
20+
public function create(Request $request): \Illuminate\Http\JsonResponse
21+
{
22+
$validatedInput = $request->validate([
23+
'wiki' => ['required', 'integer'],
24+
'profile' => ['required', 'json', new NonEmptyJsonRule]
25+
]);
26+
27+
$wiki = Wiki::find($validatedInput['wiki']);
28+
if (!$wiki) {
29+
abort(404, 'No such wiki');
30+
}
31+
32+
$rawProfile = json_decode($validatedInput['profile'], true);
33+
$profileValidator = $this->profileValidator->validate($rawProfile);
34+
$profileValidator->validateWithBag('post');
35+
36+
$profile = WikiProfile::create(['wiki_id' => $wiki->id, ...$rawProfile]);
37+
return response()->json(['data' => $profile]);
38+
}
39+
}

app/Rules/NonEmptyJsonRule.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace App\Rules;
4+
5+
use Closure;
6+
use Illuminate\Contracts\Validation\ValidationRule;
7+
8+
class NonEmptyJsonRule implements ValidationRule
9+
{
10+
public function validate(string $attribute, mixed $value, Closure $fail): void
11+
{
12+
$json = json_decode($value, true);
13+
if (!is_array($json) || empty($json)) {
14+
$fail("The {$attribute} field must be a non-empty JSON object.");
15+
}
16+
}
17+
}

routes/api.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
$router->post('managers/list', ['uses' => 'WikiManagersController@getManagersOfWiki']);
4848
$router->get('entityImport', ['middleware' => 'limit_wiki_access', 'uses' => 'WikiEntityImportController@get']);
4949
$router->post('entityImport', ['middleware' => 'limit_wiki_access', 'uses' => 'WikiEntityImportController@create']);
50+
$router->post('profile', ['middleware' => 'limit_wiki_access', 'uses' => 'WikiProfileController@create']);
5051
});
5152
$router->apiResource('deletedWikiMetrics', 'DeletedWikiMetricsController')->only(['index'])
5253
->middleware(AuthorisedUsersForDeletedWikiMetricsMiddleware::class);
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
<?php
2+
3+
namespace Tests\Routes\Wiki\Managers;
4+
5+
use App\User;
6+
use App\Wiki;
7+
use App\WikiManager;
8+
use App\WikiProfile;
9+
use Tests\TestCase;
10+
11+
class ProfileControllerTest extends TestCase
12+
{
13+
protected $route = 'wiki/profile';
14+
15+
public function setUp(): void
16+
{
17+
parent::setUp();
18+
Wiki::query()->delete();
19+
WikiManager::query()->delete();
20+
WikiProfile::query()->delete();
21+
}
22+
23+
public function tearDown(): void
24+
{
25+
Wiki::query()->delete();
26+
WikiManager::query()->delete();
27+
WikiProfile::query()->delete();
28+
parent::tearDown();
29+
}
30+
31+
public function testFailOnMissingWiki(): void
32+
{
33+
$wiki = Wiki::factory()->create();
34+
$user = User::factory()->create(['verified' => true]);
35+
WikiManager::factory()->create(['wiki_id' => $wiki->id, 'user_id' => $user->id]);
36+
$wiki->delete();
37+
38+
$this->actingAs($user, 'api')
39+
->json(
40+
'POST',
41+
$this->route,
42+
[
43+
'wiki' => $wiki->id,
44+
'profile' => json_encode([
45+
'audience' => 'wide',
46+
'temporality' => 'permanent',
47+
'purpose' => 'data_hub'
48+
])
49+
]
50+
)
51+
->assertStatus(404);
52+
}
53+
54+
public function testFailOnWrongWikiManager(): void
55+
{
56+
$userWiki = Wiki::factory()->create();
57+
$otherWiki = Wiki::factory()->create();
58+
$user = User::factory()->create(['verified' => true]);
59+
WikiManager::factory()->create(['wiki_id' => $userWiki->id, 'user_id' => $user->id]);
60+
61+
$this->actingAs($user, 'api')
62+
->json(
63+
'POST',
64+
$this->route,
65+
[
66+
'wiki' => $otherWiki->id,
67+
'profile' => json_encode([
68+
'audience' => 'wide',
69+
'temporality' => 'permanent',
70+
'purpose' => 'data_hub'
71+
])
72+
]
73+
)
74+
->assertStatus(403);
75+
}
76+
77+
public function testFailOnEmptyProfile(): void
78+
{
79+
$userWiki = Wiki::factory()->create();
80+
$user = User::factory()->create(['verified' => true]);
81+
WikiManager::factory()->create(['wiki_id' => $userWiki->id, 'user_id' => $user->id]);
82+
83+
$this->actingAs($user, 'api')
84+
->json(
85+
'POST',
86+
$this->route,
87+
[
88+
'wiki' => $userWiki->id,
89+
'profile' => '{}'
90+
]
91+
)
92+
->assertStatus(422);
93+
}
94+
95+
public function testFailOnInvalidProfile(): void
96+
{
97+
$wiki = Wiki::factory()->create();
98+
$user = User::factory()->create(['verified' => true]);
99+
WikiManager::factory()->create(['wiki_id' => $wiki->id, 'user_id' => $user->id]);
100+
101+
$this->actingAs($user, 'api')
102+
->json(
103+
'POST',
104+
$this->route,
105+
[
106+
'wiki' => $wiki->id,
107+
'profile' => json_encode([
108+
'audience' => 'invalid option',
109+
'temporality' => 'permanent',
110+
'purpose' => 'data_hub'
111+
])
112+
]
113+
)
114+
->assertStatus(422)
115+
->assertJson([
116+
'message' => 'The selected audience is invalid.',
117+
'errors' => [
118+
'audience' => [
119+
'The selected audience is invalid.'
120+
]
121+
]
122+
]);
123+
}
124+
125+
public function testKeepAllVersions(): void
126+
{
127+
$wiki = Wiki::factory()->create();
128+
$user = User::factory()->create(['verified' => true]);
129+
WikiManager::factory()->create(['wiki_id' => $wiki->id, 'user_id' => $user->id]);
130+
131+
$versionA = $this->actingAs($user, 'api')
132+
->json(
133+
'POST',
134+
$this->route,
135+
[
136+
'wiki' => $wiki->id,
137+
'profile' => json_encode([
138+
'audience' => 'wide',
139+
'temporality' => 'permanent',
140+
'purpose' => 'data_hub'
141+
])
142+
]
143+
)
144+
->assertStatus(200);
145+
146+
$versionB = $this->actingAs($user, 'api')
147+
->json(
148+
'POST',
149+
$this->route,
150+
[
151+
'wiki' => $wiki->id,
152+
'profile' => json_encode([
153+
'audience' => 'wide',
154+
'temporality' => 'temporary',
155+
'purpose' => 'data_hub'
156+
])
157+
]
158+
)
159+
->assertStatus(200);
160+
161+
$this->assertEquals(
162+
2,
163+
WikiProfile::where(['wiki_id' => $wiki->id])->count()
164+
);
165+
$this->assertEquals(
166+
'permanent',
167+
WikiProfile::find($versionA->decodeResponseJson()['data']['id'])['temporality']
168+
);
169+
$this->assertEquals(
170+
'temporary',
171+
WikiProfile::find($versionB->decodeResponseJson()['data']['id'])['temporality']
172+
);
173+
}
174+
}

0 commit comments

Comments
 (0)