feat: Autorização implementada em todos os controladores.

This commit is contained in:
lukibeg 2025-11-27 20:35:44 -03:00
parent 578e26f5da
commit cc52c73f69
9 changed files with 68 additions and 31 deletions

View File

@ -18,9 +18,11 @@ class AddClient extends Component
public function save(ClientService $clientService) public function save(ClientService $clientService)
{ {
$this->form->validate();
try { try {
$this->authorize('addClient', Auth::user());
$this->form->validate();
$data = $this->form->all(); $data = $this->form->all();
$data['name'] = $data['client_name']; $data['name'] = $data['client_name'];
@ -36,7 +38,7 @@ public function save(ClientService $clientService)
$this->dispatch('client-added'); $this->dispatch('client-added');
$this->dispatch('notify', message: $client->name . ' adicionado com sucesso!'); $this->dispatch('notify', message: $client->name . ' adicionado com sucesso!');
} catch (\Exception $e) { } catch (\Exception $e) {
$this->dispatch('notify', message: 'Ocorreu um erro inesperado ao salvar.', type: 'error'); $this->dispatch('notify', message: 'Ocorreu um erro inesperado ao salvar. ' . $e->getMessage(), type: 'error');
} }
} }

View File

@ -5,12 +5,17 @@
use Livewire\Component; use Livewire\Component;
use Livewire\Attributes\On; use Livewire\Attributes\On;
use App\Models\Client; use App\Models\Client;
use Exception;
use Illuminate\Support\Facades\Auth;
class DeleteClient extends Component class DeleteClient extends Component
{ {
#[On('confirm-delete')] #[On('confirm-delete')]
public function deleteClient($payload) public function deleteClient($payload)
{ {
try {
// Sua lógica de autorização e exclusão (Correta)
$this->authorize('deleteClient', Auth::user());
$deletedClient = Client::findOrFail($payload); $deletedClient = Client::findOrFail($payload);
@ -18,8 +23,14 @@ public function deleteClient($payload)
$deletedClient->delete(); $deletedClient->delete();
} }
// Sucesso (Dentro do try, onde deve estar)
$this->dispatch('client-deleted'); $this->dispatch('client-deleted');
$this->dispatch('notify', message: 'Cliente excluído com sucesso!'); $this->dispatch('notify', message: 'Cliente excluído com sucesso!');
} catch (Exception $e) {
// Tratamento de erro
$this->dispatch('notify', message: 'Você não possui permissão para realizar essa ação.', type: 'error');
}
} }
public function render() public function render()

View File

