feat: add installer, ranks/groups enhancements, and founder protections
This commit is contained in:
141
app/Http/Controllers/RoleController.php
Normal file
141
app/Http/Controllers/RoleController.php
Normal file
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Role;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class RoleController extends Controller
|
||||
{
|
||||
private const CORE_ROLES = ['ROLE_ADMIN', 'ROLE_USER', 'ROLE_FOUNDER'];
|
||||
|
||||
private function ensureAdmin(Request $request): ?JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
if (!$user || !$user->roles()->where('name', 'ROLE_ADMIN')->exists()) {
|
||||
return response()->json(['message' => 'Forbidden'], 403);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
if ($error = $this->ensureAdmin($request)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$roles = Role::query()
|
||||
->orderBy('name')
|
||||
->get()
|
||||
->map(fn (Role $role) => [
|
||||
'id' => $role->id,
|
||||
'name' => $role->name,
|
||||
'color' => $role->color,
|
||||
]);
|
||||
|
||||
return response()->json($roles);
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
if ($error = $this->ensureAdmin($request)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$data = $request->validate([
|
||||
'name' => ['required', 'string', 'max:100', 'unique:roles,name'],
|
||||
'color' => ['nullable', 'string', 'max:20', 'regex:/^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/'],
|
||||
]);
|
||||
|
||||
$normalizedName = $this->normalizeRoleName($data['name']);
|
||||
if (Role::query()->where('name', $normalizedName)->exists()) {
|
||||
return response()->json(['message' => 'Role already exists.'], 422);
|
||||
}
|
||||
|
||||
$role = Role::create([
|
||||
'name' => $normalizedName,
|
||||
'color' => $data['color'] ?? null,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'id' => $role->id,
|
||||
'name' => $role->name,
|
||||
'color' => $role->color,
|
||||
], 201);
|
||||
}
|
||||
|
||||
public function update(Request $request, Role $role): JsonResponse
|
||||
{
|
||||
if ($error = $this->ensureAdmin($request)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$data = $request->validate([
|
||||
'name' => ['required', 'string', 'max:100', "unique:roles,name,{$role->id}"],
|
||||
'color' => ['nullable', 'string', 'max:20', 'regex:/^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/'],
|
||||
]);
|
||||
|
||||
$normalizedName = $this->normalizeRoleName($data['name']);
|
||||
if (Role::query()
|
||||
->where('id', '!=', $role->id)
|
||||
->where('name', $normalizedName)
|
||||
->exists()
|
||||
) {
|
||||
return response()->json(['message' => 'Role already exists.'], 422);
|
||||
}
|
||||
|
||||
if (in_array($role->name, self::CORE_ROLES, true) && $normalizedName !== $role->name) {
|
||||
return response()->json(['message' => 'Core roles cannot be renamed.'], 422);
|
||||
}
|
||||
|
||||
$color = array_key_exists('color', $data) ? $data['color'] : $role->color;
|
||||
|
||||
$role->update([
|
||||
'name' => $normalizedName,
|
||||
'color' => $color,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'id' => $role->id,
|
||||
'name' => $role->name,
|
||||
'color' => $role->color,
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Request $request, Role $role): JsonResponse
|
||||
{
|
||||
if ($error = $this->ensureAdmin($request)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
if (in_array($role->name, self::CORE_ROLES, true)) {
|
||||
return response()->json(['message' => 'Core roles cannot be deleted.'], 422);
|
||||
}
|
||||
|
||||
if ($role->users()->exists()) {
|
||||
return response()->json(['message' => 'Role is assigned to users.'], 422);
|
||||
}
|
||||
|
||||
$role->delete();
|
||||
|
||||
return response()->json(null, 204);
|
||||
}
|
||||
|
||||
private function normalizeRoleName(string $value): string
|
||||
{
|
||||
$raw = strtoupper(trim($value));
|
||||
$raw = preg_replace('/\s+/', '_', $raw);
|
||||
$raw = preg_replace('/[^A-Z0-9_]/', '_', $raw);
|
||||
$raw = preg_replace('/_+/', '_', $raw);
|
||||
$raw = trim($raw, '_');
|
||||
if ($raw === '') {
|
||||
return 'ROLE_';
|
||||
}
|
||||
if (str_starts_with($raw, 'ROLE_')) {
|
||||
return $raw;
|
||||
}
|
||||
return "ROLE_{$raw}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user