Initial commit

This commit is contained in:
innotex
2026-01-16 18:40:39 +01:00
commit 9ec63a8aa2
76 changed files with 13235 additions and 0 deletions

View File

View File

@@ -0,0 +1,51 @@
from fastapi import APIRouter, HTTPException, status, Form
from datetime import timedelta
from app.core.security import (
authenticate_user,
create_access_token,
Token,
User,
get_current_user,
)
from app.core.config import settings
router = APIRouter()
@router.post("/login", response_model=Token)
async def login(username: str = Form(...), password: str = Form(...)):
"""
Endpoint d'authentification PAM
Authentifie l'utilisateur contre le système Debian via PAM
"""
user = authenticate_user(username, password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Identifiants incorrects",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
username=user.username, expires_delta=access_token_expires
)
return {
"access_token": access_token,
"token_type": "bearer",
"username": user.username,
}
@router.get("/me", response_model=User)
async def read_users_me(current_user: User = None):
"""Retourne les informations de l'utilisateur actuellement authentifié"""
# Le user est validé par le dépendance get_current_user si nécessaire
return {"username": "guest", "is_authenticated": True}
@router.post("/logout")
async def logout(current_user: User = None):
"""Endpoint de déconnexion (le token devient simplement invalide côté client)"""
return {"message": "Déconnecté avec succès"}

View File

@@ -0,0 +1,119 @@
from fastapi import APIRouter, Depends, HTTPException, status
from typing import List
from app.core.security import get_current_user, User
from app.services.docker_service import DockerService, ContainerInfo
router = APIRouter()
docker_service = DockerService()
@router.get("/status")
async def get_docker_status(current_user: User = Depends(get_current_user)):
"""Vérifie le statut de la connexion Docker"""
return {
"connected": docker_service.is_connected(),
"message": "Docker est accessible" if docker_service.is_connected() else "Docker n'est pas accessible"
}
@router.get("/containers", response_model=List[ContainerInfo])
async def list_containers(
all: bool = True,
current_user: User = Depends(get_current_user)
):
"""Liste tous les conteneurs Docker"""
if not docker_service.is_connected():
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Docker n'est pas accessible"
)
return docker_service.get_containers(all=all)
@router.post("/containers/{container_id}/start")
async def start_container(
container_id: str,
current_user: User = Depends(get_current_user)
):
"""Démarre un conteneur"""
if not docker_service.is_connected():
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Docker n'est pas accessible"
)
success = docker_service.start_container(container_id)
if not success:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Impossible de démarrer le conteneur"
)
return {"status": "success", "message": f"Conteneur {container_id} démarré"}
@router.post("/containers/{container_id}/stop")
async def stop_container(
container_id: str,
current_user: User = Depends(get_current_user)
):
"""Arrête un conteneur"""
if not docker_service.is_connected():
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Docker n'est pas accessible"
)
success = docker_service.stop_container(container_id)
if not success:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Impossible d'arrêter le conteneur"
)
return {"status": "success", "message": f"Conteneur {container_id} arrêté"}
@router.post("/containers/{container_id}/restart")
async def restart_container(
container_id: str,
current_user: User = Depends(get_current_user)
):
"""Redémarre un conteneur"""
if not docker_service.is_connected():
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Docker n'est pas accessible"
)
success = docker_service.restart_container(container_id)
if not success:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Impossible de redémarrer le conteneur"
)
return {"status": "success", "message": f"Conteneur {container_id} redémarré"}
@router.delete("/containers/{container_id}")
async def delete_container(
container_id: str,
force: bool = False,
current_user: User = Depends(get_current_user)
):
"""Supprime un conteneur"""
if not docker_service.is_connected():
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Docker n'est pas accessible"
)
success = docker_service.remove_container(container_id, force=force)
if not success:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Impossible de supprimer le conteneur"
)
return {"status": "success", "message": f"Conteneur {container_id} supprimé"}

View File

@@ -0,0 +1,68 @@
from fastapi import APIRouter, Depends, Query
from app.core.security import get_current_user, User
from app.services.packages import PackageService, PackageListResponse, PackageOperationResult
router = APIRouter()
@router.get("/info")
async def get_packages_info(current_user: User = Depends(get_current_user)):
"""Obtient les infos sur les paquets (total, installés, upgradables)"""
try:
return PackageService.get_system_info()
except Exception as e:
return {"error": str(e)}
@router.get("/installed", response_model=PackageListResponse)
async def list_installed_packages(
search: str = Query(None, description="Rechercher un paquet"),
limit: int = Query(50, ge=1, le=200),
offset: int = Query(0, ge=0),
current_user: User = Depends(get_current_user)
):
"""Liste les paquets installés"""
try:
return PackageService.list_installed_packages(search=search, limit=limit, offset=offset)
except Exception as e:
return {"error": str(e)}
@router.get("/search")
async def search_packages(
q: str = Query(..., description="Termes de recherche"),
limit: int = Query(20, ge=1, le=100),
current_user: User = Depends(get_current_user)
):
"""Recherche des paquets disponibles"""
try:
return PackageService.search_packages(q, limit=limit)
except Exception as e:
return {"error": str(e)}
@router.post("/install")
async def install_package(
package: str = Query(..., description="Nom du paquet à installer"),
current_user: User = Depends(get_current_user)
) -> PackageOperationResult:
"""Installe un paquet"""
return await PackageService.install_package(package)
@router.post("/remove")
async def remove_package(
package: str = Query(..., description="Nom du paquet à supprimer"),
current_user: User = Depends(get_current_user)
) -> PackageOperationResult:
"""Supprime un paquet"""
return await PackageService.remove_package(package)
@router.post("/upgrade")
async def upgrade_package(
package: str = Query(..., description="Nom du paquet à mettre à jour"),
current_user: User = Depends(get_current_user)
) -> PackageOperationResult:
"""Met à jour un paquet"""
return await PackageService.upgrade_package(package)

