ProjectLinks::KINDS, ]); } $version = is_string(Http::input('integrated_version')) ? trim((string)Http::input('integrated_version')) : null; $links = new ProjectLinks($db); if (!$links->record($home, $target, $kind, $version !== '' ? $version : null)) { Http::fail(500, 'link_failed', 'Die Beziehung konnte nicht gespeichert werden.'); } Http::ok([ 'from_slug' => $home, 'to_slug' => $target, 'kind' => $kind, 'integrated_version' => $version, 'message' => $version !== null ? sprintf('"%s" nutzt "%s" in Fassung %s.', $home, $target, $version) : sprintf('Beziehung "%s" -> "%s" festgehalten.', $home, $target), ]); } $repo = new BugRepo($db); $projects = $repo->getProjects(); // Ein Laufzeit-Token sieht nur sein eigenes Projekt. Ein Werkbank-Token sieht // alle: es soll ja gerade entscheiden koennen, wohin ein Fehler gehoert - und // dafuer muss es die Nachbarn kennen. $bound = ApiAuth::projectFilter($context, true); if ($bound !== null) { $projects = array_values(array_filter( $projects, static fn(array $p): bool => (string)$p['slug'] === $bound )); } // Das Heimatprojekt bleibt auch beim Werkbank-Token bekannt. Es ist der // Bezugspunkt, gegen den die Beziehungen ausgewiesen werden. $home = ApiAuth::homeProject($context); $links = new ProjectLinks($db); Http::ok([ 'count' => count($projects), 'home_project' => $home, 'projects' => array_map(static function (array $p) use ($links, $home): array { $slug = (string)$p['slug']; return [ 'id' => (int)$p['id'], 'slug' => $slug, 'name' => (string)$p['name'], 'notes' => $p['notes'] ?? null, 'repo_url' => $p['repo_url'] ?? null, 'default_agent' => $p['default_agent'] ?? null, 'open_items' => (int)($p['open_items'] ?? 0), 'critical_items' => (int)($p['critical_items'] ?? 0), // Wie haengt dieses Projekt mit dem eigenen zusammen? null heisst // schlicht "gar nicht" und ist der Normalfall. 'relation' => $home !== null ? $links->between($home, $slug) : null, ]; }, $projects), ]);