@ -5,6 +5,7 @@
use App\Livewire\Forms\ClientForm; use App\Livewire\Forms\ClientForm;
use App\Models\Client; use App\Models\Client;
use App\Services\ClientService; use App\Services\ClientService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\Crypt;
use Livewire\Attributes\On; use Livewire\Attributes\On;
use Livewire\Component; use Livewire\Component;
@ -18,7 +19,6 @@ class EditClient extends Component
public Client $client; public Client $client;
public ClientForm $clientForm; public ClientForm $clientForm;
// public ClientService $clientService;
#[On('update-client')] #[On('update-client')]
public function loadClient($id) public function loadClient($id)
@ -35,6 +35,10 @@ public function loadClient($id)
} }
public function edit(ClientService $clientService) public function edit(ClientService $clientService)
{ {
try {
$this->authorize('editClient', Auth::user());
$data = $this->clientForm->validate(); $data = $this->clientForm->validate();
if ($this->clientForm->profile_image_path) { if ($this->clientForm->profile_image_path) {
@ -44,8 +48,6 @@ public function edit(ClientService $clientService)
$data['root_password'] = Crypt::encryptString($data['root_password']); $data['root_password'] = Crypt::encryptString($data['root_password']);
try {
if (!$clientService->updateClient($this->client, $data)) { if (!$clientService->updateClient($this->client, $data)) {
throw new Exception('O serviço não confirmou a atualização.'); throw new Exception('O serviço não confirmou a atualização.');
} }

View File

@ -34,11 +34,10 @@ class CreateUser extends Component
public function createUser(UserService $userService) public function createUser(UserService $userService)
{ {
try {
$this->authorize('createUser', Auth::user());
$validated = $this->validate($this->rules, $this->messages); $validated = $this->validate($this->rules, $this->messages);
try {
$this->authorize('createUser', Auth::user());
$user = $userService->createUser($validated); $user = $userService->createUser($validated);
@ -49,6 +48,7 @@ public function createUser(UserService $userService)
$this->dispatch('notify', message: 'Usuário cadastrado com sucesso!'); $this->dispatch('notify', message: 'Usuário cadastrado com sucesso!');
} catch (\Exception $e) { } catch (\Exception $e) {
$this->addError('general', $e->getMessage()); $this->addError('general', $e->getMessage());
$this->dispatch('notify', message: 'Ocorreu um erro ao criar o usuário. ' . $e->getMessage(), type: 'error');
} }
} }

View File

@ -6,6 +6,7 @@
use Livewire\Attributes\On; use Livewire\Attributes\On;
use App\Models\User; use App\Models\User;
use App\Services\UserService; use App\Services\UserService;
use Illuminate\Support\Facades\Auth;
use Exception; use Exception;
class DeleteUser extends Component class DeleteUser extends Component
@ -14,9 +15,11 @@ class DeleteUser extends Component
#[On('confirm-delete-user')] #[On('confirm-delete-user')]
public function deleteUser(UserService $userService, $payload) public function deleteUser(UserService $userService, $payload)
{ {
try {
$this->authorize('deleteUser', Auth::user());
$deletedUser = User::findOrFail($payload); $deletedUser = User::findOrFail($payload);
try {
if ($deletedUser) { if ($deletedUser) {
$deletedUser = $userService->deleteUser($deletedUser); $deletedUser = $userService->deleteUser($deletedUser);
} }
@ -25,7 +28,7 @@ public function deleteUser(UserService $userService, $payload)
$this->dispatch('notify', message: $deletedUser->name . ' Usuário excluído com sucesso!'); $this->dispatch('notify', message: $deletedUser->name . ' Usuário excluído com sucesso!');
} catch (Exception $e) { } catch (Exception $e) {
$this->dispatch('user-delete-error'); $this->dispatch('user-delete-error');
$this->dispatch('notify', message: $e->getMessage()); $this->dispatch('notify', message: $e->getMessage(), type: 'error');
} }
} }

View File

@ -7,6 +7,7 @@
use Livewire\Component; use Livewire\Component;
use Livewire\Attributes\On; use Livewire\Attributes\On;
use App\Services\UserService; use App\Services\UserService;
use Illuminate\Support\Facades\Auth;
class EditUser extends Component class EditUser extends Component
{ {
@ -31,8 +32,11 @@ public function loadUser($id)
} }
public function editUser(UserService $userService) public function editUser(UserService $userService)
{ {
$data = $this->userForm->validate();
try { try {
$this->authorize('editUser', Auth::user());
$data = $this->userForm->validate();
if (!$userService->updateUser($this->user, $data)) { if (!$userService->updateUser($this->user, $data)) {
throw new \Exception('O serviço não confirmou a atualização.'); throw new \Exception('O serviço não confirmou a atualização.');
} }

View File

@ -22,8 +22,21 @@ public function register(): void
*/ */
public function boot(): void public function boot(): void
{ {
Gate::define('createUser', function (User $user) { // Lista de todas as ações que são exclusivas de Admin
return isset($user->permissions) ? in_array('admin', $user->permissions) : false; $adminActions = [
'createUser',
'editUser',
'deleteUser',
'addClient', // Exemplo
'deleteClient', // Exemplo
'editClient',
];
foreach ($adminActions as $action) {
Gate::define($action, function (User $user) {
// A lógica fica centralizada aqui. Se mudar, muda pra todos.
return isset($user->permissions) && in_array('admin', $user->permissions);
}); });
} }
} }
}

View File

@ -13,6 +13,8 @@ class UserService
public function __construct(protected User $user) {} public function __construct(protected User $user) {}
public function createUser(array $user) public function createUser(array $user)
{ {
$permissions = [$user['permissions']];
$user['permissions'] = $permissions;
return User::create($user); return User::create($user);
} }

View File

@ -12,7 +12,7 @@
} }
}" @notify.window="addToast($event.detail.message, $event.detail.type || 'success')" }" @notify.window="addToast($event.detail.message, $event.detail.type || 'success')"
@notifyError.window="addToast($event.detail.message, $event.detail.type || 'error')" @notifyError.window="addToast($event.detail.message, $event.detail.type || 'error')"
class="fixed top-5 right-5 z-50 flex w-full max-w-xs flex-col space-y-3"> class="fixed top-5 right-5 z-50000 flex w-full max-w-xs flex-col space-y-3">
<template x-for="toast in toasts" :key="toast.id"> <template x-for="toast in toasts" :key="toast.id">
<div x-show="true" x-transition:enter="transform ease-out duration-300 transition" <div x-show="true" x-transition:enter="transform ease-out duration-300 transition"
x-transition:enter-start="translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2" x-transition:enter-start="translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2"
@ -35,7 +35,7 @@ class="fixed top-5 right-5 z-50 flex w-full max-w-xs flex-col space-y-3">
<p class="toast-message" x-text="toast.message"></p> <p class="toast-message" x-text="toast.message"></p>
<button @click="removeToast(toast.id)" class="toast-close-button"> <button @click="removeToast(toast.id)" class="toast-close-button cursor-pointer">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"> <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
<path <path
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" /> d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />