Skip to content

Commit a68d421

Browse files
9keyyyyGukhee JoCopilot
authored
[NL-63] 유저 정보 수정 API, 오늘 운세 > 사주 정보 조회 API (#11)
* fix: github action deploy image prune 명령 추가 * fix: 스크립트 실행 오류 수정 * feat: 로또 번호 추천 프롬프트 추가 * fix: 사주명식 - 가장 강한/약한 오행 계산 및 저장 추가 * fix: parser 오류 수정 * fix: 프롬프트 수정 * feat: 사용자별 로또 번호 추천/조회 API 생성 * feat: alembic migration * fix: typeddict -> base model * Update src/lotto/service.py Co-authored-by: Copilot <[email protected]> * Update src/lotto/service.py Co-authored-by: Copilot <[email protected]> * feat: 강한/상충되는 기운 필드 추가 * feat: 유저 수정 API * feat: 오늘 운세 - 사주 정보 조회 API --------- Co-authored-by: Gukhee Jo <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent eba417c commit a68d421

File tree

8 files changed

+416
-48
lines changed

8 files changed

+416
-48
lines changed

migrations/scripts/insert_lotto_data.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626

2727
from src.config.database import Mysql
2828
from src.config.config import db_config
29-
from src.lotto.entities.models import LottoDraws, LottoStatistics
29+
from src.lotto.entities.models import LottoDraws, LottoStatistics, LottoRecommendations
30+
from src.users.entities.models import User
3031

3132

3233
class LottoDataImporter:

src/four_pillars/common/calculator.py

Lines changed: 279 additions & 32 deletions
Large diffs are not rendered by default.

src/four_pillars/entities/enums.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,24 @@
33

44
class FiveElements(str, Enum):
55
"""오행 (五行)"""
6-
WOOD = "목(木)" # 목
7-
FIRE = "화(火)" # 화
8-
EARTH = "토(土)" # 토
9-
METAL = "금(金)" # 금
10-
WATER = "수(水)" # 수
6+
7+
WOOD = "목(木)"
8+
FIRE = "화(火)"
9+
EARTH = "토(土)"
10+
METAL = "금(金)"
11+
WATER = "수(水)"
12+
13+
14+
class TenGods(str, Enum):
15+
"""십신 (十神)"""
16+
17+
COMPARISON = "비견"
18+
COMPETITOR = "겁재"
19+
EATING = "식신"
20+
HURTING = "상관"
21+
PARTIAL_WEALTH = "편재"
22+
DIRECT_WEALTH = "정재"
23+
PARTIAL_OFFICIAL = "편관"
24+
DIRECT_OFFICIAL = "정관"
25+
PARTIAL_PRINT = "편인"
26+
DIRECT_PRINT = "정인"

src/four_pillars/entities/schemas.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
from typing import Optional, List
2+
3+
from pydantic import BaseModel
24
from typing_extensions import TypedDict
35

6+
from src.config.schemas import CommonBase
7+
from src.four_pillars.entities.enums import FiveElements, TenGods
8+
9+
10+
class PillarInfo(BaseModel):
11+
stem: str # 천간 (첫 번째 글자)
12+
branch: str # 지지 (두 번째 글자)
13+
stem_ten_god: TenGods # 천간의 십신
14+
branch_ten_god: TenGods # 지지의 십신
15+
stem_element: FiveElements # 천간의 오행
16+
branch_element: FiveElements # 지지의 오행
417

518
class FourPillar(TypedDict, total=False):
619
year_pillar: str # 년주
@@ -9,3 +22,13 @@ class FourPillar(TypedDict, total=False):
922
time_pillar: Optional[str] # 시주
1023
strong_elements: Optional[List[str]] # 가장 많은 오행
1124
weak_elements: Optional[List[str]] # 가장 적은 오행
25+
26+
class FourPillarDetail(CommonBase):
27+
strong_element: FiveElements # 가장 많은 오행
28+
weak_element: FiveElements # 가장 적은 오행
29+
description: str # 종합 설명
30+
31+
year_pillar_detail: Optional[PillarInfo] # 년주 상세
32+
month_pillar_detail: Optional[PillarInfo] # 월주 상세
33+
day_pillar_detail: Optional[PillarInfo] # 일주 상세
34+
time_pillar_detail: Optional[PillarInfo] # 시주 상세

src/users/entities/schemas.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from typing import List, Optional
33

44
from src.config.schemas import CommonBase
5-
from src.four_pillars.entities.schemas import FourPillar
5+
from src.four_pillars.entities.schemas import FourPillarDetail
66
from src.users.entities.enums import Gender
77

88

@@ -20,12 +20,18 @@ class UserCreate(CommonBase):
2020
gender: Gender
2121

2222

23+
class UserUpdate(CommonBase):
24+
name: Optional[str] = None
25+
birth_date: Optional[datetime] = None
26+
gender: Optional[Gender] = None
27+
28+
2329
class UserDetail(CommonBase):
2430
id: str
2531
name: str
2632
birth_date: datetime
2733
gender: Gender
28-
four_pillar: Optional[FourPillar] = None
34+
four_pillar: Optional[FourPillarDetail] = None
2935

3036

3137
class UserList(CommonBase):

src/users/repository.py

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
from sqlalchemy.ext.asyncio import AsyncSession
66

77
from src.common.dependencies import get_db_session
8-
from src.four_pillars.entities.schemas import FourPillar
8+
from src.four_pillars.entities.schemas import FourPillarDetail
99
from src.users.entities.models import User
10-
from src.users.entities.schemas import UserCreate
10+
from src.users.entities.schemas import UserCreate, UserUpdate
1111

1212

1313
class UserRepository:
@@ -24,15 +24,23 @@ async def get_user_by_id(self, user_id: str) -> Optional[User]:
2424
result = await self.session.execute(query)
2525
return result.scalar_one_or_none()
2626

27+
async def get_user_four_pillar(self, user_id: str) -> Optional[dict]:
28+
"""사용자의 사주 정보만 조회"""
29+
query = select(User.four_pillar).where(User.id == user_id, User.is_active == True)
30+
result = await self.session.execute(query)
31+
return result.scalar_one_or_none()
32+
2733
async def create_user(
28-
self, user_create: UserCreate, four_pillar: FourPillar
34+
self, user_create: UserCreate, four_pillar: FourPillarDetail
2935
) -> User:
36+
four_pillar_dict = four_pillar.model_dump()
37+
3038
user = User(
3139
id=user_create.id,
3240
name=user_create.name,
3341
birth_date=user_create.birth_date,
3442
gender=user_create.gender,
35-
four_pillar=four_pillar,
43+
four_pillar=four_pillar_dict,
3644
is_active=True,
3745
)
3846

@@ -41,3 +49,20 @@ async def create_user(
4149
await self.session.refresh(user)
4250

4351
return user
52+
53+
async def update_user(self, user_id: str, user_update: UserUpdate, four_pillar: Optional[FourPillar] = None) -> Optional[User]:
54+
user = await self.get_user_by_id(user_id)
55+
if not user:
56+
return None
57+
58+
update_data = user_update.model_dump(exclude_unset=True)
59+
if four_pillar is not None:
60+
update_data["four_pillar"] = four_pillar
61+
62+
for field, value in update_data.items():
63+
setattr(user, field, value)
64+
65+
await self.session.flush()
66+
await self.session.refresh(user)
67+
68+
return user

src/users/router.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
from fastapi import APIRouter, Depends, Query, HTTPException
44

5+
from src.four_pillars.entities.schemas import FourPillarDetail
56
from src.lotto.entities.schemas import LottoRecommendation
67
from src.lotto.service import LottoService
7-
from src.users.entities.schemas import UserCreate, UserDetail, UserList
8+
from src.users.entities.schemas import UserCreate, UserDetail, UserList, UserUpdate
89
from src.fortune.entities.schemas import UserDailyFortuneSummary
910
from src.users.service import UserService
1011
from src.fortune.service import FortuneService
@@ -35,6 +36,32 @@ async def create_user(user_create: UserCreate, user_service: UserService = Depen
3536
"""새로운 사용자를 생성합니다."""
3637
return await user_service.create_user(user_create)
3738

39+
40+
@user_router.get("/{user_id}/four-pillar", response_model=FourPillarDetail)
41+
async def get_user_four_pillar(user_id: str, user_service: UserService = Depends()):
42+
"""
43+
사용자의 사주 정보를 조회합니다.
44+
45+
Returns:
46+
- strong_element: 가장 강한 오행
47+
- weak_element: 가장 약한 오행
48+
- description: 사주 종합 설명
49+
- year_pillar_detail: 년주 상세 정보 (천간, 지지, 십신, 오행)
50+
- month_pillar_detail: 월주 상세 정보 (천간, 지지, 십신, 오행)
51+
- day_pillar_detail: 일주 상세 정보 (천간, 지지, 십신, 오행)
52+
- time_pillar_detail: 시주 상세 정보 (천간, 지지, 십신, 오행)
53+
"""
54+
return await user_service.get_user_four_pillar(user_id)
55+
56+
@user_router.put("/{user_id}", response_model=UserDetail)
57+
async def update_user(
58+
user_id: str,
59+
user_update: UserUpdate,
60+
user_service: UserService = Depends()
61+
):
62+
"""사용자 정보를 수정합니다."""
63+
return await user_service.update_user(user_id, user_update)
64+
3865
@user_router.post("/{user_id}/lotto-recommendation", response_model=LottoRecommendation)
3966
async def create_lotto_recommendation(
4067
user_id: str,
@@ -50,7 +77,6 @@ async def create_lotto_recommendation(
5077
status_code=500, detail=f"로또 추천 생성 중 오류가 발생했습니다: {str(e)}"
5178
)
5279

53-
5480
@user_router.get(
5581
"/{user_id}/lotto-recommendation", response_model=Optional[LottoRecommendation]
5682
)

src/users/service.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from fastapi import Depends, HTTPException
22

33
from src.four_pillars.common.calculator import FourPillarsCalculator
4-
from src.users.entities.schemas import UserCreate, UserDetail, UserList
4+
from src.users.entities.schemas import UserCreate, UserDetail, UserList, UserUpdate
55
from src.users.repository import UserRepository
6+
from src.four_pillars.entities.schemas import FourPillarDetail
67

78

89
class UserService:
@@ -30,9 +31,32 @@ async def create_user(self, user_create: UserCreate) -> UserDetail:
3031
if existing_user:
3132
raise HTTPException(status_code=400, detail="User ID already exists")
3233

33-
four_pillar = self.four_pillar_calculator.calculate_four_pillars(
34+
four_pillar = self.four_pillar_calculator.calculate_four_pillars_detailed(
3435
user_create.birth_date
3536
)
3637
created_user = await self.repository.create_user(user_create, four_pillar)
3738

3839
return UserDetail.model_validate(created_user)
40+
41+
async def get_user_four_pillar(self, user_id: str) -> FourPillarDetail:
42+
"""사용자의 사주 정보만 조회"""
43+
four_pillar_dict = await self.repository.get_user_four_pillar(user_id)
44+
if not four_pillar_dict:
45+
raise HTTPException(status_code=404, detail="User not found")
46+
47+
return FourPillarDetail.model_validate(four_pillar_dict)
48+
49+
async def update_user(self, user_id: str, user_update: UserUpdate) -> UserDetail:
50+
four_pillar = None
51+
if user_update.birth_date:
52+
four_pillar = self.four_pillar_calculator.calculate_four_pillars_detailed(
53+
user_update.birth_date
54+
)
55+
56+
updated_user = await self.repository.update_user(
57+
user_id, user_update, four_pillar
58+
)
59+
if not updated_user:
60+
raise HTTPException(status_code=404, detail="User not found")
61+
62+
return UserDetail.model_validate(updated_user)

0 commit comments

Comments
 (0)