from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from typing import List from app.database import get_db from app.schemas.admin import ( UserCreate, UserUpdate, UserInfo, UserListResponse, VMAccessCreate, VMAccessUpdate, VMAccessInfo, VMAccessListResponse, AdminResponse ) from app.schemas.auth import CurrentUser from app.api.auth import get_current_user from app.models.user import User, UserRole from app.models.vm import VMAccess from app.utils.security import hash_password from app.utils.exceptions import PermissionDeniedError, NotFoundError, BadRequestError router = APIRouter() def require_admin(current_user: CurrentUser = Depends(get_current_user)): """관리자 권한 확인""" if current_user.role != "admin": raise PermissionDeniedError("관리자 권한이 필요합니다") return current_user # ==================== 사용자 관리 ==================== @router.get("/users", response_model=UserListResponse) async def get_users( current_user: CurrentUser = Depends(require_admin), db: Session = Depends(get_db) ): """사용자 목록 조회""" users = db.query(User).all() user_list = [ UserInfo( id=user.id, username=user.username, email=user.email, full_name=user.full_name, role=user.role.value, is_active=user.is_active, created_at=user.created_at, last_login=user.last_login ) for user in users ] return UserListResponse(total=len(user_list), users=user_list) @router.post("/users", response_model=AdminResponse) async def create_user( user_data: UserCreate, current_user: CurrentUser = Depends(require_admin), db: Session = Depends(get_db) ): """사용자 생성""" # 중복 확인 if db.query(User).filter(User.username == user_data.username).first(): raise BadRequestError("이미 존재하는 사용자명입니다") if db.query(User).filter(User.email == user_data.email).first(): raise BadRequestError("이미 존재하는 이메일입니다") # 역할 유효성 검사 if user_data.role not in ["admin", "user"]: raise BadRequestError("역할은 'admin' 또는 'user'만 가능합니다") # 사용자 생성 new_user = User( username=user_data.username, email=user_data.email, hashed_password=hash_password(user_data.password), full_name=user_data.full_name, role=UserRole.ADMIN if user_data.role == "admin" else UserRole.USER, is_active=True ) db.add(new_user) db.commit() return AdminResponse( success=True, message=f"사용자 '{user_data.username}'이(가) 생성되었습니다" ) @router.put("/users/{user_id}", response_model=AdminResponse) async def update_user( user_id: int, user_data: UserUpdate, current_user: CurrentUser = Depends(require_admin), db: Session = Depends(get_db) ): """사용자 정보 수정""" user = db.query(User).filter(User.id == user_id).first() if not user: raise NotFoundError("사용자를 찾을 수 없습니다") # 이메일 중복 확인 if user_data.email and user_data.email != user.email: if db.query(User).filter(User.email == user_data.email).first(): raise BadRequestError("이미 존재하는 이메일입니다") user.email = user_data.email # 비밀번호 변경 if user_data.password: user.hashed_password = hash_password(user_data.password) # 기타 정보 업데이트 if user_data.full_name is not None: user.full_name = user_data.full_name if user_data.role: if user_data.role not in ["admin", "user"]: raise BadRequestError("역할은 'admin' 또는 'user'만 가능합니다") user.role = UserRole.ADMIN if user_data.role == "admin" else UserRole.USER if user_data.is_active is not None: user.is_active = user_data.is_active db.commit() return AdminResponse( success=True, message=f"사용자 '{user.username}'의 정보가 수정되었습니다" ) @router.delete("/users/{user_id}", response_model=AdminResponse) async def delete_user( user_id: int, current_user: CurrentUser = Depends(require_admin), db: Session = Depends(get_db) ): """사용자 삭제""" # 자기 자신은 삭제 불가 if user_id == current_user.id: raise BadRequestError("자기 자신은 삭제할 수 없습니다") user = db.query(User).filter(User.id == user_id).first() if not user: raise NotFoundError("사용자를 찾을 수 없습니다") username = user.username db.delete(user) db.commit() return AdminResponse( success=True, message=f"사용자 '{username}'이(가) 삭제되었습니다" ) # ==================== VM 접근 권한 관리 ==================== @router.get("/vm-access", response_model=VMAccessListResponse) async def get_vm_access_list( current_user: CurrentUser = Depends(require_admin), db: Session = Depends(get_db) ): """VM 접근 권한 목록 조회""" accesses = db.query(VMAccess).join(User).all() access_list = [ VMAccessInfo( id=access.id, user_id=access.user_id, username=access.user.username, vm_id=access.vm_id, node=access.node, vm_name=access.vm_name, static_ip=access.static_ip, rdp_username=access.rdp_username, rdp_port=access.rdp_port, is_active=access.is_active, created_at=access.created_at ) for access in accesses ] return VMAccessListResponse(total=len(access_list), accesses=access_list) @router.post("/vm-access", response_model=AdminResponse) async def create_vm_access( access_data: VMAccessCreate, current_user: CurrentUser = Depends(require_admin), db: Session = Depends(get_db) ): """VM 접근 권한 부여""" # 사용자 존재 확인 user = db.query(User).filter(User.id == access_data.user_id).first() if not user: raise NotFoundError("사용자를 찾을 수 없습니다") # 중복 확인 existing = db.query(VMAccess).filter( VMAccess.user_id == access_data.user_id, VMAccess.vm_id == access_data.vm_id ).first() if existing: raise BadRequestError("이미 해당 사용자에게 VM 접근 권한이 있습니다") # 권한 생성 access = VMAccess( user_id=access_data.user_id, vm_id=access_data.vm_id, node=access_data.node, static_ip=access_data.static_ip, rdp_username=access_data.rdp_username, rdp_password=access_data.rdp_password, rdp_port=access_data.rdp_port, is_active=True ) db.add(access) db.commit() return AdminResponse( success=True, message=f"사용자 '{user.username}'에게 VM {access_data.vm_id} 접근 권한이 부여되었습니다" ) @router.put("/vm-access/{access_id}", response_model=AdminResponse) async def update_vm_access( access_id: int, access_data: VMAccessUpdate, current_user: CurrentUser = Depends(require_admin), db: Session = Depends(get_db) ): """VM 접근 권한 수정""" access = db.query(VMAccess).filter(VMAccess.id == access_id).first() if not access: raise NotFoundError("접근 권한을 찾을 수 없습니다") # 정보 업데이트 if access_data.static_ip is not None: access.static_ip = access_data.static_ip if access_data.rdp_username is not None: access.rdp_username = access_data.rdp_username if access_data.rdp_password is not None: access.rdp_password = access_data.rdp_password if access_data.rdp_port is not None: access.rdp_port = access_data.rdp_port if access_data.is_active is not None: access.is_active = access_data.is_active db.commit() return AdminResponse( success=True, message=f"VM {access.vm_id} 접근 권한이 수정되었습니다" ) @router.delete("/vm-access/{access_id}", response_model=AdminResponse) async def delete_vm_access( access_id: int, current_user: CurrentUser = Depends(require_admin), db: Session = Depends(get_db) ): """VM 접근 권한 삭제""" access = db.query(VMAccess).filter(VMAccess.id == access_id).first() if not access: raise NotFoundError("접근 권한을 찾을 수 없습니다") vm_id = access.vm_id db.delete(access) db.commit() return AdminResponse( success=True, message=f"VM {vm_id} 접근 권한이 삭제되었습니다" )