From 07781cc8e5f147609f2960a5a9e31152f5eaaa72 Mon Sep 17 00:00:00 2001 From: Robert Deutz Date: Sat, 16 Nov 2024 13:15:06 +0100 Subject: [PATCH 01/12] base and register --- .../Controllers/Api/V1/SiteController.php | 82 ++++++++++++++++++ app/Http/Resources/Site.php | 19 +++++ app/Http/Resources/SiteCollection.php | 19 +++++ app/Traits/ApiResponse.php | 28 +++++++ bootstrap/app.php | 1 + composer.json | 1 + composer.lock | 66 ++++++++++++++- config/sanctum.php | 83 +++++++++++++++++++ ...41_create_personal_access_tokens_table.php | 33 ++++++++ routes/api.php | 14 ++++ 10 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 app/Http/Controllers/Api/V1/SiteController.php create mode 100644 app/Http/Resources/Site.php create mode 100644 app/Http/Resources/SiteCollection.php create mode 100644 app/Traits/ApiResponse.php create mode 100644 config/sanctum.php create mode 100644 database/migrations/2024_11_16_094841_create_personal_access_tokens_table.php create mode 100644 routes/api.php diff --git a/app/Http/Controllers/Api/V1/SiteController.php b/app/Http/Controllers/Api/V1/SiteController.php new file mode 100644 index 0000000..db95eec --- /dev/null +++ b/app/Http/Controllers/Api/V1/SiteController.php @@ -0,0 +1,82 @@ +input('url'); + $key = $request->input('key'); + + if (empty($url) || empty($key)) { + return $this->error('BadRequest'); + } + + $connectionService = new SiteConnectionService($url, $key); + + // Do a health check + try{ + $connectionService->checkHealth(); + } catch (ServerException $e) { + return $this->error($e->getMessage(), 500); + } catch (ClientException|\Exception $e) { + return $this->error($e->getMessage()); + } + + // If successful save site + $site = new Site; + + $site->key = $key; + $site->url = $url; + + CheckSiteHealth::dispatch($site); + + return $this->ok(); + } + + /** + * @param Request $request + * + * @return JsonResponse + */ + public function check(Request $request): JsonResponse + { + + + return response()->json(['check']); + } + + /** + * @param Request $request + * + * @return JsonResponse + */ + public function delete(Request $request): JsonResponse + { + return response()->json(['delete']); + } +} diff --git a/app/Http/Resources/Site.php b/app/Http/Resources/Site.php new file mode 100644 index 0000000..8a302cf --- /dev/null +++ b/app/Http/Resources/Site.php @@ -0,0 +1,19 @@ + + */ + public function toArray(Request $request): array + { + return parent::toArray($request); + } +} diff --git a/app/Http/Resources/SiteCollection.php b/app/Http/Resources/SiteCollection.php new file mode 100644 index 0000000..38582a9 --- /dev/null +++ b/app/Http/Resources/SiteCollection.php @@ -0,0 +1,19 @@ + + */ + public function toArray(Request $request): array + { + return parent::toArray($request); + } +} diff --git a/app/Traits/ApiResponse.php b/app/Traits/ApiResponse.php new file mode 100644 index 0000000..64ce83f --- /dev/null +++ b/app/Traits/ApiResponse.php @@ -0,0 +1,28 @@ +success($message, 200); + } + + protected function success($message, $statusCode = 200) + { + return $this->response($message, $statusCode); + } + + protected function error($message, $statusCode = 400) + { + return $this->response($message, $statusCode); + } + + protected function response($message, $statusCode = 200) + { + return response()->json([ + 'message' => $message, + 'status' => $statusCode + ], $statusCode); + } +} diff --git a/bootstrap/app.php b/bootstrap/app.php index 36e7dd8..0be620c 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -7,6 +7,7 @@ return Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__.'/../routes/web.php', + api: __DIR__.'/../routes/api.php', commands: __DIR__.'/../routes/console.php', health: '/up', ) diff --git a/composer.json b/composer.json index 6d5fa5f..66e82c9 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "laravel/framework": "^11.9", "laravel/horizon": "^5.29", "laravel/octane": "^2.5", + "laravel/sanctum": "^4.0", "laravel/tinker": "^2.9" }, "require-dev": { diff --git a/composer.lock b/composer.lock index c069a73..ac7e110 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "34c997ee01aff538ce065acd047bca2d", + "content-hash": "d8b007a2471bdb43f04211cd5a970305", "packages": [ { "name": "brick/math", @@ -1580,6 +1580,70 @@ }, "time": "2024-11-12T14:59:47+00:00" }, + { + "name": "laravel/sanctum", + "version": "v4.0.3", + "source": { + "type": "git", + "url": "https://github.com/laravel/sanctum.git", + "reference": "54aea9d13743ae8a6cdd3c28dbef128a17adecab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/54aea9d13743ae8a6cdd3c28dbef128a17adecab", + "reference": "54aea9d13743ae8a6cdd3c28dbef128a17adecab", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/console": "^11.0", + "illuminate/contracts": "^11.0", + "illuminate/database": "^11.0", + "illuminate/support": "^11.0", + "php": "^8.2", + "symfony/console": "^7.0" + }, + "require-dev": { + "mockery/mockery": "^1.6", + "orchestra/testbench": "^9.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Sanctum\\SanctumServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sanctum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.", + "keywords": [ + "auth", + "laravel", + "sanctum" + ], + "support": { + "issues": "https://github.com/laravel/sanctum/issues", + "source": "https://github.com/laravel/sanctum" + }, + "time": "2024-09-27T14:55:41+00:00" + }, { "name": "laravel/serializable-closure", "version": "v1.3.6", diff --git a/config/sanctum.php b/config/sanctum.php new file mode 100644 index 0000000..764a82f --- /dev/null +++ b/config/sanctum.php @@ -0,0 +1,83 @@ + explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( + '%s%s', + 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', + Sanctum::currentApplicationUrlWithPort() + ))), + + /* + |-------------------------------------------------------------------------- + | Sanctum Guards + |-------------------------------------------------------------------------- + | + | This array contains the authentication guards that will be checked when + | Sanctum is trying to authenticate a request. If none of these guards + | are able to authenticate the request, Sanctum will use the bearer + | token that's present on an incoming request for authentication. + | + */ + + 'guard' => ['web'], + + /* + |-------------------------------------------------------------------------- + | Expiration Minutes + |-------------------------------------------------------------------------- + | + | This value controls the number of minutes until an issued token will be + | considered expired. This will override any values set in the token's + | "expires_at" attribute, but first-party sessions are not affected. + | + */ + + 'expiration' => null, + + /* + |-------------------------------------------------------------------------- + | Token Prefix + |-------------------------------------------------------------------------- + | + | Sanctum can prefix new tokens in order to take advantage of numerous + | security scanning initiatives maintained by open source platforms + | that notify developers if they commit tokens into repositories. + | + | See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning + | + */ + + 'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''), + + /* + |-------------------------------------------------------------------------- + | Sanctum Middleware + |-------------------------------------------------------------------------- + | + | When authenticating your first-party SPA with Sanctum you may need to + | customize some of the middleware Sanctum uses while processing the + | request. You may change the middleware listed below as required. + | + */ + + 'middleware' => [ + 'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class, + 'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class, + 'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, + ], + +]; diff --git a/database/migrations/2024_11_16_094841_create_personal_access_tokens_table.php b/database/migrations/2024_11_16_094841_create_personal_access_tokens_table.php new file mode 100644 index 0000000..e828ad8 --- /dev/null +++ b/database/migrations/2024_11_16_094841_create_personal_access_tokens_table.php @@ -0,0 +1,33 @@ +id(); + $table->morphs('tokenable'); + $table->string('name'); + $table->string('token', 64)->unique(); + $table->text('abilities')->nullable(); + $table->timestamp('last_used_at')->nullable(); + $table->timestamp('expires_at')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('personal_access_tokens'); + } +}; diff --git a/routes/api.php b/routes/api.php new file mode 100644 index 0000000..832f3b0 --- /dev/null +++ b/routes/api.php @@ -0,0 +1,14 @@ +group(function () { + Route::controller(SiteController::class)->group(function () { + Route::get('register', 'register'); + Route::get('check/{hase}', 'check'); + Route::delete('delete/{hash}', 'delete'); + }); +}); + From fde98c0c07a2ff839cf914d11f360b7425b0fdfe Mon Sep 17 00:00:00 2001 From: Robert Deutz Date: Sat, 16 Nov 2024 13:25:45 +0100 Subject: [PATCH 02/12] fix cs and phpstan --- app/Http/Controllers/Api/V1/SiteController.php | 8 ++++---- app/Traits/ApiResponse.php | 3 ++- ...4_11_16_094841_create_personal_access_tokens_table.php | 3 +-- routes/api.php | 2 -- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/Api/V1/SiteController.php b/app/Http/Controllers/Api/V1/SiteController.php index db95eec..3af5e3a 100644 --- a/app/Http/Controllers/Api/V1/SiteController.php +++ b/app/Http/Controllers/Api/V1/SiteController.php @@ -5,7 +5,7 @@ use App\Http\Controllers\Controller; use App\Jobs\CheckSiteHealth; use App\Models\Site; -use App\Services\SiteConnectionService; +use App\RemoteSite\Connection; use App\Traits\ApiResponse; use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Exception\ServerException; @@ -36,10 +36,10 @@ public function register(Request $request): JsonResponse return $this->error('BadRequest'); } - $connectionService = new SiteConnectionService($url, $key); + $connectionService = new Connection($url, $key); // Do a health check - try{ + try { $connectionService->checkHealth(); } catch (ServerException $e) { return $this->error($e->getMessage(), 500); @@ -48,7 +48,7 @@ public function register(Request $request): JsonResponse } // If successful save site - $site = new Site; + $site = new Site(); $site->key = $key; $site->url = $url; diff --git a/app/Traits/ApiResponse.php b/app/Traits/ApiResponse.php index 64ce83f..735141b 100644 --- a/app/Traits/ApiResponse.php +++ b/app/Traits/ApiResponse.php @@ -4,7 +4,8 @@ trait ApiResponse { - protected function ok($message = 'OK') { + protected function ok($message = 'OK') + { return $this->success($message, 200); } diff --git a/database/migrations/2024_11_16_094841_create_personal_access_tokens_table.php b/database/migrations/2024_11_16_094841_create_personal_access_tokens_table.php index e828ad8..668cd96 100644 --- a/database/migrations/2024_11_16_094841_create_personal_access_tokens_table.php +++ b/database/migrations/2024_11_16_094841_create_personal_access_tokens_table.php @@ -4,8 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class extends Migration -{ +return new class () extends Migration { /** * Run the migrations. */ diff --git a/routes/api.php b/routes/api.php index 832f3b0..ac53a95 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,7 +1,6 @@ group(function () { @@ -11,4 +10,3 @@ Route::delete('delete/{hash}', 'delete'); }); }); - From 023714b5ba7c78300ddc4297148591428e13a202 Mon Sep 17 00:00:00 2001 From: Robert Deutz Date: Sat, 16 Nov 2024 13:49:13 +0100 Subject: [PATCH 03/12] remove package --- composer.json | 1 - composer.lock | 66 +-------------- config/sanctum.php | 83 ------------------- ...41_create_personal_access_tokens_table.php | 32 ------- 4 files changed, 1 insertion(+), 181 deletions(-) delete mode 100644 config/sanctum.php delete mode 100644 database/migrations/2024_11_16_094841_create_personal_access_tokens_table.php diff --git a/composer.json b/composer.json index 66e82c9..6d5fa5f 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,6 @@ "laravel/framework": "^11.9", "laravel/horizon": "^5.29", "laravel/octane": "^2.5", - "laravel/sanctum": "^4.0", "laravel/tinker": "^2.9" }, "require-dev": { diff --git a/composer.lock b/composer.lock index ac7e110..c069a73 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d8b007a2471bdb43f04211cd5a970305", + "content-hash": "34c997ee01aff538ce065acd047bca2d", "packages": [ { "name": "brick/math", @@ -1580,70 +1580,6 @@ }, "time": "2024-11-12T14:59:47+00:00" }, - { - "name": "laravel/sanctum", - "version": "v4.0.3", - "source": { - "type": "git", - "url": "https://github.com/laravel/sanctum.git", - "reference": "54aea9d13743ae8a6cdd3c28dbef128a17adecab" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laravel/sanctum/zipball/54aea9d13743ae8a6cdd3c28dbef128a17adecab", - "reference": "54aea9d13743ae8a6cdd3c28dbef128a17adecab", - "shasum": "" - }, - "require": { - "ext-json": "*", - "illuminate/console": "^11.0", - "illuminate/contracts": "^11.0", - "illuminate/database": "^11.0", - "illuminate/support": "^11.0", - "php": "^8.2", - "symfony/console": "^7.0" - }, - "require-dev": { - "mockery/mockery": "^1.6", - "orchestra/testbench": "^9.0", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^10.5" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "Laravel\\Sanctum\\SanctumServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "Laravel\\Sanctum\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.", - "keywords": [ - "auth", - "laravel", - "sanctum" - ], - "support": { - "issues": "https://github.com/laravel/sanctum/issues", - "source": "https://github.com/laravel/sanctum" - }, - "time": "2024-09-27T14:55:41+00:00" - }, { "name": "laravel/serializable-closure", "version": "v1.3.6", diff --git a/config/sanctum.php b/config/sanctum.php deleted file mode 100644 index 764a82f..0000000 --- a/config/sanctum.php +++ /dev/null @@ -1,83 +0,0 @@ - explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( - '%s%s', - 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', - Sanctum::currentApplicationUrlWithPort() - ))), - - /* - |-------------------------------------------------------------------------- - | Sanctum Guards - |-------------------------------------------------------------------------- - | - | This array contains the authentication guards that will be checked when - | Sanctum is trying to authenticate a request. If none of these guards - | are able to authenticate the request, Sanctum will use the bearer - | token that's present on an incoming request for authentication. - | - */ - - 'guard' => ['web'], - - /* - |-------------------------------------------------------------------------- - | Expiration Minutes - |-------------------------------------------------------------------------- - | - | This value controls the number of minutes until an issued token will be - | considered expired. This will override any values set in the token's - | "expires_at" attribute, but first-party sessions are not affected. - | - */ - - 'expiration' => null, - - /* - |-------------------------------------------------------------------------- - | Token Prefix - |-------------------------------------------------------------------------- - | - | Sanctum can prefix new tokens in order to take advantage of numerous - | security scanning initiatives maintained by open source platforms - | that notify developers if they commit tokens into repositories. - | - | See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning - | - */ - - 'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''), - - /* - |-------------------------------------------------------------------------- - | Sanctum Middleware - |-------------------------------------------------------------------------- - | - | When authenticating your first-party SPA with Sanctum you may need to - | customize some of the middleware Sanctum uses while processing the - | request. You may change the middleware listed below as required. - | - */ - - 'middleware' => [ - 'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class, - 'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class, - 'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, - ], - -]; diff --git a/database/migrations/2024_11_16_094841_create_personal_access_tokens_table.php b/database/migrations/2024_11_16_094841_create_personal_access_tokens_table.php deleted file mode 100644 index 668cd96..0000000 --- a/database/migrations/2024_11_16_094841_create_personal_access_tokens_table.php +++ /dev/null @@ -1,32 +0,0 @@ -id(); - $table->morphs('tokenable'); - $table->string('name'); - $table->string('token', 64)->unique(); - $table->text('abilities')->nullable(); - $table->timestamp('last_used_at')->nullable(); - $table->timestamp('expires_at')->nullable(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('personal_access_tokens'); - } -}; From f96e574cec1aea00485567cddd0c1c3422bc80d4 Mon Sep 17 00:00:00 2001 From: Robert Deutz Date: Sat, 16 Nov 2024 13:49:41 +0100 Subject: [PATCH 04/12] type check --- app/Http/Controllers/Api/V1/SiteController.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Api/V1/SiteController.php b/app/Http/Controllers/Api/V1/SiteController.php index 3af5e3a..46533ca 100644 --- a/app/Http/Controllers/Api/V1/SiteController.php +++ b/app/Http/Controllers/Api/V1/SiteController.php @@ -29,10 +29,10 @@ class SiteController extends Controller */ public function register(Request $request): JsonResponse { - $url = $request->input('url'); - $key = $request->input('key'); + $url = $request->string('url'); + $key = $request->string('key'); - if (empty($url) || empty($key)) { + if ($url === '' && $key === '') { return $this->error('BadRequest'); } From 464f231a41ed672b5c36e9aa21fd2f13a246d158 Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 13:23:21 +0100 Subject: [PATCH 05/12] Fix cs --- app/Enum/WebserviceEndpoint.php | 8 ++++---- app/Jobs/CheckSiteHealth.php | 14 +++----------- app/Jobs/UpdateSite.php | 2 +- app/Models/Site.php | 2 +- app/RemoteSite/Connection.php | 7 +++---- app/RemoteSite/Responses/BaseResponse.php | 7 ++++++- 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/app/Enum/WebserviceEndpoint.php b/app/Enum/WebserviceEndpoint.php index f77efa3..d5165a5 100644 --- a/app/Enum/WebserviceEndpoint.php +++ b/app/Enum/WebserviceEndpoint.php @@ -4,8 +4,8 @@ enum WebserviceEndpoint: string { - case HEALTH_CHECK = "/api/index.php/v1/updates/health"; - case FETCH_UPDATES = "/api/index.php/v1/updates/fetch"; - case PREPARE_UPDATE = "/api/index.php/v1/updates/prepare"; - case FINALIZE_UPDATE = "/api/index.php/v1/updates/finalize"; + 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"; } diff --git a/app/Jobs/CheckSiteHealth.php b/app/Jobs/CheckSiteHealth.php index b922d2e..7cc38d3 100644 --- a/app/Jobs/CheckSiteHealth.php +++ b/app/Jobs/CheckSiteHealth.php @@ -5,7 +5,7 @@ namespace App\Jobs; use App\Models\Site; -use app\Remotesite\Connection; +use App\RemoteSite\Connection; use Carbon\Carbon; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Queue\Queueable; @@ -29,19 +29,11 @@ public function handle(): void /** @var Connection $connection */ $connection = $this->site->connection; - $response = $connection->checkHealth(); - - $healthData = collect($response); + $healthData = $connection->checkHealth(); // Write updated data to DB $this->site->fill( - $healthData->only([ - 'php_version', - 'db_type', - 'db_version', - 'cms_version', - 'server_os' - ])->toArray() + $healthData->toArray() ); // @phpstan-ignore-next-line diff --git a/app/Jobs/UpdateSite.php b/app/Jobs/UpdateSite.php index 1f54eb3..5fb1211 100644 --- a/app/Jobs/UpdateSite.php +++ b/app/Jobs/UpdateSite.php @@ -5,7 +5,7 @@ namespace App\Jobs; use App\Models\Site; -use app\Remotesite\Connection; +use App\RemoteSite\Connection; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Queue\Queueable; diff --git a/app/Models/Site.php b/app/Models/Site.php index d9f20bb..90290c1 100644 --- a/app/Models/Site.php +++ b/app/Models/Site.php @@ -4,7 +4,7 @@ namespace App\Models; -use App\Remotesite\Connection; +use App\RemoteSite\Connection; use Illuminate\Database\Eloquent\Model; class Site extends Model diff --git a/app/RemoteSite/Connection.php b/app/RemoteSite/Connection.php index f95f121..e526484 100644 --- a/app/RemoteSite/Connection.php +++ b/app/RemoteSite/Connection.php @@ -6,7 +6,6 @@ use App\Enum\HttpMethod; use App\Enum\WebserviceEndpoint; -use App\RemoteSite\Responses\HealthCheck; use App\RemoteSite\Responses\HealthCheck as HealthCheckResponse; use GuzzleHttp\Client; use GuzzleHttp\Exception\RequestException; @@ -21,14 +20,14 @@ public function __construct(protected readonly string $baseUrl, protected readon { } - public function checkHealth(): HealthCheck + public function checkHealth(): HealthCheckResponse { $healthData = $this->performWebserviceRequest( HttpMethod::GET, WebserviceEndpoint::HEALTH_CHECK ); - return HealthCheckResponse::from($healthData); + return HealthCheckResponse::from($healthData['data']['attributes']); } public function performExtractionRequest(array $data): array @@ -58,7 +57,7 @@ protected function performWebserviceRequest( $method->name, $this->baseUrl . $endpoint->value, [ - 'Authorization' => 'JUpdate-Token ' . $this->key + 'X-JUpdate-Token' => $this->key ] ); diff --git a/app/RemoteSite/Responses/BaseResponse.php b/app/RemoteSite/Responses/BaseResponse.php index 54de2e2..053b5fa 100644 --- a/app/RemoteSite/Responses/BaseResponse.php +++ b/app/RemoteSite/Responses/BaseResponse.php @@ -4,7 +4,7 @@ abstract class BaseResponse { - public static function from(array $data): self + public static function from(array $data): static { $reflect = new \ReflectionClass(static::class); $properties = $reflect->getProperties(\ReflectionProperty::IS_PUBLIC); @@ -21,4 +21,9 @@ public static function from(array $data): self return $reflect->newInstanceArgs($arguments); } + + public function toArray(): array + { + return get_object_vars($this); + } } From 3a09bb24c58a3687ff5197850015e7d98ed32463 Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 13:35:19 +0100 Subject: [PATCH 06/12] deduplicate calls --- app/RemoteSite/Connection.php | 46 ++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/app/RemoteSite/Connection.php b/app/RemoteSite/Connection.php index e526484..8b1534f 100644 --- a/app/RemoteSite/Connection.php +++ b/app/RemoteSite/Connection.php @@ -30,7 +30,7 @@ public function checkHealth(): HealthCheckResponse return HealthCheckResponse::from($healthData['data']['attributes']); } - public function performExtractionRequest(array $data): array + public function performExtractionRequest(array $requestData): array { $request = new Request( 'POST', @@ -39,19 +39,24 @@ public function performExtractionRequest(array $data): array $data['password'] = $this->key; - return $this->performHttpRequest( + // Get result + $response = $this->performHttpRequest( $request, [ - 'form_params' => $data, + 'form_params' => $requestData, 'timeout' => 300.0 ] ); + + $responseData = $this->decodeResponse($response, $request); + + return $responseData; } protected function performWebserviceRequest( HttpMethod $method, WebserviceEndpoint $endpoint, - array $data = [] + array $requestData = [] ): array { $request = new Request( $method->name, @@ -61,18 +66,32 @@ protected function performWebserviceRequest( ] ); - return $this->performHttpRequest( + // Get result + $response = $this->performHttpRequest( $request, [ - "json" => $data + "json" => $requestData ] ); + + $responseData = $this->decodeResponse($response, $request); + + // Make sure it matches the Joomla webservice response format + if (empty($responseData['data']['attributes'])) { + throw new RequestException( + "Invalid JSON format", + $request, + $response + ); + } + + return $responseData; } protected function performHttpRequest( RequestInterface $request, array $options = [] - ): array { + ): Response { /** @var Client $httpClient */ $httpClient = App::make(Client::class); @@ -91,8 +110,13 @@ protected function performHttpRequest( ); } - // Decode body - $return = json_decode( + return $response; + } + + protected function decodeResponse(Response $response, Request $request): array + { + // Decode + $data = json_decode( (string) $response->getBody(), true, 512, @@ -100,7 +124,7 @@ protected function performHttpRequest( ); // Make sure it's an array - if (!is_array($return)) { + if (!is_array($data)) { throw new RequestException( "Invalid JSON body", $request, @@ -108,6 +132,6 @@ protected function performHttpRequest( ); } - return $return; + return $data; } } From a4ed09c9a4bc589ca6b6b66610e8f88a846c0686 Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 13:46:13 +0100 Subject: [PATCH 07/12] move base dto --- .../Responses/BaseResponse.php => DTO/BaseDTO.php} | 4 ++-- app/RemoteSite/Responses/HealthCheck.php | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) rename app/{RemoteSite/Responses/BaseResponse.php => DTO/BaseDTO.php} (90%) diff --git a/app/RemoteSite/Responses/BaseResponse.php b/app/DTO/BaseDTO.php similarity index 90% rename from app/RemoteSite/Responses/BaseResponse.php rename to app/DTO/BaseDTO.php index 053b5fa..a1470fb 100644 --- a/app/RemoteSite/Responses/BaseResponse.php +++ b/app/DTO/BaseDTO.php @@ -1,8 +1,8 @@ Date: Sat, 16 Nov 2024 13:52:37 +0100 Subject: [PATCH 08/12] save site --- app/Http/Controllers/Api/V1/SiteController.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Http/Controllers/Api/V1/SiteController.php b/app/Http/Controllers/Api/V1/SiteController.php index 46533ca..ba1262d 100644 --- a/app/Http/Controllers/Api/V1/SiteController.php +++ b/app/Http/Controllers/Api/V1/SiteController.php @@ -53,6 +53,8 @@ public function register(Request $request): JsonResponse $site->key = $key; $site->url = $url; + $site->save(); + CheckSiteHealth::dispatch($site); return $this->ok(); From b4331a6736230334afbe4a3522f06d5e278c171b Mon Sep 17 00:00:00 2001 From: Robert Deutz Date: Sat, 16 Nov 2024 14:07:55 +0100 Subject: [PATCH 09/12] stan fix --- app/Http/Resources/Site.php | 19 -------------- app/Http/Resources/SiteCollection.php | 19 -------------- app/Traits/ApiResponse.php | 36 ++++++++++++++++++++++++--- 3 files changed, 32 insertions(+), 42 deletions(-) delete mode 100644 app/Http/Resources/Site.php delete mode 100644 app/Http/Resources/SiteCollection.php diff --git a/app/Http/Resources/Site.php b/app/Http/Resources/Site.php deleted file mode 100644 index 8a302cf..0000000 --- a/app/Http/Resources/Site.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ - public function toArray(Request $request): array - { - return parent::toArray($request); - } -} diff --git a/app/Http/Resources/SiteCollection.php b/app/Http/Resources/SiteCollection.php deleted file mode 100644 index 38582a9..0000000 --- a/app/Http/Resources/SiteCollection.php +++ /dev/null @@ -1,19 +0,0 @@ - - */ - public function toArray(Request $request): array - { - return parent::toArray($request); - } -} diff --git a/app/Traits/ApiResponse.php b/app/Traits/ApiResponse.php index 735141b..afda856 100644 --- a/app/Traits/ApiResponse.php +++ b/app/Traits/ApiResponse.php @@ -2,24 +2,52 @@ namespace App\Traits; +use Illuminate\Http\JsonResponse; + +/** + * Api Response + */ trait ApiResponse { - protected function ok($message = 'OK') + /** + * @param $message + * + * @return JsonResponse + */ + protected function ok($message = 'OK'): JsonResponse { return $this->success($message, 200); } - protected function success($message, $statusCode = 200) + /** + * @param $message + * @param $statusCode + * + * @return JsonResponse + */ + protected function success($message, $statusCode = 200): JsonResponse { return $this->response($message, $statusCode); } - protected function error($message, $statusCode = 400) + /** + * @param $message + * @param $statusCode + * + * @return JsonResponse + */ + protected function error($message, $statusCode = 400): JsonResponse { return $this->response($message, $statusCode); } - protected function response($message, $statusCode = 200) + /** + * @param $message + * @param $statusCode + * + * @return JsonResponse + */ + protected function response($message, $statusCode = 200): JsonResponse { return response()->json([ 'message' => $message, From 33ba90503c5f8ae4f9913e13170521270fa56468 Mon Sep 17 00:00:00 2001 From: Robert Deutz Date: Sat, 16 Nov 2024 14:13:50 +0100 Subject: [PATCH 10/12] types --- .../Controllers/Api/V1/SiteController.php | 4 +--- app/Traits/ApiResponse.php | 22 +++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/app/Http/Controllers/Api/V1/SiteController.php b/app/Http/Controllers/Api/V1/SiteController.php index ba1262d..85652a3 100644 --- a/app/Http/Controllers/Api/V1/SiteController.php +++ b/app/Http/Controllers/Api/V1/SiteController.php @@ -32,7 +32,7 @@ public function register(Request $request): JsonResponse $url = $request->string('url'); $key = $request->string('key'); - if ($url === '' && $key === '') { + if ($url->isEmpty() && $key->isEmpty()) { return $this->error('BadRequest'); } @@ -67,8 +67,6 @@ public function register(Request $request): JsonResponse */ public function check(Request $request): JsonResponse { - - return response()->json(['check']); } diff --git a/app/Traits/ApiResponse.php b/app/Traits/ApiResponse.php index afda856..a619d73 100644 --- a/app/Traits/ApiResponse.php +++ b/app/Traits/ApiResponse.php @@ -10,44 +10,44 @@ trait ApiResponse { /** - * @param $message + * @param string $message * * @return JsonResponse */ - protected function ok($message = 'OK'): JsonResponse + protected function ok(string $message = 'OK'): JsonResponse { return $this->success($message, 200); } /** - * @param $message - * @param $statusCode + * @param string $message + * @param int $statusCode * * @return JsonResponse */ - protected function success($message, $statusCode = 200): JsonResponse + protected function success(string $message, int $statusCode = 200): JsonResponse { return $this->response($message, $statusCode); } /** - * @param $message - * @param $statusCode + * @param string $message + * @param int $statusCode * * @return JsonResponse */ - protected function error($message, $statusCode = 400): JsonResponse + protected function error(string $message, int $statusCode = 400): JsonResponse { return $this->response($message, $statusCode); } /** - * @param $message - * @param $statusCode + * @param string $message + * @param int $statusCode * * @return JsonResponse */ - protected function response($message, $statusCode = 200): JsonResponse + protected function response(string $message, int $statusCode = 200): JsonResponse { return response()->json([ 'message' => $message, From d241969cd21432f52a251c1eb61c857efd049a4b Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 14:26:24 +0100 Subject: [PATCH 11/12] fix nullable error on write --- app/Http/Controllers/Api/V1/SiteController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/V1/SiteController.php b/app/Http/Controllers/Api/V1/SiteController.php index 85652a3..63ca89c 100644 --- a/app/Http/Controllers/Api/V1/SiteController.php +++ b/app/Http/Controllers/Api/V1/SiteController.php @@ -40,7 +40,7 @@ public function register(Request $request): JsonResponse // Do a health check try { - $connectionService->checkHealth(); + $healthResponse = $connectionService->checkHealth(); } catch (ServerException $e) { return $this->error($e->getMessage(), 500); } catch (ClientException|\Exception $e) { @@ -52,6 +52,7 @@ public function register(Request $request): JsonResponse $site->key = $key; $site->url = $url; + $site->fill($healthResponse->toArray()); $site->save(); From 4d5d54efe3369e3b5412f143604f9fd826947fc3 Mon Sep 17 00:00:00 2001 From: David Jardin Date: Sat, 16 Nov 2024 14:28:31 +0100 Subject: [PATCH 12/12] push last_seen --- app/Http/Controllers/Api/V1/SiteController.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Http/Controllers/Api/V1/SiteController.php b/app/Http/Controllers/Api/V1/SiteController.php index 63ca89c..1a7351a 100644 --- a/app/Http/Controllers/Api/V1/SiteController.php +++ b/app/Http/Controllers/Api/V1/SiteController.php @@ -7,6 +7,7 @@ use App\Models\Site; use App\RemoteSite\Connection; use App\Traits\ApiResponse; +use Carbon\Carbon; use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Exception\ServerException; use Illuminate\Http\JsonResponse; @@ -52,6 +53,9 @@ public function register(Request $request): JsonResponse $site->key = $key; $site->url = $url; + $site->last_seen = Carbon::now(); + + // Fill with site info $site->fill($healthResponse->toArray()); $site->save();