Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci-pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ jobs:
id: run-test
run: |
docker run --rm \
-e ENV=local \
-e MONGODB_URL=mongodb://host.docker.internal:27017/xrpedia \
${{ env.TEST_IMAGE_NAME }}
498 changes: 482 additions & 16 deletions poetry.lock

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ package-mode = false
[tool.poetry.dependencies]
python = "^3.12"
fastapi = "^0.115.11"
uvicorn = "^0.34.0"
uvicorn = {extras = ["standard"], version = "^0.34.0"}
pytest = "^8.3.5"
boto3 = "^1.37.16"
botocore = "^1.37.16"
dotenv = "^0.9.9"
httpx = "^0.28.1"
pymongo = "^4.11.3"
requests = "^2.32.3"

[tool.poetry.group.dev.dependencies]
pytest = "^8.3.5"

[build-system]
requires = ["poetry-core"]
Expand Down
2 changes: 0 additions & 2 deletions src/app.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from dotenv import load_dotenv

from src.router import router


load_dotenv()

origins = [
Expand Down
11 changes: 3 additions & 8 deletions src/main/config/mongodb.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,8 @@

load_dotenv()

MONGO_URI = os.getenv("MONGODB_URI")
MONGO_PORT = os.getenv("MONGODB_PORT")
MONGO_DB = os.getenv("MONGODB_DB")
MONGO_USER = os.getenv("MONGODB_USER")
MONGO_PASSWORD = os.getenv("MONGODB_PASSWORD")

MONGODB_URL = os.getenv("MONGODB_URL")

def get_mongo_client():
client = MongoClient("mongodb://" + MONGO_USER + ":" + MONGO_PASSWORD + "@" + MONGO_URI + ":" + MONGO_PORT + "/" + MONGO_DB + "?retryWrites=true")
return client
client = MongoClient(MONGODB_URL + "?retryWrites=true")
return client
Empty file added src/main/users/__init__.py
Empty file.
4 changes: 4 additions & 0 deletions src/main/users/dto/UserWalletDto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from pydantic import BaseModel

class WalletRequest(BaseModel):
wallet_address: str
Empty file added src/main/users/dto/__init__.py
Empty file.
24 changes: 24 additions & 0 deletions src/main/users/repository/UserRepository.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from typing import Optional
from src.main.config.mongodb import get_mongo_client

class UserRepository:
def __init__(self):
client = get_mongo_client()
self.db = client["xrpedia-data"]
self.wallets_collection = self.db["wallets"]

def find_wallets_by_user_id(self, user_id: str) -> list:
wallets = list(self.wallets_collection.find({"user_id": user_id}, {"_id": 0}))
return wallets if wallets else []

def create_or_update_wallet(self, user_id: str, wallet_address: str) -> dict:
existing_wallet = self.wallets_collection.find_one({"user_id": user_id})

if existing_wallet:
self.wallets_collection.update_one({"user_id": user_id},
{"$set": {"address": wallet_address}})
return {"message": "Wallet updated", "user_id": user_id, "wallet_address": wallet_address}

else:
self.wallets_collection.insert_one({"user_id": user_id, "address": wallet_address})
return {"message": "Wallet created", "user_id": user_id, "wallet_address": wallet_address}
27 changes: 27 additions & 0 deletions src/main/users/router/UserAPIRouter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import uuid
from fastapi import APIRouter, Depends
from src.main.auth.dependencies import get_current_user
from src.main.users.service.UserService import UserService
from src.main.users.dto.UserWalletDto import WalletRequest

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

# 유저의 XPRL 지갑 목록 조회
@router.get("/wallets")
async def get_user_wallets(
user_id: uuid.UUID = Depends(get_current_user),
user_service: UserService = Depends()
):
return user_service.get_wallets(str(user_id))

# 유저의 XPRL 지갑 주소 저장 또는 업데이트 하는 API
@router.post("/wallets")
async def create_or_update_wallet(
wallet_data: WalletRequest,
user_id: uuid.UUID = Depends(get_current_user),
user_service: UserService = Depends()
):
return user_service.add_wallet(str(user_id), wallet_data.wallet_address)
Empty file.
16 changes: 16 additions & 0 deletions src/main/users/service/UserService.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from src.main.users.repository.UserRepository import UserRepository

class UserService:
def __init__(self):
self.user_repository = UserRepository()

def get_wallets(self, user_id: str):
wallets = self.user_repository.find_wallets_by_user_id(user_id)

if not wallets:
return {"message": "No wallets found for this user"}

return wallets

def add_wallet(self, user_id: str, wallet_address: str):
return self.user_repository.create_or_update_wallet(user_id, wallet_address)
Empty file.
4 changes: 3 additions & 1 deletion src/router.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from fastapi import APIRouter

from src.main.health.router import HealthAPIRouter
from src.main.users.router import UserAPIRouter


router = APIRouter(
prefix="",
)

router.include_router(HealthAPIRouter.router)
router.include_router(HealthAPIRouter.router)
router.include_router(UserAPIRouter.router)
Empty file added src/tests/users/__init__.py
Empty file.
40 changes: 40 additions & 0 deletions src/tests/users/test_users_api_router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# import requests
# import uuid

# BASE_URL = "http://localhost:8081" #"https://5erhg0u08g.execute-api.ap-northeast-2.amazonaws.com"

# TEST_USER_ID = "11111111-2222-3333-4444-555555555555" # str(uuid.uuid4())
# TEST_WALLET_ADDRESS = "rEXTERNALTESTWALLET123"

# headers = {
# "x-auth-sub": TEST_USER_ID # 추후에 삭제할 부분
# }

# # 지갑 생성 또는 업데이트 (POST /users/wallets)
# def test_create_or_update_wallet():
# response = requests.post(
# f"{BASE_URL}/users/wallets",
# json={"wallet_address": TEST_WALLET_ADDRESS},
# headers=headers
# )

# print("POST response:", response.status_code, response.text) # 로그 출력용

# assert response.status_code == 200, f"Unexpected status: {response.status_code}, response: {response.text}"
# data = response.json()
# assert data["wallet_address"] == TEST_WALLET_ADDRESS
# assert data["user_id"] == TEST_USER_ID
# assert data["message"] in ["Wallet created", "Wallet updated"]

# # 유저 지갑 목록 조회 (GET /users/wallets)
# def test_get_wallets():
# response = requests.get(f"{BASE_URL}/users/wallets", headers=headers)

# assert response.status_code == 200, f"Unexpected status: {response.status_code}, response: {response.text}"
# data = response.json()

# if isinstance(data, dict) and "message" in data:
# assert data["message"] == "No wallets found for this user"
# else:
# assert isinstance(data, list)
# assert any(wallet["address"] == TEST_WALLET_ADDRESS for wallet in data)