Skip to content

feat: Complete backend implementation for Team Management with RBAC #169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions app/Http/Controllers/Admin/PermissionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Permission;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Inertia\Inertia;

class PermissionController extends Controller
{
/**
* Display a listing of the permissions grouped by category.
*/
public function index(Request $request)
{
$search = $request->get('search');
$group = $request->get('group');

// Get permissions with optional filtering
$query = Permission::query();

if ($search) {
$query->where(function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('description', 'like', "%{$search}%")
->orWhere('group', 'like', "%{$search}%");
});
}

if ($group) {
$query->where('group', $group);
}

$permissions = $query->orderBy('group')->orderBy('name')->get();

// Group permissions by category
$groupedPermissions = $permissions->groupBy('group')->map(function ($groupPermissions, $groupName) {
return [
'name' => $groupName,
'permissions' => $groupPermissions->toArray()
];
})->values();

// Get available groups for filter
$availableGroups = Permission::distinct('group')->pluck('group')->sort()->values();

return Inertia::render('Admin/Permissions/Index', [
'grouped_permissions' => $groupedPermissions->keyBy('name'),
'availableGroups' => $availableGroups,
'filters' => [
'search' => $search,
'group' => $group,
],
]);
}

/**
* Display the specified permission.
*/
public function show(Permission $permission)
{
$permission->load('roles.users');

return Inertia::render('Admin/Permissions/Show', [
'permission' => $permission,
'roles' => $permission->roles->map(function ($role) {
return [
'id' => $role->id,
'name' => $role->name,
'slug' => $role->slug,
'users_count' => $role->users_count ?? $role->users->count(),
];
}),
]);
}

/**
* Get permissions grouped for role assignment.
*/
public function grouped()
{
$cacheKey = 'permissions_grouped';

$grouped = Cache::remember($cacheKey, 3600, function () {
return Permission::orderBy('group')->orderBy('name')->get()
->groupBy('group')
->map(function ($permissions, $group) {
return [
'name' => $group,
'permissions' => $permissions->map(function ($permission) {
return [
'id' => $permission->id,
'name' => $permission->name,
'slug' => $permission->slug,
'description' => $permission->description,
];
})->toArray()
];
})
->values();
});

return response()->json(['groups' => $grouped]);
}

/**
* Get all permissions for API use.
*/
public function all()
{
$permissions = Permission::orderBy('group')->orderBy('name')->get([
'id', 'name', 'slug', 'description', 'group'
]);

return response()->json(['permissions' => $permissions]);
}

/**
* Sync permissions cache.
*/
public function syncCache()
{
// Clear permission-related cache
Cache::forget('permissions_grouped');
Cache::tags(['permissions'])->flush();

// Warm up the cache
$this->grouped();

return response()->json([
'message' => 'Permission cache synchronized successfully'
]);
}
}
152 changes: 152 additions & 0 deletions app/Http/Controllers/Admin/RoleController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Role;
use App\Models\Permission;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Inertia\Inertia;
use Inertia\Response;

class RoleController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request): Response
{
$query = Role::withCount('users', 'permissions');

// Search functionality
if ($search = $request->get('search')) {
$query->where(function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('description', 'like', "%{$search}%");
});
}

$roles = $query->paginate(15);

return Inertia::render('Admin/Roles/Index', [
'roles' => $roles,
'permissions' => Permission::getGrouped(),
'filters' => $request->only('search'),
]);
}

/**
* Show the form for creating a new resource.
*/
public function create(): Response
{
return Inertia::render('Admin/Roles/Create', [
'permissions' => Permission::getGrouped(),
]);
}

/**
* Store a newly created resource in storage.
*/
public function store(Request $request): RedirectResponse
{
$request->validate([
'name' => 'required|string|max:255',
'slug' => 'required|string|max:255|unique:roles',
'description' => 'required|string|max:500',
'permissions' => 'array',
'permissions.*' => 'exists:permissions,id',
]);

$role = Role::create($request->only('name', 'slug', 'description'));

if ($request->has('permissions')) {
$role->permissions()->sync($request->permissions);
}

return redirect()->route('admin.roles.index')
->with('flash.message', 'Role created successfully.');
}

/**
* Display the specified resource.
*/
public function show(Role $role): Response
{
$role->load('permissions', 'users');

return Inertia::render('Admin/Roles/Show', [
'role' => $role,
]);
}

/**
* Show the form for editing the specified resource.
*/
public function edit(Role $role): Response
{
$role->load('permissions');

return Inertia::render('Admin/Roles/Edit', [
'role' => $role,
'permissions' => Permission::getGrouped(),
]);
}

/**
* Update the specified resource in storage.
*/
public function update(Request $request, Role $role): RedirectResponse
{
$request->validate([
'name' => 'required|string|max:255',
'slug' => 'required|string|max:255|unique:roles,slug,' . $role->id,
'description' => 'required|string|max:500',
]);

$role->update($request->only('name', 'slug', 'description'));

return redirect()->route('admin.roles.index')
->with('flash.message', 'Role updated successfully.');
}

/**
* Remove the specified resource from storage.
*/
public function destroy(Role $role)
{
// Check if this is a system role
if ($role->isSystemRole()) {
return response()->json([
'message' => 'System roles cannot be deleted.'
], 403);
}

$role->delete();

return response()->json([
'message' => 'Role deleted successfully.'
]);
}

/**
* Sync permissions to the role.
*/
public function syncPermissions(Request $request, Role $role)
{
$request->validate([
'permission_groups' => 'required|array',
]);

$permissionIds = collect($request->permission_groups)
->flatten()
->toArray();

$role->syncPermissions($permissionIds);

return response()->json([
'message' => 'Permissions synchronized successfully.'
]);
}
}
Loading
Loading