diff --git a/.env.example b/.env.example index 0eceae8..722e251 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -APP_NAME=Laravel +APP_NAME="Holos" APP_ENV=local APP_KEY= APP_DEBUG=true diff --git a/app/Events/GlobalNotification.php b/app/Events/GlobalNotification.php index 68f9297..ad952af 100644 --- a/app/Events/GlobalNotification.php +++ b/app/Events/GlobalNotification.php @@ -4,10 +4,9 @@ */ use Illuminate\Broadcasting\Channel; -use Illuminate\Broadcasting\InteractsWithBroadcasting; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PrivateChannel; -use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow; +use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; @@ -20,10 +19,9 @@ * * @version 1.0.0 */ -class GlobalNotification implements ShouldBroadcastNow +class GlobalNotification implements ShouldBroadcast { use Dispatchable, - InteractsWithBroadcasting, InteractsWithSockets, SerializesModels; diff --git a/app/Events/UpdateRoleUser.php b/app/Events/UpdateRoleUser.php new file mode 100644 index 0000000..e27ce7e --- /dev/null +++ b/app/Events/UpdateRoleUser.php @@ -0,0 +1,44 @@ + + * + * @version 1.0.0 + */ +class UpdateRoleUser implements ShouldBroadcast +{ + use Dispatchable, + InteractsWithSockets, + SerializesModels; + + /** + * Crear instancia del evento + */ + public function __construct( + public Role $role + ) {} + + /** + * Obtener los canales a los que se debe transmitir el evento + * + * @return array + */ + public function broadcastOn(): array + { + return [ + new PrivateChannel("App.Models.Role.{$this->role->id}"), + ]; + } +} diff --git a/app/Http/Controllers/Admin/PermissionTypeController.php b/app/Http/Controllers/Admin/PermissionTypeController.php new file mode 100644 index 0000000..ee28935 --- /dev/null +++ b/app/Http/Controllers/Admin/PermissionTypeController.php @@ -0,0 +1,38 @@ + + * + * @version 1.0.0 + */ +class PermissionTypeController extends Controller +{ + /** + * Listar todo + */ + public function all() + { + return ApiResponse::OK->response([ + 'models' => PermissionType::orderBy('name')->get() + ]); + } + + /** + * Listar todo con permisos + */ + public function allWithPermissions() + { + return ApiResponse::OK->response([ + 'models' => PermissionType::with('permissions')->orderBy('name')->get() + ]); + } +} diff --git a/app/Http/Controllers/Admin/RoleController.php b/app/Http/Controllers/Admin/RoleController.php new file mode 100644 index 0000000..f05b0fe --- /dev/null +++ b/app/Http/Controllers/Admin/RoleController.php @@ -0,0 +1,100 @@ + + * + * @version 1.0.0 + */ +class RoleController extends Controller +{ + /** + * Listar + */ + public function index() + { + $model = Role::orderBy('description'); + + QuerySupport::queryByKey($model, request(), 'name'); + + return ApiResponse::OK->response([ + 'models' => $model + ->paginate(config('app.pagination')) + ]); + } + + /** + * Almacenar + */ + public function store(RoleStoreRequest $request) + { + Role::create($request->all()); + + return ApiResponse::OK->response(); + } + + /** + * Mostrar + */ + public function show(Role $role) + { + return ApiResponse::OK->response([ + 'model' => $role + ]); + } + + /** + * Actualizar + */ + public function update(RoleUpdateRequest $request, Role $role) + { + $role->update($request->all()); + + return ApiResponse::OK->response(); + } + + /** + * Eliminar + */ + public function destroy(Role $role) + { + $role->delete(); + + return ApiResponse::OK->response(); + } + + /** + * Permisos + */ + public function permissions(Role $role) + { + return ApiResponse::OK->response([ + 'permissions' => $role->permissions + ]); + } + + /** + * Actualizar permisos + */ + public function updatePermissions(Role $role, Request $request) + { + $role->syncPermissions($request->get('permissions', [])); + + UpdateRoleUser::dispatch($role); + + return ApiResponse::OK->response(); + } +} diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/Admin/UserController.php similarity index 98% rename from app/Http/Controllers/UserController.php rename to app/Http/Controllers/Admin/UserController.php index 00d8dc7..8ba7ef7 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -1,4 +1,4 @@ - + * + * @version 1.0.0 + */ +class ServerController extends Controller +{ + /** + * Estado del servidor + */ + public function status() + { + return ApiResponse::OK->response([ + "status" => "ok" + ]); + } + + /** + * Versión + */ + public function version() + { + return ApiResponse::OK->response([ + "version" => config('app.version') + ]); + } + + /** + * Login requerido + */ + public function loginRequired() + { + return ApiResponse::OK->response([ + "message" => __('login.required') + ]); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/System/LoginController.php b/app/Http/Controllers/System/LoginController.php index d8c05fa..aa3928e 100644 --- a/app/Http/Controllers/System/LoginController.php +++ b/app/Http/Controllers/System/LoginController.php @@ -8,7 +8,6 @@ use App\Http\Requests\User\ForgotRequest; use App\Models\User; use App\Notifications\ForgotPasswordNotification; -use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Log; use Notsoweb\ApiResponse\Enums\ApiResponse; @@ -26,16 +25,20 @@ class LoginController extends Controller */ public function login(LoginRequest $request) { - return (Auth::attempt($request->all())) - ? ApiResponse::OK->onSuccess([ - 'user' => auth()->user(), - 'token' => auth()->user() - ->createToken('golscore') - ->accessToken, - ]) - : ApiResponse::UNPROCESSABLE_CONTENT->response([ + $user = User::where('email', $request->get('email'))->first(); + + if (!$user || !$user->validateForPassportPasswordGrant($request->get('password'))) { + return ApiResponse::UNPROCESSABLE_CONTENT->response([ 'email' => ['Usuario no valido'] ]); + } + + return ApiResponse::OK->onSuccess([ + 'user' => $user, + 'token' => $user + ->createToken('golscore') + ->accessToken, + ]); } /** diff --git a/app/Http/Requests/Roles/RoleStoreRequest.php b/app/Http/Requests/Roles/RoleStoreRequest.php new file mode 100644 index 0000000..42fe05f --- /dev/null +++ b/app/Http/Requests/Roles/RoleStoreRequest.php @@ -0,0 +1,46 @@ + + * + * @version 1.0.0 + */ +class RoleStoreRequest extends FormRequest +{ + /** + * Determinar si el usuario está autorizado para realizar esta solicitud + */ + public function authorize(): bool + { + return auth()->user()->hasPermissionTo('roles.create'); + } + + /** + * Obtener las reglas de validación que se aplican a la solicitud + */ + public function rules(): array + { + return [ + 'description' => ['required', 'string', Rule::unique('roles')], + ]; + } + + /** + * Después de la validación + */ + protected function passedValidation() + { + $this->merge([ + 'name' => Str::slug($this->description), + ]); + } +} diff --git a/app/Http/Requests/Roles/RoleUpdateRequest.php b/app/Http/Requests/Roles/RoleUpdateRequest.php new file mode 100644 index 0000000..c4f9bf3 --- /dev/null +++ b/app/Http/Requests/Roles/RoleUpdateRequest.php @@ -0,0 +1,46 @@ + + * + * @version 1.0.0 + */ +class RoleUpdateRequest extends FormRequest +{ + /** + * Determinar si el usuario está autorizado para realizar esta solicitud + */ + public function authorize(): bool + { + return auth()->user()->hasPermissionTo('roles.edit'); + } + + /** + * Obtener las reglas de validación que se aplican a la solicitud + */ + public function rules(): array + { + return [ + 'description' => ['required', 'string', Rule::unique('roles')->ignore($this->route('role'))], + ]; + } + + /** + * Después de la validación + */ + protected function passedValidation() + { + $this->merge([ + 'name' => Str::slug($this->description), + ]); + } +} diff --git a/app/Http/Requests/Users/UserStoreRequest.php b/app/Http/Requests/Users/UserStoreRequest.php index 0e9ccfc..50b309f 100644 --- a/app/Http/Requests/Users/UserStoreRequest.php +++ b/app/Http/Requests/Users/UserStoreRequest.php @@ -19,7 +19,7 @@ class UserStoreRequest extends FormRequest */ public function authorize(): bool { - return true; + return auth()->user()->hasPermissionTo('users.create'); } /** diff --git a/app/Http/Requests/Users/UserUpdateRequest.php b/app/Http/Requests/Users/UserUpdateRequest.php index 2664736..5a996ba 100644 --- a/app/Http/Requests/Users/UserUpdateRequest.php +++ b/app/Http/Requests/Users/UserUpdateRequest.php @@ -20,7 +20,7 @@ class UserUpdateRequest extends FormRequest */ public function authorize(): bool { - return true; + return auth()->user()->hasPermissionTo('users.edit'); } /** diff --git a/app/Http/Traits/HasDatabaseNotifications.php b/app/Http/Traits/HasDatabaseNotifications.php index 7aeeb73..a3e1566 100644 --- a/app/Http/Traits/HasDatabaseNotifications.php +++ b/app/Http/Traits/HasDatabaseNotifications.php @@ -1,4 +1,7 @@ + * + * @version 1.0.0 */ trait HasDatabaseNotifications { diff --git a/app/Http/Traits/IsNotifiable.php b/app/Http/Traits/IsNotifiable.php index 066e436..ba832d4 100644 --- a/app/Http/Traits/IsNotifiable.php +++ b/app/Http/Traits/IsNotifiable.php @@ -1,4 +1,7 @@ + * + * @version 1.0.0 */ trait IsNotifiable { diff --git a/app/Models/Notification.php b/app/Models/Notification.php index 1382a39..c854d11 100644 --- a/app/Models/Notification.php +++ b/app/Models/Notification.php @@ -1,4 +1,7 @@ + * + * @version 1.0.0 */ class Notification extends Model { diff --git a/app/Models/PermissionType.php b/app/Models/PermissionType.php index df1ddb3..c5ecd0d 100644 --- a/app/Models/PermissionType.php +++ b/app/Models/PermissionType.php @@ -4,6 +4,7 @@ */ use Illuminate\Database\Eloquent\Model; +use Spatie\Permission\Models\Permission; /** * Tipos de permisos @@ -21,4 +22,12 @@ class PermissionType extends Model 'name', 'description' ]; + + /** + * Un tipo de permiso tiene muchos permisos + */ + public function permissions() + { + return $this->hasMany(Permission::class); + } } diff --git a/app/Models/User.php b/app/Models/User.php index e05a8be..84dfd06 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -9,6 +9,7 @@ use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; +use Illuminate\Support\Facades\Hash; use Laravel\Passport\HasApiTokens; use Spatie\Permission\Traits\HasRoles; @@ -87,4 +88,12 @@ public function lastName(): Attribute get: fn () => $this->paternal . ' ' . $this->maternal, ); } + + /** + * Validar la contraseña + */ + public function validateForPassportPasswordGrant(string $password): bool + { + return Hash::check($password, $this->password); + } } diff --git a/app/Notifications/ForgotPasswordNotification.php b/app/Notifications/ForgotPasswordNotification.php index 8829da6..b1c7902 100644 --- a/app/Notifications/ForgotPasswordNotification.php +++ b/app/Notifications/ForgotPasswordNotification.php @@ -4,7 +4,6 @@ */ use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Notification; diff --git a/bootstrap/app.php b/bootstrap/app.php index db21a73..4e0b009 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -3,6 +3,11 @@ use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\Middleware; +use Illuminate\Http\Request; +use Illuminate\Validation\UnauthorizedException; +use Illuminate\Validation\ValidationException; +use Notsoweb\ApiResponse\Enums\ApiResponse; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; return Application::configure(basePath: dirname(__DIR__)) ->withRouting( @@ -27,5 +32,21 @@ ]); }) ->withExceptions(function (Exceptions $exceptions) { - // + $exceptions->render(function (NotFoundHttpException $e, Request $request) { + if ($request->is('api/*')) { + return ApiResponse::NOT_FOUND->response(); + } + }); + + $exceptions->render(function (UnauthorizedException $e, Request $request) { + if ($request->is('api/*')) { + return ApiResponse::UNAUTHORIZED->response(); + } + }); + + $exceptions->render(function (ValidationException $e, Request $request) { + if ($request->is('api/*')) { + return ApiResponse::UNPROCESSABLE_CONTENT->response($e->errors()); + } + }); })->create(); diff --git a/composer.lock b/composer.lock index c3bc01a..7ea75f4 100644 --- a/composer.lock +++ b/composer.lock @@ -698,16 +698,16 @@ }, { "name": "egulias/email-validator", - "version": "4.0.2", + "version": "4.0.3", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e" + "reference": "b115554301161fa21467629f1e1391c1936de517" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e", - "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b115554301161fa21467629f1e1391c1936de517", + "reference": "b115554301161fa21467629f1e1391c1936de517", "shasum": "" }, "require": { @@ -753,7 +753,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/4.0.2" + "source": "https://github.com/egulias/EmailValidator/tree/4.0.3" }, "funding": [ { @@ -761,7 +761,7 @@ "type": "github" } ], - "time": "2023-10-06T06:47:41+00:00" + "time": "2024-12-27T00:36:43+00:00" }, { "name": "evenement/evenement", @@ -1419,16 +1419,16 @@ }, { "name": "laravel/framework", - "version": "v11.35.1", + "version": "v11.36.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "dcfa130ede1a6fa4343dc113410963e791ad34fb" + "reference": "df06f5163f4550641fdf349ebc04916a61135a64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/dcfa130ede1a6fa4343dc113410963e791ad34fb", - "reference": "dcfa130ede1a6fa4343dc113410963e791ad34fb", + "url": "https://api.github.com/repos/laravel/framework/zipball/df06f5163f4550641fdf349ebc04916a61135a64", + "reference": "df06f5163f4550641fdf349ebc04916a61135a64", "shasum": "" }, "require": { @@ -1449,7 +1449,7 @@ "guzzlehttp/uri-template": "^1.0", "laravel/prompts": "^0.1.18|^0.2.0|^0.3.0", "laravel/serializable-closure": "^1.3|^2.0", - "league/commonmark": "^2.2.1", + "league/commonmark": "^2.6", "league/flysystem": "^3.25.1", "league/flysystem-local": "^3.25.1", "league/uri": "^7.5.1", @@ -1464,7 +1464,7 @@ "symfony/console": "^7.0.3", "symfony/error-handler": "^7.0.3", "symfony/finder": "^7.0.3", - "symfony/http-foundation": "^7.0.3", + "symfony/http-foundation": "^7.2.0", "symfony/http-kernel": "^7.0.3", "symfony/mailer": "^7.0.3", "symfony/mime": "^7.0.3", @@ -1630,7 +1630,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-12-12T18:25:58+00:00" + "time": "2024-12-17T22:32:08+00:00" }, { "name": "laravel/passport", @@ -1769,16 +1769,16 @@ }, { "name": "laravel/pulse", - "version": "v1.3.1", + "version": "v1.3.2", "source": { "type": "git", "url": "https://github.com/laravel/pulse.git", - "reference": "d1a5bf2eca36c6e3bedb4ceecd45df7d002a1ebc" + "reference": "f0bf3959faa89c05fa211632b6d2665131b017fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pulse/zipball/d1a5bf2eca36c6e3bedb4ceecd45df7d002a1ebc", - "reference": "d1a5bf2eca36c6e3bedb4ceecd45df7d002a1ebc", + "url": "https://api.github.com/repos/laravel/pulse/zipball/f0bf3959faa89c05fa211632b6d2665131b017fc", + "reference": "f0bf3959faa89c05fa211632b6d2665131b017fc", "shasum": "" }, "require": { @@ -1852,7 +1852,7 @@ "issues": "https://github.com/laravel/pulse/issues", "source": "https://github.com/laravel/pulse" }, - "time": "2024-12-11T22:59:06+00:00" + "time": "2024-12-12T18:17:53+00:00" }, { "name": "laravel/reverb", @@ -1938,16 +1938,16 @@ }, { "name": "laravel/serializable-closure", - "version": "v2.0.0", + "version": "v2.0.1", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "0d8d3d8086984996df86596a86dea60398093a81" + "reference": "613b2d4998f85564d40497e05e89cb6d9bd1cbe8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/0d8d3d8086984996df86596a86dea60398093a81", - "reference": "0d8d3d8086984996df86596a86dea60398093a81", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/613b2d4998f85564d40497e05e89cb6d9bd1cbe8", + "reference": "613b2d4998f85564d40497e05e89cb6d9bd1cbe8", "shasum": "" }, "require": { @@ -1995,7 +1995,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2024-11-19T01:38:44+00:00" + "time": "2024-12-16T15:26:28+00:00" }, { "name": "laravel/tinker", @@ -2633,16 +2633,16 @@ }, { "name": "league/oauth2-server", - "version": "8.5.4", + "version": "8.5.5", "source": { "type": "git", "url": "https://github.com/thephpleague/oauth2-server.git", - "reference": "ab7714d073844497fd222d5d0a217629089936bc" + "reference": "cc8778350f905667e796b3c2364a9d3bd7a73518" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/ab7714d073844497fd222d5d0a217629089936bc", - "reference": "ab7714d073844497fd222d5d0a217629089936bc", + "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/cc8778350f905667e796b3c2364a9d3bd7a73518", + "reference": "cc8778350f905667e796b3c2364a9d3bd7a73518", "shasum": "" }, "require": { @@ -2709,7 +2709,7 @@ ], "support": { "issues": "https://github.com/thephpleague/oauth2-server/issues", - "source": "https://github.com/thephpleague/oauth2-server/tree/8.5.4" + "source": "https://github.com/thephpleague/oauth2-server/tree/8.5.5" }, "funding": [ { @@ -2717,7 +2717,7 @@ "type": "github" } ], - "time": "2023-08-25T22:35:12+00:00" + "time": "2024-12-20T23:06:10+00:00" }, { "name": "league/uri", @@ -2895,16 +2895,16 @@ }, { "name": "livewire/livewire", - "version": "v3.5.17", + "version": "v3.5.18", "source": { "type": "git", "url": "https://github.com/livewire/livewire.git", - "reference": "7bbf80d93db9b866776bf957ca6229364bca8d87" + "reference": "62f0fa6b340a467c25baa590a567d9a134b357da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/livewire/livewire/zipball/7bbf80d93db9b866776bf957ca6229364bca8d87", - "reference": "7bbf80d93db9b866776bf957ca6229364bca8d87", + "url": "https://api.github.com/repos/livewire/livewire/zipball/62f0fa6b340a467c25baa590a567d9a134b357da", + "reference": "62f0fa6b340a467c25baa590a567d9a134b357da", "shasum": "" }, "require": { @@ -2959,7 +2959,7 @@ "description": "A front-end framework for Laravel.", "support": { "issues": "https://github.com/livewire/livewire/issues", - "source": "https://github.com/livewire/livewire/tree/v3.5.17" + "source": "https://github.com/livewire/livewire/tree/v3.5.18" }, "funding": [ { @@ -2967,7 +2967,7 @@ "type": "github" } ], - "time": "2024-12-06T13:41:21+00:00" + "time": "2024-12-23T15:05:02+00:00" }, { "name": "monolog/monolog", @@ -3074,16 +3074,16 @@ }, { "name": "nesbot/carbon", - "version": "3.8.2", + "version": "3.8.4", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "e1268cdbc486d97ce23fef2c666dc3c6b6de9947" + "reference": "129700ed449b1f02d70272d2ac802357c8c30c58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/e1268cdbc486d97ce23fef2c666dc3c6b6de9947", - "reference": "e1268cdbc486d97ce23fef2c666dc3c6b6de9947", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/129700ed449b1f02d70272d2ac802357c8c30c58", + "reference": "129700ed449b1f02d70272d2ac802357c8c30c58", "shasum": "" }, "require": { @@ -3115,10 +3115,6 @@ ], "type": "library", "extra": { - "branch-alias": { - "dev-master": "3.x-dev", - "dev-2.x": "2.x-dev" - }, "laravel": { "providers": [ "Carbon\\Laravel\\ServiceProvider" @@ -3128,6 +3124,10 @@ "includes": [ "extension.neon" ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-master": "3.x-dev" } }, "autoload": { @@ -3176,7 +3176,7 @@ "type": "tidelift" } ], - "time": "2024-11-07T17:46:48+00:00" + "time": "2024-12-27T09:25:35+00:00" }, { "name": "nette/schema", @@ -3430,12 +3430,12 @@ "source": { "type": "git", "url": "https://github.com/notsoweb/laravel-core.git", - "reference": "c2c9413dd2be426fef44e38d1fef7d7386c18831" + "reference": "97eac719b383e9e995827b8eeb17d325ded66b7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/notsoweb/laravel-core/zipball/c2c9413dd2be426fef44e38d1fef7d7386c18831", - "reference": "c2c9413dd2be426fef44e38d1fef7d7386c18831", + "url": "https://api.github.com/repos/notsoweb/laravel-core/zipball/97eac719b383e9e995827b8eeb17d325ded66b7e", + "reference": "97eac719b383e9e995827b8eeb17d325ded66b7e", "shasum": "" }, "require": { @@ -3467,7 +3467,7 @@ "issues": "https://github.com/notsoweb/laravel-core/issues", "source": "https://github.com/notsoweb/laravel-core/tree/main" }, - "time": "2024-12-14T16:38:46+00:00" + "time": "2024-12-20T18:15:03+00:00" }, { "name": "nunomaduro/termwind", @@ -3919,16 +3919,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.42", + "version": "3.0.43", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "db92f1b1987b12b13f248fe76c3a52cadb67bb98" + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/db92f1b1987b12b13f248fe76c3a52cadb67bb98", - "reference": "db92f1b1987b12b13f248fe76c3a52cadb67bb98", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/709ec107af3cb2f385b9617be72af8cf62441d02", + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02", "shasum": "" }, "require": { @@ -4009,7 +4009,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.42" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.43" }, "funding": [ { @@ -4025,7 +4025,7 @@ "type": "tidelift" } ], - "time": "2024-09-16T03:06:04+00:00" + "time": "2024-12-14T21:12:59+00:00" }, { "name": "psr/clock", @@ -5725,12 +5725,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -5948,12 +5948,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -7309,12 +7309,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -7569,12 +7569,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -7857,31 +7857,33 @@ }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "v2.2.7", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "83ee6f38df0a63106a9e4536e3060458b74ccedb" + "reference": "0d72ac1c00084279c1816675284073c5a337c20d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/83ee6f38df0a63106a9e4536e3060458b74ccedb", - "reference": "83ee6f38df0a63106a9e4536e3060458b74ccedb", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d", + "reference": "0d72ac1c00084279c1816675284073c5a337c20d", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", - "php": "^5.5 || ^7.0 || ^8.0", - "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0" + "php": "^7.4 || ^8.0", + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5 || ^8.5.21 || ^9.5.10" + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5.10" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { @@ -7904,9 +7906,9 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "support": { "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.2.7" + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0" }, - "time": "2023-12-08T13:03:43+00:00" + "time": "2024-12-21T16:25:41+00:00" }, { "name": "vlucas/phpdotenv", @@ -9270,16 +9272,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.1", + "version": "11.5.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "2b94d4f2450b9869fa64a46fd8a6a41997aef56a" + "reference": "153d0531b9f7e883c5053160cad6dd5ac28140b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2b94d4f2450b9869fa64a46fd8a6a41997aef56a", - "reference": "2b94d4f2450b9869fa64a46fd8a6a41997aef56a", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/153d0531b9f7e883c5053160cad6dd5ac28140b3", + "reference": "153d0531b9f7e883c5053160cad6dd5ac28140b3", "shasum": "" }, "require": { @@ -9293,13 +9295,13 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.7", + "phpunit/php-code-coverage": "^11.0.8", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-invoker": "^5.0.1", "phpunit/php-text-template": "^4.0.1", "phpunit/php-timer": "^7.0.1", "sebastian/cli-parser": "^3.0.2", - "sebastian/code-unit": "^3.0.1", + "sebastian/code-unit": "^3.0.2", "sebastian/comparator": "^6.2.1", "sebastian/diff": "^6.0.2", "sebastian/environment": "^7.2.0", @@ -9351,7 +9353,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.1" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.2" }, "funding": [ { @@ -9367,7 +9369,7 @@ "type": "tidelift" } ], - "time": "2024-12-11T10:52:48+00:00" + "time": "2024-12-21T05:51:08+00:00" }, { "name": "sebastian/cli-parser", diff --git a/config/app.php b/config/app.php index 7f22fe4..ceb2972 100644 --- a/config/app.php +++ b/config/app.php @@ -12,7 +12,7 @@ | other UI elements where an application name needs to be displayed. | */ - 'version' => '0.0.1', + 'version' => '0.9.4', 'name' => env('APP_NAME', 'Laravel'), diff --git a/config/auth.php b/config/auth.php index fc8cd4a..46786ab 100644 --- a/config/auth.php +++ b/config/auth.php @@ -14,7 +14,7 @@ */ 'defaults' => [ - 'guard' => env('AUTH_GUARD', 'web'), + 'guard' => env('AUTH_GUARD', 'api'), 'passwords' => env('AUTH_PASSWORD_BROKER', 'users'), ], diff --git a/config/logging.php b/config/logging.php index 1baaa61..9f3dde0 100644 --- a/config/logging.php +++ b/config/logging.php @@ -130,5 +130,10 @@ 'driver' => 'single', 'path' => storage_path('logs/mail.log'), ], + + 'debug' => [ + 'driver' => 'single', + 'path' => storage_path('logs/debug.log'), + ], ], ]; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 5dda26a..68b5f29 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -1,11 +1,17 @@ - + * + * @version 1.0.0 + */ class DatabaseSeeder extends Seeder { /** diff --git a/database/seeders/DevSeeder.php b/database/seeders/DevSeeder.php index 66ceb05..b8a35ef 100644 --- a/database/seeders/DevSeeder.php +++ b/database/seeders/DevSeeder.php @@ -1,7 +1,17 @@ + * + * @version 1.0.0 + */ class DevSeeder extends Seeder { /** diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php index 2a5b577..597ccf2 100644 --- a/database/seeders/RoleSeeder.php +++ b/database/seeders/RoleSeeder.php @@ -1,4 +1,7 @@ + * + * @version 1.0.0 + */ class RoleSeeder extends Seeder { use RolePermission; @@ -24,28 +34,47 @@ public function run(): void $userCreate, $userEdit, $userDestroy - ] = $this->onCRUD('users', $users); + ] = $this->onCRUD('users', $users, 'api'); - $userSettings = $this->onPermission('users.settings', 'Configuración de usuarios', $users); - $userOnline = $this->onPermission('users.online', 'Usuarios en linea', $users); + $userSettings = $this->onPermission('users.settings', 'Configuración de usuarios', $users, 'api'); + $userOnline = $this->onPermission('users.online', 'Usuarios en linea', $users, 'api'); + + $roles = PermissionType::create([ + 'name' => 'Roles' + ]); + + [ + $roleIndex, + $roleCreate, + $roleEdit, + $roleDestroy + ] = $this->onCRUD('roles', $roles, 'api'); // Desarrollador Role::create([ 'name' => 'developer', - 'description' => 'Desarrollador' + 'description' => 'Desarrollador', + 'guard_name' => 'api' ])->givePermissionTo(Permission::all()); + + // Administrador Role::create([ 'name' => 'admin', - 'description' => 'Administrador' + 'description' => 'Administrador', + 'guard_name' => 'api' ])->givePermissionTo( $userIndex, $userCreate, $userEdit, $userDestroy, $userSettings, - $userOnline + $userOnline, + $roleIndex, + $roleCreate, + $roleEdit, + $roleDestroy ); } } diff --git a/database/seeders/SettingSeeder.php b/database/seeders/SettingSeeder.php index 3b6adf1..96a402e 100644 --- a/database/seeders/SettingSeeder.php +++ b/database/seeders/SettingSeeder.php @@ -8,7 +8,7 @@ use Illuminate\Database\Seeder; /** - * Descripción + * Configuraciones del sistema * * @author Moisés Cortés C. * diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php index 274cf68..3b4aedd 100644 --- a/database/seeders/UserSeeder.php +++ b/database/seeders/UserSeeder.php @@ -1,9 +1,19 @@ + * + * @version 1.0.0 + */ class UserSeeder extends Seeder { /** diff --git a/resources/css/app.css b/resources/css/app.css deleted file mode 100644 index b5c61c9..0000000 --- a/resources/css/app.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/resources/js/app.js b/resources/js/app.js deleted file mode 100644 index e59d6a0..0000000 --- a/resources/js/app.js +++ /dev/null @@ -1 +0,0 @@ -import './bootstrap'; diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js deleted file mode 100644 index deb2e10..0000000 --- a/resources/js/bootstrap.js +++ /dev/null @@ -1,12 +0,0 @@ -import axios from 'axios'; -window.axios = axios; - -window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; - -/** - * Echo exposes an expressive API for subscribing to channels and listening - * for events that are broadcast by Laravel. Echo and event broadcasting - * allow your team to quickly build robust real-time web applications. - */ - -import './echo'; diff --git a/resources/js/echo.js b/resources/js/echo.js deleted file mode 100644 index 9349afa..0000000 --- a/resources/js/echo.js +++ /dev/null @@ -1,14 +0,0 @@ -import Echo from 'laravel-echo'; - -import Pusher from 'pusher-js'; -window.Pusher = Pusher; - -window.Echo = new Echo({ - broadcaster: 'reverb', - key: import.meta.env.VITE_REVERB_APP_KEY, - wsHost: import.meta.env.VITE_REVERB_HOST, - wsPort: import.meta.env.VITE_REVERB_PORT ?? 80, - wssPort: import.meta.env.VITE_REVERB_PORT ?? 443, - forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https', - enabledTransports: ['ws', 'wss'], -}); diff --git a/routes/api.php b/routes/api.php index cd0dc30..bcef25f 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,19 +1,17 @@ response([ - "message" => "It's fine :D" - ]); -}); +Route::get('/', [ServerController::class, 'status'])->name('status'); Route::middleware('auth:api')->group(function () { // Aplicación @@ -38,6 +36,16 @@ }); Route::apiResource('users', UserController::class); + // Roles + Route::apiResource('roles', RoleController::class); + Route::get('roles/{role}/permissions', [RoleController::class, 'permissions'])->name('roles.permissions'); + Route::put('roles/{role}/permissions', [RoleController::class, 'updatePermissions'])->name('roles.permissions.update'); + + Route::prefix('permission-types')->name('permission-types.')->group(function() { + Route::get('all', [PermissionTypeController::class, 'all'])->name('all'); + Route::get('all-with-permissions', [PermissionTypeController::class, 'allWithPermissions'])->name('all-with-permissions'); + }); + // Sistema Route::prefix('system')->name('system.')->group(function() { Route::get('permissions', [SystemController::class, 'permissions'])->name('permissions'); @@ -63,4 +71,3 @@ Route::post('forgot-password', [LoginController::class, 'forgotPassword'])->name('forgot-password'); Route::post('reset-password', [LoginController::class, 'resetPassword'])->name('reset-password'); }); - diff --git a/routes/channels.php b/routes/channels.php index 2e379e9..01311c5 100644 --- a/routes/channels.php +++ b/routes/channels.php @@ -7,6 +7,10 @@ return (int) $user->id === (int) $id; }); +Broadcast::channel('App.Models.Role.{id}', function ($user, $id) { + return $user->hasRole(intval($id)); +}); + // Usuarios en linea Broadcast::channel('online', function ($user) { return $user; diff --git a/routes/web.php b/routes/web.php index 5213f27..f05d4e4 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,22 +1,8 @@ response([ - "message" => "It's fine :D" - ]); -}); - -Route::get('/version', function () { - return ApiResponse::OK->response([ - "version" => config('app.version') - ]); -}); - -Route::get('/login', function () { - return ApiResponse::OK->response([ - "message" => __('login.required') - ]); -})->name('login'); \ No newline at end of file +Route::get('/', [ServerController::class, 'status']); +Route::get('/version', [ServerController::class, 'version']); +Route::get('/login', [ServerController::class, 'loginRequired'])->name('login'); \ No newline at end of file diff --git a/storage/app/images/.gitignore b/storage/app/images/.gitignore index d6b7ef3..c96a04f 100755 --- a/storage/app/images/.gitignore +++ b/storage/app/images/.gitignore @@ -1,2 +1,2 @@ * -!.gitignore +!.gitignore \ No newline at end of file