from fastapi import APIRouter, Depends, HTTPException from service_auth import UserId from auth_config import Caller, auth from db_module import get_db from models import RepositoryUpdate, SubscribedRepository, SubscribedRepositoryList from repositories import ( validate_repository_combination_and_return_latest_tag, ) from simple_logger_handler import setup_logger logger = setup_logger(__name__) user_router = APIRouter(dependencies=[Depends(auth.require(Caller.GATEWAY))]) @user_router.post("/repository/add") def add_repository_subscription( user_id: UserId, repository: RepositoryUpdate, db=Depends(get_db), ): name = f"{repository.org}/{repository.repo}:{repository.tag}" logger.info(f"[FastAPI] Subscribe request: {repository.type.value} {name}, user_id={user_id}") with db.cursor() as cursor: cursor.execute( "SELECT id, active FROM watched_repositories " "WHERE type = %s AND org = %s AND repo = %s AND tag = %s", (repository.type.value, repository.org, repository.repo, repository.tag), ) known = cursor.fetchone() latest_entry = None if known is None or not known[1]: latest_entry = validate_repository_combination_and_return_latest_tag(repository) try: with db.cursor() as cursor: cursor.execute( "INSERT INTO watched_repositories (type, org, repo, tag, latest_entry) " "VALUES (%s, %s, %s, %s, %s) " "ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id), active = 1, missing_checks = 0, " "latest_entry = COALESCE(VALUES(latest_entry), latest_entry)", (repository.type.value, repository.org, repository.repo, repository.tag, latest_entry), ) repository_id = cursor.lastrowid cursor.execute( "INSERT INTO watched_repositories_subscriptions (user_id, repository_id, custom_name) " "VALUES (%s, %s, %s) " "ON DUPLICATE KEY UPDATE active = 1, custom_name = VALUES(custom_name)", (user_id, repository_id, repository.custom_name), ) db.commit() except Exception as e: db.rollback() logger.exception(f"[FastAPI] Failed to subscribe user_id={user_id} to {name}") raise HTTPException(status_code=500) from e logger.info(f"[FastAPI] user_id={user_id} subscribed to repository ID {repository_id} ({name})") return {"status": "ok", "detail": "Subscribed to repository", "name": name} @user_router.post("/repository/delete") def delete_repository_subscription( user_id: UserId, repository: RepositoryUpdate, db=Depends(get_db), ): name = f"{repository.org}/{repository.repo}:{repository.tag}" logger.info(f"[FastAPI] Unsubscribe request: {repository.type.value} {name}, user_id={user_id}") try: with db.cursor() as cursor: cursor.execute( "SELECT id FROM watched_repositories " "WHERE type = %s AND org = %s AND repo = %s AND tag = %s FOR UPDATE", (repository.type.value, repository.org, repository.repo, repository.tag), ) known = cursor.fetchone() if known is None: db.rollback() logger.info(f"[FastAPI] Repository {repository.type.value} {name} is not tracked, nothing to do") return {"status":"ok","detail":"Unsubscribed from repository","name":name} repository_id = known[0] cursor.execute( "UPDATE watched_repositories_subscriptions SET active = 0 " "WHERE user_id = %s AND repository_id = %s", (user_id, repository_id), ) cursor.execute( "SELECT 1 from watched_repositories_subscriptions " "WHERE repository_id = %s AND active = 1 LIMIT 1 FOR SHARE", (repository_id,), ) if cursor.fetchone() is None: cursor.execute( "UPDATE watched_repositories SET active = 0 WHERE id = %s", (repository_id,), ) db.commit() except Exception as e: db.rollback() logger.exception(f"[FastAPI] Failed to unsubscribe user_id={user_id} to {name}") raise HTTPException(status_code=500) from e logger.info(f"[FastAPI] Unsubscribe request successful: {repository.type.value} {name}, user_id={user_id}") return {"status":"ok","detail":"Unsubscribed from repository","name":name} @user_router.get("/repository/list") def list_subscribed_repositories( user_id: UserId, db = Depends(get_db), ): logger.info(f"[FastAPI] Received request to list repositories for user_id={user_id}") try: with db.cursor() as cursor: cursor.execute( "select w.type, w.org, w.repo, w.tag, w.latest_entry, s.custom_name, s.active from watched_repositories " "AS w JOIN watched_repositories_subscriptions AS s ON w.id = s.repository_id " "WHERE s.user_id = %s ORDER BY w.type", (user_id,), ) rows = cursor.fetchall() repository_list = SubscribedRepositoryList() for type, org, repo, tag, latest_entry, custom_name, is_active in rows: entry = SubscribedRepository( type = type, repository_name = custom_name or f"{org}/{repo}", tag = tag, latest_entry = latest_entry, ) (repository_list.active if is_active else repository_list.inactive).append(entry) except Exception as e: logger.exception("[FastAPI] Failed to list repository") raise HTTPException(status_code=500) from e logger.info(f"[FastAPI] Listed all repositories for user_id={user_id}") return repository_list