Files
vconnect-api/app/api/admin.py
2025-12-08 21:35:55 +09:00

276 lines
8.7 KiB
Python

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} 접근 권한이 삭제되었습니다"
)