false, 'error' => [ 'code' => 'NOT_FOUND', 'message' => 'Kundenordner nicht gefunden.' ] ]; } // Load client display name $clientDisplay = self::getClientDisplayName($clientDir); // Load project order if available $projectOrder = self::loadProjectOrder($base); // Collect available projects $foundProjects = self::scanProjectsInDirectory($base, $clientDir, $clientDisplay); // Sort projects according to order $projects = self::sortProjectsByOrder($foundProjects, $projectOrder); return [ 'success' => true, 'projects' => $projects ]; } /** * Save project order to order_project.json */ public static function saveProjectOrder($clientDir, $orderData) { $base = realpath(__DIR__ . FileSystemService::getAreaPath() . '/' . $clientDir); if (!$base || !is_dir($base)) { return [ 'success' => false, 'error' => [ 'code' => 'NOT_FOUND', 'message' => 'Kundenordner nicht gefunden.' ] ]; } // Validate that all projects in order array actually exist $existingProjects = self::getExistingProjectNames($base); foreach ($orderData['order'] as $projectName) { if (!in_array($projectName, $existingProjects)) { return [ 'success' => false, 'error' => [ 'code' => 'INVALID_PROJECT', 'message' => "Projekt '$projectName' existiert nicht." ] ]; } } // Save new order $projectOrderFile = $base . '/order_project.json'; $result = file_put_contents($projectOrderFile, json_encode($orderData['order'], JSON_PRETTY_PRINT)); if ($result === false) { return [ 'success' => false, 'error' => [ 'code' => 'WRITE_ERROR', 'message' => 'Fehler beim Speichern der order_project.json.' ] ]; } return [ 'success' => true, 'message' => 'Projekt-Reihenfolge gespeichert.' ]; } /** * Get project details (logo, poster, etc.) */ public static function getProjectDetails($clientDir, $projectName) { $setupDir = __DIR__ . FileSystemService::getAreaPath() . "/$clientDir/$projectName/setup"; $poster = null; $logo = null; if (is_dir($setupDir)) { foreach (scandir($setupDir) as $file) { if ($file === '.' || $file === '..') continue; if (stripos($file, 'poster') === 0 && preg_match('/\.(jpg|jpeg|png|webp)$/i', $file)) { $poster = '/area/' . rawurlencode($clientDir) . '/' . rawurlencode($projectName) . '/setup/' . rawurlencode($file); } if (!$logo && stripos($file, 'logo') === 0 && preg_match('/\.(jpg|jpeg|png|webp)$/i', $file)) { $logo = '/area/' . rawurlencode($clientDir) . '/' . rawurlencode($projectName) . '/setup/' . rawurlencode($file); } if ($poster && $logo) break; } } return [ 'success' => true, 'data' => [ 'poster' => $poster, 'logo' => $logo, ] ]; } /** * Private helper methods */ private static function getClientDisplayName($clientDir) { $loginsFile = __DIR__ . '/../../storage/data/clients.json'; $clientDisplay = $clientDir; if (file_exists($loginsFile)) { $logins = json_decode(file_get_contents($loginsFile), true); foreach ($logins as $login) { if (isset($login['dir']) && $login['dir'] === $clientDir) { $clientDisplay = $login['dir']; break; } } } return $clientDisplay; } private static function loadProjectOrder($basePath) { $projectOrderFile = $basePath . '/order_project.json'; $projectOrder = []; if (file_exists($projectOrderFile)) { $orderContent = file_get_contents($projectOrderFile); $decoded = json_decode($orderContent, true); if (is_array($decoded)) { $projectOrder = $decoded; } } return $projectOrder; } private static function scanProjectsInDirectory($base, $clientDir, $clientDisplay) { $foundProjects = []; foreach (scandir($base) as $entry) { if ($entry === '.' || $entry === '..') continue; $path = $base . '/' . $entry; if (is_dir($path)) { $setupDir = $path . '/setup'; $poster = null; $logo = null; if (is_dir($setupDir)) { foreach (scandir($setupDir) as $file) { if (!$poster && stripos($file, 'poster') === 0 && preg_match('/\.(jpg|jpeg|png|webp)$/i', $file)) { $poster = '/area/' . rawurlencode($clientDir) . '/' . rawurlencode($entry) . '/setup/' . rawurlencode($file); } if (!$logo && stripos($file, 'logo') === 0 && preg_match('/\.(jpg|jpeg|png|webp)$/i', $file)) { $logo = '/area/' . rawurlencode($clientDir) . '/' . rawurlencode($entry) . '/setup/' . rawurlencode($file); } if ($poster && $logo) break; } } $isHE = (stripos($entry, 'HE_') === 0); $foundProjects[$entry] = [ 'name' => $entry, 'path' => $entry, 'poster' => $poster, 'logo' => $logo, 'isHE' => $isHE, 'client' => $clientDisplay ]; } } return $foundProjects; } private static function sortProjectsByOrder($foundProjects, $projectOrder) { $projects = []; if (!empty($projectOrder)) { // First add projects in defined order foreach ($projectOrder as $orderedProject) { if (isset($foundProjects[$orderedProject])) { $projects[] = $foundProjects[$orderedProject]; unset($foundProjects[$orderedProject]); } } // New projects (not in order list) come at the BEGINNING $remainingProjects = array_values($foundProjects); usort($remainingProjects, function($a, $b) { return strcmp($a['name'], $b['name']); }); // Insert new projects BEFORE sorted ones $projects = array_merge($remainingProjects, $projects); } else { // Fallback: Alphabetical sorting $projects = array_values($foundProjects); usort($projects, function($a, $b) { return strcmp($a['name'], $b['name']); }); } return $projects; } private static function getExistingProjectNames($basePath) { $existingProjects = []; foreach (scandir($basePath) as $entry) { if ($entry === '.' || $entry === '..') continue; if (is_dir($basePath . '/' . $entry)) { $existingProjects[] = $entry; } } return $existingProjects; } }