diff --git a/app/Filament/Pages/Auth/Settings.php b/app/Filament/Pages/Auth/Settings.php index fed6b3a..debe18e 100644 --- a/app/Filament/Pages/Auth/Settings.php +++ b/app/Filament/Pages/Auth/Settings.php @@ -4,6 +4,7 @@ namespace App\Filament\Pages\Auth; +use Filament\Forms\Components\Hidden; use Filament\Forms\Components\TextInput; use JeffGreco13\FilamentBreezy\Pages\MyProfile; @@ -41,4 +42,15 @@ protected function getUpdateProfileFormSchema(): array ->label(__('user.field.email')), ]; } + + protected function getCreateApiTokenFormSchema(): array + { + return [ + TextInput::make('token_name') + ->label(__('filament-breezy::default.fields.token_name')) + ->required(), + + Hidden::make('abilities'), + ]; + } } diff --git a/app/Http/Controllers/OrganisationController.php b/app/Http/Controllers/OrganisationController.php index a4086bf..286ffc3 100644 --- a/app/Http/Controllers/OrganisationController.php +++ b/app/Http/Controllers/OrganisationController.php @@ -6,11 +6,14 @@ use App\Http\Resources\OrganisationResource; use App\Models\Organisation; +use Illuminate\Http\Resources\Json\JsonResource; class OrganisationController extends Controller { - public function __invoke() + public function __invoke(): JsonResource { + $this->authorize('accessApi'); + return OrganisationResource::collection( Organisation::query() ->withoutEagerLoads(['city']) diff --git a/app/Http/Controllers/ResourceController.php b/app/Http/Controllers/ResourceController.php index e236558..5c8e8cb 100644 --- a/app/Http/Controllers/ResourceController.php +++ b/app/Http/Controllers/ResourceController.php @@ -6,11 +6,14 @@ use App\Http\Resources\ResourceResource; use App\Models\Resource; +use Illuminate\Http\Resources\Json\JsonResource; class ResourceController extends Controller { - public function __invoke() + public function __invoke(): JsonResource { + $this->authorize('accessApi'); + return ResourceResource::collection( Resource::query() ->with([ diff --git a/app/Http/Resources/IdAndNameResource.php b/app/Http/Resources/IdAndNameResource.php index cc80aa9..a89bfa0 100644 --- a/app/Http/Resources/IdAndNameResource.php +++ b/app/Http/Resources/IdAndNameResource.php @@ -1,5 +1,7 @@ $this->id, - 'name' => $this->name + 'id' => (int) $this->id, + 'name' => $this->name, ]; } } diff --git a/app/Http/Resources/OrganisationResource.php b/app/Http/Resources/OrganisationResource.php index aad9df3..dbea7dd 100644 --- a/app/Http/Resources/OrganisationResource.php +++ b/app/Http/Resources/OrganisationResource.php @@ -17,7 +17,7 @@ class OrganisationResource extends JsonResource public function toArray(Request $request): array { return [ - 'id' => $this->id, + 'id' => (int) $this->id, 'name' => $this->name, 'type' => $this->type, 'status' => $this->status, @@ -29,7 +29,7 @@ public function toArray(Request $request): array 'activity_counties' => IdAndNameResource::collection($this->activityCounties), 'created_at' => $this->created_at->format('Y-m-d H:i:s'), 'updated_at' => $this->updated_at->format('Y-m-d H:i:s'), - 'volunteers_count' => $this->volunteers_count, + 'volunteers_count' => (int) $this->volunteers_count, ]; } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 1fe21eb..976dcfc 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -6,6 +6,9 @@ use App\Filament\Pages\Auth\Settings; use Carbon\Carbon; +use Dedoc\Scramble\Scramble; +use Dedoc\Scramble\Support\Generator\OpenApi; +use Dedoc\Scramble\Support\Generator\SecurityScheme; use Filament\Facades\Filament; use Filament\Navigation\UserMenuItem; use Illuminate\Database\Eloquent\Model; @@ -52,6 +55,12 @@ public function boot() ->icon('heroicon-o-cog'), ]); }); + + Scramble::extendOpenApi(function (OpenApi $openApi) { + $openApi->secure( + SecurityScheme::http('bearer', 'JWT') + ); + }); } public function registerReleaseVersion(): void diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index b461baf..6264f52 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -4,10 +4,12 @@ namespace App\Providers; +use App\Models\User; use Illuminate\Auth\EloquentUserProvider; use Illuminate\Database\Eloquent\Builder; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Gate; class AuthServiceProvider extends ServiceProvider { @@ -33,5 +35,13 @@ public function boot() return (new EloquentUserProvider($app['hash'], $config['model'])) ->withQuery(fn (Builder $query) => $query->withoutGlobalScopes()); }); + + Gate::define('accessApi', function (User $user) { + if (! config('filament-breezy.enable_sanctum')) { + return false; + } + + return $user->isPlatformAdmin(); + }); } } diff --git a/composer.json b/composer.json index 57af909..c4df8f1 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,7 @@ "require": { "php": "^8.1", "alcea/cnp": "^3.0", + "dedoc/scramble": "^0.8.5", "filament/filament": "^2.17", "filament/spatie-laravel-media-library-plugin": "^2.17", "guzzlehttp/guzzle": "^7.8", diff --git a/composer.lock b/composer.lock index 73afe8f..b3f69af 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": "e9b4bb95a4e6694ebfbd2633e0586d9a", + "content-hash": "79a19b0d407e1357a655d548caaa5847", "packages": [ { "name": "akaunting/laravel-money", @@ -908,6 +908,81 @@ }, "time": "2023-08-25T16:18:39+00:00" }, + { + "name": "dedoc/scramble", + "version": "v0.8.5", + "source": { + "type": "git", + "url": "https://github.com/dedoc/scramble.git", + "reference": "cc61cc79843c6e2206dc5d0f15ae705494de8249" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dedoc/scramble/zipball/cc61cc79843c6e2206dc5d0f15ae705494de8249", + "reference": "cc61cc79843c6e2206dc5d0f15ae705494de8249", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^8.0.0|^9.0.0|^10.0.0", + "nikic/php-parser": "^4.0", + "php": "^8.1", + "phpstan/phpdoc-parser": "^1.0", + "spatie/laravel-package-tools": "^1.9.2" + }, + "require-dev": { + "doctrine/dbal": "^3.4", + "laravel/pint": "^v1.1.0", + "nunomaduro/collision": "^5.0|^v6.0", + "orchestra/testbench": "^6.0|^7.0|^8.0", + "pestphp/pest": "^1.21", + "pestphp/pest-plugin-laravel": "^1.2", + "phpunit/phpunit": "^9.5", + "spatie/pest-plugin-snapshots": "^1.1" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Dedoc\\Scramble\\ScrambleServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Dedoc\\Scramble\\": "src", + "Dedoc\\Scramble\\Database\\Factories\\": "database/factories" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Lytvynenko", + "email": "litvinenko95@gmail.com", + "role": "Developer" + } + ], + "description": "Automatic generation of API documentation for Laravel applications.", + "homepage": "https://github.com/dedoc/scramble", + "keywords": [ + "documentation", + "laravel", + "openapi" + ], + "support": { + "issues": "https://github.com/dedoc/scramble/issues", + "source": "https://github.com/dedoc/scramble/tree/v0.8.5" + }, + "funding": [ + { + "url": "https://github.com/romalytvynenko", + "type": "github" + } + ], + "time": "2023-12-02T09:58:18+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.2", @@ -4773,6 +4848,53 @@ ], "time": "2023-11-12T21:59:55+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.24.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "12f01d214f1c73b9c91fdb3b1c415e4c70652083" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/12f01d214f1c73b9c91fdb3b1c415e4c70652083", + "reference": "12f01d214f1c73b9c91fdb3b1c415e4c70652083", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.3" + }, + "time": "2023-11-18T20:15:32+00:00" + }, { "name": "pragmarx/google2fa", "version": "v8.0.1", @@ -11648,53 +11770,6 @@ }, "time": "2023-08-12T11:01:26+00:00" }, - { - "name": "phpstan/phpdoc-parser", - "version": "1.24.3", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "12f01d214f1c73b9c91fdb3b1c415e4c70652083" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/12f01d214f1c73b9c91fdb3b1c415e4c70652083", - "reference": "12f01d214f1c73b9c91fdb3b1c415e4c70652083", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0", - "nikic/php-parser": "^4.15", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.5", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5", - "symfony/process": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", - "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.3" - }, - "time": "2023-11-18T20:15:32+00:00" - }, { "name": "phpunit/php-code-coverage", "version": "10.1.8", @@ -13724,5 +13799,5 @@ "php": "^8.1" }, "platform-dev": [], - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.2.0" } diff --git a/config/filament-breezy.php b/config/filament-breezy.php index 2189153..7906beb 100644 --- a/config/filament-breezy.php +++ b/config/filament-breezy.php @@ -117,5 +117,7 @@ |-------------------------------------------------------------------------- | Sanctum permissions */ - 'sanctum_permissions' => ['create', 'read', 'update', 'delete'], + 'sanctum_permissions' => [ + // 'create', 'read', 'update', 'delete', + ], ]; diff --git a/config/scramble.php b/config/scramble.php new file mode 100644 index 0000000..f1369bf --- /dev/null +++ b/config/scramble.php @@ -0,0 +1,74 @@ + 'api', + + /* + * Your API domain. By default, app domain is used. This is also a part of the default API routes + * matcher, so when implementing your own, make sure you use this config if needed. + */ + 'api_domain' => null, + + 'info' => [ + /* + * API version. + */ + 'version' => env('API_VERSION', '1'), + + /* + * Description rendered on the home page of the API documentation (`/docs/api`). + */ + 'description' => '', + ], + + /* + * Customize Stoplight Elements UI + */ + 'ui' => [ + /* + * Hide the `Try It` feature. Enabled by default. + */ + 'hide_try_it' => false, + + /* + * URL to an image that displays as a small square logo next to the title, above the table of contents. + */ + 'logo' => '', + + /* + * Use to fetch the credential policy for the Try It feature. Options are: omit, include (default), and same-origin + */ + 'try_it_credentials_policy' => 'include', + ], + + /* + * The list of servers of the API. By default, when `null`, server URL will be created from + * `scramble.api_path` and `scramble.api_domain` config variables. When providing an array, you + * will need to specify the local server URL manually (if needed). + * + * Example of non-default config (final URLs are generated using Laravel `url` helper): + * + * ```php + * 'servers' => [ + * 'Live' => 'api', + * 'Prod' => 'https://scramble.dedoc.co/api', + * ], + * ``` + */ + 'servers' => null, + + 'middleware' => [ + 'web', + // RestrictedDocsAccess::class, + ], + + 'extensions' => [], +]; diff --git a/resources/views/vendor/filament-breezy/filament/pages/my-profile.blade.php b/resources/views/vendor/filament-breezy/filament/pages/my-profile.blade.php new file mode 100644 index 0000000..0c25a35 --- /dev/null +++ b/resources/views/vendor/filament-breezy/filament/pages/my-profile.blade.php @@ -0,0 +1,59 @@ + + + + + + + + + @if (config('filament-breezy.enable_2fa')) + + + + @endif + + @can('accessApi') + + + + + + {{ __('filament-breezy::default.profile.sanctum.title') }} + + + + {{ __('filament-breezy::default.profile.sanctum.description') }} + + +
+ +
+ + + @if ($plain_text_token) + config('filament.dark_mode'), + ]) name="plain_text_token" + value="{{ $plain_text_token }}" /> + @endif + + {{ $this->createApiTokenForm }} + +
+ + {{ __('filament-breezy::default.profile.sanctum.create.submit.label') }} + +
+
+
+ + + + @livewire(\JeffGreco13\FilamentBreezy\Http\Livewire\BreezySanctumTokens::class) + +
+
+ @endcan + +
diff --git a/routes/api.php b/routes/api.php index ba4fea6..3a7363a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -17,6 +17,7 @@ | is assigned the "api" middleware group. Enjoy building your API! | */ + Route::middleware('auth:sanctum') ->prefix('/v1') ->group(function () {