feat: 사진 업로드 기능 개선 및 카테고리 업데이트

- 사진 2장까지 업로드 지원
- 카메라 촬영 + 갤러리 선택 분리
- 이미지 압축 및 최적화 (ImageUtils)
- iPhone .mpo 파일 JPEG 변환 지원
- 카테고리 변경: 치수불량 → 설계미스, 검사미스 추가
- KST 시간대 설정
- URL 해시 처리로 목록관리 페이지 이동 개선
- 로그인 OAuth2 form-data 형식 수정
- 업로드 속도 개선 및 프로그레스바 추가
This commit is contained in:
hyungi
2025-09-18 07:00:28 +09:00
parent f6bdb68d19
commit 44e2fb2e44
32 changed files with 988 additions and 177 deletions

View File

@@ -29,7 +29,7 @@ async def get_current_user(token: str = Depends(oauth2_scheme), db: Session = De
return user
async def get_current_admin(current_user: User = Depends(get_current_user)):
if current_user.role != UserRole.ADMIN:
if current_user.role != UserRole.admin:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Not enough permissions"
@@ -37,8 +37,8 @@ async def get_current_admin(current_user: User = Depends(get_current_user)):
return current_user
@router.post("/login", response_model=schemas.Token)
async def login(login_data: schemas.LoginRequest, db: Session = Depends(get_db)):
user = authenticate_user(db, login_data.username, login_data.password)
async def login(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)):
user = authenticate_user(db, form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,

View File

@@ -1,10 +1,10 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List, Optional
from datetime import datetime, date
from datetime import datetime, date, timezone, timedelta
from database.database import get_db
from database.models import DailyWork, User, UserRole
from database.models import DailyWork, User, UserRole, KST
from database import schemas
from routers.auth import get_current_user
@@ -120,7 +120,7 @@ async def delete_daily_work(
raise HTTPException(status_code=404, detail="Daily work not found")
# 권한 확인 (관리자만 삭제 가능)
if current_user.role != UserRole.ADMIN:
if current_user.role != UserRole.admin:
raise HTTPException(status_code=403, detail="Only admin can delete daily work")
db.delete(work)

View File

@@ -19,16 +19,22 @@ async def create_issue(
):
# 이미지 저장
photo_path = None
photo_path2 = None
if issue.photo:
photo_path = save_base64_image(issue.photo)
if issue.photo2:
photo_path2 = save_base64_image(issue.photo2)
# Issue 생성
db_issue = Issue(
category=issue.category,
description=issue.description,
photo_path=photo_path,
photo_path2=photo_path2,
reporter_id=current_user.id,
status=IssueStatus.NEW
status=IssueStatus.new
)
db.add(db_issue)
db.commit()
@@ -45,9 +51,8 @@ async def read_issues(
):
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)
@@ -65,9 +70,7 @@ async def read_issue(
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
@@ -83,13 +86,13 @@ async def update_issue(
raise HTTPException(status_code=404, detail="Issue not found")
# 권한 확인
if current_user.role == UserRole.USER and issue.reporter_id != current_user.id:
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:
@@ -105,10 +108,26 @@ async def update_issue(
# photo 필드는 제거 (DB에는 photo_path만 저장)
del update_data["photo"]
# 두 번째 사진이 업데이트되는 경우 처리
if "photo2" in update_data:
# 기존 사진 삭제
if issue.photo_path2:
delete_file(issue.photo_path2)
# 새 사진 저장
if update_data["photo2"]:
photo_path2 = save_base64_image(update_data["photo2"])
update_data["photo_path2"] = photo_path2
else:
update_data["photo_path2"] = None
# photo2 필드는 제거 (DB에는 photo_path2만 저장)
del update_data["photo2"]
# 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
if issue.status == IssueStatus.new:
update_data["status"] = IssueStatus.complete
for field, value in update_data.items():
setattr(issue, field, value)
@@ -128,7 +147,7 @@ async def delete_issue(
raise HTTPException(status_code=404, detail="Issue not found")
# 권한 확인 (관리자만 삭제 가능)
if current_user.role != UserRole.ADMIN:
if current_user.role != UserRole.admin:
raise HTTPException(status_code=403, detail="Only admin can delete issues")
# 이미지 파일 삭제
@@ -148,7 +167,7 @@ async def get_issue_stats(
query = db.query(Issue)
# 일반 사용자는 자신의 이슈만
if current_user.role == UserRole.USER:
if current_user.role == UserRole.user:
query = query.filter(Issue.reporter_id == current_user.id)
total = query.count()

View File

@@ -35,7 +35,7 @@ async def generate_report_summary(
)
# 일반 사용자는 자신의 이슈만
if current_user.role == UserRole.USER:
if current_user.role == UserRole.user:
issues_query = issues_query.filter(Issue.reporter_id == current_user.id)
issues = issues_query.all()
@@ -89,7 +89,7 @@ async def get_report_issues(
)
# 일반 사용자는 자신의 이슈만
if current_user.role == UserRole.USER:
if current_user.role == UserRole.user:
query = query.filter(Issue.reporter_id == current_user.id)
issues = query.order_by(Issue.report_date).all()