Skip to content

Commit 8ccb987

Browse files
authored
๐Ÿ”ฅ ๋ถˆํ•„์š”ํ•œ models ํด๋” ์ œ๊ฑฐ ๋ฐ seed์—์„œ ๋ถˆํ•„์š”ํ•œ model class import ์ œ๊ฑฐ (#61)
* โ™ป๏ธ ๋ถˆํ•„์š”ํ•œ local import๋ฅผ ์ƒ๋‹จ import๋กœ ๋ณ€๊ฒฝ * ๐Ÿ”ฅ ๋ถˆํ•„์š”ํ•œ models ํด๋” ์ œ๊ฑฐ * โ™ป๏ธ seed๋ฅผ ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋ชจ๋ธ class import ์ œ๊ฑฐ * ๐ŸŽจ ํฌ๋งคํŒ… ์ ์šฉ
1 parent d29a4f2 commit 8ccb987

7 files changed

Lines changed: 146 additions & 132 deletions

File tree

โ€Žapp/db/seed.pyโ€Ž

Lines changed: 136 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -2,143 +2,155 @@
22
from typing import cast
33
from uuid import uuid4
44

5-
from sqlalchemy.ext.asyncio import AsyncEngine
5+
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
66

7-
from app.application.models import ( # noqa: F401
8-
Application,
9-
ReviewImage,
10-
ReviewSubmission,
11-
)
12-
from app.auth.models import EmailVerification, User # noqa: F401
13-
from app.blockchain.service_impl import BlockchainServiceImpl
14-
from app.core.config import settings
7+
from app.auth.models import User
8+
from app.blockchain.service import BlockchainService
159
from app.core.security import get_password_hash
1610
from app.db.base import Base
17-
from app.db.session import AsyncSessionLocal
1811
from app.event.models import Event
1912
from app.store.models import Store
2013

2114
logger = logging.getLogger(__name__)
2215

2316

24-
async def _deploy_or_none() -> str | None:
25-
if not settings.blockchain_rpc_url or not settings.server_private_key:
26-
return None
27-
try:
28-
return await BlockchainServiceImpl().deploy_contract()
29-
except Exception:
30-
logger.exception("[SEED] contract deploy failed, skipping")
31-
return None
17+
class Seeder:
18+
def __init__(
19+
self,
20+
engine: AsyncEngine,
21+
session_factory: async_sessionmaker[AsyncSession],
22+
blockchain_service: BlockchainService | None,
23+
) -> None:
24+
self._engine = engine
25+
self._sessions = session_factory
26+
self._blockchain = blockchain_service
3227

28+
async def run(self) -> None:
29+
await self._reset()
30+
await self._seed()
3331

34-
async def _fund_contract(contract_address: str, amount_wei: int) -> None:
35-
try:
36-
await BlockchainServiceImpl().fund_contract(contract_address, amount_wei)
37-
except Exception:
38-
logger.exception("[SEED] contract fund failed contract=%s", contract_address)
32+
async def _reset(self) -> None:
33+
async with self._engine.begin() as conn:
34+
await conn.run_sync(Base.metadata.drop_all)
35+
await conn.run_sync(Base.metadata.create_all)
3936

37+
async def _deploy_contract(self) -> str | None:
38+
if not self._blockchain:
39+
return None
40+
try:
41+
return await self._blockchain.deploy_contract()
42+
except Exception:
43+
logger.exception("[SEED] contract deploy failed, skipping")
44+
return None
4045

41-
async def reset_and_seed(engine: AsyncEngine) -> None:
42-
async with engine.begin() as conn:
43-
await conn.run_sync(Base.metadata.drop_all)
44-
await conn.run_sync(Base.metadata.create_all)
46+
async def _fund_contract(self, contract_address: str, amount_wei: int) -> None:
47+
if not self._blockchain:
48+
return
49+
try:
50+
await self._blockchain.fund_contract(contract_address, amount_wei)
51+
except Exception:
52+
logger.exception(
53+
"[SEED] contract fund failed contract=%s", contract_address
54+
)
4555

46-
async with AsyncSessionLocal() as session:
47-
# --- ์‚ฌ์žฅ๋‹˜ ๊ณ„์ • ---
48-
owner1 = User(
49-
id=uuid4(),
50-
username="๊น€์ฒ ์ˆ˜",
51-
email="owner1@test.com",
52-
password_hash=get_password_hash("password123"),
53-
role="OWNER",
54-
)
55-
owner2 = User(
56-
id=uuid4(),
57-
username="์ด์˜ํฌ",
58-
email="owner2@test.com",
59-
password_hash=get_password_hash("password123"),
60-
role="OWNER",
61-
)
62-
session.add_all([owner1, owner2])
63-
await session.flush()
56+
async def _seed(self) -> None:
57+
async with self._sessions() as session:
58+
owner1 = User(
59+
id=uuid4(),
60+
username="๊น€์ฒ ์ˆ˜",
61+
email="owner1@test.com",
62+
password_hash=get_password_hash("password123"),
63+
role="OWNER",
64+
)
65+
owner2 = User(
66+
id=uuid4(),
67+
username="์ด์˜ํฌ",
68+
email="owner2@test.com",
69+
password_hash=get_password_hash("password123"),
70+
role="OWNER",
71+
)
72+
session.add_all([owner1, owner2])
73+
await session.flush()
6474

65-
# --- ๊ฐ€๊ฒŒ ---
66-
store1 = Store(
67-
id=uuid4(),
68-
name="๋ง›์žˆ๋Š” ์‚ผ๊ฒน์‚ด",
69-
address="์„œ์šธ์‹œ ๊ฐ•๋‚จ๊ตฌ ํ…Œํ—ค๋ž€๋กœ 1๊ธธ 10",
70-
category="RESTAURANT",
71-
description="์‹ ์„ ํ•œ ๊ตญ๋‚ด์‚ฐ ๋ผ์ง€๊ณ ๊ธฐ ์ „๋ฌธ์ ",
72-
owner_id=owner1.id,
73-
)
74-
store2 = Store(
75-
id=uuid4(),
76-
name="์นดํŽ˜ ๋ธŒ๋ฃจ์ž‰",
77-
address="์„œ์šธ์‹œ ๋งˆํฌ๊ตฌ ํ™์ต๋กœ 5๊ธธ 3",
78-
category="CAFE",
79-
description="์ŠคํŽ˜์…œํ‹ฐ ์›๋‘๋ฅผ ์ง์ ‘ ๋กœ์ŠคํŒ…ํ•˜๋Š” ์นดํŽ˜",
80-
owner_id=owner1.id,
81-
)
82-
store3 = Store(
83-
id=uuid4(),
84-
name="์—์ด๋ธ” ํŒจ์…˜",
85-
address="์„œ์šธ์‹œ ์ค‘๊ตฌ ๋ช…๋™๊ธธ 20",
86-
category="FASHION",
87-
description="ํŠธ๋ Œ๋””ํ•œ ์—ฌ์„ฑ ์˜๋ฅ˜ ํŽธ์ง‘์ƒต",
88-
owner_id=owner2.id,
89-
)
90-
store4 = Store(
91-
id=uuid4(),
92-
name="๊ธ€๋กœ์šฐ ๋ทฐํ‹ฐ์‚ด๋กฑ",
93-
address="์„œ์šธ์‹œ ์„œ์ดˆ๊ตฌ ๋ฐ˜ํฌ๋Œ€๋กœ 8๊ธธ 15",
94-
category="BEAUTY",
95-
description="ํ”ผ๋ถ€ ๊ด€๋ฆฌ ๋ฐ ๋„ค์ผ ์ „๋ฌธ ๋ทฐํ‹ฐ์ƒต",
96-
owner_id=owner2.id,
97-
)
98-
session.add_all([store1, store2, store3, store4])
99-
await session.flush()
75+
store1 = Store(
76+
id=uuid4(),
77+
name="๋ง›์žˆ๋Š” ์‚ผ๊ฒน์‚ด",
78+
address="์„œ์šธ์‹œ ๊ฐ•๋‚จ๊ตฌ ํ…Œํ—ค๋ž€๋กœ 1๊ธธ 10",
79+
category="RESTAURANT",
80+
description="์‹ ์„ ํ•œ ๊ตญ๋‚ด์‚ฐ ๋ผ์ง€๊ณ ๊ธฐ ์ „๋ฌธ์ ",
81+
owner_id=owner1.id,
82+
)
83+
store2 = Store(
84+
id=uuid4(),
85+
name="์นดํŽ˜ ๋ธŒ๋ฃจ์ž‰",
86+
address="์„œ์šธ์‹œ ๋งˆํฌ๊ตฌ ํ™์ต๋กœ 5๊ธธ 3",
87+
category="CAFE",
88+
description="์ŠคํŽ˜์…œํ‹ฐ ์›๋‘๋ฅผ ์ง์ ‘ ๋กœ์ŠคํŒ…ํ•˜๋Š” ์นดํŽ˜",
89+
owner_id=owner1.id,
90+
)
91+
store3 = Store(
92+
id=uuid4(),
93+
name="์—์ด๋ธ” ํŒจ์…˜",
94+
address="์„œ์šธ์‹œ ์ค‘๊ตฌ ๋ช…๋™๊ธธ 20",
95+
category="FASHION",
96+
description="ํŠธ๋ Œ๋””ํ•œ ์—ฌ์„ฑ ์˜๋ฅ˜ ํŽธ์ง‘์ƒต",
97+
owner_id=owner2.id,
98+
)
99+
store4 = Store(
100+
id=uuid4(),
101+
name="๊ธ€๋กœ์šฐ ๋ทฐํ‹ฐ์‚ด๋กฑ",
102+
address="์„œ์šธ์‹œ ์„œ์ดˆ๊ตฌ ๋ฐ˜ํฌ๋Œ€๋กœ 8๊ธธ 15",
103+
category="BEAUTY",
104+
description="ํ”ผ๋ถ€ ๊ด€๋ฆฌ ๋ฐ ๋„ค์ผ ์ „๋ฌธ ๋ทฐํ‹ฐ์ƒต",
105+
owner_id=owner2.id,
106+
)
107+
session.add_all([store1, store2, store3, store4])
108+
await session.flush()
100109

101-
# --- ์ด๋ฒคํŠธ (๊ฐ๊ฐ ์ปจํŠธ๋ž™ํŠธ ๋ฐฐํฌ) ---
102-
event_specs = [
103-
dict(
104-
title="์‚ผ๊ฒน์‚ด ๋ง›์ง‘ ๋ธ”๋กœ๊ทธ ๋ฆฌ๋ทฐ ๋ชจ์ง‘",
105-
condition="๋„ค์ด๋ฒ„ ๋ธ”๋กœ๊ทธ ์‚ฌ์ง„ 5์žฅ ์ด์ƒ, 300์ž ์ด์ƒ ๋ฆฌ๋ทฐ ์ž‘์„ฑ",
106-
reward=10_000_000_000_000_000, # 0.01 ETH
107-
is_active=True,
108-
store_id=store1.id,
109-
),
110-
dict(
111-
title="์‚ผ๊ฒน์‚ด์ง‘ ์ธ์Šคํƒ€๊ทธ๋žจ ๋ฆฌ๋ทฐ",
112-
condition="์ธ์Šคํƒ€๊ทธ๋žจ์— ํ•ด์‹œํƒœ๊ทธ #๋ง›์žˆ๋Š”์‚ผ๊ฒน์‚ด ํฌํ•จ ๊ฒŒ์‹œ๋ฌผ ์—…๋กœ๋“œ",
113-
reward=5_000_000_000_000_000, # 0.005 ETH
114-
is_active=True,
115-
store_id=store1.id,
116-
),
117-
dict(
118-
title="์นดํŽ˜ ๋ธŒ๋ฃจ์ž‰ ์Œ๋ฃŒ ๋ฆฌ๋ทฐ",
119-
condition="๋„ค์ด๋ฒ„ ์ง€๋„ ๋ฆฌ๋ทฐ ์ž‘์„ฑ",
120-
reward=3_000_000_000_000_000, # 0.003 ETH
121-
is_active=True,
122-
store_id=store2.id,
123-
),
124-
dict(
125-
title="์—์ด๋ธ” ํŒจ์…˜ ์Šคํƒ€์ผ๋ง ํ›„๊ธฐ",
126-
condition="๊ตฌ๋งค ํ›„ ์ฐฉ์šฉ์ƒท๊ณผ ํ•จ๊ป˜ SNS ๊ฒŒ์‹œ",
127-
reward=15_000_000_000_000_000, # 0.015 ETH
128-
is_active=True,
129-
store_id=store3.id,
130-
),
131-
dict(
132-
title="๊ธ€๋กœ์šฐ ๋ทฐํ‹ฐ์‚ด๋กฑ ์‹œ์ˆ  ํ›„๊ธฐ",
133-
condition="์นด์นด์˜ค๋งต ๋ฆฌ๋ทฐ 200์ž ์ด์ƒ + ์‚ฌ์ง„ 3์žฅ ์ด์ƒ ์ฒจ๋ถ€",
134-
reward=8_000_000_000_000_000, # 0.008 ETH
135-
is_active=False,
136-
store_id=store4.id,
137-
),
138-
]
139-
for spec in event_specs:
140-
contract_address = await _deploy_or_none()
141-
if contract_address:
142-
await _fund_contract(contract_address, cast(int, spec["reward"]))
143-
session.add(Event(id=uuid4(), contract_address=contract_address, **spec))
144-
await session.commit()
110+
event_specs = [
111+
dict(
112+
title="์‚ผ๊ฒน์‚ด ๋ง›์ง‘ ๋ธ”๋กœ๊ทธ ๋ฆฌ๋ทฐ ๋ชจ์ง‘",
113+
condition="๋„ค์ด๋ฒ„ ๋ธ”๋กœ๊ทธ ์‚ฌ์ง„ 5์žฅ ์ด์ƒ, 300์ž ์ด์ƒ ๋ฆฌ๋ทฐ ์ž‘์„ฑ",
114+
reward=10_000_000_000_000_000, # 0.01 ETH
115+
is_active=True,
116+
store_id=store1.id,
117+
),
118+
dict(
119+
title="์‚ผ๊ฒน์‚ด์ง‘ ์ธ์Šคํƒ€๊ทธ๋žจ ๋ฆฌ๋ทฐ",
120+
condition="์ธ์Šคํƒ€๊ทธ๋žจ์— ํ•ด์‹œํƒœ๊ทธ #๋ง›์žˆ๋Š”์‚ผ๊ฒน์‚ด ํฌํ•จ ๊ฒŒ์‹œ๋ฌผ ์—…๋กœ๋“œ",
121+
reward=5_000_000_000_000_000, # 0.005 ETH
122+
is_active=True,
123+
store_id=store1.id,
124+
),
125+
dict(
126+
title="์นดํŽ˜ ๋ธŒ๋ฃจ์ž‰ ์Œ๋ฃŒ ๋ฆฌ๋ทฐ",
127+
condition="๋„ค์ด๋ฒ„ ์ง€๋„ ๋ฆฌ๋ทฐ ์ž‘์„ฑ",
128+
reward=3_000_000_000_000_000, # 0.003 ETH
129+
is_active=True,
130+
store_id=store2.id,
131+
),
132+
dict(
133+
title="์—์ด๋ธ” ํŒจ์…˜ ์Šคํƒ€์ผ๋ง ํ›„๊ธฐ",
134+
condition="๊ตฌ๋งค ํ›„ ์ฐฉ์šฉ์ƒท๊ณผ ํ•จ๊ป˜ SNS ๊ฒŒ์‹œ",
135+
reward=15_000_000_000_000_000, # 0.015 ETH
136+
is_active=True,
137+
store_id=store3.id,
138+
),
139+
dict(
140+
title="๊ธ€๋กœ์šฐ ๋ทฐํ‹ฐ์‚ด๋กฑ ์‹œ์ˆ  ํ›„๊ธฐ",
141+
condition="์นด์นด์˜ค๋งต ๋ฆฌ๋ทฐ 200์ž ์ด์ƒ + ์‚ฌ์ง„ 3์žฅ ์ด์ƒ ์ฒจ๋ถ€",
142+
reward=8_000_000_000_000_000, # 0.008 ETH
143+
is_active=False,
144+
store_id=store4.id,
145+
),
146+
]
147+
for spec in event_specs:
148+
contract_address = await self._deploy_contract()
149+
if contract_address:
150+
await self._fund_contract(
151+
contract_address, cast(int, spec["reward"])
152+
)
153+
session.add(
154+
Event(id=uuid4(), contract_address=contract_address, **spec)
155+
)
156+
await session.commit()

โ€Žapp/main.pyโ€Ž

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88

99
from app.application.router import router as application_router
1010
from app.auth.router import router as auth_router
11+
from app.blockchain.service_impl import BlockchainServiceImpl
1112
from app.core.config import settings
1213
from app.core.exceptions import AppException
13-
from app.db.seed import reset_and_seed
14-
from app.db.session import engine
14+
from app.db.seed import Seeder
15+
from app.db.session import AsyncSessionLocal, engine
1516
from app.event.router import router as event_router
1617
from app.s3.router import router as s3_router
1718
from app.store.router import router as store_router
@@ -20,7 +21,12 @@
2021
@asynccontextmanager
2122
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
2223
if settings.seed_db:
23-
await reset_and_seed(engine)
24+
blockchain = (
25+
BlockchainServiceImpl()
26+
if settings.blockchain_rpc_url and settings.server_private_key
27+
else None
28+
)
29+
await Seeder(engine, AsyncSessionLocal, blockchain).run()
2430
yield
2531

2632

โ€Žapp/models/__init__.pyโ€Ž

Whitespace-only changes.

โ€Žapp/models/email_verification.pyโ€Ž

Lines changed: 0 additions & 1 deletion
This file was deleted.

โ€Žapp/models/event.pyโ€Ž

Lines changed: 0 additions & 1 deletion
This file was deleted.

โ€Žapp/models/user.pyโ€Ž

Lines changed: 0 additions & 1 deletion
This file was deleted.

โ€Žtests/test_auth.pyโ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
from sqlalchemy import select
44
from sqlalchemy.ext.asyncio import AsyncSession
55

6+
from app.auth.models import EmailVerification, User
67
from app.core.security import create_refresh_token, verify_password
7-
from app.models.email_verification import EmailVerification
8-
from app.models.user import User
98
from tests.conftest import auth_headers, create_user, create_verification
109

1110

0 commit comments

Comments
ย (0)