Skip to content

Commit

Permalink
feat: level up 로직 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
taewoo-dev committed Oct 20, 2024
1 parent f2fc7b3 commit cfc29de
Show file tree
Hide file tree
Showing 20 changed files with 232 additions and 40 deletions.
9 changes: 9 additions & 0 deletions src/app/v2/answers/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from app.v2.answers.services.answer_service import AnswerService

from app.v2.levels.services.level_service import LevelService

router = APIRouter(prefix="/answer", tags=["Test용"])


Expand All @@ -11,3 +13,10 @@ async def get_answer_record_view():
user_id = "180a4e40-62f8-46be-b1eb-e7e3dd91cddf"
record_dto = await AnswerService.get_answer_record(user_id)
return {"user_id": user_id, "consecutive_answer_days": record_dto.count}


@router.get("/level-up")
async def level_up_handler():
user_id = "180a4e40-62f8-46be-b1eb-e7e3dd91cddf"
result = await LevelService.level_up(user_id=user_id)
return result
4 changes: 4 additions & 0 deletions src/app/v2/badges/dtos/badge_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
class BadgeCodeDTO(BaseModel):
badgeCode: str

@classmethod
def builder(cls, badge_raw: dict) -> "BadgeCodeDTO":
return cls(badgeCode=badge_raw.get("badge_code"))


class BadgeDTO(BaseModel):
badgeCode: str
Expand Down
9 changes: 9 additions & 0 deletions src/app/v2/badges/services/badge_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from app.v2.badges.dtos.badge_dto import BadgeCodeDTO
from app.v2.badges.models.badge import Badge


class BadgeService:
@classmethod
async def get_badges(cls, user_id: str) -> list[BadgeCodeDTO]:
badges_raw = await Badge.get_badge_codes_by_user_id(user_id=user_id)
return [BadgeCodeDTO.builder(badge) for badge in badges_raw]
Empty file.
9 changes: 9 additions & 0 deletions src/app/v2/cheese_managers/dtos/cheese_dto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from pydantic import BaseModel


class CheeseResponseDTO(BaseModel):
cheeseBalance: int

@classmethod
def builder(cls, cheese_balance: int) -> "CheeseResponseDTO":
return cls(cheeseBalance=cheese_balance)
16 changes: 16 additions & 0 deletions src/app/v2/cheese_managers/router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from fastapi import APIRouter, status

from app.v2.cheese_managers.dtos.cheese_dto import CheeseResponseDTO
from app.v2.cheese_managers.services.cheese_service import CheeseService
from app.v2.users.services.user_service import UserService

router = APIRouter(prefix="/cheese", tags=["Cheese"])


@router.get("", response_model=CheeseResponseDTO, status_code=status.HTTP_200_OK)
async def get_cheese_handler():
user_id = "180a4e40-62f8-46be-b1eb-e7e3dd91cddf"
user = await UserService.get_user_info(user_id=user_id)
cheese_amount = await CheeseService.get_cheese_balance(user["cheese_manager_id"])

return CheeseResponseDTO.builder(cheese_balance=cheese_amount)
Empty file.
10 changes: 10 additions & 0 deletions src/app/v2/cheese_managers/services/cheese_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from app.v2.cheese_managers.models.cheese_manager import CheeseManager


class CheeseService:

@classmethod
async def get_cheese_balance(cls, cheese_manager_id: str) -> int:
return await CheeseManager.get_total_cheese_amount_by_manager(
cheese_manager_id=cheese_manager_id
)
4 changes: 4 additions & 0 deletions src/app/v2/colors/dtos/color_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@

class ColorCodeDTO(BaseModel):
colorCode: str

@classmethod
def builder(cls, color_raw: dict) -> "ColorCodeDTO":
return cls(colorCode=color_raw.get("color_code"))
9 changes: 9 additions & 0 deletions src/app/v2/colors/services/color_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from app.v2.colors.dtos.color_dto import ColorCodeDTO
from app.v2.colors.models.color import Color


class ColorService:
@classmethod
async def get_colors(cls, user_id: str) -> list[ColorCodeDTO]:
colors_raw = await Color.get_color_codes_by_user_id(user_id=user_id)
return [ColorCodeDTO.builder(color) for color in colors_raw]
4 changes: 4 additions & 0 deletions src/app/v2/levels/dtos/level_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@
class LevelDTO(BaseModel):
level: int
current_exp: int

@classmethod
def builder(cls, level: int, current_exp: int) -> "LevelDTO":
return cls(level=level, current_exp=current_exp)
18 changes: 18 additions & 0 deletions src/app/v2/levels/models/level.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

from app.v2.levels.querys.level_query import (
SELECT_USER_LEVEL_AND_EXP_BY_USER_UUID_QUERY,
SELECT_USER_EXP_QUERY,
UPDATE_USER_LEVEL_AND_EXP_QUERY,
)
from common.utils.query_executor import QueryExecutor

Expand All @@ -22,3 +24,19 @@ async def get_level_info_by_user_id(cls, user_id: str) -> dict | None:
return await QueryExecutor.execute_query(
query, values=value, fetch_type="single"
)

