db = Database::getInstance(); $this->encryption = App::getEncryption(); } public function findById(int $id): ?array { $server = $this->db->fetch('SELECT * FROM servers WHERE id = ? AND status = \'active\'', [$id]); if ($server) { $server = $this->encryption->decryptArray($server, $this->encryptedFields); } return $server; } public function findAll(bool $activeOnly = false): array { $sql = 'SELECT * FROM servers WHERE status = \'active\''; $params = []; if ($activeOnly) { $sql .= ' AND is_active = 1'; } $sql .= ' ORDER BY name ASC'; $servers = $this->db->fetchAll($sql, $params); return array_map(function ($server) { return $this->encryption->decryptArray($server, $this->encryptedFields); }, $servers); } public function getAll(int $page = 1, int $perPage = 20, array $filters = []): array { $where = ["s.status = 'active'"]; $params = []; if (!empty($filters['search'])) { $where[] = '(s.name LIKE ? OR s.ip_address LIKE ? OR s.description LIKE ?)'; $search = '%' . $filters['search'] . '%'; $params[] = $search; $params[] = $search; $params[] = $search; } if (isset($filters['is_active']) && $filters['is_active'] !== '') { $where[] = 's.is_active = ?'; $params[] = (int) $filters['is_active']; } if (!empty($filters['group_name'])) { $where[] = 's.group_name = ?'; $params[] = $filters['group_name']; } if (!empty($filters['status'])) { $where[] = 's.current_status = ?'; $params[] = $filters['status']; } if (!empty($filters['accessible_ids'])) { $ids = array_map('intval', $filters['accessible_ids']); $placeholders = implode(',', array_fill(0, count($ids), '?')); $where[] = "s.id IN ({$placeholders})"; $params = array_merge($params, $ids); } $whereClause = !empty($where) ? 'WHERE ' . implode(' AND ', $where) : ''; $offset = ($page - 1) * $perPage; $total = $this->db->fetch( "SELECT COUNT(*) as total FROM servers s {$whereClause}", $params ); $servers = $this->db->fetchAll( "SELECT s.* FROM servers s {$whereClause} ORDER BY s.name ASC LIMIT ? OFFSET ?", array_merge($params, [$perPage, $offset]) ); $servers = array_map(function ($server) { return $this->encryption->decryptArray($server, $this->encryptedFields); }, $servers); return [ 'data' => $servers, 'total' => (int) ($total['total'] ?? 0), 'page' => $page, 'per_page' => $perPage, 'total_pages' => ceil((int) ($total['total'] ?? 0) / $perPage), ]; } public function create(array $data): int { if (!empty($data['ssh_password'])) { $data['ssh_password'] = $this->encryption->encrypt($data['ssh_password']); } else { $data['ssh_password'] = null; } if (!empty($data['ssh_key'])) { $data['ssh_key'] = $this->encryption->encrypt($data['ssh_key']); } else { $data['ssh_key'] = null; } $data['created_at'] = date('Y-m-d H:i:s'); $data['updated_at'] = date('Y-m-d H:i:s'); if (empty($data['current_status'])) { $data['current_status'] = 'unknown'; } $userId = Session::get('user_id'); if ($userId && empty($data['created_by'])) { $data['created_by'] = $userId; } return $this->db->insert('servers', $data); } public function update(int $id, array $data): bool { if (array_key_exists('ssh_password', $data)) { if (!empty($data['ssh_password'])) { $data['ssh_password'] = $this->encryption->encrypt($data['ssh_password']); } else { unset($data['ssh_password']); } } if (array_key_exists('ssh_key', $data)) { if (!empty($data['ssh_key'])) { $data['ssh_key'] = $this->encryption->encrypt($data['ssh_key']); } else { unset($data['ssh_key']); } } $data['updated_at'] = date('Y-m-d H:i:s'); return $this->db->update('servers', $data, 'id = ?', [$id]) > 0; } public function delete(int $id): bool { return $this->db->update('servers', [ 'status' => 'deleted', 'is_active' => 0, 'updated_at' => date('Y-m-d H:i:s'), ], 'id = ?', [$id]) > 0; } public function toggleActive(int $id): ?bool { $server = $this->db->fetch('SELECT is_active, status FROM servers WHERE id = ?', [$id]); if (!$server) { return null; } $newState = $server['is_active'] ? 0 : 1; $newStatus = $newState ? 'active' : 'disabled'; $this->db->update('servers', [ 'is_active' => $newState, 'status' => $newStatus, 'updated_at' => date('Y-m-d H:i:s'), ], 'id = ?', [$id]); return (bool) $newState; } public function getGroups(): array { $groups = $this->db->fetchAll( 'SELECT DISTINCT group_name FROM servers WHERE status = \'active\' AND group_name IS NOT NULL AND group_name != "" ORDER BY group_name' ); return array_column($groups, 'group_name'); } public function countAll(): int { $result = $this->db->fetch("SELECT COUNT(*) as total FROM servers WHERE status = 'active'"); return (int) ($result['total'] ?? 0); } public function countOnline(): int { $result = $this->db->fetch( "SELECT COUNT(*) as total FROM servers WHERE current_status = 'online' AND status = 'active' AND is_active = 1" ); return (int) ($result['total'] ?? 0); } public function getUserRole(int $serverId, int $userId): ?string { $server = $this->db->fetch('SELECT created_by FROM servers WHERE id = ? AND status = \'active\'', [$serverId]); if (!$server) { return null; } if ((int) $server['created_by'] === $userId) { return 'owner'; } $direct = $this->db->fetch( 'SELECT role FROM server_user WHERE server_id = ? AND user_id = ? AND status = \'active\'', [$serverId, $userId] ); $teamRole = $this->db->fetch( 'SELECT ts.role FROM team_user tu JOIN team_server ts ON tu.team_id = ts.team_id WHERE tu.user_id = ? AND ts.server_id = ? AND tu.status = \'active\' AND ts.status = \'active\' ORDER BY FIELD(ts.role, \'manager\', \'viewer\') LIMIT 1', [$userId, $serverId] ); $directRole = $direct ? $direct['role'] : null; $teamRoleValue = $teamRole ? $teamRole['role'] : null; if ($directRole === 'manager' || $teamRoleValue === 'manager') { return 'manager'; } if ($directRole === 'viewer' || $teamRoleValue === 'viewer') { return 'viewer'; } return null; } public function getAccessibleServerIds(int $userId): array { $user = $this->db->fetch( 'SELECT role FROM users WHERE id = ? AND status = \'active\'', [$userId] ); if (!$user) { return []; } if ($user['role'] === 'super_admin') { $all = $this->db->fetchAll( 'SELECT id FROM servers WHERE status = \'active\'' ); return array_map(fn($r) => (int) $r['id'], $all); } $owned = $this->db->fetchAll( 'SELECT id FROM servers WHERE created_by = ? AND status = \'active\'', [$userId] ); $assigned = $this->db->fetchAll( 'SELECT server_id FROM server_user WHERE user_id = ? AND status = \'active\'', [$userId] ); $teamServerIds = $this->db->fetchAll( 'SELECT DISTINCT ts.server_id FROM team_user tu JOIN team_server ts ON tu.team_id = ts.team_id WHERE tu.user_id = ? AND tu.status = \'active\' AND ts.status = \'active\'', [$userId] ); $ids = []; foreach ($owned as $row) { $ids[] = (int) $row['id']; } foreach ($assigned as $row) { $ids[] = (int) $row['server_id']; } foreach ($teamServerIds as $row) { $ids[] = (int) $row['server_id']; } return array_unique($ids); } public function isOwner(int $serverId, int $userId): bool { $server = $this->db->fetch('SELECT created_by FROM servers WHERE id = ? AND status = \'active\'', [$serverId]); return $server && (int) $server['created_by'] === $userId; } public function canManage(int $serverId, int $userId): bool { $role = $this->getUserRole($serverId, $userId); return $role === 'owner' || $role === 'manager'; } public function canView(int $serverId, int $userId): bool { return $this->getUserRole($serverId, $userId) !== null; } public function getTeam(int $serverId): array { $members = $this->db->fetchAll( 'SELECT su.*, u.username, u.email FROM server_user su JOIN users u ON su.user_id = u.id WHERE su.server_id = ? AND su.status = \'active\' AND u.status = \'active\' ORDER BY su.created_at ASC', [$serverId] ); $owner = $this->db->fetch( 'SELECT u.id, u.username, u.email FROM servers s JOIN users u ON s.created_by = u.id WHERE s.id = ? AND s.status = \'active\' AND u.status = \'active\'', [$serverId] ); $result = []; if ($owner) { $result[] = [ 'user_id' => (int) $owner['id'], 'username' => $owner['username'], 'email' => $owner['email'], 'role' => 'owner', ]; } foreach ($members as $m) { $result[] = [ 'user_id' => (int) $m['user_id'], 'username' => $m['username'], 'email' => $m['email'], 'role' => $m['role'], ]; } return $result; } public function addUser(int $serverId, int $userId, string $role): bool { if (!in_array($role, ['viewer', 'manager'], true)) { return false; } $existing = $this->db->fetch( 'SELECT id FROM server_user WHERE server_id = ? AND user_id = ? AND status = \'active\'', [$serverId, $userId] ); if ($existing) { return false; } $this->db->insert('server_user', [ 'server_id' => $serverId, 'user_id' => $userId, 'role' => $role, ]); return true; } public function removeUser(int $serverId, int $userId): bool { return $this->db->update( 'server_user', ['status' => 'deleted'], 'server_id = ? AND user_id = ?', [$serverId, $userId] ) > 0; } public function updateUserRole(int $serverId, int $userId, string $role): bool { if (!in_array($role, ['viewer', 'manager'], true)) { return false; } return $this->db->update( 'server_user', ['role' => $role], 'server_id = ? AND user_id = ? AND status = \'active\'', [$serverId, $userId] ) > 0; } public function getOwnedServers(int $userId): array { return $this->db->fetchAll( 'SELECT * FROM servers WHERE created_by = ? AND status = \'active\' ORDER BY name ASC', [$userId] ); } }