From 3fa66cceff58c2b6de7f3fdad606d124defd63af Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 15:46:04 +0100 Subject: [PATCH 01/11] Implement non-extraction calls --- app/Enum/WebserviceEndpoint.php | 61 ++++++- app/Jobs/UpdateSite.php | 46 +++++ app/Models/Site.php | 10 ++ app/RemoteSite/Connection.php | 38 +++- app/RemoteSite/Responses/FinalizeUpdate.php | 13 ++ app/RemoteSite/Responses/GetUpdate.php | 13 ++ app/RemoteSite/Responses/HealthCheck.php | 2 +- app/RemoteSite/Responses/PrepareUpdate.php | 14 ++ .../Responses/ResponseInterface.php | 10 ++ tests/Unit/ExampleTest.php | 16 -- tests/Unit/Jobs/UpdateSiteTest.php | 165 ++++++++++++++++++ 11 files changed, 358 insertions(+), 30 deletions(-) create mode 100644 app/RemoteSite/Responses/FinalizeUpdate.php create mode 100644 app/RemoteSite/Responses/GetUpdate.php create mode 100644 app/RemoteSite/Responses/PrepareUpdate.php create mode 100644 app/RemoteSite/Responses/ResponseInterface.php delete mode 100644 tests/Unit/ExampleTest.php create mode 100644 tests/Unit/Jobs/UpdateSiteTest.php diff --git a/app/Enum/WebserviceEndpoint.php b/app/Enum/WebserviceEndpoint.php index d5165a5..243ed54 100644 --- a/app/Enum/WebserviceEndpoint.php +++ b/app/Enum/WebserviceEndpoint.php @@ -2,10 +2,63 @@ namespace App\Enum; +use App\RemoteSite\Responses\FinalizeUpdate; +use App\RemoteSite\Responses\GetUpdate; +use App\RemoteSite\Responses\HealthCheck; +use App\RemoteSite\Responses\PrepareUpdate; + enum WebserviceEndpoint: string { - case HEALTH_CHECK = "/api/index.php/v1/joomlaupdate/healthcheck"; - case FETCH_UPDATES = "/api/index.php/v1/joomlaupdate/fetchUpdate"; - case PREPARE_UPDATE = "/api/index.php/v1/joomlaupdate/prepareUpdate"; - case FINALIZE_UPDATE = "/api/index.php/v1/joomlaupdate/finalizeUpdate"; + case checkHealth = "/api/index.php/v1/joomlaupdate/healthcheck"; + case getUpdate = "/api/index.php/v1/joomlaupdate/getUpdate"; + case prepareUpdate = "/api/index.php/v1/joomlaupdate/prepareUpdate"; + case finalizeUpdate = "/api/index.php/v1/joomlaupdate/finalizeUpdate"; + + public function getMethod(): HttpMethod + { + switch ($this->name) { + case self::checkHealth->name: + case self::getUpdate->name: + return HttpMethod::GET; + + case self::prepareUpdate->name: + case self::finalizeUpdate->name: + return HttpMethod::POST; + } + + throw new \ValueError("No method defined"); + } + + public function getResponseClass(): string + { + switch ($this->name) { + case self::checkHealth->name: + return HealthCheck::class; + case self::getUpdate->name: + return GetUpdate::class; + case self::prepareUpdate->name: + return PrepareUpdate::class; + case self::finalizeUpdate->name: + return FinalizeUpdate::class; + } + + throw new \ValueError("No method defined"); + } + + public function getUrl(): string + { + return $this->value; + } + + public static function tryFromName(string $name): ?static + { + $reflection = new \ReflectionEnum(static::class); + + if (!$reflection->hasCase($name)) { + return null; + } + + /** @var static */ + return $reflection->getCase($name)->getValue(); + } } diff --git a/app/Jobs/UpdateSite.php b/app/Jobs/UpdateSite.php index 5fb1211..0970161 100644 --- a/app/Jobs/UpdateSite.php +++ b/app/Jobs/UpdateSite.php @@ -6,11 +6,15 @@ use App\Models\Site; use App\RemoteSite\Connection; +use App\RemoteSite\Responses\PrepareUpdate; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Queue\Queueable; +use Illuminate\Support\Facades\Log; class UpdateSite implements ShouldQueue { + protected int $preUpdateCode; + use Queueable; /** @@ -30,5 +34,47 @@ public function handle(): void // Test connection and get current version $healthResult = $connection->checkHealth(); + + // Check the version + if (version_compare($healthResult->cms_version, $this->targetVersion, ">=")) { + Log::info("Site is already up to date: " . $this->site->id); + + return; + } + + // Store pre-update response code + $this->preUpdateCode = $this->site->getFrontendStatus(); + + // Let site fetch available updates + $updateResult = $connection->getUpdate(); + + // Check if update is found and return if not + if (is_null($updateResult->availableUpdate)) { + Log::info("No update available for site: " . $this->site->id); + + return; + } + + // Check the version and return if it does not match + if ($updateResult->availableUpdate !== $this->targetVersion) { + Log::info("Update version mismatch for site: " . $this->site->id); + + return; + } + + $prepareResult = $connection->prepareUpdate($this->targetVersion); + + // Perform the actual extraction + $this->performExtraction($prepareResult); + + // Run the postupdate steps + if (!$connection->finalizeUpdate()->success) { + throw new \Exception("Update for site failed in postprocessing: " . $this->site->id); + } + } + + protected function performExtraction(PrepareUpdate $prepareResult) + { + } } diff --git a/app/Models/Site.php b/app/Models/Site.php index 90290c1..c38481b 100644 --- a/app/Models/Site.php +++ b/app/Models/Site.php @@ -5,7 +5,9 @@ namespace App\Models; use App\RemoteSite\Connection; +use GuzzleHttp\Client; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\App; class Site extends Model { @@ -45,4 +47,12 @@ public function getConnectionAttribute(): Connection { return new Connection($this->url, $this->key); } + + public function getFrontendStatus(): int + { + /** @var Client $httpClient */ + $httpClient = App::make(Client::class); + + return $httpClient->get($this->url)->getStatusCode(); + } } diff --git a/app/RemoteSite/Connection.php b/app/RemoteSite/Connection.php index 8b1534f..508a7e7 100644 --- a/app/RemoteSite/Connection.php +++ b/app/RemoteSite/Connection.php @@ -6,7 +6,11 @@ use App\Enum\HttpMethod; use App\Enum\WebserviceEndpoint; +use App\RemoteSite\Responses\FinalizeUpdate as FinalizeUpdateResponse; use App\RemoteSite\Responses\HealthCheck as HealthCheckResponse; +use App\RemoteSite\Responses\GetUpdate as GetUpdateResponse; +use App\RemoteSite\Responses\PrepareUpdate as PrepareUpdateResponse; +use App\RemoteSite\Responses\ResponseInterface; use GuzzleHttp\Client; use GuzzleHttp\Exception\RequestException; use GuzzleHttp\Psr7\Request; @@ -14,27 +18,43 @@ use Illuminate\Support\Facades\App; use Psr\Http\Message\RequestInterface; +/** + * @method HealthCheckResponse checkHealth() + * @method GetUpdateResponse getUpdate() + * @method PrepareUpdateResponse prepareUpdate(string $targetVersion) + * @method FinalizeUpdateResponse finalizeUpdate() + */ class Connection { public function __construct(protected readonly string $baseUrl, protected readonly string $key) { } - public function checkHealth(): HealthCheckResponse + public function __call(string $method, array $arguments): ResponseInterface { - $healthData = $this->performWebserviceRequest( - HttpMethod::GET, - WebserviceEndpoint::HEALTH_CHECK + $endpoint = WebserviceEndpoint::tryFromName($method); + + if (is_null($endpoint)) { + throw new \BadMethodCallException(); + } + + // Call + $data = $this->performWebserviceRequest( + $endpoint->getMethod(), + $endpoint->getUrl(), + ...$arguments ); - return HealthCheckResponse::from($healthData['data']['attributes']); + $responseClass = $endpoint->getResponseClass(); + + return $responseClass::from($data); } public function performExtractionRequest(array $requestData): array { $request = new Request( 'POST', - $this->baseUrl . 'extract.php' + $this->baseUrl . '/extract.php' ); $data['password'] = $this->key; @@ -55,12 +75,12 @@ public function performExtractionRequest(array $requestData): array protected function performWebserviceRequest( HttpMethod $method, - WebserviceEndpoint $endpoint, + string $endpoint, array $requestData = [] ): array { $request = new Request( $method->name, - $this->baseUrl . $endpoint->value, + $this->baseUrl . $endpoint, [ 'X-JUpdate-Token' => $this->key ] @@ -85,7 +105,7 @@ protected function performWebserviceRequest( ); } - return $responseData; + return $responseData['data']['attributes']; } protected function performHttpRequest( diff --git a/app/RemoteSite/Responses/FinalizeUpdate.php b/app/RemoteSite/Responses/FinalizeUpdate.php new file mode 100644 index 0000000..e90427e --- /dev/null +++ b/app/RemoteSite/Responses/FinalizeUpdate.php @@ -0,0 +1,13 @@ +assertTrue(true); - } -} diff --git a/tests/Unit/Jobs/UpdateSiteTest.php b/tests/Unit/Jobs/UpdateSiteTest.php new file mode 100644 index 0000000..9553f5a --- /dev/null +++ b/tests/Unit/Jobs/UpdateSiteTest.php @@ -0,0 +1,165 @@ +getSiteMock(['checkHealth' => $this->getHealthCheckMock(["cms_version" => "1.0.0"])]); + + Log::spy(); + + $object = new UpdateSite($site, "1.0.0"); + $object->handle(); + + Log::shouldHaveReceived('info') + ->once() + ->withArgs(function ($message) { + return str_contains($message, 'Site is already up to date'); + }); + + $this->assertTrue(true); + } + + public function testJobQuitsIfNoUpdateIsAvailable() + { + $site = $this->getSiteMock( + [ + 'checkHealth' => $this->getHealthCheckMock(), + 'getUpdate' => $this->getGetUpdateMock(null) + ] + ); + + Log::spy(); + + $object = new UpdateSite($site, "1.0.1"); + $object->handle(); + + Log::shouldHaveReceived('info') + ->once() + ->withArgs(function ($message) { + return str_contains($message, 'No update available for site'); + }); + + $this->assertTrue(true); + } + + public function testJobQuitsIfAvailabelUpdateDoesNotMatchTargetVersion() + { + $site = $this->getSiteMock( + [ + 'checkHealth' => $this->getHealthCheckMock(), + 'getUpdate' => $this->getGetUpdateMock("1.0.2") + ] + ); + + Log::spy(); + + $object = new UpdateSite($site, "1.0.1"); + $object->handle(); + + Log::shouldHaveReceived('info') + ->once() + ->withArgs(function ($message) { + return str_contains($message, 'Update version mismatch for site'); + }); + + $this->assertTrue(true); + } + + public function testJobFailsIfFinalizeUpdateReturnsFalse() + { + $this->expectExceptionMessage("Update for site failed in postprocessing: 1"); + + $site = $this->getSiteMock( + [ + 'checkHealth' => $this->getHealthCheckMock(), + 'getUpdate' => $this->getGetUpdateMock("1.0.1"), + 'prepareUpdate' => $this->getPrepareUpdateMock(), + 'finalizeUpdate' => $this->getFinalizeUpdateMock(false) + ] + ); + + $object = new UpdateSite($site, "1.0.1"); + $object->handle(); + } + + protected function getSiteMock(array $responses) + { + $connectionMock = $this->getMockBuilder(Connection::class) + ->disableOriginalConstructor() + ->getMock(); + + $connectionMock + ->method("__call") + ->willReturnCallback( + function ($method) use ($responses) { + return $responses[$method]; + } + ); + + $siteMock = $this->getMockBuilder(Site::class) + ->onlyMethods(['getConnectionAttribute', 'getFrontendStatus']) + ->getMock(); + + $siteMock->method('getConnectionAttribute')->willReturn($connectionMock); + $siteMock->method('getFrontendStatus')->willReturn(200); + $siteMock->id = 1; + + return $siteMock; + } + + protected function getHealthCheckMock($overrides = []) + { + $defaults = [ + "php_version" => "1.0.0", + "db_type" => "mysqli", + "db_version" => "1.0.0", + "cms_version" => "1.0.0", + "server_os" => "Joomla OS 1.0.0" + ]; + + return HealthCheck::from([ + ...$defaults, + ...$overrides + ]); + } + + protected function getGetUpdateMock($version) + { + return GetUpdate::from([ + "availableUpdate" => $version + ]); + } + + protected function getFinalizeUpdateMock(bool $success) + { + return FinalizeUpdate::from([ + "success" => $success + ]); + } + + protected function getPrepareUpdateMock($overrides = []) + { + $defaults = [ + "password" => "foobar123", + "filesize" => 123456 + ]; + + return PrepareUpdate::from([ + ...$defaults, + ...$overrides + ]); + } +} From 9f0f34efffa23ede2ffb6aa711ee2815ea81bb5a Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 15:46:45 +0100 Subject: [PATCH 02/11] cs fix --- app/Enum/WebserviceEndpoint.php | 2 -- app/Jobs/UpdateSite.php | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/Enum/WebserviceEndpoint.php b/app/Enum/WebserviceEndpoint.php index 243ed54..4acf3b8 100644 --- a/app/Enum/WebserviceEndpoint.php +++ b/app/Enum/WebserviceEndpoint.php @@ -41,8 +41,6 @@ public function getResponseClass(): string case self::finalizeUpdate->name: return FinalizeUpdate::class; } - - throw new \ValueError("No method defined"); } public function getUrl(): string diff --git a/app/Jobs/UpdateSite.php b/app/Jobs/UpdateSite.php index 0970161..9565407 100644 --- a/app/Jobs/UpdateSite.php +++ b/app/Jobs/UpdateSite.php @@ -73,7 +73,7 @@ public function handle(): void } } - protected function performExtraction(PrepareUpdate $prepareResult) + protected function performExtraction(PrepareUpdate $prepareResult): void { } From d4a8193ddf71fa2e7dd0021aaa620a2fe9549dbe Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 15:48:02 +0100 Subject: [PATCH 03/11] cs fix --- app/Enum/WebserviceEndpoint.php | 1 + app/Jobs/UpdateSite.php | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Enum/WebserviceEndpoint.php b/app/Enum/WebserviceEndpoint.php index 4acf3b8..fcf91ae 100644 --- a/app/Enum/WebserviceEndpoint.php +++ b/app/Enum/WebserviceEndpoint.php @@ -21,6 +21,7 @@ public function getMethod(): HttpMethod case self::getUpdate->name: return HttpMethod::GET; + // no break case self::prepareUpdate->name: case self::finalizeUpdate->name: return HttpMethod::POST; diff --git a/app/Jobs/UpdateSite.php b/app/Jobs/UpdateSite.php index 9565407..362d26a 100644 --- a/app/Jobs/UpdateSite.php +++ b/app/Jobs/UpdateSite.php @@ -13,9 +13,8 @@ class UpdateSite implements ShouldQueue { - protected int $preUpdateCode; - use Queueable; + protected int $preUpdateCode; /** * Create a new job instance. From 67a64d7f1cf74f97dc854e45910cedaa186b3f72 Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 15:56:37 +0100 Subject: [PATCH 04/11] implement extraction logic --- app/Jobs/UpdateSite.php | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/app/Jobs/UpdateSite.php b/app/Jobs/UpdateSite.php index 362d26a..682e8d3 100644 --- a/app/Jobs/UpdateSite.php +++ b/app/Jobs/UpdateSite.php @@ -9,6 +9,7 @@ use App\RemoteSite\Responses\PrepareUpdate; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Queue\Queueable; +use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Log; class UpdateSite implements ShouldQueue @@ -74,6 +75,45 @@ public function handle(): void protected function performExtraction(PrepareUpdate $prepareResult): void { + $connection = App::make(Connection::class, [ + $this->site->url, + $prepareResult->password + ]); + + // Ping server + $pingResult = $connection->performExtractionRequest(["task" => "ping"]); + + if (empty($pingResult["message"]) || $pingResult["message"] === 'Invalid login') { + throw new \Exception( + "Invalid ping response for site: " . $this->site->id + ); + } + + // Start extraction + $stepResult = $connection->performExtractionRequest(["task" => "startExtract"]); + + // Run actual core update + while (array_key_exists("done", $stepResult) && $stepResult["done"] !== true) { + if ($stepResult["status"] !== true) { + throw new \Exception( + "Invalid extract response for site: " . $this->site->id + ); + } + + // Make next backup step + $stepResult = $connection->performExtractionRequest( + [ + "task" => "stepExtract", + "instance" => $stepResult["instance"] + ] + ); + } + // Clean up restore + $connection->performExtractionRequest( + [ + "task" => "finalizeUpdate" + ] + ); } } From 54da9110a607b14761649343ee8ea4845aefb280 Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 15:57:52 +0100 Subject: [PATCH 05/11] cs fix --- app/Jobs/UpdateSite.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Jobs/UpdateSite.php b/app/Jobs/UpdateSite.php index 682e8d3..56775c7 100644 --- a/app/Jobs/UpdateSite.php +++ b/app/Jobs/UpdateSite.php @@ -75,6 +75,7 @@ public function handle(): void protected function performExtraction(PrepareUpdate $prepareResult): void { + /** Create a separate connection with the extraction password **/ $connection = App::make(Connection::class, [ $this->site->url, $prepareResult->password @@ -100,7 +101,7 @@ protected function performExtraction(PrepareUpdate $prepareResult): void ); } - // Make next backup step + // Make next extraction step $stepResult = $connection->performExtractionRequest( [ "task" => "stepExtract", From e4a95fdf1651f94a7f264be13a96b7d9107665b6 Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 15:58:37 +0100 Subject: [PATCH 06/11] fix test --- tests/Unit/Jobs/UpdateSiteTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Unit/Jobs/UpdateSiteTest.php b/tests/Unit/Jobs/UpdateSiteTest.php index 9553f5a..15b4618 100644 --- a/tests/Unit/Jobs/UpdateSiteTest.php +++ b/tests/Unit/Jobs/UpdateSiteTest.php @@ -116,6 +116,7 @@ function ($method) use ($responses) { $siteMock->method('getConnectionAttribute')->willReturn($connectionMock); $siteMock->method('getFrontendStatus')->willReturn(200); $siteMock->id = 1; + $siteMock->url = "http://example.org"; return $siteMock; } From b10cb01dc1aa21d93f7801094f31d9e0d2bf5395 Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 16:02:34 +0100 Subject: [PATCH 07/11] fix --- pint.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pint.json b/pint.json index 684f282..9184dc2 100644 --- a/pint.json +++ b/pint.json @@ -1,3 +1,6 @@ { - "preset": "psr12" + "preset": "psr12", + "notName": [ + "WebserviceEndpoint.php" + ] } From 28c7c01ab5ba6de1049dc195af13e6a787a2bae4 Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 16:19:20 +0100 Subject: [PATCH 08/11] fix tests --- app/Jobs/UpdateSite.php | 6 +++--- tests/Unit/Jobs/UpdateSiteTest.php | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/app/Jobs/UpdateSite.php b/app/Jobs/UpdateSite.php index 56775c7..04cc98d 100644 --- a/app/Jobs/UpdateSite.php +++ b/app/Jobs/UpdateSite.php @@ -76,9 +76,9 @@ public function handle(): void protected function performExtraction(PrepareUpdate $prepareResult): void { /** Create a separate connection with the extraction password **/ - $connection = App::make(Connection::class, [ - $this->site->url, - $prepareResult->password + $connection = App::makeWith(Connection::class, [ + "baseUrl" => $this->site->url, + "key" => $prepareResult->password ]); // Ping server diff --git a/tests/Unit/Jobs/UpdateSiteTest.php b/tests/Unit/Jobs/UpdateSiteTest.php index 15b4618..a6327d5 100644 --- a/tests/Unit/Jobs/UpdateSiteTest.php +++ b/tests/Unit/Jobs/UpdateSiteTest.php @@ -9,6 +9,7 @@ use App\RemoteSite\Responses\GetUpdate; use App\RemoteSite\Responses\HealthCheck; use App\RemoteSite\Responses\PrepareUpdate; +use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Log; use Tests\TestCase; @@ -91,6 +92,8 @@ public function testJobFailsIfFinalizeUpdateReturnsFalse() ] ); + App::bind(Connection::class, fn() => $this->getSuccessfulExtractionMock()); + $object = new UpdateSite($site, "1.0.1"); $object->handle(); } @@ -163,4 +166,30 @@ protected function getPrepareUpdateMock($overrides = []) ...$overrides ]); } + + protected function getSuccessfulExtractionMock() + { + $connectionMock = $this->getMockBuilder(Connection::class) + ->disableOriginalConstructor() + ->getMock(); + + $connectionMock + ->method("performExtractionRequest") + ->willReturnCallback( + function ($data) { + switch ($data["task"]) { + case "ping": + return ["message" => "Success"]; + + case "startExtract": + return ["done" => true]; + + case "finalizeUpdate": + return ["success" => true]; + } + } + ); + + return $connectionMock; + } } From b0a98ad2441ac769a7ca0decf6f167e6d22b5c5b Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 16:20:45 +0100 Subject: [PATCH 09/11] cs fix --- tests/Unit/Jobs/UpdateSiteTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Jobs/UpdateSiteTest.php b/tests/Unit/Jobs/UpdateSiteTest.php index a6327d5..a6cb236 100644 --- a/tests/Unit/Jobs/UpdateSiteTest.php +++ b/tests/Unit/Jobs/UpdateSiteTest.php @@ -92,7 +92,7 @@ public function testJobFailsIfFinalizeUpdateReturnsFalse() ] ); - App::bind(Connection::class, fn() => $this->getSuccessfulExtractionMock()); + App::bind(Connection::class, fn () => $this->getSuccessfulExtractionMock()); $object = new UpdateSite($site, "1.0.1"); $object->handle(); From c95d34298a6938ad61943e24f70e68862d0d5e76 Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 16:25:20 +0100 Subject: [PATCH 10/11] cs fix --- pint.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pint.json b/pint.json index 9184dc2..087d1aa 100644 --- a/pint.json +++ b/pint.json @@ -1,6 +1,6 @@ { "preset": "psr12", - "notName": [ - "WebserviceEndpoint.php" - ] + "notName": [ + "WebserviceEndpoint.php" + ] } From 4de09d5805ded0460b3ffe58cd7542ae6dddd5c3 Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 16:51:59 +0100 Subject: [PATCH 11/11] compare status codes --- app/Jobs/UpdateSite.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/Jobs/UpdateSite.php b/app/Jobs/UpdateSite.php index 04cc98d..bd16e83 100644 --- a/app/Jobs/UpdateSite.php +++ b/app/Jobs/UpdateSite.php @@ -71,6 +71,11 @@ public function handle(): void if (!$connection->finalizeUpdate()->success) { throw new \Exception("Update for site failed in postprocessing: " . $this->site->id); } + + // Compare codes + if ($this->site->getFrontendStatus() !== $this->preUpdateCode) { + throw new \Exception("Status code has changed after update for site: " . $this->site->id); + } } protected function performExtraction(PrepareUpdate $prepareResult): void