@classmethod
async def get_required_exp_by_user_id(cls, user_id: str) -> dict | None:
query = SELECT_USER_EXP_QUERY
value = user_id
return await QueryExecutor.execute_query(
query, values=(value,), fetch_type="single"
)

@classmethod
async def update_level_and_exp(
cls, user_id: str, new_level: int, new_exp: int
) -> None:
query = UPDATE_USER_LEVEL_AND_EXP_QUERY
values = (new_level, new_exp, user_id)
await QueryExecutor.execute_query(query, values=values, fetch_type="single")
16 changes: 16 additions & 0 deletions src/app/v2/levels/querys/level_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,19 @@
level l ON u.level_id = l.level_id
WHERE {USER_ID_QUERY}
"""

SELECT_USER_EXP_QUERY = f"""
SELECT li.required_exp
FROM user u
JOIN level l ON u.level_id = l.level_id
JOIN level_inventory li ON l.user_level = li.level
WHERE {USER_ID_QUERY}
LIMIT 1;
"""

UPDATE_USER_LEVEL_AND_EXP_QUERY = f"""
UPDATE level l
JOIN user u ON u.level_id = l.level_id
SET l.user_level = %s, l.user_exp = %s
WHERE {USER_ID_QUERY};
"""
52 changes: 52 additions & 0 deletions src/app/v2/levels/services/level_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import asyncio

from app.v2.levels.dtos.level_dto import LevelDTO
from app.v2.levels.models.level import Level


class LevelService:
@classmethod
async def get_level_info(cls, user_id: str) -> LevelDTO:
# 레벨 정보를 조회하는 로직
level_info_raw = await Level.get_level_info_by_user_id(user_id=user_id)
return LevelDTO.builder(
level=level_info_raw.get("level_level"),
current_exp=level_info_raw.get("level_exp"),
)

@classmethod
async def level_up(cls, user_id: str) -> dict:
"""
유저가 레벨업 가능한지 확인 후, 레벨업 처리
"""
level_dto, required_exp_raw = await asyncio.gather(
cls.get_level_info(user_id=user_id),
Level.get_required_exp_by_user_id(user_id=user_id),
)

level = level_dto.level
current_exp = level_dto.current_exp
required_exp = required_exp_raw["required_exp"]

if current_exp >= required_exp:
new_exp = current_exp - required_exp
new_level = level + 1

await Level.update_level_and_exp(
user_id=user_id, new_level=new_level, new_exp=new_exp
)

return {
"status": "success",
"message": "레벨업 성공",
"new_level": new_level,
"remaining_exp": new_exp,
}

return {
"status": "failure",
"message": "레벨업에 필요한 경험치가 부족합니다",
"current_level": level,
"current_exp": current_exp,
"required_exp": required_exp,
}
65 changes: 26 additions & 39 deletions src/app/v2/mobiles/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,28 @@
from fastapi import APIRouter, status, HTTPException

from app.v2.answers.models.answer import Answer
from app.v2.badges.dtos.badge_dto import BadgeCodeDTO

from app.v2.badges.models.badge import Badge
from app.v2.badges.services.badge_service import BadgeService
from app.v2.cheese_managers.models.cheese_manager import CheeseManager
from app.v2.colors.dtos.color_dto import ColorCodeDTO
from app.v2.colors.models.color import Color
from app.v2.cheese_managers.services.cheese_service import CheeseService

from app.v2.colors.services.color_service import ColorService
from app.v2.levels.dtos.level_dto import LevelDTO
from app.v2.levels.models.level import Level
from app.v2.levels.services.level_service import LevelService

from app.v2.mobiles.dtos.mypage_response import (
UserProfileWithLevel,
MyPageResponseDTO,
)
from app.v2.mobiles.dtos.teller_card_response import DataDTO, TellerCardResponseDTO
from app.v2.teller_cards.dtos.teller_card_dto import TellerCardDTO
from app.v2.teller_cards.models.teller_card import TellerCard

from app.v2.teller_cards.services.teller_card_service import TellerCardService
from app.v2.users.dtos.user_info_dto import UserInfoDTO
from app.v2.users.dtos.user_profile_dto import UserProfileDTO
from app.v2.users.models.user import User
from app.v2.users.services.user_service import UserService

router = APIRouter(prefix="/mobiles", tags=["모바일 화면용 컨트롤러"])

Expand All @@ -30,50 +34,33 @@ async def mobile_main_handler():
pass


@router.get("/tellercard")
@router.get(
"/tellercard",
response_model=TellerCardResponseDTO,
status_code=status.HTTP_200_OK,
)
async def mobile_teller_card_handler():
user_id = "180a4e40-62f8-46be-b1eb-e7e3dd91cddf"

try:
badges_raw, colors_raw, level_info_raw, teller_cards_raw, user_raw = (
await asyncio.gather(
Badge.get_badge_codes_by_user_id(user_id=user_id),
Color.get_color_codes_by_user_id(user_id=user_id),
Level.get_level_info_by_user_id(user_id=user_id),
TellerCard.get_teller_card_info_by_user_id(user_id=user_id),
User.get_user_info_by_user_id(user_id=user_id),
)
badges_task = BadgeService.get_badges(user_id)
colors_task = ColorService.get_colors(user_id)
level_info_task = LevelService.get_level_info(user_id) # LevelService 추가
teller_card_task = TellerCardService.get_teller_card(user_id)
user_info_task = UserService.get_user_info(user_id)

badges, colors, level_info, teller_card, user_raw = await asyncio.gather(
badges_task, colors_task, level_info_task, teller_card_task, user_info_task
)
except Exception as e:
raise HTTPException(status_code=500, detail="내부 서버 오류")

cheese_amount = await CheeseManager.get_total_cheese_amount_by_manager(
cheese_manager_id=user_raw["cheese_manager_id"]
)

badges: list[BadgeCodeDTO] = [
BadgeCodeDTO(badgeCode=badge.get("badge_code")) for badge in badges_raw
]
colors: list[ColorCodeDTO] = [
ColorCodeDTO(colorCode=color.get("color_code")) for color in colors_raw
]

teller_card = TellerCardDTO(
badgeCode=teller_cards_raw.get("activate_badge_code"),
badgeName=teller_cards_raw.get("badge_name"),
badgeMiddleName=teller_cards_raw.get("badge_middle_name"),
colorCode=teller_cards_raw.get("activate_color_code"),
)

user_info = UserInfoDTO(
nickname=user_raw.get("nickname"),
cheeseBalance=cheese_amount,
tellerCard=teller_card,
cheese_amount = await CheeseService.get_cheese_balance(
user_raw["cheese_manager_id"]
)

level_info: LevelDTO = LevelDTO(
level=level_info_raw.get("level_level"),
current_exp=level_info_raw.get("level_exp"),
user_info = UserInfoDTO.builder(
user_raw, cheeseBalance=cheese_amount, tellerCard=teller_card
)

data = DataDTO(badges=badges, colors=colors, userInfo=user_info, level=level_info)
Expand Down
9 changes: 9 additions & 0 deletions src/app/v2/teller_cards/dtos/teller_card_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,12 @@ class TellerCardDTO(BaseModel):
badgeName: str
badgeMiddleName: str
colorCode: str

@classmethod
def builder(cls, teller_card_raw: dict) -> "TellerCardDTO":
return cls(
badgeCode=teller_card_raw.get("activate_badge_code"),
badgeName=teller_card_raw.get("badge_name"),
badgeMiddleName=teller_card_raw.get("badge_middle_name"),
colorCode=teller_card_raw.get("activate_color_code"),
)
11 changes: 11 additions & 0 deletions src/app/v2/teller_cards/services/teller_card_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from app.v2.teller_cards.dtos.teller_card_dto import TellerCardDTO
from app.v2.teller_cards.models.teller_card import TellerCard


class TellerCardService:
@classmethod
async def get_teller_card(cls, user_id: str) -> TellerCardDTO:
teller_cards_raw = await TellerCard.get_teller_card_info_by_user_id(
user_id=user_id
)
return TellerCardDTO.builder(teller_cards_raw)
11 changes: 10 additions & 1 deletion src/app/v2/users/dtos/user_info_dto.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
from pydantic import BaseModel

from app.v2.teller_cards.dtos.teller_card_dto import TellerCardDTO


class UserInfoDTO(BaseModel):
nickname: str
cheeseBalance: int
tellerCard: TellerCardDTO

@classmethod
def builder(
cls, user_raw: dict, cheeseBalance: int, tellerCard: TellerCardDTO
) -> "UserInfoDTO":
return cls(
nickname=user_raw.get("nickname"),
cheeseBalance=cheeseBalance,
tellerCard=tellerCard,
)
14 changes: 14 additions & 0 deletions src/app/v2/users/services/user_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from app.v2.cheese_managers.models.cheese_manager import CheeseManager
from app.v2.users.models.user import User


class UserService:
@classmethod
async def get_user_info(cls, user_id: str) -> dict:
return await User.get_user_info_by_user_id(user_id=user_id)

@classmethod
async def get_cheese_balance(cls, cheese_manager_id: str) -> int:
return await CheeseManager.get_total_cheese_amount_by_manager(
cheese_manager_id=cheese_manager_id
)
2 changes: 2 additions & 0 deletions src/common/handlers/router_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from app.v2.payments.router import router as payment_router
from app.v2.missions.router import router as mission_router
from app.v2.answers.router import router as answer_router
from app.v2.cheese_managers.router import router as cheese_router


def attach_router_handlers(app):
Expand All @@ -14,4 +15,5 @@ def attach_router_handlers(app):
app.include_router(router=teller_card_router, prefix="/api/v2")
app.include_router(router=payment_router, prefix="/api/v2")
app.include_router(router=mission_router, prefix="/api/v2")
app.include_router(router=cheese_router, prefix="/api/v2")
app.include_router(router=answer_router, prefix="/test")

0 comments on commit cfc29de

Please sign in to comment.