diff --git a/.aws/ecs-task-definition.json b/.aws/ecs-task-definition.json index ef56b20..923b9b2 100644 --- a/.aws/ecs-task-definition.json +++ b/.aws/ecs-task-definition.json @@ -35,6 +35,10 @@ { "name": "AWS_S3_BUCKET_NAME", "valueFrom": "arn:aws:secretsmanager:ap-northeast-2:864981757354:secret:xrpedia/credentials-UAy9x0:xrpedia-s3-bucket-name::" + }, + { + "name": "COGNITO_USER_POOL_ID", + "valueFrom": "arn:aws:secretsmanager:ap-northeast-2:864981757354:secret:xrpedia/credentials-UAy9x0:xrpedia-cognito-user-pool-id::" } ], "ulimits": [], diff --git a/src/main/document/dto/document.py b/src/main/document/dto/document.py index b3db460..902fdae 100644 --- a/src/main/document/dto/document.py +++ b/src/main/document/dto/document.py @@ -9,7 +9,7 @@ class saveDocument(BaseModel): downloads: int # 더미 pageNumber: int # 더미 upload_date: datetime - uploader_id: str + uploader: str price: float category: str rating: float # 더미 diff --git a/src/main/document/repository/document_repository.py b/src/main/document/repository/document_repository.py index 8574a7c..b5b59cf 100644 --- a/src/main/document/repository/document_repository.py +++ b/src/main/document/repository/document_repository.py @@ -32,7 +32,7 @@ def get_document(document_id: str) -> documentDetailDto: downloads= get_doc["downloads"], pageNumber= int(get_doc["pageNumber"], 0), upload_date= get_doc["upload_date"], - uploader= get_doc["uploader_id"], #이거 추후에 변경해야 함함 + uploader= get_doc["uploader"], #이거 추후에 변경해야 함함 price= get_doc["price"], category= get_doc["category"], rating= get_doc["rating"]) @@ -59,7 +59,7 @@ def get_documents_by_user(user_id: str) -> List[documentDetailDto]: downloads=doc["downloads"], pageNumber=doc["pageNumber"], upload_date=doc["upload_date"], - uploader=doc["uploader_id"], + uploader=doc["uploader"], price=doc["price"], category=doc["category"], rating=doc["rating"] @@ -94,7 +94,7 @@ def get_all_documents(): downloads=doc["downloads"], pageNumber=doc["pageNumber"], upload_date=doc["upload_date"], - uploader=doc["uploader_id"], + uploader=doc["uploader"], price=doc["price"], category=doc["category"], rating=doc["rating"] diff --git a/src/main/document/service/document_service.py b/src/main/document/service/document_service.py index 47aeebf..7c4d3b4 100644 --- a/src/main/document/service/document_service.py +++ b/src/main/document/service/document_service.py @@ -6,6 +6,7 @@ from src.main.user.repository.UserRepository import get_user from src.main.nft.service.nft_service import process_nft_issuance_with_response from src.main.document.dto.document import saveDocument, documentRequestDto +from src.main.user.service import UserService from datetime import datetime import asyncio @@ -14,6 +15,9 @@ async def save_document_service(request: documentRequestDto, user_id: str) : upload_date = datetime.now() + user = UserService.get_user_info(user_id) + user_name = user["nickname"] + saved = saveDocument( file_id = request.file_id, document_name = request.document_name, @@ -22,7 +26,7 @@ async def save_document_service(request: documentRequestDto, user_id: str) : downloads=32, pageNumber=3, upload_date=upload_date, - uploader_id=user_id, + uploader=user_name, price=request.price, category=request.category, rating=4.0 diff --git a/src/main/user/dto/UserInfoDto.py b/src/main/user/dto/UserInfoDto.py new file mode 100644 index 0000000..9b7919e --- /dev/null +++ b/src/main/user/dto/UserInfoDto.py @@ -0,0 +1,8 @@ +from pydantic import BaseModel + +class UserInfoResponse(BaseModel): + user_id: str + nickname: str + level_title: str + point: float + total_revenue: float diff --git a/src/main/user/repository/UserRepository.py b/src/main/user/repository/UserRepository.py index 52c4c04..f428b9e 100644 --- a/src/main/user/repository/UserRepository.py +++ b/src/main/user/repository/UserRepository.py @@ -1,21 +1,59 @@ from src.config.mongodb import get_mongo_client +from typing import Optional +from src.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 save_wallet(self, user_id: str, wallet_address: str, point: int = 0, nft_grade: str = "bronze"): + existing = self.wallets_collection.find_one({"user_id": user_id}) + if existing: + self.wallets_collection.update_one( + {"user_id": user_id}, + {"$set": {"address": wallet_address, + "point": point, + "nft_grade": nft_grade}} + ) + return {"message": "Wallet updated", + "user_id": user_id, + "wallet_address": wallet_address, + "point": point, + "nft_grade": nft_grade} + else: + self.wallets_collection.insert_one({"user_id": user_id, + "address": wallet_address, + "point": point, + "nft_grade": nft_grade}) + return {"message": "Wallet created", + "user_id": user_id, + "wallet_address": wallet_address, + "point": point, + "nft_grade": nft_grade} + #db에서 user 가져오기 -def get_user(user_id: str) -> str: - client = get_mongo_client() - db = client['xrpedia-data'] - nft_collection = db['wallets'] + def get_user(user_id: str) -> str: + client = get_mongo_client() + db = client['xrpedia-data'] + nft_collection = db['wallets'] - if not user_id: - raise Exception(404, detail="회원 정보를 찾을 수 없습니다.") + if not user_id: + raise Exception(404, detail="회원 정보를 찾을 수 없습니다.") - user = nft_collection.find_one({"user_id": user_id}) + user = nft_collection.find_one({"user_id": user_id}) - if not user: - raise Exception(404, detail="해당 유저를 찾을 수 없습니다.") + if not user: + raise Exception(404, detail="해당 유저를 찾을 수 없습니다.") - # ObjectId는 JSON 직렬화가 안 되므로 필요 시 string으로 바꿔줍니다 - user["_id"] = str(user["_id"]) + # ObjectId는 JSON 직렬화가 안 되므로 필요 시 string으로 바꿔줍니다 + user["_id"] = str(user["_id"]) - return user \ No newline at end of file + return user \ No newline at end of file diff --git a/src/main/user/service/UserService.py b/src/main/user/service/UserService.py new file mode 100644 index 0000000..89c067b --- /dev/null +++ b/src/main/user/service/UserService.py @@ -0,0 +1,157 @@ +from xrpl.clients import JsonRpcClient +from xrpl.asyncio.wallet import generate_faucet_wallet +from xrpl.models.requests import AccountInfo, AccountTx +from xrpl.utils import xrp_to_drops +from src.main.user.repository.UserRepository import UserRepository +import boto3 +import os +from src.main.user.dto.UserInfoDto import UserInfoResponse +from dotenv import load_dotenv + +load_dotenv() + +TESTNET_URL = "https://s.altnet.rippletest.net:51234" +client = JsonRpcClient(TESTNET_URL) +class UserService: + def __init__(self): + self.user_repository = UserRepository() + self.user_pool_id = os.environ.get('COGNITO_USER_POOL_ID', '') + if os.environ.get('ENV') == 'local-profile': + session = boto3.Session( + profile_name=os.environ.get('AWS_PROFILE', 'default') + ) + self.cognito_client = session.client( + 'cognito-idp', + region_name=os.environ.get('AWS_REGION', 'ap-northeast-2') + ) + else: + self.cognito_client = boto3.client( + 'cognito-idp', + region_name=os.environ.get('AWS_REGION', 'ap-northeast-2') + ) + + 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 + + async def generate_wallet(self, user_id: str): + wallet = await generate_faucet_wallet(client=client, debug=True) + wallet_address = wallet.classic_address + result = self.user_repository.save_wallet(user_id, wallet_address) + return result + + def get_account_info(self, client: JsonRpcClient, address: str, **kwargs) -> dict: + """ + XRPL 네트워크에서 이 계정의 정보를 가져옵니다. + + Args: + client (JsonRpcClient): 요청을 보낼 클라이언트입니다. + address (str): 계정 정보를 조회할 계정의 주소입니다. + **kwargs: 추가적인 선택적 매개변수들입니다. + + Returns: + dict: 이 계정의 정보를 포함하는 딕셔너리 객체입니다. + """ + return client.request(AccountInfo(account=address, **kwargs)) + + def get_account_transactions(self, client: JsonRpcClient, address: str, limit: int = 0, **kwargs) -> list: + """ + XRPL 네트워크에서 이 계정의 거래 내역을 가져옵니다. + + Args: + client (JsonRpcClient): 요청을 보낼 클라이언트입니다. + address (str): 거래 내역을 조회할 계정의 주소입니다. + limit (Optional[int]): 검색할 거래의 최대 개수입니다. 0이면 모두 검색합니다. 기본값은 0입니다. + **kwargs: 추가적인 선택적 매개변수들입니다. + + Returns: + list: 이 계정의 거래 내역을 포함하는 리스트입니다. + """ + result = client.request(AccountTx(account=address, limit=limit, **kwargs)) + return result.get('result', {}).get('transactions', []) + + def get_user_info(self, user_id: str) -> UserInfoResponse: + # Cognito에서 nickname 조회 + nickname = "Unknown" + try: + if self.user_pool_id: + # Cognito 사용자 풀에서 사용자 정보 조회 + response = self.cognito_client.list_users( + UserPoolId=self.user_pool_id, + Filter=f'sub = "{user_id}"' + ) + + if response.get('Users') and len(response['Users']) > 0: + # 사용자의 속성에서 nickname 찾기 + for attr in response['Users'][0].get('Attributes', []): + if attr['Name'] == 'nickname': + nickname = attr['Value'] + break + except Exception as e: + print(f"Error fetching user from Cognito: {str(e)}") + + # MongoDB에서 사용자의 지갑 주소 조회 + # point = 0.0 + # total_revenue = 0.0 + # wallets = self.user_repository.find_wallets_by_user_id(user_id) + # if wallets: + # try: + # # 첫 번째 지갑의 잔액 조회 + # wallet_address = wallets[0].get('address') + # if wallet_address: + # # XRPL 네트워크에서 계정 정보 조회 + # account_info = self.get_account_info(client, wallet_address) + # if account_info and 'result' in account_info: + # # 잔액 정보 추출 + # balance = account_info['result'].get('account_data', {}).get('Balance', '0') + # # XRP 단위로 변환 (XRP는 소수점 6자리까지 표현) + # point = float(balance) / 1000000 + + # # 계정의 거래 내역 조회 + # transactions = self.get_account_transactions(client, wallet_address) + + # # 사용자가 받은 모든 금액 합산 (수익) + # for tx in transactions: + # # 트랜잭션이 '지불' 타입이고, 이 지갑이 수취인인 경우 + # if (tx.get('tx', {}).get('TransactionType') == 'Payment' and + # tx.get('tx', {}).get('Destination') == wallet_address): + # # 지불된 금액 추출 (delivered_amount 또는 Amount 사용) + # delivered_amount = tx.get('meta', {}).get('delivered_amount') + # amount = tx.get('tx', {}).get('Amount') + + # # 실제 받은 금액 계산 + # received_amount = 0 + # if delivered_amount and isinstance(delivered_amount, str): + # received_amount = float(delivered_amount) / 1000000 + # elif amount and isinstance(amount, str): + # received_amount = float(amount) / 1000000 + + # total_revenue += received_amount + + # except Exception as e: + # print(f"Error fetching data from XRPL: {str(e)}") + + # nft_grade, point, total_revenue 조회 -> 모두 `wallets` 컬렉션에서 조회 + total_revenue = 0.0 + point = 0.0 + nft_grade = "조회되지 않음" + + wallets = self.user_repository.find_wallets_by_user_id(user_id) + if wallets: + for wallet in wallets: + total_revenue += wallet.get('total_revenue', 0.0) + point += wallet.get('point', 0.0) + nft_grade = wallet.get('nft_grade', "조회되지 않음") + + # 응답 객체 생성 및 반환 + user_info = UserInfoResponse( + user_id=user_id, + nickname=nickname, + level_title=nft_grade, + point=point, # XRPL 계정 잔액으로 설정 + total_revenue=total_revenue # 계산된 총 수익 + ) + + return user_info