- 일일 공수 입력 기능 - 부적합 사항 등록 (이미지 선택사항) - 날짜별 부적합 조회 (시간순 나열) - 목록 관리 (인라인 편집, 작업시간 확인 버튼) - 보고서 생성 (총 공수/부적합 시간 분리) - JWT 인증 및 권한 관리 - Docker 기반 배포 환경 구성
165 lines
5.1 KiB
Python
165 lines
5.1 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from sqlalchemy.orm import Session
|
|
from typing import List, Optional
|
|
from datetime import datetime
|
|
|
|
from database.database import get_db
|
|
from database.models import Issue, IssueStatus, User, UserRole
|
|
from database import schemas
|
|
from routers.auth import get_current_user
|
|
from services.file_service import save_base64_image, delete_file
|
|
|
|
router = APIRouter(prefix="/api/issues", tags=["issues"])
|
|
|
|
@router.post("/", response_model=schemas.Issue)
|
|
async def create_issue(
|
|
issue: schemas.IssueCreate,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
# 이미지 저장
|
|
photo_path = None
|
|
if issue.photo:
|
|
photo_path = save_base64_image(issue.photo)
|
|
|
|
# Issue 생성
|
|
db_issue = Issue(
|
|
category=issue.category,
|
|
description=issue.description,
|
|
photo_path=photo_path,
|
|
reporter_id=current_user.id,
|
|
status=IssueStatus.NEW
|
|
)
|
|
db.add(db_issue)
|
|
db.commit()
|
|
db.refresh(db_issue)
|
|
return db_issue
|
|
|
|
@router.get("/", response_model=List[schemas.Issue])
|
|
async def read_issues(
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
status: Optional[IssueStatus] = None,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
query = db.query(Issue)
|
|
|
|
# 일반 사용자는 자신의 이슈만 조회
|
|
if current_user.role == UserRole.USER:
|
|
query = query.filter(Issue.reporter_id == current_user.id)
|
|
|
|
if status:
|
|
query = query.filter(Issue.status == status)
|
|
|
|
issues = query.offset(skip).limit(limit).all()
|
|
return issues
|
|
|
|
@router.get("/{issue_id}", response_model=schemas.Issue)
|
|
async def read_issue(
|
|
issue_id: int,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
issue = db.query(Issue).filter(Issue.id == issue_id).first()
|
|
if not issue:
|
|
raise HTTPException(status_code=404, detail="Issue not found")
|
|
|
|
# 권한 확인
|
|
if current_user.role == UserRole.USER and issue.reporter_id != current_user.id:
|
|
raise HTTPException(status_code=403, detail="Not authorized to view this issue")
|
|
|
|
return issue
|
|
|
|
@router.put("/{issue_id}", response_model=schemas.Issue)
|
|
async def update_issue(
|
|
issue_id: int,
|
|
issue_update: schemas.IssueUpdate,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
issue = db.query(Issue).filter(Issue.id == issue_id).first()
|
|
if not issue:
|
|
raise HTTPException(status_code=404, detail="Issue not found")
|
|
|
|
# 권한 확인
|
|
if current_user.role == UserRole.USER and issue.reporter_id != current_user.id:
|
|
raise HTTPException(status_code=403, detail="Not authorized to update this issue")
|
|
|
|
# 업데이트
|
|
update_data = issue_update.dict(exclude_unset=True)
|
|
|
|
# 사진이 업데이트되는 경우 처리
|
|
if "photo" in update_data:
|
|
# 기존 사진 삭제
|
|
if issue.photo_path:
|
|
delete_file(issue.photo_path)
|
|
|
|
# 새 사진 저장
|
|
if update_data["photo"]:
|
|
photo_path = save_base64_image(update_data["photo"])
|
|
update_data["photo_path"] = photo_path
|
|
else:
|
|
update_data["photo_path"] = None
|
|
|
|
# photo 필드는 제거 (DB에는 photo_path만 저장)
|
|
del update_data["photo"]
|
|
|
|
# work_hours가 입력되면 자동으로 상태를 complete로 변경
|
|
if "work_hours" in update_data and update_data["work_hours"] > 0:
|
|
if issue.status == IssueStatus.NEW:
|
|
update_data["status"] = IssueStatus.COMPLETE
|
|
|
|
for field, value in update_data.items():
|
|
setattr(issue, field, value)
|
|
|
|
db.commit()
|
|
db.refresh(issue)
|
|
return issue
|
|
|
|
@router.delete("/{issue_id}")
|
|
async def delete_issue(
|
|
issue_id: int,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
issue = db.query(Issue).filter(Issue.id == issue_id).first()
|
|
if not issue:
|
|
raise HTTPException(status_code=404, detail="Issue not found")
|
|
|
|
# 권한 확인 (관리자만 삭제 가능)
|
|
if current_user.role != UserRole.ADMIN:
|
|
raise HTTPException(status_code=403, detail="Only admin can delete issues")
|
|
|
|
# 이미지 파일 삭제
|
|
if issue.photo_path:
|
|
delete_file(issue.photo_path)
|
|
|
|
db.delete(issue)
|
|
db.commit()
|
|
return {"detail": "Issue deleted successfully"}
|
|
|
|
@router.get("/stats/summary")
|
|
async def get_issue_stats(
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""이슈 통계 조회"""
|
|
query = db.query(Issue)
|
|
|
|
# 일반 사용자는 자신의 이슈만
|
|
if current_user.role == UserRole.USER:
|
|
query = query.filter(Issue.reporter_id == current_user.id)
|
|
|
|
total = query.count()
|
|
new = query.filter(Issue.status == IssueStatus.NEW).count()
|
|
progress = query.filter(Issue.status == IssueStatus.PROGRESS).count()
|
|
complete = query.filter(Issue.status == IssueStatus.COMPLETE).count()
|
|
|
|
return {
|
|
"total": total,
|
|
"new": new,
|
|
"progress": progress,
|
|
"complete": complete
|
|
}
|