feat: 사용자별 페이지 접근 권한 시스템 구현
- 기존 4단계 권한을 admin/user 2단계로 단순화 - 페이지별 세부 접근 권한 관리 시스템 추가 - 부적합 조회 시 일반 사용자는 본인 등록 건만 조회 가능하도록 제한 - 관리자 전용 전체 부적합 조회 API 추가 (/api/issues/admin/all) Backend Changes: - models.py: UserPagePermission 모델 추가, UserRole 단순화 - page_permissions.py: 페이지 권한 관리 API 라우터 추가 - auth.py: 사용자 목록 조회 및 비밀번호 초기화 API 추가 - issues.py: 권한별 부적합 조회 제한 로직 구현 - 마이그레이션: 010~012 권한 시스템 관련 DB 스키마 변경
This commit is contained in:
324
backend/routers/page_permissions.py
Normal file
324
backend/routers/page_permissions.py
Normal file
@@ -0,0 +1,324 @@
|
||||
"""
|
||||
페이지 권한 관리 API 라우터
|
||||
사용자별 페이지 접근 권한을 관리하는 엔드포인트들
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
from database.database import get_db
|
||||
from database.models import User, UserPagePermission, UserRole
|
||||
from routers.auth import get_current_user
|
||||
|
||||
router = APIRouter(prefix="/api", tags=["page-permissions"])
|
||||
|
||||
# Pydantic 모델들
|
||||
class PagePermissionRequest(BaseModel):
|
||||
user_id: int
|
||||
page_name: str
|
||||
can_access: bool
|
||||
notes: Optional[str] = None
|
||||
|
||||
class PagePermissionResponse(BaseModel):
|
||||
id: int
|
||||
user_id: int
|
||||
page_name: str
|
||||
can_access: bool
|
||||
granted_by_id: Optional[int]
|
||||
granted_at: str
|
||||
notes: Optional[str]
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
class UserPagePermissionSummary(BaseModel):
|
||||
user_id: int
|
||||
username: str
|
||||
full_name: Optional[str]
|
||||
role: str
|
||||
permissions: List[PagePermissionResponse]
|
||||
|
||||
# 기본 페이지 목록
|
||||
DEFAULT_PAGES = {
|
||||
'issues_create': {'title': '부적합 등록', 'default_access': True},
|
||||
'issues_view': {'title': '부적합 조회', 'default_access': True},
|
||||
'issues_manage': {'title': '부적합 관리', 'default_access': False},
|
||||
'projects_manage': {'title': '프로젝트 관리', 'default_access': False},
|
||||
'daily_work': {'title': '일일 공수', 'default_access': False},
|
||||
'reports': {'title': '보고서', 'default_access': False}
|
||||
}
|
||||
|
||||
@router.post("/page-permissions/grant")
|
||||
async def grant_page_permission(
|
||||
request: PagePermissionRequest,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""페이지 권한 부여/취소"""
|
||||
|
||||
# 관리자만 권한 설정 가능
|
||||
if current_user.role != UserRole.admin:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="관리자만 권한을 설정할 수 있습니다."
|
||||
)
|
||||
|
||||
# 대상 사용자 확인
|
||||
target_user = db.query(User).filter(User.id == request.user_id).first()
|
||||
if not target_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="사용자를 찾을 수 없습니다."
|
||||
)
|
||||
|
||||
# 유효한 페이지명 확인
|
||||
if request.page_name not in DEFAULT_PAGES:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="유효하지 않은 페이지명입니다."
|
||||
)
|
||||
|
||||
# 기존 권한 확인
|
||||
existing_permission = db.query(UserPagePermission).filter(
|
||||
UserPagePermission.user_id == request.user_id,
|
||||
UserPagePermission.page_name == request.page_name
|
||||
).first()
|
||||
|
||||
if existing_permission:
|
||||
# 기존 권한 업데이트
|
||||
existing_permission.can_access = request.can_access
|
||||
existing_permission.granted_by_id = current_user.id
|
||||
existing_permission.notes = request.notes
|
||||
db.commit()
|
||||
db.refresh(existing_permission)
|
||||
return {"message": "권한이 업데이트되었습니다.", "permission_id": existing_permission.id}
|
||||
else:
|
||||
# 새 권한 생성
|
||||
new_permission = UserPagePermission(
|
||||
user_id=request.user_id,
|
||||
page_name=request.page_name,
|
||||
can_access=request.can_access,
|
||||
granted_by_id=current_user.id,
|
||||
notes=request.notes
|
||||
)
|
||||
db.add(new_permission)
|
||||
db.commit()
|
||||
db.refresh(new_permission)
|
||||
return {"message": "권한이 설정되었습니다.", "permission_id": new_permission.id}
|
||||
|
||||
@router.get("/users/{user_id}/page-permissions", response_model=List[PagePermissionResponse])
|
||||
async def get_user_page_permissions(
|
||||
user_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""특정 사용자의 페이지 권한 목록 조회"""
|
||||
|
||||
# 관리자이거나 본인의 권한만 조회 가능
|
||||
if current_user.role != UserRole.admin and current_user.id != user_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="권한이 없습니다."
|
||||
)
|
||||
|
||||
# 사용자 존재 확인
|
||||
user = db.query(User).filter(User.id == user_id).first()
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="사용자를 찾을 수 없습니다."
|
||||
)
|
||||
|
||||
# 사용자의 페이지 권한 조회
|
||||
permissions = db.query(UserPagePermission).filter(
|
||||
UserPagePermission.user_id == user_id
|
||||
).all()
|
||||
|
||||
return permissions
|
||||
|
||||
@router.get("/page-permissions/check/{user_id}/{page_name}")
|
||||
async def check_page_access(
|
||||
user_id: int,
|
||||
page_name: str,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""특정 사용자의 특정 페이지 접근 권한 확인"""
|
||||
|
||||
# 사용자 존재 확인
|
||||
user = db.query(User).filter(User.id == user_id).first()
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="사용자를 찾을 수 없습니다."
|
||||
)
|
||||
|
||||
# admin은 모든 페이지 접근 가능
|
||||
if user.role == UserRole.admin:
|
||||
return {"can_access": True, "reason": "admin_role"}
|
||||
|
||||
# 유효한 페이지명 확인
|
||||
if page_name not in DEFAULT_PAGES:
|
||||
return {"can_access": False, "reason": "invalid_page"}
|
||||
|
||||
# 개별 권한 확인
|
||||
permission = db.query(UserPagePermission).filter(
|
||||
UserPagePermission.user_id == user_id,
|
||||
UserPagePermission.page_name == page_name
|
||||
).first()
|
||||
|
||||
if permission:
|
||||
return {
|
||||
"can_access": permission.can_access,
|
||||
"reason": "explicit_permission",
|
||||
"granted_at": permission.granted_at.isoformat() if permission.granted_at else None
|
||||
}
|
||||
|
||||
# 기본 권한 확인
|
||||
default_access = DEFAULT_PAGES[page_name]['default_access']
|
||||
return {
|
||||
"can_access": default_access,
|
||||
"reason": "default_permission"
|
||||
}
|
||||
|
||||
@router.get("/page-permissions/all-users", response_model=List[UserPagePermissionSummary])
|
||||
async def get_all_users_permissions(
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""모든 사용자의 페이지 권한 요약 조회 (관리자용)"""
|
||||
|
||||
if current_user.role != UserRole.admin:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="관리자만 접근할 수 있습니다."
|
||||
)
|
||||
|
||||
# 모든 사용자 조회
|
||||
users = db.query(User).filter(User.is_active == True).all()
|
||||
|
||||
result = []
|
||||
for user in users:
|
||||
# 각 사용자의 권한 조회
|
||||
permissions = db.query(UserPagePermission).filter(
|
||||
UserPagePermission.user_id == user.id
|
||||
).all()
|
||||
|
||||
result.append(UserPagePermissionSummary(
|
||||
user_id=user.id,
|
||||
username=user.username,
|
||||
full_name=user.full_name,
|
||||
role=user.role.value,
|
||||
permissions=permissions
|
||||
))
|
||||
|
||||
return result
|
||||
|
||||
@router.get("/page-permissions/available-pages")
|
||||
async def get_available_pages(
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""사용 가능한 페이지 목록 조회"""
|
||||
|
||||
return {
|
||||
"pages": DEFAULT_PAGES,
|
||||
"total_count": len(DEFAULT_PAGES)
|
||||
}
|
||||
|
||||
@router.delete("/page-permissions/{permission_id}")
|
||||
async def delete_page_permission(
|
||||
permission_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""페이지 권한 삭제 (기본값으로 되돌림)"""
|
||||
|
||||
if current_user.role != UserRole.admin:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="관리자만 권한을 삭제할 수 있습니다."
|
||||
)
|
||||
|
||||
# 권한 조회
|
||||
permission = db.query(UserPagePermission).filter(
|
||||
UserPagePermission.id == permission_id
|
||||
).first()
|
||||
|
||||
if not permission:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="권한을 찾을 수 없습니다."
|
||||
)
|
||||
|
||||
# 권한 삭제
|
||||
db.delete(permission)
|
||||
db.commit()
|
||||
|
||||
return {"message": "권한이 삭제되었습니다. 기본값이 적용됩니다."}
|
||||
|
||||
class BulkPermissionRequest(BaseModel):
|
||||
user_id: int
|
||||
permissions: List[dict] # [{"page_name": "issues_manage", "can_access": true}, ...]
|
||||
|
||||
@router.post("/page-permissions/bulk-grant")
|
||||
async def bulk_grant_permissions(
|
||||
request: BulkPermissionRequest,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""사용자의 여러 페이지 권한을 일괄 설정"""
|
||||
|
||||
if current_user.role != UserRole.admin:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="관리자만 권한을 설정할 수 있습니다."
|
||||
)
|
||||
|
||||
# 대상 사용자 확인
|
||||
target_user = db.query(User).filter(User.id == request.user_id).first()
|
||||
if not target_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="사용자를 찾을 수 없습니다."
|
||||
)
|
||||
|
||||
updated_permissions = []
|
||||
|
||||
for perm_data in request.permissions:
|
||||
page_name = perm_data.get('page_name')
|
||||
can_access = perm_data.get('can_access', False)
|
||||
|
||||
# 유효한 페이지명 확인
|
||||
if page_name not in DEFAULT_PAGES:
|
||||
continue
|
||||
|
||||
# 기존 권한 확인
|
||||
existing_permission = db.query(UserPagePermission).filter(
|
||||
UserPagePermission.user_id == request.user_id,
|
||||
UserPagePermission.page_name == page_name
|
||||
).first()
|
||||
|
||||
if existing_permission:
|
||||
# 기존 권한 업데이트
|
||||
existing_permission.can_access = can_access
|
||||
existing_permission.granted_by_id = current_user.id
|
||||
updated_permissions.append(existing_permission)
|
||||
else:
|
||||
# 새 권한 생성
|
||||
new_permission = UserPagePermission(
|
||||
user_id=request.user_id,
|
||||
page_name=page_name,
|
||||
can_access=can_access,
|
||||
granted_by_id=current_user.id
|
||||
)
|
||||
db.add(new_permission)
|
||||
updated_permissions.append(new_permission)
|
||||
|
||||
db.commit()
|
||||
|
||||
return {
|
||||
"message": f"{len(updated_permissions)}개의 권한이 설정되었습니다.",
|
||||
"updated_count": len(updated_permissions)
|
||||
}
|
||||
Reference in New Issue
Block a user