mirror of
https://github.com/bohd4nx/FragmentAPI.git
synced 2026-07-25 06:14:29 +00:00
feat: update payment method defaults to use PaymentMethod enum; refactor related validation checks
This commit is contained in:
@@ -136,7 +136,7 @@ class FragmentClient:
|
||||
username: str,
|
||||
months: int,
|
||||
show_sender: bool = True,
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
) -> PremiumResult:
|
||||
"""Gift Telegram Premium to a user.
|
||||
|
||||
@@ -156,7 +156,7 @@ class FragmentClient:
|
||||
username: str,
|
||||
amount: int,
|
||||
show_sender: bool = True,
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
) -> StarsResult:
|
||||
"""Send Telegram Stars to a user.
|
||||
|
||||
@@ -212,7 +212,7 @@ class FragmentClient:
|
||||
channel: str,
|
||||
winners: int,
|
||||
amount: int,
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
) -> StarsGiveawayResult:
|
||||
"""Run a Telegram Stars giveaway for a channel.
|
||||
|
||||
@@ -233,7 +233,7 @@ class FragmentClient:
|
||||
channel: str,
|
||||
winners: int,
|
||||
months: int = 3,
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
) -> PremiumGiveawayResult:
|
||||
"""Run a Telegram Premium giveaway for a channel.
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ def get_cookies_from_browser(browser: str = "chrome") -> CookieResult:
|
||||
global rookiepy
|
||||
|
||||
key = browser.lower()
|
||||
if key not in SupportedBrowser._value2member_map_:
|
||||
if not any(key == m for m in SupportedBrowser):
|
||||
supported = ", ".join(sorted(b.value for b in SupportedBrowser))
|
||||
raise CookieError(CookieError.UNSUPPORTED_BROWSER.format(browser=browser, supported=supported))
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import json
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from pyfragment.core.constants import ADS_TOPUP_PAGE, DEVICE
|
||||
from pyfragment.core.constants import ADS_TOPUP_PAGE, DEVICE_INFO
|
||||
from pyfragment.domains.tonapi.account import get_account_info
|
||||
from pyfragment.domains.tonapi.transaction import process_transaction
|
||||
from pyfragment.exceptions import ConfigurationError, FragmentAPIError, FragmentError, UnexpectedError, VerificationError
|
||||
@@ -34,7 +34,7 @@ async def recharge_ads(client: FragmentClient, account: str, amount: int) -> Ads
|
||||
"getAdsRechargeLink",
|
||||
{
|
||||
"account": json.dumps(account_info),
|
||||
"device": DEVICE,
|
||||
"device": json.dumps(DEVICE_INFO),
|
||||
"transaction": 1,
|
||||
"id": req_id,
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@ import json
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from pyfragment.core.constants import ADS_TOPUP_PAGE, DEVICE
|
||||
from pyfragment.core.constants import ADS_TOPUP_PAGE, DEVICE_INFO
|
||||
from pyfragment.domains.payments import parse_required_payment_amount
|
||||
from pyfragment.domains.tonapi.account import get_account_info
|
||||
from pyfragment.domains.tonapi.transaction import process_transaction
|
||||
@@ -48,7 +48,7 @@ async def topup_ton(client: FragmentClient, username: str, amount: int, show_sen
|
||||
"getAdsTopupLink",
|
||||
{
|
||||
"account": json.dumps(account),
|
||||
"device": DEVICE,
|
||||
"device": json.dumps(DEVICE_INFO),
|
||||
"transaction": 1,
|
||||
"id": req_id,
|
||||
"show_sender": int(show_sender),
|
||||
|
||||
@@ -6,7 +6,7 @@ import random
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from pyfragment.core.constants import (
|
||||
DEVICE,
|
||||
DEVICE_INFO,
|
||||
PREMIUM_GIVEAWAY_PAGE,
|
||||
PREMIUM_MONTHS_VALID,
|
||||
PREMIUM_WINNERS_MAX,
|
||||
@@ -43,13 +43,13 @@ async def giveaway_stars(
|
||||
channel: str,
|
||||
winners: int,
|
||||
amount: int,
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
) -> StarsGiveawayResult:
|
||||
if not isinstance(winners, int) or not (STARS_WINNERS_MIN <= winners <= STARS_WINNERS_MAX):
|
||||
raise ConfigurationError(ConfigurationError.INVALID_WINNERS_STARS)
|
||||
if not isinstance(amount, int) or not (STARS_GIVEAWAY_MIN <= amount <= STARS_GIVEAWAY_MAX):
|
||||
raise ConfigurationError(ConfigurationError.INVALID_STARS_PER_WINNER)
|
||||
if payment_method not in PaymentMethod._value2member_map_:
|
||||
if not any(payment_method == m for m in PaymentMethod):
|
||||
raise ConfigurationError(
|
||||
ConfigurationError.INVALID_PAYMENT_METHOD.format(
|
||||
method=payment_method,
|
||||
@@ -89,7 +89,7 @@ async def giveaway_stars(
|
||||
"getGiveawayStarsLink",
|
||||
{
|
||||
"account": json.dumps(account),
|
||||
"device": DEVICE,
|
||||
"device": json.dumps(DEVICE_INFO),
|
||||
"transaction": 1,
|
||||
"id": req_id,
|
||||
},
|
||||
@@ -133,17 +133,17 @@ async def giveaway_premium(
|
||||
channel: str,
|
||||
winners: int,
|
||||
months: int = 3,
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
) -> PremiumGiveawayResult:
|
||||
if not isinstance(winners, int) or not (PREMIUM_WINNERS_MIN <= winners <= PREMIUM_WINNERS_MAX):
|
||||
raise ConfigurationError(ConfigurationError.INVALID_WINNERS_PREMIUM)
|
||||
if months not in PREMIUM_MONTHS_VALID:
|
||||
raise ConfigurationError(ConfigurationError.INVALID_MONTHS)
|
||||
if payment_method not in PaymentMethod._value2member_map_:
|
||||
if not any(payment_method == m for m in PaymentMethod):
|
||||
raise ConfigurationError(
|
||||
ConfigurationError.INVALID_PAYMENT_METHOD.format(
|
||||
method=payment_method,
|
||||
supported=", ".join(sorted(PaymentMethod._value2member_map_)),
|
||||
supported=", ".join(sorted(m.value for m in PaymentMethod)),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -188,7 +188,7 @@ async def giveaway_premium(
|
||||
"getGiveawayPremiumLink",
|
||||
{
|
||||
"account": json.dumps(account),
|
||||
"device": DEVICE,
|
||||
"device": json.dumps(DEVICE_INFO),
|
||||
"transaction": 1,
|
||||
"id": req_id,
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@ class GiveawaysService(BaseService):
|
||||
channel: str,
|
||||
winners: int,
|
||||
amount: int,
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
) -> StarsGiveawayResult:
|
||||
return await giveaway_stars(self._client, channel, winners, amount, payment_method=payment_method)
|
||||
|
||||
@@ -26,6 +26,6 @@ class GiveawaysService(BaseService):
|
||||
channel: str,
|
||||
winners: int,
|
||||
months: int = 3,
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
) -> PremiumGiveawayResult:
|
||||
return await giveaway_premium(self._client, channel, winners, months, payment_method=payment_method)
|
||||
|
||||
@@ -6,7 +6,7 @@ import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from pyfragment.core.constants import (
|
||||
DEVICE,
|
||||
DEVICE_INFO,
|
||||
PREMIUM_MONTHS_VALID,
|
||||
PREMIUM_PAGE,
|
||||
STARS_PAGE,
|
||||
@@ -39,15 +39,15 @@ async def purchase_stars(
|
||||
username: str,
|
||||
amount: int,
|
||||
show_sender: bool = True,
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
) -> StarsResult:
|
||||
if not isinstance(amount, int) or not (STARS_PURCHASE_MIN <= amount <= STARS_PURCHASE_MAX):
|
||||
raise ConfigurationError(ConfigurationError.INVALID_STARS_AMOUNT)
|
||||
if payment_method not in PaymentMethod._value2member_map_:
|
||||
if not any(payment_method == m for m in PaymentMethod):
|
||||
raise ConfigurationError(
|
||||
ConfigurationError.INVALID_PAYMENT_METHOD.format(
|
||||
method=payment_method,
|
||||
supported=", ".join(sorted(PaymentMethod._value2member_map_)),
|
||||
supported=", ".join(sorted(m.value for m in PaymentMethod)),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -77,7 +77,7 @@ async def purchase_stars(
|
||||
"getBuyStarsLink",
|
||||
{
|
||||
"account": json.dumps(account),
|
||||
"device": DEVICE,
|
||||
"device": json.dumps(DEVICE_INFO),
|
||||
"transaction": 1,
|
||||
"id": req_id,
|
||||
"show_sender": int(show_sender),
|
||||
@@ -120,15 +120,15 @@ async def purchase_premium(
|
||||
username: str,
|
||||
months: int,
|
||||
show_sender: bool = True,
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
) -> PremiumResult:
|
||||
if months not in PREMIUM_MONTHS_VALID:
|
||||
raise ConfigurationError(ConfigurationError.INVALID_MONTHS)
|
||||
if payment_method not in PaymentMethod._value2member_map_:
|
||||
if not any(payment_method == m for m in PaymentMethod):
|
||||
raise ConfigurationError(
|
||||
ConfigurationError.INVALID_PAYMENT_METHOD.format(
|
||||
method=payment_method,
|
||||
supported=", ".join(sorted(PaymentMethod._value2member_map_)),
|
||||
supported=", ".join(sorted(m.value for m in PaymentMethod)),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -158,7 +158,7 @@ async def purchase_premium(
|
||||
"getGiftPremiumLink",
|
||||
{
|
||||
"account": json.dumps(account),
|
||||
"device": DEVICE,
|
||||
"device": json.dumps(DEVICE_INFO),
|
||||
"transaction": 1,
|
||||
"id": req_id,
|
||||
"show_sender": int(show_sender),
|
||||
|
||||
@@ -17,7 +17,7 @@ class PurchasesService(BaseService):
|
||||
username: str,
|
||||
amount: int,
|
||||
show_sender: bool = True,
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
) -> StarsResult:
|
||||
return await purchase_stars(self._client, username, amount, show_sender=show_sender, payment_method=payment_method)
|
||||
|
||||
@@ -26,6 +26,6 @@ class PurchasesService(BaseService):
|
||||
username: str,
|
||||
months: int,
|
||||
show_sender: bool = True,
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
) -> PremiumResult:
|
||||
return await purchase_premium(self._client, username, months, show_sender=show_sender, payment_method=payment_method)
|
||||
|
||||
@@ -124,7 +124,7 @@ async def _broadcast_with_retry(wallet: Any, message: dict[str, Any], payload: s
|
||||
async def process_transaction(
|
||||
client: FragmentClient,
|
||||
transaction_data: dict[str, Any],
|
||||
payment_method: PaymentMethod = "ton",
|
||||
payment_method: PaymentMethod = PaymentMethod.TON,
|
||||
required_payment_amount: float | None = None,
|
||||
) -> str:
|
||||
"""Sign and broadcast a Fragment transaction with the seeded TON wallet.
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import StrEnum
|
||||
import sys
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
from tonutils.contracts.wallet import WalletV4R2, WalletV5R1
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
from enum import StrEnum
|
||||
else:
|
||||
|
||||
class StrEnum(str, Enum): # noqa: F811
|
||||
pass
|
||||
|
||||
|
||||
class PaymentMethod(StrEnum):
|
||||
TON = "ton"
|
||||
|
||||
@@ -9,6 +9,7 @@ from tonutils.exceptions import ProviderResponseError
|
||||
|
||||
from pyfragment import TransactionError, WalletError
|
||||
from pyfragment.domains.tonapi.transaction import process_transaction
|
||||
from pyfragment.models.enums import PaymentMethod
|
||||
from tests.shared import VALID_SEED
|
||||
|
||||
|
||||
@@ -145,7 +146,7 @@ async def test_usdt_payment_requires_min_ton_gas_reserve() -> None:
|
||||
wallet = _make_wallet(balance_nanotons=10_000_000) # 0.01 TON below MIN_TON_BALANCE
|
||||
with _patch_wallet(wallet), patch("pyfragment.domains.tonapi.account.get_usdt_balance", AsyncMock(return_value=100.0)):
|
||||
with pytest.raises(WalletError, match="Insufficient TON balance"):
|
||||
await process_transaction(_make_client(), TRANSACTION_DATA, payment_method="usdt_ton")
|
||||
await process_transaction(_make_client(), TRANSACTION_DATA, payment_method=PaymentMethod.USDT_TON)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -173,6 +174,6 @@ async def test_usdt_payment_checks_usdt_balance() -> None:
|
||||
await process_transaction(
|
||||
_make_client(),
|
||||
transaction,
|
||||
payment_method="usdt_ton",
|
||||
payment_method=PaymentMethod.USDT_TON,
|
||||
required_payment_amount=12.5,
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ import pytest
|
||||
import pyfragment.domains.giveaways.giveaway as _giveaway_stars_mod
|
||||
import pyfragment.domains.purchases.purchase as _purchase_stars_mod
|
||||
from pyfragment import ConfigurationError, FragmentClient, StarsGiveawayResult, StarsResult, UserNotFoundError
|
||||
from pyfragment.models.enums import PaymentMethod
|
||||
from tests.shared import FAKE_ACCOUNT, FAKE_RECIPIENT, FAKE_REQ_ID, FAKE_TRANSACTION, FAKE_TX_HASH
|
||||
|
||||
# Stars purchase validation tests
|
||||
@@ -78,7 +79,7 @@ async def test_purchase_stars_passes_payment_method(client: FragmentClient) -> N
|
||||
patch.object(_purchase_stars_mod, "get_account_info", AsyncMock(return_value=FAKE_ACCOUNT)),
|
||||
patch.object(_purchase_stars_mod, "process_transaction", proc_mock),
|
||||
):
|
||||
await client.purchase_stars("@user", amount=500, payment_method="usdt_ton")
|
||||
await client.purchase_stars("@user", amount=500, payment_method=PaymentMethod.USDT_TON)
|
||||
|
||||
init_call = call_mock.await_args_list[2]
|
||||
assert init_call.args[0] == "initBuyStarsRequest"
|
||||
@@ -198,7 +199,7 @@ async def test_giveaway_stars_passes_payment_method(client: FragmentClient) -> N
|
||||
patch.object(_giveaway_stars_mod, "get_account_info", AsyncMock(return_value=FAKE_ACCOUNT)),
|
||||
patch.object(_giveaway_stars_mod, "process_transaction", proc_mock),
|
||||
):
|
||||
await client.giveaway_stars("@channel", winners=3, amount=1000, payment_method="usdt_ton")
|
||||
await client.giveaway_stars("@channel", winners=3, amount=1000, payment_method=PaymentMethod.USDT_TON)
|
||||
|
||||
init_call = call_mock.await_args_list[2]
|
||||
assert init_call.args[0] == "initGiveawayStarsRequest"
|
||||
|
||||
@@ -7,6 +7,7 @@ import pytest
|
||||
import pyfragment.domains.giveaways.giveaway as _giveaway_premium_mod
|
||||
import pyfragment.domains.purchases.purchase as _purchase_premium_mod
|
||||
from pyfragment import ConfigurationError, FragmentClient, PremiumGiveawayResult, PremiumResult, UserNotFoundError
|
||||
from pyfragment.models.enums import PaymentMethod
|
||||
from tests.shared import FAKE_ACCOUNT, FAKE_RECIPIENT, FAKE_REQ_ID, FAKE_TRANSACTION, FAKE_TX_HASH
|
||||
|
||||
# Premium purchase validation tests
|
||||
@@ -75,7 +76,7 @@ async def test_purchase_premium_passes_payment_method(client: FragmentClient) ->
|
||||
patch.object(_purchase_premium_mod, "get_account_info", AsyncMock(return_value=FAKE_ACCOUNT)),
|
||||
patch.object(_purchase_premium_mod, "process_transaction", proc_mock),
|
||||
):
|
||||
await client.purchase_premium("@user", months=6, payment_method="usdt_ton")
|
||||
await client.purchase_premium("@user", months=6, payment_method=PaymentMethod.USDT_TON)
|
||||
|
||||
init_call = call_mock.await_args_list[2]
|
||||
assert init_call.args[0] == "initGiftPremiumRequest"
|
||||
@@ -183,7 +184,7 @@ async def test_giveaway_premium_passes_payment_method(client: FragmentClient) ->
|
||||
patch.object(_giveaway_premium_mod, "get_account_info", AsyncMock(return_value=FAKE_ACCOUNT)),
|
||||
patch.object(_giveaway_premium_mod, "process_transaction", proc_mock),
|
||||
):
|
||||
await client.giveaway_premium("@channel", winners=10, months=6, payment_method="usdt_ton")
|
||||
await client.giveaway_premium("@channel", winners=10, months=6, payment_method=PaymentMethod.USDT_TON)
|
||||
|
||||
init_call = call_mock.await_args_list[2]
|
||||
assert init_call.args[0] == "initGiveawayPremiumRequest"
|
||||
|
||||
Reference in New Issue
Block a user