aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/__main__.py8
-rw-r--r--bot/api.py40
-rw-r--r--bot/cogs/doc.py153
-rw-r--r--bot/cogs/events.py16
-rw-r--r--bot/cogs/off_topic_names.py72
-rw-r--r--bot/cogs/sync.py86
-rw-r--r--bot/cogs/tags.py249
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):