Files
M-Project/backend/routers/page_permissions.py
Hyungi Ahn f6691730ce feat: 목록 관리 3개 하위 페이지 권한 시스템 구현
목록 관리를 수신함, 관리함, 폐기함 3개 하위 페이지로 세분화하고
각각 별도의 권한 관리가 가능하도록 시스템 구현

Backend Changes:
- page_permissions.py: issues_inbox, issues_management, issues_archive 권한 추가
- 수신함: 기본 접근 허용 (true)
- 관리함, 폐기함: 관리자 권한 필요 (false)

Frontend Changes:
- permissions.js: 3개 하위 페이지 권한 정의 추가
- common-header.js: 드롭다운 하위 메뉴 구조 구현
  * 데스크톱: 호버 드롭다운 메뉴
  * 모바일: 접을 수 있는 하위 메뉴
- admin.html: 권한 관리 UI에 새 페이지들 추가

Features:
- 권한별 하위 메뉴 필터링
- 반응형 드롭다운 메뉴
- 개별 페이지별 권한 제어
- 관리자 페이지에서 세부 권한 설정 가능

Next: 실제 페이지 파일 생성 및 기능 구현 예정
2025-10-25 09:24:32 +09:00

328 lines
11 KiB
Python

"""
페이지 권한 관리 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': True},
'issues_inbox': {'title': '수신함', 'default_access': True},
'issues_management': {'title': '관리함', 'default_access': False},
'issues_archive': {'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)
}