mirror of
https://github.com/boticord/boticordpy.git
synced 2024-09-22 19:32:01 +03:00
search
This commit is contained in:
parent
e26366da74
commit
daa2e31732
6 changed files with 374 additions and 15 deletions
|
@ -2,16 +2,15 @@
|
|||
Boticord API Wrapper
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
A basic wrapper for the BotiCord API.
|
||||
:copyright: (c) 2022 Marakarka
|
||||
:copyright: (c) 2023 Marakarka
|
||||
:license: MIT, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
__title__ = "boticordpy"
|
||||
__author__ = "Marakarka"
|
||||
__license__ = "MIT"
|
||||
__copyright__ = "Copyright 2022 Marakarka"
|
||||
__version__ = "2.2.2"
|
||||
__copyright__ = "Copyright 2021 - 2023 Marakarka"
|
||||
__version__ = "3.0.0a"
|
||||
|
||||
from .client import BoticordClient
|
||||
|
||||
from .types import *
|
||||
|
|
|
@ -3,6 +3,7 @@ import typing
|
|||
from . import types as boticord_types
|
||||
from .http import HttpClient
|
||||
from .autopost import AutoPost
|
||||
from .exceptions import MeilisearchException
|
||||
|
||||
|
||||
class BoticordClient:
|
||||
|
@ -18,12 +19,13 @@ class BoticordClient:
|
|||
BotiCord API version (Default: 3)
|
||||
"""
|
||||
|
||||
__slots__ = ("http", "_autopost", "_token")
|
||||
__slots__ = ("http", "_autopost", "_token", "_meilisearch_api_key")
|
||||
|
||||
http: HttpClient
|
||||
|
||||
def __init__(self, token: str = None, version: int = 3):
|
||||
self._token = token
|
||||
self._meilisearch_api_key = None
|
||||
self._autopost: typing.Optional[AutoPost] = None
|
||||
self.http = HttpClient(token, version)
|
||||
|
||||
|
@ -104,6 +106,79 @@ class BoticordClient:
|
|||
response = await self.http.get_user_info(user_id)
|
||||
return boticord_types.UserProfile.from_dict(response)
|
||||
|
||||
async def __search_for(self, index, data):
|
||||
"""Search for smth on BotiCord"""
|
||||
if self._meilisearch_api_key is None:
|
||||
token_response = await self.http.get_search_key()
|
||||
self._meilisearch_api_key = token_response["key"]
|
||||
|
||||
try:
|
||||
response = await self.http.search_for(
|
||||
index, self._meilisearch_api_key, data
|
||||
)
|
||||
except MeilisearchException:
|
||||
token_response = await self.http.get_search_key()
|
||||
self._meilisearch_api_key = token_response["key"]
|
||||
|
||||
response = await self.http.search_for(
|
||||
index, self._meilisearch_api_key, data
|
||||
)
|
||||
|
||||
return response["hits"]
|
||||
|
||||
async def search_for_bots(
|
||||
self, **kwargs
|
||||
) -> typing.List[boticord_types.MeiliIndexedBot]:
|
||||
"""Search for bots on BotiCord.
|
||||
|
||||
Note:
|
||||
You can find every keyword argument `here <https://www.meilisearch.com/docs/reference/api/search#search-parameters>`_.
|
||||
|
||||
Returns:
|
||||
List[:obj:`~.types.MeiliIndexedBot`]:
|
||||
List of found bots
|
||||
"""
|
||||
|
||||
response = await self.__search_for("bots", kwargs)
|
||||
return [boticord_types.MeiliIndexedBot.from_dict(bot) for bot in response]
|
||||
|
||||
async def search_for_servers(
|
||||
self, **kwargs
|
||||
) -> typing.List[boticord_types.MeiliIndexedServer]:
|
||||
"""Search for servers on BotiCord.
|
||||
|
||||
Note:
|
||||
You can find every keyword argument `here <https://www.meilisearch.com/docs/reference/api/search#search-parameters>`_.
|
||||
|
||||
Returns:
|
||||
List[:obj:`~.types.MeiliIndexedServer`]:
|
||||
List of found servers
|
||||
"""
|
||||
|
||||
response = await self.__search_for("servers", kwargs)
|
||||
return [
|
||||
boticord_types.MeiliIndexedServer.from_dict(server) for server in response
|
||||
]
|
||||
|
||||
async def search_for_comments(
|
||||
self, **kwargs
|
||||
) -> typing.List[boticord_types.MeiliIndexedComment]:
|
||||
"""Search for comments on BotiCord.
|
||||
|
||||
Note:
|
||||
You can find every keyword argument `here <https://www.meilisearch.com/docs/reference/api/search#search-parameters>`_.
|
||||
|
||||
Returns:
|
||||
List[:obj:`~.types.MeiliIndexedComment`]:
|
||||
List of found comments
|
||||
"""
|
||||
|
||||
response = await self.__search_for("comments", kwargs)
|
||||
return [
|
||||
boticord_types.MeiliIndexedComment.from_dict(comment)
|
||||
for comment in response
|
||||
]
|
||||
|
||||
def autopost(self) -> AutoPost:
|
||||
"""Returns a helper instance for auto-posting.
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class InternalException(BoticordException):
|
|||
|
||||
|
||||
class HTTPException(BoticordException):
|
||||
"""Exception that's thrown when an HTTP request operation fails.
|
||||
"""Exception that's thrown when request to BotiCord API operation fails.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
@ -37,6 +37,23 @@ class HTTPException(BoticordException):
|
|||
super().__init__(fmt)
|
||||
|
||||
|
||||
class MeilisearchException(BoticordException):
|
||||
"""Exception that's thrown when request to Meilisearch API operation fails.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
response:
|
||||
The response of the failed HTTP request.
|
||||
"""
|
||||
|
||||
def __init__(self, response):
|
||||
self.response = response
|
||||
|
||||
fmt = f"{self.response['code']} ({self.response['message']})"
|
||||
|
||||
super().__init__(fmt)
|
||||
|
||||
|
||||
class StatusCodes(IntEnum):
|
||||
"""Status codes of response"""
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from urllib.parse import urlparse
|
||||
import asyncio
|
||||
import typing
|
||||
|
||||
import aiohttp
|
||||
|
||||
from . import exceptions
|
||||
from .types import LinkDomain
|
||||
|
||||
|
||||
class HttpClient:
|
||||
|
@ -29,13 +29,17 @@ class HttpClient:
|
|||
|
||||
self.session = kwargs.get("session") or aiohttp.ClientSession(loop=loop)
|
||||
|
||||
async def make_request(self, method: str, endpoint: str, **kwargs) -> dict:
|
||||
async def make_request(
|
||||
self, method: str, endpoint: str, *, meilisearch_token: str = None, **kwargs
|
||||
) -> dict:
|
||||
"""Send requests to the API"""
|
||||
|
||||
kwargs["headers"] = {"Content-Type": "application/json"}
|
||||
|
||||
if self.token is not None:
|
||||
kwargs["headers"]["Authorization"] = self.token
|
||||
if meilisearch_token is not None:
|
||||
kwargs["headers"]["Authorization"] = f"Bearer {meilisearch_token}"
|
||||
|
||||
url = f"{self.API_URL}{endpoint}"
|
||||
|
||||
|
@ -43,11 +47,14 @@ class HttpClient:
|
|||
data = await response.json()
|
||||
|
||||
if (200, 201).__contains__(response.status):
|
||||
return data["result"]
|
||||
return data["result"] if not meilisearch_token else data
|
||||
else:
|
||||
raise exceptions.HTTPException(
|
||||
{"status": response.status, "error": data["errors"][0]["code"]}
|
||||
)
|
||||
if not meilisearch_token:
|
||||
raise exceptions.HTTPException(
|
||||
{"status": response.status, "error": data["errors"][0]["code"]}
|
||||
)
|
||||
else:
|
||||
raise exceptions.MeilisearchException(data)
|
||||
|
||||
def get_bot_info(self, bot_id: typing.Union[str, int]):
|
||||
"""Get information about the specified bot"""
|
||||
|
@ -64,3 +71,16 @@ class HttpClient:
|
|||
def get_user_info(self, user_id: typing.Union[str, int]):
|
||||
"""Get information about specified user"""
|
||||
return self.make_request("GET", f"users/{user_id}")
|
||||
|
||||
def get_search_key(self):
|
||||
"""Get API key for Meilisearch"""
|
||||
return self.make_request("GET", f"search-key")
|
||||
|
||||
def search_for(self, index: str, api_key: str, data: dict):
|
||||
"""Search for something on BotiCord."""
|
||||
return self.make_request(
|
||||
"POST",
|
||||
f"search/indexes/{index}/search",
|
||||
meilisearch_token=api_key,
|
||||
json=data,
|
||||
)
|
||||
|
|
|
@ -559,7 +559,12 @@ class PartialUser(APIObjectBase):
|
|||
|
||||
@dataclass(repr=False)
|
||||
class ResourceServer(APIObjectBase):
|
||||
"""Information about server from BotiCord."""
|
||||
"""Information about server from BotiCord.
|
||||
|
||||
.. warning::
|
||||
|
||||
The result of the reverse conversion (`.to_dict()`) may not match the actual data.
|
||||
"""
|
||||
|
||||
id: str
|
||||
"""Server's ID"""
|
||||
|
@ -700,6 +705,9 @@ class ResourceBot(APIObjectBase):
|
|||
short_link: Optional[str]
|
||||
"""Short link to the bot's page"""
|
||||
|
||||
standart_banner_id: int
|
||||
"""Server's standart banner ID"""
|
||||
|
||||
invite_link: str
|
||||
"""Invite link"""
|
||||
|
||||
|
@ -788,6 +796,7 @@ class ResourceBot(APIObjectBase):
|
|||
self.support_server_invite_link = data.get("support_server_invite")
|
||||
self.website = data.get("website")
|
||||
self.up_count = data.get("upCount")
|
||||
self.standart_banner_id = data.get("standartBannerID")
|
||||
|
||||
self.premium_active = data["premium"].get("active")
|
||||
self.premium_splash_url = data["premium"].get("splashURL")
|
||||
|
@ -850,5 +859,231 @@ class UserProfile(PartialUser):
|
|||
return self
|
||||
|
||||
|
||||
class LinkDomain:
|
||||
pass
|
||||
@dataclass(repr=False)
|
||||
class MeiliIndexedBot(APIObjectBase):
|
||||
"""Bot found on BotiCord
|
||||
|
||||
.. warning::
|
||||
|
||||
The result of the reverse conversion (`.to_dict()`) may not match the actual data.
|
||||
"""
|
||||
|
||||
id: str
|
||||
"""ID of the bot"""
|
||||
|
||||
name: str
|
||||
"""Name of the bot"""
|
||||
|
||||
short_description: str
|
||||
"""Short description of the bot"""
|
||||
|
||||
description: str
|
||||
"""Description of the bot"""
|
||||
|
||||
avatar: Optional[str]
|
||||
"""Avatar of the bot"""
|
||||
|
||||
invite: str
|
||||
"""Invite link"""
|
||||
|
||||
premium_active: bool
|
||||
"""Is premium status active? (True/False)"""
|
||||
|
||||
premium_banner: Optional[str]
|
||||
"""Premium banner URL"""
|
||||
|
||||
banner: int
|
||||
"""Standart banner"""
|
||||
|
||||
rating: int
|
||||
"""Bot's rating"""
|
||||
|
||||
discriminator: str
|
||||
"""Bot's discriminator"""
|
||||
|
||||
library: Optional[BotLibrary]
|
||||
"""The library that the bot is based on"""
|
||||
|
||||
guilds: Optional[int]
|
||||
"""Number of guilds"""
|
||||
|
||||
shards: Optional[int]
|
||||
"""Number of shards"""
|
||||
|
||||
members: Optional[int]
|
||||
"""Number of members"""
|
||||
|
||||
tags: List[BotTag]
|
||||
"""List of bot tags"""
|
||||
|
||||
ups: int
|
||||
"""List of bot's ups"""
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict):
|
||||
"""Generate a MeiliIndexedBot from the given data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data: :class:`dict`
|
||||
The dictionary to convert into a MeiliIndexedBot.
|
||||
"""
|
||||
|
||||
self: MeiliIndexedBot = super().__new__(cls)
|
||||
|
||||
self.id = data.get("id")
|
||||
self.name = data.get("name")
|
||||
self.short_description = data.get("shortDescription")
|
||||
self.description = data.get("description")
|
||||
self.avatar = data.get("avatar")
|
||||
self.invite = data.get("invite")
|
||||
self.discriminator = data.get("discriminator")
|
||||
self.ups = data.get("ups")
|
||||
self.rating = data.get("rating")
|
||||
self.banner = data.get("banner")
|
||||
|
||||
self.premium_active = data.get("premiumActive")
|
||||
self.premium_banner = data.get("premiumBanner")
|
||||
|
||||
self.library = (
|
||||
BotLibrary(data["library"]) if data.get("library") is not None else None
|
||||
)
|
||||
self.tags = [BotTag(tag) for tag in data.get("tags", [])]
|
||||
|
||||
self.guilds = data.get("guilds")
|
||||
self.shards = data.get("shards")
|
||||
self.members = data.get("members")
|
||||
|
||||
return self
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class MeiliIndexedServer(APIObjectBase):
|
||||
"""Server found on BotiCord
|
||||
|
||||
.. warning::
|
||||
|
||||
The result of the reverse conversion (`.to_dict()`) may not match the actual data.
|
||||
"""
|
||||
|
||||
id: str
|
||||
"""ID of the server"""
|
||||
|
||||
name: str
|
||||
"""Name of the server"""
|
||||
|
||||
short_description: str
|
||||
"""Short description of the server"""
|
||||
|
||||
description: str
|
||||
"""Description of the server"""
|
||||
|
||||
avatar: Optional[str]
|
||||
"""Avatar of the server"""
|
||||
|
||||
invite: str
|
||||
"""Invite link"""
|
||||
|
||||
premium_active: bool
|
||||
"""Is premium status active? (True/False)"""
|
||||
|
||||
premium_banner: Optional[str]
|
||||
"""Premium banner URL"""
|
||||
|
||||
banner: int
|
||||
"""Standart banner"""
|
||||
|
||||
discord_banner: Optional[str]
|
||||
"""Discord banner URL"""
|
||||
|
||||
rating: int
|
||||
"""Server's rating"""
|
||||
|
||||
members: Optional[int]
|
||||
"""Number of members"""
|
||||
|
||||
tags: List[ServerTag]
|
||||
"""List of server tags"""
|
||||
|
||||
ups: int
|
||||
"""List of server's ups"""
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict):
|
||||
"""Generate a MeiliIndexedServer from the given data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data: :class:`dict`
|
||||
The dictionary to convert into a MeiliIndexedServer.
|
||||
"""
|
||||
|
||||
self: MeiliIndexedServer = super().__new__(cls)
|
||||
|
||||
self.id = data.get("id")
|
||||
self.name = data.get("name")
|
||||
self.short_description = data.get("shortDescription")
|
||||
self.description = data.get("description")
|
||||
self.avatar = data.get("avatar")
|
||||
self.invite = data.get("invite")
|
||||
self.ups = data.get("ups")
|
||||
self.rating = data.get("rating")
|
||||
self.banner = data.get("banner")
|
||||
|
||||
self.premium_active = data.get("premiumActive")
|
||||
self.premium_banner = data.get("premiumBanner")
|
||||
self.discord_banner = data.get("discordBanner")
|
||||
|
||||
self.tags = [ServerTag(tag) for tag in data.get("tags", [])]
|
||||
|
||||
self.members = data.get("members")
|
||||
|
||||
return self
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class MeiliIndexedComment(APIObjectBase):
|
||||
"""Comment found on BotiCord"""
|
||||
|
||||
id: str
|
||||
"""ID of the comment"""
|
||||
|
||||
author: str
|
||||
"""Id of the author of the comment"""
|
||||
|
||||
rating: int
|
||||
"""Comment's rating"""
|
||||
|
||||
content: str
|
||||
"""Content of the comment"""
|
||||
|
||||
resource: str
|
||||
"""Id of the resource"""
|
||||
|
||||
created: datetime
|
||||
"""When the comment was created"""
|
||||
|
||||
mod_reply: Optional[str]
|
||||
"""Reply to the comment"""
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict):
|
||||
"""Generate a MeiliIndexedComment from the given data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data: :class:`dict`
|
||||
The dictionary to convert into a MeiliIndexedComment.
|
||||
"""
|
||||
|
||||
self: MeiliIndexedComment = super().__new__(cls)
|
||||
|
||||
self.id = data.get("id")
|
||||
self.rating = data.get("rating")
|
||||
self.author = data.get("author")
|
||||
self.content = data.get("content")
|
||||
self.resource = data.get("resource")
|
||||
self.mod_reply = data.get("modReply")
|
||||
self.created = datetime.utcfromtimestamp(data.get("created") / 1000)
|
||||
|
||||
return self
|
||||
|
|
|
@ -56,3 +56,16 @@ Users
|
|||
:members:
|
||||
:exclude-members: to_dict
|
||||
:inherited-members:
|
||||
|
||||
|
||||
MeiliSearch
|
||||
------------
|
||||
|
||||
.. autoclass:: MeiliIndexedBot
|
||||
:members:
|
||||
|
||||
.. autoclass:: MeiliIndexedServer
|
||||
:members:
|
||||
|
||||
.. autoclass:: MeiliIndexedComment
|
||||
:members:
|
||||
|
|
Loading…
Reference in a new issue