From e165cd7e28961b564d30807a7e4e3ebe00d86bb3 Mon Sep 17 00:00:00 2001 From: leon-morival Date: Fri, 28 Nov 2025 14:56:42 +0100 Subject: [PATCH] feat: scramble --- .env.example | 2 +- app/Http/Controllers/AuthController.php | 13 +- app/Providers/AppServiceProvider.php | 15 +- bootstrap/app.php | 2 +- composer.json | 1 + composer.lock | 357 ++++++++++++------ config/scramble.php | 136 +++++++ .../0001_01_01_000000_create_users_table.php | 2 +- lang/en/auth.php | 1 + lang/fr/auth.php | 21 ++ lang/fr/pagination.php | 19 + lang/fr/passwords.php | 22 ++ lang/fr/validation.php | 217 +++++++++++ routes/api.php | 7 + 14 files changed, 693 insertions(+), 122 deletions(-) create mode 100644 config/scramble.php create mode 100644 lang/fr/auth.php create mode 100644 lang/fr/pagination.php create mode 100644 lang/fr/passwords.php create mode 100644 lang/fr/validation.php diff --git a/.env.example b/.env.example index f61263a..2333278 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,7 @@ APP_KEY= APP_DEBUG=true APP_URL=http://localhost -APP_LOCALE=en +APP_LOCALE=fr APP_FALLBACK_LOCALE=en APP_FAKER_LOCALE=en_US diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index bd5b80d..a429336 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -5,13 +5,15 @@ namespace App\Http\Controllers; use App\Http\Requests\Auth\LoginRequest; use App\Http\Requests\Auth\RegisterRequest; use App\Models\User; +use Hash; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Validation\ValidationException; use Symfony\Component\HttpFoundation\Response; class AuthController extends Controller { - public function register(RegisterRequest $request): JsonResponse +public function register(RegisterRequest $request): JsonResponse { $data = $request->validated(); @@ -70,15 +72,6 @@ class AuthController extends Controller } - - - - - - - - - /** * Determine the token name to use for the access token. * diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 452e6b6..c64c142 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,7 +2,12 @@ namespace App\Providers; +use Dedoc\Scramble\Scramble; +use Dedoc\Scramble\Support\Generator\OpenApi; +use Dedoc\Scramble\Support\Generator\SecurityScheme; +use Illuminate\Routing\Route; use Illuminate\Support\ServiceProvider; +use Illuminate\Support\Str; class AppServiceProvider extends ServiceProvider { @@ -19,6 +24,14 @@ class AppServiceProvider extends ServiceProvider */ public function boot(): void { - // + Scramble::configure() + ->routes(function (Route $route) { + return Str::startsWith($route->uri, 'api/'); + }) + ->withDocumentTransformers(function (OpenApi $openApi) { + $openApi->secure( + SecurityScheme::http('bearer') + ); + }); } } diff --git a/bootstrap/app.php b/bootstrap/app.php index c3928c5..0cee472 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -6,7 +6,7 @@ use Illuminate\Foundation\Configuration\Middleware; return Application::configure(basePath: dirname(__DIR__)) ->withRouting( - web: __DIR__.'/../routes/web.php', + // 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 7079612..5c0c243 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "license": "MIT", "require": { "php": "^8.2", + "dedoc/scramble": "^0.13.5", "laravel/framework": "^12.0", "laravel/sanctum": "^4.0", "laravel/tinker": "^2.10.1" diff --git a/composer.lock b/composer.lock index 4e25982..eb3337f 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": "1ef9e2b78ee122ba1af242cab0df7034", + "content-hash": "df51c00372eede5c1382e8cb8bc2a796", "packages": [ { "name": "brick/math", @@ -135,6 +135,86 @@ ], "time": "2024-02-09T16:56:22+00:00" }, + { + "name": "dedoc/scramble", + "version": "v0.13.5", + "source": { + "type": "git", + "url": "https://github.com/dedoc/scramble.git", + "reference": "b827b5f96fb9f0f6069af65faeefdde9fedf4b9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dedoc/scramble/zipball/b827b5f96fb9f0f6069af65faeefdde9fedf4b9e", + "reference": "b827b5f96fb9f0f6069af65faeefdde9fedf4b9e", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^10.0|^11.0|^12.0", + "myclabs/deep-copy": "^1.12", + "nikic/php-parser": "^5.0", + "php": "^8.1", + "phpstan/phpdoc-parser": "^1.0|^2.0", + "spatie/laravel-package-tools": "^1.9.2" + }, + "require-dev": { + "larastan/larastan": "^3.3", + "laravel/pint": "^v1.1.0", + "nunomaduro/collision": "^7.0|^8.0", + "orchestra/testbench": "^8.0|^9.0|^10.0", + "pestphp/pest": "^2.34|^3.7", + "pestphp/pest-plugin-laravel": "^2.3|^3.1", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5|^11.5.3", + "spatie/laravel-permission": "^6.10", + "spatie/pest-plugin-snapshots": "^2.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.13.5" + }, + "funding": [ + { + "url": "https://github.com/romalytvynenko", + "type": "github" + } + ], + "time": "2025-11-24T09:09:10+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.3", @@ -2183,6 +2263,66 @@ ], "time": "2025-03-24T10:02:05+00:00" }, + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, { "name": "nesbot/carbon", "version": "3.10.3", @@ -2662,6 +2802,53 @@ ], "time": "2025-08-21T11:53:16+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "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/2.3.0" + }, + "time": "2025-08-30T15:50:23+00:00" + }, { "name": "psr/clock", "version": "1.0.0", @@ -3351,6 +3538,67 @@ }, "time": "2025-09-04T20:59:21+00:00" }, + { + "name": "spatie/laravel-package-tools", + "version": "1.92.7", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-package-tools.git", + "reference": "f09a799850b1ed765103a4f0b4355006360c49a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/f09a799850b1ed765103a4f0b4355006360c49a5", + "reference": "f09a799850b1ed765103a4f0b4355006360c49a5", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^9.28|^10.0|^11.0|^12.0", + "php": "^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.5", + "orchestra/testbench": "^7.7|^8.0|^9.0|^10.0", + "pestphp/pest": "^1.23|^2.1|^3.1", + "phpunit/php-code-coverage": "^9.0|^10.0|^11.0", + "phpunit/phpunit": "^9.5.24|^10.5|^11.5", + "spatie/pest-plugin-test-time": "^1.1|^2.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\LaravelPackageTools\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Tools for creating Laravel packages", + "homepage": "https://github.com/spatie/laravel-package-tools", + "keywords": [ + "laravel-package-tools", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-package-tools/issues", + "source": "https://github.com/spatie/laravel-package-tools/tree/1.92.7" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2025-07-17T15:46:43+00:00" + }, { "name": "symfony/clock", "version": "v7.4.0", @@ -7006,66 +7254,6 @@ }, "time": "2024-05-16T03:13:13+00:00" }, - { - "name": "myclabs/deep-copy", - "version": "1.13.4", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", - "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3 <3.2.2" - }, - "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpspec/prophecy": "^1.10", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" - }, - "type": "library", - "autoload": { - "files": [ - "src/DeepCopy/deep_copy.php" - ], - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2025-08-01T08:46:24+00:00" - }, { "name": "nunomaduro/collision", "version": "v8.8.3", @@ -7920,53 +8108,6 @@ }, "time": "2025-11-21T15:09:14+00:00" }, - { - "name": "phpstan/phpdoc-parser", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0", - "nikic/php-parser": "^5.3.0", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^9.6", - "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/2.3.0" - }, - "time": "2025-08-30T15:50:23+00:00" - }, { "name": "phpunit/php-code-coverage", "version": "12.4.0", diff --git a/config/scramble.php b/config/scramble.php new file mode 100644 index 0000000..e2ee332 --- /dev/null +++ b/config/scramble.php @@ -0,0 +1,136 @@ + '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, + + /* + * The path where your OpenAPI specification will be exported. + */ + 'export_path' => 'api.json', + + 'info' => [ + /* + * API version. + */ + 'version' => env('API_VERSION', '0.0.1'), + + /* + * Description rendered on the home page of the API documentation (`/docs/api`). + */ + 'description' => '', + ], + + /* + * Customize Stoplight Elements UI + */ + 'ui' => [ + /* + * Define the title of the documentation's website. App name is used when this config is `null`. + */ + 'title' => null, + + /* + * Define the theme of the documentation. Available options are `light`, `dark`, and `system`. + */ + 'theme' => 'light', + + /* + * Hide the `Try It` feature. Enabled by default. + */ + 'hide_try_it' => false, + + /* + * Hide the schemas in the Table of Contents. Enabled by default. + */ + 'hide_schemas' => 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', + + /* + * There are three layouts for Elements: + * - sidebar - (Elements default) Three-column design with a sidebar that can be resized. + * - responsive - Like sidebar, except at small screen sizes it collapses the sidebar into a drawer that can be toggled open. + * - stacked - Everything in a single column, making integrations with existing websites that have their own sidebar or other columns already. + */ + 'layout' => 'responsive', + ], + + /* + * 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, + + /** + * Determines how Scramble stores the descriptions of enum cases. + * Available options: + * - 'description' – Case descriptions are stored as the enum schema's description using table formatting. + * - 'extension' – Case descriptions are stored in the `x-enumDescriptions` enum schema extension. + * + * @see https://redocly.com/docs-legacy/api-reference-docs/specification-extensions/x-enum-descriptions + * - false - Case descriptions are ignored. + */ + 'enum_cases_description_strategy' => 'description', + + /** + * Determines how Scramble stores the names of enum cases. + * Available options: + * - 'names' – Case names are stored in the `x-enumNames` enum schema extension. + * - 'varnames' - Case names are stored in the `x-enum-varnames` enum schema extension. + * - false - Case names are not stored. + */ + 'enum_cases_names_strategy' => false, + + /** + * When Scramble encounters deep objects in query parameters, it flattens the parameters so the generated + * OpenAPI document correctly describes the API. Flattening deep query parameters is relevant until + * OpenAPI 3.2 is released and query string structure can be described properly. + * + * For example, this nested validation rule describes the object with `bar` property: + * `['foo.bar' => ['required', 'int']]`. + * + * When `flatten_deep_query_parameters` is `true`, Scramble will document the parameter like so: + * `{"name":"foo[bar]", "schema":{"type":"int"}, "required":true}`. + * + * When `flatten_deep_query_parameters` is `false`, Scramble will document the parameter like so: + * `{"name":"foo", "schema": {"type":"object", "properties":{"bar":{"type": "int"}}, "required": ["bar"]}, "required":true}`. + */ + 'flatten_deep_query_parameters' => true, + + 'middleware' => [ + 'web', + RestrictedDocsAccess::class, + ], + + 'extensions' => [], +]; diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php index 05fb5d9..a3fc05a 100644 --- a/database/migrations/0001_01_01_000000_create_users_table.php +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -13,7 +13,7 @@ return new class extends Migration { Schema::create('users', function (Blueprint $table) { $table->id(); - $table->string('name'); + $table->string('username'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); diff --git a/lang/en/auth.php b/lang/en/auth.php index 6598e2c..8797eb6 100644 --- a/lang/en/auth.php +++ b/lang/en/auth.php @@ -16,5 +16,6 @@ return [ 'failed' => 'These credentials do not match our records.', 'password' => 'The provided password is incorrect.', 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', + 'logout_success' => "You have been deconnecte" ]; diff --git a/lang/fr/auth.php b/lang/fr/auth.php new file mode 100644 index 0000000..e7b7f67 --- /dev/null +++ b/lang/fr/auth.php @@ -0,0 +1,21 @@ + 'Impossible de vous connecter', + 'password' => 'Email ou mot de passe incorrect', + 'throttle' => 'Trop de tentatives veuillez reessayer dans :seconds seconds.', + 'logout_success' => 'Vous êtes bien déconnecté' + +]; diff --git a/lang/fr/pagination.php b/lang/fr/pagination.php new file mode 100644 index 0000000..d481411 --- /dev/null +++ b/lang/fr/pagination.php @@ -0,0 +1,19 @@ + '« Previous', + 'next' => 'Next »', + +]; diff --git a/lang/fr/passwords.php b/lang/fr/passwords.php new file mode 100644 index 0000000..e211a28 --- /dev/null +++ b/lang/fr/passwords.php @@ -0,0 +1,22 @@ + 'Votre mot de passe a été réinitialisé.', + 'sent' => 'Nous avons envoyé par e-mail le lien de réinitialisation de votre mot de passe.', + 'throttled' => 'Veuillez patienter avant de réessayer.', + 'token' => 'Ce jeton de réinitialisation du mot de passe est invalide.', + 'user' => "Nous ne trouvons pas d’utilisateur avec cette adresse e-mail.", + +]; diff --git a/lang/fr/validation.php b/lang/fr/validation.php new file mode 100644 index 0000000..6927c3e --- /dev/null +++ b/lang/fr/validation.php @@ -0,0 +1,217 @@ + 'Le champ :attribute doit être accepté.', + 'accepted_if' => 'Le champ :attribute doit être accepté lorsque :other est :value.', + 'active_url' => 'Le champ :attribute doit être une URL valide.', + 'after' => 'Le champ :attribute doit être une date postérieure à :date.', + 'after_or_equal' => 'Le champ :attribute doit être une date postérieure ou égale à :date.', + 'alpha' => 'Le champ :attribute ne doit contenir que des lettres.', + 'alpha_dash' => 'Le champ :attribute ne doit contenir que des lettres, chiffres, tirets et underscores.', + 'alpha_num' => 'Le champ :attribute ne doit contenir que des lettres et chiffres.', + 'any_of' => 'Le champ :attribute est invalide.', + 'array' => 'Le champ :attribute doit être un tableau.', + 'ascii' => 'Le champ :attribute ne doit contenir que des caractères alphanumériques ASCII simples.', + 'before' => 'Le champ :attribute doit être une date antérieure à :date.', + 'before_or_equal' => 'Le champ :attribute doit être une date antérieure ou égale à :date.', + + 'between' => [ + 'array' => 'Le champ :attribute doit contenir entre :min et :max éléments.', + 'file' => 'Le champ :attribute doit être entre :min et :max kilo-octets.', + 'numeric' => 'Le champ :attribute doit être entre :min et :max.', + 'string' => 'Le champ :attribute doit être entre :min et :max caractères.', + ], + + 'boolean' => 'Le champ :attribute doit être vrai ou faux.', + 'can' => 'Le champ :attribute contient une valeur non autorisée.', + 'confirmed' => 'La confirmation du champ :attribute ne correspond pas.', + 'contains' => 'Le champ :attribute manque une valeur requise.', + 'current_password' => 'Le mot de passe est incorrect.', + 'date' => 'Le champ :attribute doit être une date valide.', + 'date_equals' => 'Le champ :attribute doit être une date égale à :date.', + 'date_format' => 'Le champ :attribute doit correspondre au format :format.', + 'decimal' => 'Le champ :attribute doit contenir :decimal décimales.', + 'declined' => 'Le champ :attribute doit être refusé.', + 'declined_if' => 'Le champ :attribute doit être refusé lorsque :other est :value.', + 'different' => 'Le champ :attribute et :other doivent être différents.', + 'digits' => 'Le champ :attribute doit contenir :digits chiffres.', + 'digits_between' => 'Le champ :attribute doit contenir entre :min et :max chiffres.', + 'dimensions' => "Le champ :attribute a des dimensions d'image invalides.", + 'distinct' => 'Le champ :attribute contient une valeur dupliquée.', + 'doesnt_contain' => 'Le champ :attribute ne doit contenir aucun des éléments suivants : :values.', + 'doesnt_end_with' => 'Le champ :attribute ne doit pas se terminer par l’un des éléments suivants : :values.', + 'doesnt_start_with' => 'Le champ :attribute ne doit pas commencer par l’un des éléments suivants : :values.', + 'email' => 'Le champ :attribute doit être une adresse email valide.', + 'encoding' => 'Le champ :attribute doit être encodé en :encoding.', + 'ends_with' => 'Le champ :attribute doit se terminer par l’un des éléments suivants : :values.', + 'enum' => 'La valeur sélectionnée pour :attribute est invalide.', + 'exists' => 'La valeur sélectionnée pour :attribute est invalide.', + 'extensions' => 'Le champ :attribute doit avoir une extension parmi :values.', + 'file' => 'Le champ :attribute doit être un fichier.', + 'filled' => 'Le champ :attribute doit avoir une valeur.', + + 'gt' => [ + 'array' => 'Le champ :attribute doit contenir plus de :value éléments.', + 'file' => 'Le champ :attribute doit être supérieur à :value kilo-octets.', + 'numeric' => 'Le champ :attribute doit être supérieur à :value.', + 'string' => 'Le champ :attribute doit contenir plus de :value caractères.', + ], + + 'gte' => [ + 'array' => 'Le champ :attribute doit contenir au moins :value éléments.', + 'file' => 'Le champ :attribute doit être supérieur ou égal à :value kilo-octets.', + 'numeric' => 'Le champ :attribute doit être supérieur ou égal à :value.', + 'string' => 'Le champ :attribute doit contenir au moins :value caractères.', + ], + + 'hex_color' => 'Le champ :attribute doit être une couleur hexadécimale valide.', + 'image' => 'Le champ :attribute doit être une image.', + 'in' => 'La valeur sélectionnée pour :attribute est invalide.', + 'in_array' => 'Le champ :attribute doit exister dans :other.', + 'in_array_keys' => 'Le champ :attribute doit contenir au moins une des clés suivantes : :values.', + 'integer' => 'Le champ :attribute doit être un entier.', + 'ip' => 'Le champ :attribute doit être une adresse IP valide.', + 'ipv4' => 'Le champ :attribute doit être une adresse IPv4 valide.', + 'ipv6' => 'Le champ :attribute doit être une adresse IPv6 valide.', + 'json' => 'Le champ :attribute doit être une chaîne JSON valide.', + 'list' => 'Le champ :attribute doit être une liste.', + 'lowercase' => 'Le champ :attribute doit être en minuscules.', + + 'lt' => [ + 'array' => 'Le champ :attribute doit contenir moins de :value éléments.', + 'file' => 'Le champ :attribute doit être inférieur à :value kilo-octets.', + 'numeric' => 'Le champ :attribute doit être inférieur à :value.', + 'string' => 'Le champ :attribute doit contenir moins de :value caractères.', + ], + + 'lte' => [ + 'array' => 'Le champ :attribute ne doit pas contenir plus de :value éléments.', + 'file' => 'Le champ :attribute doit être inférieur ou égal à :value kilo-octets.', + 'numeric' => 'Le champ :attribute doit être inférieur ou égal à :value.', + 'string' => 'Le champ :attribute doit contenir au maximum :value caractères.', + ], + + 'mac_address' => 'Le champ :attribute doit être une adresse MAC valide.', + + 'max' => [ + 'array' => 'Le champ :attribute ne doit pas contenir plus de :max éléments.', + 'file' => 'Le champ :attribute ne doit pas dépasser :max kilo-octets.', + 'numeric' => 'Le champ :attribute ne doit pas être supérieur à :max.', + 'string' => 'Le champ :attribute ne doit pas dépasser :max caractères.', + ], + + 'max_digits' => 'Le champ :attribute ne doit pas avoir plus de :max chiffres.', + 'mimes' => 'Le champ :attribute doit être un fichier de type : :values.', + 'mimetypes' => 'Le champ :attribute doit être un fichier de type : :values.', + + 'min' => [ + 'array' => 'Le champ :attribute doit contenir au moins :min éléments.', + 'file' => 'Le champ :attribute doit être au moins de :min kilo-octets.', + 'numeric' => 'Le champ :attribute doit être au moins :min.', + 'string' => 'Le champ :attribute doit contenir au moins :min caractères.', + ], + + 'min_digits' => 'Le champ :attribute doit contenir au moins :min chiffres.', + 'missing' => 'Le champ :attribute doit être manquant.', + 'missing_if' => 'Le champ :attribute doit être manquant lorsque :other est :value.', + 'missing_unless' => 'Le champ :attribute doit être manquant sauf si :other vaut :value.', + 'missing_with' => 'Le champ :attribute doit être manquant lorsque :values est présent.', + 'missing_with_all' => 'Le champ :attribute doit être manquant lorsque :values sont présents.', + 'multiple_of' => 'Le champ :attribute doit être un multiple de :value.', + 'not_in' => 'La valeur sélectionnée pour :attribute est invalide.', + 'not_regex' => 'Le format du champ :attribute est invalide.', + 'numeric' => 'Le champ :attribute doit être un nombre.', + + 'password' => [ + 'letters' => 'Le champ :attribute doit contenir au moins une lettre.', + 'mixed' => 'Le champ :attribute doit contenir au moins une majuscule et une minuscule.', + 'numbers' => 'Le champ :attribute doit contenir au moins un chiffre.', + 'symbols' => 'Le champ :attribute doit contenir au moins un symbole.', + 'uncompromised' => 'Le :attribute fourni apparaît dans une fuite de données. Veuillez en choisir un autre.', + ], + + 'present' => 'Le champ :attribute doit être présent.', + 'present_if' => 'Le champ :attribute doit être présent lorsque :other est :value.', + 'present_unless' => 'Le champ :attribute doit être présent sauf si :other vaut :value.', + 'present_with' => 'Le champ :attribute doit être présent lorsque :values est présent.', + 'present_with_all' => 'Le champ :attribute doit être présent lorsque :values sont présents.', + + 'prohibited' => 'Le champ :attribute est interdit.', + 'prohibited_if' => 'Le champ :attribute est interdit lorsque :other vaut :value.', + 'prohibited_if_accepted' => 'Le champ :attribute est interdit lorsque :other est accepté.', + 'prohibited_if_declined' => 'Le champ :attribute est interdit lorsque :other est refusé.', + 'prohibited_unless' => 'Le champ :attribute est interdit sauf si :other est dans :values.', + 'prohibits' => 'Le champ :attribute interdit :other d’être présent.', + + 'regex' => 'Le format du champ :attribute est invalide.', + 'required' => 'Le champ :attribute est obligatoire.', + 'required_array_keys' => 'Le champ :attribute doit contenir des entrées pour : :values.', + 'required_if' => 'Le champ :attribute est obligatoire lorsque :other vaut :value.', + 'required_if_accepted' => 'Le champ :attribute est obligatoire lorsque :other est accepté.', + 'required_if_declined' => 'Le champ :attribute est obligatoire lorsque :other est refusé.', + 'required_unless' => 'Le champ :attribute est obligatoire sauf si :other est dans :values.', + 'required_with' => 'Le champ :attribute est obligatoire lorsque :values est présent.', + 'required_with_all' => 'Le champ :attribute est obligatoire lorsque :values sont présents.', + 'required_without' => 'Le champ :attribute est obligatoire lorsque :values n’est pas présent.', + 'required_without_all' => 'Le champ :attribute est obligatoire lorsque aucun de :values n’est présent.', + + 'same' => 'Le champ :attribute doit correspondre à :other.', + + 'size' => [ + 'array' => 'Le champ :attribute doit contenir :size éléments.', + 'file' => 'Le champ :attribute doit faire :size kilo-octets.', + 'numeric' => 'Le champ :attribute doit être :size.', + 'string' => 'Le champ :attribute doit contenir :size caractères.', + ], + + 'starts_with' => 'Le champ :attribute doit commencer par l’un des éléments suivants : :values.', + 'string' => 'Le champ :attribute doit être une chaîne de caractères.', + 'timezone' => 'Le champ :attribute doit être un fuseau horaire valide.', + 'unique' => 'La valeur du champ :attribute est déjà utilisée.', + 'uploaded' => 'Le téléchargement du fichier :attribute a échoué.', + 'uppercase' => 'Le champ :attribute doit être en majuscules.', + 'url' => 'Le champ :attribute doit être une URL valide.', + 'ulid' => 'Le champ :attribute doit être un ULID valide.', + 'uuid' => 'Le champ :attribute doit être un UUID valide.', + + /* + |-------------------------------------------------------------------------- + | Lignes de langage de validation personnalisées + |-------------------------------------------------------------------------- + | + | Vous pouvez spécifier ici des messages personnalisés pour les attributs + | en utilisant la convention "attribute.rule" pour nommer les lignes. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'message-personnalisé', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Attributs personnalisés + |-------------------------------------------------------------------------- + | + | Ces lignes permettent de remplacer les noms d'attributs par des termes + | plus lisibles comme “Adresse E-mail” au lieu de “email”. + | + */ + + 'attributes' => [], + +]; diff --git a/routes/api.php b/routes/api.php index a435271..d62030c 100644 --- a/routes/api.php +++ b/routes/api.php @@ -9,6 +9,13 @@ Route::middleware('auth:sanctum')->group(function (): void { // }); // User + Route::prefix('auth')->group(function (): void { + Route::post('register', [AuthController::class, 'register']); + Route::post('login', [AuthController::class, 'login']); + + // Route::get('{provider}/redirect', [ProviderRedirectController::class, 'redirect']); + // Route::get('{provider}/callback', [ProviderCallbackController::class, 'callback']); +}); Route::get('auth/me', [AuthController::class, 'me']); Route::post('auth/logout', [AuthController::class, 'logout']);