Skip to content

Commit 5a2c67e

Browse files
tarrowdeer-wmde
authored andcommitted
Create WikiProfile objects when a Wiki is made (#905)
This creates a WikiProfile object if a profile is provided at wiki creation time. It also add some validation for the form of this profile over the network. It should be noted that the _other strings are stored unsantised user input. We need to take this into account if we do anything with them Bug: T389063
1 parent 0f87af3 commit 5a2c67e

4 files changed

Lines changed: 146 additions & 7 deletions

File tree

app/Helper/ProfileValidator.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
namespace App\Helper;
3+
4+
use Illuminate\Support\Facades\Validator;
5+
use App\Http\Controllers\WikiController;
6+
7+
class ProfileValidator
8+
{
9+
public function validate( $profile ): \Illuminate\Validation\Validator {
10+
11+
return Validator::make($profile, [
12+
'purpose' => 'in:data_hub,data_lab,tool_lab,test_drive,decide_later,other',
13+
'purpose_other' => 'string|required_if:purpose,other|missing_unless:purpose,other',
14+
'audience' => 'in:narrow,wide,other',
15+
'audience_other' => 'string|required_if:audience,other|missing_unless:audience,other',
16+
'temporality' => 'in:permanent,temporary,decide_later,other',
17+
'temporality_other' => 'string|required_if:temporality,other|missing_unless:temporality,other',
18+
]);
19+
}
20+
21+
}

app/Http/Controllers/WikiController.php

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Http\Controllers;
44

5+
use App\Helper\ProfileValidator;
56
use App\Jobs\KubernetesIngressCreate;
67
use App\Jobs\MediawikiInit;
78
use App\Jobs\ProvisionQueryserviceNamespaceJob;
@@ -13,10 +14,12 @@
1314
use App\WikiDb;
1415
use App\WikiDomain;
1516
use App\WikiManager;
17+
use App\WikiProfile;
1618
use App\WikiSetting;
1719
use Illuminate\Http\Request;
1820
use Illuminate\Support\Facades\App;
1921
use Illuminate\Support\Facades\DB;
22+
use Illuminate\Support\Facades\Validator;
2023
use Illuminate\Support\Str;
2124
use Illuminate\Support\Facades\Config;
2225
use App\Helper\DomainValidator;
@@ -25,9 +28,11 @@
2528
class WikiController extends Controller
2629
{
2730
private $domainValidator;
31+
private $profileValidator;
2832

29-
public function __construct( DomainValidator $domainValidator )
33+
public function __construct( DomainValidator $domainValidator, ProfileValidator $profileValidator )
3034
{
35+
$this->profileValidator = $profileValidator;
3136
$this->domainValidator = $domainValidator;
3237
}
3338

@@ -42,28 +47,35 @@ public function create(Request $request): \Illuminate\Http\Response
4247
abort(503, 'Search enabled, but its configuration is invalid');
4348
}
4449
}
45-
4650
$user = $request->user();
4751

4852
$submittedDomain = strtolower($request->input('domain'));
4953
$submittedDomain = DomainHelper::encode($submittedDomain);
5054

51-
$validator = $this->domainValidator->validate( $submittedDomain );
55+
$domainValidator = $this->domainValidator->validate( $submittedDomain );
5256
$isSubdomain = $this->isSubDomain($submittedDomain);
5357

54-
$validator->validateWithBag('post');
58+
$domainValidator->validateWithBag('post');
5559

5660
// TODO extra validation that username is correct?
5761
$request->validate([
5862
'sitename' => 'required|min:3',
5963
'username' => 'required',
64+
'profile' => 'nullable|json',
6065
]);
61-
66+
67+
$rawProfile = false;
68+
if ($request->filled('profile') ) {
69+
$rawProfile = json_decode($request->input('profile'), true);
70+
$profileValidator = $this->profileValidator->validate($rawProfile);
71+
$profileValidator->validateWithBag('post');
72+
}
73+
6274
$wiki = null;
6375
$dbAssignment = null;
6476

