mirror of
https://github.com/boticord/boticordpy.git
synced 2024-11-14 12:27:28 +03:00
add link shortener
This commit is contained in:
parent
e101a948c4
commit
f4a136a348
7 changed files with 149 additions and 37 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -7,6 +7,6 @@ __pycache__
|
||||||
dist
|
dist
|
||||||
docs/_build
|
docs/_build
|
||||||
boticordpy.egg-info
|
boticordpy.egg-info
|
||||||
test.py
|
_testing.py
|
||||||
/.pytest_cache
|
/.pytest_cache
|
||||||
/docs/build/
|
/docs/build/
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
"""
|
"""
|
||||||
Boticord API Wrapper
|
Boticord API Wrapper
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
A basic wrapper for the Boticord API.
|
A basic wrapper for the BotiCord API.
|
||||||
:copyright: (c) 2022 Marakarka
|
:copyright: (c) 2022 Marakarka
|
||||||
:license: MIT, see LICENSE for more details.
|
:license: MIT, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__title__ = 'boticordpy'
|
__title__ = "boticordpy"
|
||||||
__author__ = 'Marakarka'
|
__author__ = "Marakarka"
|
||||||
__license__ = 'MIT'
|
__license__ = "MIT"
|
||||||
__copyright__ = 'Copyright 2022 Marakarka'
|
__copyright__ = "Copyright 2022 Marakarka"
|
||||||
__version__ = '2.1.0'
|
__version__ = "2.1.0"
|
||||||
|
|
||||||
from .client import BoticordClient
|
from .client import BoticordClient
|
||||||
from .webhook import Webhook
|
from .webhook import Webhook
|
||||||
|
|
|
@ -20,7 +20,7 @@ class AutoPost:
|
||||||
"_error",
|
"_error",
|
||||||
"_stats",
|
"_stats",
|
||||||
"_task",
|
"_task",
|
||||||
"_stopped"
|
"_stopped",
|
||||||
)
|
)
|
||||||
|
|
||||||
_success: typing.Any
|
_success: typing.Any
|
||||||
|
@ -134,7 +134,9 @@ class AutoPost:
|
||||||
Boticord recommends not to set interval lower than 900 seconds!
|
Boticord recommends not to set interval lower than 900 seconds!
|
||||||
"""
|
"""
|
||||||
if seconds < 900:
|
if seconds < 900:
|
||||||
raise ValueError("no. Boticord recommends not to set interval lower than 900 seconds!")
|
raise ValueError(
|
||||||
|
"no. Boticord recommends not to set interval lower than 900 seconds!"
|
||||||
|
)
|
||||||
|
|
||||||
self._interval = seconds
|
self._interval = seconds
|
||||||
return self
|
return self
|
||||||
|
@ -170,7 +172,9 @@ class AutoPost:
|
||||||
raise bexc.InternalException("You must provide stats")
|
raise bexc.InternalException("You must provide stats")
|
||||||
|
|
||||||
if self.is_running:
|
if self.is_running:
|
||||||
raise bexc.InternalException("Automatically stats posting is already running")
|
raise bexc.InternalException(
|
||||||
|
"Automatically stats posting is already running"
|
||||||
|
)
|
||||||
|
|
||||||
task = asyncio.ensure_future(self._internal_loop())
|
task = asyncio.ensure_future(self._internal_loop())
|
||||||
self._task = task
|
self._task = task
|
||||||
|
|
|
@ -15,11 +15,8 @@ class BoticordClient:
|
||||||
token (:obj:`str`)
|
token (:obj:`str`)
|
||||||
Your bot's Boticord API Token.
|
Your bot's Boticord API Token.
|
||||||
"""
|
"""
|
||||||
__slots__ = (
|
|
||||||
"http",
|
__slots__ = ("http", "_autopost", "_token")
|
||||||
"_autopost",
|
|
||||||
"_token"
|
|
||||||
)
|
|
||||||
|
|
||||||
http: HttpClient
|
http: HttpClient
|
||||||
|
|
||||||
|
@ -56,7 +53,9 @@ class BoticordClient:
|
||||||
response = await self.http.get_bot_comments(bot_id)
|
response = await self.http.get_bot_comments(bot_id)
|
||||||
return [boticord_types.SingleComment(**comment) for comment in response]
|
return [boticord_types.SingleComment(**comment) for comment in response]
|
||||||
|
|
||||||
async def post_bot_stats(self, servers: int = 0, shards: int = 0, users: int = 0) -> dict:
|
async def post_bot_stats(
|
||||||
|
self, servers: int = 0, shards: int = 0, users: int = 0
|
||||||
|
) -> dict:
|
||||||
"""Post Bot's stats.
|
"""Post Bot's stats.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -70,11 +69,9 @@ class BoticordClient:
|
||||||
:obj:`dict`:
|
:obj:`dict`:
|
||||||
Boticord API Response status
|
Boticord API Response status
|
||||||
"""
|
"""
|
||||||
response = await self.http.post_bot_stats({
|
response = await self.http.post_bot_stats(
|
||||||
"servers": servers,
|
{"servers": servers, "shards": shards, "users": users}
|
||||||
"shards": shards,
|
)
|
||||||
"users": users
|
|
||||||
})
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
async def get_server_info(self, server_id: int) -> boticord_types.Server:
|
async def get_server_info(self, server_id: int) -> boticord_types.Server:
|
||||||
|
@ -160,6 +157,61 @@ class BoticordClient:
|
||||||
response = await self.http.get_user_bots(user_id)
|
response = await self.http.get_user_bots(user_id)
|
||||||
return [boticord_types.SimpleBot(**bot) for bot in response]
|
return [boticord_types.SimpleBot(**bot) for bot in response]
|
||||||
|
|
||||||
|
async def get_my_shorted_links(self, *, code: str = None):
|
||||||
|
"""Gets shorted links of an authorized user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
code (:obj:`str`)
|
||||||
|
Code of shorted link. Could be None.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Union[:obj:`list` [ :obj:`~.types.ShortedLink` ], :obj:`~types.ShortedLink`]:
|
||||||
|
List of shorted links if none else shorted link
|
||||||
|
"""
|
||||||
|
response = await self.http.get_my_shorted_links(code)
|
||||||
|
|
||||||
|
return (
|
||||||
|
[boticord_types.ShortedLink(**link) for link in response]
|
||||||
|
if code is None
|
||||||
|
else boticord_types.ShortedLink(**response[0])
|
||||||
|
)
|
||||||
|
|
||||||
|
async def create_shorted_link(self, *, code: str, link: str, domain: boticord_types.LinkDomain = 1):
|
||||||
|
"""Creates new shorted link
|
||||||
|
|
||||||
|
Args:
|
||||||
|
code (:obj:`str`)
|
||||||
|
Code of link to short.
|
||||||
|
link (:obj:`str`)
|
||||||
|
Link to short.
|
||||||
|
domain (:obj:`~.types.LinkDomain`)
|
||||||
|
Domain to use in shorted link
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`~types.ShortedLink`:
|
||||||
|
Shorted Link
|
||||||
|
"""
|
||||||
|
response = await self.http.create_shorted_link(code, link, domain=domain)
|
||||||
|
|
||||||
|
return boticord_types.ShortedLink(**response)
|
||||||
|
|
||||||
|
async def delete_shorted_link(self, code: str, domain: boticord_types.LinkDomain = 1):
|
||||||
|
"""Deletes shorted link
|
||||||
|
|
||||||
|
Args:
|
||||||
|
code (:obj:`str`)
|
||||||
|
Code of link to delete.
|
||||||
|
domain (:obj:`~.types.LinkDomain`)
|
||||||
|
Domain that is used in shorted link
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`bool`:
|
||||||
|
Is link deleted successfully?
|
||||||
|
"""
|
||||||
|
response = await self.http.delete_shorted_link(code, domain)
|
||||||
|
|
||||||
|
return response.get('ok', False)
|
||||||
|
|
||||||
def autopost(self) -> AutoPost:
|
def autopost(self) -> AutoPost:
|
||||||
"""Returns a helper instance for auto-posting.
|
"""Returns a helper instance for auto-posting.
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import asyncio
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
from . import exceptions
|
from . import exceptions
|
||||||
|
from .types import LinkDomain
|
||||||
|
|
||||||
|
|
||||||
class HttpClient:
|
class HttpClient:
|
||||||
|
@ -23,26 +24,21 @@ class HttpClient:
|
||||||
self.token = auth_token
|
self.token = auth_token
|
||||||
self.API_URL = "https://api.boticord.top/v1/"
|
self.API_URL = "https://api.boticord.top/v1/"
|
||||||
|
|
||||||
loop = kwargs.get('loop') or asyncio.get_event_loop()
|
loop = kwargs.get("loop") or asyncio.get_event_loop()
|
||||||
|
|
||||||
self.session = kwargs.get('session') or aiohttp.ClientSession(loop=loop)
|
self.session = kwargs.get("session") or aiohttp.ClientSession(loop=loop)
|
||||||
|
|
||||||
async def make_request(self,
|
async def make_request(self, method: str, endpoint: str, **kwargs):
|
||||||
method: str,
|
|
||||||
endpoint: str,
|
|
||||||
**kwargs):
|
|
||||||
"""Send requests to the API"""
|
"""Send requests to the API"""
|
||||||
|
|
||||||
kwargs["headers"] = {
|
kwargs["headers"] = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Authorization": self.token
|
"Authorization": self.token,
|
||||||
}
|
}
|
||||||
|
|
||||||
url = f"{self.API_URL}{endpoint}"
|
url = f"{self.API_URL}{endpoint}"
|
||||||
|
|
||||||
async with self.session.request(method,
|
async with self.session.request(method, url, **kwargs) as response:
|
||||||
url,
|
|
||||||
**kwargs) as response:
|
|
||||||
data = await response.json()
|
data = await response.json()
|
||||||
|
|
||||||
if response.status == 200:
|
if response.status == 200:
|
||||||
|
@ -97,3 +93,21 @@ class HttpClient:
|
||||||
def get_user_bots(self, user_id: int):
|
def get_user_bots(self, user_id: int):
|
||||||
"""Get bots of specified user"""
|
"""Get bots of specified user"""
|
||||||
return self.make_request("GET", f"bots/{user_id}")
|
return self.make_request("GET", f"bots/{user_id}")
|
||||||
|
|
||||||
|
def get_my_shorted_links(self, code: str = None):
|
||||||
|
"""Get shorted links of an authorized user"""
|
||||||
|
body = {"code": code} if code is not None else {}
|
||||||
|
|
||||||
|
return self.make_request("POST", "links/get", json=body)
|
||||||
|
|
||||||
|
def create_shorted_link(self, code: str, link: str, *, domain: LinkDomain = 1):
|
||||||
|
"""Create new shorted link"""
|
||||||
|
return self.make_request(
|
||||||
|
"POST", "links/create", json={"code": code, "link": link, "domain": int(domain)}
|
||||||
|
)
|
||||||
|
|
||||||
|
def delete_shorted_link(self, code: str, domain: LinkDomain = 1):
|
||||||
|
"""Delete shorted link"""
|
||||||
|
return self.make_request(
|
||||||
|
"POST", "links/delete", json={"code": code, "domain": int(domain)}
|
||||||
|
)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import typing
|
import typing
|
||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
KT = typing.TypeVar("KT")
|
KT = typing.TypeVar("KT")
|
||||||
VT = typing.TypeVar("VT")
|
VT = typing.TypeVar("VT")
|
||||||
|
@ -59,8 +60,7 @@ def parse_user_comments_dict(response_data: dict) -> dict:
|
||||||
|
|
||||||
|
|
||||||
class ApiData(dict, typing.MutableMapping[KT, VT]):
|
class ApiData(dict, typing.MutableMapping[KT, VT]):
|
||||||
"""Base class used to represent received data from the API.
|
"""Base class used to represent received data from the API."""
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs: VT) -> None:
|
def __init__(self, **kwargs: VT) -> None:
|
||||||
super().__init__(**parse_response_dict(kwargs))
|
super().__init__(**parse_response_dict(kwargs))
|
||||||
|
@ -94,6 +94,7 @@ class SingleComment(ApiData):
|
||||||
|
|
||||||
class Bot(ApiData):
|
class Bot(ApiData):
|
||||||
"""This model represents a bot, returned from the BotiCord API"""
|
"""This model represents a bot, returned from the BotiCord API"""
|
||||||
|
|
||||||
id: str
|
id: str
|
||||||
"""Bot's Id"""
|
"""Bot's Id"""
|
||||||
|
|
||||||
|
@ -340,3 +341,38 @@ class CommentResponse(ApiData):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**parse_webhook_response_dict(kwargs))
|
super().__init__(**parse_webhook_response_dict(kwargs))
|
||||||
|
|
||||||
|
|
||||||
|
class LinkDomain(IntEnum):
|
||||||
|
"""Domain to short the link"""
|
||||||
|
|
||||||
|
BCORD_CC = 1
|
||||||
|
"""``bcord.cc`` domain, default"""
|
||||||
|
|
||||||
|
MYSERVERS_ME = 2
|
||||||
|
"""``myservers.me`` domain"""
|
||||||
|
|
||||||
|
DISCORD_CAMP = 3
|
||||||
|
"""``discord.camp`` domain"""
|
||||||
|
|
||||||
|
|
||||||
|
class ShortedLink(ApiData):
|
||||||
|
id: int
|
||||||
|
"""Id of shorted link"""
|
||||||
|
|
||||||
|
code: str
|
||||||
|
"""Code of shorted link"""
|
||||||
|
|
||||||
|
owner_i_d: str
|
||||||
|
"""Id of owner of shorted link"""
|
||||||
|
|
||||||
|
domain: str
|
||||||
|
"""Domain of shorted link"""
|
||||||
|
|
||||||
|
views: int
|
||||||
|
"""Link views count"""
|
||||||
|
|
||||||
|
date: int
|
||||||
|
"""Timestamp of link creation moment"""
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**parse_response_dict(kwargs))
|
||||||
|
|
|
@ -20,6 +20,7 @@ class Webhook:
|
||||||
Keyword Arguments:
|
Keyword Arguments:
|
||||||
loop: `asyncio loop`
|
loop: `asyncio loop`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
"_webserver",
|
"_webserver",
|
||||||
"_listeners",
|
"_listeners",
|
||||||
|
@ -27,7 +28,7 @@ class Webhook:
|
||||||
"__app",
|
"__app",
|
||||||
"_endpoint_name",
|
"_endpoint_name",
|
||||||
"_x_hook_key",
|
"_x_hook_key",
|
||||||
"_loop"
|
"_loop",
|
||||||
)
|
)
|
||||||
|
|
||||||
__app: web.Application
|
__app: web.Application
|
||||||
|
@ -39,7 +40,7 @@ class Webhook:
|
||||||
self._listeners = {}
|
self._listeners = {}
|
||||||
self.__app = web.Application()
|
self.__app = web.Application()
|
||||||
self._is_running = False
|
self._is_running = False
|
||||||
self._loop = kwargs.get('loop') or asyncio.get_event_loop()
|
self._loop = kwargs.get("loop") or asyncio.get_event_loop()
|
||||||
|
|
||||||
def listener(self, response_type: str):
|
def listener(self, response_type: str):
|
||||||
"""Decorator to set the listener.
|
"""Decorator to set the listener.
|
||||||
|
@ -47,6 +48,7 @@ class Webhook:
|
||||||
response_type (:obj:`str`)
|
response_type (:obj:`str`)
|
||||||
Type of response (Check reference page)
|
Type of response (Check reference page)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def inner(func):
|
def inner(func):
|
||||||
if not asyncio.iscoroutinefunction(func):
|
if not asyncio.iscoroutinefunction(func):
|
||||||
raise TypeError(f"<{func.__qualname__}> must be a coroutine function")
|
raise TypeError(f"<{func.__qualname__}> must be a coroutine function")
|
||||||
|
@ -80,7 +82,11 @@ class Webhook:
|
||||||
|
|
||||||
if responder is not None:
|
if responder is not None:
|
||||||
await responder(
|
await responder(
|
||||||
(BumpResponse if data["type"].endswith("_bump") else CommentResponse)(**data)
|
(
|
||||||
|
BumpResponse
|
||||||
|
if data["type"].endswith("_bump")
|
||||||
|
else CommentResponse
|
||||||
|
)(**data)
|
||||||
)
|
)
|
||||||
|
|
||||||
return web.Response(status=200)
|
return web.Response(status=200)
|
||||||
|
|
Loading…
Reference in a new issue