query(' SELECT u.id, u.username, u.email, u.first_name, u.last_name, u.role_id, u.is_active, u.last_login, u.created_at, r.name as role_name, r.display_name as role_display_name FROM users u LEFT JOIN roles r ON u.role_id = r.id ORDER BY u.created_at DESC '); $users = $stmt->fetchAll(); // Get roles for dropdown $stmt = $pdo->query('SELECT id, name, display_name FROM roles ORDER BY id'); $roles = $stmt->fetchAll(); successResponse([ 'users' => $users, 'roles' => $roles, ]); } /** * POST - Create new user * * @param array $authData */ function handleCreateUser(PDO $pdo, array $authData): void { $input = getJsonInput(); // Validate required fields $requiredFields = [ 'username' => 'Uživatelské jméno', 'email' => 'E-mail', 'password' => 'Heslo', 'first_name' => 'Jméno', 'last_name' => 'Příjmení', 'role_id' => 'Role', ]; foreach ($requiredFields as $field => $label) { if (empty($input[$field])) { errorResponse("$label je povinné"); } } $username = sanitize($input['username']); $email = sanitize($input['email']); $password = $input['password']; $firstName = sanitize($input['first_name']); $lastName = sanitize($input['last_name']); $roleId = (int) $input['role_id']; $isActive = isset($input['is_active']) ? ($input['is_active'] ? 1 : 0) : 1; // Non-admin nesmí přiřadit admin roli if (!($authData['user']['is_admin'] ?? false)) { $stmt = $pdo->prepare('SELECT name FROM roles WHERE id = ?'); $stmt->execute([$roleId]); $targetRole = $stmt->fetch(); if ($targetRole && $targetRole['name'] === 'admin') { errorResponse('Nemáte oprávnění přiřadit roli administrátora', 403); } } // Validate email format if (!isValidEmail($email)) { errorResponse('Neplatný formát e-mailu'); } // Validate password length if (strlen($password) < 8) { errorResponse('Heslo musí mít alespoň 8 znaků'); } // Check username uniqueness $stmt = $pdo->prepare('SELECT id FROM users WHERE username = ?'); $stmt->execute([$username]); if ($stmt->fetch()) { errorResponse('Uživatelské jméno již existuje'); } // Check email uniqueness $stmt = $pdo->prepare('SELECT id FROM users WHERE email = ?'); $stmt->execute([$email]); if ($stmt->fetch()) { errorResponse('E-mail již existuje'); } // Validate role exists $stmt = $pdo->prepare('SELECT id FROM roles WHERE id = ?'); $stmt->execute([$roleId]); if (!$stmt->fetch()) { errorResponse('Neplatná role'); } // Hash password $passwordHash = password_hash($password, PASSWORD_BCRYPT, ['cost' => BCRYPT_COST]); // Insert user $stmt = $pdo->prepare(' INSERT INTO users (username, email, password_hash, first_name, last_name, role_id, is_active) VALUES (?, ?, ?, ?, ?, ?, ?) '); $stmt->execute([$username, $email, $passwordHash, $firstName, $lastName, $roleId, $isActive]); $newUserId = (int)$pdo->lastInsertId(); // Audit log AuditLog::logCreate('user', $newUserId, [ 'username' => $username, 'email' => $email, 'first_name' => $firstName, 'last_name' => $lastName, 'role_id' => $roleId, 'is_active' => $isActive, ], "Vytvořen uživatel '$username'"); successResponse(['id' => $newUserId], 'Uživatel byl úspěšně vytvořen'); } /** * PUT - Update user * * @param array $authData */ function handleUpdateUser(PDO $pdo, int $userId, int $currentUserId, array $authData): void { // Get existing user $stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?'); $stmt->execute([$userId]); $existingUser = $stmt->fetch(); if (!$existingUser) { errorResponse('Uživatel nebyl nalezen', 404); } $input = getJsonInput(); $username = isset($input['username']) ? sanitize($input['username']) : $existingUser['username']; $email = isset($input['email']) ? sanitize($input['email']) : $existingUser['email']; $firstName = isset($input['first_name']) ? sanitize($input['first_name']) : $existingUser['first_name']; $lastName = isset($input['last_name']) ? sanitize($input['last_name']) : $existingUser['last_name']; $roleId = isset($input['role_id']) ? (int) $input['role_id'] : $existingUser['role_id']; $isActive = isset($input['is_active']) ? ($input['is_active'] ? 1 : 0) : $existingUser['is_active']; // Validate email format if (!isValidEmail($email)) { errorResponse('Neplatný formát e-mailu'); } // Check username uniqueness (excluding current user) $stmt = $pdo->prepare('SELECT id FROM users WHERE username = ? AND id != ?'); $stmt->execute([$username, $userId]); if ($stmt->fetch()) { errorResponse('Uživatelské jméno již existuje'); } // Check email uniqueness (excluding current user) $stmt = $pdo->prepare('SELECT id FROM users WHERE email = ? AND id != ?'); $stmt->execute([$email, $userId]); if ($stmt->fetch()) { errorResponse('E-mail již existuje'); } // Validate role exists $stmt = $pdo->prepare('SELECT id, name FROM roles WHERE id = ?'); $stmt->execute([$roleId]); $targetRole = $stmt->fetch(); if (!$targetRole) { errorResponse('Neplatná role'); } // Non-admin nesmí přiřadit admin roli if (!($authData['user']['is_admin'] ?? false) && $targetRole['name'] === 'admin') { errorResponse('Nemáte oprávnění přiřadit roli administrátora', 403); } // Update user if (!empty($input['password'])) { // Validate password length if (strlen($input['password']) < 8) { errorResponse('Heslo musí mít alespoň 8 znaků'); } $passwordHash = password_hash($input['password'], PASSWORD_BCRYPT, ['cost' => BCRYPT_COST]); $stmt = $pdo->prepare(' UPDATE users SET username = ?, email = ?, password_hash = ?, first_name = ?, last_name = ?, role_id = ?, is_active = ?, password_changed_at = NOW() WHERE id = ? '); $stmt->execute([$username, $email, $passwordHash, $firstName, $lastName, $roleId, $isActive, $userId]); } else { $stmt = $pdo->prepare(' UPDATE users SET username = ?, email = ?, first_name = ?, last_name = ?, role_id = ?, is_active = ? WHERE id = ? '); $stmt->execute([$username, $email, $firstName, $lastName, $roleId, $isActive, $userId]); } // Note: With JWT, user data is in the token - no session to update // Audit log AuditLog::logUpdate('user', $userId, [ 'username' => $existingUser['username'], 'email' => $existingUser['email'], 'first_name' => $existingUser['first_name'], 'last_name' => $existingUser['last_name'], 'role_id' => $existingUser['role_id'], 'is_active' => $existingUser['is_active'], ], [ 'username' => $username, 'email' => $email, 'first_name' => $firstName, 'last_name' => $lastName, 'role_id' => $roleId, 'is_active' => $isActive, ], "Upraven uživatel '$username'"); successResponse(null, 'Uživatel byl úspěšně aktualizován'); } /** * DELETE - Delete user */ function handleDeleteUser(PDO $pdo, int $userId, int $currentUserId): void { // Prevent self-deletion if ($userId === $currentUserId) { errorResponse('Nemůžete smazat svůj vlastní účet'); } // Get user for audit log $stmt = $pdo->prepare('SELECT username FROM users WHERE id = ?'); $stmt->execute([$userId]); $user = $stmt->fetch(); if (!$user) { errorResponse('Uživatel nebyl nalezen', 404); } // Delete related records first (refresh tokens for JWT auth) $stmt = $pdo->prepare('DELETE FROM refresh_tokens WHERE user_id = ?'); $stmt->execute([$userId]); // Delete user $stmt = $pdo->prepare('DELETE FROM users WHERE id = ?'); $stmt->execute([$userId]); // Audit log AuditLog::logDelete('user', $userId, ['username' => $user['username']], "Smazán uživatel '{$user['username']}'"); successResponse(null, 'Uživatel byl úspěšně smazán'); }