mirror of
https://github.com/deesiigneer/pyspapi.git
synced 2026-04-20 12:35:26 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d36ecfca36 | ||
|
|
c086954c25 | ||
|
|
8d60472b9a | ||
|
|
14166cf519 | ||
|
|
ab60b4f104 |
@@ -1,16 +1,15 @@
|
|||||||
from pyspapi import SPAPI
|
|
||||||
from asyncio import get_event_loop
|
from asyncio import get_event_loop
|
||||||
|
|
||||||
|
from pyspapi import SPAPI
|
||||||
|
|
||||||
spapi = SPAPI(card_id='CARD_ID', token='TOKEN')
|
spapi = SPAPI(card_id='CARD_ID', token='TOKEN')
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
new_balance = await spapi.create_transaction(receiver='77552',
|
new_balance = await spapi.create_transaction(receiver='77552',
|
||||||
amount=1,
|
amount=1,
|
||||||
comment="test"
|
comment='test')
|
||||||
)
|
|
||||||
print(new_balance)
|
print(new_balance)
|
||||||
|
|
||||||
|
|
||||||
loop = get_event_loop()
|
loop = get_event_loop()
|
||||||
loop.run_until_complete(main())
|
loop.run_until_complete(main())
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
from .api import *
|
||||||
from .spworlds import *
|
from .spworlds import *
|
||||||
|
from .types import *
|
||||||
|
|
||||||
__author__ = 'deesiigneer'
|
__author__ = 'deesiigneer'
|
||||||
__url__ = 'https://github.com/deesiigneer/pyspapi'
|
__url__ = 'https://github.com/deesiigneer/pyspapi'
|
||||||
__description__ = 'API wrapper for SP servers written in Python.'
|
__description__ = 'API wrapper for SP servers written in Python.'
|
||||||
__license__ = 'MIT'
|
__license__ = 'MIT'
|
||||||
__version__ = "3.1.0"
|
__version__ = "3.2.0"
|
||||||
|
|||||||
@@ -1,23 +1,32 @@
|
|||||||
|
import asyncio
|
||||||
|
import json
|
||||||
from base64 import b64encode
|
from base64 import b64encode
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
import aiohttp
|
from typing import Optional, Any, Dict
|
||||||
import json
|
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
|
||||||
|
from ..exceptions import ValidationError, SPAPIError
|
||||||
|
|
||||||
log = getLogger('pyspapi')
|
log = getLogger('pyspapi')
|
||||||
|
|
||||||
|
|
||||||
class APISession(object):
|
class APISession(object):
|
||||||
""" Holds aiohttp session for its lifetime and wraps different types of request """
|
|
||||||
|
|
||||||
def __init__(self, card_id: str, token: str, timeout=5, sleep_time=0.2, retries=0):
|
def __init__(self, card_id: str,
|
||||||
self.__url = "https://spworlds.ru/"
|
token: str,
|
||||||
|
timeout: int = 5,
|
||||||
|
sleep_time: float = 0.2,
|
||||||
|
retries: int = 0,
|
||||||
|
raise_exception: bool = False):
|
||||||
|
self.__url = "https://spworlds.ru/api/public/"
|
||||||
self.__id = card_id
|
self.__id = card_id
|
||||||
self.__token = token
|
self.__token = token
|
||||||
self.__sleep_timeout = sleep_time
|
self.__sleep_timeout = sleep_time
|
||||||
self.__retries = retries
|
self.__retries = retries
|
||||||
self.__timeout = timeout
|
self.__timeout = timeout
|
||||||
self.session = None
|
self.__raise_exception = raise_exception
|
||||||
|
self.session: Optional[aiohttp.ClientSession] = None
|
||||||
|
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
self.session = aiohttp.ClientSession(
|
self.session = aiohttp.ClientSession(
|
||||||
@@ -29,62 +38,50 @@ class APISession(object):
|
|||||||
await self.session.close()
|
await self.session.close()
|
||||||
self.session = None
|
self.session = None
|
||||||
|
|
||||||
def __get_url(self, endpoint: str) -> str:
|
async def request(self, method: str, endpoint: str, data: Optional[Dict] = None) -> Any:
|
||||||
""" Get URL for requests """
|
url = self.__url + endpoint
|
||||||
url = self.__url
|
headers = {
|
||||||
api = "api/public"
|
'Authorization': f"Bearer {str(b64encode(str(f'{self.__id}:{self.__token}').encode('utf-8')), 'utf-8')}",
|
||||||
return f"{url}{api}/{endpoint}"
|
'User-Agent': 'https://github.com/deesiigneer/pyspapi',
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
async def __request(self, method: str, endpoint: str, data=None):
|
attempt = 0
|
||||||
url = self.__get_url(endpoint)
|
while True:
|
||||||
response = await self.session.request(
|
attempt += 1
|
||||||
method=method,
|
if attempt > 1:
|
||||||
url=url,
|
log.warning(f'[pyspapi] Repeat attempt {attempt}: {method.upper()} {url}')
|
||||||
json=data,
|
try:
|
||||||
headers={'Authorization': f"Bearer {str(b64encode(str(f'{self.__id}:{self.__token}').encode('utf-8')), 'utf-8')}",
|
async with self.session.request(method, url, json=data, headers=headers) as resp:
|
||||||
'User-Agent': 'https://github.com/deesiigneer/pyspapi'},
|
if resp.status == 422:
|
||||||
ssl=True
|
errors = await resp.json()
|
||||||
)
|
log.error(f"[pyspapi] Validation error: {errors}")
|
||||||
if response.status not in [200, 201]:
|
if self.__raise_exception:
|
||||||
message = await response.json()
|
raise ValidationError(errors)
|
||||||
raise aiohttp.ClientResponseError(
|
return None
|
||||||
code=response.status,
|
|
||||||
message=message['message'],
|
|
||||||
headers=response.headers,
|
|
||||||
history=response.history,
|
|
||||||
request_info=response.request_info
|
|
||||||
)
|
|
||||||
return response
|
|
||||||
|
|
||||||
async def get(self, endpoint, **kwargs):
|
if resp.status >= 400:
|
||||||
""" GET requests """
|
content = await resp.text()
|
||||||
try:
|
log.error(f"[pyspapi] API error {resp.status}: {content}")
|
||||||
return await self.__request("GET", endpoint, None, **kwargs)
|
if self.__raise_exception:
|
||||||
except aiohttp.ClientResponseError as e:
|
raise SPAPIError(resp.status, content)
|
||||||
log.error(f"GET request to {endpoint} failed with status {e.status}: {e.message}")
|
return None
|
||||||
except aiohttp.ClientError as e:
|
|
||||||
log.error(f"GET request to {endpoint} failed: {e}")
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f"GET request to {endpoint} failed: {e}")
|
|
||||||
|
|
||||||
async def post(self, endpoint, data, **kwargs):
|
return await resp.json()
|
||||||
""" POST requests """
|
except (aiohttp.ClientError, asyncio.TimeoutError) as e:
|
||||||
try:
|
log.exception(f"[pyspapi] Connection error: {e}")
|
||||||
return await self.__request("POST", endpoint, data, **kwargs)
|
if attempt > self.__retries:
|
||||||
except aiohttp.ClientResponseError as e:
|
return None
|
||||||
log.error(f"POST request to {endpoint} failed with status {e.status}: {e.message}")
|
await asyncio.sleep(self.__sleep_timeout)
|
||||||
except aiohttp.ClientError as e:
|
|
||||||
log.error(f"POST request to {endpoint} failed: {e}")
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f"POST request to {endpoint} failed: {e}")
|
|
||||||
|
|
||||||
async def put(self, endpoint, data, **kwargs):
|
async def get(self, endpoint: str) -> Any:
|
||||||
""" PUT requests """
|
async with self:
|
||||||
try:
|
return await self.request("GET", endpoint)
|
||||||
return await self.__request("PUT", endpoint, data, **kwargs)
|
|
||||||
except aiohttp.ClientResponseError as e:
|
async def post(self, endpoint: str, data: Optional[Dict] = None) -> Any:
|
||||||
log.error(f"PUT request to {endpoint} failed with status {e.status}: {e.message}")
|
async with self:
|
||||||
except aiohttp.ClientError as e:
|
return await self.request("POST", endpoint, data)
|
||||||
log.error(f"PUT request to {endpoint} failed: {e}")
|
|
||||||
except Exception as e:
|
async def put(self, endpoint: str, data: Optional[Dict] = None) -> Any:
|
||||||
log.error(f"PUT request to {endpoint} failed: {e}")
|
async with self:
|
||||||
|
return await self.request("PUT", endpoint, data)
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
class SPAPIError(Exception):
|
||||||
|
"""
|
||||||
|
Базовая ошибка для всех исключений, связанных с API SPWorlds.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, status_code: int, message: str):
|
||||||
|
self.status_code = status_code
|
||||||
|
self.message = message
|
||||||
|
super().__init__(f"[{status_code}] {message}")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"SPAPIError: [{self.status_code}] {self.message}"
|
||||||
|
|
||||||
|
|
||||||
|
class ValidationError(SPAPIError):
|
||||||
|
"""
|
||||||
|
Ошибка валидации.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, errors):
|
||||||
|
self.errors = errors
|
||||||
|
super().__init__(422, f"Validation failed: {errors}")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"ValidationError: {self.errors}"
|
||||||
|
|||||||
@@ -1,21 +1,30 @@
|
|||||||
|
from base64 import b64encode
|
||||||
|
from hashlib import sha256
|
||||||
|
from hmac import new, compare_digest
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from .api import APISession
|
from .api import APISession
|
||||||
from .types import User
|
from .types import User
|
||||||
from .types.me import Account
|
from .types.me import Account
|
||||||
from .types.payment import Item
|
from .types.payment import Item
|
||||||
from hmac import new, compare_digest
|
|
||||||
from hashlib import sha256
|
|
||||||
from base64 import b64encode
|
|
||||||
import aiohttp
|
|
||||||
|
|
||||||
__all__ = ['SPAPI']
|
__all__ = ['SPAPI']
|
||||||
|
|
||||||
|
|
||||||
class SPAPI(APISession):
|
class SPAPI(APISession):
|
||||||
"""
|
"""
|
||||||
Представляет собой клиент API для взаимодействия с конкретным сервисом.
|
pyspapi — высокоуровневый клиент для взаимодействия с SPWorldsAPI.
|
||||||
|
|
||||||
|
Предоставляет удобные методы для работы с балансом карты, вебхуками,
|
||||||
|
информацией о пользователе, транзакциями и платежами, а также верификацией вебхуков.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, card_id=None, token=None, timeout=5, sleep_time=0.2, retries=0):
|
def __init__(self, card_id: str,
|
||||||
|
token: str,
|
||||||
|
timeout: int = 5,
|
||||||
|
sleep_time: float = 0.2,
|
||||||
|
retries: int = 0,
|
||||||
|
raise_exception: bool = False):
|
||||||
"""
|
"""
|
||||||
Инициализирует объект SPAPI.
|
Инициализирует объект SPAPI.
|
||||||
|
|
||||||
@@ -24,13 +33,15 @@ class SPAPI(APISession):
|
|||||||
:param token: Токен API.
|
:param token: Токен API.
|
||||||
:type token: str
|
:type token: str
|
||||||
:param timeout: Таймаут для запросов API в секундах. По умолчанию 5.
|
:param timeout: Таймаут для запросов API в секундах. По умолчанию 5.
|
||||||
:type timeout: int, optional
|
:type timeout: int
|
||||||
:param sleep_time: Время ожидания между повторными запросами в секундах. По умолчанию 0.2.
|
:param sleep_time: Время ожидания между повторными запросами в секундах. По умолчанию 0.2.
|
||||||
:type sleep_time: float, optional
|
:type sleep_time: float
|
||||||
:param retries: Количество повторных попыток для неудачных запросов. По умолчанию 0.
|
:param retries: Количество повторных попыток для неудачных запросов. По умолчанию 0.
|
||||||
:type retries: int, optional
|
:type retries: int
|
||||||
|
:param raise_exception: Поднимать исключения при ошибке, если True.
|
||||||
|
:type raise_exception: bool
|
||||||
"""
|
"""
|
||||||
super().__init__(card_id, token, timeout, sleep_time, retries)
|
super().__init__(card_id, token, timeout, sleep_time, retries, raise_exception)
|
||||||
self.__card_id = card_id
|
self.__card_id = card_id
|
||||||
self.__token = token
|
self.__token = token
|
||||||
|
|
||||||
@@ -38,67 +49,48 @@ class SPAPI(APISession):
|
|||||||
"""
|
"""
|
||||||
Возвращает строковое представление объекта SPAPI.
|
Возвращает строковое представление объекта SPAPI.
|
||||||
"""
|
"""
|
||||||
return "%s(%s)" % (
|
return f"{self.__class__.__name__}({vars(self)})"
|
||||||
self.__class__.__name__,
|
|
||||||
self.__dict__
|
|
||||||
)
|
|
||||||
|
|
||||||
async def __get(self, method):
|
|
||||||
"""
|
|
||||||
Выполняет GET-запрос к API.
|
|
||||||
|
|
||||||
:param method: Метод API для вызова.
|
|
||||||
:type method: str
|
|
||||||
|
|
||||||
:return: JSON-ответ от API.
|
|
||||||
:rtype: dict
|
|
||||||
"""
|
|
||||||
async with APISession(self.__card_id, self.__token) as session:
|
|
||||||
response = await session.get(method)
|
|
||||||
response = await response.json()
|
|
||||||
return response
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
async def balance(self):
|
async def balance(self) -> Optional[int]:
|
||||||
"""
|
"""
|
||||||
Получает текущий баланс карты.
|
Получает текущий баланс карты.
|
||||||
|
|
||||||
:return: Текущий баланс карты.
|
:return: Текущий баланс карты.
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
card = await self.__get('card')
|
return int((await super().get('card'))['balance'])
|
||||||
return card['balance']
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
async def webhook(self) -> str:
|
async def webhook(self) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Получает URL вебхука, связанного с картой.
|
Получает URL вебхука, связанного с картой.
|
||||||
|
|
||||||
:return: URL вебхука.
|
:return: URL вебхука.
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
card = await self.__get('card')
|
return str((await super().get('card'))['webhook'])
|
||||||
return card['webhook']
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
async def me(self):
|
async def me(self) -> Optional[Account]:
|
||||||
"""
|
"""
|
||||||
Получает информацию об аккаунте текущего пользователя.
|
Получает информацию об аккаунте текущего пользователя.
|
||||||
|
|
||||||
:return: Объект Account, представляющий аккаунт текущего пользователя.
|
:return: Объект Account, представляющий аккаунт текущего пользователя.
|
||||||
:rtype: Account
|
:rtype: :class:`Account`
|
||||||
"""
|
"""
|
||||||
me = await self.__get('account/me')
|
me = await super().get('accounts/me')
|
||||||
return Account(
|
return Account(
|
||||||
account_id=me['id'],
|
account_id=me['id'],
|
||||||
username=me['username'],
|
username=me['username'],
|
||||||
|
minecraftuuid=me['minecraftUUID'],
|
||||||
status=me['status'],
|
status=me['status'],
|
||||||
roles=me['roles'],
|
roles=me['roles'],
|
||||||
city=me['city'],
|
cities=me['cities'],
|
||||||
cards=me['cards'],
|
cards=me['cards'],
|
||||||
created_at=me['createdAt'])
|
created_at=me['createdAt'])
|
||||||
|
|
||||||
async def get_user(self, discord_id: int) -> User:
|
async def get_user(self, discord_id: int) -> Optional[User]:
|
||||||
"""
|
"""
|
||||||
Получает информацию о пользователе по его ID в Discord.
|
Получает информацию о пользователе по его ID в Discord.
|
||||||
|
|
||||||
@@ -106,13 +98,13 @@ class SPAPI(APISession):
|
|||||||
:type discord_id: int
|
:type discord_id: int
|
||||||
|
|
||||||
:return: Объект User, представляющий пользователя.
|
:return: Объект User, представляющий пользователя.
|
||||||
:rtype: User
|
:rtype: :class:`User`
|
||||||
"""
|
"""
|
||||||
user = await self.__get(f'users/{discord_id}')
|
user = await super().get(f'users/{discord_id}')
|
||||||
cards = await self.__get(f"accounts/{user['username']}/cards")
|
cards = await super().get(f"accounts/{user['username']}/cards")
|
||||||
return User(user['username'], user['uuid'], cards)
|
return User(user['username'], user['uuid'], cards)
|
||||||
|
|
||||||
async def create_transaction(self, receiver: str, amount: int, comment: str):
|
async def create_transaction(self, receiver: str, amount: int, comment: str) -> Optional[int]:
|
||||||
"""
|
"""
|
||||||
Создает транзакцию.
|
Создает транзакцию.
|
||||||
|
|
||||||
@@ -126,17 +118,15 @@ class SPAPI(APISession):
|
|||||||
:return: Баланс после транзакции.
|
:return: Баланс после транзакции.
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
async with APISession(self.__card_id, self.__token) as session:
|
data = {
|
||||||
data = {
|
'receiver': receiver,
|
||||||
'receiver': receiver,
|
'amount': amount,
|
||||||
'amount': amount,
|
'comment': comment
|
||||||
'comment': comment
|
}
|
||||||
}
|
|
||||||
res = await session.post('transactions', data)
|
|
||||||
res = await res.json()
|
|
||||||
return res['balance']
|
|
||||||
|
|
||||||
async def create_payment(self, webhook_url: str, redirect_url: str, data: str, items) -> str:
|
return int((await super().post('transactions', data))['balance'])
|
||||||
|
|
||||||
|
async def create_payment(self, webhook_url: str, redirect_url: str, data: str, items: list[Item]) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Создает платеж.
|
Создает платеж.
|
||||||
|
|
||||||
@@ -148,40 +138,30 @@ class SPAPI(APISession):
|
|||||||
:type data: str
|
:type data: str
|
||||||
:param items: Элементы, включаемые в платеж.
|
:param items: Элементы, включаемые в платеж.
|
||||||
|
|
||||||
:return: URL для платежа.
|
:return: URL для платежа или None при ошибке.
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
async with APISession(self.__card_id, self.__token) as session:
|
data = {
|
||||||
data = {
|
'items': items,
|
||||||
'items': items,
|
'redirectUrl': redirect_url,
|
||||||
'redirectUrl': redirect_url,
|
'webhookUrl': webhook_url,
|
||||||
'webhookUrl': webhook_url,
|
'data': data
|
||||||
'data': data
|
}
|
||||||
}
|
|
||||||
res = await session.post('payments',data)
|
|
||||||
res = await res.json()
|
|
||||||
return res['url']
|
|
||||||
|
|
||||||
async def update_webhook(self, url: str):
|
return str((await super().post('payments', data))['url'])
|
||||||
|
|
||||||
|
async def update_webhook(self, url: str) -> Optional[dict]:
|
||||||
"""
|
"""
|
||||||
Обновляет URL вебхука, связанного с картой.
|
Обновляет URL вебхука, связанного с картой.
|
||||||
|
|
||||||
:param url: Новый URL вебхука.
|
:param url: Новый URL вебхука.
|
||||||
:type url: str
|
:return: Ответ API в виде словаря или None при ошибке.
|
||||||
|
|
||||||
:return: JSON-ответ от API.
|
|
||||||
:rtype: dict
|
|
||||||
"""
|
"""
|
||||||
async with APISession(self.__card_id, self.__token) as session:
|
data = {'url': url}
|
||||||
data = {
|
|
||||||
'url': url
|
|
||||||
}
|
|
||||||
res = await session.put(endpoint='card/webhook', data=data)
|
|
||||||
if res:
|
|
||||||
res = await res.json()
|
|
||||||
return res
|
|
||||||
|
|
||||||
def webhook_verify(self, data: str, header) -> bool:
|
return await super().put('card/webhook', data)
|
||||||
|
|
||||||
|
def webhook_verify(self, data: str, header: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Проверяет достоверность вебхука.
|
Проверяет достоверность вебхука.
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +1,61 @@
|
|||||||
class City:
|
class City:
|
||||||
def __init__(
|
def __init__(self, city_id=None, name=None, x=None, z=None, nether_x=None, nether_z=None, lane=None, role=None,
|
||||||
self,
|
created_at=None):
|
||||||
city_id=None,
|
|
||||||
name=None,
|
|
||||||
description=None,
|
|
||||||
x_cord=None,
|
|
||||||
z_cord=None,
|
|
||||||
is_mayor=None,
|
|
||||||
):
|
|
||||||
self._id = city_id
|
self._id = city_id
|
||||||
self._name = name
|
self._name = name
|
||||||
self._description = description
|
self._x = x
|
||||||
self._x_cord = x_cord
|
self._z = z
|
||||||
self._z_cord = z_cord
|
self._nether_x = nether_x
|
||||||
self._isMayor = is_mayor
|
self._nether_z = nether_z
|
||||||
|
self._lane = lane
|
||||||
|
self._role = role
|
||||||
|
self._created_at = created_at
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
return self._id
|
return self._id
|
||||||
|
|
||||||
@property
|
|
||||||
def description(self):
|
|
||||||
return self._description
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def x_cord(self):
|
def x(self):
|
||||||
return self._x_cord
|
return self._x
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def z_cord(self):
|
def z(self):
|
||||||
return self._z_cord
|
return self._z
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mayor(self):
|
def nether_x(self):
|
||||||
return self._isMayor
|
return self._nether_x
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nether_z(self):
|
||||||
|
return self._nether_z
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lane(self):
|
||||||
|
return self._lane
|
||||||
|
|
||||||
|
@property
|
||||||
|
def role(self):
|
||||||
|
return self._role
|
||||||
|
|
||||||
|
@property
|
||||||
|
def created_at(self):
|
||||||
|
return self._created_at
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"City(id={self.id}, name={self.name}, description={self.description}, x={self.x_cord}, z={self.z_cord}, is_mayor={self.mayor})"
|
return (
|
||||||
|
f"City(id={self._id}, name={self._name}, x={self._x}, z={self._z}, "
|
||||||
|
f"nether_x={self._nether_x}, nether_z={self._nether_z}, lane={self._lane}, role={self._role}, "
|
||||||
|
f"created_at={self._created_at})"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Cards:
|
class Card:
|
||||||
def __init__(self, card_id=None, name=None, number=None, color=None):
|
def __init__(self, card_id=None, name=None, number=None, color=None):
|
||||||
self._id = card_id
|
self._id = card_id
|
||||||
self._name = name
|
self._name = name
|
||||||
@@ -67,18 +79,32 @@ class Cards:
|
|||||||
return self._color
|
return self._color
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"Card(id={self.id}, name={self.name}, number={self.number}, color={self.color})"
|
return f"Card(id={self._id}, name={self._name}, number={self._number}, color={self._color})"
|
||||||
|
|
||||||
|
|
||||||
class Account:
|
class Account:
|
||||||
def __init__(self, account_id, username, status, roles, created_at, cards, city):
|
def __init__(self, account_id, username, minecraftuuid, status, roles, created_at, cards, cities):
|
||||||
self._id = account_id
|
self._id = account_id
|
||||||
self._username = username
|
self._username = username
|
||||||
|
self._minecraftuuid = minecraftuuid
|
||||||
self._status = status
|
self._status = status
|
||||||
self._roles = roles
|
self._roles = roles
|
||||||
self._city = City(**city) if city else None
|
self._cities = [
|
||||||
|
City(
|
||||||
|
city_id=city['city_id'],
|
||||||
|
name=city['name'],
|
||||||
|
x=city['x'],
|
||||||
|
z=city['z'],
|
||||||
|
nether_x=city['nether_x'],
|
||||||
|
nether_z=city['nether_z'],
|
||||||
|
lane=city['lane'],
|
||||||
|
role=city['role'],
|
||||||
|
created_at=city['created_at'],
|
||||||
|
)
|
||||||
|
for city in cities
|
||||||
|
]
|
||||||
self._cards = [
|
self._cards = [
|
||||||
Cards(
|
Card(
|
||||||
card_id=card["id"],
|
card_id=card["id"],
|
||||||
name=card["name"],
|
name=card["name"],
|
||||||
number=card["number"],
|
number=card["number"],
|
||||||
@@ -96,6 +122,10 @@ class Account:
|
|||||||
def username(self):
|
def username(self):
|
||||||
return self._username
|
return self._username
|
||||||
|
|
||||||
|
@property
|
||||||
|
def minecraftuuid(self):
|
||||||
|
return self._minecraftuuid
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def status(self):
|
def status(self):
|
||||||
return self._status
|
return self._status
|
||||||
@@ -105,8 +135,8 @@ class Account:
|
|||||||
return self._roles
|
return self._roles
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def city(self):
|
def cities(self):
|
||||||
return self._city
|
return self._cities
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cards(self):
|
def cards(self):
|
||||||
@@ -117,4 +147,6 @@ class Account:
|
|||||||
return self._created_at
|
return self._created_at
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"Account(id={self.id}, username={self.username}, status={self.status}, roles={self.roles}, city={self.city}, cards={self.cards}, created_at={self.created_at})"
|
return (f"Account(id={self._id}, username={self._username}, minecraftUUID={self._minecraftuuid}, "
|
||||||
|
f"status={self._status}, roles={self._roles}, cities={self._cities}, cards={self._cards}, "
|
||||||
|
f"created_at={self._created_at})")
|
||||||
|
|||||||
9
setup.py
9
setup.py
@@ -1,6 +1,6 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from setuptools import setup
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
requirements = []
|
requirements = []
|
||||||
with open("requirements.txt") as f:
|
with open("requirements.txt") as f:
|
||||||
@@ -21,10 +21,6 @@ readme = ""
|
|||||||
with open("README.rst") as f:
|
with open("README.rst") as f:
|
||||||
readme = f.read()
|
readme = f.read()
|
||||||
|
|
||||||
packages = [
|
|
||||||
"pyspapi"
|
|
||||||
]
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='pyspapi',
|
name='pyspapi',
|
||||||
license='MIT',
|
license='MIT',
|
||||||
@@ -39,7 +35,8 @@ setup(
|
|||||||
description='API wrapper for SP servers written in Python',
|
description='API wrapper for SP servers written in Python',
|
||||||
long_description=readme,
|
long_description=readme,
|
||||||
long_description_content_type='text/x-rst',
|
long_description_content_type='text/x-rst',
|
||||||
packages=packages,
|
packages=find_packages(),
|
||||||
|
package_data={'pyspapi': ['types/*', 'api/*']}, # Включаем дополнительные файлы и папки
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
install_requires=requirements,
|
install_requires=requirements,
|
||||||
python_requires='>=3.8.0',
|
python_requires='>=3.8.0',
|
||||||
|
|||||||
Reference in New Issue
Block a user