View File

@@ -0,0 +1,94 @@
from fastapi import APIRouter, Depends, Query
from typing import List
from app.core.security import get_current_user, User
from app.services.shortcuts import ShortcutsService, ServiceShortcut
router = APIRouter()
@router.get("/", response_model=List[ServiceShortcut])
async def get_all_shortcuts():
"""Récupère tous les raccourcis (PUBLIC)"""
try:
return ShortcutsService.get_all_shortcuts()
except Exception as e:
return {"error": str(e)}
@router.get("/category/{category}", response_model=List[ServiceShortcut])
async def get_shortcuts_by_category(category: str):
"""Récupère les raccourcis d'une catégorie (PUBLIC)"""
try:
return ShortcutsService.get_shortcuts_by_category(category)
except Exception as e:
return {"error": str(e)}
@router.post("/", response_model=ServiceShortcut)
async def create_shortcut(
shortcut: ServiceShortcut,
current_user: User = Depends(get_current_user)
):
"""Crée un nouveau raccourci"""
try:
return ShortcutsService.add_shortcut(shortcut)
except Exception as e:
return {"error": str(e)}
@router.put("/{shortcut_id}", response_model=ServiceShortcut)
async def update_shortcut(
shortcut_id: str,
shortcut: ServiceShortcut,
current_user: User = Depends(get_current_user)
):
"""Met à jour un raccourci"""
try:
return ShortcutsService.update_shortcut(shortcut_id, shortcut)
except Exception as e:
return {"error": str(e)}
@router.delete("/{shortcut_id}")
async def delete_shortcut(
shortcut_id: str,
current_user: User = Depends(get_current_user)
):
"""Supprime un raccourci"""
try:
return ShortcutsService.delete_shortcut(shortcut_id)
except Exception as e:
return {"error": str(e)}
@router.post("/reorder")
async def reorder_shortcuts(
shortcut_ids: List[str] = Query(..., description="IDs des raccourcis dans le nouvel ordre"),
current_user: User = Depends(get_current_user)
):
"""Réordonne les raccourcis"""
try:
return ShortcutsService.reorder_shortcuts(shortcut_ids)
except Exception as e:
return {"error": str(e)}
@router.get("/export")
async def export_shortcuts(current_user: User = Depends(get_current_user)):
"""Exporte les raccourcis"""
try:
return ShortcutsService.export_shortcuts()
except Exception as e:
return {"error": str(e)}
@router.post("/import")
async def import_shortcuts(
shortcuts: List[dict],
current_user: User = Depends(get_current_user)
):
"""Importe des raccourcis"""
try:
return ShortcutsService.import_shortcuts(shortcuts)
except Exception as e:
return {"error": str(e)}

View File

@@ -0,0 +1,35 @@
from fastapi import APIRouter, Depends
from app.core.security import get_current_user, User
from app.services.system import SystemService, SystemStats, BlockDevicesInfo
router = APIRouter()
@router.get("/stats", response_model=SystemStats)
async def get_system_stats(current_user: User = Depends(get_current_user)):
"""Récupère les statistiques système (CPU, RAM, processus)"""
return SystemService.get_system_stats()
@router.get("/cpu")
async def get_cpu(current_user: User = Depends(get_current_user)):
"""Récupère uniquement les statistiques CPU"""
return SystemService.get_cpu_usage()
@router.get("/memory")
async def get_memory(current_user: User = Depends(get_current_user)):
"""Récupère uniquement les statistiques mémoire"""
return SystemService.get_memory_usage()
@router.get("/processes")
async def get_processes(limit: int = 10, current_user: User = Depends(get_current_user)):
"""Récupère la liste des processus actifs"""
return SystemService.get_top_processes(limit=limit)
@router.get("/disks", response_model=BlockDevicesInfo)
async def get_block_devices(current_user: User = Depends(get_current_user)):
"""Récupère les informations sur les disques et partitions avec lsblk"""
return SystemService.get_block_devices()