6577
// TODO create with some sort of owner etc?
66-
DB::transaction(function () use ($user, $request, &$wiki, &$dbAssignment, $isSubdomain, $submittedDomain) {
78+
DB::transaction(function () use ($user, $request, &$wiki, &$dbAssignment, $isSubdomain, $submittedDomain, $rawProfile) {
6779
$dbVersion = Config::get('wbstack.wiki_db_use_version');
6880
$wikiDbCondition = ['wiki_id'=>null, 'version'=>$dbVersion];
6981

@@ -123,6 +135,12 @@ public function create(Request $request): \Illuminate\Http\Response
123135
'user_id' => $user->id,
124136
'wiki_id' => $wiki->id,
125137
]);
138+
139+
// Create WikiProfile
140+
if ($rawProfile) {
141+
WikiProfile::create([ 'wiki_id' => $wiki->id, ...$rawProfile ] );
142+
}
143+
126144

127145
// TODO maybe always make these run in a certain order..?
128146
dispatch(new MediawikiInit($wiki->domain, $request->input('username'), $user->email));
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
namespace Tests\Jobs;
3+
4+
use Tests\TestCase;
5+
use App\Helper\ProfileValidator;
6+
7+
class ProfileValidatorTest extends TestCase {
8+
9+
/**
10+
* @dataProvider validProfileProvider
11+
*/
12+
public function testProfileValidatorWorksWithValidProfile($profile): void {
13+
$validatorFactory = new ProfileValidator();
14+
$validator=$validatorFactory->validate($profile);
15+
$this->assertTrue($validator->passes());
16+
}
17+
18+
/**
19+
* @dataProvider invalidProfileProvider
20+
*/
21+
public function testProfileValidatorWorksWithInvalidProfile($profile): void {
22+
$validatorFactory = new ProfileValidator();
23+
$validator=$validatorFactory->validate($profile);
24+
$this->assertFalse($validator->passes());
25+
}
26+
27+
private function validProfileProvider() {
28+
return [
29+
[ 'boring profile with no other' => [
30+
'purpose' => 'data_hub',
31+
'audience' => 'narrow',
32+
'temporality' => 'permanent',
33+
] ],
34+
[ 'with other values' => [
35+
'purpose' => 'other',
36+
'purpose_other' => 'for fun',
37+
'audience' => 'other',
38+
'audience_other' => 'my cat',
39+
'temporality' => 'other',
40+
'temporality_other' => 'only in the past',
41+
] ],
42+
];
43+
}
44+
45+
46+
private function invalidProfileProvider() {
47+
return [
48+
[ 'missing other keys' => [
49+
'purpose' => 'other',
50+
'audience' => 'narrow',
51+
'temporality' => 'permanent',
52+
] ],
53+
[ 'other keys when there should not be' => [
54+
'purpose' => 'data_hub',
55+
'purpose_other' => 'asdfasdf',
56+
'audience' => 'narrow',
57+
'temporality' => 'permanent',
58+
] ],
59+
];
60+
}
61+
}

tests/Routes/Wiki/CreateTest.php

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Tests\Routes\Wiki\Managers;
44

5+
use App\WikiProfile;
56
use Tests\Routes\Traits\OptionsRequestAllowed;
67
use Tests\TestCase;
78
use Illuminate\Foundation\Testing\DatabaseTransactions;
@@ -264,13 +265,51 @@ static public function createWikiHandlesRangeOfPostValuesProvider(): array {
264265
unset($noUsername['username']);
265266
$noprofile = self::defaultData;
266267
unset($noprofile['profile']);
268+
$profileWithOther = self::defaultData;
269+
$profileWithOther['profile'] = '{
270+
"audience": "other",
271+
"audience_other": "just my cat",
272+
"temporality": "permanent",
273+
"purpose": "data_hub"
274+
}';
275+
$profileWithOtherStringMissing = self::defaultData;
276+
$profileWithOtherStringMissing['profile'] = '{
277+
"audience": "other",
278+
"temporality": "permanent",
279+
"purpose": "data_hub"
280+
}';
281+
$profileWithExtraneousOther = self::defaultData;
282+
$profileWithExtraneousOther['profile'] = '{
283+
"audience_other": "just my cat",
284+
"temporality": "permanent",
285+
"purpose": "data_hub"
286+
}';
267287
return [
268288
'all params present' => [self::defaultData , 200],
269289
'missing domain' => [$noDomain, 422],
270290
'missing sitename' => [$noSitename, 422],
271291
'missing username' => [$noUsername, 422],
272-
'missing profile' => [$noprofile, 200]
292+
'missing profile' => [$noprofile, 200],
293+
'profile with other' => [$profileWithOther, 200],
294+
'profile with other string missing' => [$profileWithOtherStringMissing, 422],
295+
'profile with extraneous other' => [$profileWithExtraneousOther, 422]
273296
];
274297
}
275298

299+
public function testCreateWithProfileCreatesProfiles(): void {
300+
$this->createSQLandQSDBs();
301+
Queue::fake();
302+
$user = User::factory()->create(['verified' => true]);
303+
$response = $this->actingAs($user, 'api')
304+
->json(
305+
'POST',
306+
$this->route,
307+
self::defaultData
308+
);
309+
$id = $response->decodeResponseJson()['data']['id'];
310+
$this->assertEquals( 1,
311+
WikiProfile::where( [ 'wiki_id' => $id ] )->count()
312+
);
313+
}
314+
276315
}

0 commit comments

Comments
 (0)