añadir funicionalidades de permisos y grupos
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled

This commit is contained in:
2025-04-27 23:43:22 +02:00
parent fa7c92bee2
commit 883daf32ed
51 changed files with 2673 additions and 441 deletions

View File

@@ -2,7 +2,11 @@
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
abstract class Controller
{
//
use AuthorizesRequests, ValidatesRequests; // <-- Traits esenciales
}

View File

@@ -4,6 +4,10 @@ namespace App\Http\Controllers;
use App\Models\Folder;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Validator;
use App\Rules\UniqueFolderName;
use Illuminate\Support\Facades\Gate;
class FolderController extends Controller
{
@@ -50,9 +54,51 @@ class FolderController extends Controller
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Folder $folder)
public function update(Folder $folder, Request $request)
{
//
try {
// Verificar permisos
if (!Gate::allows('update', $folder)) {
return response()->json([
'success' => false,
'message' => 'No tienes permisos para modificar esta carpeta'
], Response::HTTP_FORBIDDEN);
}
// Validación
$validator = Validator::make($request->all(), [
'name' => [
'required',
'max:255',
new UniqueFolderName(
$folder->project_id,
$folder->parent_id
)
]
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], Response::HTTP_UNPROCESSABLE_ENTITY);
}
// Actualizar nombre
$folder->update(['name' => $request->name]);
return response()->json([
'success' => true,
'message' => 'Carpeta actualizada',
'folder' => $folder
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'Error al actualizar carpeta: ' . $e->getMessage()
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
/**
@@ -60,6 +106,91 @@ class FolderController extends Controller
*/
public function destroy(Folder $folder)
{
//
try {
// Verificar permisos
if (!Gate::allows('delete', $folder)) {
return response()->json([
'success' => false,
'message' => 'No tienes permisos para eliminar esta carpeta'
], Response::HTTP_FORBIDDEN);
}
// Validar que esté vacía
if ($folder->documents()->exists() || $folder->children()->exists()) {
return response()->json([
'success' => false,
'message' => 'No puedes eliminar carpetas con contenido'
], Response::HTTP_UNPROCESSABLE_ENTITY);
}
// Eliminar
$folder->delete();
return response()->json([
'success' => true,
'message' => 'Carpeta eliminada'
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'Error al eliminar carpeta: ' . $e->getMessage()
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
/**
* Move the specified folder to a new location.
*/
public function move(Folder $folder, Request $request)
{
try {
// Verificar permisos
if (!Gate::allows('move', $folder)) {
return response()->json([
'success' => false,
'message' => 'No tienes permisos para esta acción'
], Response::HTTP_FORBIDDEN);
}
// Validación
$validator = Validator::make($request->all(), [
'parent_id' => 'nullable|exists:folders,id',
'project_id' => 'required|exists:projects,id'
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'errors' => $validator->errors()
], Response::HTTP_UNPROCESSABLE_ENTITY);
}
// Prevenir movimiento a sí mismo o descendientes
if ($request->parent_id && $folder->isDescendantOf($request->parent_id)) {
return response()->json([
'success' => false,
'message' => 'No puedes mover una carpeta a su propia jerarquía'
], Response::HTTP_UNPROCESSABLE_ENTITY);
}
// Actualizar ubicación
$folder->update([
'parent_id' => $request->parent_id,
'project_id' => $request->project_id
]);
return response()->json([
'success' => true,
'message' => 'Carpeta movida exitosamente',
'folder' => $folder->fresh()
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'Error al mover la carpeta: ' . $e->getMessage()
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Http\Controllers;
use App\Models\Group;
use Illuminate\Http\Request;
class GroupController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(Group $group)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Group $group)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Group $group)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Group $group)
{
//
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use App\Http\Controllers\Controller; // <-- Asegúrate de tener esta línea
use Illuminate\Http\Request;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
@@ -12,24 +13,36 @@ class RoleController extends Controller
public function index()
{
$this->authorize('viewAny', Role::class);
$roles = Role::withCount('users')->paginate(10);
return view('roles.index', compact('roles'));
}
public function create()
{
$this->authorize('create', Role::class);
$permissions = Permission::all()->groupBy('group');
$this->authorize('create roles');
$permissions = Permission::all(['id', 'name']);
return view('roles.create', compact('permissions'));
}
public function store(StoreRoleRequest $request)
public function store(Request $request)
{
$role = Role::create($request->only('name'));
/*$role = Role::create($request->only('name'));
$role->syncPermissions($request->permissions);
return redirect()->route('roles.index')
->with('success', 'Rol creado exitosamente');
->with('success', 'Rol creado exitosamente');*/
$this->authorize('create', Role::class);
$request->validate([
'name' => 'required|unique:roles',
'description' => 'required'
]);
Role::create($request->all());
return redirect()->route('roles.index');
}
public function edit(Role $role)
@@ -41,7 +54,7 @@ class RoleController extends Controller
return view('roles.edit', compact('role', 'permissions', 'rolePermissions'));
}
public function update(StoreRoleRequest $request, Role $role)
public function update(Request $request, Role $role)
{
$role->update($request->only('name'));
$role->syncPermissions($request->permissions);

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class CheckResourcePermissions
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle($request, $next, $permission)
{
$resource = $request->route()->parameter('project')
?? $request->route()->parameter('folder');
if (!$request->user()->hasPermissionToResource($resource, $permission)) {
abort(403);
}
return $next($request);
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace App\Livewire;
use App\Models\Document;
use Livewire\Component;
use Livewire\WithFileUploads;
use App\Models\Project;
use App\Models\Folder;
class FileUpload extends Component
{
use WithFileUploads;
public Project $project;
public Folder|null $folder;
public $files = [];
public $previews = [];
public $maxSize = 50; // MB
public $folderId;
protected $listeners = ['folderChanged' => 'updateFolder'];
public function updateFolder($folderId)
{
$this->folder = Folder::find($folderId);
}
public function updatedFiles()
{
$this->validate([
'files.*' => "max:{$this->maxSize}1024|mimes:pdf,docx,xlsx,jpg,png,svg",
'folderId' => 'required|exists:folders,id'
]);
$this->previews = [];
foreach ($this->files as $file) {
$this->previews[] = [
'name' => $file->getClientOriginalName(),
'type' => $file->getMimeType(),
'size' => $file->getSize(),
'preview' => str_starts_with($file->getMimeType(), 'image/')
? $file->temporaryUrl()
: null
];
Document::create([
'name' => $file->getClientOriginalName(),
'file_path' => $file->store("projects/{$this->folderId}"),
'folder_id' => $this->folderId
]);
}
}
public function save()
{
$this->validate([
'files.*' => "required|max:{$this->maxSize}1024|mimes:pdf,docx,xlsx,jpg,png,svg"
]);
foreach ($this->files as $file) {
$path = $file->store("projects/{$this->project->id}/documents", 'public');
$this->project->documents()->create([
'name' => $file->getClientOriginalName(),
'file_path' => $path,
'folder_id' => $this->folder?->id,
'size' => $file->getSize(),
'type' => $file->getMimeType()
]);
}
$this->reset(['files', 'previews']);
$this->emit('documentsUpdated');
}
public function render()
{
return view('livewire.file-upload');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Livewire;
use Livewire\Component;
class GroupSearch extends Component
{
public function render()
{
return view('livewire.group-search');
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Project;
use App\Models\Folder;
use App\Models\User;
class PermissionManager extends Component
{
public $selectedProject;
public $selectedFolder;
public $assignTo = 'user';
public $selectedPermissions = [];
public $selectedUser;
public $selectedGroup;
protected $listeners = ['userSelected', 'groupSelected'];
public function rules()
{
return [
'selectedProject' => 'required|exists:projects,id',
'selectedFolder' => 'nullable|exists:folders,id',
'selectedPermissions' => 'required|array|min:1',
'selectedUser' => 'required_if:assignTo,user',
'selectedGroup' => 'required_if:assignTo,group',
];
}
public function getSelectedResourceIdProperty()
{
return $this->selectedFolder ?: $this->selectedProject;
}
public function getCanSaveProperty()
{
return $this->selectedProject &&
($this->assignTo === 'group' ? $this->selectedGroup : $this->selectedUser) &&
count($this->selectedPermissions) > 0;
}
public function getProjectsProperty()
{
return Project::accessibleBy(auth()->user())->get();
}
public function getFoldersProperty()
{
if (!$this->selectedProject) return collect();
return Folder::where('project_id', $this->selectedProject)
->withDepth()
->get()
->toTree();
}
public function getPermissionsProperty()
{
$type = $this->selectedFolder ? 'folder' : 'project';
return config("permissions.types.$type", []);
}
public function userSelected($userId)
{
$this->selectedUser = $userId;
}
public function groupSelected($groupId)
{
$this->selectedGroup = $groupId;
}
public function savePermissions()
{
$this->validate();
$model = $this->assignTo === 'user'
? User::find($this->selectedUser)
: Group::find($this->selectedGroup);
$resource = $this->selectedFolder
? Folder::find($this->selectedFolder)
: Project::find($this->selectedProject);
// Asignar permisos usando Spatie
$model->givePermissionTo(
$resource->permissions()->whereIn('name', $this->selectedPermissions)->get()
);
$this->reset(['selectedPermissions']);
$this->dispatch('permissionsUpdated');
session()->flash('message', 'Permisos actualizados correctamente.');
}
public function render()
{
return view('livewire.permission-manager');
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace App\Livewire;
use Livewire\Component;
use Spatie\Permission\Models\Permission;
use App\Models\{User, Group};
class PermissionsList extends Component
{
public $resourceId;
public $resourceType;
public function mount($resourceId)
{
$this->resourceId = $resourceId;
$this->determineResourceType();
}
protected function determineResourceType()
{
if (Project::find($this->resourceId)) {
$this->resourceType = 'project';
} else {
$this->resourceType = 'folder';
}
}
public function getPermissions()
{
return Permission::where('name', 'like', "{$this->resourceType}-{$this->resourceId}-%")
->get()
->groupBy(function ($permission) {
return explode('-', $permission->name)[2]; // Obtener tipo de permiso
});
}
public function revokePermission($permissionId, $modelType, $modelId)
{
$permission = Permission::findOrFail($permissionId);
$model = $modelType === 'user'
? User::find($modelId)
: Group::find($modelId);
$model->revokePermissionTo($permission);
$this->dispatch('permissionsUpdated');
}
public function render()
{
return view('livewire.permissions-list', [
'permissions' => $this->getPermissions(),
'users' => User::withPermissionsForResource($this->resourceId, $this->resourceType)->get(),
'groups' => Group::withPermissionsForResource($this->resourceId, $this->resourceType)->get()
]);
}
}

View File

@@ -3,28 +3,40 @@
namespace App\Livewire;
use Livewire\Component;
use Livewire\Attributes\Title;
use Livewire\WithFileUploads;
use App\Models\Project;
use App\Models\Folder;
use App\Models\Document;
use Illuminate\Validation\Rule;
class ProjectShow extends Component
{
use WithFileUploads;
public Project $project;
public $selectedFolderId = null;
public ?Folder $currentFolder = null;
public $expandedFolders = [];
public $files = [];
public $folderName = '';
public $selectedFolderId = null;
public function mount(Project $project)
{
$this->project = $project->load('rootFolders');
$this->currentFolder = $this->project->rootFolders->first() ?? null;
}
public function selectFolder($folderId)
{
$this->selectedFolderId = $folderId;
$this->currentFolder = Folder::with('children')->find($folderId);
}
public function toggleFolder($folderId)
public function toggleFolder($folderId): void
{
if (in_array($folderId, $this->expandedFolders)) {
$this->expandedFolders = array_diff($this->expandedFolders, [$folderId]);
@@ -33,18 +45,82 @@ class ProjectShow extends Component
}
}
public function createFolder(): void
{
$this->validate([
'folderName' => [
'required',
'max:255',
Rule::unique('folders', 'name')->where(function ($query) {
return $query->where('project_id', $this->project->id)
->where('parent_id', $this->currentFolder?->id);
})
]
]);
Folder::create([
'name' => $this->folderName,
'project_id' => $this->project->id,
'parent_id' => $this->currentFolder?->id
]);
$this->reset('folderName');
$this->project->load('rootFolders'); // Recargar carpetas raíz
if ($this->currentFolder) {
$this->currentFolder->load('children'); // Recargar hijos si está en una subcarpeta
}
$this->project->refresh();
}
public function uploadFiles(): void
{
$this->validate([
'files.*' => 'file|max:10240|mimes:pdf,docx,xlsx,jpg,png'
]);
foreach ($this->files as $file) {
Document::create([
'name' => $file->getClientOriginalName(),
'file_path' => $file->store("projects/{$this->project->id}/documents"),
'project_id' => $this->project->id,
'folder_id' => $this->currentFolder?->id
]);
}
$this->reset('files');
if ($this->currentFolder) {
$this->currentFolder->refresh(); // Recargar documentos
}
$this->reset('files');
}
public function getDocumentsProperty()
{
return Document::where('folder_id', $this->selectedFolderId)
->where('project_id', $this->project->id)
->with('versions')
->get();
return $this->currentFolder
? $this->currentFolder->documents()->with('versions')->get()
: Document::whereNull('folder_id')->where('project_id', $this->project->id)->with('versions')->get();
}
public function getBreadcrumbsProperty()
{
if (!$this->currentFolder) return collect();
$breadcrumbs = collect();
$folder = $this->currentFolder;
while ($folder) {
$breadcrumbs->prepend($folder);
$folder = $folder->parent;
}
return $breadcrumbs;
}
public function render()
{
return view('livewire.project-show', [
'rootFolders' => $this->project->rootFolders
]);
return view('livewire.project-show')
->layout('layouts.livewire-app', [
'title' => $this->project->name
]);
}
}

25
app/Livewire/Toolbar.php Normal file
View File

@@ -0,0 +1,25 @@
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Project;
use App\Models\Folder;
class Toolbar extends Component
{
public Project $project;
public ?Folder $currentFolder;
public function mount(Project $project, Folder $currentFolder = null)
{
$this->project = $project;
$this->currentFolder = $currentFolder;
}
public function render()
{
return view('livewire.toolbar');
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Livewire;
use App\Models\User;
use Livewire\Component;
class UserSearch extends Component
{
public $search = '';
public $selectedUser;
public function selectUser($userId)
{
$this->selectedUser = $userId;
$this->emitUp('userSelected', $userId);
}
public function render()
{
$users = User::query()
->when($this->search, fn($q) => $q->where('name', 'like', "%{$this->search}%"))
->limit(5)
->get();
return view('livewire.user-search', compact('users'));
}
}

176
app/Models/Group.php Normal file
View File

@@ -0,0 +1,176 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Spatie\Permission\Traits\HasPermissions;
use Illuminate\Database\Eloquent\Builder;
class Group extends Model
{
use SoftDeletes, HasPermissions;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'description'
];
/**
* The accessors to append to the model's array form.
*
* @var array
*/
protected $appends = ['permission_names'];
/**
* Relationship: Users belonging to this group
*/
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class)
->withTimestamps()
->using(GroupUser::class);
}
/**
* Relationship: Permissions assigned to this group
*/
public function permissions(): BelongsToMany
{
return $this->belongsToMany(
config('permission.models.permission'),
config('permission.table_names.group_has_permissions'),
'group_id',
'permission_id'
);
}
/**
* Scope: Groups with specific permission
*/
public function scopeWithPermission(Builder $query, $permission): Builder
{
return $query->whereHas('permissions', function ($q) use ($permission) {
$q->where('name', $permission);
});
}
/**
* Scope: Groups with permissions on specific resource
*/
public function scopeWithResourcePermissions(Builder $query, $resourceId, $resourceType): Builder
{
return $query->whereHas('permissions', function ($q) use ($resourceId, $resourceType) {
$q->where('name', 'like', "{$resourceType}-{$resourceId}-%");
});
}
/**
* Assign permission to group
*/
public function assignPermission($permission): self
{
if (is_string($permission)) {
$permission = Permission::findByName($permission);
}
$this->permissions()->syncWithoutDetaching($permission);
return $this;
}
/**
* Revoke permission from group
*/
public function revokePermission($permission): self
{
if (is_string($permission)) {
$permission = Permission::findByName($permission);
}
$this->permissions()->detach($permission);
return $this;
}
/**
* Sync all permissions
*/
public function syncPermissions($permissions): self
{
$permissionIds = collect($permissions)->map(function ($perm) {
return is_string($perm) ? Permission::findByName($perm)->id : $perm->id;
});
$this->permissions()->sync($permissionIds);
return $this;
}
/**
* Check if group has permission
*/
public function hasPermission($permission): bool
{
if (is_string($permission)) {
return $this->permissions->contains('name', $permission);
}
return $this->permissions->contains('id', $permission->id);
}
/**
* Get all users with permissions through this group
*/
public function getUsersWithPermissionsAttribute()
{
return User::whereHas('groups', function ($query) {
$query->where('groups.id', $this->id);
})->get();
}
/**
* Get permission names attribute
*/
public function getPermissionNamesAttribute()
{
return $this->permissions->pluck('name');
}
/**
* Validation rules
*/
public static function validationRules($groupId = null): array
{
return [
'name' => 'required|string|max:255|unique:groups,name,'.$groupId,
'description' => 'nullable|string|max:500',
'permissions' => 'array',
'permissions.*' => 'exists:permissions,id',
'users' => 'array',
'users.*' => 'exists:users,id'
];
}
/**
* The "booting" method of the model
*/
protected static function boot()
{
parent::boot();
static::deleting(function ($group) {
if ($group->isForceDeleting()) {
$group->users()->detach();
$group->permissions()->detach();
}
});
}
}

View File

@@ -29,6 +29,11 @@ class Project extends Model
return $this->hasMany(Folder::class);
}
public function currentFolder()
{
return $this->belongsTo(Folder::class);
}
public function documents() {
return $this->hasMany(Document::class);
}

View File

@@ -4,6 +4,7 @@ namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Str;
@@ -12,8 +13,7 @@ use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable;
use HasRoles;
use HasFactory, Notifiable, HasRoles, SoftDeletes;
/**
* The attributes that are mass assignable.
@@ -60,4 +60,34 @@ class User extends Authenticatable
->map(fn (string $name) => Str::of($name)->substr(0, 1))
->implode('');
}
public function groups()
{
return $this->belongsToMany(Group::class)
->withTimestamps()
->using(GroupUser::class);
}
public function hasPermissionThroughGroup($permission)
{
return $this->groups->flatMap(function ($group) {
return $group->permissions;
})->contains('name', $permission);
}
public function getAllPermissionsAttribute()
{
return $this->getAllPermissions()
->merge($this->groups->flatMap->permissions)
->unique('id');
}
public function hasAnyPermission($permissions): bool
{
return $this->hasPermissionTo($permissions) ||
$this->groups->contains(function ($group) use ($permissions) {
return $group->hasAnyPermission($permissions);
});
}
}

View File

@@ -4,10 +4,13 @@ namespace App\Policies;
use App\Models\Document;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Auth\Access\Response;
class DocumentPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*/
@@ -22,7 +25,8 @@ class DocumentPolicy
public function view(User $user, Document $document)
{
return $user->hasPermissionTo('view documents')
&& $user->hasProjectAccess($document->project_id);
&& $user->hasProjectAccess($document->project_id)
&& $user->hasPermissionToResource($document->resource(), 'view');
}
/**
@@ -38,7 +42,7 @@ class DocumentPolicy
*/
public function update(User $user, Document $document): bool
{
return false;
return $user->hasPermissionToResource($document->resource(), 'edit');
}
/**
@@ -46,7 +50,7 @@ class DocumentPolicy
*/
public function delete(User $user, Document $document): bool
{
return false;
return $user->hasPermissionTo('delete documents');
}
/**

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Policies;
use App\Models\User;
use App\Models\Folder;
class FolderPolicy
{
/**
* Create a new policy instance.
*/
public function __construct()
{
//
}
public function create(User $user, Folder $folder = null)
{
if ($folder) {
return $user->can('manage-projects') &&
$user->projects->contains($folder->project_id);
}
return $user->can('manage-projects');
}
public function move(User $user, Folder $folder)
{
return $user->can('manage-projects') &&
$user->projects->contains($folder->project_id);
}
public function delete(User $user, Folder $folder)
{
return $user->can('delete-projects') &&
$user->projects->contains($folder->project_id);
}
}

View File

@@ -74,5 +74,10 @@ class ProjectPolicy
$project->managers->contains($user->id) ||
$project->users->contains($user->id);
}
public function managePermissions(User $user, Project $project)
{
return $user->hasPermissionToResource($project, 'manage_permissions');
}
}

View File

@@ -2,7 +2,7 @@
namespace App\Policies;
use App\Models\Role;
use Spatie\Permission\Models\Role;
use App\Models\User;
use Illuminate\Auth\Access\Response;
@@ -13,7 +13,7 @@ class RolePolicy
*/
public function viewAny(User $user): bool
{
return $user->hasPermissionTo('manage roles');
return $user->hasPermissionTo('view roles');
}
/**
@@ -29,7 +29,7 @@ class RolePolicy
*/
public function create(User $user): bool
{
return $user->hasPermissionTo('manage roles');
return $user->hasPermissionTo('create roles');
}
/**
@@ -37,7 +37,7 @@ class RolePolicy
*/
public function update(User $user, Role $role): bool
{
return $user->hasPermissionTo('manage roles') && !$role->is_protected;
return $user->hasPermissionTo('edit roles') && !$role->is_protected;
}
/**
@@ -45,7 +45,7 @@ class RolePolicy
*/
public function delete(User $user, Role $role): bool
{
return $user->hasPermissionTo('manage roles') && !$role->is_protected;
return $user->hasPermissionTo('delete roles') && !$role->is_protected;
}
/**

View File

@@ -2,33 +2,14 @@
namespace App\Providers;
use App\Models\Document;
use App\Models\Project;
use App\Models\User;
use App\Policies\DocumentPolicy;
use App\Policies\PermissionPolicy;
use App\Policies\ProfilePolicy;
use App\Policies\ProjectPolicy;
use App\Policies\RolePolicy;
use App\Policies\UserPolicy;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Validator;
use Livewire\Livewire;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class AppServiceProvider extends ServiceProvider
{
protected $policies = [
User::class => UserPolicy::class,
User::class => ProfilePolicy::class,
Role::class => RolePolicy::class,
Permission::class => PermissionPolicy::class,
Document::class => DocumentPolicy::class,
Project::class => ProjectPolicy::class,
];
/**
* Register any application services.
*/
@@ -42,10 +23,23 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot(): void
{
//
// Configuración de componentes Blade
Blade::componentNamespace('App\\View\\Components', 'icons');
Blade::component('multiselect', \App\View\Components\Multiselect::class);
// Registro de componentes Livewire
Livewire::component('project-show', \App\Http\Livewire\ProjectShow::class);
Livewire::component('file-upload', \App\Http\Livewire\FileUpload::class);
Livewire::component('toolbar', \App\Http\Livewire\Toolbar::class);
// Validación personalizada
Validator::extend('max_upload_size', function ($attribute, $value, $parameters, $validator) {
$maxSize = env('MAX_UPLOAD_SIZE', 51200); // 50MB por defecto
$totalSize = array_reduce($value, function($sum, $file) {
return $sum + $file->getSize();
}, 0);
return $totalSize <= ($maxSize * 1024);
});
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace App\Providers;
use App\Models\Document;
use App\Models\Folder;
use App\Models\Project;
use App\Models\User;
use App\Policies\DocumentPolicy;
use App\Policies\FolderPolicy;
use App\Policies\PermissionPolicy;
use App\Policies\ProfilePolicy;
use App\Policies\ProjectPolicy;
use App\Policies\RolePolicy;
use App\Policies\UserPolicy;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;
use Livewire\Livewire;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class AppServiceProvider extends ServiceProvider
{
protected $policies = [
User::class => UserPolicy::class,
User::class => ProfilePolicy::class,
Role::class => RolePolicy::class,
Permission::class => PermissionPolicy::class,
Document::class => DocumentPolicy::class,
Project::class => ProjectPolicy::class,
Folder::class => FolderPolicy::class,
];
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
//
Blade::componentNamespace('App\\View\\Components', 'icons');
Blade::component('multiselect', \App\View\Components\Multiselect::class);
Livewire::component('project-show', \App\Http\Livewire\ProjectShow::class);
Livewire::component('project-show', \App\Http\Livewire\FileUpload::class);
Livewire::component('toolbar', \App\Http\Livewire\Toolbar::class);
Validator::extend('max_upload_size', function ($attribute, $value, $parameters, $validator) {
$maxSize = env('MAX_UPLOAD_SIZE', 51200); // Default 50MB
$totalSize = array_reduce($value, function($sum, $file) {
return $sum + $file->getSize();
}, 0);
return $totalSize <= ($maxSize * 1024);
});
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace App\Providers;
//use Illuminate\Support\ServiceProvider;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use App\Models\User;
use App\Models\Document;
use App\Models\Project;
use App\Models\Folder;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use App\Policies\UserPolicy;
use App\Policies\DocumentPolicy;
use App\Policies\ProjectPolicy;
use App\Policies\FolderPolicy;
use App\Policies\RolePolicy;
use App\Policies\PermissionPolicy;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array<class-string, class-string>
*/
protected $policies = [
User::class => UserPolicy::class,
Project::class => ProjectPolicy::class,
Folder::class => FolderPolicy::class,
Document::class => DocumentPolicy::class,
Role::class => RolePolicy::class,
Permission::class => PermissionPolicy::class,
];
/**
* Register services.
*/
public function register(): void
{
//
}
/**
* Bootstrap services.
*/
public function boot(): void
{
$this->registerPolicies();
// Configuración adicional de gates aquí si es necesario
Gate::before(function ($user, $ability) {
return $user->hasRole('admin') ? true : null;
});
}
}