from .api import StupidWalletAPI
from .const import *

src/stupidwalletapi/__init__.py
penggrin12/stupidwalletapi
from typing import List
from .base import BaseAPI
from .models import Cheque, Invoice
from .const import WAV_COIN


class StupidWalletAPI(BaseAPI):
    def __init__(self, token: str):
        super().__init__(token, "https://sw.svat.dev")

    async def get_balance(self, coin_id: int = WAV_COIN) -> int:
        response = await self._make_request("GET",
                                            "/user/get_balance",
                                            {"coin_id": coin_id})
        return response.get("coin_amount")

    async def test_apikey(self) -> bool:
        try:
            return (await self.get_balance(WAV_COIN)) is not None
        except Exception:
            return False

    # Cheques

    async def cheque_from_id(self, cheque_id: str) -> Cheque:
        result = Cheque.from_info_cheque(await self._make_request("GET",
                                                                  "/user/info_cheque",
                                                                  {"cheque_id": cheque_id}))
        result._cheque_id = cheque_id
        return result

    async def my_cheques(self) -> List[Cheque]:
        response = await self._make_request("GET", "/user/my_cheques", {})
        return [Cheque(data) for data in response.get("data")]

    async def info_cheque(self, cheque_id: str) -> Cheque:
        response = await self._make_request("GET", "/user/info_cheque", {"cheque_id": cheque_id})
        return Cheque.from_info_cheque(response)

    async def create_cheque(self, coin_id: int, coin_amount: int, password: str = None, comment: str = None) -> Cheque:
        response = await self._make_request(
            "POST",
            "/user/create_cheque",
            {"coin_id": coin_id, "coin_amount": coin_amount,
             "password": password or "", "comment": comment or ""}
        )
        return await self.cheque_from_id(response.get("cheque_id"))

    async def claim_cheque(self, cheque_id: str, password: str = None) -> Cheque:
        await self._make_request(
            "POST",
            "/user/claim_cheque",
            {"cheque_id": cheque_id, "password": password or ""}
        )
        return await self.cheque_from_id(cheque_id)

    # Invoices

    async def my_invoices(self) -> List[Invoice]:
        response = await self._make_request("GET", "/invoice/my_invoices", {})
        return [Invoice(data) for data in response.get("data")]

    async def get_invoice_data(self, invoice_unique_hash: str) -> Invoice:
        response = await self._make_request("GET", "/invoice/get_invoice_data",
                                            {"invoice_unique_hash": invoice_unique_hash})
        return Invoice(response)

    async def pay_invoice(self, invoice_unique_hash: str) -> Invoice:
        await self._make_request(
            "POST",
            "/invoice/pay_invoice",
            {"invoice_unique_hash": invoice_unique_hash}
        )
        return await self.get_invoice_data(invoice_unique_hash)

    async def create_invoice(self, coin_id: int, coin_amount: int, expiration_time: int = None, comment: str = None,
                             return_url: str = None) -> Invoice:
        """
        expiration_time: in minutes (default: 500_000)
        """
        response = await self._make_request(
            "POST",
            "/invoice/create_invoice",
            {"coin_id": coin_id, "coin_amount": coin_amount, "expiration_time": expiration_time or 500_000,
             "comment": comment or "", "return_url": return_url or ""}
        )
        return await self.get_invoice_data(response.get("invoice_unique_hash"))

    async def delete_invoice(self, invoice_unique_hash: str):
        await self._make_request(
            "DELETE",
            "/invoice/delete_invoice",
            {"invoice_unique_hash": invoice_unique_hash}
        )

    # Custom methods
    async def create_cheques_on_all_coins(self, coin_id: int, coin_amount: int):
        for _ in range(int((await self.get_balance(coin_id)) / coin_amount)):
            await self.create_cheque(coin_id=coin_id, coin_amount=coin_amount)

    async def claim_all_cheques(self) -> int:
        claimed_cheques = 0

        while True:
            cheques = await self.my_cheques()

            if not cheques:
                break

            for cheque in cheques:
                await self.claim_cheque(cheque_id=cheque.id)
                claimed_cheques += 1

        return claimed_cheques

