v0.2
This commit is contained in:
parent
f4d0a290c3
commit
b78f7c8d3b
@ -2,7 +2,7 @@ from typing import List
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.schemas.character import CharacterCreate, CharacterResponse
|
||||
from app.schemas.character import CharacterCreate, CharacterResponse, CharacterUpdateRequest
|
||||
from app.schemas.homework import HomeworkSelectableResponse
|
||||
from app.crud.character import create_character, get_characters_by_user
|
||||
from app.services.character_homework_service import get_homeworks_with_assignment_status, assign_homework_to_character, unassign_homework_from_character
|
||||
@ -60,3 +60,36 @@ def unassign_homework(
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
return unassign_homework_from_character(db, current_user.id, character_id, homework_type_id)
|
||||
|
||||
@router.put("/{character_id}")
|
||||
def update_character(
|
||||
character_id: int,
|
||||
req: CharacterUpdateRequest,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
character = db.query(Character).filter(Character.id == character_id).first()
|
||||
|
||||
if not character or character.user_id != current_user.id:
|
||||
raise HTTPException(status_code=403, detail="권한이 없습니다.")
|
||||
|
||||
character.name = req.name
|
||||
character.server = req.server
|
||||
character.power = req.power
|
||||
db.commit()
|
||||
return {"message": "캐릭터가 수정되었습니다."}
|
||||
|
||||
@router.delete("/{character_id}")
|
||||
def delete_character(
|
||||
character_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
character = db.query(Character).filter(Character.id == character_id).first()
|
||||
|
||||
if not character or character.user_id != current_user.id:
|
||||
raise HTTPException(status_code=403, detail="권한이 없습니다.")
|
||||
|
||||
db.delete(character)
|
||||
db.commit()
|
||||
return {"message": "캐릭터가 삭제되었습니다."}
|
||||
@ -1,12 +1,12 @@
|
||||
from datetime import datetime, time
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from app.core.deps import get_db, get_current_user
|
||||
from app.models.homework import HomeworkType
|
||||
from app.models.user import User
|
||||
from app.schemas.homework import HomeworkTypeCreate, HomeworkTypeResponse
|
||||
from app.schemas.homework import HomeworkTypeCreate, HomeworkTypeResponse, HomeworkTypeUpdateRequest
|
||||
from app.crud.homework import create_homework_type, get_homework_types_by_user
|
||||
|
||||
router = APIRouter()
|
||||
@ -37,3 +37,42 @@ def list_homework_types(
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
return get_homework_types_by_user(current_user.id, db)
|
||||
|
||||
@router.put("/{homework_type_id}")
|
||||
def update_homework_type(
|
||||
homework_type_id: int,
|
||||
req: HomeworkTypeUpdateRequest,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
current_user = db.merge(current_user)
|
||||
|
||||
homework_type = db.query(HomeworkType).filter(HomeworkType.id == homework_type_id).first()
|
||||
|
||||
if not homework_type or homework_type.user_id != current_user.id:
|
||||
raise HTTPException(status_code=403, detail="권한이 없습니다.")
|
||||
|
||||
homework_type.name = req.name
|
||||
homework_type.description = req.description
|
||||
homework_type.repeat_type = req.repeat_type
|
||||
homework_type.repeat_count = req.repeat_count
|
||||
|
||||
db.commit()
|
||||
return {"message": "숙제가 수정되었습니다."}
|
||||
|
||||
@router.delete("/{homework_type_id}")
|
||||
def delete_homework_type(
|
||||
homework_type_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
current_user = db.merge(current_user)
|
||||
|
||||
homework_type = db.query(HomeworkType).filter(HomeworkType.id == homework_type_id).first()
|
||||
|
||||
if not homework_type or homework_type.user_id != current_user.id:
|
||||
raise HTTPException(status_code=403, detail="권한이 없습니다.")
|
||||
|
||||
db.delete(homework_type)
|
||||
db.commit()
|
||||
return {"message": "숙제가 삭제되었습니다."}
|
||||
@ -1,12 +1,16 @@
|
||||
# app/api/user.py
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi.logger import logger
|
||||
import traceback
|
||||
import sys
|
||||
from sqlalchemy.orm import Session
|
||||
from app.schemas.user import UserCreate, UserResponse
|
||||
from app.schemas.user import UserCreate, UserResponse, PasswordUpdateRequest
|
||||
from app.crud.user import create_user
|
||||
from app.models.user import User
|
||||
from app.core.database import SessionLocal
|
||||
from app.core.deps import get_current_user
|
||||
from app.core.security import verify_password, get_password_hash
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@ -25,3 +29,31 @@ def register_user(user_create: UserCreate, db: Session = Depends(get_db)):
|
||||
@router.get("/me", response_model=UserResponse)
|
||||
def get_my_profile(current_user: User = Depends(get_current_user)):
|
||||
return current_user
|
||||
|
||||
@router.put("/me/password", status_code=204)
|
||||
def update_password(
|
||||
pw_req: PasswordUpdateRequest,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
try:
|
||||
if not verify_password(pw_req.current_password, current_user.password_hash):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="현재 비밀번호가 일치하지 않습니다."
|
||||
)
|
||||
|
||||
print("기존:", current_user.password_hash)
|
||||
print("신규:", get_password_hash(pw_req.new_password))
|
||||
|
||||
current_user = db.merge(current_user) # 세션에 붙임
|
||||
current_user.password_hash = get_password_hash(pw_req.new_password)
|
||||
db.flush()
|
||||
db.expunge(current_user)
|
||||
print("✅ flush 완료됨. 커밋 시도 중...")
|
||||
db.commit()
|
||||
print("✅ 커밋 완료됨.")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 비밀번호 변경 중 예외 발생: {e}")
|
||||
traceback.print_exc(file=sys.stdout) # ← 여기가 핵심
|
||||
raise
|
||||
@ -1,13 +1,20 @@
|
||||
# app/core/database.py
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy import create_engine, event
|
||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||
from app.core.config import settings
|
||||
from sqlalchemy.engine import Engine
|
||||
import traceback
|
||||
|
||||
engine = create_engine(settings.database_url, echo=True)
|
||||
engine = create_engine(settings.database_url, echo=True, future=True)
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
Base = declarative_base()
|
||||
|
||||
@event.listens_for(Engine, "handle_error")
|
||||
def receive_handle_error(exception_context):
|
||||
print("🔥 SQLAlchemy DB 에러 감지!")
|
||||
traceback.print_exc()
|
||||
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
|
||||
15
app/main.py
15
app/main.py
@ -1,7 +1,8 @@
|
||||
#pp/main.py
|
||||
from fastapi import FastAPI
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
import traceback
|
||||
|
||||
from app.api import user, auth, character, homework, character_homework, dashboard
|
||||
|
||||
@ -17,13 +18,23 @@ app = FastAPI(
|
||||
root_path="/api"
|
||||
)
|
||||
|
||||
@app.middleware("http")
|
||||
async def log_exceptions_middleware(request: Request, call_next):
|
||||
try:
|
||||
response = await call_next(request)
|
||||
return response
|
||||
except Exception as exc:
|
||||
print("❌ 전역 예외 발생:")
|
||||
traceback.print_exc()
|
||||
raise
|
||||
|
||||
origins = [
|
||||
"https://sukjenogi.biryu2000.kr", # 프론트 도메인
|
||||
]
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=origins,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# app/models/user.py
|
||||
from sqlalchemy import Column, Integer, String, DateTime
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from datetime import datetime
|
||||
from app.core.config import Base
|
||||
|
||||
@ -10,8 +11,8 @@ class User(Base):
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
email = Column(String, unique=True, nullable=False, index=True)
|
||||
password_hash = Column(String, nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
created_at = Column(DateTime, server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
|
||||
characters = relationship("Character", back_populates="user")
|
||||
homework_types = relationship("HomeworkType", back_populates="user", cascade="all, delete")
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# app/schemas/character.py
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, constr, conint
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
@ -23,3 +23,8 @@ class CharacterResponse(BaseModel):
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
class CharacterUpdateRequest(BaseModel):
|
||||
name: constr(min_length=1)
|
||||
server: constr(min_length=1)
|
||||
power: conint(ge=0) # 0 이상 정수
|
||||
@ -1,6 +1,6 @@
|
||||
# app/schemas/homework.py
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, constr, conint
|
||||
from datetime import time, datetime
|
||||
from typing import Optional
|
||||
|
||||
@ -28,4 +28,10 @@ class HomeworkSelectableResponse(BaseModel):
|
||||
title: str
|
||||
assigned: str # 'Y' or 'N'
|
||||
reset_type: str
|
||||
clear_count: int
|
||||
clear_count: int
|
||||
|
||||
class HomeworkTypeUpdateRequest(BaseModel):
|
||||
name: constr(min_length=1)
|
||||
description: str | None = None
|
||||
repeat_type: constr(min_length=1)
|
||||
repeat_count: conint(ge=1)
|
||||
@ -1,6 +1,6 @@
|
||||
# app/schemas/user.py
|
||||
|
||||
from pydantic import BaseModel, EmailStr
|
||||
from pydantic import BaseModel, EmailStr, constr
|
||||
from datetime import datetime
|
||||
|
||||
# 사용자 생성 요청용 (회원가입)
|
||||
@ -14,5 +14,9 @@ class UserResponse(BaseModel):
|
||||
email: EmailStr
|
||||
created_at: datetime
|
||||
|
||||
class PasswordUpdateRequest(BaseModel):
|
||||
current_password: constr(min_length=4)
|
||||
new_password: constr(min_length=6)
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user