7 changed files with 716 additions and 224 deletions
@ -0,0 +1,11 @@ |
|||||
|
# Ignore pycache |
||||
|
|
||||
|
__pycache__ |
||||
|
|
||||
|
# Ignore dist |
||||
|
|
||||
|
/dist |
||||
|
|
||||
|
# Ignore pyproject |
||||
|
|
||||
|
pyproject.toml |
@ -1,224 +0,0 @@ |
|||||
import requests |
|
||||
import json |
|
||||
from flask import request |
|
||||
from websocket import create_connection |
|
||||
import socketio |
|
||||
|
|
||||
|
|
||||
class Scopes: |
|
||||
"""Удобный класс, для простого указания прав в приложении""" |
|
||||
|
|
||||
USER_SHOW = "oauth-user-show" |
|
||||
|
|
||||
DONATION_SUBSCRIBE = "oauth-donation-subscribe" |
|
||||
DONATION_INDEX = "oauth-donation-index" |
|
||||
|
|
||||
CUSTOM_ALERT_STORE = "oauth-custom_alert-store" |
|
||||
|
|
||||
GOAL_SUBSCRIBE = "oauth-goal-subscribe" |
|
||||
POLL_SUBSCRIBE = "oauth-poll-subscribe" |
|
||||
|
|
||||
ALL_SCOPES = [USER_SHOW, DONATION_INDEX, DONATION_SUBSCRIBE, CUSTOM_ALERT_STORE, |
|
||||
GOAL_SUBSCRIBE, POLL_SUBSCRIBE] |
|
||||
|
|
||||
|
|
||||
class Channels: |
|
||||
"""Права для подписки на каналы Centrifugo""" |
|
||||
|
|
||||
NEW_DONATION_ALERTS = "$alerts:donation_" |
|
||||
|
|
||||
DONATION_GOALS_UPDATES = "$goals:goal_" |
|
||||
|
|
||||
POLLS_UPDATES = "$polls:poll_" |
|
||||
|
|
||||
ALL_CHANNELS = [NEW_DONATION_ALERTS, DONATION_GOALS_UPDATES, POLLS_UPDATES] |
|
||||
|
|
||||
|
|
||||
class DonationAlertsApi: |
|
||||
"""Основной класс для работы с DA API""" |
|
||||
|
|
||||
def __init__(self, client_id, client_secret, redirect_uri, scopes): |
|
||||
symbols = [",", ", ", " ", "%20"] |
|
||||
|
|
||||
if isinstance(scopes, list): |
|
||||
obj_scopes = [] |
|
||||
for scope in scopes: |
|
||||
obj_scopes.append(scope) |
|
||||
|
|
||||
scopes = " ".join(obj_scopes) |
|
||||
|
|
||||
for symbol in symbols: |
|
||||
if symbol in scopes: |
|
||||
self.scope = scopes.replace(symbol, "%20").strip() # Replaces some symbols on '%20' for stable work |
|
||||
else: |
|
||||
self.scope = scopes |
|
||||
|
|
||||
self.client_id = client_id |
|
||||
self.client_secret = client_secret |
|
||||
self.redirect_uri = redirect_uri |
|
||||
self.login_url = f"https://www.donationalerts.com/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&scope={self.scope}" |
|
||||
self.token_url = f"https://www.donationalerts.com/oauth/token" |
|
||||
|
|
||||
# API LINKS |
|
||||
self.user_api = "https://www.donationalerts.com/api/v1/user/oauth" |
|
||||
self.donations_api = "https://www.donationalerts.com/api/v1/alerts/donations" |
|
||||
self.custom_alerts_api = "https://www.donationalerts.com/api/v1/custom_alert" |
|
||||
|
|
||||
def login(self): |
|
||||
return self.login_url |
|
||||
|
|
||||
def get_code(self): |
|
||||
return request.args.get("code") # Получаем аргмент "code" из адресной строки |
|
||||
|
|
||||
def get_access_token(self, code, full=False): |
|
||||
""" Параметр full=False |
|
||||
|
|
||||
Если True, то выводит весь json объект, а не только access_token |
|
||||
|
|
||||
""" |
|
||||
|
|
||||
payload = { |
|
||||
"client_id": self.client_id, |
|
||||
"client_secret": self.client_secret, |
|
||||
"grant_type": "authorization_code", |
|
||||
"code": code, |
|
||||
"redirect_uri": self.redirect_uri, |
|
||||
"scope": self.scope |
|
||||
} |
|
||||
|
|
||||
access_token = requests.post(url=self.token_url, data=payload).json() |
|
||||
self.refresh_token = access_token.get("refresh_token") |
|
||||
|
|
||||
return access_token if full else access_token.get("access_token") |
|
||||
|
|
||||
def get_donations(self, access_token): |
|
||||
headers = { |
|
||||
"Authorization": f"Bearer {access_token}", |
|
||||
"Content-Type": "application/x-www-form-urlencoded" |
|
||||
} |
|
||||
donate_object = requests.get(url=self.donations_api, headers=headers).json() |
|
||||
|
|
||||
return donate_object |
|
||||
|
|
||||
def get_user(self, access_token): |
|
||||
headers = { |
|
||||
"Authorization": f"Bearer {access_token}", |
|
||||
"Content-Type": "application/x-www-form-urlencoded" |
|
||||
} |
|
||||
user_object = requests.get(url=self.user_api, headers=headers).json() |
|
||||
|
|
||||
return user_object["data"] |
|
||||
|
|
||||
def send_custom_alert(self, access_token, external_id, headline, message, image_url=None, sound_url=None, is_shown=0): |
|
||||
headers = { |
|
||||
"Authorization": f"Bearer {access_token}", |
|
||||
"Content-Type": "application/x-www-form-urlencoded" |
|
||||
} |
|
||||
data = { |
|
||||
"external_id": external_id, |
|
||||
"header": headline, |
|
||||
"message": message, |
|
||||
"is_shown": is_shown, |
|
||||
"image_url": image_url, |
|
||||
"sound_url": sound_url |
|
||||
} |
|
||||
custom_alert_object = requests.post(url=self.custom_alerts_api, data=data, headers=headers).json() |
|
||||
|
|
||||
return custom_alert_object |
|
||||
|
|
||||
def get_refresh_token(self): |
|
||||
headers = {"Content-Type": "application/x-www-form-urlencoded"} |
|
||||
data = { |
|
||||
"grant_type": "refresh_token", |
|
||||
"client_id": self.client_id, |
|
||||
"client_secret": self.client_secret, |
|
||||
"refresh_token": self.refresh_token, |
|
||||
"redirect_uri": self.redirect_uri, |
|
||||
"scope": self.scope |
|
||||
} |
|
||||
|
|
||||
response = requests.post(url=self.token_url, data=data, headers=headers).json() |
|
||||
return response |
|
||||
|
|
||||
|
|
||||
class Centrifugo: |
|
||||
"""Получение событий в реальном времени (Oauth2)""" |
|
||||
|
|
||||
def __init__(self, socket_connection_token, access_token, user_id): |
|
||||
self.socket_connection_token = socket_connection_token |
|
||||
self.access_token = access_token |
|
||||
self.user_id = user_id |
|
||||
|
|
||||
self.uri = "wss://centrifugo.donationalerts.com/connection/websocket" |
|
||||
|
|
||||
def connect(self): |
|
||||
self.ws = create_connection(self.uri) # Подключаемся к серверу |
|
||||
self.ws.send(json.dumps( |
|
||||
{ |
|
||||
"params": { |
|
||||
"token": self.socket_connection_token |
|
||||
}, |
|
||||
"id": self.user_id |
|
||||
} |
|
||||
)) |
|
||||
self.ws_response = json.loads(self.ws.recv()) |
|
||||
|
|
||||
return self.ws_response |
|
||||
|
|
||||
def subscribe(self, channels): |
|
||||
chnls = [f"{channels}{self.user_id}"] |
|
||||
|
|
||||
if isinstance(channels, list): |
|
||||
chnls = [] |
|
||||
for channel in channels: |
|
||||
chnls.append(f"{channel}{self.user_id}") |
|
||||
|
|
||||
headers = { |
|
||||
"Authorization": f"Bearer {self.access_token}", |
|
||||
"Content-Type": "application/json" |
|
||||
} |
|
||||
data = { |
|
||||
"channels": chnls, |
|
||||
"client": self.ws_response["result"]["client"] |
|
||||
} |
|
||||
|
|
||||
response = requests.post(url="https://www.donationalerts.com/api/v1/centrifuge/subscribe", data=json.dumps(data), headers=headers).json() |
|
||||
for ch in response["channels"]: |
|
||||
self.ws.send(json.dumps( |
|
||||
{ |
|
||||
"params": { |
|
||||
"channel": ch["channel"], |
|
||||
"token": ch["token"] |
|
||||
}, |
|
||||
"method": 1, |
|
||||
"id": self.user_id |
|
||||
} |
|
||||
)) |
|
||||
|
|
||||
answer = {"response": self.ws.recv(), "sec_response": self.ws.recv()} |
|
||||
return answer # Возвращаем первые два ответа от сервера |
|
||||
|
|
||||
def listen(self): |
|
||||
return json.loads(self.ws.recv())["result"]["data"]["data"] # Возвращаем 3-й ответ от сервера |
|
||||
|
|
||||
sio = socketio.Client() |
|
||||
|
|
||||
|
|
||||
class Alert: |
|
||||
"""Получение донатов в реальном времени без Oauth2""" |
|
||||
|
|
||||
def __init__(self, token): |
|
||||
self.token = token # TOKEN можно скопировать здесь - https://www.donationalerts.com/dashboard/general |
|
||||
|
|
||||
def event(self): |
|
||||
def wrapper(function): |
|
||||
@sio.on("connect") |
|
||||
def on_connect(): |
|
||||
sio.emit("add-user", {"token": self.token, "type": "alert_widget"}) |
|
||||
|
|
||||
@sio.on("donation") |
|
||||
def on_message(data): |
|
||||
function(json.loads(data)) # Отправляем полученные данные в функцию |
|
||||
|
|
||||
sio.connect("wss://socket.donationalerts.ru:443", transports="websocket") |
|
||||
return wrapper |
|
@ -0,0 +1,2 @@ |
|||||
|
from .utils import * |
||||
|
from .donationalerts_api import * |
@ -0,0 +1,300 @@ |
|||||
|
import json |
||||
|
|
||||
|
import asyncio |
||||
|
import socketio |
||||
|
import aiohttp |
||||
|
import websockets |
||||
|
|
||||
|
from .utils import Event, User, Data, Donations, DonationsData, CentrifugoResponse |
||||
|
|
||||
|
DEFAULT_URL = "https://www.donationalerts.com/oauth/" |
||||
|
DEFAULT_API_LINK = "https://www.donationalerts.com/api/v1/" |
||||
|
|
||||
|
|
||||
|
class DonationAlertsApi: |
||||
|
|
||||
|
def __init__(self, client_id, client_secret, redirect_uri, scopes): |
||||
|
symbols = [",", ", ", " ", "%20"] |
||||
|
|
||||
|
if isinstance(scopes, list): |
||||
|
obj_scopes = [] |
||||
|
for scope in scopes: |
||||
|
obj_scopes.append(scope) |
||||
|
|
||||
|
scopes = " ".join(obj_scopes) |
||||
|
|
||||
|
for symbol in symbols: |
||||
|
if symbol in scopes: |
||||
|
self.scope = scopes.replace(symbol, "%20").strip() # Replaces some symbols on '%20' for stable work |
||||
|
else: |
||||
|
self.scope = scopes |
||||
|
|
||||
|
self.client_id = client_id |
||||
|
self.client_secret = client_secret |
||||
|
self.redirect_uri = redirect_uri |
||||
|
|
||||
|
def login(self): |
||||
|
return f"{DEFAULT_URL}authorize?client_id={self.client_id}&redirect_uri={self.redirect_uri}&response_type=code&scope={self.scope}" |
||||
|
|
||||
|
async def get_access_token(self, code, *, full_json=False): |
||||
|
payload = { |
||||
|
"client_id": self.client_id, |
||||
|
"client_secret": self.client_secret, |
||||
|
"grant_type": "authorization_code", |
||||
|
"code": code, |
||||
|
"redirect_uri": self.redirect_uri, |
||||
|
"scope": self.scope |
||||
|
} |
||||
|
|
||||
|
async with aiohttp.ClientSession() as session: |
||||
|
async with session.post(f"{DEFAULT_URL}token", data=payload) as response: |
||||
|
obj = await response.json() |
||||
|
|
||||
|
return Data( |
||||
|
obj["access_token"], |
||||
|
obj["expires_in"], |
||||
|
obj["refresh_token"], |
||||
|
obj["token_type"], |
||||
|
obj |
||||
|
) if full_json else obj["access_token"] |
||||
|
|
||||
|
async def donations_list(self, access_token, *, current_page: int=1, from_page: int=1, last_page: int=13, per_page: int=30, to: int=30, total: int=385): |
||||
|
headers = { |
||||
|
"Authorization": f"Bearer {access_token}", |
||||
|
"Content-Type": "application/x-www-form-urlencoded" |
||||
|
} |
||||
|
|
||||
|
"""Pagination in development""" |
||||
|
meta = { |
||||
|
"current_page": current_page, |
||||
|
"from": from_page, |
||||
|
"last_page": last_page, |
||||
|
"path": f"{DEFAULT_API_LINK}alerts/donations", |
||||
|
"per_page": per_page, |
||||
|
"to": to, |
||||
|
"total": total |
||||
|
} |
||||
|
links = { |
||||
|
"first": f"{DEFAULT_API_LINK}alerts/donations?page={from_page}", |
||||
|
"last": f"{DEFAULT_API_LINK}alerts/donations?page={last_page}", |
||||
|
"last": f"{DEFAULT_API_LINK}alerts/donations?page={last_page}", |
||||
|
"next": f"{DEFAULT_API_LINK}alerts/donations?page={current_page + 1}", |
||||
|
"prev": None |
||||
|
} |
||||
|
|
||||
|
async with aiohttp.ClientSession() as session: |
||||
|
async with session.get(f"{DEFAULT_API_LINK}alerts/donations", headers=headers) as response: |
||||
|
objs = await response.json() |
||||
|
donations = Donations(objects=objs["data"]) |
||||
|
|
||||
|
for obj in objs["data"]: |
||||
|
donation_object = DonationsData( |
||||
|
obj["amount"], |
||||
|
obj["amount_in_user_currency"], |
||||
|
obj["created_at"], |
||||
|
obj["currency"], |
||||
|
obj["id"], |
||||
|
obj["is_shown"], |
||||
|
obj["message"], |
||||
|
obj["message_type"], |
||||
|
obj["name"], |
||||
|
obj["payin_system"], |
||||
|
obj["recipient_name"], |
||||
|
obj["shown_at"], |
||||
|
obj["username"] |
||||
|
) |
||||
|
donations.donation.append(donation_object) |
||||
|
|
||||
|
return donations |
||||
|
|
||||
|
async def user(self, access_token): |
||||
|
headers = { |
||||
|
"Authorization": f"Bearer {access_token}", |
||||
|
"Content-Type": "application/x-www-form-urlencoded" |
||||
|
} |
||||
|
|
||||
|
async with aiohttp.ClientSession() as session: |
||||
|
async with session.get(f"{DEFAULT_API_LINK}user/oauth", headers=headers) as response: |
||||
|
obj = await response.json() |
||||
|
|
||||
|
return User( |
||||
|
obj["data"]["avatar"], |
||||
|
obj["data"]["code"], |
||||
|
obj["data"]["email"], |
||||
|
obj["data"]["id"], |
||||
|
obj["data"]["language"], |
||||
|
obj["data"]["name"], |
||||
|
obj["data"]["socket_connection_token"], |
||||
|
obj["data"] |
||||
|
) |
||||
|
|
||||
|
async def send_custom_alert(self, access_token, external_id, headline, message, *, image_url=None, sound_url=None, is_shown=0): |
||||
|
headers = { |
||||
|
"Authorization": f"Bearer {access_token}", |
||||
|
"Content-Type": "application/x-www-form-urlencoded" |
||||
|
} |
||||
|
payload = { |
||||
|
"external_id": external_id, |
||||
|
"headline": headline, |
||||
|
"message": message, |
||||
|
"is_shown": is_shown, |
||||
|
"image_url": image_url, |
||||
|
"sound_url": sound_url |
||||
|
} |
||||
|
|
||||
|
async with aiohttp.ClientSession() as session: |
||||
|
async with session.post(f"{DEFAULT_API_LINK}custom_alert", data=payload, headers=headers) as response: |
||||
|
return await response.json() |
||||
|
|
||||
|
async def get_refresh_token(self, access_token, refresh_token): |
||||
|
headers = { |
||||
|
"Content-Type": "application/x-www-form-urlencoded" |
||||
|
} |
||||
|
payload = { |
||||
|
"grant_type": "refresh_token", |
||||
|
"client_id": self.client_id, |
||||
|
"client_secret": self.client_secret, |
||||
|
"refresh_token": refresh_token, |
||||
|
"redirect_uri": self.redirect_uri, |
||||
|
"scope": self.scope |
||||
|
} |
||||
|
|
||||
|
async with aiohttp.ClientSession() as session: |
||||
|
async with session.post(f"{DEFAULT_URL}token", data=payload, headers=headers) as response: |
||||
|
obj = await response.json() |
||||
|
|
||||
|
return Data( |
||||
|
obj["access_token"], |
||||
|
obj["expires_in"], |
||||
|
obj["refresh_token"], |
||||
|
obj["token_type"], |
||||
|
obj |
||||
|
) |
||||
|
|
||||
|
|
||||
|
class Centrifugo: |
||||
|
|
||||
|
def __init__(self, socket_connection_token, access_token, user_id): |
||||
|
self.socket_connection_token = socket_connection_token |
||||
|
self.access_token = access_token |
||||
|
self.user_id = user_id |
||||
|
|
||||
|
async def subscribe(self, channels): |
||||
|
chnls = [f"{channels}{self.user_id}"] |
||||
|
if isinstance(channels, list): |
||||
|
chnls = [] |
||||
|
for channel in channels: |
||||
|
chnls.append(f"{channel}{self.user_id}") |
||||
|
|
||||
|
async with websockets.connect("wss://centrifugo.donationalerts.com/connection/websocket") as websocket: |
||||
|
await websocket.send(json.dumps( |
||||
|
{ |
||||
|
"params": { |
||||
|
"token": self.socket_connection_token |
||||
|
}, |
||||
|
"id": self.user_id |
||||
|
} |
||||
|
)) |
||||
|
|
||||
|
websocket_response = json.loads(await websocket.recv()) |
||||
|
|
||||
|
headers = { |
||||
|
"Authorization": f"Bearer {self.access_token}", |
||||
|
"Content-Type": "application/json" |
||||
|
} |
||||
|
data = { |
||||
|
"channels": chnls, |
||||
|
"client": websocket_response["result"]["client"] |
||||
|
} |
||||
|
|
||||
|
async with aiohttp.ClientSession(headers=headers) as session: |
||||
|
async with session.post(f"{DEFAULT_API_LINK}centrifuge/subscribe", data=json.dumps(data)) as response: |
||||
|
response = await response.json() |
||||
|
|
||||
|
for ch in response["channels"]: |
||||
|
await websocket.send(json.dumps( |
||||
|
{ |
||||
|
"params": { |
||||
|
"channel": ch["channel"], |
||||
|
"token": ch["token"] |
||||
|
}, |
||||
|
"method": 1, |
||||
|
"id": self.user_id |
||||
|
} |
||||
|
)) |
||||
|
|
||||
|
await websocket.recv() |
||||
|
await websocket.recv() |
||||
|
|
||||
|
obj = json.loads(await websocket.recv())["result"]["data"]["data"] |
||||
|
return CentrifugoResponse( |
||||
|
obj["amount"], |
||||
|
obj["amount_in_user_currency"], |
||||
|
obj["created_at"], |
||||
|
obj["currency"], |
||||
|
obj["id"], |
||||
|
obj["is_shown"], |
||||
|
obj["message"], |
||||
|
obj["message_type"], |
||||
|
obj["name"], |
||||
|
obj["payin_system"], |
||||
|
obj["recipient_name"], |
||||
|
obj["shown_at"], |
||||
|
obj["username"], |
||||
|
obj["reason"], |
||||
|
obj |
||||
|
) |
||||
|
|
||||
|
|
||||
|
sio = socketio.AsyncClient() |
||||
|
|
||||
|
|
||||
|
class Alert: |
||||
|
|
||||
|
def __init__(self, token): |
||||
|
self.token = token |
||||
|
|
||||
|
def event(self): |
||||
|
def decorate(function): |
||||
|
async def wrapper(): |
||||
|
|
||||
|
@sio.on("connect") |
||||
|
async def on_connect(): |
||||
|
await sio.emit("add-user", {"token": self.token, "type": "alert_widget"}) |
||||
|
|
||||
|
@sio.on("donation") |
||||
|
async def on_message(data): |
||||
|
data = json.loads(data) |
||||
|
|
||||
|
await function( |
||||
|
Event( |
||||
|
data["id"], |
||||
|
data["alert_type"], |
||||
|
data["is_shown"], |
||||
|
json.loads(data["additional_data"]), |
||||
|
data["billing_system"], |
||||
|
data["billing_system_type"], |
||||
|
data["username"], |
||||
|
data["amount"], |
||||
|
data["amount_formatted"], |
||||
|
data["amount_main"], |
||||
|
data["currency"], |
||||
|
data["message"], |
||||
|
data["header"], |
||||
|
data["date_created"], |
||||
|
data["emotes"], |
||||
|
data["ap_id"], |
||||
|
data["_is_test_alert"], |
||||
|
data["message_type"], |
||||
|
data["preset_id"], |
||||
|
data |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
await sio.connect("wss://socket.donationalerts.ru:443", transports="websocket") |
||||
|
|
||||
|
loop = asyncio.get_event_loop() |
||||
|
loop.run_until_complete(wrapper()) |
||||
|
return loop.run_forever() |
||||
|
|
||||
|
return decorate |
@ -0,0 +1,286 @@ |
|||||
|
import json |
||||
|
import requests |
||||
|
|
||||
|
from websocket import create_connection |
||||
|
import socketio |
||||
|
|
||||
|
from .utils import Event, User, Data, Donations, DonationsData, CentrifugoResponse |
||||
|
|
||||
|
DEFAULT_URL = "https://www.donationalerts.com/oauth/" |
||||
|
DEFAULT_API_LINK = "https://www.donationalerts.com/api/v1/" |
||||
|
|
||||
|
|
||||
|
class DonationAlertsApi: |
||||
|
""" |
||||
|
This class describes work with Donation Alerts API |
||||
|
""" |
||||
|
|
||||
|
def __init__(self, client_id, client_secret, redirect_uri, scopes): |
||||
|
symbols = [",", ", ", " ", "%20"] |
||||
|
|
||||
|
if isinstance(scopes, list): |
||||
|
obj_scopes = [] |
||||
|
for scope in scopes: |
||||
|
obj_scopes.append(scope) |
||||
|
|
||||
|
scopes = " ".join(obj_scopes) |
||||
|
|
||||
|
for symbol in symbols: |
||||
|
if symbol in scopes: |
||||
|
self.scope = scopes.replace(symbol, "%20").strip() # Replaces some symbols on '%20' for stable work |
||||
|
else: |
||||
|
self.scope = scopes |
||||
|
|
||||
|
self.client_id = client_id |
||||
|
self.client_secret = client_secret |
||||
|
self.redirect_uri = redirect_uri |
||||
|
|
||||
|
def login(self): |
||||
|
return f"{DEFAULT_URL}authorize?client_id={self.client_id}&redirect_uri={self.redirect_uri}&response_type=code&scope={self.scope}" |
||||
|
|
||||
|
def get_access_token(self, code, *, full_json=False): |
||||
|
payload = { |
||||
|
"client_id": self.client_id, |
||||
|
"client_secret": self.client_secret, |
||||
|
"grant_type": "authorization_code", |
||||
|
"code": code, |
||||
|
"redirect_uri": self.redirect_uri, |
||||
|
"scope": self.scope |
||||
|
} |
||||
|
|
||||
|
access_token = requests.post(f"{DEFAULT_URL}token", data=payload).json() |
||||
|
self.refresh_token = access_token.get("refresh_token") |
||||
|
|
||||
|
return Data( |
||||
|
obj["access_token"], |
||||
|
obj["expires_in"], |
||||
|
obj["refresh_token"], |
||||
|
obj["token_type"], |
||||
|
obj |
||||
|
) if full_json else obj["access_token"] |
||||
|
|
||||
|
def donations_list(self, access_token, *, current_page: int=1, from_page: int=1, last_page: int=13, per_page: int=30, to: int=30, total: int=385): |
||||
|
headers = { |
||||
|
"Authorization": f"Bearer {access_token}", |
||||
|
"Content-Type": "application/x-www-form-urlencoded" |
||||
|
} |
||||
|
|
||||
|
"""Pagination in development""" |
||||
|
meta = { |
||||
|
"current_page": current_page, |
||||
|
"from": from_page, |
||||
|
"last_page": last_page, |
||||
|
"path": f"{DEFAULT_API_LINK}alerts/donations", |
||||
|
"per_page": per_page, |
||||
|
"to": to, |
||||
|
"total": total |
||||
|
} |
||||
|
links = { |
||||
|
"first": f"{DEFAULT_API_LINK}alerts/donations?page={from_page}", |
||||
|
"last": f"{DEFAULT_API_LINK}alerts/donations?page={last_page}", |
||||
|
"last": f"{DEFAULT_API_LINK}alerts/donations?page={last_page}", |
||||
|
"next": f"{DEFAULT_API_LINK}alerts/donations?page={current_page + 1}", |
||||
|
"prev": None |
||||
|
} |
||||
|
|
||||
|
objs = requests.get(f"{DEFAULT_API_LINK}alerts/donations", headers=headers).json() |
||||
|
donations = Donations(objects=objs["data"]) |
||||
|
|
||||
|
for obj in objs["data"]: |
||||
|
donation_object = DonationsData( |
||||
|
obj["amount"], |
||||
|
obj["amount_in_user_currency"], |
||||
|
obj["created_at"], |
||||
|
obj["currency"], |
||||
|
obj["id"], |
||||
|
obj["is_shown"], |
||||
|
obj["message"], |
||||
|
obj["message_type"], |
||||
|
obj["name"], |
||||
|
obj["payin_system"], |
||||
|
obj["recipient_name"], |
||||
|
obj["shown_at"], |
||||
|
obj["username"] |
||||
|
) |
||||
|
donations.donation.append(donation_object) |
||||
|
|
||||
|
return donations |
||||
|
|
||||
|
def user(self, access_token): |
||||
|
headers = { |
||||
|
"Authorization": f"Bearer {access_token}", |
||||
|
"Content-Type": "application/x-www-form-urlencoded" |
||||
|
} |
||||
|
obj = requests.get(f"{DEFAULT_API_LINK}user/oauth", headers=headers).json() |
||||
|
|
||||
|
return User( |
||||
|
obj["data"]["avatar"], |
||||
|
obj["data"]["code"], |
||||
|
obj["data"]["email"], |
||||
|
obj["data"]["id"], |
||||
|
obj["data"]["language"], |
||||
|
obj["data"]["name"], |
||||
|
obj["data"]["socket_connection_token"], |
||||
|
obj["data"] |
||||
|
) |
||||
|
|
||||
|
def send_custom_alert(self, access_token, external_id, headline, message, *, image_url=None, sound_url=None, is_shown=0): |
||||
|
headers = { |
||||
|
"Authorization": f"Bearer {access_token}", |
||||
|
"Content-Type": "application/x-www-form-urlencoded" |
||||
|
} |
||||
|
payload = { |
||||
|
"external_id": external_id, |
||||
|
"headline": headline, |
||||
|
"message": message, |
||||
|
"is_shown": is_shown, |
||||
|
"image_url": image_url, |
||||
|
"sound_url": sound_url |
||||
|
} |
||||
|
|
||||
|
obj = requests.post(f"{DEFAULT_API_LINK}custom_alert", data=payload, headers=headers).json() |
||||
|
return obj |
||||
|
|
||||
|
def get_refresh_token(self, access_token, refresh_token): |
||||
|
headers = { |
||||
|
"Content-Type": "application/x-www-form-urlencoded" |
||||
|
} |
||||
|
payload = { |
||||
|
"grant_type": "refresh_token", |
||||
|
"client_id": self.client_id, |
||||
|
"client_secret": self.client_secret, |
||||
|
"refresh_token": refresh_token, |
||||
|
"redirect_uri": self.redirect_uri, |
||||
|
"scope": self.scope |
||||
|
} |
||||
|
|
||||
|
obj = requests.post(f"{DEFAULT_URL}token", data=payload, headers=headers).json() |
||||
|
return Data( |
||||
|
obj["access_token"], |
||||
|
obj["expires_in"], |
||||
|
obj["refresh_token"], |
||||
|
obj["token_type"], |
||||
|
obj |
||||
|
) |
||||
|
|
||||
|
|
||||
|
class Centrifugo: |
||||
|
|
||||
|
def __init__(self, socket_connection_token, access_token, user_id): |
||||
|
self.socket_connection_token = socket_connection_token |
||||
|
self.access_token = access_token |
||||
|
self.user_id = user_id |
||||
|
|
||||
|
self.uri = "wss://centrifugo.donationalerts.com/connection/websocket" |
||||
|
|
||||
|
def subscribe(self, channels): |
||||
|
chnls = [f"{channels}{self.user_id}"] |
||||
|
if isinstance(channels, list): |
||||
|
chnls = [] |
||||
|
for channel in channels: |
||||
|
chnls.append(f"{channel}{self.user_id}") |
||||
|
|
||||
|
ws = create_connection(self.uri) |
||||
|
ws.send(json.dumps( |
||||
|
{ |
||||
|
"params": { |
||||
|
"token": self.socket_connection_token |
||||
|
}, |
||||
|
"id": self.user_id |
||||
|
} |
||||
|
)) |
||||
|
|
||||
|
ws_response = json.loads(ws.recv()) |
||||
|
|
||||
|
headers = { |
||||
|
"Authorization": f"Bearer {self.access_token}", |
||||
|
"Content-Type": "application/json" |
||||
|
} |
||||
|
data = { |
||||
|
"channels": chnls, |
||||
|
"client": ws_response["result"]["client"] |
||||
|
} |
||||
|
|
||||
|
response = requests.post(f"{DEFAULT_API_LINK}centrifuge/subscribe", data=json.dumps(data), headers=headers).json() |
||||
|
for ch in response["channels"]: |
||||
|
self.ws.send(json.dumps( |
||||
|
{ |
||||
|
"params": { |
||||
|
"channel": ch["channel"], |
||||
|
"token": ch["token"] |
||||
|
}, |
||||
|
"method": 1, |
||||
|
"id": self.user_id |
||||
|
} |
||||
|
)) |
||||
|
|
||||
|
ws.recv() |
||||
|
ws.recv() |
||||
|
|
||||
|
obj = json.loads(ws.recv())["result"]["data"]["data"] |
||||
|
return CentrifugoResponse( |
||||
|
obj["amount"], |
||||
|
obj["amount_in_user_currency"], |
||||
|
obj["created_at"], |
||||
|
obj["currency"], |
||||
|
obj["id"], |
||||
|
obj["is_shown"], |
||||
|
obj["message"], |
||||
|
obj["message_type"], |
||||
|
obj["name"], |
||||
|
obj["payin_system"], |
||||
|
obj["recipient_name"], |
||||
|
obj["shown_at"], |
||||
|
obj["username"], |
||||
|
obj["reason"], |
||||
|
obj |
||||
|
) |
||||
|
|
||||
|
|
||||
|
sio = socketio.Client() |
||||
|
|
||||
|
|
||||
|
class Alert: |
||||
|
|
||||
|
def __init__(self, token): |
||||
|
self.token = token |
||||
|
|
||||
|
def event(self): |
||||
|
def wrapper(function): |
||||
|
|
||||
|
@sio.on("connect") |
||||
|
def on_connect(): |
||||
|
sio.emit("add-user", {"token": self.token, "type": "alert_widget"}) |
||||
|
|
||||
|
@sio.on("donation") |
||||
|
def on_message(data): |
||||
|
data = json.loads(data) |
||||
|
|
||||
|
function( |
||||
|
Event( |
||||
|
data["id"], |
||||
|
data["alert_type"], |
||||
|
data["is_shown"], |
||||
|
json.loads(data["additional_data"]), |
||||
|
data["billing_system"], |
||||
|
data["billing_system_type"], |
||||
|
data["username"], |
||||
|
data["amount"], |
||||
|
data["amount_formatted"], |
||||
|
data["amount_main"], |
||||
|
data["currency"], |
||||
|
data["message"], |
||||
|
data["header"], |
||||
|
data["date_created"], |
||||
|
data["emotes"], |
||||
|
data["ap_id"], |
||||
|
data["_is_test_alert"], |
||||
|
data["message_type"], |
||||
|
data["preset_id"], |
||||
|
data |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
sio.connect("wss://socket.donationalerts.ru:443", transports="websocket") |
||||
|
|
||||
|
return wrapper |
@ -0,0 +1,23 @@ |
|||||
|
class Scopes: |
||||
|
USER_SHOW = "oauth-user-show" |
||||
|
|
||||
|
DONATION_SUBSCRIBE = "oauth-donation-subscribe" |
||||
|
DONATION_INDEX = "oauth-donation-index" |
||||
|
|
||||
|
CUSTOM_ALERT_STORE = "oauth-custom_alert-store" |
||||
|
|
||||
|
GOAL_SUBSCRIBE = "oauth-goal-subscribe" |
||||
|
POLL_SUBSCRIBE = "oauth-poll-subscribe" |
||||
|
|
||||
|
ALL_SCOPES = [USER_SHOW, DONATION_INDEX, DONATION_SUBSCRIBE, CUSTOM_ALERT_STORE, |
||||
|
GOAL_SUBSCRIBE, POLL_SUBSCRIBE] |
||||
|
|
||||
|
|
||||
|
class Channels: |
||||
|
NEW_DONATION_ALERTS = "$alerts:donation_" |
||||
|
|
||||
|
DONATION_GOALS_UPDATES = "$goals:goal_" |
||||
|
|
||||
|
POLLS_UPDATES = "$polls:poll_" |
||||
|
|
||||
|
ALL_CHANNELS = [NEW_DONATION_ALERTS, DONATION_GOALS_UPDATES, POLLS_UPDATES] |
@ -0,0 +1,94 @@ |
|||||
|
from dataclasses import dataclass |
||||
|
|
||||
|
|
||||
|
@dataclass |
||||
|
class Event: |
||||
|
|
||||
|
id: int |
||||
|
alert_type: str |
||||
|
is_shown: str |
||||
|
additional_data: dict |
||||
|
billing_system: str |
||||
|
billing_system_type: str |
||||
|
username: str |
||||
|
amount: str |
||||
|
amount_formatted: str |
||||
|
amount_main: int |
||||
|
currency: str |
||||
|
message: str |
||||
|
header: str |
||||
|
date_created: str |
||||
|
emotes: str |
||||
|
ap_id: str |
||||
|
_is_test_alert: bool |
||||
|
message_type: str |
||||
|
preset_id: int |
||||
|
objects: dict |
||||
|
|
||||
|
|
||||
|
@dataclass |
||||
|
class Donations: |
||||
|
|
||||
|
donation = [] |
||||
|
objects: dict = None |
||||
|
|
||||
|
|
||||
|
@dataclass |
||||
|
class DonationsData: |
||||
|
|
||||
|
amount: int |
||||
|
amount_in_user_currency: float |
||||
|
created_at: str |
||||
|
currency: str |
||||
|
id: int |
||||
|
is_shown: int |
||||
|
message: str |
||||
|
message_type: str |
||||
|
name: str |
||||
|
payin_system: str |
||||
|
recipient_name: str |
||||
|
shown_at: str |
||||
|
username: str |
||||
|
|
||||
|
|
||||
|
@dataclass |
||||
|
class User: |
||||
|
|
||||
|
avatar: str |
||||
|
code: str |
||||
|
email: str |
||||
|
id: int |
||||
|
language: str |
||||
|
name: str |
||||
|
socket_connection_token: str |
||||
|
objects: dict |
||||
|
|
||||
|
|
||||
|
@dataclass |
||||
|
class Data: |
||||
|
|
||||
|
access_token: str |
||||
|
expires_in: int |
||||
|
refresh_token: str |
||||
|
token_type: str |
||||
|
objects: dict |
||||
|
|
||||
|
|
||||
|
@dataclass |
||||
|
class CentrifugoResponse: |
||||
|
|
||||
|
amount: int |
||||
|
amount_in_user_currency: float |
||||
|
created_at: str |
||||
|
currency: str |
||||
|
id: int |
||||
|
is_shown: int |
||||
|
message: str |
||||
|
message_type: str |
||||
|
name: str |
||||
|
payin_system: str |
||||
|
recipient_name: str |
||||
|
shown_at: str |
||||
|
username: str |
||||
|
reason: str |
||||
|
objects: dict |
Loading…
Reference in new issue