From 696ea5e36cdb9adb14827d1ef3272803d30c2941 Mon Sep 17 00:00:00 2001 From: Perside Rosalie Date: Fri, 21 Nov 2025 17:24:05 +0100 Subject: [PATCH 1/6] [WIP]: Make API Endpoint to set the ReadOnly status of a Wiki --- .../Backend/WikiReadOnlyController.php | 30 +++++++++++++++++++ app/Wiki.php | 7 +++++ routes/backend.php | 1 + 3 files changed, 38 insertions(+) create mode 100644 app/Http/Controllers/Backend/WikiReadOnlyController.php diff --git a/app/Http/Controllers/Backend/WikiReadOnlyController.php b/app/Http/Controllers/Backend/WikiReadOnlyController.php new file mode 100644 index 00000000..749f2e1d --- /dev/null +++ b/app/Http/Controllers/Backend/WikiReadOnlyController.php @@ -0,0 +1,30 @@ +query('domain'); + $wiki = Wiki::where('domain', $domain)->first(); + + if (!$wiki) { + return response()->json([ + 'error' => 'Wiki not found for domain: ' . $domain + ], 404); + } + + $wiki->setSetting('wgReadOnly', 'This wiki is currently read-only.'); + return response()->json([ + 'success' => true, + 'domain' => $domain, + 'message' => 'Wiki set to read-only successfully.', + ]); + } + +} diff --git a/app/Wiki.php b/app/Wiki.php index 109c5588..2dd2dc83 100644 --- a/app/Wiki.php +++ b/app/Wiki.php @@ -159,4 +159,11 @@ public function getDomainDecodedAttribute(): string { public function wikiLatestProfile() { return $this->hasOne(WikiProfile::class)->latestOfMany(); } + + public function setSetting(string $name, string $value): void { + $this->settings()->updateOrCreate( + ['name' => $name], + ['value' => $value] + ); + } } diff --git a/routes/backend.php b/routes/backend.php index 478a4036..28e351fe 100644 --- a/routes/backend.php +++ b/routes/backend.php @@ -10,6 +10,7 @@ // GET $router->get('healthz', fn () => "It's Alive"); $router->get('getWikiHostsForDomain', ['uses' => 'MediaWikiHostsController@getWikiHostsForDomain']); +$router->post('setWikiReadonly', ['uses' => 'WikiReadOnlyController@setWikiReadonly']); $router->group(['prefix' => 'ingress'], function () use ($router) { // GET From f92967a6f8b180064e417cb8e7f06096be50238f Mon Sep 17 00:00:00 2001 From: Perside Rosalie Date: Mon, 24 Nov 2025 14:15:33 +0100 Subject: [PATCH 2/6] fix linting --- app/Http/Controllers/Backend/WikiReadOnlyController.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Backend/WikiReadOnlyController.php b/app/Http/Controllers/Backend/WikiReadOnlyController.php index 749f2e1d..26cffa79 100644 --- a/app/Http/Controllers/Backend/WikiReadOnlyController.php +++ b/app/Http/Controllers/Backend/WikiReadOnlyController.php @@ -7,24 +7,23 @@ use Illuminate\Http\Request; class WikiReadOnlyController extends Controller { + public function setWikiReadonly(Request $request) { - public function getWikiVersionForDomain(Request $request) { - - $domain = $request->query('domain'); + $domain = $request->input('domain'); $wiki = Wiki::where('domain', $domain)->first(); if (!$wiki) { return response()->json([ - 'error' => 'Wiki not found for domain: ' . $domain + 'error' => 'Wiki not found for domain: ' . $domain, ], 404); } $wiki->setSetting('wgReadOnly', 'This wiki is currently read-only.'); + return response()->json([ 'success' => true, 'domain' => $domain, 'message' => 'Wiki set to read-only successfully.', ]); } - } From c5b00ef1c9cc07e7e4ac4d87c5563c56f0cb5a84 Mon Sep 17 00:00:00 2001 From: Perside Rosalie Date: Mon, 24 Nov 2025 16:25:57 +0100 Subject: [PATCH 3/6] Add tests --- .../Backend/WikiReadOnlyController.php | 8 +++- routes/backend.php | 2 +- .../Backend/WikiReadOnlyControllerTest.php | 48 +++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 tests/Routes/Backend/WikiReadOnlyControllerTest.php diff --git a/app/Http/Controllers/Backend/WikiReadOnlyController.php b/app/Http/Controllers/Backend/WikiReadOnlyController.php index 26cffa79..1761645a 100644 --- a/app/Http/Controllers/Backend/WikiReadOnlyController.php +++ b/app/Http/Controllers/Backend/WikiReadOnlyController.php @@ -7,9 +7,13 @@ use Illuminate\Http\Request; class WikiReadOnlyController extends Controller { - public function setWikiReadonly(Request $request) { + public function setWikiReadOnly(Request $request) { - $domain = $request->input('domain'); + $validated = $request->validate([ + 'domain' => 'required|string', + ]); + + $domain = $validated['domain']; $wiki = Wiki::where('domain', $domain)->first(); if (!$wiki) { diff --git a/routes/backend.php b/routes/backend.php index 28e351fe..c093ac2e 100644 --- a/routes/backend.php +++ b/routes/backend.php @@ -10,7 +10,7 @@ // GET $router->get('healthz', fn () => "It's Alive"); $router->get('getWikiHostsForDomain', ['uses' => 'MediaWikiHostsController@getWikiHostsForDomain']); -$router->post('setWikiReadonly', ['uses' => 'WikiReadOnlyController@setWikiReadonly']); +$router->post('setWikiReadOnly', ['uses' => 'WikiReadOnlyController@setWikiReadOnly']); $router->group(['prefix' => 'ingress'], function () use ($router) { // GET diff --git a/tests/Routes/Backend/WikiReadOnlyControllerTest.php b/tests/Routes/Backend/WikiReadOnlyControllerTest.php new file mode 100644 index 00000000..427eb5d3 --- /dev/null +++ b/tests/Routes/Backend/WikiReadOnlyControllerTest.php @@ -0,0 +1,48 @@ +postJson($this->route, [ + 'domain' => 'nonexistent.wikibase.cloud', + ]); + + $response->assertStatus(404) + ->assertJson([ + 'error' => 'Wiki not found for domain: nonexistent.wikibase.cloud', + ]); + } + + public function testSetWikiToReadOnly() { + $wiki = Wiki::factory()->create([ + 'domain' => 'somewiki.wikibase.cloud', + ]); + + $response = $this->postJson($this->route, [ + 'domain' => 'somewiki.wikibase.cloud', + ]); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'domain' => 'somewiki.wikibase.cloud', + 'message' => 'Wiki set to read-only successfully.', + ]); + + $this->assertSame( + 'This wiki is currently read-only.', + WikiSetting::whereWikiId($wiki->id)->whereName('wgReadOnly')->first()->value + ); + + } +} From 1594ba3e92e708be604081a5d86b390a4705b28c Mon Sep 17 00:00:00 2001 From: Perside Rosalie Date: Mon, 24 Nov 2025 17:10:55 +0100 Subject: [PATCH 4/6] Use PUT method instead of POST --- routes/backend.php | 2 +- tests/Routes/Backend/WikiReadOnlyControllerTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/routes/backend.php b/routes/backend.php index c093ac2e..3461d83d 100644 --- a/routes/backend.php +++ b/routes/backend.php @@ -10,7 +10,7 @@ // GET $router->get('healthz', fn () => "It's Alive"); $router->get('getWikiHostsForDomain', ['uses' => 'MediaWikiHostsController@getWikiHostsForDomain']); -$router->post('setWikiReadOnly', ['uses' => 'WikiReadOnlyController@setWikiReadOnly']); +$router->put('setWikiReadOnly', ['uses' => 'WikiReadOnlyController@setWikiReadOnly']); $router->group(['prefix' => 'ingress'], function () use ($router) { // GET diff --git a/tests/Routes/Backend/WikiReadOnlyControllerTest.php b/tests/Routes/Backend/WikiReadOnlyControllerTest.php index 427eb5d3..1060b01d 100644 --- a/tests/Routes/Backend/WikiReadOnlyControllerTest.php +++ b/tests/Routes/Backend/WikiReadOnlyControllerTest.php @@ -13,7 +13,7 @@ class WikiReadOnlyControllerTest extends TestCase { protected string $route = '/backend/setWikiReadOnly'; public function testItReturns404WhenWikiNotFound() { - $response = $this->postJson($this->route, [ + $response = $this->putJson($this->route, [ 'domain' => 'nonexistent.wikibase.cloud', ]); @@ -28,7 +28,7 @@ public function testSetWikiToReadOnly() { 'domain' => 'somewiki.wikibase.cloud', ]); - $response = $this->postJson($this->route, [ + $response = $this->putJson($this->route, [ 'domain' => 'somewiki.wikibase.cloud', ]); From a5356a8cb65290ba0af8f9a2697473c5c7541fcf Mon Sep 17 00:00:00 2001 From: Perside Rosalie Date: Tue, 25 Nov 2025 12:46:08 +0100 Subject: [PATCH 5/6] Add readOnly parameter --- .../Backend/WikiReadOnlyController.php | 26 ++++++++++++++----- app/Wiki.php | 4 +++ .../Backend/WikiReadOnlyControllerTest.php | 22 ++++++++++++++++ 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/app/Http/Controllers/Backend/WikiReadOnlyController.php b/app/Http/Controllers/Backend/WikiReadOnlyController.php index 1761645a..e1614657 100644 --- a/app/Http/Controllers/Backend/WikiReadOnlyController.php +++ b/app/Http/Controllers/Backend/WikiReadOnlyController.php @@ -11,23 +11,35 @@ public function setWikiReadOnly(Request $request) { $validated = $request->validate([ 'domain' => 'required|string', + 'readOnly' => 'required|boolean', ]); $domain = $validated['domain']; + $readOnly = $validated['readOnly']; $wiki = Wiki::where('domain', $domain)->first(); if (!$wiki) { return response()->json([ - 'error' => 'Wiki not found for domain: ' . $domain, + 'error' => "Wiki not found for domain: $domain", ], 404); } - $wiki->setSetting('wgReadOnly', 'This wiki is currently read-only.'); + if ($readOnly) { + $wiki->setSetting('wgReadOnly', 'This wiki is currently read-only.'); - return response()->json([ - 'success' => true, - 'domain' => $domain, - 'message' => 'Wiki set to read-only successfully.', - ]); + return response()->json([ + 'success' => true, + 'domain' => $domain, + 'message' => 'Wiki set to read-only successfully.', + ]); + } else { + $wiki->deleteSetting('wgReadOnly'); + + return response()->json([ + 'success' => true, + 'domain' => $domain, + 'message' => 'Read-only setting successfully removed for wiki.', + ]); + } } } diff --git a/app/Wiki.php b/app/Wiki.php index 2dd2dc83..8807653f 100644 --- a/app/Wiki.php +++ b/app/Wiki.php @@ -166,4 +166,8 @@ public function setSetting(string $name, string $value): void { ['value' => $value] ); } + + public function deleteSetting(string $name): ?string { + return $this->settings()->where('name', $name)->delete(); + } } diff --git a/tests/Routes/Backend/WikiReadOnlyControllerTest.php b/tests/Routes/Backend/WikiReadOnlyControllerTest.php index 1060b01d..6e1db32f 100644 --- a/tests/Routes/Backend/WikiReadOnlyControllerTest.php +++ b/tests/Routes/Backend/WikiReadOnlyControllerTest.php @@ -15,6 +15,7 @@ class WikiReadOnlyControllerTest extends TestCase { public function testItReturns404WhenWikiNotFound() { $response = $this->putJson($this->route, [ 'domain' => 'nonexistent.wikibase.cloud', + 'readOnly' => true, ]); $response->assertStatus(404) @@ -30,6 +31,7 @@ public function testSetWikiToReadOnly() { $response = $this->putJson($this->route, [ 'domain' => 'somewiki.wikibase.cloud', + 'readOnly' => true, ]); $response->assertStatus(200) @@ -45,4 +47,24 @@ public function testSetWikiToReadOnly() { ); } + + public function testDeleteSettingForReadOnlyFalse() { + $wiki = Wiki::factory()->create([ + 'domain' => 'somewiki.wikibase.cloud', + ]); + $wiki->setSetting('wgReadOnly', 'test'); + + $this->putJson($this->route, [ + 'domain' => $wiki->domain, + 'readOnly' => false, + ]) + ->assertStatus(200) + ->assertJson(['message' => 'Read-only setting successfully removed for wiki.']); + + $this->assertNull( + WikiSetting::whereWikiId($wiki->id) + ->whereName('wgReadOnly') + ->first(), + ); + } } From 7154e055014d4d24ef68e75254faeb83ee78777c Mon Sep 17 00:00:00 2001 From: Ollie Date: Wed, 26 Nov 2025 11:38:56 +0000 Subject: [PATCH 6/6] Minor improvements --- app/Http/Controllers/Backend/WikiReadOnlyController.php | 4 ++-- routes/backend.php | 1 + tests/Routes/Backend/WikiReadOnlyControllerTest.php | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Backend/WikiReadOnlyController.php b/app/Http/Controllers/Backend/WikiReadOnlyController.php index e1614657..0fae6196 100644 --- a/app/Http/Controllers/Backend/WikiReadOnlyController.php +++ b/app/Http/Controllers/Backend/WikiReadOnlyController.php @@ -16,11 +16,11 @@ public function setWikiReadOnly(Request $request) { $domain = $validated['domain']; $readOnly = $validated['readOnly']; - $wiki = Wiki::where('domain', $domain)->first(); + $wiki = Wiki::where('domain', $domain)->first(); if (!$wiki) { return response()->json([ - 'error' => "Wiki not found for domain: $domain", + 'error' => "Wiki not found for domain '$domain'", ], 404); } diff --git a/routes/backend.php b/routes/backend.php index 3461d83d..b1499068 100644 --- a/routes/backend.php +++ b/routes/backend.php @@ -10,6 +10,7 @@ // GET $router->get('healthz', fn () => "It's Alive"); $router->get('getWikiHostsForDomain', ['uses' => 'MediaWikiHostsController@getWikiHostsForDomain']); +// PUT $router->put('setWikiReadOnly', ['uses' => 'WikiReadOnlyController@setWikiReadOnly']); $router->group(['prefix' => 'ingress'], function () use ($router) { diff --git a/tests/Routes/Backend/WikiReadOnlyControllerTest.php b/tests/Routes/Backend/WikiReadOnlyControllerTest.php index 6e1db32f..2f531dd0 100644 --- a/tests/Routes/Backend/WikiReadOnlyControllerTest.php +++ b/tests/Routes/Backend/WikiReadOnlyControllerTest.php @@ -20,7 +20,7 @@ public function testItReturns404WhenWikiNotFound() { $response->assertStatus(404) ->assertJson([ - 'error' => 'Wiki not found for domain: nonexistent.wikibase.cloud', + 'error' => "Wiki not found for domain 'nonexistent.wikibase.cloud'", ]); }