src/stupidwalletapi/api.py
penggrin12/stupidwalletapi
import asyncio

import httpx

#ыы пися
class SWError(Exception):
  def __init__(self, message: str):
    self.message = message
    super().__init__(message)
    


class BaseAPI:
    def __init__(self, token: str, base_url: str):
        self.TOKEN = token
        self.BASE_URL = base_url
        self.lock = asyncio.Lock()
        self._headers = {
            'accept': 'application/json',
            'api-key': self.TOKEN,
        }

    async def _make_request(self, method, url, params=None) -> dict:
        async with self.lock:
            async with httpx.AsyncClient() as client:
                response = await client.request(method, self.BASE_URL + url, params=params, headers=self._headers)
                print(url, response.status_code, response.json())

            await asyncio.sleep(0.42)
            if (response.json()).get('detail') is None:
                return response.json()
            else:
                raise SWError((response.json()).get('detail'))

src/stupidwalletapi/base.py
penggrin12/stupidwalletapi
WAV_COIN = 1
TWAV_COIN = 2
src/stupidwalletapi/const.py
penggrin12/stupidwalletapi
from typing import Optional, Self, List, Union
from datetime import datetime


class PayHistoryItem:
    def __init__(self, raw: dict):
        self._user_id = raw.get("user_id")
        self._pay_time = raw.get("pay_time")
        self._pay_hash = raw.get("pay_hash")

    def __str__(self) -> str:
        return f"<PayHistory Item by {self._user_id}, at {self._pay_time}>"

    def __repr__(self) -> str:
        return self.__str__()

    @property
    def user_id(self) -> int:
        return self._user_id

    @property
    def pay_time(self) -> datetime:
        return datetime.fromisoformat(self._pay_time)

    @property
    def pay_hash(self) -> str:
        return self._pay_hash


class Cheque:
    def __init__(self, raw: dict):
        self._cheque_id = raw.get("cheque_id")
        self._is_activated = raw.get("is_activated")
        self._coin_id = raw.get("coin_id")
        self._coin_amount = raw.get("coin_amount")
        self._password = raw.get("password")
        self._comment = raw.get("comment")

    def __str__(self) -> str:
        return f"<Cheque #{self._cheque_id}, {self._coin_id}: {self._coin_amount}>"

    def __repr__(self) -> str:
        return self.__str__()

    @staticmethod
    def from_my_cheques(raw: dict) -> Self:
        return Cheque(raw)

    @staticmethod
    def from_info_cheque(raw: dict) -> Self:
        return Cheque(raw)

    @property
    def cheque_id(self) -> str:
        return self._cheque_id

    @property
    def id(self) -> str:
        """Alias for cheque_id"""
        return self._cheque_id

    @property
    def is_activated(self) -> Optional[bool]:
        """Only works when cheque is found with info_cheque"""
        return self._is_activated

    @property
    def coin_id(self) -> int:
        return self._coin_id

    @property
    def coin_amount(self) -> int:
        return self._coin_amount

    @property
    def amount(self) -> int:
        """Alias for coin_amount"""
        return self._coin_amount

    @property
    def password(self) -> Optional[str]:
        return self._password

    @property
    def comment(self) -> Optional[str]:
        return self._comment


