diff --git a/.env.full b/.env.full index 556d2e9..5696afa 100644 --- a/.env.full +++ b/.env.full @@ -89,3 +89,6 @@ DB_HUB_COLLATION=utf8mb4_0900_ai_ci GITEA_DOMAIN= GITEA_TOKEN= + +# API key for Scribe documentation. +SCRIBE_AUTH_KEY= diff --git a/.env.light b/.env.light index 6bd4cd1..947270c 100644 --- a/.env.light +++ b/.env.light @@ -42,3 +42,6 @@ SCOUT_DRIVER=collection MAIL_MAILER=log MAIL_FROM_ADDRESS="no-reply@sp-tarkov.com" MAIL_FROM_NAME="${APP_NAME}" + +# API key for Scribe documentation. +SCRIBE_AUTH_KEY= diff --git a/.gitignore b/.gitignore index 3ccc7e5..e554aa8 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ Homestead.json Homestead.yaml npm-debug.log yarn-error.log +.scribe diff --git a/app/Http/Controllers/Api/AuthController.php b/app/Http/Controllers/Api/AuthController.php index 3a4cca0..31321bb 100644 --- a/app/Http/Controllers/Api/AuthController.php +++ b/app/Http/Controllers/Api/AuthController.php @@ -9,41 +9,77 @@ use App\Traits\ApiResponses; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; +use Knuckles\Scribe\Attributes\BodyParam; +use Knuckles\Scribe\Attributes\Response; +use Knuckles\Scribe\Attributes\ResponseField; +use Laravel\Sanctum\PersonalAccessToken; class AuthController extends Controller { use ApiResponses; + /** + * Login + * + * Authenticates the user and returns a read-only API token. This API token can then be saved and used for future + * requests that require authentication. + * + * @unauthenticated + * + * @group Authentication + */ + #[BodyParam('token_name', 'string', 'The name of the API token.', required: false, example: 'Dynamic API Token')] + #[Response(['message' => 'authenticated', 'data' => ['token' => 'YOUR_API_KEY'], 'status' => 200], status: 200, description: 'Authenticated successfully')] + #[Response(['message' => 'invalid credentials', 'status' => 401], status: 401, description: 'Invalid credentials')] + #[ResponseField('token', description: 'The newly created read-only API token to use for future authenticated requests.')] public function login(LoginUserRequest $request): JsonResponse { $request->validated($request->all()); if (! Auth::attempt($request->only('email', 'password'))) { - return $this->error(__('Invalid credentials'), 401); + return $this->error(__('invalid credentials'), 401); } $user = User::firstWhere('email', $request->email); $tokenName = $request->token_name ?? __('Dynamic API Token'); - return $this->success(__('Authenticated'), [ + return $this->success(__('authenticated'), [ // Only allowing the 'read' scope to be dynamically created. Can revisit later when writes are possible. 'token' => $user->createToken($tokenName, ['read'])->plainTextToken, ]); } + /** + * Logout + * + * Destroys the user's current API token, effectively logging them out. + * + * @group Authentication + */ + #[Response(['message' => 'success', 'status' => 200], status: 200, description: 'Token destroyed successfully')] public function logout(Request $request): JsonResponse { - /** @var \Laravel\Sanctum\PersonalAccessToken $token */ + /** @var PersonalAccessToken $token */ $token = $request->user()->currentAccessToken(); $token->delete(); - return $this->success(__('Revoked API token')); + return $this->success(__('success')); } + /** + * Logout All + * + * Destroys all the user's API tokens, effectively logging everyone out of the account. + * + * @group Authentication + */ + #[Response(['message' => 'success', 'status' => 200], status: 200, description: 'Tokens destroyed successfully')] public function logoutAll(Request $request): JsonResponse { $request->user()->tokens()->delete(); - return $this->success(__('Revoked all API tokens')); + return $this->success(__('success')); } } diff --git a/app/Http/Controllers/Api/V0/ModController.php b/app/Http/Controllers/Api/V0/ModController.php index 29738af..1eca110 100644 --- a/app/Http/Controllers/Api/V0/ModController.php +++ b/app/Http/Controllers/Api/V0/ModController.php @@ -3,43 +3,58 @@ namespace App\Http\Controllers\Api\V0; use App\Http\Filters\V1\ModFilter; -use App\Http\Requests\Api\V0\StoreModRequest; -use App\Http\Requests\Api\V0\UpdateModRequest; use App\Http\Resources\Api\V0\ModResource; use App\Models\Mod; use Illuminate\Http\Resources\Json\AnonymousResourceCollection; use Illuminate\Http\Resources\Json\JsonResource; +use Knuckles\Scribe\Attributes\QueryParam; +use Knuckles\Scribe\Attributes\UrlParam; class ModController extends ApiController { /** - * Display a listing of the resource. + * Get Mods + * + * List, filter, and sort basic information about mods. + * + * @group Mods */ + #[QueryParam('include', 'string', 'The relationships to include within the `includes` key. By default no relationships are automatically included.', required: false, example: 'users,versions,license')] + #[QueryParam('filter[id]', 'string', 'Filter by the `id`. Select multiple by separating the IDs with a comma.', required: false, example: '5,10,15')] + #[QueryParam('filter[hub_id]', 'string', 'Filter by the `hub_id` attribute. Select multiple by separating the IDs with a comma.', required: false, example: '20')] + #[QueryParam('filter[name]', 'string', 'Filter by the `name` attribute. Use `*` as the wildcard character.', required: false, example: '*SAIN*')] + #[QueryParam('filter[slug]', 'string', 'Filter by the `slug` attribute. Use `*` as the wildcard character.', required: false, example: '*raid-times')] + #[QueryParam('filter[teaser]', 'string', 'Filter by the `teaser` attribute. Use `*` as the wildcard character.', required: false, example: '*weighted*random*times*')] + #[QueryParam('filter[source_code_link]', 'string', 'Filter by the `source_code_link` attribute. Use `*` as the wildcard character.', required: false, example: '*https*.net*')] + #[QueryParam('filter[featured]', 'boolean', 'Filter by the `featured` attribute. All "truthy" or "falsy" values are supported.', required: false, example: 'true')] + #[QueryParam('filter[contains_ads]', 'boolean', 'Filter by the `contains_ads` attribute. All "truthy" or "falsy" values are supported.', required: false, example: 'true')] + #[QueryParam('filter[contains_ai_content]', 'boolean', 'Filter by the `contains_ai_content` attribute. All "truthy" or "falsy" values are supported.', required: false, example: 'true')] + #[QueryParam('filter[created_at]', 'string', 'Filter by the `created_at` attribute. Ranges are possible by separating the dates with a comma.', required: false, example: '2023-12-31,2024-12-31')] + #[QueryParam('filter[updated_at]', 'string', 'Filter by the `updated_at` attribute. Ranges are possible by separating the dates with a comma.', required: false, example: '2023-12-31,2024-12-31')] + #[QueryParam('filter[published_at]', 'string', 'Filter by the `published_at` attribute. Ranges are possible by seperating the dates with a comma.', required: false, example: '2023-12-31,2024-12-31')] + #[QueryParam('sort', 'string', 'Sort the results by a comma seperated list of attributes. The default sort direction is ASC, append the attribute name with a minus to sort DESC.', required: false, example: '-featured,name')] public function index(ModFilter $filters): AnonymousResourceCollection { return ModResource::collection(Mod::filter($filters)->paginate()); } - /** - * Store a newly created resource in storage. - */ - public function store(StoreModRequest $request): void {} + //public function store(StoreModRequest $request): void {} /** - * Display the specified resource. + * Get Mod + * + * Display more detailed information about a specific mod. + * + * @group Mods */ + #[UrlParam('id', 'integer', 'The ID of the mod.', required: true, example: 558)] + #[QueryParam('include', 'string', 'The relationships to include within the `includes` key. By default no relationships are automatically included.', required: false, example: 'users,versions,license')] public function show(Mod $mod): JsonResource { return new ModResource($mod); } - /** - * Update the specified resource in storage. - */ - public function update(UpdateModRequest $request, Mod $mod): void {} + //public function update(UpdateModRequest $request, Mod $mod): void {} - /** - * Remove the specified resource from storage. - */ - public function destroy(Mod $mod): void {} + //public function destroy(Mod $mod): void {} } diff --git a/app/Http/Controllers/Api/V0/UsersController.php b/app/Http/Controllers/Api/V0/UsersController.php index ca1cd62..737e87e 100644 --- a/app/Http/Controllers/Api/V0/UsersController.php +++ b/app/Http/Controllers/Api/V0/UsersController.php @@ -3,43 +3,48 @@ namespace App\Http\Controllers\Api\V0; use App\Http\Filters\V1\UserFilter; -use App\Http\Requests\Api\V0\StoreUserRequest; -use App\Http\Requests\Api\V0\UpdateUserRequest; use App\Http\Resources\Api\V0\UserResource; use App\Models\User; use Illuminate\Http\Resources\Json\AnonymousResourceCollection; use Illuminate\Http\Resources\Json\JsonResource; +use Knuckles\Scribe\Attributes\QueryParam; class UsersController extends ApiController { /** - * Display a listing of the resource. + * Get Users + * + * List, filter, and sort basic information about users. + * + * @group Users */ + #[QueryParam('include', 'string', 'The relationships to include within the `includes` key. By default no relationships are automatically included.', required: false, example: 'user_role')] + #[QueryParam('filter[id]', 'string', 'Filter by the `id`. Select multiple by separating the IDs with a comma.', required: false, example: '5,10,15')] + #[QueryParam('filter[name]', 'string', 'Filter by the `name` attribute. Use `*` as the wildcard character.', required: false, example: '*fringe')] + #[QueryParam('filter[created_at]', 'string', 'Filter by the `created_at` attribute. Ranges are possible by separating the dates with a comma.', required: false, example: '2023-12-31,2024-12-31')] + #[QueryParam('filter[updated_at]', 'string', 'Filter by the `updated_at` attribute. Ranges are possible by separating the dates with a comma.', required: false, example: '2023-12-31,2024-12-31')] + #[QueryParam('sort', 'string', 'Sort the results by a comma seperated list of attributes. The default sort direction is ASC, append the attribute name with a minus to sort DESC.', required: false, example: 'created_at,-name')] public function index(UserFilter $filters): AnonymousResourceCollection { return UserResource::collection(User::filter($filters)->paginate()); } - /** - * Store a newly created resource in storage. - */ - public function store(StoreUserRequest $request): void {} + //public function store(StoreUserRequest $request): void {} /** - * Display the specified resource. + * Get User + * + * Display more detailed information about a specific user. + * + * @group Users */ + #[QueryParam('include', 'string', 'The relationships to include within the `includes` key. By default no relationships are automatically included.', required: false, example: 'user_role')] public function show(User $user): JsonResource { return new UserResource($user); } - /** - * Update the specified resource in storage. - */ - public function update(UpdateUserRequest $request, User $user): void {} + //public function update(UpdateUserRequest $request, User $user): void {} - /** - * Remove the specified resource from storage. - */ - public function destroy(User $user): void {} + //public function destroy(User $user): void {} } diff --git a/app/Traits/ApiResponses.php b/app/Traits/ApiResponses.php index dfd4345..7117318 100644 --- a/app/Traits/ApiResponses.php +++ b/app/Traits/ApiResponses.php @@ -8,8 +8,6 @@ trait ApiResponses { /** * Return a success JSON response. - * - * @param array $data */ protected function success(string $message, ?array $data = []): JsonResponse { @@ -18,15 +16,17 @@ trait ApiResponses /** * The base response. - * - * @param array $data */ private function baseResponse(?string $message = '', ?array $data = [], ?int $code = 200): JsonResponse { - return response()->json([ - 'message' => $message, - 'data' => $data, - ], $code); + $response = []; + $response['message'] = $message; + if ($data) { + $response['data'] = $data; + } + $response['status'] = $code; + + return response()->json($response, $code); } /** diff --git a/composer.json b/composer.json index ebef945..3ea0c7e 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,7 @@ "require-dev": { "barryvdh/laravel-debugbar": "^3.13", "fakerphp/faker": "^1.23", + "knuckleswtf/scribe": "^4.37", "larastan/larastan": "^2.9", "laravel/pint": "^1.16", "laravel/sail": "^1.29", diff --git a/composer.lock b/composer.lock index 399951e..cb92761 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": "aef706ee9aa7b671ca81c5ced4a7bfb7", + "content-hash": "a687bfe8867c5e74bf6a974aaa969f62", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -9510,6 +9510,56 @@ ], "time": "2024-02-20T07:24:02+00:00" }, + { + "name": "erusev/parsedown", + "version": "1.7.4", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "type": "library", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "support": { + "issues": "https://github.com/erusev/parsedown/issues", + "source": "https://github.com/erusev/parsedown/tree/1.7.x" + }, + "time": "2019-12-30T22:54:17+00:00" + }, { "name": "fakerphp/faker", "version": "v1.23.1", @@ -9815,6 +9865,101 @@ }, "time": "2024-03-08T09:58:59+00:00" }, + { + "name": "knuckleswtf/scribe", + "version": "4.37.2", + "source": { + "type": "git", + "url": "https://github.com/knuckleswtf/scribe.git", + "reference": "6318f3f68cbf09328e5cb6843ce1739e529ef1ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/knuckleswtf/scribe/zipball/6318f3f68cbf09328e5cb6843ce1739e529ef1ac", + "reference": "6318f3f68cbf09328e5cb6843ce1739e529ef1ac", + "shasum": "" + }, + "require": { + "erusev/parsedown": "1.7.4", + "ext-fileinfo": "*", + "ext-json": "*", + "ext-pdo": "*", + "fakerphp/faker": "^1.9.1", + "illuminate/console": "^8.0|^9.0|^10.0|^11.0", + "illuminate/routing": "^8.0|^9.0|^10.0|^11.0", + "illuminate/support": "^8.0|^9.0|^10.0|^11.0", + "league/flysystem": "^1.1.4|^2.1.1|^3.0", + "mpociot/reflection-docblock": "^1.0.1", + "nikic/php-parser": "^5.0", + "nunomaduro/collision": "^5.10|^6.0|^7.0|^8.0", + "php": ">=8.0", + "ramsey/uuid": "^4.2.2", + "shalvah/clara": "^3.1.0", + "shalvah/upgrader": ">=0.6.0", + "spatie/data-transfer-object": "^2.6|^3.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0" + }, + "replace": { + "mpociot/laravel-apidoc-generator": "*" + }, + "require-dev": { + "brianium/paratest": "^6.0", + "dms/phpunit-arraysubset-asserts": "^0.4", + "laravel/legacy-factories": "^1.3.0", + "laravel/lumen-framework": "^8.0|^9.0|^10.0", + "league/fractal": "^0.20", + "nikic/fast-route": "^1.3", + "orchestra/testbench": "^6.0|^7.0|^8.0", + "pestphp/pest": "^1.21", + "phpstan/phpstan": "^1.0", + "phpunit/phpunit": "^9.0|^10.0", + "symfony/css-selector": "^5.4|^6.0", + "symfony/dom-crawler": "^5.4|^6.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Knuckles\\Scribe\\ScribeServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Knuckles\\Camel\\": "camel/", + "Knuckles\\Scribe\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Shalvah" + } + ], + "description": "Generate API documentation for humans from your Laravel codebase.✍", + "homepage": "http://github.com/knuckleswtf/scribe", + "keywords": [ + "api", + "dingo", + "documentation", + "laravel" + ], + "support": { + "issues": "https://github.com/knuckleswtf/scribe/issues", + "source": "https://github.com/knuckleswtf/scribe/tree/4.37.2" + }, + "funding": [ + { + "url": "https://patreon.com/shalvah", + "type": "patreon" + } + ], + "time": "2024-08-30T12:15:51+00:00" + }, { "name": "larastan/larastan", "version": "v2.9.8", @@ -10197,6 +10342,59 @@ }, "time": "2024-05-16T03:13:13+00:00" }, + { + "name": "mpociot/reflection-docblock", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/mpociot/reflection-docblock.git", + "reference": "c8b2e2b1f5cebbb06e2b5ccbf2958f2198867587" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mpociot/reflection-docblock/zipball/c8b2e2b1f5cebbb06e2b5ccbf2958f2198867587", + "reference": "c8b2e2b1f5cebbb06e2b5ccbf2958f2198867587", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Mpociot": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "support": { + "issues": "https://github.com/mpociot/reflection-docblock/issues", + "source": "https://github.com/mpociot/reflection-docblock/tree/master" + }, + "time": "2016-06-20T20:53:12+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.12.0", @@ -12426,6 +12624,111 @@ ], "time": "2023-02-07T11:34:05+00:00" }, + { + "name": "shalvah/clara", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/shalvah/clara.git", + "reference": "cdbb5737cbdd101756d97dd2279a979a1af7710b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/shalvah/clara/zipball/cdbb5737cbdd101756d97dd2279a979a1af7710b", + "reference": "cdbb5737cbdd101756d97dd2279a979a1af7710b", + "shasum": "" + }, + "require": { + "php": ">=7.4", + "symfony/console": "^4.0|^5.0|^6.0|^7.0" + }, + "require-dev": { + "eloquent/phony-phpunit": "^7.0", + "phpunit/phpunit": "^9.1" + }, + "type": "library", + "autoload": { + "files": [ + "helpers.php" + ], + "psr-4": { + "Shalvah\\Clara\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "🔊 Simple, pretty, testable console output for CLI apps.", + "keywords": [ + "cli", + "log", + "logging" + ], + "support": { + "issues": "https://github.com/shalvah/clara/issues", + "source": "https://github.com/shalvah/clara/tree/3.2.0" + }, + "time": "2024-02-27T20:30:59+00:00" + }, + { + "name": "shalvah/upgrader", + "version": "0.6.0", + "source": { + "type": "git", + "url": "https://github.com/shalvah/upgrader.git", + "reference": "d95ed17fe9f5e1ee7d47ad835595f1af080a867f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/shalvah/upgrader/zipball/d95ed17fe9f5e1ee7d47ad835595f1af080a867f", + "reference": "d95ed17fe9f5e1ee7d47ad835595f1af080a867f", + "shasum": "" + }, + "require": { + "illuminate/support": ">=8.0", + "nikic/php-parser": "^5.0", + "php": ">=8.0" + }, + "require-dev": { + "dms/phpunit-arraysubset-asserts": "^0.2.0", + "pestphp/pest": "^1.21", + "phpstan/phpstan": "^1.0", + "spatie/ray": "^1.33" + }, + "type": "library", + "autoload": { + "psr-4": { + "Shalvah\\Upgrader\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Shalvah", + "email": "hello@shalvah.me" + } + ], + "description": "Create automatic upgrades for your package.", + "homepage": "http://github.com/shalvah/upgrader", + "keywords": [ + "upgrade" + ], + "support": { + "issues": "https://github.com/shalvah/upgrader/issues", + "source": "https://github.com/shalvah/upgrader/tree/0.6.0" + }, + "funding": [ + { + "url": "https://patreon.com/shalvah", + "type": "patreon" + } + ], + "time": "2024-02-20T11:51:46+00:00" + }, { "name": "spatie/backtrace", "version": "1.6.2", @@ -12489,6 +12792,70 @@ ], "time": "2024-07-22T08:21:24+00:00" }, + { + "name": "spatie/data-transfer-object", + "version": "3.9.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/data-transfer-object.git", + "reference": "1df0906c4e9e3aebd6c0506fd82c8b7d5548c1c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/data-transfer-object/zipball/1df0906c4e9e3aebd6c0506fd82c8b7d5548c1c8", + "reference": "1df0906c4e9e3aebd6c0506fd82c8b7d5548c1c8", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "illuminate/collections": "^8.36", + "jetbrains/phpstorm-attributes": "^1.0", + "larapack/dd": "^1.1", + "phpunit/phpunit": "^9.5.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\DataTransferObject\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brent Roose", + "email": "brent@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Data transfer objects with batteries included", + "homepage": "https://github.com/spatie/data-transfer-object", + "keywords": [ + "data-transfer-object", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/data-transfer-object/issues", + "source": "https://github.com/spatie/data-transfer-object/tree/3.9.1" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "abandoned": "spatie/laravel-data", + "time": "2022-09-16T13:34:38+00:00" + }, { "name": "spatie/error-solutions", "version": "1.1.1", @@ -12806,6 +13173,82 @@ ], "time": "2024-06-12T15:01:18+00:00" }, + { + "name": "symfony/var-exporter", + "version": "v7.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "b80a669a2264609f07f1667f891dbfca25eba44c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/b80a669a2264609f07f1667f891dbfca25eba44c", + "reference": "b80a669a2264609f07f1667f891dbfca25eba44c", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v7.1.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-28T08:00:31+00:00" + }, { "name": "symfony/yaml", "version": "v7.1.4", diff --git a/config/scribe.php b/config/scribe.php new file mode 100644 index 0000000..98547d3 --- /dev/null +++ b/config/scribe.php @@ -0,0 +1,269 @@ + for the generated documentation. If this is empty, Scribe will infer it from config('app.name'). + 'title' => 'The Forge API Documentation', + + // A short description of your API. Will be included in the docs webpage, Postman collection and OpenAPI spec. + 'description' => '', + + // The base URL displayed in the docs. If this is empty, Scribe will use the value of config('app.url') at generation time. + // If you're using `laravel` type, you can set this to a dynamic string, like '{{ config("app.tenant_url") }}' to get a dynamic base URL. + 'base_url' => null, + + 'routes' => [ + [ + // Routes that match these conditions will be included in the docs + 'match' => [ + // Match only routes whose paths match this pattern (use * as a wildcard to match any characters). Example: 'users/*'. + 'prefixes' => ['api/*'], + + // Match only routes whose domains match this pattern (use * as a wildcard to match any characters). Example: 'api.*'. + 'domains' => ['*'], + + // [Dingo router only] Match only routes registered under this version. Wildcards are NOT supported. + 'versions' => ['v0'], + ], + + // Include these routes even if they did not match the rules above. + 'include' => [ + // 'users.index', 'POST /new', '/auth/*' + ], + + // Exclude these routes even if they matched the rules above. + 'exclude' => [ + // 'GET /health', 'admin.*' + ], + ], + ], + + // The type of documentation output to generate. + // - "static" will generate a static HTMl page in the /public/docs folder, + // - "laravel" will generate the documentation as a Blade view, so you can add routing and authentication. + // - "external_static" and "external_laravel" do the same as above, but generate a basic template, + // passing the OpenAPI spec as a URL, allowing you to easily use the docs with an external generator + 'type' => 'static', + + // See https://scribe.knuckles.wtf/laravel/reference/config#theme for supported options + 'theme' => 'default', + + 'static' => [ + // HTML documentation, assets and Postman collection will be generated to this folder. + // Source Markdown will still be in resources/docs. + 'output_path' => 'public/docs', + ], + + 'laravel' => [ + // Whether to automatically create a docs endpoint for you to view your generated docs. + // If this is false, you can still set up routing manually. + 'add_routes' => true, + + // URL path to use for the docs endpoint (if `add_routes` is true). + // By default, `/docs` opens the HTML page, `/docs.postman` opens the Postman collection, and `/docs.openapi` the OpenAPI spec. + 'docs_url' => '/docs', + + // Directory within `public` in which to store CSS and JS assets. + // By default, assets are stored in `public/vendor/scribe`. + // If set, assets will be stored in `public/{{assets_directory}}` + 'assets_directory' => null, + + // Middleware to attach to the docs endpoint (if `add_routes` is true). + 'middleware' => [], + ], + + 'external' => [ + 'html_attributes' => [], + ], + + 'try_it_out' => [ + // Add a Try It Out button to your endpoints so consumers can test endpoints right from their browser. + // Don't forget to enable CORS headers for your endpoints. + 'enabled' => true, + + // The base URL for the API tester to use (for example, you can set this to your staging URL). + // Leave as null to use the current app URL when generating (config("app.url")). + 'base_url' => null, + + // [Laravel Sanctum] Fetch a CSRF token before each request, and add it as an X-XSRF-TOKEN header. + 'use_csrf' => false, + + // The URL to fetch the CSRF token from (if `use_csrf` is true). + 'csrf_url' => '/sanctum/csrf-cookie', + ], + + // How is your API authenticated? This information will be used in the displayed docs, generated examples and response calls. + 'auth' => [ + // Set this to true if ANY endpoints in your API use authentication. + 'enabled' => true, + + // Set this to true if your API should be authenticated by default. If so, you must also set `enabled` (above) to true. + // You can then use @unauthenticated or @authenticated on individual endpoints to change their status from the default. + 'default' => true, + + // Where is the auth value meant to be sent in a request? + // Options: query, body, basic, bearer, header (for custom header) + 'in' => 'bearer', + + // The name of the auth parameter (eg token, key, apiKey) or header (eg Authorization, Api-Key). + 'name' => 'Authorization', + + // The value of the parameter to be used by Scribe to authenticate response calls. + // This will NOT be included in the generated documentation. If empty, Scribe will use a random value. + 'use_value' => env('SCRIBE_AUTH_KEY'), + + // Placeholder your users will see for the auth parameter in the example requests. + // Set this to null if you want Scribe to use a random value as placeholder instead. + 'placeholder' => 'YOUR_API_KEY', + + // Any extra authentication-related info for your users. Markdown and HTML are supported. + 'extra_info' => 'You can generate your own API token by logging into The Forge, clicking your profile picture, and clicking API Tokens.', + ], + + // Text to place in the "Introduction" section, right after the `description`. Markdown and HTML are supported. + 'intro_text' => <<<'INTRO' +This documentation aims to provide all the information you need to work with our API. + + +INTRO + , + + // Example requests for each endpoint will be shown in each of these languages. + // Supported options are: bash, javascript, php, python + // To add a language of your own, see https://scribe.knuckles.wtf/laravel/advanced/example-requests + 'example_languages' => [ + 'javascript', + 'php', + 'python', + ], + + // Generate a Postman collection (v2.1.0) in addition to HTML docs. + // For 'static' docs, the collection will be generated to public/docs/collection.json. + // For 'laravel' docs, it will be generated to storage/app/scribe/collection.json. + // Setting `laravel.add_routes` to true (above) will also add a route for the collection. + 'postman' => [ + 'enabled' => true, + 'overrides' => [ + // 'info.version' => '2.0.0', + ], + ], + + // Generate an OpenAPI spec (v3.0.1) in addition to docs webpage. + // For 'static' docs, the collection will be generated to public/docs/openapi.yaml. + // For 'laravel' docs, it will be generated to storage/app/scribe/openapi.yaml. + // Setting `laravel.add_routes` to true (above) will also add a route for the spec. + 'openapi' => [ + 'enabled' => true, + 'overrides' => [ + // 'info.version' => '2.0.0', + ], + ], + + 'groups' => [ + // Endpoints which don't have a @group will be placed in this default group. + 'default' => 'Endpoints', + + // By default, Scribe will sort groups alphabetically, and endpoints in the order their routes are defined. + // You can override this by listing the groups, subgroups and endpoints here in the order you want them. + // See https://scribe.knuckles.wtf/blog/laravel-v4#easier-sorting and https://scribe.knuckles.wtf/laravel/reference/config#order for details + 'order' => [], + ], + + // Custom logo path. This will be used as the value of the src attribute for the tag, + // so make sure it points to an accessible URL or path. Set to false to not use a logo. + // For example, if your logo is in public/img: + // - 'logo' => '../img/logo.png' // for `static` type (output folder is public/docs) + // - 'logo' => 'img/logo.png' // for `laravel` type + 'logo' => false, + + // Customize the "Last updated" value displayed in the docs by specifying tokens and formats. + // Examples: + // - {date:F j Y} => March 28, 2022 + // - {git:short} => Short hash of the last Git commit + // Available tokens are `{date:}` and `{git:}`. + // The format you pass to `date` will be passed to PHP's `date()` function. + // The format you pass to `git` can be either "short" or "long". + 'last_updated' => 'Last updated: {date:F j, Y}', + + 'examples' => [ + // Set this to any number (eg. 1234) to generate the same example values for parameters on each run, + 'faker_seed' => null, + + // With API resources and transformers, Scribe tries to generate example models to use in your API responses. + // By default, Scribe will try the model's factory, and if that fails, try fetching the first from the database. + // You can reorder or remove strategies here. + 'models_source' => ['factoryCreate', 'factoryMake', 'databaseFirst'], + ], + + // The strategies Scribe will use to extract information about your routes at each stage. + // If you create or install a custom strategy, add it here. + 'strategies' => [ + 'metadata' => [ + Strategies\Metadata\GetFromDocBlocks::class, + Strategies\Metadata\GetFromMetadataAttributes::class, + ], + 'urlParameters' => [ + Strategies\UrlParameters\GetFromLaravelAPI::class, + Strategies\UrlParameters\GetFromUrlParamAttribute::class, + Strategies\UrlParameters\GetFromUrlParamTag::class, + ], + 'queryParameters' => [ + Strategies\QueryParameters\GetFromFormRequest::class, + Strategies\QueryParameters\GetFromInlineValidator::class, + Strategies\QueryParameters\GetFromQueryParamAttribute::class, + Strategies\QueryParameters\GetFromQueryParamTag::class, + ], + 'headers' => [ + Strategies\Headers\GetFromHeaderAttribute::class, + Strategies\Headers\GetFromHeaderTag::class, + [ + 'override', + [ + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + ], + ], + ], + 'bodyParameters' => [ + Strategies\BodyParameters\GetFromFormRequest::class, + Strategies\BodyParameters\GetFromInlineValidator::class, + Strategies\BodyParameters\GetFromBodyParamAttribute::class, + Strategies\BodyParameters\GetFromBodyParamTag::class, + ], + 'responses' => [ + Strategies\Responses\UseResponseAttributes::class, + Strategies\Responses\UseTransformerTags::class, + Strategies\Responses\UseApiResourceTags::class, + Strategies\Responses\UseResponseTag::class, + Strategies\Responses\UseResponseFileTag::class, + [ + Strategies\Responses\ResponseCalls::class, + [ + 'only' => ['GET *'], + // Disable debug mode when generating response calls to avoid error stack traces in responses + 'config' => [ + 'app.debug' => false, + ], + ], + ], + ], + 'responseFields' => [ + Strategies\ResponseFields\GetFromResponseFieldAttribute::class, + Strategies\ResponseFields\GetFromResponseFieldTag::class, + ], + ], + + // For response calls, API resource responses and transformer responses, + // Scribe will try to start database transactions, so no changes are persisted to your database. + // Tell Scribe which connections should be transacted here. If you only use one db connection, you can leave this as is. + 'database_connections_to_transact' => [config('database.default')], + + 'fractal' => [ + // If you are using a custom serializer with league/fractal, you can specify it here. + 'serializer' => null, + ], + + 'routeMatcher' => \Knuckles\Scribe\Matching\RouteMatcher::class, +]; diff --git a/public/docs/collection.json b/public/docs/collection.json new file mode 100644 index 0000000..45faaeb --- /dev/null +++ b/public/docs/collection.json @@ -0,0 +1,486 @@ +{ + "variable": [ + { + "id": "baseUrl", + "key": "baseUrl", + "type": "string", + "name": "string", + "value": "http:\/\/forge.test" + } + ], + "info": { + "name": "The Forge API Documentation", + "_postman_id": "111f14f0-1551-4ff3-a8c0-1301df26b9c2", + "description": "", + "schema": "https:\/\/schema.getpostman.com\/json\/collection\/v2.1.0\/collection.json" + }, + "item": [ + { + "name": "Authentication", + "description": "", + "item": [ + { + "name": "Login", + "request": { + "url": { + "host": "{{baseUrl}}", + "path": "api\/login", + "query": [], + "raw": "{{baseUrl}}\/api\/login" + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application\/json" + }, + { + "key": "Accept", + "value": "application\/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\"email\":\"olson.margret@example.net\",\"password\":\"j\\\/.0^{~eOsyx^\",\"token_name\":\"Dynamic API Token\"}" + }, + "description": "Authenticates the user and returns a read-only API token. This API token can then be saved and used for future\nrequests that require authentication.