commit 4df2c3488988e615e0467b8591b2a7ed43681a4b Author: harold Date: Mon Jul 14 13:31:00 2025 +0500 add router for create payment for tips diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..449bdee --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +venv +.idea +migrations/versions +*.pyc +.env +.venv +.pytest_cache +.prod_env +.env_test +.env_docker_test +.vscode +docker \ No newline at end of file diff --git a/src/core/__init__.py b/src/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/core/api_tips_integrate/__init__.py b/src/core/api_tips_integrate/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/core/api_tips_integrate/auth.py b/src/core/api_tips_integrate/auth.py new file mode 100644 index 0000000..3f2ff2d --- /dev/null +++ b/src/core/api_tips_integrate/auth.py @@ -0,0 +1,5 @@ + + + + + diff --git a/src/core/api_tips_integrate/constants.py b/src/core/api_tips_integrate/constants.py new file mode 100644 index 0000000..0955edb --- /dev/null +++ b/src/core/api_tips_integrate/constants.py @@ -0,0 +1,3 @@ +from typing import Literal + +DONATES_SUM_PERIODS = Literal["24h", "7d", "30d", "1y"] \ No newline at end of file diff --git a/src/core/api_tips_integrate/docs.py b/src/core/api_tips_integrate/docs.py new file mode 100644 index 0000000..e69de29 diff --git a/src/core/api_tips_integrate/router.py b/src/core/api_tips_integrate/router.py new file mode 100644 index 0000000..2b0c787 --- /dev/null +++ b/src/core/api_tips_integrate/router.py @@ -0,0 +1,46 @@ +from typing import Literal, Annotated + +from fastapi import APIRouter, Depends + +from src.core.api_tips_integrate.constants import DONATES_SUM_PERIODS +from src.core.api_tips_integrate.schemas import CreateTipSchema +from src.core.api_tips_integrate.service import create_payment_link_for_tip_service +from src.core.common.dependencies import http_bearer, data_from_token +from src.core.common.schemas import TokenPayloadSchema, PaymentLinkSchema + +router = APIRouter( + tags=["Tips Integrate"], +) + + +@router.get( + path="/last-payments" +) +async def get_last_donates( + token: Annotated[str, Depends(http_bearer)], +): + pass + + +@router.get( + path="/summary-payments" +) +async def get_summary_payments_for_period( + token: Annotated[str, Depends(http_bearer)], + period: DONATES_SUM_PERIODS, +): + pass + + +@router.post( + path="/payment-request", + response_model=PaymentLinkSchema, +) +async def create_payment_request( + jwt_data: Annotated[TokenPayloadSchema, Depends(data_from_token)], + create_tip_schema: CreateTipSchema, +): + return await create_payment_link_for_tip_service( + jwt_data=jwt_data, + create_tip_schema=create_tip_schema, + ) diff --git a/src/core/api_tips_integrate/schemas.py b/src/core/api_tips_integrate/schemas.py new file mode 100644 index 0000000..a9fa9d8 --- /dev/null +++ b/src/core/api_tips_integrate/schemas.py @@ -0,0 +1,17 @@ +from pydantic import Field, BaseModel + + +class CreateTipSchema(BaseModel): + amount: int = Field( + ..., + description="Amount of the tip in RUB currency", + ge=10, + ) + text: str | None = Field( + default=None, + description="Text of the tip", + ) + from_user: str | None = Field( + default=None, + description="User who sent the tip", + ) \ No newline at end of file diff --git a/src/core/api_tips_integrate/service.py b/src/core/api_tips_integrate/service.py new file mode 100644 index 0000000..e807031 --- /dev/null +++ b/src/core/api_tips_integrate/service.py @@ -0,0 +1,62 @@ +import httpx + +from src.core.api_tips_integrate.schemas import CreateTipSchema +from src.core.common.constants import DH_ACCOUNTS_API_URL, DH_WIDGETS_API_URL +from src.core.common.schemas import TokenPayloadSchema, UserInfoSchema, PaymentLinkSchema + + +async def create_payment_link_for_tip_service( + jwt_data: TokenPayloadSchema, + create_tip_schema: CreateTipSchema, +): + async with httpx.AsyncClient() as client: + headers = { + "accept": "application/json" + } + response = await client.get( + headers=headers, + url=DH_ACCOUNTS_API_URL + f"info/{jwt_data.account_id}" + ) + + user_data = UserInfoSchema(**response.json()) + + async with httpx.AsyncClient() as client: + headers = { + "accept": "application/json", + "Content-Type": "application/json" + } + data = { + "amount": create_tip_schema.amount, + } + + if create_tip_schema.from_user: + data["donatUser"] = create_tip_schema.from_user + if create_tip_schema.text: + data["text"] = create_tip_schema.text + + print(DH_WIDGETS_API_URL + f"donat/{user_data.login}") + response = await client.post( + headers=headers, + json=data, + url=DH_WIDGETS_API_URL + f"donat/{user_data.login}" + ) + if response.status_code != 200: + print(response.json()) + + payment_link_schema = PaymentLinkSchema(**response.json()) + + return payment_link_schema + + + + +async def get_last_donates_by_login(): + pass + + +async def get_summary_donates_for_period(): + pass + + +async def create_payment_link_for_donate(): + pass diff --git a/src/core/common/__init__.py b/src/core/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/core/common/constants.py b/src/core/common/constants.py new file mode 100644 index 0000000..0497f5a --- /dev/null +++ b/src/core/common/constants.py @@ -0,0 +1,4 @@ +DH_PAYMENTS_API_URL = "https://payment.donatehelper.com/api/payment/" +DH_AUTH_API_URL = "https://auth.donatehelper.com/api/auth/" +DH_WIDGETS_API_URL = "https://widget.donatehelper.com/api/widget/" +DH_ACCOUNTS_API_URL = "https://account.donatehelper.com/api/streamer/" \ No newline at end of file diff --git a/src/core/common/dependencies.py b/src/core/common/dependencies.py new file mode 100644 index 0000000..0482232 --- /dev/null +++ b/src/core/common/dependencies.py @@ -0,0 +1,18 @@ +from typing import Annotated + +from fastapi import Depends +from fastapi.security import HTTPBearer + +from src.core.common.jwt import decode_token_from_base64 +from src.core.common.schemas import TokenPayloadSchema + +http_bearer = HTTPBearer() + + + +async def data_from_token( + token: Annotated[str, Depends(http_bearer)] +) -> TokenPayloadSchema: + return decode_token_from_base64( + token=token, + ) \ No newline at end of file diff --git a/src/core/common/jwt.py b/src/core/common/jwt.py new file mode 100644 index 0000000..ba35d4f --- /dev/null +++ b/src/core/common/jwt.py @@ -0,0 +1,17 @@ +import base64 +import json + +from fastapi.security import HTTPAuthorizationCredentials + +from src.core.common.schemas import TokenPayloadSchema + + +def decode_token_from_base64( + token: HTTPAuthorizationCredentials +) -> TokenPayloadSchema: + token = token.credentials + payload_b64 = token.split(".")[1] + payload_bytes = base64.urlsafe_b64decode(payload_b64 + "==") # Добавляем padding + payload = json.loads(payload_bytes) + + return TokenPayloadSchema(**payload) diff --git a/src/core/common/schemas.py b/src/core/common/schemas.py new file mode 100644 index 0000000..7007877 --- /dev/null +++ b/src/core/common/schemas.py @@ -0,0 +1,26 @@ +from datetime import datetime + +from pydantic import BaseModel, AnyHttpUrl, EmailStr, HttpUrl, UUID4 + + +class ResponseTokenSchema(BaseModel): + access_token: str + token_type: str = "bearer" + + +class UserInfoSchema(BaseModel): + avatar: AnyHttpUrl + created_at: datetime + email: EmailStr + login: str + updated_at: datetime + + +class PaymentLinkSchema(BaseModel): + payment_url: HttpUrl + + +class TokenPayloadSchema(BaseModel): + account_id: int + exp: int + sub: EmailStr diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..0374fdc --- /dev/null +++ b/src/main.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI + +from src.core.api_tips_integrate.router import router as tips_router + + +app = FastAPI( + title="DonateHelper integrate api for tips.", +) +app.include_router( + router=tips_router, + prefix="/tips", +) + +