From 5699dadd28d9cc109679dc594477e7887e5931f0 Mon Sep 17 00:00:00 2001 From: hiren Date: Thu, 25 Aug 2022 12:35:19 +0530 Subject: [PATCH 01/13] Create models --- app/Models/Project.php | 28 ++++++ app/Models/Role.php | 19 ++++ app/Models/Task.php | 43 ++++++++++ app/Models/User.php | 18 +++- app/Traits/uuidtrait.php | 86 +++++++++++++++++++ composer.json | 1 + composer.lock | 60 ++++++++++++- .../2014_10_12_000000_create_users_table.php | 3 +- ...08_25_063204_initial_project_migration.php | 47 ++++++++++ database/seeders/RoleSeeder.php | 23 +++++ 10 files changed, 321 insertions(+), 7 deletions(-) create mode 100644 app/Models/Project.php create mode 100644 app/Models/Role.php create mode 100644 app/Models/Task.php create mode 100644 app/Traits/uuidtrait.php create mode 100644 database/migrations/2022_08_25_063204_initial_project_migration.php create mode 100644 database/seeders/RoleSeeder.php diff --git a/app/Models/Project.php b/app/Models/Project.php new file mode 100644 index 0000000..2c918c4 --- /dev/null +++ b/app/Models/Project.php @@ -0,0 +1,28 @@ + + */ + protected $fillable = [ + 'id', + 'name', + ]; + + public function task(){ + return $this->hasMany(Task::class, 'project_id', 'id'); + } +} diff --git a/app/Models/Role.php b/app/Models/Role.php new file mode 100644 index 0000000..45d6772 --- /dev/null +++ b/app/Models/Role.php @@ -0,0 +1,19 @@ + "Admin", + "PRODUCT_OWNER" => "Product Owner", + "TEAM_MEMBER" => "Team Member" + ]; +} diff --git a/app/Models/Task.php b/app/Models/Task.php new file mode 100644 index 0000000..582aa32 --- /dev/null +++ b/app/Models/Task.php @@ -0,0 +1,43 @@ + "NOT_STARTED", + "IN_PROGRESS" => "IN_PROGRESS", + "READY_FOR_TEST" => "READY_FOR_TEST", + "COMPLETED" => "COMPLETED", + ); + + /** + * The attributes that are mass assignable. + * + * @var array + */ + protected $fillable = [ + 'id', + 'title', + 'description', + 'status', + 'project_id', + 'user_id', + ]; + + public function project(){ + return $this->hasOne(Project::class, 'id', 'project_id'); + } + + public function user(){ + return $this->hasOne(User::class, 'id', 'user_id'); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 8996368..5c093f3 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,23 +4,25 @@ use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; -use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Sanctum\HasApiTokens; +use GoldSpecDigital\LaravelEloquentUUID\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { use HasApiTokens, HasFactory, Notifiable; + public $incrementing = false; + /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ - 'name', - 'email', - 'password', + 'id', + 'username', + 'role_id' ]; /** @@ -41,4 +43,12 @@ class User extends Authenticatable protected $casts = [ 'email_verified_at' => 'datetime', ]; + + public function task(){ + return $this->hasMany(Task::class, 'user_id', 'id'); + } + + public function role(){ + return $this->hasOne(Role::class, 'id', 'role_id'); + } } diff --git a/app/Traits/uuidtrait.php b/app/Traits/uuidtrait.php new file mode 100644 index 0000000..4d04a66 --- /dev/null +++ b/app/Traits/uuidtrait.php @@ -0,0 +1,86 @@ +uuid = Uuid::uuid4()->toString(); + }); + + static::saving(function ($model) { + // What's that, trying to change the UUID huh? Nope, not gonna happen. + $original_uuid = $model->getOriginal('uuid'); + + if ($original_uuid !== $model->uuid) { + $model->uuid = $original_uuid; + } + }); + } + + /** + * Scope a query to only include models matching the supplied UUID. + * Returns the model by default, or supply a second flag `false` to get the Query Builder instance. + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * + * @param \Illuminate\Database\Schema\Builder $query The Query Builder instance. + * @param string $uuid The UUID of the model. + * @param bool|true $first Returns the model by default, or set to `false` to chain for query builder. + * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder + */ + public function scopeUuid($query, $uuid, $first = true) + { + if (!is_string($uuid) || (preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $uuid) !== 1)) { + throw (new ModelNotFoundException)->setModel(get_class($this)); + } + + $search = $query->where('uuid', $uuid); + + return $first ? $search->firstOrFail() : $search; + } + + /** + * Scope a query to only include models matching the supplied ID or UUID. + * Returns the model by default, or supply a second flag `false` to get the Query Builder instance. + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * + * @param \Illuminate\Database\Schema\Builder $query The Query Builder instance. + * @param string $uuid The UUID of the model. + * @param bool|true $first Returns the model by default, or set to `false` to chain for query builder. + * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder + */ + public function scopeIdOrUuId($query, $id_or_uuid, $first = true) + { + if (!is_string($id_or_uuid) && !is_numeric($id_or_uuid)) { + throw (new ModelNotFoundException)->setModel(get_class($this)); + } + + if (preg_match('/^([0-9]+|[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$/', $id_or_uuid) !== 1) { + throw (new ModelNotFoundException)->setModel(get_class($this)); + } + + $search = $query->where(function ($query) use ($id_or_uuid) { + $query->where('id', $id_or_uuid) + ->orWhere('uuid', $id_or_uuid); + }); + + return $first ? $search->firstOrFail() : $search; + } +} diff --git a/composer.json b/composer.json index 2b0c115..a7b4e01 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,7 @@ "require": { "php": "^7.3|^8.0", "fruitcake/laravel-cors": "^2.0", + "goldspecdigital/laravel-eloquent-uuid": "^8.0", "guzzlehttp/guzzle": "^7.0.1", "laravel/framework": "^8.75", "laravel/sanctum": "^2.11", diff --git a/composer.lock b/composer.lock index 59a2b32..6437de7 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": "c61ff82cbf0142a401a48a8161e1595a", + "content-hash": "35ab0206631194c1ac5162ce6519e6cc", "packages": [ { "name": "brick/math", @@ -587,6 +587,62 @@ ], "time": "2022-02-20T15:07:15+00:00" }, + { + "name": "goldspecdigital/laravel-eloquent-uuid", + "version": "v8.0.1", + "source": { + "type": "git", + "url": "https://github.com/goldspecdigital/laravel-eloquent-uuid.git", + "reference": "e98748113e3b9de5b408cdc306e9d93e18121988" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/goldspecdigital/laravel-eloquent-uuid/zipball/e98748113e3b9de5b408cdc306e9d93e18121988", + "reference": "e98748113e3b9de5b408cdc306e9d93e18121988", + "shasum": "" + }, + "require": { + "laravel/framework": "^8.0", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "ext-pdo": "*", + "orchestra/testbench": "^6.0", + "phpunit/phpunit": "^8.4" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "GoldSpecDigital\\LaravelEloquentUUID\\UuidServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "GoldSpecDigital\\LaravelEloquentUUID\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Inamdar", + "email": "matt@goldspecdigital.com" + } + ], + "description": "A simple drop-in solution for providing UUID support for the IDs of your Eloquent models.", + "homepage": "https://github.com/goldspecdigital/laravel-eloquent-uuid", + "keywords": [ + "eloquent", + "laravel", + "php", + "uuid" + ], + "time": "2020-12-23T10:10:54+00:00" + }, { "name": "graham-campbell/result-type", "version": "v1.0.4", @@ -7918,5 +7974,5 @@ "php": "^7.3|^8.0" }, "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "1.1.0" } diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php index 621a24e..578e6ce 100644 --- a/database/migrations/2014_10_12_000000_create_users_table.php +++ b/database/migrations/2014_10_12_000000_create_users_table.php @@ -14,11 +14,12 @@ class CreateUsersTable extends Migration public function up() { Schema::create('users', function (Blueprint $table) { - $table->id(); + $table->uuid('id')->primary(); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); + $table->integer('role_id')->nullable(); $table->rememberToken(); $table->timestamps(); }); diff --git a/database/migrations/2022_08_25_063204_initial_project_migration.php b/database/migrations/2022_08_25_063204_initial_project_migration.php new file mode 100644 index 0000000..59de770 --- /dev/null +++ b/database/migrations/2022_08_25_063204_initial_project_migration.php @@ -0,0 +1,47 @@ +uuid('id')->primary(); + $table->string('name')->unique(); + }); + Schema::create('tasks', function (Blueprint $table) { + $table->uuid('id')->primary(); + $table->string('title'); + $table->string('description'); + $table->string('status'); + $table->uuid('project_id'); + $table->uuid('user_id'); + }); + Schema::create('roles', function (Blueprint $table) { + $table->id(); + $table->string('slug')->unique(); + $table->string('name')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('projects'); + Schema::dropIfExists('tasks'); + Schema::dropIfExists('roles'); + } +} diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php new file mode 100644 index 0000000..800d02c --- /dev/null +++ b/database/seeders/RoleSeeder.php @@ -0,0 +1,23 @@ + $value) { + $role = Role::firstOrCreate(['slug'=>$roleKey]); + $role->name = $value; + $role->save(); + } + + } +} From 128477bf6e3c9b425e4c3cd6a81c5ac559f4d69c Mon Sep 17 00:00:00 2001 From: hiren Date: Thu, 25 Aug 2022 14:56:28 +0530 Subject: [PATCH 02/13] WIP: RestAPIs --- app/Http/Controllers/UserController.php | 79 + app/Http/Requests/UserRequest.php | 59 + app/Managers/UserManager.php | 35 + app/Providers/AppServiceProvider.php | 6 +- app/Resources/UserResource.php | 31 + app/Traits/uuidtrait.php | 86 - app/api.php | 59 + composer.json | 1 + composer.lock | 1670 +++++++++-------- config/l5-swagger.php | 294 +++ database/seeders/User.php | 18 + resources/views/vendor/l5-swagger/.gitkeep | 0 .../views/vendor/l5-swagger/index.blade.php | 78 + routes/api.php | 5 + storage/api-docs/api-docs.json | 144 ++ 15 files changed, 1736 insertions(+), 829 deletions(-) create mode 100644 app/Http/Controllers/UserController.php create mode 100644 app/Http/Requests/UserRequest.php create mode 100644 app/Managers/UserManager.php create mode 100644 app/Resources/UserResource.php delete mode 100644 app/Traits/uuidtrait.php create mode 100644 app/api.php create mode 100644 config/l5-swagger.php create mode 100644 database/seeders/User.php create mode 100644 resources/views/vendor/l5-swagger/.gitkeep create mode 100644 resources/views/vendor/l5-swagger/index.blade.php create mode 100644 storage/api-docs/api-docs.json diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php new file mode 100644 index 0000000..811232f --- /dev/null +++ b/app/Http/Controllers/UserController.php @@ -0,0 +1,79 @@ +validated(); + + $user = $this->app('user_manager')->store($validated); + + return new UserResource($user); + } + + /** + * Display the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function show($id) + { + return new UserResource(User::findOrFail($id)); + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(UserRequest $request, User $user) + { + $validated = $request->validated(); + + $user = $this->app('user_manager')->store($validated, $user); + + return new UserResource($user); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy(User $user) + { + $user->delete(); + + return response()->json([ + 'message' => 'User deleted successfully' + ], 200); + } +} \ No newline at end of file diff --git a/app/Http/Requests/UserRequest.php b/app/Http/Requests/UserRequest.php new file mode 100644 index 0000000..edf7737 --- /dev/null +++ b/app/Http/Requests/UserRequest.php @@ -0,0 +1,59 @@ + __("Username")]); + $messages['username.min:3'] = __("The :name field must contain at least 3 character", ["name" => __("Username")]); + $messages['username.max:255'] = __("The :name field cannot exceed 255 character", ["name" => __("Username")]); + $messages['username.unique:users,username'] = __("The :name has already been taken", ["name" => __("Username")]); + + $messages['password.required'] = __("The :name field is required", ["name" => __("Password")]); + $messages['password.min:6'] = __("The :name must contain at least 6 character", ["name" => __("Password")]); + + $messages['role_id.required'] = __("The :name field is required", ["name" => __("Role")]); + $messages['role_id.exists'] = __("The :name not exist", ["name" => __("Role")]); + + return $messages; + + } +} \ No newline at end of file diff --git a/app/Managers/UserManager.php b/app/Managers/UserManager.php new file mode 100644 index 0000000..7b166be --- /dev/null +++ b/app/Managers/UserManager.php @@ -0,0 +1,35 @@ + $input['email'], + 'name' => $input['name'], + 'role_id' => $input['role_id'], + ]); + } else { + $user->fill([ + 'email' => $input['email'], + 'name' => $input['name'], + 'role_id' => $input['role_id'], + ]); + + } + if (isset($input['password'])) { + $user->password = bcrypt($input['password']); + } + $user->save(); + return $user; + } +} \ No newline at end of file diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index ee8ca5b..9b4766c 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -3,6 +3,7 @@ namespace App\Providers; use Illuminate\Support\ServiceProvider; +use App\Managers\UserManager; class AppServiceProvider extends ServiceProvider { @@ -13,7 +14,10 @@ class AppServiceProvider extends ServiceProvider */ public function register() { - // + $this->app->singleton('user_manager',function() { + return UserManager(); + }); + } /** diff --git a/app/Resources/UserResource.php b/app/Resources/UserResource.php new file mode 100644 index 0000000..a41556e --- /dev/null +++ b/app/Resources/UserResource.php @@ -0,0 +1,31 @@ + $this->id, + 'username' => $this->username, + 'role_id' => $this->role_id, + ]; + + } +} \ No newline at end of file diff --git a/app/Traits/uuidtrait.php b/app/Traits/uuidtrait.php deleted file mode 100644 index 4d04a66..0000000 --- a/app/Traits/uuidtrait.php +++ /dev/null @@ -1,86 +0,0 @@ -uuid = Uuid::uuid4()->toString(); - }); - - static::saving(function ($model) { - // What's that, trying to change the UUID huh? Nope, not gonna happen. - $original_uuid = $model->getOriginal('uuid'); - - if ($original_uuid !== $model->uuid) { - $model->uuid = $original_uuid; - } - }); - } - - /** - * Scope a query to only include models matching the supplied UUID. - * Returns the model by default, or supply a second flag `false` to get the Query Builder instance. - * - * @throws \Illuminate\Database\Eloquent\ModelNotFoundException - * - * @param \Illuminate\Database\Schema\Builder $query The Query Builder instance. - * @param string $uuid The UUID of the model. - * @param bool|true $first Returns the model by default, or set to `false` to chain for query builder. - * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder - */ - public function scopeUuid($query, $uuid, $first = true) - { - if (!is_string($uuid) || (preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $uuid) !== 1)) { - throw (new ModelNotFoundException)->setModel(get_class($this)); - } - - $search = $query->where('uuid', $uuid); - - return $first ? $search->firstOrFail() : $search; - } - - /** - * Scope a query to only include models matching the supplied ID or UUID. - * Returns the model by default, or supply a second flag `false` to get the Query Builder instance. - * - * @throws \Illuminate\Database\Eloquent\ModelNotFoundException - * - * @param \Illuminate\Database\Schema\Builder $query The Query Builder instance. - * @param string $uuid The UUID of the model. - * @param bool|true $first Returns the model by default, or set to `false` to chain for query builder. - * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder - */ - public function scopeIdOrUuId($query, $id_or_uuid, $first = true) - { - if (!is_string($id_or_uuid) && !is_numeric($id_or_uuid)) { - throw (new ModelNotFoundException)->setModel(get_class($this)); - } - - if (preg_match('/^([0-9]+|[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$/', $id_or_uuid) !== 1) { - throw (new ModelNotFoundException)->setModel(get_class($this)); - } - - $search = $query->where(function ($query) use ($id_or_uuid) { - $query->where('id', $id_or_uuid) - ->orWhere('uuid', $id_or_uuid); - }); - - return $first ? $search->firstOrFail() : $search; - } -} diff --git a/app/api.php b/app/api.php new file mode 100644 index 0000000..728bdc8 --- /dev/null +++ b/app/api.php @@ -0,0 +1,59 @@ +=8.40.0 || ^7.0", + "php": "^7.2 || ^8.0", + "swagger-api/swagger-ui": "^3.0", + "symfony/yaml": "^5.0", + "zircote/swagger-php": "3.*" + }, + "require-dev": { + "mockery/mockery": "1.*", + "orchestra/testbench": "6.* || 5.*", + "php-coveralls/php-coveralls": "^2.0", + "phpunit/phpunit": "9.*" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "L5Swagger\\L5SwaggerServiceProvider" + ], + "aliases": { + "L5Swagger": "L5Swagger\\L5SwaggerFacade" + } + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "L5Swagger\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Darius Matulionis", + "email": "darius@matulionis.lt" + } + ], + "description": "OpenApi or Swagger integration to Laravel", + "keywords": [ + "api", + "documentation", + "laravel", + "openapi", + "specification", + "swagger", + "ui" + ], + "support": { + "issues": "https://github.com/DarkaOnLine/L5-Swagger/issues", + "source": "https://github.com/DarkaOnLine/L5-Swagger/tree/8.1.0" + }, + "funding": [ + { + "url": "https://github.com/DarkaOnLine", + "type": "github" + } + ], + "time": "2022-01-07T09:08:44+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.1", @@ -141,6 +276,79 @@ }, "time": "2021-08-13T13:06:58+00:00" }, + { + "name": "doctrine/annotations", + "version": "1.13.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "648b0343343565c4a056bfc8392201385e8d89f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/648b0343343565c4a056bfc8392201385e8d89f0", + "reference": "648b0343343565c4a056bfc8392201385e8d89f0", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/coding-standard": "^6.0 || ^8.1", + "phpstan/phpstan": "^1.4.10 || ^1.8.0", + "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", + "symfony/cache": "^4.4 || ^5.2", + "vimeo/psalm": "^4.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.13.3" + }, + "time": "2022-07-02T10:48:51+00:00" + }, { "name": "doctrine/inflector", "version": "2.0.4", @@ -234,16 +442,16 @@ }, { "name": "doctrine/lexer", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "9c50f840f257bbb941e6f4a0e94ccf5db5c3f76c" + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/9c50f840f257bbb941e6f4a0e94ccf5db5c3f76c", - "reference": "9c50f840f257bbb941e6f4a0e94ccf5db5c3f76c", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", "shasum": "" }, "require": { @@ -251,7 +459,7 @@ }, "require-dev": { "doctrine/coding-standard": "^9.0", - "phpstan/phpstan": "1.3", + "phpstan/phpstan": "^1.3", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "vimeo/psalm": "^4.11" }, @@ -290,7 +498,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.2.2" + "source": "https://github.com/doctrine/lexer/tree/1.2.3" }, "funding": [ { @@ -306,7 +514,7 @@ "type": "tidelift" } ], - "time": "2022-01-12T08:27:12+00:00" + "time": "2022-02-28T11:07:21+00:00" }, { "name": "dragonmantank/cron-expression", @@ -439,20 +647,20 @@ }, { "name": "fruitcake/laravel-cors", - "version": "v2.1.0", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/fruitcake/laravel-cors.git", - "reference": "361d71f00a0eea8b74da26ae75d0d207c53aa5b3" + "reference": "783a74f5e3431d7b9805be8afb60fd0a8f743534" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fruitcake/laravel-cors/zipball/361d71f00a0eea8b74da26ae75d0d207c53aa5b3", - "reference": "361d71f00a0eea8b74da26ae75d0d207c53aa5b3", + "url": "https://api.github.com/repos/fruitcake/laravel-cors/zipball/783a74f5e3431d7b9805be8afb60fd0a8f743534", + "reference": "783a74f5e3431d7b9805be8afb60fd0a8f743534", "shasum": "" }, "require": { - "fruitcake/php-cors": "^1", + "asm89/stack-cors": "^2.0.1", "illuminate/contracts": "^6|^7|^8|^9", "illuminate/support": "^6|^7|^8|^9", "php": ">=7.2" @@ -502,7 +710,7 @@ ], "support": { "issues": "https://github.com/fruitcake/laravel-cors/issues", - "source": "https://github.com/fruitcake/laravel-cors/tree/v2.1.0" + "source": "https://github.com/fruitcake/laravel-cors/tree/v2.2.0" }, "funding": [ { @@ -514,78 +722,7 @@ "type": "github" } ], - "time": "2022-02-19T14:17:28+00:00" - }, - { - "name": "fruitcake/php-cors", - "version": "v1.2.0", - "source": { - "type": "git", - "url": "https://github.com/fruitcake/php-cors.git", - "reference": "58571acbaa5f9f462c9c77e911700ac66f446d4e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/58571acbaa5f9f462c9c77e911700ac66f446d4e", - "reference": "58571acbaa5f9f462c9c77e911700ac66f446d4e", - "shasum": "" - }, - "require": { - "php": "^7.4|^8.0", - "symfony/http-foundation": "^4.4|^5.4|^6" - }, - "require-dev": { - "phpstan/phpstan": "^1.4", - "phpunit/phpunit": "^9", - "squizlabs/php_codesniffer": "^3.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.1-dev" - } - }, - "autoload": { - "psr-4": { - "Fruitcake\\Cors\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fruitcake", - "homepage": "https://fruitcake.nl" - }, - { - "name": "Barryvdh", - "email": "barryvdh@gmail.com" - } - ], - "description": "Cross-origin resource sharing library for the Symfony HttpFoundation", - "homepage": "https://github.com/fruitcake/php-cors", - "keywords": [ - "cors", - "laravel", - "symfony" - ], - "support": { - "issues": "https://github.com/fruitcake/php-cors/issues", - "source": "https://github.com/fruitcake/php-cors/tree/v1.2.0" - }, - "funding": [ - { - "url": "https://fruitcake.nl", - "type": "custom" - }, - { - "url": "https://github.com/barryvdh", - "type": "github" - } - ], - "time": "2022-02-20T15:07:15+00:00" + "time": "2022-02-23T14:25:13+00:00" }, { "name": "goldspecdigital/laravel-eloquent-uuid", @@ -641,28 +778,32 @@ "php", "uuid" ], + "support": { + "issues": "https://github.com/goldspecdigital/laravel-eloquent-uuid/issues", + "source": "https://github.com/goldspecdigital/laravel-eloquent-uuid/tree/v8.0.1" + }, "time": "2020-12-23T10:10:54+00:00" }, { "name": "graham-campbell/result-type", - "version": "v1.0.4", + "version": "v1.1.0", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "0690bde05318336c7221785f2a932467f98b64ca" + "reference": "a878d45c1914464426dc94da61c9e1d36ae262a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/0690bde05318336c7221785f2a932467f98b64ca", - "reference": "0690bde05318336c7221785f2a932467f98b64ca", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/a878d45c1914464426dc94da61c9e1d36ae262a8", + "reference": "a878d45c1914464426dc94da61c9e1d36ae262a8", "shasum": "" }, "require": { - "php": "^7.0 || ^8.0", - "phpoption/phpoption": "^1.8" + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9" }, "require-dev": { - "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8" + "phpunit/phpunit": "^8.5.28 || ^9.5.21" }, "type": "library", "autoload": { @@ -691,7 +832,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.4" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.0" }, "funding": [ { @@ -703,26 +844,26 @@ "type": "tidelift" } ], - "time": "2021-11-21T21:41:47+00:00" + "time": "2022-07-30T15:56:11+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "7.4.1", + "version": "7.4.5", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79" + "reference": "1dd98b0564cb3f6bd16ce683cb755f94c10fbd82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ee0a041b1760e6a53d2a39c8c34115adc2af2c79", - "reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/1dd98b0564cb3f6bd16ce683cb755f94c10fbd82", + "reference": "1dd98b0564cb3f6bd16ce683cb755f94c10fbd82", "shasum": "" }, "require": { "ext-json": "*", "guzzlehttp/promises": "^1.5", - "guzzlehttp/psr7": "^1.8.3 || ^2.1", + "guzzlehttp/psr7": "^1.9 || ^2.4", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -811,7 +952,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.4.1" + "source": "https://github.com/guzzle/guzzle/tree/7.4.5" }, "funding": [ { @@ -827,7 +968,7 @@ "type": "tidelift" } ], - "time": "2021-12-06T18:43:05+00:00" + "time": "2022-06-20T22:16:13+00:00" }, { "name": "guzzlehttp/promises", @@ -856,12 +997,12 @@ } }, "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -915,16 +1056,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.1.0", + "version": "2.4.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72" + "reference": "13388f00956b1503577598873fffb5ae994b5737" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/089edd38f5b8abba6cb01567c2a8aaa47cec4c72", - "reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/13388f00956b1503577598873fffb5ae994b5737", + "reference": "13388f00956b1503577598873fffb5ae994b5737", "shasum": "" }, "require": { @@ -948,7 +1089,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "2.4-dev" } }, "autoload": { @@ -1010,7 +1151,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.1.0" + "source": "https://github.com/guzzle/psr7/tree/2.4.0" }, "funding": [ { @@ -1026,20 +1167,20 @@ "type": "tidelift" } ], - "time": "2021-10-06T17:43:30+00:00" + "time": "2022-06-20T21:43:11+00:00" }, { "name": "laravel/framework", - "version": "v8.83.1", + "version": "v8.83.23", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "bddba117f8bce2f3c9875ca1ca375a96350d0f4d" + "reference": "bdc707f8b9bcad289b24cd182d98ec7480ac4491" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/bddba117f8bce2f3c9875ca1ca375a96350d0f4d", - "reference": "bddba117f8bce2f3c9875ca1ca375a96350d0f4d", + "url": "https://api.github.com/repos/laravel/framework/zipball/bdc707f8b9bcad289b24cd182d98ec7480ac4491", + "reference": "bdc707f8b9bcad289b24cd182d98ec7480ac4491", "shasum": "" }, "require": { @@ -1199,24 +1340,25 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2022-02-15T15:05:20+00:00" + "time": "2022-07-26T13:30:00+00:00" }, { "name": "laravel/sanctum", - "version": "v2.14.1", + "version": "v2.15.1", "source": { "type": "git", "url": "https://github.com/laravel/sanctum.git", - "reference": "89937617fa144ddb759a740861a47c4f2fd2245b" + "reference": "31fbe6f85aee080c4dc2f9b03dc6dd5d0ee72473" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sanctum/zipball/89937617fa144ddb759a740861a47c4f2fd2245b", - "reference": "89937617fa144ddb759a740861a47c4f2fd2245b", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/31fbe6f85aee080c4dc2f9b03dc6dd5d0ee72473", + "reference": "31fbe6f85aee080c4dc2f9b03dc6dd5d0ee72473", "shasum": "" }, "require": { "ext-json": "*", + "illuminate/console": "^6.9|^7.0|^8.0|^9.0", "illuminate/contracts": "^6.9|^7.0|^8.0|^9.0", "illuminate/database": "^6.9|^7.0|^8.0|^9.0", "illuminate/support": "^6.9|^7.0|^8.0|^9.0", @@ -1263,20 +1405,20 @@ "issues": "https://github.com/laravel/sanctum/issues", "source": "https://github.com/laravel/sanctum" }, - "time": "2022-02-15T08:08:57+00:00" + "time": "2022-04-08T13:39:49+00:00" }, { "name": "laravel/serializable-closure", - "version": "v1.1.1", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "9e4b005daa20b0c161f3845040046dc9ddc1d74e" + "reference": "09f0e9fb61829f628205b7c94906c28740ff9540" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/9e4b005daa20b0c161f3845040046dc9ddc1d74e", - "reference": "9e4b005daa20b0c161f3845040046dc9ddc1d74e", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/09f0e9fb61829f628205b7c94906c28740ff9540", + "reference": "09f0e9fb61829f628205b7c94906c28740ff9540", "shasum": "" }, "require": { @@ -1322,20 +1464,20 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2022-02-11T19:23:53+00:00" + "time": "2022-05-16T17:09:47+00:00" }, { "name": "laravel/tinker", - "version": "v2.7.0", + "version": "v2.7.2", "source": { "type": "git", "url": "https://github.com/laravel/tinker.git", - "reference": "5f2f9815b7631b9f586a3de7933c25f9327d4073" + "reference": "dff39b661e827dae6e092412f976658df82dbac5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/5f2f9815b7631b9f586a3de7933c25f9327d4073", - "reference": "5f2f9815b7631b9f586a3de7933c25f9327d4073", + "url": "https://api.github.com/repos/laravel/tinker/zipball/dff39b661e827dae6e092412f976658df82dbac5", + "reference": "dff39b661e827dae6e092412f976658df82dbac5", "shasum": "" }, "require": { @@ -1388,22 +1530,22 @@ ], "support": { "issues": "https://github.com/laravel/tinker/issues", - "source": "https://github.com/laravel/tinker/tree/v2.7.0" + "source": "https://github.com/laravel/tinker/tree/v2.7.2" }, - "time": "2022-01-10T08:52:49+00:00" + "time": "2022-03-23T12:38:24+00:00" }, { "name": "league/commonmark", - "version": "2.2.2", + "version": "2.3.5", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "13d7751377732637814f0cda0e3f6d3243f9f769" + "reference": "84d74485fdb7074f4f9dd6f02ab957b1de513257" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/13d7751377732637814f0cda0e3f6d3243f9f769", - "reference": "13d7751377732637814f0cda0e3f6d3243f9f769", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/84d74485fdb7074f4f9dd6f02ab957b1de513257", + "reference": "84d74485fdb7074f4f9dd6f02ab957b1de513257", "shasum": "" }, "require": { @@ -1412,24 +1554,26 @@ "php": "^7.4 || ^8.0", "psr/event-dispatcher": "^1.0", "symfony/deprecation-contracts": "^2.1 || ^3.0", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "require-dev": { "cebe/markdown": "^1.0", "commonmark/cmark": "0.30.0", "commonmark/commonmark.js": "0.30.0", "composer/package-versions-deprecated": "^1.8", + "embed/embed": "^4.4", "erusev/parsedown": "^1.0", "ext-json": "*", "github/gfm": "0.29.0", "michelf/php-markdown": "^1.4", - "phpstan/phpstan": "^0.12.88 || ^1.0.0", - "phpunit/phpunit": "^9.5.5", + "nyholm/psr7": "^1.5", + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.21", "scrutinizer/ocular": "^1.8.1", - "symfony/finder": "^5.3", + "symfony/finder": "^5.3 | ^6.0", "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0", - "unleashedtech/php-coding-standard": "^3.1", - "vimeo/psalm": "^4.7.3" + "unleashedtech/php-coding-standard": "^3.1.1", + "vimeo/psalm": "^4.24.0" }, "suggest": { "symfony/yaml": "v2.3+ required if using the Front Matter extension" @@ -1437,7 +1581,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.3-dev" + "dev-main": "2.4-dev" } }, "autoload": { @@ -1494,7 +1638,7 @@ "type": "tidelift" } ], - "time": "2022-02-13T15:00:57+00:00" + "time": "2022-07-29T10:59:45+00:00" }, { "name": "league/config", @@ -1674,16 +1818,16 @@ }, { "name": "league/mime-type-detection", - "version": "1.9.0", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "aa70e813a6ad3d1558fc927863d47309b4c23e69" + "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/aa70e813a6ad3d1558fc927863d47309b4c23e69", - "reference": "aa70e813a6ad3d1558fc927863d47309b4c23e69", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ff6248ea87a9f116e78edd6002e39e5128a0d4dd", + "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd", "shasum": "" }, "require": { @@ -1714,7 +1858,7 @@ "description": "Mime-type detection for Flysystem", "support": { "issues": "https://github.com/thephpleague/mime-type-detection/issues", - "source": "https://github.com/thephpleague/mime-type-detection/tree/1.9.0" + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.11.0" }, "funding": [ { @@ -1726,20 +1870,20 @@ "type": "tidelift" } ], - "time": "2021-11-21T11:48:40+00:00" + "time": "2022-04-17T13:12:02+00:00" }, { "name": "monolog/monolog", - "version": "2.3.5", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "fd4380d6fc37626e2f799f29d91195040137eba9" + "reference": "720488632c590286b88b80e62aa3d3d551ad4a50" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd4380d6fc37626e2f799f29d91195040137eba9", - "reference": "fd4380d6fc37626e2f799f29d91195040137eba9", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/720488632c590286b88b80e62aa3d3d551ad4a50", + "reference": "720488632c590286b88b80e62aa3d3d551ad4a50", "shasum": "" }, "require": { @@ -1752,18 +1896,22 @@ "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "elasticsearch/elasticsearch": "^7", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", "graylog2/gelf-php": "^1.4.2", + "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", - "php-console/php-console": "^3.1.3", - "phpspec/prophecy": "^1.6.1", + "phpspec/prophecy": "^1.15", "phpstan/phpstan": "^0.12.91", - "phpunit/phpunit": "^8.5", - "predis/predis": "^1.1", - "rollbar/rollbar": "^1.3", - "ruflin/elastica": ">=0.90@dev", - "swiftmailer/swiftmailer": "^5.3|^6.0" + "phpunit/phpunit": "^8.5.14", + "predis/predis": "^1.1 || ^2.0", + "rollbar/rollbar": "^1.3 || ^2 || ^3", + "ruflin/elastica": "^7", + "swiftmailer/swiftmailer": "^5.3|^6.0", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", @@ -1778,7 +1926,6 @@ "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", - "php-console/php-console": "Allow sending log messages to Google Chrome", "rollbar/rollbar": "Allow sending log messages to Rollbar", "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, @@ -1813,7 +1960,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.3.5" + "source": "https://github.com/Seldaek/monolog/tree/2.8.0" }, "funding": [ { @@ -1825,20 +1972,20 @@ "type": "tidelift" } ], - "time": "2021-10-01T21:08:31+00:00" + "time": "2022-07-24T11:55:47+00:00" }, { "name": "nesbot/carbon", - "version": "2.57.0", + "version": "2.61.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "4a54375c21eea4811dbd1149fe6b246517554e78" + "reference": "bdf4f4fe3a3eac4de84dbec0738082a862c68ba6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4a54375c21eea4811dbd1149fe6b246517554e78", - "reference": "4a54375c21eea4811dbd1149fe6b246517554e78", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/bdf4f4fe3a3eac4de84dbec0738082a862c68ba6", + "reference": "bdf4f4fe3a3eac4de84dbec0738082a862c68ba6", "shasum": "" }, "require": { @@ -1853,10 +2000,12 @@ "doctrine/orm": "^2.7", "friendsofphp/php-cs-fixer": "^3.0", "kylekatarnls/multi-tester": "^2.0", + "ondrejmirtes/better-reflection": "*", "phpmd/phpmd": "^2.9", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.54 || ^1.0", - "phpunit/phpunit": "^7.5.20 || ^8.5.14", + "phpstan/phpstan": "^0.12.99 || ^1.7.14", + "phpunit/php-file-iterator": "^2.0.5 || ^3.0.6", + "phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20", "squizlabs/php_codesniffer": "^3.4" }, "bin": [ @@ -1913,15 +2062,19 @@ }, "funding": [ { - "url": "https://opencollective.com/Carbon", - "type": "open_collective" + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", "type": "tidelift" } ], - "time": "2022-02-13T18:13:33+00:00" + "time": "2022-08-06T12:41:24+00:00" }, { "name": "nette/schema", @@ -2072,16 +2225,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.13.2", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077" + "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/34bea19b6e03d8153165d8f30bba4c3be86184c1", + "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1", "shasum": "" }, "require": { @@ -2122,9 +2275,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.14.0" }, - "time": "2021-11-30T19:35:32+00:00" + "time": "2022-05-31T20:59:12+00:00" }, { "name": "opis/closure", @@ -2154,12 +2307,12 @@ } }, "autoload": { - "psr-4": { - "Opis\\Closure\\": "src/" - }, "files": [ "functions.php" - ] + ], + "psr-4": { + "Opis\\Closure\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2193,29 +2346,33 @@ }, { "name": "phpoption/phpoption", - "version": "1.8.1", + "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15" + "reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15", - "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dc5ff11e274a90cc1c743f66c9ad700ce50db9ab", + "reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab", "shasum": "" }, "require": { - "php": "^7.0 || ^8.0" + "php": "^7.2.5 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.4.1", - "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8" + "bamarni/composer-bin-plugin": "^1.8", + "phpunit/phpunit": "^8.5.28 || ^9.5.21" }, "type": "library", "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true + }, "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -2248,7 +2405,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.8.1" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.0" }, "funding": [ { @@ -2260,7 +2417,56 @@ "type": "tidelift" } ], - "time": "2021-12-04T23:24:31+00:00" + "time": "2022-07-30T15:51:26+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" }, { "name": "psr/container", @@ -2623,16 +2829,16 @@ }, { "name": "psy/psysh", - "version": "v0.11.1", + "version": "v0.11.8", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "570292577277f06f590635381a7f761a6cf4f026" + "reference": "f455acf3645262ae389b10e9beba0c358aa6994e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/570292577277f06f590635381a7f761a6cf4f026", - "reference": "570292577277f06f590635381a7f761a6cf4f026", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/f455acf3645262ae389b10e9beba0c358aa6994e", + "reference": "f455acf3645262ae389b10e9beba0c358aa6994e", "shasum": "" }, "require": { @@ -2643,16 +2849,17 @@ "symfony/console": "^6.0 || ^5.0 || ^4.0 || ^3.4", "symfony/var-dumper": "^6.0 || ^5.0 || ^4.0 || ^3.4" }, + "conflict": { + "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" + }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.2", - "hoa/console": "3.17.05.02" + "bamarni/composer-bin-plugin": "^1.2" }, "suggest": { "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", "ext-pdo-sqlite": "The doc command requires SQLite to work.", "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", - "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history.", - "hoa/console": "A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit." + "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history." }, "bin": [ "bin/psysh" @@ -2692,9 +2899,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.11.1" + "source": "https://github.com/bobthecow/psysh/tree/v0.11.8" }, - "time": "2022-01-03T13:58:38+00:00" + "time": "2022-07-28T14:25:11+00:00" }, { "name": "ralouphie/getallheaders", @@ -2884,12 +3091,12 @@ } }, "autoload": { - "psr-4": { - "Ramsey\\Uuid\\": "src/" - }, "files": [ "src/functions.php" - ] + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2917,6 +3124,67 @@ ], "time": "2021-09-25T23:10:38+00:00" }, + { + "name": "swagger-api/swagger-ui", + "version": "v3.52.5", + "source": { + "type": "git", + "url": "https://github.com/swagger-api/swagger-ui.git", + "reference": "f1ad60dc92e7edb0898583e16c3e66fe3e9eada2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swagger-api/swagger-ui/zipball/f1ad60dc92e7edb0898583e16c3e66fe3e9eada2", + "reference": "f1ad60dc92e7edb0898583e16c3e66fe3e9eada2", + "shasum": "" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Anna Bodnia", + "email": "anna.bodnia@gmail.com" + }, + { + "name": "Buu Nguyen", + "email": "buunguyen@gmail.com" + }, + { + "name": "Josh Ponelat", + "email": "jponelat@gmail.com" + }, + { + "name": "Kyle Shockey", + "email": "kyleshockey1@gmail.com" + }, + { + "name": "Robert Barnwell", + "email": "robert@robertismy.name" + }, + { + "name": "Sahar Jafari", + "email": "shr.jafari@gmail.com" + } + ], + "description": " Swagger UI is a collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.", + "homepage": "http://swagger.io", + "keywords": [ + "api", + "documentation", + "openapi", + "specification", + "swagger", + "ui" + ], + "support": { + "issues": "https://github.com/swagger-api/swagger-ui/issues", + "source": "https://github.com/swagger-api/swagger-ui/tree/v3.52.5" + }, + "time": "2021-10-14T14:25:14+00:00" + }, { "name": "swiftmailer/swiftmailer", "version": "v6.3.0", @@ -2995,16 +3263,16 @@ }, { "name": "symfony/console", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a2a86ec353d825c75856c6fd14fac416a7bdb6b8" + "reference": "535846c7ee6bc4dd027ca0d93220601456734b10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a2a86ec353d825c75856c6fd14fac416a7bdb6b8", - "reference": "a2a86ec353d825c75856c6fd14fac416a7bdb6b8", + "url": "https://api.github.com/repos/symfony/console/zipball/535846c7ee6bc4dd027ca0d93220601456734b10", + "reference": "535846c7ee6bc4dd027ca0d93220601456734b10", "shasum": "" }, "require": { @@ -3074,7 +3342,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.3" + "source": "https://github.com/symfony/console/tree/v5.4.11" }, "funding": [ { @@ -3090,20 +3358,20 @@ "type": "tidelift" } ], - "time": "2022-01-26T16:28:35+00:00" + "time": "2022-07-22T10:42:43+00:00" }, { "name": "symfony/css-selector", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "b0a190285cd95cb019237851205b8140ef6e368e" + "reference": "c1681789f059ab756001052164726ae88512ae3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/b0a190285cd95cb019237851205b8140ef6e368e", - "reference": "b0a190285cd95cb019237851205b8140ef6e368e", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/c1681789f059ab756001052164726ae88512ae3d", + "reference": "c1681789f059ab756001052164726ae88512ae3d", "shasum": "" }, "require": { @@ -3140,7 +3408,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.4.3" + "source": "https://github.com/symfony/css-selector/tree/v5.4.11" }, "funding": [ { @@ -3156,20 +3424,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-06-27T16:58:25+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.0", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", - "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", "shasum": "" }, "require": { @@ -3207,7 +3475,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" }, "funding": [ { @@ -3223,20 +3491,20 @@ "type": "tidelift" } ], - "time": "2021-07-12T14:48:14+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/error-handler", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "c4ffc2cd919950d13c8c9ce32a70c70214c3ffc5" + "reference": "f75d17cb4769eb38cd5fccbda95cd80a054d35c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/c4ffc2cd919950d13c8c9ce32a70c70214c3ffc5", - "reference": "c4ffc2cd919950d13c8c9ce32a70c70214c3ffc5", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/f75d17cb4769eb38cd5fccbda95cd80a054d35c8", + "reference": "f75d17cb4769eb38cd5fccbda95cd80a054d35c8", "shasum": "" }, "require": { @@ -3278,7 +3546,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.4.3" + "source": "https://github.com/symfony/error-handler/tree/v5.4.11" }, "funding": [ { @@ -3294,20 +3562,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-07-29T07:37:50+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.4.3", + "version": "v5.4.9", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d" + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dec8a9f58d20df252b9cd89f1c6c1530f747685d", - "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", + "reference": "8e6ce1cc0279e3ff3c8ff0f43813bc88d21ca1bc", "shasum": "" }, "require": { @@ -3363,7 +3631,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.3" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.9" }, "funding": [ { @@ -3379,20 +3647,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-05-05T16:45:39+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v2.5.0", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "66bea3b09be61613cd3b4043a65a8ec48cfa6d2a" + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/66bea3b09be61613cd3b4043a65a8ec48cfa6d2a", - "reference": "66bea3b09be61613cd3b4043a65a8ec48cfa6d2a", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", "shasum": "" }, "require": { @@ -3442,7 +3710,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2" }, "funding": [ { @@ -3458,20 +3726,20 @@ "type": "tidelift" } ], - "time": "2021-07-12T14:48:14+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/finder", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d" + "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/231313534dded84c7ecaa79d14bc5da4ccb69b7d", - "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d", + "url": "https://api.github.com/repos/symfony/finder/zipball/7872a66f57caffa2916a584db1aa7f12adc76f8c", + "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c", "shasum": "" }, "require": { @@ -3505,7 +3773,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.3" + "source": "https://github.com/symfony/finder/tree/v5.4.11" }, "funding": [ { @@ -3521,20 +3789,20 @@ "type": "tidelift" } ], - "time": "2022-01-26T16:34:36+00:00" + "time": "2022-07-29T07:37:50+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "ef409ff341a565a3663157d4324536746d49a0c7" + "reference": "0a5868e0999e9d47859ba3d918548ff6943e6389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ef409ff341a565a3663157d4324536746d49a0c7", - "reference": "ef409ff341a565a3663157d4324536746d49a0c7", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/0a5868e0999e9d47859ba3d918548ff6943e6389", + "reference": "0a5868e0999e9d47859ba3d918548ff6943e6389", "shasum": "" }, "require": { @@ -3578,7 +3846,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.3" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.11" }, "funding": [ { @@ -3594,20 +3862,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.4.4", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "49f40347228c773688a0488feea0175aa7f4d268" + "reference": "4fd590a2ef3f62560dbbf6cea511995dd77321ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/49f40347228c773688a0488feea0175aa7f4d268", - "reference": "49f40347228c773688a0488feea0175aa7f4d268", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/4fd590a2ef3f62560dbbf6cea511995dd77321ee", + "reference": "4fd590a2ef3f62560dbbf6cea511995dd77321ee", "shasum": "" }, "require": { @@ -3690,7 +3958,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.4.4" + "source": "https://github.com/symfony/http-kernel/tree/v5.4.11" }, "funding": [ { @@ -3706,20 +3974,20 @@ "type": "tidelift" } ], - "time": "2022-01-29T18:08:07+00:00" + "time": "2022-07-29T12:30:22+00:00" }, { "name": "symfony/mime", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "e1503cfb5c9a225350f549d3bb99296f4abfb80f" + "reference": "3cd175cdcdb6db2e589e837dd46aff41027d9830" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/e1503cfb5c9a225350f549d3bb99296f4abfb80f", - "reference": "e1503cfb5c9a225350f549d3bb99296f4abfb80f", + "url": "https://api.github.com/repos/symfony/mime/zipball/3cd175cdcdb6db2e589e837dd46aff41027d9830", + "reference": "3cd175cdcdb6db2e589e837dd46aff41027d9830", "shasum": "" }, "require": { @@ -3773,7 +4041,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.3" + "source": "https://github.com/symfony/mime/tree/v5.4.11" }, "funding": [ { @@ -3789,20 +4057,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-07-20T11:34:24+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", "shasum": "" }, "require": { @@ -3817,7 +4085,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3825,12 +4093,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3855,7 +4123,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" }, "funding": [ { @@ -3871,20 +4139,20 @@ "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-iconv", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "f1aed619e28cb077fc83fac8c4c0383578356e40" + "reference": "143f1881e655bebca1312722af8068de235ae5dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/f1aed619e28cb077fc83fac8c4c0383578356e40", - "reference": "f1aed619e28cb077fc83fac8c4c0383578356e40", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/143f1881e655bebca1312722af8068de235ae5dc", + "reference": "143f1881e655bebca1312722af8068de235ae5dc", "shasum": "" }, "require": { @@ -3899,7 +4167,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3938,7 +4206,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.26.0" }, "funding": [ { @@ -3954,20 +4222,20 @@ "type": "tidelift" } ], - "time": "2022-01-04T09:04:05+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + "reference": "433d05519ce6990bf3530fba6957499d327395c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", + "reference": "433d05519ce6990bf3530fba6957499d327395c2", "shasum": "" }, "require": { @@ -3979,7 +4247,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4019,7 +4287,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" }, "funding": [ { @@ -4035,20 +4303,20 @@ "type": "tidelift" } ], - "time": "2021-11-23T21:10:46+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "749045c69efb97c70d25d7463abba812e91f3a44" + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/749045c69efb97c70d25d7463abba812e91f3a44", - "reference": "749045c69efb97c70d25d7463abba812e91f3a44", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8", "shasum": "" }, "require": { @@ -4062,7 +4330,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4106,7 +4374,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0" }, "funding": [ { @@ -4122,20 +4390,20 @@ "type": "tidelift" } ], - "time": "2021-09-14T14:02:44+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", "shasum": "" }, "require": { @@ -4147,7 +4415,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4190,7 +4458,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" }, "funding": [ { @@ -4206,20 +4474,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", "shasum": "" }, "require": { @@ -4234,7 +4502,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4273,7 +4541,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" }, "funding": [ { @@ -4289,20 +4557,20 @@ "type": "tidelift" } ], - "time": "2021-11-30T18:21:41+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" + "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/bf44a9fd41feaac72b074de600314a93e2ae78e2", + "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2", "shasum": "" }, "require": { @@ -4311,7 +4579,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4349,7 +4617,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.26.0" }, "funding": [ { @@ -4365,20 +4633,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:17:38+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85", + "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85", "shasum": "" }, "require": { @@ -4387,7 +4655,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4428,7 +4696,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0" }, "funding": [ { @@ -4444,20 +4712,20 @@ "type": "tidelift" } ], - "time": "2021-06-05T21:20:04+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9" + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/57b712b08eddb97c762a8caa32c84e037892d2e9", - "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", "shasum": "" }, "require": { @@ -4466,7 +4734,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4511,7 +4779,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" }, "funding": [ { @@ -4527,20 +4795,20 @@ "type": "tidelift" } ], - "time": "2021-09-13T13:58:33+00:00" + "time": "2022-05-10T07:21:04+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.24.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f" + "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", - "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1", + "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1", "shasum": "" }, "require": { @@ -4549,7 +4817,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4590,7 +4858,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.24.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0" }, "funding": [ { @@ -4606,20 +4874,20 @@ "type": "tidelift" } ], - "time": "2021-09-13T13:58:11+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/process", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "553f50487389a977eb31cf6b37faae56da00f753" + "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/553f50487389a977eb31cf6b37faae56da00f753", - "reference": "553f50487389a977eb31cf6b37faae56da00f753", + "url": "https://api.github.com/repos/symfony/process/zipball/6e75fe6874cbc7e4773d049616ab450eff537bf1", + "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1", "shasum": "" }, "require": { @@ -4652,7 +4920,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.3" + "source": "https://github.com/symfony/process/tree/v5.4.11" }, "funding": [ { @@ -4668,20 +4936,20 @@ "type": "tidelift" } ], - "time": "2022-01-26T16:28:35+00:00" + "time": "2022-06-27T16:58:25+00:00" }, { "name": "symfony/routing", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "44b29c7a94e867ccde1da604792f11a469958981" + "reference": "3e01ccd9b2a3a4167ba2b3c53612762300300226" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/44b29c7a94e867ccde1da604792f11a469958981", - "reference": "44b29c7a94e867ccde1da604792f11a469958981", + "url": "https://api.github.com/repos/symfony/routing/zipball/3e01ccd9b2a3a4167ba2b3c53612762300300226", + "reference": "3e01ccd9b2a3a4167ba2b3c53612762300300226", "shasum": "" }, "require": { @@ -4742,7 +5010,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.4.3" + "source": "https://github.com/symfony/routing/tree/v5.4.11" }, "funding": [ { @@ -4758,26 +5026,26 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.5.0", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc" + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", - "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", "shasum": "" }, "require": { "php": ">=7.2.5", "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1" + "symfony/deprecation-contracts": "^2.1|^3" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -4825,7 +5093,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.0" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" }, "funding": [ { @@ -4841,20 +5109,20 @@ "type": "tidelift" } ], - "time": "2021-11-04T16:48:04+00:00" + "time": "2022-05-30T19:17:29+00:00" }, { "name": "symfony/string", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10" + "reference": "5eb661e49ad389e4ae2b6e4df8d783a8a6548322" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/92043b7d8383e48104e411bc9434b260dbeb5a10", - "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10", + "url": "https://api.github.com/repos/symfony/string/zipball/5eb661e49ad389e4ae2b6e4df8d783a8a6548322", + "reference": "5eb661e49ad389e4ae2b6e4df8d783a8a6548322", "shasum": "" }, "require": { @@ -4876,12 +5144,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "Symfony\\Component\\String\\": "" - }, "files": [ "Resources/functions.php" ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, "exclude-from-classmap": [ "/Tests/" ] @@ -4911,7 +5179,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.3" + "source": "https://github.com/symfony/string/tree/v5.4.11" }, "funding": [ { @@ -4927,20 +5195,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-07-24T16:15:25+00:00" }, { "name": "symfony/translation", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "a9dd7403232c61e87e27fb306bbcd1627f245d70" + "reference": "7a1a8f6bbff269f434a83343a0a5d36a4f8cfa21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/a9dd7403232c61e87e27fb306bbcd1627f245d70", - "reference": "a9dd7403232c61e87e27fb306bbcd1627f245d70", + "url": "https://api.github.com/repos/symfony/translation/zipball/7a1a8f6bbff269f434a83343a0a5d36a4f8cfa21", + "reference": "7a1a8f6bbff269f434a83343a0a5d36a4f8cfa21", "shasum": "" }, "require": { @@ -5008,7 +5276,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v5.4.3" + "source": "https://github.com/symfony/translation/tree/v5.4.11" }, "funding": [ { @@ -5024,20 +5292,20 @@ "type": "tidelift" } ], - "time": "2022-01-07T00:28:17+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { "name": "symfony/translation-contracts", - "version": "v2.5.0", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "d28150f0f44ce854e942b671fc2620a98aae1b1e" + "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/d28150f0f44ce854e942b671fc2620a98aae1b1e", - "reference": "d28150f0f44ce854e942b671fc2620a98aae1b1e", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/136b19dd05cdf0709db6537d058bcab6dd6e2dbe", + "reference": "136b19dd05cdf0709db6537d058bcab6dd6e2dbe", "shasum": "" }, "require": { @@ -5058,8 +5326,101 @@ }, "autoload": { "psr-4": { - "Symfony\\Contracts\\Translation\\": "" - } + "Symfony\\Contracts\\Translation\\": "" + } + }, + "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": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v2.5.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": "2022-06-27T16:58:25+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v5.4.11", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "b8f306d7b8ef34fb3db3305be97ba8e088fb4861" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8f306d7b8ef34fb3db3305be97ba8e088fb4861", + "reference": "b8f306d7b8ef34fb3db3305be97ba8e088fb4861", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "phpunit/phpunit": "<5.4.3", + "symfony/console": "<4.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/uid": "^5.1|^6.0", + "twig/twig": "^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5075,18 +5436,14 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to translation", + "description": "Provides mechanisms for walking through any arbitrary PHP variable", "homepage": "https://symfony.com", "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + "debug", + "dump" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v2.5.0" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.11" }, "funding": [ { @@ -5102,53 +5459,43 @@ "type": "tidelift" } ], - "time": "2021-08-17T14:20:01+00:00" + "time": "2022-07-20T13:00:38+00:00" }, { - "name": "symfony/var-dumper", - "version": "v5.4.3", + "name": "symfony/yaml", + "version": "v5.4.11", "source": { "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "970a01f208bf895c5f327ba40b72288da43adec4" + "url": "https://github.com/symfony/yaml.git", + "reference": "05d4ea560f3402c6c116afd99fdc66e60eda227e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/970a01f208bf895c5f327ba40b72288da43adec4", - "reference": "970a01f208bf895c5f327ba40b72288da43adec4", + "url": "https://api.github.com/repos/symfony/yaml/zipball/05d4ea560f3402c6c116afd99fdc66e60eda227e", + "reference": "05d4ea560f3402c6c116afd99fdc66e60eda227e", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.16" + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "phpunit/phpunit": "<5.4.3", - "symfony/console": "<4.4" + "symfony/console": "<5.3" }, "require-dev": { - "ext-iconv": "*", - "symfony/console": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/uid": "^5.1|^6.0", - "twig/twig": "^2.13|^3.0.4" + "symfony/console": "^5.3|^6.0" }, "suggest": { - "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", - "ext-intl": "To show region name in time zone dump", - "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + "symfony/console": "For validating YAML files using the lint command" }, "bin": [ - "Resources/bin/var-dump-server" + "Resources/bin/yaml-lint" ], "type": "library", "autoload": { - "files": [ - "Resources/functions/dump.php" - ], "psr-4": { - "Symfony\\Component\\VarDumper\\": "" + "Symfony\\Component\\Yaml\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5160,22 +5507,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", - "keywords": [ - "debug", - "dump" - ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.3" + "source": "https://github.com/symfony/yaml/tree/v5.4.11" }, "funding": [ { @@ -5191,7 +5534,7 @@ "type": "tidelift" } ], - "time": "2022-01-17T16:30:37+00:00" + "time": "2022-06-27T16:58:25+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -5402,21 +5745,21 @@ }, { "name": "webmozart/assert", - "version": "1.10.0", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" + "ext-ctype": "*", + "php": "^7.2 || ^8.0" }, "conflict": { "phpstan/phpstan": "<0.12.20", @@ -5454,37 +5797,111 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + }, + { + "name": "zircote/swagger-php", + "version": "3.3.6", + "source": { + "type": "git", + "url": "https://github.com/zircote/swagger-php.git", + "reference": "5016342f966fca29dda84455de066c5c90d37941" }, - "time": "2021-03-09T10:59:23+00:00" + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/5016342f966fca29dda84455de066c5c90d37941", + "reference": "5016342f966fca29dda84455de066c5c90d37941", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^1.7", + "ext-json": "*", + "php": ">=7.2", + "psr/log": "^1.1 || ^2.0 || ^3.0", + "symfony/finder": ">=2.2", + "symfony/yaml": ">=3.3" + }, + "require-dev": { + "composer/package-versions-deprecated": "1.11.99.2", + "friendsofphp/php-cs-fixer": "^2.17 || ^3.0", + "phpunit/phpunit": ">=8.5.14" + }, + "bin": [ + "bin/openapi" + ], + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "OpenApi\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Robert Allen", + "email": "zircote@gmail.com" + }, + { + "name": "Bob Fanger", + "email": "bfanger@gmail.com", + "homepage": "https://bfanger.nl" + }, + { + "name": "Martin Rademacher", + "email": "mano@radebatz.net", + "homepage": "https://radebatz.net" + } + ], + "description": "swagger-php - Generate interactive documentation for your RESTful API using phpdoc annotations", + "homepage": "https://github.com/zircote/swagger-php/", + "keywords": [ + "api", + "json", + "rest", + "service discovery" + ], + "support": { + "issues": "https://github.com/zircote/swagger-php/issues", + "source": "https://github.com/zircote/swagger-php/tree/3.3.6" + }, + "time": "2022-05-21T01:52:14+00:00" } ], "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", + "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^8.0", + "doctrine/coding-standard": "^9", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.22" }, "type": "library", "autoload": { @@ -5511,7 +5928,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + "source": "https://github.com/doctrine/instantiator/tree/1.4.1" }, "funding": [ { @@ -5527,20 +5944,20 @@ "type": "tidelift" } ], - "time": "2020-11-10T18:47:58+00:00" + "time": "2022-03-03T08:28:38+00:00" }, { "name": "facade/flare-client-php", - "version": "1.9.1", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/facade/flare-client-php.git", - "reference": "b2adf1512755637d0cef4f7d1b54301325ac78ed" + "reference": "213fa2c69e120bca4c51ba3e82ed1834ef3f41b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/flare-client-php/zipball/b2adf1512755637d0cef4f7d1b54301325ac78ed", - "reference": "b2adf1512755637d0cef4f7d1b54301325ac78ed", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/213fa2c69e120bca4c51ba3e82ed1834ef3f41b8", + "reference": "213fa2c69e120bca4c51ba3e82ed1834ef3f41b8", "shasum": "" }, "require": { @@ -5553,7 +5970,7 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14", - "phpunit/phpunit": "^7.5.16", + "phpunit/phpunit": "^7.5", "spatie/phpunit-snapshot-assertions": "^2.0" }, "type": "library", @@ -5584,7 +6001,7 @@ ], "support": { "issues": "https://github.com/facade/flare-client-php/issues", - "source": "https://github.com/facade/flare-client-php/tree/1.9.1" + "source": "https://github.com/facade/flare-client-php/tree/1.10.0" }, "funding": [ { @@ -5592,20 +6009,20 @@ "type": "github" } ], - "time": "2021-09-13T12:16:46+00:00" + "time": "2022-08-09T11:23:57+00:00" }, { "name": "facade/ignition", - "version": "2.17.4", + "version": "2.17.6", "source": { "type": "git", "url": "https://github.com/facade/ignition.git", - "reference": "95c80bd35ee6858e9e1439b2f6a698295eeb2070" + "reference": "6acd82e986a2ecee89e2e68adfc30a1936d1ab7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/95c80bd35ee6858e9e1439b2f6a698295eeb2070", - "reference": "95c80bd35ee6858e9e1439b2f6a698295eeb2070", + "url": "https://api.github.com/repos/facade/ignition/zipball/6acd82e986a2ecee89e2e68adfc30a1936d1ab7c", + "reference": "6acd82e986a2ecee89e2e68adfc30a1936d1ab7c", "shasum": "" }, "require": { @@ -5670,7 +6087,7 @@ "issues": "https://github.com/facade/ignition/issues", "source": "https://github.com/facade/ignition" }, - "time": "2021-12-27T15:11:24+00:00" + "time": "2022-06-30T18:26:59+00:00" }, { "name": "facade/ignition-contracts", @@ -5727,16 +6144,16 @@ }, { "name": "fakerphp/faker", - "version": "v1.19.0", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "d7f08a622b3346766325488aa32ddc93ccdecc75" + "reference": "37f751c67a5372d4e26353bd9384bc03744ec77b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/d7f08a622b3346766325488aa32ddc93ccdecc75", - "reference": "d7f08a622b3346766325488aa32ddc93ccdecc75", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/37f751c67a5372d4e26353bd9384bc03744ec77b", + "reference": "37f751c67a5372d4e26353bd9384bc03744ec77b", "shasum": "" }, "require": { @@ -5763,7 +6180,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "v1.19-dev" + "dev-main": "v1.20-dev" } }, "autoload": { @@ -5788,9 +6205,9 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.19.0" + "source": "https://github.com/FakerPHP/Faker/tree/v1.20.0" }, - "time": "2022-02-02T17:38:57+00:00" + "time": "2022-07-20T13:12:54+00:00" }, { "name": "filp/whoops", @@ -5916,16 +6333,16 @@ }, { "name": "laravel/sail", - "version": "v1.13.4", + "version": "v1.15.4", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "57d2942d5edd89b2018d0a3447da321fa35baac7" + "reference": "853dea1fa866a52a93beccc4e5affdc49b98e7d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/57d2942d5edd89b2018d0a3447da321fa35baac7", - "reference": "57d2942d5edd89b2018d0a3447da321fa35baac7", + "url": "https://api.github.com/repos/laravel/sail/zipball/853dea1fa866a52a93beccc4e5affdc49b98e7d5", + "reference": "853dea1fa866a52a93beccc4e5affdc49b98e7d5", "shasum": "" }, "require": { @@ -5972,7 +6389,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2022-02-17T19:55:30+00:00" + "time": "2022-08-17T13:17:15+00:00" }, { "name": "mockery/mockery", @@ -6048,28 +6465,29 @@ }, { "name": "myclabs/deep-copy", - "version": "1.10.2", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, - "replace": { - "myclabs/deep-copy": "self.version" + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" }, "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", "autoload": { @@ -6094,7 +6512,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" }, "funding": [ { @@ -6102,7 +6520,7 @@ "type": "tidelift" } ], - "time": "2020-11-13T09:40:50+00:00" + "time": "2022-03-03T13:19:32+00:00" }, { "name": "nunomaduro/collision", @@ -6302,252 +6720,25 @@ }, "time": "2022-02-21T01:04:05+00:00" }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", - "shasum": "" - }, - "require": { - "ext-filter": "*", - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" - }, - "time": "2021-10-19T17:43:47+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", - "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "*", - "psalm/phar": "^4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0" - }, - "time": "2022-01-04T19:58:01+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "v1.15.0", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", - "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.2", - "phpdocumentor/reflection-docblock": "^5.2", - "sebastian/comparator": "^3.0 || ^4.0", - "sebastian/recursion-context": "^3.0 || ^4.0" - }, - "require-dev": { - "phpspec/phpspec": "^6.0 || ^7.0", - "phpunit/phpunit": "^8.0 || ^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "support": { - "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" - }, - "time": "2021-12-08T12:19:24+00:00" - }, { "name": "phpunit/php-code-coverage", - "version": "9.2.11", + "version": "9.2.16", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "665a1ac0a763c51afc30d6d130dac0813092b17f" + "reference": "2593003befdcc10db5e213f9f28814f5aa8ac073" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/665a1ac0a763c51afc30d6d130dac0813092b17f", - "reference": "665a1ac0a763c51afc30d6d130dac0813092b17f", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2593003befdcc10db5e213f9f28814f5aa8ac073", + "reference": "2593003befdcc10db5e213f9f28814f5aa8ac073", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.13.0", + "nikic/php-parser": "^4.14", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -6596,7 +6787,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.11" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.16" }, "funding": [ { @@ -6604,7 +6795,7 @@ "type": "github" } ], - "time": "2022-02-18T12:46:09+00:00" + "time": "2022-08-20T05:26:47+00:00" }, { "name": "phpunit/php-file-iterator", @@ -6849,16 +7040,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.14", + "version": "9.5.23", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "1883687169c017d6ae37c58883ca3994cfc34189" + "reference": "888556852e7e9bbeeedb9656afe46118765ade34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1883687169c017d6ae37c58883ca3994cfc34189", - "reference": "1883687169c017d6ae37c58883ca3994cfc34189", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/888556852e7e9bbeeedb9656afe46118765ade34", + "reference": "888556852e7e9bbeeedb9656afe46118765ade34", "shasum": "" }, "require": { @@ -6873,8 +7064,7 @@ "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", - "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.7", + "phpunit/php-code-coverage": "^9.2.13", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -6888,13 +7078,9 @@ "sebastian/global-state": "^5.0.1", "sebastian/object-enumerator": "^4.0.3", "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3.4", + "sebastian/type": "^3.0", "sebastian/version": "^3.0.2" }, - "require-dev": { - "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0.1" - }, "suggest": { "ext-soap": "*", "ext-xdebug": "*" @@ -6936,7 +7122,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.14" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.23" }, "funding": [ { @@ -6948,7 +7134,7 @@ "type": "github" } ], - "time": "2022-02-18T12:54:07+00:00" + "time": "2022-08-22T14:01:36+00:00" }, { "name": "sebastian/cli-parser", @@ -7316,16 +7502,16 @@ }, { "name": "sebastian/environment", - "version": "5.1.3", + "version": "5.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac" + "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7", + "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7", "shasum": "" }, "require": { @@ -7367,7 +7553,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.4" }, "funding": [ { @@ -7375,7 +7561,7 @@ "type": "github" } ], - "time": "2020-09-28T05:52:38+00:00" + "time": "2022-04-03T09:37:03+00:00" }, { "name": "sebastian/exporter", @@ -7807,28 +7993,28 @@ }, { "name": "sebastian/type", - "version": "2.3.4", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914" + "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914", - "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b233b84bc4465aff7b57cf1c4bc75c86d00d6dad", + "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad", "shasum": "" }, "require": { "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -7851,7 +8037,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.4" + "source": "https://github.com/sebastianbergmann/type/tree/3.0.0" }, "funding": [ { @@ -7859,7 +8045,7 @@ "type": "github" } ], - "time": "2021-06-15T12:49:02+00:00" + "time": "2022-03-15T09:54:48+00:00" }, { "name": "sebastian/version", @@ -7974,5 +8160,5 @@ "php": "^7.3|^8.0" }, "platform-dev": [], - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.3.0" } diff --git a/config/l5-swagger.php b/config/l5-swagger.php new file mode 100644 index 0000000..81b3dff --- /dev/null +++ b/config/l5-swagger.php @@ -0,0 +1,294 @@ + 'default', + 'documentations' => [ + 'default' => [ + 'api' => [ + 'title' => 'Open API UI', + ], + + 'routes' => [ + /* + * Route for accessing api documentation interface + */ + 'api' => 'api/documentation', + ], + 'paths' => [ + /* + * Edit to include full URL in ui for assets + */ + 'use_absolute_path' => env('L5_SWAGGER_USE_ABSOLUTE_PATH', true), + + /* + * File name of the generated json documentation file + */ + 'docs_json' => 'api-docs.json', + + /* + * File name of the generated YAML documentation file + */ + 'docs_yaml' => 'api-docs.yaml', + + /* + * Set this to `json` or `yaml` to determine which documentation file to use in UI + */ + 'format_to_use_for_docs' => env('L5_FORMAT_TO_USE_FOR_DOCS', 'json'), + + /* + * Absolute paths to directory containing the swagger annotations are stored. + */ + 'annotations' => [ + base_path('app'), + ], + + ], + ], + ], + 'defaults' => [ + 'routes' => [ + /* + * Route for accessing parsed swagger annotations. + */ + 'docs' => 'docs', + + /* + * Route for Oauth2 authentication callback. + */ + 'oauth2_callback' => 'api/oauth2-callback', + + /* + * Middleware allows to prevent unexpected access to API documentation + */ + 'middleware' => [ + 'api' => [], + 'asset' => [], + 'docs' => [], + 'oauth2_callback' => [], + ], + + /* + * Route Group options + */ + 'group_options' => [], + ], + + 'paths' => [ + /* + * Absolute path to location where parsed annotations will be stored + */ + 'docs' => storage_path('api-docs'), + + /* + * Absolute path to directory where to export views + */ + 'views' => base_path('resources/views/vendor/l5-swagger'), + + /* + * Edit to set the api's base path + */ + 'base' => env('L5_SWAGGER_BASE_PATH', null), + + /* + * Edit to set path where swagger ui assets should be stored + */ + 'swagger_ui_assets_path' => env('L5_SWAGGER_UI_ASSETS_PATH', 'vendor/swagger-api/swagger-ui/dist/'), + + /* + * Absolute path to directories that should be exclude from scanning + * @deprecated Please use `scanOptions.exclude` + * `scanOptions.exclude` overwrites this + */ + 'excludes' => [], + ], + + 'scanOptions' => [ + /** + * analyser: defaults to \OpenApi\StaticAnalyser . + * + * @see \OpenApi\scan + */ + 'analyser' => null, + + /** + * analysis: defaults to a new \OpenApi\Analysis . + * + * @see \OpenApi\scan + */ + 'analysis' => null, + + /** + * Custom query path processors classes. + * + * @link https://github.com/zircote/swagger-php/tree/master/Examples/schema-query-parameter-processor + * @see \OpenApi\scan + */ + 'processors' => [ + // new \App\SwaggerProcessors\SchemaQueryParameter(), + ], + + /** + * pattern: string $pattern File pattern(s) to scan (default: *.php) . + * + * @see \OpenApi\scan + */ + 'pattern' => null, + + /* + * Absolute path to directories that should be exclude from scanning + * @note This option overwrites `paths.excludes` + * @see \OpenApi\scan + */ + 'exclude' => [], + ], + + /* + * API security definitions. Will be generated into documentation file. + */ + 'securityDefinitions' => [ + 'securitySchemes' => [ + /* + * Examples of Security schemes + */ + /* + 'api_key_security_example' => [ // Unique name of security + 'type' => 'apiKey', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'A short description for security scheme', + 'name' => 'api_key', // The name of the header or query parameter to be used. + 'in' => 'header', // The location of the API key. Valid values are "query" or "header". + ], + 'oauth2_security_example' => [ // Unique name of security + 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'A short description for oauth2 security scheme.', + 'flow' => 'implicit', // The flow used by the OAuth2 security scheme. Valid values are "implicit", "password", "application" or "accessCode". + 'authorizationUrl' => 'http://example.com/auth', // The authorization URL to be used for (implicit/accessCode) + //'tokenUrl' => 'http://example.com/auth' // The authorization URL to be used for (password/application/accessCode) + 'scopes' => [ + 'read:projects' => 'read your projects', + 'write:projects' => 'modify projects in your account', + ] + ], + */ + + /* Open API 3.0 support + 'passport' => [ // Unique name of security + 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'Laravel passport oauth2 security.', + 'in' => 'header', + 'scheme' => 'https', + 'flows' => [ + "password" => [ + "authorizationUrl" => config('app.url') . '/oauth/authorize', + "tokenUrl" => config('app.url') . '/oauth/token', + "refreshUrl" => config('app.url') . '/token/refresh', + "scopes" => [] + ], + ], + ], + 'sanctum' => [ // Unique name of security + 'type' => 'apiKey', // Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'Enter token in format (Bearer )', + 'name' => 'Authorization', // The name of the header or query parameter to be used. + 'in' => 'header', // The location of the API key. Valid values are "query" or "header". + ], + */ + ], + 'security' => [ + /* + * Examples of Securities + */ + [ + /* + 'oauth2_security_example' => [ + 'read', + 'write' + ], + + 'passport' => [] + */ + ], + ], + ], + + /* + * Set this to `true` in development mode so that docs would be regenerated on each request + * Set this to `false` to disable swagger generation on production + */ + 'generate_always' => env('L5_SWAGGER_GENERATE_ALWAYS', true), + + /* + * Set this to `true` to generate a copy of documentation in yaml format + */ + 'generate_yaml_copy' => env('L5_SWAGGER_GENERATE_YAML_COPY', false), + + /* + * Edit to trust the proxy's ip address - needed for AWS Load Balancer + * string[] + */ + 'proxy' => false, + + /* + * Configs plugin allows to fetch external configs instead of passing them to SwaggerUIBundle. + * See more at: https://github.com/swagger-api/swagger-ui#configs-plugin + */ + 'additional_config_url' => null, + + /* + * Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), + * 'method' (sort by HTTP method). + * Default is the order returned by the server unchanged. + */ + 'operations_sort' => env('L5_SWAGGER_OPERATIONS_SORT', null), + + /* + * Pass the validatorUrl parameter to SwaggerUi init on the JS side. + * A null value here disables validation. + */ + 'validator_url' => null, + + /* + * Swagger UI configuration parameters + */ + 'ui' => [ + 'display' => [ + /* + * Controls the default expansion setting for the operations and tags. It can be : + * 'list' (expands only the tags), + * 'full' (expands the tags and operations), + * 'none' (expands nothing). + */ + 'doc_expansion' => env('L5_SWAGGER_UI_DOC_EXPANSION', 'none'), + + /** + * If set, enables filtering. The top bar will show an edit box that + * you can use to filter the tagged operations that are shown. Can be + * Boolean to enable or disable, or a string, in which case filtering + * will be enabled using that string as the filter expression. Filtering + * is case-sensitive matching the filter expression anywhere inside + * the tag. + */ + 'filter' => env('L5_SWAGGER_UI_FILTERS', true), // true | false + ], + + 'authorization' => [ + /* + * If set to true, it persists authorization data, and it would not be lost on browser close/refresh + */ + 'persist_authorization' => env('L5_SWAGGER_UI_PERSIST_AUTHORIZATION', false), + + 'oauth2' => [ + /* + * If set to true, adds PKCE to AuthorizationCodeGrant flow + */ + 'use_pkce_with_authorization_code_grant' => false, + ], + ], + ], + /* + * Constants which can be used in annotations + */ + 'constants' => [ + 'L5_SWAGGER_CONST_HOST' => env('L5_SWAGGER_CONST_HOST', 'http://my-default-host.com'), + ], + ], +]; diff --git a/database/seeders/User.php b/database/seeders/User.php new file mode 100644 index 0000000..bb43678 --- /dev/null +++ b/database/seeders/User.php @@ -0,0 +1,18 @@ + + + + + {{config('l5-swagger.documentations.'.$documentation.'.api.title')}} + + + + + + + +
+ + + + + + diff --git a/routes/api.php b/routes/api.php index eb6fa48..eec74d8 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,6 +2,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; +use App\Http\Controllers\UserController; /* |-------------------------------------------------------------------------- @@ -17,3 +18,7 @@ Route::middleware('auth:sanctum')->get('/user', function (Request $request) { return $request->user(); }); + +Route::prefix('v1')->group(function () { + Route::apiResource('users', UserController::class)->parameters(['users'=>'user_id']); +}); \ No newline at end of file diff --git a/storage/api-docs/api-docs.json b/storage/api-docs/api-docs.json new file mode 100644 index 0000000..2298187 --- /dev/null +++ b/storage/api-docs/api-docs.json @@ -0,0 +1,144 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Project API API", + "contact": { + "name": "Hiren Shah", + "email": "hiren@atyantik.com" + }, + "license": { + "name": "Properietary", + "url": "https://atyantik.com" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://localhost:8000/api/v1/" + } + ], + "paths": { + "/projects": { + "get": { + "responses": { + "200": { + "description": "Display a listing of projects." + } + } + } + } + }, + "components": { + "schemas": { + "Error": { + "properties": { + "errorMessage": { + "type": "string" + } + }, + "type": "object" + }, + "Success": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + }, + "Pagination": { + "properties": { + "pagination": { + "properties": { + "total": { + "description": "Total", + "type": "integer" + }, + "count": { + "description": "Count", + "type": "integer" + }, + "pageSize": { + "description": "Per Page", + "type": "integer" + }, + "pageIndex": { + "description": "Current Page", + "type": "integer" + }, + "totalPages": { + "description": "Total Page", + "type": "integer" + }, + "links": { + "properties": { + "first": { + "description": "First Page", + "type": "string" + }, + "last": { + "description": "Last Page", + "type": "string" + }, + "current": { + "description": "Current Page", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "parameters": { + "Authorization": { + "name": "Authorization", + "in": "header", + "description": "JWT Token", + "required": true, + "schema": { + "type": "string" + } + }, + "sortBy": { + "name": "sortBy", + "in": "query", + "description": "Sort Order", + "schema": { + "type": "string" + } + }, + "sortDirection": { + "name": "sortDirection", + "in": "query", + "description": "Sort Direction", + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ] + } + }, + "includes": { + "name": "includes", + "in": "query", + "description": "Includes for getting object dependened data", + "schema": { + "type": "array", + "items": { + "type": "string", + "collectionFormat": "csv" + } + } + } + } + }, + "security": [ + [] + ] +} \ No newline at end of file From 8df0e86ddb9adb04e245c8ac83cb27b4f19e429c Mon Sep 17 00:00:00 2001 From: hiren Date: Thu, 25 Aug 2022 17:18:02 +0530 Subject: [PATCH 03/13] Create REST APIs --- app/Http/Controllers/ProjectController.php | 83 +++++++++++++++++ app/Http/Controllers/TaskController.php | 91 +++++++++++++++++++ app/Http/Controllers/UserController.php | 3 +- app/Http/Requests/ProjectRequest.php | 50 ++++++++++ app/Http/Requests/TaskRequest.php | 64 +++++++++++++ app/Http/Requests/UserRequest.php | 5 + app/Managers/UserManager.php | 7 +- app/Models/Role.php | 16 ++++ app/Models/User.php | 2 + app/Providers/AppServiceProvider.php | 4 +- app/Resources/ProjectResource.php | 30 ++++++ app/Resources/TaskResource.php | 34 +++++++ app/Resources/UserResource.php | 3 + .../2014_10_12_000000_create_users_table.php | 3 +- database/seeders/User.php | 18 +++- routes/api.php | 5 +- 16 files changed, 408 insertions(+), 10 deletions(-) create mode 100644 app/Http/Controllers/ProjectController.php create mode 100644 app/Http/Controllers/TaskController.php create mode 100644 app/Http/Requests/ProjectRequest.php create mode 100644 app/Http/Requests/TaskRequest.php create mode 100644 app/Resources/ProjectResource.php create mode 100644 app/Resources/TaskResource.php diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php new file mode 100644 index 0000000..9a22b0d --- /dev/null +++ b/app/Http/Controllers/ProjectController.php @@ -0,0 +1,83 @@ +input(); + + $project = Project::create([ + 'name' => $input['name'], + ]); + + return new ProjectResource($project); + } + + /** + * Display the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function show($id) + { + return new ProjectResource(Project::findOrFail($id)); + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(ProjectRequest $request, Project $project) + { + $input = $request->input(); + + $project->fill([ + 'name' => $input['name'], + ]); + + return new ProjectResource($project); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy(Project $project) + { + $project->delete(); + + return response()->json([ + 'message' => 'Project deleted successfully' + ], 200); + } +} diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php new file mode 100644 index 0000000..50cbc82 --- /dev/null +++ b/app/Http/Controllers/TaskController.php @@ -0,0 +1,91 @@ +input(); + + $task = Task::create([ + 'title' => $input['title'], + 'description' => $input['description'], + 'status' => $input['status'], + 'project_id' => $input['project_id'], + 'user_id' => $input['user_id'], + ]); + + return new TaskResource($task); + } + + /** + * Display the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function show($id) + { + return new TaskResource(Task::findOrFail($id)); + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(TaskRequest $request, Task $task) + { + $input = $request->input(); + + $task->fill([ + 'title' => $input['title'], + 'description' => $input['description'], + 'status' => $input['status'], + 'project_id' => $input['project_id'], + 'user_id' => $input['user_id'], + ]); + + return new TaskResource($task); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy(Task $task) + { + $task->delete(); + + return response()->json([ + 'message' => 'Task deleted successfully' + ], 200); + } +} diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 811232f..bc07794 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -28,9 +28,8 @@ public function index() */ public function store(UserRequest $request) { - $validated = $request->validated(); - $user = $this->app('user_manager')->store($validated); + $user = app('user_manager')->store($request->inpput()); return new UserResource($user); } diff --git a/app/Http/Requests/ProjectRequest.php b/app/Http/Requests/ProjectRequest.php new file mode 100644 index 0000000..69dae56 --- /dev/null +++ b/app/Http/Requests/ProjectRequest.php @@ -0,0 +1,50 @@ + __("Name")]); + $messages['name.string'] = __("The :name field must be a string", ["name" => __("Name")]); + $messages['nmae.unique'] = __("The :name has already been taken", ["name" => __("Name")]); + + return $messages; + + } +} \ No newline at end of file diff --git a/app/Http/Requests/TaskRequest.php b/app/Http/Requests/TaskRequest.php new file mode 100644 index 0000000..600386a --- /dev/null +++ b/app/Http/Requests/TaskRequest.php @@ -0,0 +1,64 @@ + __("Title")]); + $messages['title.string'] = __("The :name field must be a string", ["name" => __("Title")]); + + $messages['description.string'] = __("The :name field must be a string", ["name" => __("Description")]); + + $messages['status.required'] = __("The :name field is required", ["name" => __("Status")]); + $messages['status.string'] = __("The :name field must be a string", ["name" => __("Status")]); + + $messages['project_id.required'] = __("The :name field is required", ["name" => __("Project ID")]); + $messages['project_id.exists'] = __("The :name not exist", ["name" => __("Project ID")]); + + $messages['user_id.required'] = __("The :name field is required", ["name" => __("user ID")]); + $messages['user_id.exists'] = __("The :name not exist", ["name" => __("User ID")]); + + return $messages; + + } +} \ No newline at end of file diff --git a/app/Http/Requests/UserRequest.php b/app/Http/Requests/UserRequest.php index edf7737..e548dfa 100644 --- a/app/Http/Requests/UserRequest.php +++ b/app/Http/Requests/UserRequest.php @@ -25,6 +25,8 @@ public function rules() { $rules = []; + $rules['name'] = ['required']; + $rules['email'] = ['required' , 'unique:users,email']; $rules['username'] = ['required' , 'min:3' , 'max:255' , 'unique:users,username']; $rules['password'] = ['required' , 'confirmed', 'min:6']; $rules['role_id'] = ['required', 'exists:roles,id']; @@ -42,6 +44,9 @@ public function messages() $messages = []; + $messages['email.required'] = __("The :name field is required", ["name" => __("Email")]); + $messages['email.unique'] = __("The :name has already been taken", ["name" => __("Email")]); + $messages['username.required'] = __("The :name field is required", ["name" => __("Username")]); $messages['username.min:3'] = __("The :name field must contain at least 3 character", ["name" => __("Username")]); $messages['username.max:255'] = __("The :name field cannot exceed 255 character", ["name" => __("Username")]); diff --git a/app/Managers/UserManager.php b/app/Managers/UserManager.php index 7b166be..e1ff7f8 100644 --- a/app/Managers/UserManager.php +++ b/app/Managers/UserManager.php @@ -3,7 +3,7 @@ namespace App\Managers; use App\Models\User; -use Ramsey\Uuid\Uuid; +use Illuminate\Support\Facades\Hash; /** * Class FullTimeStep1Service. @@ -12,9 +12,11 @@ class UserManager { public function store(array $input, User $user = null) : User { + if (!$user) { $user = User::create([ 'email' => $input['email'], + 'username' => $input['username'], 'name' => $input['name'], 'role_id' => $input['role_id'], ]); @@ -22,12 +24,13 @@ public function store(array $input, User $user = null) : User { $user->fill([ 'email' => $input['email'], 'name' => $input['name'], + 'username' => $input['username'], 'role_id' => $input['role_id'], ]); } if (isset($input['password'])) { - $user->password = bcrypt($input['password']); + $user->password = Hash::make($input['password']); } $user->save(); return $user; diff --git a/app/Models/Role.php b/app/Models/Role.php index 45d6772..b3a93ae 100644 --- a/app/Models/Role.php +++ b/app/Models/Role.php @@ -16,4 +16,20 @@ class Role extends Model "PRODUCT_OWNER" => "Product Owner", "TEAM_MEMBER" => "Team Member" ]; + const ADMIN ='ADMIN'; + const PRODUCT_OWNER ='PRODUCT_OWNER'; + const TEAM_MEMBER ='TEAM_MEMBER'; + + public static function scopeIsAdmin($query) + { + return $query->where('slug',static::ADMIN); + } + public static function scopeIsProductOwner($query) + { + return $query->where('slug',static::PRODUCT_OWNER); + } + public static function scopeIsTeamMember($query) + { + return $query->where('slug',static::TEAM_MEMBER); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 5c093f3..2c08c9c 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -22,6 +22,8 @@ class User extends Authenticatable protected $fillable = [ 'id', 'username', + 'email', + 'name', 'role_id' ]; diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 9b4766c..ac5111e 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -14,8 +14,8 @@ class AppServiceProvider extends ServiceProvider */ public function register() { - $this->app->singleton('user_manager',function() { - return UserManager(); + $this->app->singleton('user_manager', function($app) { + return new UserManager(); }); } diff --git a/app/Resources/ProjectResource.php b/app/Resources/ProjectResource.php new file mode 100644 index 0000000..427622e --- /dev/null +++ b/app/Resources/ProjectResource.php @@ -0,0 +1,30 @@ + $this->id, + 'name' => $this->name, + ]; + + } +} \ No newline at end of file diff --git a/app/Resources/TaskResource.php b/app/Resources/TaskResource.php new file mode 100644 index 0000000..c5e3631 --- /dev/null +++ b/app/Resources/TaskResource.php @@ -0,0 +1,34 @@ + $this->id, + 'title' => $this->title, + 'description' => $this->description, + 'status' => $this->status, + 'project_id' => $this->project_id, + 'user_id' => $this->user_id, + ]; + + } +} \ No newline at end of file diff --git a/app/Resources/UserResource.php b/app/Resources/UserResource.php index a41556e..221f194 100644 --- a/app/Resources/UserResource.php +++ b/app/Resources/UserResource.php @@ -23,8 +23,11 @@ public function toArray($request) { return [ 'id' => $this->id, + 'email' => $this->email, 'username' => $this->username, + 'name' => $this->name, 'role_id' => $this->role_id, + 'role'=>$this->role->name, ]; } diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php index 578e6ce..e944684 100644 --- a/database/migrations/2014_10_12_000000_create_users_table.php +++ b/database/migrations/2014_10_12_000000_create_users_table.php @@ -17,8 +17,9 @@ public function up() $table->uuid('id')->primary(); $table->string('name'); $table->string('email')->unique(); + $table->string('username')->unique(); $table->timestamp('email_verified_at')->nullable(); - $table->string('password'); + $table->string('password')->default(''); $table->integer('role_id')->nullable(); $table->rememberToken(); $table->timestamps(); diff --git a/database/seeders/User.php b/database/seeders/User.php index bb43678..b95d619 100644 --- a/database/seeders/User.php +++ b/database/seeders/User.php @@ -3,6 +3,10 @@ namespace Database\Seeders; use Illuminate\Database\Seeder; +use App\Models\Role; +use Database\Seeders\RoleSeeder; +use App\Models\User as BaseUser; +use Illuminate\Support\Facades\Hash; class User extends Seeder { @@ -13,6 +17,18 @@ class User extends Seeder */ public function run() { - // + + $users = [ + 'admin'=>['name'=>'Admin','username'=>'admin','email'=>'admin@atyantik.com','role_id'=>Role::isAdmin()->first()->id], + 'team'=>['name'=>'Team Member','username'=>'team_member','email'=>'team-member@atyantik.com','role_id'=>Role::isTeamMember()->first()->id], + 'product_owner'=>['name'=>'Product Owner','username'=>'product_owner','email'=>'product-owner@atyantik.com','role_id'=>Role::isProductOwner()->first()->id], + ]; + foreach ($users as $key => $user) { + if(!BaseUser::where(['email'=>$user['email']])->first()) { + $user = BaseUser::create($user); + $user->password = Hash::make($key.'@123'); + $user->save(); + } + } } } diff --git a/routes/api.php b/routes/api.php index eec74d8..12e79a5 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,7 +2,6 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; -use App\Http\Controllers\UserController; /* |-------------------------------------------------------------------------- @@ -20,5 +19,7 @@ }); Route::prefix('v1')->group(function () { - Route::apiResource('users', UserController::class)->parameters(['users'=>'user_id']); + Route::apiResource('users', App\Http\Controllers\UserController::class)->parameters(['users'=>'user_id']); + Route::apiResource('projects', App\Http\Controllers\ProjectController::class)->parameters(['projects'=>'project_id']); + Route::apiResource('tasks', App\Http\Controllers\TaskController::class)->parameters(['tasks'=>'task_id']); }); \ No newline at end of file From e0f0434c3009c193f749f7c501fc458252baffba Mon Sep 17 00:00:00 2001 From: hiren Date: Thu, 25 Aug 2022 20:32:46 +0530 Subject: [PATCH 04/13] Implement features --- app/Exceptions/Handler.php | 69 +++++++++++++++--- app/Http/Controllers/ProjectController.php | 8 ++ app/Http/Controllers/TaskController.php | 73 +++++++++++++++---- app/Http/Controllers/UserController.php | 40 ++++++++-- app/Http/Kernel.php | 5 +- app/Http/Middleware/Acl.php | 24 ++++++ app/Http/Requests/TaskRequest.php | 6 ++ app/Http/Requests/UserRequest.php | 7 +- app/Managers/UserManager.php | 18 +++-- app/Models/Task.php | 2 +- config/acl.php | 36 +++++++++ config/auth.php | 5 ++ ...01_create_personal_access_tokens_table.php | 2 +- routes/api.php | 13 ++-- 14 files changed, 263 insertions(+), 45 deletions(-) create mode 100644 app/Http/Middleware/Acl.php create mode 100644 config/acl.php diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 8e7fbd1..efd2940 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -1,16 +1,23 @@ > + * @var array */ protected $dontReport = [ // @@ -19,23 +26,65 @@ class Handler extends ExceptionHandler /** * A list of the inputs that are never flashed for validation exceptions. * - * @var array + * @var array */ protected $dontFlash = [ - 'current_password', 'password', 'password_confirmation', ]; /** - * Register the exception handling callbacks for the application. + * Report or log an exception. * + * @param Exception $exception * @return void */ - public function register() + public function report(Throwable $exception) + { + if (app()->bound('sentry') && $this->shouldReport($exception)) { + app('sentry')->captureException($exception); + } + parent::report($exception); + } + + /** + * Render an exception into an HTTP response. + * + * @param Request $request + * @param Exception $exception + * @return Response + */ + public function render($request, Throwable $exception) + { + if ($exception instanceof UnauthorizedException) { + return response()->json(["message" => $exception->getMessage()], 403); + } elseif ($exception instanceof ModelNotFoundException) { + return response()->json(['message' => 'Respected model not found'], 422); + } elseif ($exception instanceof NotFoundHttpException) { + return response()->json(['message' => $exception->getMessage()], 404); + } elseif ($request->expectsJson() && $exception instanceof HttpException && $exception->getStatusCode()===503) { + return response()->json(['message' => $exception->getMessage()], 503); + } + + return parent::render($request, $exception); + } + + /** + * Convert a validation exception into a JSON response. + * + * @param Request $request + * @param ValidationException $exception + * @return JsonResponse + */ + protected function invalidJson($request, ValidationException $exception) + { + return response()->json($exception->errors(), $exception->status); + } + protected function convertValidationExceptionToResponse(ValidationException $e, $request) { - $this->reportable(function (Throwable $e) { - // - }); + if ($e->response) { + return $e->response; + } + return $this->invalidJson($request, $e); } -} +} \ No newline at end of file diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index 9a22b0d..5d54a92 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -10,6 +10,14 @@ class ProjectController extends Controller { + public function __construct() + { + $this->middleware('acl:list:projects')->only(['index']); + $this->middleware('acl:create:project')->only(['store']); + $this->middleware('acl:view:project')->only(['show']); + $this->middleware('acl:update:project')->only(['update']); + $this->middleware('acl:delete:project')->only(['destroy']); + } /** * Display a listing of the resource. * diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php index 50cbc82..b022b5e 100644 --- a/app/Http/Controllers/TaskController.php +++ b/app/Http/Controllers/TaskController.php @@ -7,17 +7,33 @@ use App\Resources\TaskResource; use App\Models\Task; use Illuminate\Http\Request; +use Illuminate\Validation\UnauthorizedException; class TaskController extends Controller { + public function __construct() + { + $this->middleware('acl:create:task')->only(['store']); + $this->middleware('acl:delete:task')->only(['destroy']); + } + /** - * Display a listing of the resource. + Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { - return TaskResource::collection(Task::all()); + $canListAllTasks = $request->user()->tokenCan('list:tasks'); + $canListOwnTasks = $request->user()->tokenCan('list:own:tasks'); + if (!$canListAllTasks && !$canListOwnTasks) { + throw new UnauthorizedException('You are not authorized for this action', 403); + } + if ($canListAllTasks) { + return Task::simplePaginate(10); + } + $userId = $request->user()->id; + return Task::where(['user_id' => $userId])->simplePaginate(); } /** @@ -49,7 +65,20 @@ public function store(TaskRequest $request) */ public function show($id) { - return new TaskResource(Task::findOrFail($id)); + $canViewTask = $request->user()->tokenCan('view:task'); + $canViewOwnTask = $request->user()->tokenCan('view:own:task'); + if (!$canViewTask && !$canViewOwnTask) { + throw new UnauthorizedException('You are not authorized for this action', 403); + } + if ( + !$canViewTask + && $canViewOwnTask + && $task->user_id !== $request->user->id + ) { + throw new UnauthorizedException('You are not authorized for this action', 403); + } + + return $task->toArray(); } /** @@ -59,19 +88,37 @@ public function show($id) * @param int $id * @return \Illuminate\Http\Response */ - public function update(TaskRequest $request, Task $task) + public function update(TaskRequest $request, $taskId) { - $input = $request->input(); - $task->fill([ - 'title' => $input['title'], - 'description' => $input['description'], - 'status' => $input['status'], - 'project_id' => $input['project_id'], - 'user_id' => $input['user_id'], - ]); + $canUpdateTask = $request->user()->tokenCan('update:task'); + $canUpdateOwnTask = $request->user()->tokenCan('update:own:task'); + if (!$canUpdateTask && !$canUpdateOwnTask) { + throw new UnauthorizedException('You are not authorized for this action', 403); + } + $task = Task::findOrFail($taskId); - return new TaskResource($task); + if ( + !$canUpdateTask + && $canUpdateOwnTask + && $task->user_id !== $request->user->id + ) { + throw new UnauthorizedException('You are not authorized for this action', 403); + } + $updatable = [ + 'title', + 'description', + 'status', + 'project_id', + ]; + // A user cannot assign the task to another member + // Only product owner can + if ($canUpdateTask) { + array_push($updatable, 'user_id'); + } + $taskData = $request->only($updatable); + $task->update($taskData); + return $task->toArray(); } /** diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index bc07794..c9b9432 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -7,9 +7,21 @@ use App\Resources\UserResource; use App\Models\User; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Illuminate\Database\Eloquent\ModelNotFoundException; + class UserController extends Controller { + public function __construct() + { + $this->middleware('acl:list:users')->only(['index']); + $this->middleware('acl:create:user')->only(['store']); + $this->middleware('acl:view:user')->only(['show']); + $this->middleware('acl:update:user')->only(['update']); + $this->middleware('acl:delete:user')->only(['destroy']); + } /** * Display a listing of the resource. * @@ -29,7 +41,7 @@ public function index() public function store(UserRequest $request) { - $user = app('user_manager')->store($request->inpput()); + $user = app('user_manager')->store($request->input()); return new UserResource($user); } @@ -52,11 +64,11 @@ public function show($id) * @param int $id * @return \Illuminate\Http\Response */ - public function update(UserRequest $request, User $user) + public function update(UserRequest $request, $userId) { - $validated = $request->validated(); + $user = User::findOrFail($userId); + $user = app('user_manager')->store($request->input(), $user); - $user = $this->app('user_manager')->store($validated, $user); return new UserResource($user); } @@ -67,12 +79,30 @@ public function update(UserRequest $request, User $user) * @param int $id * @return \Illuminate\Http\Response */ - public function destroy(User $user) + public function destroy($userId) { + $user = User::findOrFail($userId); + $user->delete(); return response()->json([ 'message' => 'User deleted successfully' ], 200); } + + public function login(Request $request) { + if( + Auth::attempt([ + 'username' => $request->username, + 'password' => $request->password + ]) + ) { + $role = Auth::user()->role->slug; + $token = $request->user()->createToken($request->username, config("acl.{$role}") ?? []); + return [ + 'token' => $token->plainTextToken + ]; + } + throw new NotFoundHttpException('Cannot find user with provided details'); + } } \ No newline at end of file diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index d3722c2..2bff13d 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -40,7 +40,7 @@ class Kernel extends HttpKernel ], 'api' => [ - // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, + \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], @@ -63,5 +63,8 @@ class Kernel extends HttpKernel 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, + 'abilities' => \Laravel\Sanctum\Http\Middleware\CheckAbilities::class, + 'ability' => \Laravel\Sanctum\Http\Middleware\CheckForAnyAbility::class, + 'acl' => \App\Http\Middleware\Acl::class, ]; } diff --git a/app/Http/Middleware/Acl.php b/app/Http/Middleware/Acl.php new file mode 100644 index 0000000..18573ae --- /dev/null +++ b/app/Http/Middleware/Acl.php @@ -0,0 +1,24 @@ +user()->tokenCan($ability)) { + throw new UnauthorizedException('You are not authorized'); + } + return $next($request); + } +} diff --git a/app/Http/Requests/TaskRequest.php b/app/Http/Requests/TaskRequest.php index 600386a..382b650 100644 --- a/app/Http/Requests/TaskRequest.php +++ b/app/Http/Requests/TaskRequest.php @@ -30,6 +30,12 @@ public function rules() $rules['status'] = ['required', 'string']; $rules['project_id'] = ['required', 'exists:projects,id']; $rules['user_id'] = ['required', 'exists:users,id']; + if ($this->isMethod('put') || $this->isMethod('patch')) { + foreach($rules as $key=>$rule) { + array_unshift($rule,'sometimes'); + $rules[$key]=$rule; + } + } return $rules; } diff --git a/app/Http/Requests/UserRequest.php b/app/Http/Requests/UserRequest.php index e548dfa..c87baed 100644 --- a/app/Http/Requests/UserRequest.php +++ b/app/Http/Requests/UserRequest.php @@ -30,7 +30,12 @@ public function rules() $rules['username'] = ['required' , 'min:3' , 'max:255' , 'unique:users,username']; $rules['password'] = ['required' , 'confirmed', 'min:6']; $rules['role_id'] = ['required', 'exists:roles,id']; - + if ($this->isMethod('put') || $this->isMethod('patch')) { + foreach($rules as $key=>$rule) { + array_unshift($rule,'sometimes'); + $rules[$key]=$rule; + } + } return $rules; } diff --git a/app/Managers/UserManager.php b/app/Managers/UserManager.php index e1ff7f8..49c30e0 100644 --- a/app/Managers/UserManager.php +++ b/app/Managers/UserManager.php @@ -10,10 +10,11 @@ */ class UserManager { - public function store(array $input, User $user = null) : User { + public function store($input, $user = null) : User { if (!$user) { + var_dump("hi"); $user = User::create([ 'email' => $input['email'], 'username' => $input['username'], @@ -21,12 +22,15 @@ public function store(array $input, User $user = null) : User { 'role_id' => $input['role_id'], ]); } else { - $user->fill([ - 'email' => $input['email'], - 'name' => $input['name'], - 'username' => $input['username'], - 'role_id' => $input['role_id'], - ]); + $fillables = ['email','name','username','role_id']; + foreach ($fillables as $key => $value) { + if (isset($input[$value])) { + $user->fill([ + $value => $input[$value] + ]); + } + } + } if (isset($input['password'])) { diff --git a/app/Models/Task.php b/app/Models/Task.php index 582aa32..24d003a 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -15,7 +15,7 @@ class Task extends Model const STATUS = array( "NOT_STARTED" => "NOT_STARTED", "IN_PROGRESS" => "IN_PROGRESS", - "READY_FOR_TEST" => "READY_FOR_TEST", + "READY_FOR_TEST" => "READY_FOR_TEST", "COMPLETED" => "COMPLETED", ); diff --git a/config/acl.php b/config/acl.php new file mode 100644 index 0000000..964dcc7 --- /dev/null +++ b/config/acl.php @@ -0,0 +1,36 @@ + [ + // Users + 'list:users', + 'view:user', + 'create:user', + 'update:user', + 'delete:user', + ], + 'PRODUCT_OWNER' => [ + + // Projects + 'list:projects', + 'view:project', + 'create:project', + 'update:project', + 'delete:project', + + // Tasks + 'list:tasks', + 'view:task', + 'create:task', + 'update:task', + 'assign:task', + 'delete:task', + ], + + 'TEAM_MEMBER' => [ + // Tasks + 'list:own:tasks', + 'view:own:task', + 'update:own:task', + ] +]; diff --git a/config/auth.php b/config/auth.php index d8c6cee..8080450 100644 --- a/config/auth.php +++ b/config/auth.php @@ -40,6 +40,11 @@ 'driver' => 'session', 'provider' => 'users', ], + + 'api' => [ + 'driver' => 'sanctum', + 'provider' => 'users', + ], ], /* diff --git a/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php b/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php index 4315e16..d24fe13 100644 --- a/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php +++ b/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php @@ -15,7 +15,7 @@ public function up() { Schema::create('personal_access_tokens', function (Blueprint $table) { $table->id(); - $table->morphs('tokenable'); + $table->uuidMorphs('tokenable'); $table->string('name'); $table->string('token', 64)->unique(); $table->text('abilities')->nullable(); diff --git a/routes/api.php b/routes/api.php index 12e79a5..b81b56f 100644 --- a/routes/api.php +++ b/routes/api.php @@ -14,12 +14,13 @@ | */ -Route::middleware('auth:sanctum')->get('/user', function (Request $request) { - return $request->user(); -}); Route::prefix('v1')->group(function () { - Route::apiResource('users', App\Http\Controllers\UserController::class)->parameters(['users'=>'user_id']); - Route::apiResource('projects', App\Http\Controllers\ProjectController::class)->parameters(['projects'=>'project_id']); - Route::apiResource('tasks', App\Http\Controllers\TaskController::class)->parameters(['tasks'=>'task_id']); + Route::group(['middleware' => ['auth:api']], function () { + Route::apiResource('users', App\Http\Controllers\UserController::class)->parameters(['users'=>'user_id']); + Route::apiResource('projects', App\Http\Controllers\ProjectController::class)->parameters(['projects'=>'project_id']); + Route::apiResource('tasks', App\Http\Controllers\TaskController::class)->parameters(['tasks'=>'task_id']); + + }); + Route::name('login')->post('users/login', [App\Http\Controllers\UserController::class, 'login']); }); \ No newline at end of file From b320fd08a1f9a4f0f2c04123148b08e2a75da541 Mon Sep 17 00:00:00 2001 From: hiren Date: Thu, 25 Aug 2022 21:02:29 +0530 Subject: [PATCH 05/13] Implement Pagination --- .gitignore | 1 + app/Http/Controllers/ProjectController.php | 6 +- composer.json | 4 +- composer.lock | 216 ++++++++++++++++++++- config/json-api-paginate.php | 58 ++++++ storage/debugbar/.gitignore | 2 + 6 files changed, 283 insertions(+), 4 deletions(-) create mode 100644 config/json-api-paginate.php create mode 100644 storage/debugbar/.gitignore diff --git a/.gitignore b/.gitignore index eb003b0..5d19f90 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ npm-debug.log yarn-error.log /.idea /.vscode +/storage/debugbar \ No newline at end of file diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index 5d54a92..3ae7587 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -23,9 +23,11 @@ public function __construct() * * @return \Illuminate\Http\Response */ - public function index() + public function index(Request $request) { - return ProjectResource::collection(Project::all()); + $query = Project::query(); + + return Project::simplePaginate(); } /** diff --git a/composer.json b/composer.json index f13e8cb..5de652a 100644 --- a/composer.json +++ b/composer.json @@ -12,9 +12,11 @@ "guzzlehttp/guzzle": "^7.0.1", "laravel/framework": "^8.75", "laravel/sanctum": "^2.11", - "laravel/tinker": "^2.5" + "laravel/tinker": "^2.5", + "spatie/laravel-json-api-paginate": "^1.12" }, "require-dev": { + "barryvdh/laravel-debugbar": "^3.7", "facade/ignition": "^2.5", "fakerphp/faker": "^1.9.1", "laravel/sail": "^1.0.1", diff --git a/composer.lock b/composer.lock index aae1ba8..a187585 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": "06e16e85540ae716cfe0c1d773271ecf", + "content-hash": "3f9aa4cfab863e48d420b08faf56fef6", "packages": [ { "name": "asm89/stack-cors", @@ -3124,6 +3124,70 @@ ], "time": "2021-09-25T23:10:38+00:00" }, + { + "name": "spatie/laravel-json-api-paginate", + "version": "1.12.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-json-api-paginate.git", + "reference": "5ecdd3569d07a22798d8fe9de9ec6de640343b75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-json-api-paginate/zipball/5ecdd3569d07a22798d8fe9de9ec6de640343b75", + "reference": "5ecdd3569d07a22798d8fe9de9ec6de640343b75", + "shasum": "" + }, + "require": { + "illuminate/support": "^6.0|^7.0|^8.0|^9.0", + "php": "^7.3|^8.0" + }, + "require-dev": { + "orchestra/testbench": "^4.0|^5.0|^6.0|^7.0", + "phpunit/phpunit": "^8.0|^9.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\JsonApiPaginate\\JsonApiPaginateServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\JsonApiPaginate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "A paginator that plays nice with the JSON API spec", + "homepage": "https://github.com/spatie/laravel-json-api-paginate", + "keywords": [ + "laravel-json-api-paginate", + "spatie" + ], + "support": { + "source": "https://github.com/spatie/laravel-json-api-paginate/tree/1.12.0" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + } + ], + "time": "2022-05-16T12:16:39+00:00" + }, { "name": "swagger-api/swagger-ui", "version": "v3.52.5", @@ -5876,6 +5940,90 @@ } ], "packages-dev": [ + { + "name": "barryvdh/laravel-debugbar", + "version": "v3.7.0", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-debugbar.git", + "reference": "3372ed65e6d2039d663ed19aa699956f9d346271" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/3372ed65e6d2039d663ed19aa699956f9d346271", + "reference": "3372ed65e6d2039d663ed19aa699956f9d346271", + "shasum": "" + }, + "require": { + "illuminate/routing": "^7|^8|^9", + "illuminate/session": "^7|^8|^9", + "illuminate/support": "^7|^8|^9", + "maximebf/debugbar": "^1.17.2", + "php": ">=7.2.5", + "symfony/finder": "^5|^6" + }, + "require-dev": { + "mockery/mockery": "^1.3.3", + "orchestra/testbench-dusk": "^5|^6|^7", + "phpunit/phpunit": "^8.5|^9.0", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.6-dev" + }, + "laravel": { + "providers": [ + "Barryvdh\\Debugbar\\ServiceProvider" + ], + "aliases": { + "Debugbar": "Barryvdh\\Debugbar\\Facades\\Debugbar" + } + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Barryvdh\\Debugbar\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "PHP Debugbar integration for Laravel", + "keywords": [ + "debug", + "debugbar", + "laravel", + "profiler", + "webprofiler" + ], + "support": { + "issues": "https://github.com/barryvdh/laravel-debugbar/issues", + "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.7.0" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2022-07-11T09:26:42+00:00" + }, { "name": "doctrine/instantiator", "version": "1.4.1", @@ -6391,6 +6539,72 @@ }, "time": "2022-08-17T13:17:15+00:00" }, + { + "name": "maximebf/debugbar", + "version": "v1.18.0", + "source": { + "type": "git", + "url": "https://github.com/maximebf/php-debugbar.git", + "reference": "0d44b75f3b5d6d41ae83b79c7a4bceae7fbc78b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/0d44b75f3b5d6d41ae83b79c7a4bceae7fbc78b6", + "reference": "0d44b75f3b5d6d41ae83b79c7a4bceae7fbc78b6", + "shasum": "" + }, + "require": { + "php": "^7.1|^8", + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^2.6|^3|^4|^5|^6" + }, + "require-dev": { + "phpunit/phpunit": "^7.5.20 || ^9.4.2", + "twig/twig": "^1.38|^2.7|^3.0" + }, + "suggest": { + "kriswallsmith/assetic": "The best way to manage assets", + "monolog/monolog": "Log using Monolog", + "predis/predis": "Redis storage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + } + }, + "autoload": { + "psr-4": { + "DebugBar\\": "src/DebugBar/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maxime Bouroumeau-Fuseau", + "email": "maxime.bouroumeau@gmail.com", + "homepage": "http://maximebf.com" + }, + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Debug bar in the browser for php application", + "homepage": "https://github.com/maximebf/php-debugbar", + "keywords": [ + "debug", + "debugbar" + ], + "support": { + "issues": "https://github.com/maximebf/php-debugbar/issues", + "source": "https://github.com/maximebf/php-debugbar/tree/v1.18.0" + }, + "time": "2021-12-27T18:49:48+00:00" + }, { "name": "mockery/mockery", "version": "1.5.0", diff --git a/config/json-api-paginate.php b/config/json-api-paginate.php new file mode 100644 index 0000000..490ccd7 --- /dev/null +++ b/config/json-api-paginate.php @@ -0,0 +1,58 @@ + 3, + + /* + * The default number of results that will be returned + * when using the JSON API paginator. + */ + 'default_size' => 3, + + /* + * The key of the page[x] query string parameter for page number. + */ + 'number_parameter' => 'pageIndex', + + /* + * The key of the page[x] query string parameter for page size. + */ + 'size_parameter' => 'pageSize', + + /* + * The key of the page[x] query string parameter for cursor. + */ + 'cursor_parameter' => 'cursor', + + /* + * The name of the macro that is added to the Eloquent query builder. + */ + 'method_name' => 'jsonPaginate', + + /* + * If you only need to display Next and Previous links, you may use + * simple pagination to perform a more efficient query. + */ + 'use_simple_pagination' => true, + + /* + * If you want to use cursor pagination, set this to true. + * This would override use_simple_pagination. + */ + 'use_cursor_pagination' => false, + + /* + * Here you can override the base url to be used in the link items. + */ + 'base_url' => null, + + /* + * The name of the query parameter used for pagination + */ + 'pagination_parameter' => 'page', +]; diff --git a/storage/debugbar/.gitignore b/storage/debugbar/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/debugbar/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore From fcf8a57085f49e08c5666aa0bb50aed3d2e9e391 Mon Sep 17 00:00:00 2001 From: hiren Date: Thu, 25 Aug 2022 21:04:39 +0530 Subject: [PATCH 06/13] Implement Pagination --- app/Http/Controllers/ProjectController.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index 3ae7587..a957a7f 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -25,9 +25,12 @@ public function __construct() */ public function index(Request $request) { - $query = Project::query(); + $query =Project::query(); + if ($request->query('q',null)) { + $query->where('name','like',$request->query('q')); + } - return Project::simplePaginate(); + return $query->jsonPaginate(); } /** From 9991e59894edc24daeef60eec2fd613a1558d634 Mon Sep 17 00:00:00 2001 From: hiren Date: Thu, 25 Aug 2022 21:07:21 +0530 Subject: [PATCH 07/13] Add Postman Collections --- .../ProjectManagement.postman_collection.json | 512 ++++++++++++++++++ 1 file changed, 512 insertions(+) create mode 100644 docs/ProjectManagement.postman_collection.json diff --git a/docs/ProjectManagement.postman_collection.json b/docs/ProjectManagement.postman_collection.json new file mode 100644 index 0000000..c2c2f0e --- /dev/null +++ b/docs/ProjectManagement.postman_collection.json @@ -0,0 +1,512 @@ +{ + "info": { + "_postman_id": "b1745b6b-5e81-4649-818e-8d372141bacb", + "name": "Accenture", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "3060542" + }, + "item": [ + { + "name": "Users (All)", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "3|4444", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "http://localhost:8000/api/v1/users", + "protocol": "http", + "host": [ + "laravel-coding-test-level-2", + "test" + ], + "path": [ + "api", + "v1", + "users" + ] + } + }, + "response": [] + }, + { + "name": "A User", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "3|DHBHYKhEHV9u3ZXDcnDTFWIbUbLfxFm1R0p1IpsF", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "http://localhost:8000/api/v1/users/631ddd759d04487a868afdd1b7ad0cae", + "protocol": "http", + "host": [ + "laravel-coding-test-level-2", + "test" + ], + "path": [ + "api", + "v1", + "users", + "631ddd759d04487a868afdd1b7ad0cae" + ] + } + }, + "response": [] + }, + { + "name": "Store User", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "3|DHBHYKhEHV9u3ZXDcnDTFWIbUbLfxFm1R0p1IpsF", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "username", + "value": "product_owner2", + "type": "text" + }, + { + "key": "password", + "value": "123456", + "type": "text" + }, + { + "key": "role_id", + "value": "2", + "type": "text" + } + ] + }, + "url": { + "raw": "http://localhost:8000/api/v1/users", + "protocol": "http", + "host": [ + "laravel-coding-test-level-2", + "test" + ], + "path": [ + "api", + "v1", + "users" + ] + } + }, + "response": [] + }, + { + "name": "Update User", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "3|DHBHYKhEHV9u3ZXDcnDTFWIbUbLfxFm1R0p1IpsF", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "username", + "value": "team_member_edit", + "type": "text" + }, + { + "key": "password", + "value": "123456", + "type": "text" + }, + { + "key": "role_id", + "value": "3", + "type": "text" + } + ] + }, + "url": { + "raw": "http://localhost:8000/api/v1/users/631ddd759d04487a868afdd1b7ad0cae", + "protocol": "http", + "host": [ + "laravel-coding-test-level-2", + "test" + ], + "path": [ + "api", + "v1", + "users", + "631ddd759d04487a868afdd1b7ad0cae" + ] + } + }, + "response": [] + }, + { + "name": "Update User", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "3|DHBHYKhEHV9u3ZXDcnDTFWIbUbLfxFm1R0p1IpsF", + "type": "string" + } + ] + }, + "method": "PATCH", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "username", + "value": "team_member", + "type": "text" + }, + { + "key": "password", + "value": "123456", + "type": "text" + }, + { + "key": "role_id", + "value": "3", + "type": "text" + } + ] + }, + "url": { + "raw": "http://localhost:8000/api/v1/users/631ddd759d04487a868afdd1b7ad0cae", + "protocol": "http", + "host": [ + "laravel-coding-test-level-2", + "test" + ], + "path": [ + "api", + "v1", + "users", + "631ddd759d04487a868afdd1b7ad0cae" + ] + } + }, + "response": [] + }, + { + "name": "Delete User", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "3|DHBHYKhEHV9u3ZXDcnDTFWIbUbLfxFm1R0p1IpsF", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "http://localhost:8000/api/v1/users/631ddd759d04487a868afdd1b7ad0cae", + "protocol": "http", + "host": [ + "laravel-coding-test-level-2", + "test" + ], + "path": [ + "api", + "v1", + "users", + "631ddd759d04487a868afdd1b7ad0cae" + ] + } + }, + "response": [] + }, + { + "name": "Projects (Paginate)", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "2|mQ0ZCny8gXXmiY2ZuvjQm31ESrWkHG6kut58LzVv", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "http://localhost:8000/api/v1/projects?q=Project A&pageIndex=2&pageSize=5&sortBy=id&sortDirection=DESC", + "protocol": "http", + "host": [ + "laravel-coding-test-level-2", + "test" + ], + "path": [ + "api", + "v1", + "projects" + ], + "query": [ + { + "key": "q", + "value": "Project A" + }, + { + "key": "pageIndex", + "value": "2" + }, + { + "key": "pageSize", + "value": "5" + }, + { + "key": "sortBy", + "value": "id" + }, + { + "key": "sortDirection", + "value": "DESC" + } + ] + } + }, + "response": [] + }, + { + "name": "Store Project", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "2|mQ0ZCny8gXXmiY2ZuvjQm31ESrWkHG6kut58LzVv", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "name", + "value": "Project A", + "type": "text" + } + ] + }, + "url": { + "raw": "http://localhost:8000/api/v1/projects", + "protocol": "http", + "host": [ + "laravel-coding-test-level-2", + "test" + ], + "path": [ + "api", + "v1", + "projects" + ] + } + }, + "response": [] + }, + { + "name": "Store Task", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "2|mQ0ZCny8gXXmiY2ZuvjQm31ESrWkHG6kut58LzVv", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "title", + "value": "Task A", + "type": "text" + }, + { + "key": "description", + "value": "Sample Desc", + "type": "text" + }, + { + "key": "project_id", + "value": "553f8b2ecf0b4085ac346363cdcfca29", + "type": "text" + }, + { + "key": "user_id", + "value": "631ddd759d04487a868afdd1b7ad0cae", + "type": "text" + } + ] + }, + "url": { + "raw": "http://localhost:8000/api/v1/tasks", + "protocol": "http", + "host": [ + "laravel-coding-test-level-2", + "test" + ], + "path": [ + "api", + "v1", + "tasks" + ] + } + }, + "response": [] + }, + { + "name": "Update Task Status", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "3|DHBHYKhEHV9u3ZXDcnDTFWIbUbLfxFm1R0p1IpsF", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "status", + "value": "IN_PROGRESS", + "type": "text" + } + ] + }, + "url": { + "raw": "http://localhost:8000/api/v1/taskstatus/cbec712866c74cca8fcd6761a7dc2f8e", + "protocol": "http", + "host": [ + "laravel-coding-test-level-2", + "test" + ], + "path": [ + "api", + "v1", + "taskstatus", + "cbec712866c74cca8fcd6761a7dc2f8e" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file From c1430aee1c5d633dea8867e3a84c4069f61fa4f0 Mon Sep 17 00:00:00 2001 From: hiren Date: Thu, 25 Aug 2022 21:27:54 +0530 Subject: [PATCH 08/13] Added Bonus Feature Cache & Docker Image --- .dockerignore | 1 + Dockerfile | 81 ++++++++++++ Dockerfile.local | 83 ++++++++++++ app/Http/Controllers/ProjectController.php | 2 +- app/Http/Kernel.php | 2 + app/Models/ClearCacheTrait.php | 22 ++++ app/Models/Project.php | 2 +- composer.json | 3 +- composer.lock | 141 ++++++++++++++++++++- config/responsecache.php | 71 +++++++++++ docker/nginx.conf | 35 +++++ docker/php.ini | 6 + docker/run.sh | 9 ++ docker/supervisor.conf | 71 +++++++++++ 14 files changed, 525 insertions(+), 4 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 Dockerfile.local create mode 100644 app/Models/ClearCacheTrait.php create mode 100644 config/responsecache.php create mode 100644 docker/nginx.conf create mode 100644 docker/php.ini create mode 100644 docker/run.sh create mode 100644 docker/supervisor.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5657f6e --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +vendor \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d8e7995 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,81 @@ +FROM php:8.0-fpm + +# Set working directory +WORKDIR /var/www + +# Install dependencies +RUN apt-get update && apt-get install -y \ + libmemcached-dev \ + wget \ + libonig-dev \ + libzip-dev \ + build-essential \ + libpng-dev \ + libjpeg62-turbo-dev \ + libfreetype6-dev \ + locales \ + zip \ + jpegoptim optipng pngquant gifsicle \ + unzip \ + git \ + curl \ + lua-zlib-dev \ + libmemcached-dev \ + nginx \ + redis-server + +# Install php extensions +RUN docker-php-ext-install mbstring pdo_mysql zip exif pcntl gd + +# Install Memcached +RUN mkdir -p /usr/src/php/ext/memcached +WORKDIR /usr/src/php/ext/memcached +RUN wget https://github.com/php-memcached-dev/php-memcached/archive/v3.2.0.zip; unzip /usr/src/php/ext/memcached/v3.2.0.zip +RUN mv /usr/src/php/ext/memcached/php-memcached-3.2.0/* /usr/src/php/ext/memcached/ +RUN docker-php-ext-configure memcached && docker-php-ext-install memcached +# reset working dir +WORKDIR /var/www + + +RUN mkdir -p /usr/src/php/ext/redis +WORKDIR /usr/src/php/ext/redis +RUN curl -fsSL https://pecl.php.net/get/redis --ipv4 | tar xvz -C "/usr/src/php/ext/redis" --strip 1; +RUN docker-php-ext-configure redis && docker-php-ext-install redis +# reset working dir +WORKDIR /var/www + + +# Install supervisor +RUN apt-get install -y supervisor + +# Install composer +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + +# Clear cache +RUN apt-get clean && rm -rf /var/lib/apt/lists/* + +# Add user for laravel application +RUN groupadd -g 1000 www +RUN useradd -u 1000 -ms /bin/bash -g www www + +# Copy code to /var/www +COPY --chown=www:www-data . /var/www + +# add root to www group +RUN chmod -R ug+w /var/www/storage + +# Copy nginx/php/supervisor configs +RUN cp docker/supervisor.conf /etc/supervisord.conf +RUN cp docker/php.ini /usr/local/etc/php/conf.d/app.ini +RUN cp docker/nginx.conf /etc/nginx/sites-enabled/default + +# PHP Error Log Files +RUN mkdir /var/log/php +RUN touch /var/log/php/errors.log && chmod 777 /var/log/php/errors.log + +# Deployment steps +RUN composer install --optimize-autoloader --no-dev +RUN chmod +x /var/www/docker/run.sh + +EXPOSE 80 +ENTRYPOINT ["/var/www/docker/run.sh"] diff --git a/Dockerfile.local b/Dockerfile.local new file mode 100644 index 0000000..cba323f --- /dev/null +++ b/Dockerfile.local @@ -0,0 +1,83 @@ +FROM php:8.0-fpm + +# Set working directory +WORKDIR /var/www + +# Install dependencies +RUN apt-get update && apt-get install -y \ + libmemcached-dev \ + wget \ + libonig-dev \ + libzip-dev \ + build-essential \ + libpng-dev \ + libjpeg62-turbo-dev \ + libfreetype6-dev \ + locales \ + zip \ + jpegoptim optipng pngquant gifsicle \ + unzip \ + git \ + curl \ + lua-zlib-dev \ + libmemcached-dev \ + nginx \ + redis-server + +# Install php extensions +RUN docker-php-ext-install mbstring pdo_mysql zip exif pcntl gd + +# Install Memcached +RUN mkdir -p /usr/src/php/ext/memcached +WORKDIR /usr/src/php/ext/memcached +RUN wget https://github.com/php-memcached-dev/php-memcached/archive/v3.2.0.zip; unzip /usr/src/php/ext/memcached/v3.2.0.zip +RUN mv /usr/src/php/ext/memcached/php-memcached-3.2.0/* /usr/src/php/ext/memcached/ +RUN docker-php-ext-configure memcached && docker-php-ext-install memcached +# reset working dir +WORKDIR /var/www + + +RUN mkdir -p /usr/src/php/ext/redis +WORKDIR /usr/src/php/ext/redis +RUN curl -fsSL https://pecl.php.net/get/redis --ipv4 | tar xvz -C "/usr/src/php/ext/redis" --strip 1; +RUN docker-php-ext-configure redis && docker-php-ext-install redis +# reset working dir +WORKDIR /var/www + + +# Install supervisor +RUN apt-get install -y supervisor + +# Install composer +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + +# Clear cache +RUN apt-get clean && rm -rf /var/lib/apt/lists/* + +# Add user for laravel application +RUN groupadd -g 1000 www +RUN useradd -u 1000 -ms /bin/bash -g www www + +# Copy code to /var/www +COPY --chown=www:www-data . /var/www + +# add root to www group +RUN chmod -R ug+w /var/www/storage + +VOLUME . /var/www + +# Copy nginx/php/supervisor configs +RUN cp docker/supervisor.conf /etc/supervisord.conf +RUN cp docker/php.ini /usr/local/etc/php/conf.d/app.ini +RUN cp docker/nginx.conf /etc/nginx/sites-enabled/default + +# PHP Error Log Files +RUN mkdir /var/log/php +RUN touch /var/log/php/errors.log && chmod 777 /var/log/php/errors.log + +# Deployment steps +RUN composer install --optimize-autoloader --no-dev +RUN chmod +x /var/www/docker/run.sh + +EXPOSE 80 +ENTRYPOINT ["/var/www/docker/run.sh"] diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index a957a7f..68a4862 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -12,7 +12,7 @@ class ProjectController extends Controller { public function __construct() { - $this->middleware('acl:list:projects')->only(['index']); + $this->middleware([\Spatie\ResponseCache\Middlewares\CacheResponse::class,'acl:list:projects'])->only(['index']); $this->middleware('acl:create:project')->only(['store']); $this->middleware('acl:view:project')->only(['show']); $this->middleware('acl:update:project')->only(['update']); diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 2bff13d..caf2353 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -66,5 +66,7 @@ class Kernel extends HttpKernel 'abilities' => \Laravel\Sanctum\Http\Middleware\CheckAbilities::class, 'ability' => \Laravel\Sanctum\Http\Middleware\CheckForAnyAbility::class, 'acl' => \App\Http\Middleware\Acl::class, + 'doNotCacheResponse' => \Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class, + ]; } diff --git a/app/Models/ClearCacheTrait.php b/app/Models/ClearCacheTrait.php new file mode 100644 index 0000000..153ca02 --- /dev/null +++ b/app/Models/ClearCacheTrait.php @@ -0,0 +1,22 @@ + env('RESPONSE_CACHE_ENABLED', true), + + /* + * The given class will determinate if a request should be cached. The + * default class will cache all successful GET-requests. + * + * You can provide your own class given that it implements the + * CacheProfile interface. + */ + 'cache_profile' => Spatie\ResponseCache\CacheProfiles\CacheAllSuccessfulGetRequests::class, + + /* + * When using the default CacheRequestFilter this setting controls the + * default number of seconds responses must be cached. + */ + 'cache_lifetime_in_seconds' => env('RESPONSE_CACHE_LIFETIME', 60 * 60 * 24 * 7), + + /* + * This setting determines if a http header named with the cache time + * should be added to a cached response. This can be handy when + * debugging. + */ + 'add_cache_time_header' => env('APP_DEBUG', true), + + /* + * This setting determines the name of the http header that contains + * the time at which the response was cached + */ + 'cache_time_header_name' => env('RESPONSE_CACHE_HEADER_NAME', 'laravel-responsecache'), + + /* + * Here you may define the cache store that should be used to store + * requests. This can be the name of any store that is + * configured in app/config/cache.php + */ + 'cache_store' => env('RESPONSE_CACHE_DRIVER', 'file'), + + /* + * Here you may define replacers that dynamically replace content from the response. + * Each replacer must implement the Replacer interface. + */ + 'replacers' => [ + \Spatie\ResponseCache\Replacers\CsrfTokenReplacer::class, + ], + + /* + * If the cache driver you configured supports tags, you may specify a tag name + * here. All responses will be tagged. When clearing the responsecache only + * items with that tag will be flushed. + * + * You may use a string or an array here. + */ + 'cache_tag' => '', + + /* + * This class is responsible for generating a hash for a request. This hash + * is used to look up an cached response. + */ + 'hasher' => \Spatie\ResponseCache\Hasher\DefaultHasher::class, + + /* + * This class is responsible for serializing responses. + */ + 'serializer' => \Spatie\ResponseCache\Serializers\DefaultSerializer::class, +]; diff --git a/docker/nginx.conf b/docker/nginx.conf new file mode 100644 index 0000000..d74dfb2 --- /dev/null +++ b/docker/nginx.conf @@ -0,0 +1,35 @@ +server { + listen 80; + root /var/www/public; + + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-Content-Type-Options "nosniff"; + + index index.php index.html; + charset utf-8; + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + error_page 404 /index.php; + + location ~ \.php$ { + try_files $uri =404; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass 127.0.0.1:9000; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_buffering off; + } + + location / { + try_files $uri $uri/ /index.php?$query_string; + gzip_static on; + } + + location ~ /\.(?!well-known).* { + deny all; + } +} diff --git a/docker/php.ini b/docker/php.ini new file mode 100644 index 0000000..2727278 --- /dev/null +++ b/docker/php.ini @@ -0,0 +1,6 @@ +log_errors=1 +display_errors=1 +post_max_size=40M +upload_max_filesize=40M +display_startup_errors=1 +error_log=/var/log/php/errors.log diff --git a/docker/run.sh b/docker/run.sh new file mode 100644 index 0000000..86398d1 --- /dev/null +++ b/docker/run.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +cd /var/www + +# php artisan migrate:fresh --seed +php artisan cache:clear +php artisan route:cache + +/usr/bin/supervisord -c /etc/supervisord.conf diff --git a/docker/supervisor.conf b/docker/supervisor.conf new file mode 100644 index 0000000..83c0862 --- /dev/null +++ b/docker/supervisor.conf @@ -0,0 +1,71 @@ +[supervisord] +nodaemon=true +loglevel=info +logfile=/var/log/supervisord.log +pidfile=/var/run/supervisord.pid + +[group:laravel-worker] +priority=999 +programs=redis,nginx,php8-fpm +# programs=redis,nginx,php8-fpm,laravel-schedule,laravel-notification,laravel-queue + +[program:nginx] +priority=10 +autostart=true +autorestart=true +stderr_logfile_maxbytes=0 +stdout_logfile_maxbytes=0 +stdout_events_enabled=true +stderr_events_enabled=true +command=/usr/sbin/nginx -g 'daemon off;' +stderr_logfile=/var/log/nginx/error.log +stdout_logfile=/var/log/nginx/access.log + +[program:redis] +priority=10 +autostart=true +autorestart=true +stderr_logfile_maxbytes=0 +stdout_logfile_maxbytes=0 +stdout_events_enabled=true +stderr_events_enabled=true +command=/usr/bin/redis-server +stderr_logfile=/var/log/redis/error.log +stdout_logfile=/var/log/redis/access.log + +[program:php8-fpm] +priority=5 +autostart=true +autorestart=true +stderr_logfile_maxbytes=0 +stdout_logfile_maxbytes=0 +command=/usr/local/sbin/php-fpm -R +stderr_logfile=/var/log/nginx/php-error.log +stdout_logfile=/var/log/nginx/php-access.log + +# [program:laravel-schedule] +# numprocs=1 +# autostart=true +# autorestart=true +# redirect_stderr=true +# process_name=%(program_name)s_%(process_num)02d +# command=php /var/www/artisan schedule:run +# stdout_logfile=/var/log/nginx/schedule.log + +# [program:laravel-notification] +# numprocs=1 +# autostart=true +# autorestart=true +# redirect_stderr=true +# process_name=%(program_name)s_%(process_num)02d +# command=php /var/www/artisan notification:worker +# stdout_logfile=/var/log/nginx/notification.log + +# [program:laravel-queue] +# numprocs=5 +# autostart=true +# autorestart=true +# redirect_stderr=true +# process_name=%(program_name)s_%(process_num)02d +# stdout_logfile=/var/log/nginx/worker.log +# command=php /var/www/artisan queue:work sqs --sleep=3 --tries=3 From fb243d052aaac87e8197b4e034fbe527f2cc1f3c Mon Sep 17 00:00:00 2001 From: hiren Date: Fri, 26 Aug 2022 12:48:46 +0530 Subject: [PATCH 09/13] Write Test --- .env.testing | 49 +++++++++++++++++++ app/Http/Middleware/Acl.php | 1 + app/Managers/UserManager.php | 1 - tests/Feature/ProjectTest.php | 82 ++++++++++++++++++++++++++++++++ tests/Feature/TeamMemberTest.php | 52 ++++++++++++++++++++ tests/Feature/UserTest.php | 50 +++++++++++++++++++ tests/TestCase.php | 43 +++++++++++++++++ 7 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 .env.testing create mode 100644 tests/Feature/ProjectTest.php create mode 100644 tests/Feature/TeamMemberTest.php create mode 100644 tests/Feature/UserTest.php diff --git a/.env.testing b/.env.testing new file mode 100644 index 0000000..f817e90 --- /dev/null +++ b/.env.testing @@ -0,0 +1,49 @@ +APP_NAME=Laravel +APP_ENV=local +APP_KEY=base64:k/nD/nGycrB8CR2Xuu1svePLBI4YT8mBR7TbmZznigI= +APP_DEBUG=false +APP_URL=http://localhost + +LOG_CHANNEL=stack +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +DB_CONNECTION=sqlite + +BROADCAST_DRIVER=log +CACHE_DRIVER=file +FILESYSTEM_DRIVER=local +QUEUE_CONNECTION=sync +SESSION_DRIVER=file +SESSION_LIFETIME=120 + +MEMCACHED_HOST=127.0.0.1 + +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_MAILER=smtp +MAIL_HOST=mailhog +MAIL_PORT=1025 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null +MAIL_FROM_ADDRESS=null +MAIL_FROM_NAME="${APP_NAME}" + +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= +AWS_USE_PATH_STYLE_ENDPOINT=false + +PUSHER_APP_ID= +PUSHER_APP_KEY= +PUSHER_APP_SECRET= +PUSHER_APP_CLUSTER=mt1 + +MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" +MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" + +DB_DATABASE=":memory:" \ No newline at end of file diff --git a/app/Http/Middleware/Acl.php b/app/Http/Middleware/Acl.php index 18573ae..c7812a8 100644 --- a/app/Http/Middleware/Acl.php +++ b/app/Http/Middleware/Acl.php @@ -16,6 +16,7 @@ class Acl */ public function handle(Request $request, Closure $next, $ability) { + if (!$request->user()->tokenCan($ability)) { throw new UnauthorizedException('You are not authorized'); } diff --git a/app/Managers/UserManager.php b/app/Managers/UserManager.php index 49c30e0..4a49a1c 100644 --- a/app/Managers/UserManager.php +++ b/app/Managers/UserManager.php @@ -14,7 +14,6 @@ public function store($input, $user = null) : User { if (!$user) { - var_dump("hi"); $user = User::create([ 'email' => $input['email'], 'username' => $input['username'], diff --git a/tests/Feature/ProjectTest.php b/tests/Feature/ProjectTest.php new file mode 100644 index 0000000..b0df027 --- /dev/null +++ b/tests/Feature/ProjectTest.php @@ -0,0 +1,82 @@ +bootUp(); + // create two user + $this->loginAsRole('ADMIN'); + $user1Data=[ + "name" => "Demo User 1", + "email" => "demo-1@atyantik.com", + "username" => "demo-1", + "password" => "demo-1@123", + "password_confirmation" => "demo-1@123", + "role_id" => 3 + ]; + $user2Data=[ + "name" => "Demo User 2", + "email" => "demo-2@atyantik.com", + "username" => "demo-2", + "password" => "demo-2@123", + "password_confirmation" => "demo-2@123", + "role_id" => 3 + ]; + $createUser1Response = $this->post('/api/v1/users', $user1Data); + $createUser2Response = $this->post('/api/v1/users', $user2Data); + $createUser1Response->assertStatus(201); + $createUser2Response->assertStatus(201); + $user1 = json_decode($createUser1Response->getContent()); + $user2 = json_decode($createUser2Response->getContent()); + + // create project + $this->loginAsRole('PRODUCT_OWNER'); + $project = [ + "name" => "Test Project A", + ]; + $createProjectResponse = $this->post('api/v1/projects', $project); + $createProjectResponse->assertStatus(201); + $createProjectResponse->assertJsonPath("data.name", "Test Project A"); + $projectObj = json_decode($createProjectResponse->getContent()); + + $task1Response = $this->post('api/v1/tasks', [ + "title" => "Task 1", + "description" => "Task 1 For User 1", + "project_id" => $projectObj->data->id, + "user_id" => $user1->data->id, + "status" => 'NOT_STARTED' + ]); + $task1Response->assertStatus(201); + $task1Response->assertJsonPath("data.title", "Task 1"); + $task1Response->assertJsonPath("data.status", 'NOT_STARTED'); + $task1Response->assertJsonPath("data.project_id", $projectObj->data->id); + $task1Response->assertJsonPath("data.user_id", $user1->data->id); + + $task2Response = $this->post('/api/v1/tasks', [ + "title" => "Task 2", + "description" => "Task 2 for user 2", + "project_id" => $projectObj->data->id, + "user_id" => $user2->data->id, + "status" => 'NOT_STARTED' + ]); + $task2Response->assertStatus(201); + $task2Response->assertJsonPath("data.title", "Task 2"); + $task2Response->assertJsonPath("data.status", 'NOT_STARTED'); + $task2Response->assertJsonPath("data.project_id", $projectObj->data->id); + $task2Response->assertJsonPath("data.user_id", $user2->data->id); + + $this->shutdown(); + } +} diff --git a/tests/Feature/TeamMemberTest.php b/tests/Feature/TeamMemberTest.php new file mode 100644 index 0000000..6a66b9b --- /dev/null +++ b/tests/Feature/TeamMemberTest.php @@ -0,0 +1,52 @@ +bootUp(); + // create project + $this->loginAsRole('PRODUCT_OWNER'); + $project = [ + "name" => "Test Project A For Status Change", + ]; + $createProjectResponse = $this->post('api/v1/projects', $project); + $createProjectResponse->assertStatus(201); + $createProjectResponse->assertJsonPath("data.name", "Test Project A For Status Change"); + $projectObj = json_decode($createProjectResponse->getContent()); + $existingTeamMember = \App\Models\User::where('email','team-member@atyantik.com')->first(); + + $taskResponse = $this->post('api/v1/tasks', [ + "title" => "Task 1 For Status Change", + "description" => "Task 1 For User 1", + "project_id" => $projectObj->data->id, + "user_id" => $existingTeamMember->id, + "status" => 'NOT_STARTED' + ]); + $taskResponse->assertStatus(201); + $taskObj = json_decode($taskResponse->getContent()); + + $taskResponse->assertJsonPath("data.title", "Task 1 For Status Change"); + $taskResponse->assertJsonPath("data.status", 'NOT_STARTED'); + $taskResponse->assertJsonPath("data.project_id", $projectObj->data->id); + $taskResponse->assertJsonPath("data.user_id", $existingTeamMember->id); + + $this->loginAsRole('TEAM_MEMBER'); + $taskResponse = $this->patch('api/v1/tasks/'.$taskObj->data->id, [ + "status" => 'IN_PROGRESS' + ]); + $taskResponse->assertStatus(200); + + } +} diff --git a/tests/Feature/UserTest.php b/tests/Feature/UserTest.php new file mode 100644 index 0000000..fdb7f27 --- /dev/null +++ b/tests/Feature/UserTest.php @@ -0,0 +1,50 @@ +get('/'); + + $response->assertStatus(200); + } + + public function test_user_create() + { + $this->bootUp(); + $this->loginAsRole('ADMIN'); + + $userData = [ + "name" => "Hiren Test", + "email" => "hiren-test@atyantik.com", + "username" => "hiren-test", + "password" => "hiren-test@123", + "password_confirmation" => "hiren-test@123", + "role_id" => 1 + ]; + $createUserResponse = $this->post('/api/v1/users', $userData); + $checkUserData = [ + "name" => "Hiren Test", + "email" => "hiren-test@atyantik.com", + "username" => "hiren-test", + "role_id" => 1 + ]; + + foreach ($checkUserData as $userKey => $userValue) { + $createUserResponse->assertJsonPath("data.{$userKey}", $userValue); + } + $this->shutdown(); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 2932d4a..01e853e 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -7,4 +7,47 @@ abstract class TestCase extends BaseTestCase { use CreatesApplication; + + protected function bootUp() { + $this->artisan('db:wipe'); + $this->artisan('migrate'); + $this->artisan('db:seed --class="RoleSeeder"'); + $this->artisan('db:seed --class="User"'); + } + + protected function loginAsRole($role = '') { + $loginApiLink = '/api/v1/users/login'; + + // Only admin can create users + + if ($role === 'ADMIN') { + // Login as Admin, PHP unit test case will take care of the + // token/cookie + $this->post($loginApiLink, [ + "username" => "admin", + "password" => "admin@123", + ]); + } + if ($role === 'PRODUCT_OWNER') { + // Login as Admin, PHP unit test case will take care of the + // token/cookie + $this->post($loginApiLink, [ + "username" => "product_owner", + "password" => "product_owner@123", + ]); + } + + if ($role === 'TEAM_MEMBER') { + // Login as Admin, PHP unit test case will take care of the + // token/cookie + $this->post($loginApiLink, [ + "username" => "team", + "password" => "team@123", + ]); + } + } + + protected function shutdown() { + $this->artisan('db:wipe'); + } } From d89f52965aff6fb6fde5b6efd967812bdcb816bd Mon Sep 17 00:00:00 2001 From: hiren Date: Fri, 26 Aug 2022 14:23:03 +0530 Subject: [PATCH 10/13] Basic Open API features --- app/Http/Middleware/VerifyCsrfToken.php | 2 +- app/Models/User.php | 13 +++++ app/api.php | 22 ++++++- storage/api-docs/api-docs.json | 76 ++++++++++++++++++++++++- tests/Feature/TeamMemberTest.php | 52 +++++++++++++++++ 5 files changed, 162 insertions(+), 3 deletions(-) create mode 100644 tests/Feature/TeamMemberTest.php diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index 9e86521..a58f6cd 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -12,6 +12,6 @@ class VerifyCsrfToken extends Middleware * @var array */ protected $except = [ - // + 'api/v1/*' ]; } diff --git a/app/Models/User.php b/app/Models/User.php index 2c08c9c..6868b9d 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -8,6 +8,19 @@ use Laravel\Sanctum\HasApiTokens; use GoldSpecDigital\LaravelEloquentUUID\Foundation\Auth\User as Authenticatable; +/** + * + * @OA\Schema(schema="Login", + * @OA\Property(property="username", type="string", description="username", default="admin"), + * @OA\Property(property="password", type="string", description="password", default="admin@123") + * ); + * @OA\RequestBody( + * request="Login", + * description="Login ", + * required=true, + * @OA\JsonContent(ref="#/components/schemas/Login") + * ) + **/ class User extends Authenticatable { use HasApiTokens, HasFactory, Notifiable; diff --git a/app/api.php b/app/api.php index 728bdc8..d736124 100644 --- a/app/api.php +++ b/app/api.php @@ -43,7 +43,7 @@ * ) * ) * ), - * @OA\Parameter(name="Authorization", in="header", @OA\Schema(type="string"), required=true, description="JWT Token"), + * @OA\Parameter(name="Authorization", in="header", @OA\Schema(type="string"), required=true, description="Sanctum Token"), * @OA\Parameter(name="sortBy", in="query", @OA\Schema(type="string"), description="Sort Order"), * @OA\Parameter(name="sortDirection", in="query", @OA\Schema(type="string", enum={"asc","desc"}), description="Sort Direction"), * @OA\Parameter(name="includes", in="query", description="Includes for getting object dependened data", @OA\Schema(type="array", @OA\Items( type="string", collectionFormat="csv")) ) @@ -57,3 +57,23 @@ * @OA\Response(response="200", description="Display a listing of projects.") * ) */ + +/** + * @OA\Post( + * path="/users/login", + * tags={"Login"}, + * summary="Login as User", + * description="Login as User", + * requestBody={"$ref":"#/components/requestBodies/Login"}, + * @OA\Response( + * response=200, + * description="successful operation", + * @OA\JsonContent(ref="#/components/schemas/Success") + * ), + * @OA\Response(response=400, description="Invalid Order"), + * @OA\Response(response=401, description="Invalid Credential", @OA\JsonContent(ref="#/components/schemas/Error")), + * @OA\Response(response=403, description="Forbidden"), + * @OA\Response(response=404, description="Invalid Client Code"), + * @OA\Response(response=500, description="Internal Server Error") + * ) + */ \ No newline at end of file diff --git a/storage/api-docs/api-docs.json b/storage/api-docs/api-docs.json index 2298187..282eea8 100644 --- a/storage/api-docs/api-docs.json +++ b/storage/api-docs/api-docs.json @@ -26,6 +26,52 @@ } } } + }, + "/users/login": { + "post": { + "tags": [ + "Login" + ], + "summary": "Login as User", + "description": "Login as User", + "requestBody": { + "$ref": "#/components/requestBodies/Login" + }, + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Success" + } + } + } + }, + "400": { + "description": "Invalid Order" + }, + "401": { + "description": "Invalid Credential", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Invalid Client Code" + }, + "500": { + "description": "Internal Server Error" + } + } + } } }, "components": { @@ -92,13 +138,28 @@ } }, "type": "object" + }, + "Login": { + "properties": { + "username": { + "description": "username", + "type": "string", + "default": "admin" + }, + "password": { + "description": "password", + "type": "string", + "default": "admin@123" + } + }, + "type": "object" } }, "parameters": { "Authorization": { "name": "Authorization", "in": "header", - "description": "JWT Token", + "description": "Sanctum Token", "required": true, "schema": { "type": "string" @@ -136,6 +197,19 @@ } } } + }, + "requestBodies": { + "Login": { + "description": "Login ", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Login" + } + } + } + } } }, "security": [ diff --git a/tests/Feature/TeamMemberTest.php b/tests/Feature/TeamMemberTest.php new file mode 100644 index 0000000..6a66b9b --- /dev/null +++ b/tests/Feature/TeamMemberTest.php @@ -0,0 +1,52 @@ +bootUp(); + // create project + $this->loginAsRole('PRODUCT_OWNER'); + $project = [ + "name" => "Test Project A For Status Change", + ]; + $createProjectResponse = $this->post('api/v1/projects', $project); + $createProjectResponse->assertStatus(201); + $createProjectResponse->assertJsonPath("data.name", "Test Project A For Status Change"); + $projectObj = json_decode($createProjectResponse->getContent()); + $existingTeamMember = \App\Models\User::where('email','team-member@atyantik.com')->first(); + + $taskResponse = $this->post('api/v1/tasks', [ + "title" => "Task 1 For Status Change", + "description" => "Task 1 For User 1", + "project_id" => $projectObj->data->id, + "user_id" => $existingTeamMember->id, + "status" => 'NOT_STARTED' + ]); + $taskResponse->assertStatus(201); + $taskObj = json_decode($taskResponse->getContent()); + + $taskResponse->assertJsonPath("data.title", "Task 1 For Status Change"); + $taskResponse->assertJsonPath("data.status", 'NOT_STARTED'); + $taskResponse->assertJsonPath("data.project_id", $projectObj->data->id); + $taskResponse->assertJsonPath("data.user_id", $existingTeamMember->id); + + $this->loginAsRole('TEAM_MEMBER'); + $taskResponse = $this->patch('api/v1/tasks/'.$taskObj->data->id, [ + "status" => 'IN_PROGRESS' + ]); + $taskResponse->assertStatus(200); + + } +} From ceb191bde0677b9f66cf19862f78cac97317a34f Mon Sep 17 00:00:00 2001 From: hiren Date: Fri, 26 Aug 2022 15:40:32 +0530 Subject: [PATCH 11/13] Added User List API with sanctum authorizaion feature for OpenAPI 3.0 --- app/Http/Controllers/UserController.php | 3 +- app/Resources/UserResource.php | 9 ++++ app/api.php | 33 +++++++++++--- config/l5-swagger.php | 2 +- storage/api-docs/api-docs.json | 57 +++++++++++++++++++++---- 5 files changed, 85 insertions(+), 19 deletions(-) diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index c9b9432..5b21694 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -11,12 +11,11 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Illuminate\Database\Eloquent\ModelNotFoundException; - class UserController extends Controller { public function __construct() { - $this->middleware('acl:list:users')->only(['index']); + //$this->middleware('acl:list:users')->only(['index']); $this->middleware('acl:create:user')->only(['store']); $this->middleware('acl:view:user')->only(['show']); $this->middleware('acl:update:user')->only(['update']); diff --git a/app/Resources/UserResource.php b/app/Resources/UserResource.php index 221f194..f242b23 100644 --- a/app/Resources/UserResource.php +++ b/app/Resources/UserResource.php @@ -4,6 +4,15 @@ use Illuminate\Http\Resources\Json\JsonResource; +/** + * @OA\Schema( + * title="UserResource", + * description="User resource", + * @OA\Xml( + * name="UserResource" + * ) + * ) + */ class UserResource extends JsonResource { /** diff --git a/app/api.php b/app/api.php index d736124..4527945 100644 --- a/app/api.php +++ b/app/api.php @@ -51,13 +51,6 @@ * ) */ -/** - * @OA\Get( - * path="/projects", - * @OA\Response(response="200", description="Display a listing of projects.") - * ) - */ - /** * @OA\Post( * path="/users/login", @@ -76,4 +69,30 @@ * @OA\Response(response=404, description="Invalid Client Code"), * @OA\Response(response=500, description="Internal Server Error") * ) + */ + +/** + * @OA\Get( + * path="/users", + * security={{ + * "sanctum":{} + * }}, + * operationId="getUserList", + * tags={"Users"}, + * summary="Get list of users", + * description="Returns list of users", + * @OA\Response( + * response=200, + * description="Successful operation", + * @OA\JsonContent(ref="#/components/schemas/UserResource") + * ), + * @OA\Response( + * response=401, + * description="Unauthenticated", + * ), + * @OA\Response( + * response=403, + * description="Forbidden" + * ) + * ) */ \ No newline at end of file diff --git a/config/l5-swagger.php b/config/l5-swagger.php index 81b3dff..91f32ae 100644 --- a/config/l5-swagger.php +++ b/config/l5-swagger.php @@ -185,13 +185,13 @@ ], ], ], + */ 'sanctum' => [ // Unique name of security 'type' => 'apiKey', // Valid values are "basic", "apiKey" or "oauth2". 'description' => 'Enter token in format (Bearer )', 'name' => 'Authorization', // The name of the header or query parameter to be used. 'in' => 'header', // The location of the API key. Valid values are "query" or "header". ], - */ ], 'security' => [ /* diff --git a/storage/api-docs/api-docs.json b/storage/api-docs/api-docs.json index 282eea8..7a2f50c 100644 --- a/storage/api-docs/api-docs.json +++ b/storage/api-docs/api-docs.json @@ -18,15 +18,6 @@ } ], "paths": { - "/projects": { - "get": { - "responses": { - "200": { - "description": "Display a listing of projects." - } - } - } - }, "/users/login": { "post": { "tags": [ @@ -72,6 +63,39 @@ } } } + }, + "/users": { + "get": { + "tags": [ + "Users" + ], + "summary": "Get list of users", + "description": "Returns list of users", + "operationId": "getUserList", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserResource" + } + } + } + }, + "401": { + "description": "Unauthenticated" + }, + "403": { + "description": "Forbidden" + } + }, + "security": [ + { + "sanctum": [] + } + ] + } } }, "components": { @@ -153,6 +177,13 @@ } }, "type": "object" + }, + "UserResource": { + "title": "UserResource", + "description": "User resource", + "xml": { + "name": "UserResource" + } } }, "parameters": { @@ -210,6 +241,14 @@ } } } + }, + "securitySchemes": { + "sanctum": { + "type": "apiKey", + "description": "Enter token in format (Bearer )", + "name": "Authorization", + "in": "header" + } } }, "security": [ From 8bbaa32a9ac9ac069b6b09dbf95525d553ffa88a Mon Sep 17 00:00:00 2001 From: hiren Date: Fri, 26 Aug 2022 15:43:20 +0530 Subject: [PATCH 12/13] uncommented middleware for get users --- app/Http/Controllers/UserController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 5b21694..8c76dad 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -15,7 +15,7 @@ class UserController extends Controller { public function __construct() { - //$this->middleware('acl:list:users')->only(['index']); + $this->middleware('acl:list:users')->only(['index']); $this->middleware('acl:create:user')->only(['store']); $this->middleware('acl:view:user')->only(['show']); $this->middleware('acl:update:user')->only(['update']); From b3f8ec5ac6c00127f05389f21aeda028ab1fa0b6 Mon Sep 17 00:00:00 2001 From: hiren Date: Fri, 26 Aug 2022 16:32:52 +0530 Subject: [PATCH 13/13] WIP:User Create API Open API 3.0 --- app/api.php | 67 ++++++++++++++++++++++++++++++++ storage/api-docs/api-docs.json | 71 ++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/app/api.php b/app/api.php index 4527945..3e7c8eb 100644 --- a/app/api.php +++ b/app/api.php @@ -95,4 +95,71 @@ * description="Forbidden" * ) * ) + */ + +/** + * @OA\Post( + * path="/users", + * operationId="storeUser", + * tags={"Users"}, + * summary="Store new user", + * description="Returns user data", + * @OA\Parameter( + * name="name", + * in="query", + * required=true, + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Parameter( + * name="email", + * in="query", + * required=true, + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Parameter( + * name="mobile_number", + * in="query", + * required=true, + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\Parameter( + * name="password", + * in="query", + * required=true, + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Parameter( + * name="password_confirmation", + * in="query", + * required=true, + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Response( + * response=201, + * description="Successful operation", + * @OA\JsonContent(ref="#/components/schemas/UserResource") + * ), + * @OA\Response( + * response=400, + * description="Bad Request" + * ), + * @OA\Response( + * response=401, + * description="Unauthenticated", + * ), + * @OA\Response( + * response=403, + * description="Forbidden" + * ) + * ) */ \ No newline at end of file diff --git a/storage/api-docs/api-docs.json b/storage/api-docs/api-docs.json index 7a2f50c..b57788c 100644 --- a/storage/api-docs/api-docs.json +++ b/storage/api-docs/api-docs.json @@ -95,6 +95,77 @@ "sanctum": [] } ] + }, + "post": { + "tags": [ + "Users" + ], + "summary": "Store new user", + "description": "Returns user data", + "operationId": "storeUser", + "parameters": [ + { + "name": "name", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "email", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "mobile_number", + "in": "query", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "password", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "password_confirmation", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserResource" + } + } + } + }, + "400": { + "description": "Bad Request" + }, + "401": { + "description": "Unauthenticated" + }, + "403": { + "description": "Forbidden" + } + } } } },