from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException, Query, status from app.core.crypto import create_access_token from app.core.dependencies import get_current_user, require_superuser from app.modules.sync import repository as sync_repo from app.modules.sync.schemas import EnterpriseOut, FarmHubOut from app.modules.users.models import User router = APIRouter() @router.get("/enterprises") def list_enterprises(user: User = Depends(get_current_user)): # Superuser sees all; regular users see memberships only (simplified v1) if user.is_superuser: from sqlalchemy import select from app.core.database import session_scope from app.modules.sync.models import Enterprise with session_scope() as db: rows = list(db.scalars(select(Enterprise).order_by(Enterprise.name))) return [ EnterpriseOut(id=r.id, name=r.name, slug=r.slug, status=r.status).model_dump() for r in rows ] from sqlalchemy import select from app.core.database import session_scope from app.modules.sync.models import Enterprise, EnterpriseMember with session_scope() as db: rows = list( db.scalars( select(Enterprise) .join(EnterpriseMember, EnterpriseMember.enterprise_id == Enterprise.id) .where(EnterpriseMember.user_id == user.id) ) ) return [EnterpriseOut(id=r.id, name=r.name, slug=r.slug, status=r.status).model_dump() for r in rows] @router.post("/enterprises") def create_enterprise(body: dict, _: User = Depends(require_superuser)): ent = sync_repo.create_enterprise(body["name"], body["slug"]) return EnterpriseOut(id=ent.id, name=ent.name, slug=ent.slug, status=ent.status).model_dump() @router.get("/enterprises/{enterprise_id}/farms") def list_farms(enterprise_id: str, user: User = Depends(get_current_user)): member = sync_repo.get_member(user.id, enterprise_id) if not member and not user.is_superuser: from fastapi import HTTPException, status raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_FORBIDDEN") hubs = sync_repo.list_farm_hubs(enterprise_id) return [ FarmHubOut( id=h.id, enterprise_id=h.enterprise_id, name=h.name, hub_site_id=h.hub_site_id, url=h.url, status=h.status, last_seen=h.last_seen, wesp_version=h.wesp_version, ).model_dump() for h in hubs ] @router.post("/enterprises/{enterprise_id}/session") def enterprise_session(enterprise_id: str, user: User = Depends(get_current_user)): member = sync_repo.get_member(user.id, enterprise_id) if not member and not user.is_superuser: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_FORBIDDEN") role = member.role if member else "admin" farm_ids = None if role == "admin" else sync_repo.list_farm_access(user.id, enterprise_id) token = create_access_token( user.id, user.role, user.is_superuser, enterprise_id=enterprise_id, enterprise_role=role, farm_ids=farm_ids, ) return { "access_token": token, "enterprise_id": enterprise_id, "enterprise_role": role, "farm_ids": farm_ids, } @router.get("/enterprises/{enterprise_id}/sync-status") def enterprise_sync_status(enterprise_id: str, user: User = Depends(get_current_user)): member = sync_repo.get_member(user.id, enterprise_id) if not member and not user.is_superuser: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_FORBIDDEN") from app.modules.sync.service import get_sync_metrics return get_sync_metrics(enterprise_id) @router.get("/enterprises/{enterprise_id}/members") def list_members(enterprise_id: str, user: User = Depends(get_current_user)): member = sync_repo.get_member(user.id, enterprise_id) if not member or member.role != "admin": if not user.is_superuser: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_ADMIN_ONLY") from app.modules.users.repository import get_user_by_id rows = sync_repo.list_members(enterprise_id) return [ { "user_id": m.user_id, "role": m.role, "email": (get_user_by_id(m.user_id).email if get_user_by_id(m.user_id) else None), "farm_ids": sync_repo.list_farm_access(m.user_id, enterprise_id), } for m in rows ] @router.post("/enterprises/{enterprise_id}/members") def add_enterprise_member(enterprise_id: str, body: dict, user: User = Depends(get_current_user)): member = sync_repo.get_member(user.id, enterprise_id) if not member or member.role != "admin": if not user.is_superuser: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_ADMIN_ONLY") from app.modules.users.repository import get_user_by_email target = get_user_by_email(body["email"].strip().lower()) if not target: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="USER_NOT_FOUND") existing = sync_repo.get_member(target.id, enterprise_id) if existing: sync_repo.set_member_role(target.id, enterprise_id, body.get("role", existing.role)) else: sync_repo.add_member(target.id, enterprise_id, body.get("role", "viewer")) for farm_id in body.get("farm_ids") or []: sync_repo.grant_farm_access(target.id, farm_id) return {"status": "ok", "user_id": target.id} @router.post("/enterprises/{enterprise_id}/farm-access") def grant_farm_access(enterprise_id: str, body: dict, user: User = Depends(get_current_user)): member = sync_repo.get_member(user.id, enterprise_id) if not member or member.role != "admin": if not user.is_superuser: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="ENTERPRISE_ADMIN_ONLY") sync_repo.grant_farm_access(body["user_id"], body["farm_hub_id"]) return {"status": "ok"}