class Invoice:
    def __init__(self, raw: dict):
        self._creator_id = raw.get("creator_id")
        self._invoice_unique_hash = raw.get("invoice_unique_hash")
        self._coin_id = raw.get("coin_id")
        self._coin_amount = raw.get("coin_amount")
        self._comment = raw.get("comment")
        self._expiration_time = raw.get("expiration_time")
        self._creation_time = raw.get("creation_time")
        self._return_url = raw.get("return_url")
        self._pay_history = raw.get("pay_history")

    def __str__(self) -> str:
        return f"<Invoice #{self._invoice_unique_hash}, {self._coin_id}: {self._coin_amount}>"

    def __repr__(self) -> str:
        return self.__str__()

    @property
    def creator_id(self) -> int:
        return self._creator_id

    @property
    def invoice_unique_hash(self) -> str:
        return self._invoice_unique_hash

    @property
    def invoice_id(self) -> str:
        """Alias for invoice_unique_hash"""
        return self._invoice_unique_hash

    @property
    def id(self) -> str:
        """Alias for invoice_unique_hash"""
        return self.invoice_unique_hash

    @property
    def coin_id(self) -> int:
        return self._coin_id

    @property
    def coin_amount(self) -> int:
        return self._coin_amount

    @property
    def amount(self) -> int:
        """Alias for coin_amount"""
        return self._coin_amount

    @property
    def comment(self) -> Optional[str]:
        return self._comment

    @property
    def expiration_time(self) -> datetime:
        return datetime.fromisoformat(self._expiration_time)

    @property
    def expiration(self) -> datetime:
        """Alias for expiration_time"""
        return self.expiration_time

    @property
    def creation_time(self) -> datetime:
        return datetime.fromisoformat(self._creation_time)

    @property
    def creation(self) -> datetime:
        """Alias for creation_time"""
        return self.creation_time

    @property
    def return_url(self) -> str:
        return self._return_url

    @property
    def pay_history(self) -> Union[List[PayHistoryItem], List]:
        """Only works when cheque is found with get_invoice_data"""
        return [PayHistoryItem(
            data) for data in self._pay_history] if self._pay_history else []

src/stupidwalletapi/models.py
penggrin12/stupidwalletapi
import asyncio

import stupidwalletapi


async def testing_all():
    test_password = "123testтест!./:p"
    test_comment = "123testтест!:/.;p"
    test_return_url = "https://t.me/penggrin"
    test_amount = 1
    swapi = stupidwalletapi.StupidWalletAPI(input("token: "))

    assert (await swapi.test_apikey())

    cheque1 = await swapi.create_cheque(stupidwalletapi.WAV_COIN, test_amount, test_password, test_comment)

    assert (cheque1.amount == test_amount)
    assert (cheque1.coin_amount == cheque1.amount)
    assert (cheque1.coin_id == stupidwalletapi.WAV_COIN)
    assert (cheque1.cheque_id == cheque1.id)
    assert (cheque1.comment == test_comment)
    assert (cheque1.is_activated is False)

    cheque2 = await swapi.claim_cheque(cheque1.id, test_password)

    assert (cheque2.id == cheque1.id)
    assert cheque2.is_activated

    invoice1 = await swapi.create_invoice(
        stupidwalletapi.WAV_COIN,
        test_amount,
        comment=test_comment,
        return_url=test_return_url
    )
    assert (invoice1.amount == test_amount)
    assert (invoice1.coin_amount == invoice1.amount)
    assert (invoice1.coin_id == stupidwalletapi.WAV_COIN)
    assert (invoice1.invoice_unique_hash == invoice1.id)
    assert (invoice1.invoice_unique_hash == invoice1.invoice_id)
    assert (invoice1.comment == test_comment)
    assert (invoice1.return_url == test_return_url)
    assert (len(invoice1.pay_history) == 0)

    invoice2 = await swapi.pay_invoice(invoice1.id)
    assert (invoice1.id == invoice2.id)
    assert (len(invoice2.pay_history) == 1)

    await swapi.delete_invoice(invoice1.id)

    balance1 = await swapi.get_balance(stupidwalletapi.WAV_COIN)

    await swapi.create_cheques_on_all_coins(stupidwalletapi.WAV_COIN, test_amount)

    balance2 = await swapi.get_balance(stupidwalletapi.WAV_COIN)

    await swapi.claim_all_cheques()

    balance3 = await swapi.get_balance(stupidwalletapi.WAV_COIN)

    assert (balance1 != balance2)
    assert (balance1 == balance3)


asyncio.run(testing_all())

tests/maintest.py
penggrin12/stupidwalletapi