From b8c7f79a862376c6cc5fb9c11b645089779f390e Mon Sep 17 00:00:00 2001 From: Thomas Arrow Date: Thu, 19 Mar 2026 08:56:31 +0000 Subject: [PATCH] Create KER Object when a Wiki is made This creates a KnowledgeEquityResponse Object if one is provided at wiki creation time. It adds some validation for the content revieved over the network. No sanitisation has been applied to the freeTextResponse. This needs to be taken into account if we reuse this somewhere Bug: T419208 --- app/Http/Controllers/WikiController.php | 18 +++++- tests/Routes/Wiki/CreateTest.php | 79 +++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/WikiController.php b/app/Http/Controllers/WikiController.php index 6cbcb4fb..9cd45095 100644 --- a/app/Http/Controllers/WikiController.php +++ b/app/Http/Controllers/WikiController.php @@ -10,6 +10,7 @@ use App\Jobs\MediawikiInit; use App\Jobs\ProvisionQueryserviceNamespaceJob; use App\Jobs\ProvisionWikiDbJob; +use App\KnowledgeEquityResponse; use App\QueryserviceNamespace; use App\Wiki; use App\WikiDb; @@ -21,6 +22,7 @@ use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; +use Illuminate\Validation\Rule; class WikiController extends Controller { private $domainValidator; @@ -55,6 +57,14 @@ public function create(Request $request): \Illuminate\Http\Response { 'sitename' => 'required|min:3', 'username' => 'required', 'profile' => 'nullable|json', + 'knowledgeEquityResponse.selectedOption' => [ + 'nullable', + Rule::in('yes', 'no', 'unsure', 'unsaid'), + ], + 'knowledgeEquityResponse.freeTextResponse' => [ + 'nullable', + 'max:3000', + ], ]); $rawProfile = false; @@ -64,11 +74,13 @@ public function create(Request $request): \Illuminate\Http\Response { $profileValidator->validateWithBag('post'); } + $rawKnowledgeEquityResponse = $request->input('knowledgeEquityResponse'); + $wiki = null; $dbAssignment = null; // TODO create with some sort of owner etc? - DB::transaction(function () use ($user, $request, &$wiki, &$dbAssignment, $submittedDomain, $rawProfile) { + DB::transaction(function () use ($user, $request, &$wiki, &$dbAssignment, $submittedDomain, $rawProfile, $rawKnowledgeEquityResponse) { $dbVersion = Config::get('wbstack.wiki_db_use_version'); $wikiDbCondition = ['wiki_id' => null, 'version' => $dbVersion]; @@ -158,6 +170,10 @@ public function create(Request $request): \Illuminate\Http\Response { if ($rawProfile) { WikiProfile::create(['wiki_id' => $wiki->id, ...$rawProfile]); } + + if ($rawKnowledgeEquityResponse) { + KnowledgeEquityResponse::create(['wiki_id' => $wiki->id, ...$rawKnowledgeEquityResponse]); + } }); // TODO maybe always make these run in a certain order..? diff --git a/tests/Routes/Wiki/CreateTest.php b/tests/Routes/Wiki/CreateTest.php index 6d66842a..170590fa 100644 --- a/tests/Routes/Wiki/CreateTest.php +++ b/tests/Routes/Wiki/CreateTest.php @@ -5,6 +5,7 @@ use App\Jobs\ElasticSearchAliasInit; use App\Jobs\MediawikiInit; use App\Jobs\ProvisionWikiDbJob; +use App\KnowledgeEquityResponse; use App\QueryserviceNamespace; use App\User; use App\Wiki; @@ -310,4 +311,82 @@ public function testCreateWithProfileCreatesProfiles(): void { WikiProfile::where(['wiki_id' => $id])->count() ); } + + public function testCreateWithKERCreatesProfiles(): void { + $this->createSQLandQSDBs(); + Queue::fake(); + $user = User::factory()->create(['verified' => true]); + $response = $this->actingAs($user, 'api') + ->json( + 'POST', + $this->route, + [...self::defaultData, 'knowledgeEquityResponse' => [ + // This only tests the selectedOption since in the future this will become required while + // the freeTextResponse will not. + 'selectedOption' => 'yes', + ]] + ); + $id = $response->decodeResponseJson()['data']['id']; + $this->assertEquals(1, + KnowledgeEquityResponse::where(['wiki_id' => $id])->count() + ); + } + + public function testCreateWithKERRejectsIfSelectedOptionIsInvalid(): void { + $this->createSQLandQSDBs(); + Queue::fake(); + $user = User::factory()->create(['verified' => true]); + $response = $this->actingAs($user, 'api') + ->json( + 'POST', + $this->route, + [...self::defaultData, 'knowledgeEquityResponse' => [ + 'selectedOption' => 'yeeeeeah', + ]] + ); + $response->assertStatus(422); + // This only tests for the existance of an error key. + // Using JSON path to check the specific errors message + // binds very tightly to the laravel implemention of validation and was hard to make work. + $response->assertJsonStructure(['errors']); + } + + public function testCreateWithKERCreatesIf3000FreeTextResponse(): void { + $this->createSQLandQSDBs(); + Queue::fake(); + $user = User::factory()->create(['verified' => true]); + $response = $this->actingAs($user, 'api') + ->json( + 'POST', + $this->route, + [...self::defaultData, 'knowledgeEquityResponse' => [ + 'selectedOption' => 'yes', + 'freeTextResponse' => str_repeat('a', 3000), + ]] + ); + $id = $response->decodeResponseJson()['data']['id']; + $this->assertEquals(1, + KnowledgeEquityResponse::where(['wiki_id' => $id])->count() + ); + } + + public function testCreateWithKERErrorsIf3001FreeTextResponse(): void { + $this->createSQLandQSDBs(); + Queue::fake(); + $user = User::factory()->create(['verified' => true]); + $response = $this->actingAs($user, 'api') + ->json( + 'POST', + $this->route, + [...self::defaultData, 'knowledgeEquityResponse' => [ + 'selectedOption' => 'yes', + 'freeTextResponse' => str_repeat('a', 3001), + ]] + ); + $response->assertStatus(422); + // This only tests for the existance of an error key. + // Using JSON path to check the specific errors message + // binds very tightly to the laravel implemention of validation and was hard to make work. + $response->assertJsonStructure(['errors']); + } }