Compare commits
No commits in common. "93d92a0686ec571e0cb4c8035c52d8c9baa5b691" and "694593aadd5e4dc350c9b8fb2c4ac8c7c4371c50" have entirely different histories.
93d92a0686
...
694593aadd
19
README.md
19
README.md
@ -1,19 +0,0 @@
|
|||||||
# SukjeNogi Backend
|
|
||||||
|
|
||||||
숙제노기 프로젝트의 백엔드 서버입니다. FastAPI로 작성되었으며 캐릭터별 과제 관리 기능 등을 REST API로 제공합니다.
|
|
||||||
|
|
||||||
## 실행 방법
|
|
||||||
|
|
||||||
### Docker 사용
|
|
||||||
```bash
|
|
||||||
docker build -t sukjenogi-backend .
|
|
||||||
docker run -d --env-file .env -p 8000:8000 sukjenogi-backend
|
|
||||||
```
|
|
||||||
|
|
||||||
### docker-compose 사용
|
|
||||||
`docker-compose.yml` 파일에 필요한 환경변수를 정의한 뒤 다음 명령으로 실행할 수 있습니다.
|
|
||||||
```bash
|
|
||||||
docker compose up -d --build
|
|
||||||
```
|
|
||||||
|
|
||||||
서버가 시작되면 `http://localhost:8000` 에서 서비스에 접근할 수 있습니다.
|
|
||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from app.core.deps import get_db
|
from app.core.database import SessionLocal
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.core.security import verify_password, create_access_token
|
from app.core.security import verify_password, create_access_token
|
||||||
from pydantic import BaseModel, EmailStr
|
from pydantic import BaseModel, EmailStr
|
||||||
@ -11,6 +11,14 @@ from datetime import timedelta
|
|||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
def get_db():
|
||||||
|
db = SessionLocal()
|
||||||
|
try:
|
||||||
|
yield db
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
# 로그인 요청 스키마
|
# 로그인 요청 스키마
|
||||||
class LoginRequest(BaseModel):
|
class LoginRequest(BaseModel):
|
||||||
email: EmailStr
|
email: EmailStr
|
||||||
|
|||||||
@ -75,8 +75,7 @@ def update_character(
|
|||||||
|
|
||||||
character.name = req.name
|
character.name = req.name
|
||||||
character.server = req.server
|
character.server = req.server
|
||||||
character.combat_power = req.power
|
character.power = req.power
|
||||||
character.is_public = req.is_public
|
|
||||||
db.commit()
|
db.commit()
|
||||||
return {"message": "캐릭터가 수정되었습니다."}
|
return {"message": "캐릭터가 수정되었습니다."}
|
||||||
|
|
||||||
@ -119,6 +118,7 @@ def update_character_order(
|
|||||||
for update in updates:
|
for update in updates:
|
||||||
character = db.query(Character).filter_by(id=update.id, user_id=user.id).first()
|
character = db.query(Character).filter_by(id=update.id, user_id=user.id).first()
|
||||||
if character:
|
if character:
|
||||||
|
character.order = update.order
|
||||||
character.order = update.order
|
character.order = update.order
|
||||||
db.add(character)
|
db.add(character)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|||||||
@ -1,104 +0,0 @@
|
|||||||
from fastapi import APIRouter, Depends, HTTPException
|
|
||||||
from sqlalchemy.orm import Session
|
|
||||||
from app.core.deps import get_db, get_current_user
|
|
||||||
from app.schemas.friend import (
|
|
||||||
FriendRequestCreate,
|
|
||||||
FriendRequestResponse,
|
|
||||||
FriendResponse,
|
|
||||||
FriendListItem,
|
|
||||||
)
|
|
||||||
from app.schemas.character import CharacterResponse
|
|
||||||
from app.schemas.dashboard import DashboardHomework
|
|
||||||
from app.services import friend_service
|
|
||||||
from app.models.user import User
|
|
||||||
|
|
||||||
router = APIRouter()
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/request", response_model=FriendRequestResponse)
|
|
||||||
def send_request(
|
|
||||||
request_data: FriendRequestCreate,
|
|
||||||
db: Session = Depends(get_db),
|
|
||||||
current_user: User = Depends(get_current_user)
|
|
||||||
):
|
|
||||||
return friend_service.send_friend_request(db, current_user.id, request_data.to_user_email)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/requests/received", response_model=list[FriendRequestResponse])
|
|
||||||
def get_received_requests(
|
|
||||||
db: Session = Depends(get_db),
|
|
||||||
current_user: User = Depends(get_current_user)
|
|
||||||
):
|
|
||||||
return friend_service.get_received_requests(db, current_user.id)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/requests/sent", response_model=list[FriendRequestResponse])
|
|
||||||
def get_sent_requests(
|
|
||||||
db: Session = Depends(get_db),
|
|
||||||
current_user: User = Depends(get_current_user)
|
|
||||||
):
|
|
||||||
return friend_service.get_sent_requests(db, current_user.id)
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/requests/{request_id}/cancel")
|
|
||||||
def cancel_sent_request(
|
|
||||||
request_id: int,
|
|
||||||
db: Session = Depends(get_db),
|
|
||||||
current_user: User = Depends(get_current_user)
|
|
||||||
):
|
|
||||||
friend_service.cancel_sent_request(db, request_id, current_user.id)
|
|
||||||
return {"detail": "요청을 취소했습니다."}
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/requests/{request_id}/respond")
|
|
||||||
def respond_to_request(
|
|
||||||
request_id: int,
|
|
||||||
accept: bool,
|
|
||||||
db: Session = Depends(get_db),
|
|
||||||
current_user: User = Depends(get_current_user)
|
|
||||||
):
|
|
||||||
friend_service.respond_to_request(db, request_id, current_user.id, accept)
|
|
||||||
return {"detail": "요청을 처리했습니다."}
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/list", response_model=list[FriendListItem])
|
|
||||||
def get_friend_list(
|
|
||||||
db: Session = Depends(get_db),
|
|
||||||
current_user: User = Depends(get_current_user)
|
|
||||||
):
|
|
||||||
return friend_service.get_friend_list(db, current_user.id)
|
|
||||||
|
|
||||||
@router.get("/{friend_id}/characters", response_model=list[CharacterResponse])
|
|
||||||
def get_friend_characters(
|
|
||||||
friend_id: int,
|
|
||||||
db: Session = Depends(get_db),
|
|
||||||
current_user: User = Depends(get_current_user)
|
|
||||||
):
|
|
||||||
return friend_service.get_public_characters_of_friend(db, current_user.id, friend_id)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get(
|
|
||||||
"/{friend_id}/characters/{character_id}/homeworks",
|
|
||||||
response_model=list[DashboardHomework],
|
|
||||||
)
|
|
||||||
def get_friend_character_homeworks(
|
|
||||||
friend_id: int,
|
|
||||||
character_id: int,
|
|
||||||
db: Session = Depends(get_db),
|
|
||||||
current_user: User = Depends(get_current_user)
|
|
||||||
):
|
|
||||||
return friend_service.get_public_homeworks_of_friend_character(
|
|
||||||
db,
|
|
||||||
current_user.id,
|
|
||||||
friend_id,
|
|
||||||
character_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
@router.delete("/{friend_id}")
|
|
||||||
def delete_friend(
|
|
||||||
friend_id: int,
|
|
||||||
db: Session = Depends(get_db),
|
|
||||||
current_user: User = Depends(get_current_user)
|
|
||||||
):
|
|
||||||
friend_service.delete_friend(db, current_user.id, friend_id)
|
|
||||||
return {"detail": "친구가 삭제되었습니다."}
|
|
||||||
@ -24,7 +24,6 @@ def register_homework_type(
|
|||||||
reset_type=homework_data.reset_type,
|
reset_type=homework_data.reset_type,
|
||||||
reset_time=homework_data.reset_time or time(6, 0),
|
reset_time=homework_data.reset_time or time(6, 0),
|
||||||
clear_count=homework_data.clear_count or 0,
|
clear_count=homework_data.clear_count or 0,
|
||||||
is_public=homework_data.is_public,
|
|
||||||
created_at=datetime.utcnow(),
|
created_at=datetime.utcnow(),
|
||||||
)
|
)
|
||||||
db.add(homework_type)
|
db.add(homework_type)
|
||||||
@ -53,11 +52,10 @@ def update_homework_type(
|
|||||||
if not homework_type or homework_type.user_id != current_user.id:
|
if not homework_type or homework_type.user_id != current_user.id:
|
||||||
raise HTTPException(status_code=403, detail="권한이 없습니다.")
|
raise HTTPException(status_code=403, detail="권한이 없습니다.")
|
||||||
|
|
||||||
homework_type.title = req.title
|
homework_type.name = req.name
|
||||||
homework_type.description = req.description
|
homework_type.description = req.description
|
||||||
homework_type.reset_type = req.reset_type
|
homework_type.repeat_type = req.repeat_type
|
||||||
homework_type.clear_count = req.clear_count
|
homework_type.repeat_count = req.repeat_count
|
||||||
homework_type.is_public = req.is_public
|
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
return {"message": "숙제가 수정되었습니다."}
|
return {"message": "숙제가 수정되었습니다."}
|
||||||
|
|||||||
@ -1,17 +1,16 @@
|
|||||||
# app/api/user.py
|
# app/api/user.py
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
from fastapi.logger import logger
|
from fastapi.logger import logger
|
||||||
import traceback
|
import traceback
|
||||||
import sys
|
import sys
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from app.schemas.user import UserCreate, UserResponse, PasswordUpdateRequest, UserPublicInfoResponse, UserByCharacterResponse
|
from app.schemas.user import UserCreate, UserResponse, PasswordUpdateRequest
|
||||||
from app.crud.user import create_user
|
from app.crud.user import create_user
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.core.database import SessionLocal
|
from app.core.database import SessionLocal
|
||||||
from app.core.deps import get_current_user
|
from app.core.deps import get_current_user
|
||||||
from app.core.security import verify_password, get_password_hash
|
from app.core.security import verify_password, get_password_hash
|
||||||
from app.services import user_service
|
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@ -58,19 +57,3 @@ def update_password(
|
|||||||
logger.error(f"❌ 비밀번호 변경 중 예외 발생: {e}")
|
logger.error(f"❌ 비밀번호 변경 중 예외 발생: {e}")
|
||||||
traceback.print_exc(file=sys.stdout) # ← 여기가 핵심
|
traceback.print_exc(file=sys.stdout) # ← 여기가 핵심
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@router.get("/public-info", response_model=UserPublicInfoResponse)
|
|
||||||
def get_public_info(
|
|
||||||
email: str = Query(...),
|
|
||||||
db: Session = Depends(get_db),
|
|
||||||
current_user: User = Depends(get_current_user)
|
|
||||||
):
|
|
||||||
return user_service.get_user_public_info(db, current_user.id, email)
|
|
||||||
|
|
||||||
@router.get("/by-character", response_model=UserByCharacterResponse)
|
|
||||||
def get_by_character(
|
|
||||||
server: str,
|
|
||||||
name: str,
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
return user_service.get_user_by_character(db, server, name)
|
|
||||||
@ -1,6 +1,7 @@
|
|||||||
# app/core/config.py
|
# app/core/config.py
|
||||||
|
|
||||||
from pydantic_settings import BaseSettings
|
from pydantic_settings import BaseSettings
|
||||||
|
from sqlalchemy.orm import declarative_base
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
database_url: str
|
database_url: str
|
||||||
@ -13,4 +14,6 @@ class Settings(BaseSettings):
|
|||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
|
|
||||||
|
# 베이스 클래스
|
||||||
|
Base = declarative_base()
|
||||||
|
|
||||||
|
|||||||
@ -10,8 +10,6 @@ engine = create_engine(settings.database_url, echo=True, future=True)
|
|||||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
|
|
||||||
import app.models # ✅ 그대로 유지
|
|
||||||
|
|
||||||
@event.listens_for(Engine, "handle_error")
|
@event.listens_for(Engine, "handle_error")
|
||||||
def receive_handle_error(exception_context):
|
def receive_handle_error(exception_context):
|
||||||
print("🔥 SQLAlchemy DB 에러 감지!")
|
print("🔥 SQLAlchemy DB 에러 감지!")
|
||||||
@ -24,3 +22,5 @@ def get_db():
|
|||||||
finally:
|
finally:
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
# 세션 클래스 생성
|
||||||
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
@ -21,7 +21,6 @@ def create_character(user_id: int, character_data: CharacterCreate, db: Session)
|
|||||||
server=character_data.server,
|
server=character_data.server,
|
||||||
job=character_data.job,
|
job=character_data.job,
|
||||||
combat_power=character_data.combat_power, # ← 수동 입력 허용
|
combat_power=character_data.combat_power, # ← 수동 입력 허용
|
||||||
is_public=character_data.is_public,
|
|
||||||
created_at=datetime.utcnow(),
|
created_at=datetime.utcnow(),
|
||||||
updated_at=datetime.utcnow(),
|
updated_at=datetime.utcnow(),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -5,12 +5,9 @@ from app.schemas.homework import HomeworkTypeCreate
|
|||||||
def create_homework_type(user_id: int, data: HomeworkTypeCreate, db: Session):
|
def create_homework_type(user_id: int, data: HomeworkTypeCreate, db: Session):
|
||||||
new_homework = HomeworkType(
|
new_homework = HomeworkType(
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
title=data.title,
|
name=data.name,
|
||||||
description=data.description,
|
|
||||||
reset_type=data.reset_type,
|
|
||||||
reset_time=data.reset_time,
|
reset_time=data.reset_time,
|
||||||
clear_count=data.clear_count,
|
clear_count=data.clear_count,
|
||||||
is_public=data.is_public,
|
|
||||||
)
|
)
|
||||||
db.add(new_homework)
|
db.add(new_homework)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|||||||
53
app/main.py
53
app/main.py
@ -1,5 +1,4 @@
|
|||||||
#pp/main.py
|
#pp/main.py
|
||||||
from app.models import User, Character, HomeworkType, Friend, FriendRequest # 👈 명시적 import!
|
|
||||||
from fastapi import FastAPI, Request, Depends
|
from fastapi import FastAPI, Request, Depends
|
||||||
from fastapi.openapi.docs import get_swagger_ui_html
|
from fastapi.openapi.docs import get_swagger_ui_html
|
||||||
from fastapi.openapi.utils import get_openapi
|
from fastapi.openapi.utils import get_openapi
|
||||||
@ -8,37 +7,37 @@ from fastapi.middleware.cors import CORSMiddleware
|
|||||||
from fastapi.security import OAuth2PasswordBearer
|
from fastapi.security import OAuth2PasswordBearer
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from app.api import user, auth, character, homework, character_homework, dashboard, friend
|
from app.api import user, auth, character, homework, character_homework, dashboard
|
||||||
|
|
||||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login")
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login")
|
||||||
|
|
||||||
|
# app = FastAPI(
|
||||||
|
# title="숙제노기 API",
|
||||||
|
# description="마비노기 모바일 숙제 관리용 백엔드 API",
|
||||||
|
# version="0.1.0",
|
||||||
|
# docs_url="/docs",
|
||||||
|
# redoc_url=None,
|
||||||
|
# openapi_url="/openapi.json",
|
||||||
|
# root_path="/api"
|
||||||
|
# )
|
||||||
|
|
||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="숙제노기 API",
|
docs_url=None,
|
||||||
description="마비노기 모바일 숙제 관리용 백엔드 API",
|
|
||||||
version="0.1.0",
|
|
||||||
docs_url="/docs",
|
|
||||||
redoc_url=None,
|
redoc_url=None,
|
||||||
openapi_url="/openapi.json",
|
openapi_url=None
|
||||||
root_path="/api"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# app = FastAPI(
|
@app.get("/docs", include_in_schema=False)
|
||||||
# docs_url=None,
|
def custom_docs(user=Depends(get_current_user)):
|
||||||
# redoc_url=None,
|
return get_swagger_ui_html(openapi_url="/openapi.json", title="Sukjenogi API Docs")
|
||||||
# openapi_url=None
|
|
||||||
# )
|
@app.get("/openapi.json", include_in_schema=False)
|
||||||
#
|
def custom_openapi(user=Depends(get_current_user)):
|
||||||
# @app.get("/docs", include_in_schema=False)
|
return get_openapi(
|
||||||
# def custom_docs(user=Depends(get_current_user)):
|
title="Sukjenogi API",
|
||||||
# return get_swagger_ui_html(openapi_url="/openapi.json", title="Sukjenogi API Docs")
|
version="0.2",
|
||||||
#
|
routes=app.routes
|
||||||
# @app.get("/openapi.json", include_in_schema=False)
|
)
|
||||||
# def custom_openapi(user=Depends(get_current_user)):
|
|
||||||
# return get_openapi(
|
|
||||||
# title="Sukjenogi API",
|
|
||||||
# version="0.2",
|
|
||||||
# routes=app.routes
|
|
||||||
# )
|
|
||||||
|
|
||||||
@app.middleware("http")
|
@app.middleware("http")
|
||||||
async def log_exceptions_middleware(request: Request, call_next):
|
async def log_exceptions_middleware(request: Request, call_next):
|
||||||
@ -58,8 +57,7 @@ origins = [
|
|||||||
|
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
CORSMiddleware,
|
CORSMiddleware,
|
||||||
# allow_origins=origins,
|
allow_origins=origins,
|
||||||
allow_origins=["*"],
|
|
||||||
allow_credentials=True,
|
allow_credentials=True,
|
||||||
allow_methods=["*"],
|
allow_methods=["*"],
|
||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
@ -71,7 +69,6 @@ app.include_router(character.router, prefix="/characters", tags=["Characters"])
|
|||||||
app.include_router(homework.router, prefix="/homeworks", tags=["Homeworks"])
|
app.include_router(homework.router, prefix="/homeworks", tags=["Homeworks"])
|
||||||
app.include_router(character_homework.router, prefix="/characterHomework", tags=["Character Homeworks"])
|
app.include_router(character_homework.router, prefix="/characterHomework", tags=["Character Homeworks"])
|
||||||
app.include_router(dashboard.router, prefix="/dashboard", tags=["Dashboard"])
|
app.include_router(dashboard.router, prefix="/dashboard", tags=["Dashboard"])
|
||||||
app.include_router(friend.router, prefix="/friends", tags=["Friends"])
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
def read_root():
|
def read_root():
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
# app/models/__init__.py
|
|
||||||
from app.models.user import User
|
|
||||||
from app.models.character import Character
|
|
||||||
from app.models.homework import HomeworkType
|
|
||||||
from app.models.friend import Friend, FriendRequest
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Boolean, func
|
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Boolean, func
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from app.core.database import Base
|
from app.core.config import Base
|
||||||
|
|
||||||
|
|
||||||
class Character(Base):
|
class Character(Base):
|
||||||
@ -22,8 +22,6 @@ class Character(Base):
|
|||||||
|
|
||||||
order = Column(Integer, default=0)
|
order = Column(Integer, default=0)
|
||||||
|
|
||||||
is_public = Column(Boolean, default=False, nullable=False)
|
|
||||||
|
|
||||||
|
|
||||||
class CharacterHomework(Base):
|
class CharacterHomework(Base):
|
||||||
__tablename__ = "character_homeworks"
|
__tablename__ = "character_homeworks"
|
||||||
|
|||||||
@ -1,41 +0,0 @@
|
|||||||
from sqlalchemy import Column, Integer, Enum, ForeignKey, DateTime, CheckConstraint, UniqueConstraint
|
|
||||||
from sqlalchemy.orm import relationship
|
|
||||||
from datetime import datetime
|
|
||||||
from app.core.database import Base
|
|
||||||
import enum
|
|
||||||
|
|
||||||
class FriendRequestStatus(enum.Enum):
|
|
||||||
pending = "pending"
|
|
||||||
accepted = "accepted"
|
|
||||||
rejected = "rejected"
|
|
||||||
cancelled = "cancelled"
|
|
||||||
|
|
||||||
class FriendRequest(Base):
|
|
||||||
__tablename__ = "friend_requests"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
from_user_id = Column(Integer, ForeignKey("users.id"))
|
|
||||||
to_user_id = Column(Integer, ForeignKey("users.id"))
|
|
||||||
status = Column(Enum(FriendRequestStatus), default=FriendRequestStatus.pending, nullable=False)
|
|
||||||
created_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
updated_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
|
|
||||||
# 🔽 문자열로 참조
|
|
||||||
from_user = relationship("User", foreign_keys=[from_user_id], back_populates="sent_requests")
|
|
||||||
to_user = relationship("User", foreign_keys=[to_user_id], back_populates="received_requests")
|
|
||||||
|
|
||||||
class Friend(Base):
|
|
||||||
__tablename__ = "friends"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
user_id_1 = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
|
|
||||||
user_id_2 = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
|
|
||||||
created_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
|
|
||||||
__table_args__ = (
|
|
||||||
UniqueConstraint("user_id_1", "user_id_2", name="unique_friend_pair"),
|
|
||||||
CheckConstraint("user_id_1 < user_id_2", name="check_user_order"),
|
|
||||||
)
|
|
||||||
|
|
||||||
user1 = relationship("User", foreign_keys=[user_id_1], back_populates="friendships1")
|
|
||||||
user2 = relationship("User", foreign_keys=[user_id_2], back_populates="friendships2")
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
from sqlalchemy import Column, Integer, String, Time, ForeignKey, DateTime, Boolean
|
from sqlalchemy import Column, Integer, String, Time, ForeignKey, DateTime
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from datetime import time, datetime
|
from datetime import time, datetime
|
||||||
|
|
||||||
from app.core.database import Base
|
from app.core.config import Base
|
||||||
|
|
||||||
class HomeworkType(Base):
|
class HomeworkType(Base):
|
||||||
__tablename__ = "homework_types"
|
__tablename__ = "homework_types"
|
||||||
@ -20,5 +20,3 @@ class HomeworkType(Base):
|
|||||||
assigned_characters = relationship("CharacterHomework", back_populates="homework_type", cascade="all, delete")
|
assigned_characters = relationship("CharacterHomework", back_populates="homework_type", cascade="all, delete")
|
||||||
|
|
||||||
order = Column(Integer, default=0)
|
order = Column(Integer, default=0)
|
||||||
|
|
||||||
is_public = Column(Boolean, default=False, nullable=False)
|
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
|
# app/models/user.py
|
||||||
from sqlalchemy import Column, Integer, String, DateTime
|
from sqlalchemy import Column, Integer, String, DateTime
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from sqlalchemy.sql import func
|
from sqlalchemy.sql import func
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from app.core.database import Base
|
from app.core.config import Base
|
||||||
|
|
||||||
class User(Base):
|
class User(Base):
|
||||||
__tablename__ = "users"
|
__tablename__ = "users"
|
||||||
@ -13,12 +14,5 @@ class User(Base):
|
|||||||
created_at = Column(DateTime, server_default=func.now(), nullable=False)
|
created_at = Column(DateTime, server_default=func.now(), nullable=False)
|
||||||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now(), nullable=False)
|
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||||
|
|
||||||
from app.models.character import Character
|
characters = relationship("Character", back_populates="user")
|
||||||
characters = relationship(Character, back_populates="user")
|
|
||||||
homework_types = relationship("HomeworkType", back_populates="user", cascade="all, delete")
|
homework_types = relationship("HomeworkType", back_populates="user", cascade="all, delete")
|
||||||
|
|
||||||
# 🔽 문자열만 사용하고 foreign_keys 생략 (권장)
|
|
||||||
sent_requests = relationship("FriendRequest", back_populates="from_user", foreign_keys="FriendRequest.from_user_id")
|
|
||||||
received_requests = relationship("FriendRequest", back_populates="to_user", foreign_keys="FriendRequest.to_user_id")
|
|
||||||
friendships1 = relationship("Friend", back_populates="user1", foreign_keys="Friend.user_id_1")
|
|
||||||
friendships2 = relationship("Friend", back_populates="user2", foreign_keys="Friend.user_id_2")
|
|
||||||
@ -10,7 +10,6 @@ class CharacterCreate(BaseModel):
|
|||||||
server: Optional[str] = None
|
server: Optional[str] = None
|
||||||
job: Optional[str] = None
|
job: Optional[str] = None
|
||||||
combat_power: Optional[int] = None # ← 추가
|
combat_power: Optional[int] = None # ← 추가
|
||||||
is_public: bool = False
|
|
||||||
|
|
||||||
# 캐릭터 응답용
|
# 캐릭터 응답용
|
||||||
class CharacterResponse(BaseModel):
|
class CharacterResponse(BaseModel):
|
||||||
@ -19,7 +18,6 @@ class CharacterResponse(BaseModel):
|
|||||||
server: Optional[str]
|
server: Optional[str]
|
||||||
job: Optional[str]
|
job: Optional[str]
|
||||||
combat_power: Optional[int] # ← 추가
|
combat_power: Optional[int] # ← 추가
|
||||||
is_public: bool
|
|
||||||
auto_synced_at: Optional[datetime]
|
auto_synced_at: Optional[datetime]
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
|
|
||||||
@ -30,7 +28,6 @@ class CharacterUpdateRequest(BaseModel):
|
|||||||
name: constr(min_length=1)
|
name: constr(min_length=1)
|
||||||
server: constr(min_length=1)
|
server: constr(min_length=1)
|
||||||
power: conint(ge=0) # 0 이상 정수
|
power: conint(ge=0) # 0 이상 정수
|
||||||
is_public: bool
|
|
||||||
|
|
||||||
class CharacterDetailResponse(BaseModel):
|
class CharacterDetailResponse(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
@ -38,7 +35,6 @@ class CharacterDetailResponse(BaseModel):
|
|||||||
server: str
|
server: str
|
||||||
combat_power: int
|
combat_power: int
|
||||||
user_id: int
|
user_id: int
|
||||||
is_public: bool
|
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
updated_at: datetime
|
updated_at: datetime
|
||||||
|
|
||||||
|
|||||||
@ -1,46 +0,0 @@
|
|||||||
from pydantic import BaseModel
|
|
||||||
from datetime import datetime
|
|
||||||
from enum import Enum
|
|
||||||
|
|
||||||
|
|
||||||
class FriendRequestStatus(str, Enum):
|
|
||||||
pending = "pending"
|
|
||||||
accepted = "accepted"
|
|
||||||
rejected = "rejected"
|
|
||||||
cancelled = "cancelled"
|
|
||||||
|
|
||||||
|
|
||||||
class FriendRequestCreate(BaseModel):
|
|
||||||
to_user_email: str
|
|
||||||
|
|
||||||
|
|
||||||
class FriendRequestResponse(BaseModel):
|
|
||||||
id: int
|
|
||||||
from_user_id: int
|
|
||||||
to_user_id: int
|
|
||||||
from_user_email: str | None = None
|
|
||||||
to_user_email: str | None = None
|
|
||||||
status: FriendRequestStatus
|
|
||||||
created_at: datetime
|
|
||||||
updated_at: datetime
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
orm_mode = True
|
|
||||||
|
|
||||||
|
|
||||||
class FriendResponse(BaseModel):
|
|
||||||
id: int
|
|
||||||
user_id_1: int
|
|
||||||
user_id_2: int
|
|
||||||
created_at: datetime
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
orm_mode = True
|
|
||||||
|
|
||||||
|
|
||||||
class FriendListItem(BaseModel):
|
|
||||||
id: int
|
|
||||||
email: str
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
orm_mode = True
|
|
||||||
@ -10,7 +10,6 @@ class HomeworkTypeCreate(BaseModel):
|
|||||||
reset_type: str
|
reset_type: str
|
||||||
reset_time: Optional[time] = None
|
reset_time: Optional[time] = None
|
||||||
clear_count: Optional[int] = 0
|
clear_count: Optional[int] = 0
|
||||||
is_public: bool = False
|
|
||||||
|
|
||||||
class HomeworkTypeResponse(BaseModel):
|
class HomeworkTypeResponse(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
@ -19,7 +18,6 @@ class HomeworkTypeResponse(BaseModel):
|
|||||||
reset_type: str
|
reset_type: str
|
||||||
reset_time: time
|
reset_time: time
|
||||||
clear_count: int
|
clear_count: int
|
||||||
is_public: bool
|
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
@ -33,11 +31,10 @@ class HomeworkSelectableResponse(BaseModel):
|
|||||||
clear_count: int
|
clear_count: int
|
||||||
|
|
||||||
class HomeworkTypeUpdateRequest(BaseModel):
|
class HomeworkTypeUpdateRequest(BaseModel):
|
||||||
title: constr(min_length=1)
|
name: constr(min_length=1)
|
||||||
description: str | None = None
|
description: str | None = None
|
||||||
reset_type: constr(min_length=1)
|
repeat_type: constr(min_length=1)
|
||||||
clear_count: conint(ge=1)
|
repeat_count: conint(ge=1)
|
||||||
is_public: bool
|
|
||||||
|
|
||||||
class HomeworkTypeDetailResponse(BaseModel):
|
class HomeworkTypeDetailResponse(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
@ -47,7 +44,6 @@ class HomeworkTypeDetailResponse(BaseModel):
|
|||||||
reset_type: str
|
reset_type: str
|
||||||
reset_time: time
|
reset_time: time
|
||||||
clear_count: int
|
clear_count: int
|
||||||
is_public: bool
|
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
|
|
||||||
model_config = {
|
model_config = {
|
||||||
|
|||||||
@ -20,19 +20,3 @@ class PasswordUpdateRequest(BaseModel):
|
|||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class UserPublicInfoResponse(BaseModel):
|
|
||||||
id: int
|
|
||||||
email: str
|
|
||||||
is_friend: bool
|
|
||||||
request_sent: bool
|
|
||||||
request_received: bool
|
|
||||||
|
|
||||||
class UserByCharacterResponse(BaseModel):
|
|
||||||
user_id: int
|
|
||||||
email: str
|
|
||||||
character_id: int
|
|
||||||
character_name: str
|
|
||||||
server: str
|
|
||||||
is_public: bool
|
|
||||||
@ -117,3 +117,36 @@ def update_homework_completion(
|
|||||||
db.commit()
|
db.commit()
|
||||||
return {"message": "숙제 완료 상태가 업데이트되었습니다."}
|
return {"message": "숙제 완료 상태가 업데이트되었습니다."}
|
||||||
|
|
||||||
|
def update_homework_completion(
|
||||||
|
db: Session,
|
||||||
|
user_id: int,
|
||||||
|
character_id: int,
|
||||||
|
homework_type_id: int,
|
||||||
|
new_complete_cnt: int
|
||||||
|
):
|
||||||
|
character = db.query(Character).filter_by(id=character_id, user_id=user_id).first()
|
||||||
|
if not character:
|
||||||
|
raise HTTPException(status_code=404, detail="캐릭터가 없습니다.")
|
||||||
|
|
||||||
|
homework = db.query(HomeworkType).filter_by(id=homework_type_id, user_id=user_id).first()
|
||||||
|
if not homework:
|
||||||
|
raise HTTPException(status_code=404, detail="숙제를 찾을 수 없습니다.")
|
||||||
|
|
||||||
|
ch = db.query(CharacterHomework).filter_by(
|
||||||
|
character_id=character_id,
|
||||||
|
homework_type_id=homework_type_id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if not ch:
|
||||||
|
raise HTTPException(status_code=404, detail="지정된 숙제가 없습니다.")
|
||||||
|
|
||||||
|
if new_complete_cnt > homework.clear_count:
|
||||||
|
raise HTTPException(status_code=400, detail="완료 횟수가 숙제 클리어 기준을 초과했습니다.")
|
||||||
|
|
||||||
|
ch.complete_cnt = new_complete_cnt
|
||||||
|
ch.last_completed_at = datetime.utcnow()
|
||||||
|
ch.updated_at = datetime.utcnow()
|
||||||
|
ch.is_done = (new_complete_cnt == homework.clear_count)
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
return {"message": "숙제 완료 상태가 업데이트되었습니다."}
|
||||||
@ -1,232 +0,0 @@
|
|||||||
from sqlalchemy.orm import Session, aliased
|
|
||||||
from sqlalchemy import select
|
|
||||||
from app.models.friend import FriendRequest, Friend, FriendRequestStatus
|
|
||||||
from app.models.user import User
|
|
||||||
from app.models.character import Character, CharacterHomework
|
|
||||||
from app.models.homework import HomeworkType
|
|
||||||
from fastapi import HTTPException, status
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
|
|
||||||
def send_friend_request(db: Session, from_user_id: int, to_user_email: str):
|
|
||||||
to_user = db.query(User).filter(User.email == to_user_email).first()
|
|
||||||
if not to_user:
|
|
||||||
raise HTTPException(status_code=404, detail="해당 이메일의 유저를 찾을 수 없습니다.")
|
|
||||||
|
|
||||||
if to_user.id == from_user_id:
|
|
||||||
raise HTTPException(status_code=400, detail="자기 자신에게 친구 요청을 보낼 수 없습니다.")
|
|
||||||
|
|
||||||
# 이미 친구인지 확인
|
|
||||||
user_ids = sorted([from_user_id, to_user.id])
|
|
||||||
existing_friend = db.query(Friend).filter(
|
|
||||||
Friend.user_id_1 == user_ids[0],
|
|
||||||
Friend.user_id_2 == user_ids[1]
|
|
||||||
).first()
|
|
||||||
if existing_friend:
|
|
||||||
raise HTTPException(status_code=400, detail="이미 친구 상태입니다.")
|
|
||||||
|
|
||||||
# 이미 pending 요청이 있는지 확인
|
|
||||||
existing_request = db.query(FriendRequest).filter(
|
|
||||||
FriendRequest.from_user_id == from_user_id,
|
|
||||||
FriendRequest.to_user_id == to_user.id,
|
|
||||||
FriendRequest.status == FriendRequestStatus.pending
|
|
||||||
).first()
|
|
||||||
if existing_request:
|
|
||||||
raise HTTPException(status_code=400, detail="이미 친구 요청을 보낸 상태입니다.")
|
|
||||||
|
|
||||||
friend_request = FriendRequest(
|
|
||||||
from_user_id=from_user_id,
|
|
||||||
to_user_id=to_user.id,
|
|
||||||
)
|
|
||||||
db.add(friend_request)
|
|
||||||
db.commit()
|
|
||||||
db.refresh(friend_request)
|
|
||||||
return friend_request
|
|
||||||
|
|
||||||
|
|
||||||
def get_received_requests(db: Session, user_id: int):
|
|
||||||
sender = aliased(User)
|
|
||||||
receiver = aliased(User)
|
|
||||||
stmt = (
|
|
||||||
select(
|
|
||||||
FriendRequest.id,
|
|
||||||
FriendRequest.from_user_id,
|
|
||||||
FriendRequest.to_user_id,
|
|
||||||
sender.email.label("from_user_email"),
|
|
||||||
receiver.email.label("to_user_email"),
|
|
||||||
FriendRequest.status,
|
|
||||||
FriendRequest.created_at,
|
|
||||||
FriendRequest.updated_at,
|
|
||||||
)
|
|
||||||
.join(sender, FriendRequest.from_user_id == sender.id)
|
|
||||||
.join(receiver, FriendRequest.to_user_id == receiver.id)
|
|
||||||
.where(
|
|
||||||
FriendRequest.to_user_id == user_id,
|
|
||||||
FriendRequest.status == FriendRequestStatus.pending,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return db.execute(stmt).mappings().all()
|
|
||||||
|
|
||||||
|
|
||||||
def get_sent_requests(db: Session, user_id: int):
|
|
||||||
sender = aliased(User)
|
|
||||||
receiver = aliased(User)
|
|
||||||
stmt = (
|
|
||||||
select(
|
|
||||||
FriendRequest.id,
|
|
||||||
FriendRequest.from_user_id,
|
|
||||||
FriendRequest.to_user_id,
|
|
||||||
sender.email.label("from_user_email"),
|
|
||||||
receiver.email.label("to_user_email"),
|
|
||||||
FriendRequest.status,
|
|
||||||
FriendRequest.created_at,
|
|
||||||
FriendRequest.updated_at,
|
|
||||||
)
|
|
||||||
.join(sender, FriendRequest.from_user_id == sender.id)
|
|
||||||
.join(receiver, FriendRequest.to_user_id == receiver.id)
|
|
||||||
.where(
|
|
||||||
FriendRequest.from_user_id == user_id,
|
|
||||||
FriendRequest.status == FriendRequestStatus.pending,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return db.execute(stmt).mappings().all()
|
|
||||||
|
|
||||||
|
|
||||||
def cancel_sent_request(db: Session, request_id: int, user_id: int):
|
|
||||||
request = db.query(FriendRequest).filter(
|
|
||||||
FriendRequest.id == request_id,
|
|
||||||
FriendRequest.from_user_id == user_id
|
|
||||||
).first()
|
|
||||||
|
|
||||||
if not request:
|
|
||||||
raise HTTPException(status_code=404, detail="요청을 찾을 수 없습니다.")
|
|
||||||
|
|
||||||
request.status = FriendRequestStatus.cancelled
|
|
||||||
request.updated_at = datetime.utcnow()
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
|
|
||||||
def respond_to_request(db: Session, request_id: int, user_id: int, accept: bool):
|
|
||||||
request = db.query(FriendRequest).filter(
|
|
||||||
FriendRequest.id == request_id,
|
|
||||||
FriendRequest.to_user_id == user_id,
|
|
||||||
FriendRequest.status == FriendRequestStatus.pending
|
|
||||||
).first()
|
|
||||||
|
|
||||||
if not request:
|
|
||||||
raise HTTPException(status_code=404, detail="요청을 찾을 수 없습니다.")
|
|
||||||
|
|
||||||
request.status = FriendRequestStatus.accepted if accept else FriendRequestStatus.rejected
|
|
||||||
request.updated_at = datetime.utcnow()
|
|
||||||
|
|
||||||
# 친구 수락 시 friends 테이블에도 저장
|
|
||||||
if accept:
|
|
||||||
user_ids = sorted([request.from_user_id, request.to_user_id])
|
|
||||||
friend = Friend(
|
|
||||||
user_id_1=user_ids[0],
|
|
||||||
user_id_2=user_ids[1]
|
|
||||||
)
|
|
||||||
db.add(friend)
|
|
||||||
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
|
|
||||||
def get_friend_list(db: Session, user_id: int):
|
|
||||||
friends = db.query(Friend).filter(
|
|
||||||
(Friend.user_id_1 == user_id) | (Friend.user_id_2 == user_id)
|
|
||||||
).all()
|
|
||||||
|
|
||||||
result = []
|
|
||||||
for f in friends:
|
|
||||||
friend_id = f.user_id_2 if f.user_id_1 == user_id else f.user_id_1
|
|
||||||
friend = db.query(User).filter(User.id == friend_id).first()
|
|
||||||
friend_email = friend.email if friend else None
|
|
||||||
result.append({"id": friend_id, "email": friend_email})
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def get_public_characters_of_friend(db: Session, current_user_id: int, friend_id: int):
|
|
||||||
# 친구 관계 확인
|
|
||||||
user_ids = sorted([current_user_id, friend_id])
|
|
||||||
is_friend = db.query(Friend).filter(
|
|
||||||
Friend.user_id_1 == user_ids[0],
|
|
||||||
Friend.user_id_2 == user_ids[1]
|
|
||||||
).first()
|
|
||||||
|
|
||||||
if not is_friend:
|
|
||||||
raise HTTPException(status_code=403, detail="친구가 아닙니다.")
|
|
||||||
|
|
||||||
# 공개된 캐릭터 목록
|
|
||||||
characters = db.query(Character).filter(
|
|
||||||
Character.user_id == friend_id,
|
|
||||||
Character.is_public == True
|
|
||||||
).all()
|
|
||||||
|
|
||||||
return characters
|
|
||||||
|
|
||||||
def get_public_homeworks_of_friend_character(
|
|
||||||
db: Session,
|
|
||||||
current_user_id: int,
|
|
||||||
friend_id: int,
|
|
||||||
character_id: int
|
|
||||||
):
|
|
||||||
# 1. 친구인지 확인
|
|
||||||
user_ids = sorted([current_user_id, friend_id])
|
|
||||||
is_friend = db.query(Friend).filter(
|
|
||||||
Friend.user_id_1 == user_ids[0],
|
|
||||||
Friend.user_id_2 == user_ids[1]
|
|
||||||
).first()
|
|
||||||
if not is_friend:
|
|
||||||
raise HTTPException(status_code=403, detail="친구가 아닙니다.")
|
|
||||||
|
|
||||||
# 2. 해당 캐릭터가 공개인지 확인
|
|
||||||
character = db.query(Character).filter(
|
|
||||||
Character.id == character_id,
|
|
||||||
Character.user_id == friend_id,
|
|
||||||
Character.is_public == True
|
|
||||||
).first()
|
|
||||||
if not character:
|
|
||||||
raise HTTPException(status_code=404, detail="공개된 캐릭터를 찾을 수 없습니다.")
|
|
||||||
|
|
||||||
# 3. 공개된 숙제만 조회하며 완료 횟수도 포함
|
|
||||||
rows = (
|
|
||||||
db.query(
|
|
||||||
HomeworkType.id.label("homework_id"),
|
|
||||||
HomeworkType.title,
|
|
||||||
HomeworkType.reset_type,
|
|
||||||
HomeworkType.clear_count,
|
|
||||||
CharacterHomework.complete_cnt,
|
|
||||||
)
|
|
||||||
.join(CharacterHomework, CharacterHomework.homework_type_id == HomeworkType.id)
|
|
||||||
.filter(
|
|
||||||
CharacterHomework.character_id == character_id,
|
|
||||||
HomeworkType.is_public == True,
|
|
||||||
)
|
|
||||||
.order_by(HomeworkType.order.asc())
|
|
||||||
.all()
|
|
||||||
)
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
"homework_id": row[0],
|
|
||||||
"title": row[1],
|
|
||||||
"reset_type": row[2],
|
|
||||||
"clear_count": row[3],
|
|
||||||
"complete_cnt": row[4],
|
|
||||||
}
|
|
||||||
for row in rows
|
|
||||||
]
|
|
||||||
|
|
||||||
def delete_friend(db: Session, user_id: int, friend_id: int):
|
|
||||||
user_ids = sorted([user_id, friend_id])
|
|
||||||
|
|
||||||
friend = db.query(Friend).filter(
|
|
||||||
Friend.user_id_1 == user_ids[0],
|
|
||||||
Friend.user_id_2 == user_ids[1]
|
|
||||||
).first()
|
|
||||||
|
|
||||||
if not friend:
|
|
||||||
raise HTTPException(status_code=404, detail="친구 관계가 존재하지 않습니다.")
|
|
||||||
|
|
||||||
db.delete(friend)
|
|
||||||
db.commit()
|
|
||||||
@ -1,68 +0,0 @@
|
|||||||
from fastapi import HTTPException
|
|
||||||
from sqlalchemy.orm import Session
|
|
||||||
|
|
||||||
from app.models.user import User
|
|
||||||
from app.models.friend import Friend, FriendRequest, FriendRequestStatus
|
|
||||||
from app.models.character import Character
|
|
||||||
|
|
||||||
def get_user_public_info(
|
|
||||||
db: Session,
|
|
||||||
current_user_id: int,
|
|
||||||
target_email: str
|
|
||||||
):
|
|
||||||
target_user = db.query(User).filter(User.email == target_email).first()
|
|
||||||
if not target_user:
|
|
||||||
raise HTTPException(status_code=404, detail="해당 유저를 찾을 수 없습니다.")
|
|
||||||
|
|
||||||
if target_user.id == current_user_id:
|
|
||||||
raise HTTPException(status_code=400, detail="자기 자신은 검색할 수 없습니다.")
|
|
||||||
|
|
||||||
user_ids = sorted([current_user_id, target_user.id])
|
|
||||||
is_friend = db.query(Friend).filter(
|
|
||||||
Friend.user_id_1 == user_ids[0],
|
|
||||||
Friend.user_id_2 == user_ids[1]
|
|
||||||
).first() is not None
|
|
||||||
|
|
||||||
request_sent = db.query(FriendRequest).filter(
|
|
||||||
FriendRequest.from_user_id == current_user_id,
|
|
||||||
FriendRequest.to_user_id == target_user.id,
|
|
||||||
FriendRequest.status == FriendRequestStatus.pending
|
|
||||||
).first() is not None
|
|
||||||
|
|
||||||
request_received = db.query(FriendRequest).filter(
|
|
||||||
FriendRequest.from_user_id == target_user.id,
|
|
||||||
FriendRequest.to_user_id == current_user_id,
|
|
||||||
FriendRequest.status == FriendRequestStatus.pending
|
|
||||||
).first() is not None
|
|
||||||
|
|
||||||
return {
|
|
||||||
"id": target_user.id,
|
|
||||||
"email": target_user.email,
|
|
||||||
"is_friend": is_friend,
|
|
||||||
"request_sent": request_sent,
|
|
||||||
"request_received": request_received,
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_user_by_character(
|
|
||||||
db: Session,
|
|
||||||
server: str,
|
|
||||||
name: str
|
|
||||||
):
|
|
||||||
character = db.query(Character).filter(
|
|
||||||
Character.server == server,
|
|
||||||
Character.name == name
|
|
||||||
).first()
|
|
||||||
|
|
||||||
if not character:
|
|
||||||
raise HTTPException(status_code=404, detail="캐릭터를 찾을 수 없습니다.")
|
|
||||||
|
|
||||||
user = db.query(User).filter(User.id == character.user_id).first()
|
|
||||||
|
|
||||||
return {
|
|
||||||
"user_id": user.id,
|
|
||||||
"email": user.email,
|
|
||||||
"character_id": character.id,
|
|
||||||
"character_name": character.name,
|
|
||||||
"server": character.server,
|
|
||||||
"is_public": character.is_public
|
|
||||||
}
|
|
||||||
@ -1,10 +1,10 @@
|
|||||||
# create_db.py
|
# create_db.py
|
||||||
|
|
||||||
from app.core.database import Base, engine
|
from app.core.config import Base
|
||||||
|
from app.core.database import engine
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
from app.models.character import Character
|
from app.models.character import Character
|
||||||
from app.models.homework import HomeworkType
|
from app.models.homework import HomeworkType, CharacterHomework
|
||||||
from app.models.character import CharacterHomework
|
|
||||||
|
|
||||||
print("📦 DB 테이블 생성 중...")
|
print("📦 DB 테이블 생성 중...")
|
||||||
Base.metadata.create_all(bind=engine)
|
Base.metadata.create_all(bind=engine)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user