diff options
| -rw-r--r-- | bot/__main__.py | 8 | ||||
| -rw-r--r-- | bot/api.py | 40 | ||||
| -rw-r--r-- | bot/cogs/doc.py | 153 | ||||
| -rw-r--r-- | bot/cogs/events.py | 16 | ||||
| -rw-r--r-- | bot/cogs/off_topic_names.py | 72 | ||||
| -rw-r--r-- | bot/cogs/sync.py | 86 | ||||
| -rw-r--r-- | bot/cogs/tags.py | 249 |
7 files changed, 242 insertions, 382 deletions
diff --git a/bot/__main__.py b/bot/__main__.py index 3c40a3243..c598fd921 100644 --- a/bot/__main__.py +++ b/bot/__main__.py @@ -1,3 +1,4 @@ +import asyncio import logging import socket @@ -5,6 +6,7 @@ from aiohttp import AsyncResolver, ClientSession, TCPConnector from discord import Game from discord.ext.commands import Bot, when_mentioned_or +from bot.api import APIClient from bot.constants import Bot as BotConfig, DEBUG_MODE from bot.utils.service_discovery import wait_for_rmq @@ -27,6 +29,7 @@ bot.http_session = ClientSession( family=socket.AF_INET, ) ) +bot.api_client = APIClient(loop=asyncio.get_event_loop()) log.info("Waiting for RabbitMQ...") has_rmq = wait_for_rmq() @@ -57,9 +60,13 @@ if not DEBUG_MODE: bot.load_extension("bot.cogs.verification") # Feature cogs +<<<<<<< HEAD +======= bot.load_extension("bot.cogs.alias") bot.load_extension("bot.cogs.deployment") +>>>>>>> master bot.load_extension("bot.cogs.defcon") +bot.load_extension("bot.cogs.deployment") bot.load_extension("bot.cogs.eval") bot.load_extension("bot.cogs.fun") bot.load_extension("bot.cogs.superstarify") @@ -71,6 +78,7 @@ bot.load_extension("bot.cogs.reminders") bot.load_extension("bot.cogs.site") bot.load_extension("bot.cogs.snakes") bot.load_extension("bot.cogs.snekbox") +bot.load_extension("bot.cogs.sync") bot.load_extension("bot.cogs.tags") bot.load_extension("bot.cogs.token_remover") bot.load_extension("bot.cogs.utils") diff --git a/bot/api.py b/bot/api.py new file mode 100644 index 000000000..f8757d3d0 --- /dev/null +++ b/bot/api.py @@ -0,0 +1,40 @@ +from urllib.parse import quote as quote_url + +import aiohttp + +from .constants import Keys, URLs + + +class APIClient: + def __init__(self, **kwargs): + auth_headers = { + 'Authorization': f"Token {Keys.site_api}" + } + + if 'headers' in kwargs: + kwargs['headers'].update(auth_headers) + else: + kwargs['headers'] = auth_headers + + self.session = aiohttp.ClientSession( + **kwargs, + raise_for_status=True + ) + + @staticmethod + def _url_for(endpoint: str): + return f"{URLs.site_schema}{URLs.site_api}/{quote_url(endpoint)}" + + async def get(self, endpoint: str, *args, **kwargs): + async with self.session.get(self._url_for(endpoint), *args, **kwargs) as resp: + return await resp.json() + + async def post(self, endpoint: str, *args, **kwargs): + async with self.session.post(self._url_for(endpoint), *args, **kwargs) as resp: + return await resp.json() + + async def delete(self, endpoint: str, *args, **kwargs): + async with self.session.delete(self._url_for(endpoint), *args, **kwargs) as resp: + if resp.status == 204: + return None + return await resp.json() diff --git a/bot/cogs/doc.py b/bot/cogs/doc.py index 2b310f11c..860ec7f62 100644 --- a/bot/cogs/doc.py +++ b/bot/cogs/doc.py @@ -1,11 +1,10 @@ import asyncio import functools import logging -import random import re import textwrap from collections import OrderedDict -from typing import Dict, List, Optional, Tuple +from typing import Optional, Tuple import discord from bs4 import BeautifulSoup @@ -14,7 +13,7 @@ from markdownify import MarkdownConverter from requests import ConnectionError from sphinx.ext import intersphinx -from bot.constants import ERROR_REPLIES, Keys, Roles, URLs +from bot.constants import Keys, Roles from bot.converters import ValidPythonIdentifier, ValidURL from bot.decorators import with_role from bot.pagination import LinePaginator @@ -126,7 +125,6 @@ class Doc: self.base_urls = {} self.bot = bot self.inventories = {} - self.headers = {"X-API-KEY": Keys.site_api} async def on_ready(self): await self.refresh_inventory() @@ -179,7 +177,7 @@ class Doc: coros = [ self.update_single( package["package"], package["base_url"], package["inventory_url"], config - ) for package in await self.get_all_packages() + ) for package in await self.bot.api_client.get('bot/documentation-links') ] await asyncio.gather(*coros) @@ -267,95 +265,6 @@ class Doc: description=f"```py\n{signature}```{description}" ) - async def get_all_packages(self) -> List[Dict[str, str]]: - """ - Performs HTTP GET to get all packages from the website. - - :return: - A list of packages, in the following format: - [ - { - "package": "example-package", - "base_url": "https://example.readthedocs.io", - "inventory_url": "https://example.readthedocs.io/objects.inv" - }, - ... - ] - `package` specifies the package name, for example 'aiohttp'. - `base_url` specifies the documentation root URL, used to build absolute links. - `inventory_url` specifies the location of the Intersphinx inventory. - """ - - async with self.bot.http_session.get(URLs.site_docs_api, headers=self.headers) as resp: - return await resp.json() - - async def get_package(self, package_name: str) -> Optional[Dict[str, str]]: - """ - Performs HTTP GET to get the specified package from the documentation database. - - :param package_name: The package name for which information should be returned. - :return: - Either a dictionary with information in the following format: - { - "package": "example-package", - "base_url": "https://example.readthedocs.io", - "inventory_url": "https://example.readthedocs.io/objects.inv" - } - or `None` if the site didn't returned no results for the given name. - """ - - params = {"package": package_name} - - async with self.bot.http_session.get(URLs.site_docs_api, - headers=self.headers, - params=params) as resp: - package_data = await resp.json() - if not package_data: - return None - return package_data[0] - - async def set_package(self, name: str, base_url: str, inventory_url: str) -> Dict[str, bool]: - """ - Performs HTTP POST to add a new package to the website's documentation database. - - :param name: The name of the package, for example `aiohttp`. - :param base_url: The documentation root URL, used to build absolute links. - :param inventory_url: The absolute URl to the intersphinx inventory of the package. - - :return: The JSON response of the server, which is always: - { - "success": True - } - """ - - package_json = { - 'package': name, - 'base_url': base_url, - 'inventory_url': inventory_url - } - - async with self.bot.http_session.post(URLs.site_docs_api, - headers=self.headers, - json=package_json) as resp: - return await resp.json() - - async def delete_package(self, name: str) -> bool: - """ - Performs HTTP DELETE to delete the specified package from the documentation database. - - :param name: The package to delete. - - :return: `True` if successful, `False` if the package is unknown. - """ - - package_json = {'package': name} - - async with self.bot.http_session.delete(URLs.site_docs_api, - headers=self.headers, - json=package_json) as resp: - changes = await resp.json() - return changes["deleted"] == 1 # Did the package delete successfully? - @commands.group(name='docs', aliases=('doc', 'd'), invoke_without_command=True) async def docs_group(self, ctx, symbol: commands.clean_content = None): """Lookup documentation for Python symbols.""" @@ -386,7 +295,12 @@ class Doc: ) lines = sorted(f"• [`{name}`]({url})" for name, url in self.base_urls.items()) - await LinePaginator.paginate(lines, ctx, inventory_embed, max_size=400, empty=False) + if self.base_urls: + await LinePaginator.paginate(lines, ctx, inventory_embed, max_size=400, empty=False) + + else: + inventory_embed.description = "Hmmm, seems like there's nothing here yet." + await ctx.send(embed=inventory_embed) else: # Fetching documentation for a symbol (at least for the first time, since @@ -427,7 +341,13 @@ class Doc: https://discordpy.readthedocs.io/en/rewrite/objects.inv """ - await self.set_package(package_name, base_url, inventory_url) + body = { + 'package': package_name, + 'base_url': base_url, + 'inventory_url': inventory_url + } + await self.bot.api_client.post('bot/documentation-links', json=body) + log.info( f"User @{ctx.author.name}#{ctx.author.discriminator} ({ctx.author.id}) " "added a new documentation package:\n" @@ -455,42 +375,13 @@ class Doc: !docs delete aiohttp """ - success = await self.delete_package(package_name) - if success: + await self.bot.api_client.delete(f'bot/documentation-links/{package_name}') - async with ctx.typing(): - # Rebuild the inventory to ensure that everything - # that was from this package is properly deleted. - await self.refresh_inventory() - await ctx.send(f"Successfully deleted `{package_name}` and refreshed inventory.") - - else: - await ctx.send( - f"Can't find any package named `{package_name}` in the database. " - "View all known packages by using `docs.get()`." - ) - - @get_command.error - @delete_command.error - @set_command.error - async def general_command_error(self, ctx, error: commands.CommandError): - """ - Handle the `BadArgument` error caused by - the commands when argument validation fails. - - :param ctx: Discord message context of the message creating the error - :param error: The error raised, usually `BadArgument` - """ - - if isinstance(error, commands.BadArgument): - embed = discord.Embed( - title=random.choice(ERROR_REPLIES), - description=f"Error: {error}", - colour=discord.Colour.red() - ) - await ctx.send(embed=embed) - else: - log.exception(f"Unhandled error: {error}") + async with ctx.typing(): + # Rebuild the inventory to ensure that everything + # that was from this package is properly deleted. + await self.refresh_inventory() + await ctx.send(f"Successfully deleted `{package_name}` and refreshed inventory.") def setup(bot): diff --git a/bot/cogs/events.py b/bot/cogs/events.py index edfc6e579..160791fb0 100644 --- a/bot/cogs/events.py +++ b/bot/cogs/events.py @@ -1,5 +1,6 @@ import logging +from aiohttp import ClientResponseError from discord import Colour, Embed, Member, Object from discord.ext.commands import ( BadArgument, Bot, BotMissingPermissions, @@ -140,10 +141,17 @@ class Events: f"Here's what I'm missing: **{e.missing_perms}**" ) elif isinstance(e, CommandInvokeError): - await ctx.send( - f"Sorry, an unexpected error occurred. Please let us know!\n\n```{e}```" - ) - raise e.original + if isinstance(e.original, ClientResponseError): + if e.original.code == 404: + await ctx.send("There does not seem to be anything matching your query.") + else: + await ctx.send("BEEP BEEP UNKNOWN API ERROR!=?!??!?!?!?") + + else: + await ctx.send( + f"Sorry, an unexpected error occurred. Please let us know!\n\n```{e}```" + ) + raise e.original raise e async def on_ready(self): diff --git a/bot/cogs/off_topic_names.py b/bot/cogs/off_topic_names.py index 25b8a48b8..b22926664 100644 --- a/bot/cogs/off_topic_names.py +++ b/bot/cogs/off_topic_names.py @@ -5,7 +5,7 @@ from datetime import datetime, timedelta from discord import Colour, Embed from discord.ext.commands import BadArgument, Bot, Context, Converter, group -from bot.constants import Channels, Keys, Roles, URLs +from bot.constants import Channels, Keys, Roles from bot.decorators import with_role from bot.pagination import LinePaginator @@ -44,7 +44,7 @@ async def update_names(bot: Bot, headers: dict): Args: bot (Bot): The running bot instance, used for fetching data from the - website via the bot's `http_session`. + website via the bot's `api_client`. """ while True: @@ -53,11 +53,9 @@ async def update_names(bot: Bot, headers: dict): seconds_to_sleep = (next_midnight - datetime.utcnow()).seconds await asyncio.sleep(seconds_to_sleep) - response = await bot.http_session.get( - f'{URLs.site_off_topic_names_api}?random_items=3', - headers=headers + channel_0_name, channel_1_name, channel_2_name = await bot.api_client.get( + 'bot/off-topic-channel-names', params={'random_items': 3} ) - channel_0_name, channel_1_name, channel_2_name = await response.json() channel_0, channel_1, channel_2 = (bot.get_channel(channel_id) for channel_id in CHANNELS) await channel_0.edit(name=f'ot0-{channel_0_name}') @@ -98,49 +96,24 @@ class OffTopicNames: async def add_command(self, ctx, name: OffTopicName): """Adds a new off-topic name to the rotation.""" - result = await self.bot.http_session.post( - URLs.site_off_topic_names_api, - headers=self.headers, - params={'name': name} + await self.bot.api_client.post(f'bot/off-topic-channel-names', params={'name': name}) + log.info( + f"{ctx.author.name}#{ctx.author.discriminator}" + f" added the off-topic channel name '{name}" ) - - response = await result.json() - - if result.status == 200: - log.info( - f"{ctx.author.name}#{ctx.author.discriminator}" - f" added the off-topic channel name '{name}" - ) - await ctx.send(":ok_hand:") - else: - error_reason = response.get('message', "No reason provided.") - await ctx.send(f":warning: got non-200 from the API: {error_reason}") + await ctx.send(":ok_hand:") @otname_group.command(name='delete', aliases=('remove', 'rm', 'del', 'd')) @with_role(Roles.owner, Roles.admin, Roles.moderator) async def delete_command(self, ctx, name: OffTopicName): """Removes a off-topic name from the rotation.""" - result = await self.bot.http_session.delete( - URLs.site_off_topic_names_api, - headers=self.headers, - params={'name': name} + await self.bot.api_client.delete(f'bot/off-topic-channel-names/{name}') + log.info( + f"{ctx.author.name}#{ctx.author.discriminator}" + f" deleted the off-topic channel name '{name}" ) - - response = await result.json() - - if result.status == 200: - if response['deleted'] == 0: - await ctx.send(f":warning: No name matching `{name}` was found in the database.") - else: - log.info( - f"{ctx.author.name}#{ctx.author.discriminator}" - f" deleted the off-topic channel name '{name}" - ) - await ctx.send(":ok_hand:") - else: - error_reason = response.get('message', "No reason provided.") - await ctx.send(f":warning: got non-200 from the API: {error_reason}") + await ctx.send(":ok_hand:") @otname_group.command(name='list', aliases=('l',)) @with_role(Roles.owner, Roles.admin, Roles.moderator) @@ -150,18 +123,17 @@ class OffTopicNames: Restricted to Moderator and above to not spoil the surprise. """ - result = await self.bot.http_session.get( - URLs.site_off_topic_names_api, - headers=self.headers - ) - response = await result.json() - lines = sorted(f"• {name}" for name in response) - + result = await self.bot.api_client.get('bot/off-topic-channel-names') + lines = sorted(f"• {name}" for name in result) embed = Embed( - title=f"Known off-topic names (`{len(response)}` total)", + title=f"Known off-topic names (`{len(result)}` total)", colour=Colour.blue() ) - await LinePaginator.paginate(lines, ctx, embed, max_size=400, empty=False) + if result: + await LinePaginator.paginate(lines, ctx, embed, max_size=400, empty=False) + else: + embed.description = "Hmmm, seems like there's nothing here yet." + await ctx.send(embed=embed) def setup(bot: Bot): diff --git a/bot/cogs/sync.py b/bot/cogs/sync.py new file mode 100644 index 000000000..cccaa7d28 --- /dev/null +++ b/bot/cogs/sync.py @@ -0,0 +1,86 @@ +import logging +from collections import namedtuple +from typing import Callable, Iterable + +from discord import Guild, Role +from discord.ext.commands import Bot + + +log = logging.getLogger(__name__) +Role = namedtuple('Role', ('id', 'name', 'colour', 'permissions')) + + +async def sync_roles(bot: Bot, guild: Guild): + """ + Synchronize roles found on the given `guild` with the ones on the API. + """ + + def convert_role(role: Role): + return { + 'id': role.id, + 'name': role.name, + 'colour': role.colour, + 'permissions': role.permissions + } + + roles = await bot.api_client.get('bot/roles') + site_roles = { + Role(**role_dict) + for role_dict in roles + } + server_roles = { + Role( + id=role.id, name=role.name, + colour=role.colour.value, permissions=role.permissions.value + ) + for role in guild.roles + } + roles_to_update = server_roles - site_roles + + for role in roles_to_update: + log.info(f"Updating role `{role.name}` on the site.") + await bot.api_client.post( + 'bot/roles', + json={ + 'id': role.id, + 'name': role.name, + 'colour': role.colour, + 'permissions': role.permissions + } + ) + + +async def sync_members(bot: Bot, guild: Guild): + """ + Synchronize members found on the given `guild` with the ones on the API. + """ + + current_members = await bot.api_client.get('bot/members') + + +class Sync: + """Captures relevant events and sends them to the site.""" + + # The server to synchronize events on. + # Note that setting this wrongly will result in things getting deleted + # that possibly shouldn't be. + SYNC_SERVER_ID = 267624335836053506 + + # An iterable of callables that are called when the bot is ready. + ON_READY_SYNCERS: Iterable[Callable[[Bot, Guild], None]] = ( + sync_roles, + ) + + def __init__(self, bot): + self.bot = bot + + async def on_ready(self): + guild = self.bot.get_guild(self.SYNC_SERVER_ID) + if guild is not None: + for syncer in self.ON_READY_SYNCERS: + await syncer(self.bot, guild) + + +def setup(bot): + bot.add_cog(Sync(bot)) + log.info("Cog loaded: Sync") diff --git a/bot/cogs/tags.py b/bot/cogs/tags.py index b128b6de1..5a0198db8 100644 --- a/bot/cogs/tags.py +++ b/bot/cogs/tags.py @@ -1,7 +1,5 @@ import logging -import random import time -from typing import Optional from discord import Colour, Embed from discord.ext.commands import ( @@ -9,9 +7,7 @@ from discord.ext.commands import ( Context, group ) -from bot.constants import ( - Channels, Cooldowns, ERROR_REPLIES, Keys, Roles, URLs -) +from bot.constants import Channels, Cooldowns, Keys, Roles from bot.converters import TagContentConverter, TagNameConverter, ValidURL from bot.decorators import with_role from bot.pagination import LinePaginator @@ -34,72 +30,7 @@ class Tags: def __init__(self, bot: Bot): self.bot = bot self.tag_cooldowns = {} - self.headers = {"X-API-KEY": Keys.site_api} - - async def get_tag_data(self, tag_name=None) -> dict: - """ - Retrieve the tag_data from our API - - :param tag_name: the tag to retrieve - :return: - if tag_name was provided, returns a dict with tag data. - if not, returns a list of dicts with all tag data. - - """ - params = {} - - if tag_name: - params["tag_name"] = tag_name - - response = await self.bot.http_session.get(URLs.site_tags_api, headers=self.headers, params=params) - tag_data = await response.json() - - return tag_data - - async def post_tag_data(self, tag_name: str, tag_content: str, image_url: Optional[str]) -> dict: - """ - Send some tag_data to our API to have it saved in the database. - - :param tag_name: The name of the tag to create or edit. - :param tag_content: The content of the tag. - :param image_url: The image URL of the tag, can be `None`. - :return: json response from the API in the following format: - { - 'success': bool - } - """ - - params = { - 'tag_name': tag_name, - 'tag_content': tag_content, - 'image_url': image_url - } - - response = await self.bot.http_session.post(URLs.site_tags_api, headers=self.headers, json=params) - tag_data = await response.json() - - return tag_data - - async def delete_tag_data(self, tag_name: str) -> dict: - """ - Delete a tag using our API. - - :param tag_name: The name of the tag to delete. - :return: json response from the API in the following format: - { - 'success': bool - } - """ - - params = {} - - if tag_name: - params['tag_name'] = tag_name - - response = await self.bot.http_session.delete(URLs.site_tags_api, headers=self.headers, json=params) - tag_data = await response.json() - - return tag_data + self.headers = {"Authorization": f"Token {Keys.site_api}"} @group(name='tags', aliases=('tag', 't'), hidden=True, invoke_without_command=True) async def tags_group(self, ctx: Context, *, tag_name: TagNameConverter = None): @@ -147,69 +78,32 @@ class Tags: f"Cooldown ends in {time_left:.1f} seconds.") return - tags = [] - - embed = Embed() - embed.colour = Colour.red() - tag_data = await self.get_tag_data(tag_name) - - # If we found something, prepare that data - if tag_data: - embed.colour = Colour.blurple() - - if tag_name: - log.debug(f"{ctx.author} requested the tag '{tag_name}'") - embed.title = tag_name - - if ctx.channel.id not in TEST_CHANNELS: - self.tag_cooldowns[tag_name] = { - "time": time.time(), - "channel": ctx.channel.id - } - - else: - embed.title = "**Current tags**" - - if isinstance(tag_data, list): - log.debug(f"{ctx.author} requested a list of all tags") - tags = [f"**»** {tag['tag_name']}" for tag in tag_data] - tags = sorted(tags) - - else: - embed.description = tag_data['tag_content'] - if tag_data['image_url'] is not None: - embed.set_image(url=tag_data['image_url']) + if tag_name is not None: + tag = await self.bot.api_client.get(f'bot/tags/{tag_name}') + if ctx.channel.id not in TEST_CHANNELS: + self.tag_cooldowns[tag_name] = { + "time": time.time(), + "channel": ctx.channel.id + } + await ctx.send(embed=Embed.from_data(tag['embed'])) - # If its invoked from error handler just ignore it. - elif hasattr(ctx, "invoked_from_error_handler"): - return - # If not, prepare an error message. else: - embed.colour = Colour.red() - - if isinstance(tag_data, dict): - log.warning(f"{ctx.author} requested the tag '{tag_name}', but it could not be found.") - embed.description = f"**{tag_name}** is an unknown tag name. Please check the spelling and try again." + tags = await self.bot.api_client.get('bot/tags') + if not tags: + await ctx.send(embed=Embed( + description="**There are no tags in the database!**", + colour=Colour.red() + )) else: - log.warning(f"{ctx.author} requested a list of all tags, but the tags database was empty!") - embed.description = "**There are no tags in the database!**" - - if tag_name: - embed.set_footer(text="To show a list of all tags, use !tags.") - embed.title = "Tag not found." - - # Paginate if this is a list of all tags - if tags: - log.debug(f"Returning a paginated list of all tags.") - return await LinePaginator.paginate( - (lines for lines in tags), - ctx, embed, - footer_text="To show a tag, type !tags <tagname>.", - empty=False, - max_lines=15 - ) - - return await ctx.send(embed=embed) + embed = Embed(title="**Current tags**") + await LinePaginator.paginate( + sorted(f"**»** {tag['title']}" for tag in tags), + ctx, + embed, + footer_text="To show a tag, type !tags <tagname>.", + empty=False, + max_lines=15 + ) @tags_group.command(name='set', aliases=('add', 'edit', 's')) @with_role(Roles.admin, Roles.owner, Roles.moderator) @@ -217,44 +111,36 @@ class Tags: self, ctx: Context, tag_name: TagNameConverter, + *, tag_content: TagContentConverter, - image_url: ValidURL = None ): """ - Create a new tag or edit an existing one. + Create a new tag or update an existing one. :param ctx: discord message context :param tag_name: The name of the tag to create or edit. :param tag_content: The content of the tag. - :param image_url: An optional image for the tag. """ - tag_name = tag_name.lower().strip() - tag_content = tag_content.strip() - - embed = Embed() - embed.colour = Colour.red() - tag_data = await self.post_tag_data(tag_name, tag_content, image_url) - - if tag_data.get("success"): - log.debug(f"{ctx.author} successfully added the following tag to our database: \n" - f"tag_name: {tag_name}\n" - f"tag_content: '{tag_content}'\n" - f"image_url: '{image_url}'") - embed.colour = Colour.blurple() - embed.title = "Tag successfully added" - embed.description = f"**{tag_name}** added to tag database." - else: - log.error("There was an unexpected database error when trying to add the following tag: \n" - f"tag_name: {tag_name}\n" - f"tag_content: '{tag_content}'\n" - f"image_url: '{image_url}'\n" - f"response: {tag_data}") - embed.title = "Database error" - embed.description = ("There was a problem adding the data to the tags database. " - "Please try again. If the problem persists, see the error logs.") + body = { + 'title': tag_name.lower().strip(), + 'embed': { + 'title': tag_name, + 'description': tag_content + } + } - return await ctx.send(embed=embed) + await self.bot.api_client.post('bot/tags', json=body) + + log.debug(f"{ctx.author} successfully added the following tag to our database: \n" + f"tag_name: {tag_name}\n" + f"tag_content: '{tag_content}'\n") + + await ctx.send(embed=Embed( + title="Tag successfully added", + description=f"**{tag_name}** added to tag database.", + colour=Colour.blurple() + )) @tags_group.command(name='delete', aliases=('remove', 'rm', 'd')) @with_role(Roles.admin, Roles.owner) @@ -266,45 +152,14 @@ class Tags: :param tag_name: The name of the tag to delete. """ - tag_name = tag_name.lower().strip() - embed = Embed() - embed.colour = Colour.red() - tag_data = await self.delete_tag_data(tag_name) - - if tag_data.get("success") is True: - log.debug(f"{ctx.author} successfully deleted the tag called '{tag_name}'") - embed.colour = Colour.blurple() - embed.title = tag_name - embed.description = f"Tag successfully removed: {tag_name}." + await self.bot.api_client.delete(f'bot/tags/{tag_name}') - elif tag_data.get("success") is False: - log.debug(f"{ctx.author} tried to delete a tag called '{tag_name}', but the tag does not exist.") - embed.colour = Colour.red() - embed.title = tag_name - embed.description = "Tag doesn't appear to exist." - - else: - log.error("There was an unexpected database error when trying to delete the following tag: \n" - f"tag_name: {tag_name}\n" - f"response: {tag_data}") - embed.title = "Database error" - embed.description = ("There was an unexpected error with deleting the data from the tags database. " - "Please try again. If the problem persists, see the error logs.") - - return await ctx.send(embed=embed) - - @get_command.error - @set_command.error - @delete_command.error - async def command_error(self, ctx, error): - if isinstance(error, BadArgument): - embed = Embed() - embed.colour = Colour.red() - embed.description = str(error) - embed.title = random.choice(ERROR_REPLIES) - await ctx.send(embed=embed) - else: - log.error(f"Unhandled tag command error: {error} ({error.original})") + log.debug(f"{ctx.author} successfully deleted the tag called '{tag_name}'") + await ctx.send(embed=Embed( + title=tag_name, + description=f"Tag successfully removed: {tag_name}.", + colour=Colour.blurple() + )) def setup(bot): |