Files
app/api/admin/handlers/roles-handlers.php
Simon 5ef6fc8064 refactor: odstraneni PSR-1 SideEffects warningu
- Handler funkce extrahovany z API souboru do api/admin/handlers/
- config.php rozdeleny na helpers.php (funkce) a constants.php (konstanty)
- require_once odstranen z class souboru (AuditLog, JWTAuth, LeaveNotification)
- vendor/autoload.php presunuto do config.php bootstrap
- totp-handlers.php: pridany use deklarace pro TwoFactorAuth
- phpstan.neon: bootstrapFiles, scanDirectories, dynamicConstantNames
- Opraveny chybejici routing bloky v totp.php a session.php

Vysledek: phpcs 0 errors 0 warnings, PHPStan 0 errors, ESLint 0 errors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 14:29:21 +01:00

238 lines
6.7 KiB
PHP

<?php
declare(strict_types=1);
/**
* GET - List all roles with their permissions + all available permissions
*/
function handleGetRole(PDO $pdo): void
{
// Get all roles with user count (LEFT JOIN instead of correlated subquery)
$stmt = $pdo->query('
SELECT r.*, COUNT(u.id) as user_count
FROM roles r
LEFT JOIN users u ON u.role_id = r.id
GROUP BY r.id
ORDER BY r.id
');
$roles = $stmt->fetchAll();
// Batch fetch all role-permission mappings in one query (was N+1)
$stmt = $pdo->query('
SELECT rp.role_id, p.name
FROM role_permissions rp
JOIN permissions p ON p.id = rp.permission_id
');
$allRolePerms = $stmt->fetchAll();
// Group permissions by role_id
$permsByRole = [];
foreach ($allRolePerms as $rp) {
$permsByRole[$rp['role_id']][] = $rp['name'];
}
foreach ($roles as &$role) {
$role['permissions'] = $permsByRole[$role['id']] ?? [];
$role['permission_count'] = count($role['permissions']);
}
unset($role);
// Get all available permissions grouped by module
$stmt = $pdo->query('SELECT id, name, display_name, description FROM permissions ORDER BY id');
$allPermissions = $stmt->fetchAll();
$grouped = [];
foreach ($allPermissions as $perm) {
$parts = explode('.', $perm['name'], 2);
$module = $parts[0];
if (!isset($grouped[$module])) {
$grouped[$module] = [];
}
$grouped[$module][] = $perm;
}
successResponse([
'roles' => $roles,
'permissions' => $allPermissions,
'permission_groups' => $grouped,
]);
}
/**
* POST - Create new role
*/
function handleCreateRole(PDO $pdo): void
{
$input = getJsonInput();
$name = trim($input['name'] ?? '');
$displayName = trim($input['display_name'] ?? '');
$description = trim($input['description'] ?? '');
$permissions = $input['permissions'] ?? [];
if (!$name) {
errorResponse('Název role je povinný');
}
if (!$displayName) {
errorResponse('Zobrazovaný název je povinný');
}
// Validate name format (slug)
if (!preg_match('/^[a-z0-9_-]+$/', $name)) {
errorResponse('Název role může obsahovat pouze malá písmena, čísla, pomlčky a podtržítka');
}
// Check uniqueness
$stmt = $pdo->prepare('SELECT id FROM roles WHERE name = ?');
$stmt->execute([$name]);
if ($stmt->fetch()) {
errorResponse('Role s tímto názvem již existuje');
}
$pdo->beginTransaction();
try {
// Create role
$stmt = $pdo->prepare('
INSERT INTO roles (name, display_name, description)
VALUES (?, ?, ?)
');
$stmt->execute([$name, $displayName, $description ?: null]);
$newRoleId = (int)$pdo->lastInsertId();
// Assign permissions
if (!empty($permissions)) {
$stmt = $pdo->prepare('
INSERT INTO role_permissions (role_id, permission_id)
SELECT ?, id FROM permissions WHERE name = ?
');
foreach ($permissions as $permName) {
$stmt->execute([$newRoleId, $permName]);
}
}
$pdo->commit();
AuditLog::logCreate('role', $newRoleId, [
'name' => $name,
'display_name' => $displayName,
'permissions' => $permissions,
], "Vytvořena role '$displayName'");
successResponse(['id' => $newRoleId], 'Role byla vytvořena');
} catch (PDOException $e) {
$pdo->rollBack();
throw $e;
}
}
/**
* PUT - Update role
*/
function handleUpdateRole(PDO $pdo, int $roleId): void
{
// Get existing role
$stmt = $pdo->prepare('SELECT * FROM roles WHERE id = ?');
$stmt->execute([$roleId]);
$role = $stmt->fetch();
if (!$role) {
errorResponse('Role nebyla nalezena', 404);
}
// Block editing admin role name
if ($role['name'] === 'admin') {
errorResponse('Roli administrátora nelze upravovat');
}
$input = getJsonInput();
$displayName = trim($input['display_name'] ?? $role['display_name']);
$description = trim($input['description'] ?? $role['description'] ?? '');
$permissions = $input['permissions'] ?? null;
if (!$displayName) {
errorResponse('Zobrazovaný název je povinný');
}
$pdo->beginTransaction();
try {
// Update role
$stmt = $pdo->prepare('
UPDATE roles SET display_name = ?, description = ?
WHERE id = ?
');
$stmt->execute([$displayName, $description ?: null, $roleId]);
// Update permissions if provided
if ($permissions !== null) {
// Remove existing permissions
$stmt = $pdo->prepare('DELETE FROM role_permissions WHERE role_id = ?');
$stmt->execute([$roleId]);
// Add new permissions
if (!empty($permissions)) {
$stmt = $pdo->prepare('
INSERT INTO role_permissions (role_id, permission_id)
SELECT ?, id FROM permissions WHERE name = ?
');
foreach ($permissions as $permName) {
$stmt->execute([$roleId, $permName]);
}
}
}
$pdo->commit();
AuditLog::logUpdate('role', $roleId, [
'display_name' => $role['display_name'],
], [
'display_name' => $displayName,
'permissions' => $permissions,
], "Upravena role '$displayName'");
successResponse(null, 'Role byla aktualizována');
} catch (PDOException $e) {
$pdo->rollBack();
throw $e;
}
}
/**
* DELETE - Delete role
*/
function handleDeleteRole(PDO $pdo, int $roleId): void
{
$stmt = $pdo->prepare('SELECT * FROM roles WHERE id = ?');
$stmt->execute([$roleId]);
$role = $stmt->fetch();
if (!$role) {
errorResponse('Role nebyla nalezena', 404);
}
// Block deleting admin role
if ($role['name'] === 'admin') {
errorResponse('Roli administrátora nelze smazat');
}
// Check if role has users
$stmt = $pdo->prepare('SELECT COUNT(*) FROM users WHERE role_id = ?');
$stmt->execute([$roleId]);
$userCount = $stmt->fetchColumn();
if ($userCount > 0) {
errorResponse("Nelze smazat roli s {$userCount} přiřazenými uživateli. Nejprve změňte roli těmto uživatelům.");
}
// Delete role (cascade deletes role_permissions)
$stmt = $pdo->prepare('DELETE FROM roles WHERE id = ?');
$stmt->execute([$roleId]);
AuditLog::logDelete('role', $roleId, $role, "Smazána role '{$role['display_name']}'");
successResponse(null, 'Role byla smazána');
}