import httpx import os from pathlib import Path from fastapi import APIRouter, HTTPException from pydantic import BaseModel router = APIRouter() class SubscribeRequest(BaseModel): """Schema für Subscription Request""" repo_url: str target_name: str = "imported-repo" token_provided: str | None = None class UnsubscribeRequest(BaseModel): """Schema fuer Deabonination""" project_name: str @router.get("/projects") #✅ Listet abonierte Projekte! async def list_projects(): """Listet lokale (abonierte) Projekte an.""" from .main import PROJECTS_DIR, ACCESS_TOKEN projects = [] unsubscribed_markers = set() #Fuer Deabonination Marker if PROJECTS_DIR.exists() and str(PROJECTS_DIR).strip(): # Suche nach .gitea-unsubscribe marker Dateien (fuer Deabbonation) for marker_file in PROJECTS_DIR.glob(".*.unsubscribe"): project_name = marker_file.stem.replace(".gitea-unsubscribe", "") unsubscribed_markers.add(project_name) if PROJECTS_DIR.exists() and str(PROJECTS_DIR).strip(): # Sortiere: Abonnierte zuerst, dann alphabtsortiert all_projects = [] for project_dir in sorted(PROJECTS_DIR.iterdir()): if project_dir.is_dir() and not project_dir.name.startswith('.'): has_git = (project_dir / '.git').exists() changes_marker = Path(project_dir / ".gitea-changes.marker") has_changes = changes_marker.exists() all_projects.append({ "name": project_dir.name, "path": str(project_dir), "subscribed": True, "has_git": bool(has_git), "has_undiscovered_changes": has_changes, "_sort_priority": 0 if not has_changes else 1 # ohne changes = priority höher (kommt zuerst) }) # Sortiere nach Changes-Status zuerst, dann alphabetisch projects = sorted(all_projects, key=lambda x: (-x["_sort_priority"], x["name"])) # Entferne Hilfsfeld für API-Ausgabe for p in projects: del p["_sort_priority"] return {"projects": projects} @router.post("/unsubscribe") #❌ NEU: Deabonination Endpoint! async def unsubscribe_repo(req: UnsubscribeRequest): """Loeschen eines abonnierten Projekts.""" from .main import PROJECTS_DIR target_dir = PROJECTS_DIR / req.project_name if not target_dir.exists(): return {"success": False, "error": f"Projekt '{req.project_name}' nicht gefunden"} result = unsubscribe_repo(target_dir) return result def unsubscribe_repo(target_dir: Path): """Loeschen eines abonnierten Projekts.""" import shutil if not target_dir.exists(): return {"success": False, "error": "Projekt nicht gefunden"} try: shutil.rmtree(str(target_dir)) marker_file = Path(str(target_dir) + ".unsubscribe") marker_file.touch() return {"success": True, "message": f"{target_dir.name} erfolgreich geloescht"} except Exception as e: return {"success": False, "error": str(e)} @router.get("/repos") # Listet Gitea-Repos! async def list_repos(): """Listet Repositories von Gitea auf.""" from .main import GITEE_URL, ACCESS_TOKEN token = ACCESS_TOKEN or "" if not token: return {"error": "Kein Token vorhanden!", "hint": "Setze ACCESS_TOKEN Umgebungsvariable"} headers = {"Authorization": f"token {token}"} async with httpx.AsyncClient() as client: resp = await client.get(f"{GITEE_URL}/api/v1/user/repos", headers=headers) return resp.json() @router.post("/subscribe") # Klont Repo! async def subscribe_repo(req: SubscribeRequest): """Abonniert und klont ein Repository.""" from .main import ACCESS_TOKEN effective_token = req.token_provided or ACCESS_TOKEN or "" if not effective_token: raise HTTPException(status_code=401, detail="Kein TOKEN vorhanden! Bitte setze ACCESS_TOKEN Umgebungsvariable.") target_dir = Path("/projects") / req.target_name result = clone_repo(req.repo_url, target_dir, token=effective_token) if not result["success"]: return {"error": result.get("error"), "success": False} (target_dir / ".gitea-changes.marker").touch() generate_changelog(target_dir) # Loesche Deabonination-Marker wenn Projekt wieder abonniert wurde marker_file = Path(str(target_dir) + ".unsubscribe") if marker_file.exists(): marker_file.unlink() return { "message": f"✅ {req.target_name} geklont!", "path": str(target_dir), "success": True, "token_used": bool(effective_token and not req.token_provided) } # Importiere die Funktionen am Ende damit sie verfügbar sind! from .git_manager import clone_repo from .changelog_gen import generate_changelog