Upload 1.5.0 version

Upload docs
This commit is contained in:
Teleport
2023-05-08 21:43:58 +03:00
parent 852a407ceb
commit 6b771f8925
22 changed files with 676 additions and 367 deletions

View File

@@ -1,42 +1,61 @@
import platform
import sys
from base64 import b64encode
from dataclasses import dataclass
from enum import Enum
from hashlib import sha256
import hmac
import requests as rq
import time
from typing import Optional, List
from typing import List, Callable
import logging
from mojang import MojangAPI
from mojang import API as MAPI
from . import errors as err
from .User import User
from .Parameters import PaymentParameters, TransactionParameters
from .Parameters import Payment, Transaction
# deesiigneer stole some of my ideas and improved them. But I didn't lose my head and improved what deesiigneer improved :)
mapi = MAPI()
class Py_SPW:
__spworlds_api_url = 'https://spworlds.ru/api/public'
class _RequestTypes(Enum):
POST = 'POST'
GET = 'GET'
@dataclass
class _Card:
id: str
token: str
class SpApi:
_spworlds_api_url = 'https://spworlds.ru/api/public'
def __init__(self, card_id: str, card_token: str):
self.__card_token = card_token
self.__authorization = f"Bearer {str(b64encode(str(f'{card_id}:{card_token}').encode('utf-8')), 'utf-8')}"
self._card = _Card(card_id, card_token)
self._authorization = f"Bearer {str(b64encode(str(f'{card_id}:{card_token}').encode('utf-8')), 'utf-8')}"
def __get(self, path: str = None, ignore_status_code: bool = False) -> rq.Response:
def _request(self, method: _RequestTypes, path: str = '', body: dict = None, *,
ignore_codes: list = []) -> rq.Response:
headers = {
'Authorization': self.__authorization,
'User-Agent': 'Py-SPW'
'Authorization': self._authorization,
'User-Agent': f'Py-SPW (Python {platform.python_version()})'
}
try:
response = rq.get(url=self.__spworlds_api_url + path, headers=headers)
response = rq.request(method.value, url=self._spworlds_api_url + path, headers=headers, json=body)
except rq.exceptions.ConnectionError as error:
raise err.SpwApiError(error)
if ignore_status_code:
if response.headers.get('Content-Type') != 'application/json':
raise err.SpwApiDDOS()
if response.ok or response.status_code in ignore_codes:
return response
if response.status_code == 200:
return response
elif response.status_code == 401:
raise err.SpwUnauthorized()
elif response.status_code >= 500:
raise err.SpwApiError(f'HTTP: {response.status_code}, Server Error.')
@@ -45,74 +64,30 @@ class Py_SPW:
raise err.SpwApiError(
f'HTTP: {response.status_code} {response.json()["error"]}. Message: {response.json()["message"]}')
def __post(self, path: str = None, body: dict = None) -> rq.Response:
headers = {
'Authorization': self.__authorization,
'User-Agent': 'Py-SPW'
}
def ping(self) -> bool:
"""
Проверка работоспособности API
:return: Bool работает или нет
"""
try:
response = rq.post(url=self.__spworlds_api_url + path, headers=headers, json=body)
self.get_balance()
return True
except rq.exceptions.ConnectionError as error:
raise err.SpwApiError(error)
except err.SpwApiError:
return False
if response.status_code == 200:
return response
elif response.status_code >= 500:
raise err.SpwApiError(f'HTTP: {response.status_code}, Server Error.')
else:
raise err.SpwApiError(f'HTTP: {response.status_code} {response.json()["error"]}. Message: {response.json()["message"]}')
def get_user(self, discord_id: str, use_mojang_api: bool = True) -> User:
def get_user(self, discord_id: str) -> User:
"""
Получение пользователя
:param use_mojang_api: Если True то будет обращаться к Mojang API для получения UUID, иначе обращаться не будет
:param discord_id: ID пользователя дискорда.
:return: Class pyspw.User.User
"""
response = self.__get(f'/users/{discord_id}', True)
response = self._request(_RequestTypes.GET, f'/users/{discord_id}', ignore_codes=[404])
if response.status_code == 404:
raise err.SpwUserNotFound(discord_id)
if response.status_code == 200:
return User(response.json()['username'], use_mojang_api)
elif response.status_code == 404:
return User(None, use_mojang_api)
elif response.status_code >= 500:
raise err.SpwApiError(f'HTTP: {response.status_code}, Server Error.')
else:
raise err.SpwApiError(f'HTTP: {response.status_code} {response.json()["error"]}. Message: {response.json()["message"]}')
def get_users(self, discord_ids: List[str], delay: float = 0.5, use_mojang_api: bool = True) -> List[User]:
"""
Получение пользователей
:param use_mojang_api: Если True то будет обращаться к Mojang API для получения UUID, иначе обращаться не будет
:param delay: Значение задержки между запросами, указывается в секундах
:param discord_ids: List с IDs пользователей дискорда.
:return: List содержащий Classes pyspw.User.User
"""
users = []
if len(discord_ids) > 100 and delay < 0.5:
logging.warning('You send DOS attack to SPWorlds API. Please set the delay to greater than or equal to 0.5')
for discord_id in discord_ids:
users.append(self.get_user(discord_id, False))
time.sleep(delay)
if use_mojang_api:
nicknames = [user.nickname for user in users]
uuids = MojangAPI.get_uuids(nicknames)
for user in users:
user.uuid = uuids[user.nickname]
return users
return User(response.json()['username'])
def check_access(self, discord_id: str) -> bool:
"""
@@ -120,31 +95,8 @@ class Py_SPW:
:param discord_id: ID пользователя дискорда.
:return: Bool True если у пользователя есть проходка, иначе False
"""
return self.get_user(discord_id, False).access
def check_accesses(self, discord_ids: List[str], delay: float = 0.5) -> List[bool]:
"""
Получение статуса проходок
:param delay: Значение задержки между запросами, указывается в секундах
:param discord_ids: List с IDs пользователей дискорда.
:return: List содержащий bool со значением статуса проходки
"""
accesses = []
users = self.get_users(discord_ids, delay, False)
if len(discord_ids) > 100 and delay < 0.5:
logging.warning('You send DOS attack to SPWorlds API. Please set the delay to greater than or equal to 0.5')
for user in users:
if user is not None:
accesses.append(True)
else:
accesses.append(False)
return accesses
response = self._request(_RequestTypes.GET, f'/users/{discord_id}', ignore_codes=[404])
return response.status_code != 404
def check_webhook(self, webhook_data: str, X_Body_Hash: str) -> bool:
"""
@@ -154,77 +106,80 @@ class Py_SPW:
:return: Bool True если вебхук пришел от верифицированного сервера, иначе False
"""
hmac_data = hmac.new(self.__card_token.encode('utf-8'), webhook_data.encode('utf-8'), sha256).digest()
hmac_data = hmac.new(self._card.token.encode('utf-8'), webhook_data.encode('utf-8'), sha256).digest()
base64_data = b64encode(hmac_data)
return hmac.compare_digest(base64_data, X_Body_Hash.encode('utf-8'))
def create_payment(self, params: PaymentParameters) -> str:
def create_payment(self, params: Payment) -> str:
"""
Создание ссылки на оплату
:param params: class PaymentParams параметров оплаты
:return: Str ссылка на страницу оплаты, на которую стоит перенаправить пользователя.
"""
return self._request(_RequestTypes.POST, '/payment', params.dict()).json()['url']
body = {
'amount': params.amount,
'redirectUrl': params.redirectUrl,
'webhookUrl': params.webhookUrl,
'data': params.data
}
return self.__post('/payment', body).json()['url']
def create_payments(self, payments: List[PaymentParameters], delay: float = 0.5) -> list:
"""
Создание ссылок на оплату
:param payments: Список содержащий classes PaymentParams
:param delay: Значение задержки между запросами, указывается в секундах
:return: List со ссылками на страницы оплаты, в том порядке, в котором они были в кортеже payments
"""
answer = []
if len(payments) > 100 and delay < 0.5:
logging.warning('You send DOS attack to SPWorlds API. Please set the delay to greater than or equal to 0.5')
for payment in payments:
answer.append(self.create_payment(payment))
time.sleep(delay)
return answer
def send_transaction(self, params: TransactionParameters) -> None:
def send_transaction(self, params: Transaction) -> None:
"""
Отправка транзакции
:param params: class TransactionParameters параметры транзакции
:return: None.
"""
body = {
'receiver': params.receiver,
'amount': params.amount,
'comment': params.comment
}
self.__post('/transactions', body)
def send_transactions(self, transactions: List[TransactionParameters], delay: float = 0.5) -> None:
"""
Отправка транзакций
:param delay: Значение задержки между запросами, указывается в секундах
:param transactions: Список содержащий classes TransactionParameters
:return: List со ссылками на страницы оплаты, в том порядке, в котором они были в кортеже payments
"""
if len(transactions) > 100 and delay < 0.5:
logging.warning('You send DOS attack to SPWorlds API. Please set the delay to greater than or equal to 0.5')
for transaction in transactions:
self.send_transaction(transaction)
time.sleep(delay)
response = self._request(_RequestTypes.POST, '/transactions', params.dict(), ignore_codes=[400])
if response.status_code == 400 and response.json()["message"] == 'Недостаточно средств на карте':
raise err.SpwInsufficientFunds()
def get_balance(self) -> int:
"""
Получение баланса
:return: Int со значением баланса
"""
return self._request(_RequestTypes.GET, '/card').json()['balance']
return self.__get('/card').json()['balance']
# Manys
def _many_req(self, iterable: List, method: Callable, delay: float) -> List:
users = []
if len(iterable) > 100 and delay <= 0.5:
logging.warning('You send DOS attack to SPWorlds API. Please set the delay to greater than to 0.5')
for i in iterable:
users.append(method(i))
time.sleep(delay)
return users
def get_users(self, discord_ids: List[str], delay: float = 0.3) -> List[User]:
"""
Получение пользователей
:param delay: Значение задержки между запросами, указывается в секундах
:param discord_ids: List с IDs пользователей дискорда.
:return: List содержащий Classes pyspw.User.User
"""
return self._many_req(discord_ids, self.get_user, delay)
def check_accesses(self, discord_ids: List[str], delay: float = 0.3) -> List[bool]:
"""
Получение статуса проходок
:param delay: Значение задержки между запросами, указывается в секундах
:param discord_ids: List с IDs пользователей дискорда.
:return: List содержащий bool со значением статуса проходки
"""
return self._many_req(discord_ids, self.check_access, delay)
def create_payments(self, payments: List[Payment], delay: float = 0.5) -> List[str]:
"""
Создание ссылок на оплату
:param payments: Список содержащий classes PaymentParams
:param delay: Значение задержки между запросами, указывается в секундах
:return: List со ссылками на страницы оплаты, в том порядке, в котором они были в кортеже payments
"""
return self._many_req(payments, self.create_payment, delay)
def send_transactions(self, transactions: List[Transaction], delay: float = 0.5) -> None:
"""
Отправка транзакций
:param delay: Значение задержки между запросами, указывается в секундах
:param transactions: Список содержащий classes TransactionParameters
:return: List со ссылками на страницы оплаты, в том порядке, в котором они были в кортеже payments
"""
self._many_req(transactions, self.send_transaction, delay)