diff --git a/src/pluralkit/bot/commands/__init__.py b/src/pluralkit/bot/commands/__init__.py index 5faa9e0f..1cbe35b8 100644 --- a/src/pluralkit/bot/commands/__init__.py +++ b/src/pluralkit/bot/commands/__init__.py @@ -6,7 +6,7 @@ import discord import pluralkit from pluralkit import db -from pluralkit.bot import utils +from pluralkit.bot import utils, embeds logger = logging.getLogger("pluralkit.bot.commands") @@ -17,10 +17,6 @@ class InvalidCommandSyntax(Exception): class NoSystemRegistered(Exception): pass - -class CommandError(Exception): - def __init__(self, message): - self.message = message class CommandContext(namedtuple("CommandContext", ["client", "conn", "message", "system"])): client: discord.Client @@ -62,9 +58,6 @@ def command(cmd, usage=None, description=None, category=None, system_required=Tr except InvalidCommandSyntax: usage_str = "**Usage:** pk;{} {}".format(cmd, usage or "") await client.send_message(message.channel, embed=utils.make_default_embed(usage_str)) - except CommandError as e: - embed = e.message if isinstance(e.message, discord.Embed) else utils.make_error_embed(e.message) - await client.send_message(message.channel, embed=embed) except Exception: logger.exception("Exception while handling command {} (args={}, system={})".format(cmd, args, system.hid if system else "(none)")) @@ -86,7 +79,7 @@ def member_command(cmd, usage=None, description=None, category=None, system_only member = await utils.get_member_fuzzy(ctx.conn, system_id=system_id, key=args[0], system_only=system_only) if member is None: - raise CommandError("Can't find member \"{}\".".format(args[0])) + return embeds.error("Can't find member \"{}\".".format(args[0])) ctx = MemberCommandContext(client=ctx.client, conn=ctx.conn, message=ctx.message, system=ctx.system, member=member) return await func(ctx, args[1:]) diff --git a/src/pluralkit/bot/commands/import_commands.py b/src/pluralkit/bot/commands/import_commands.py index 23d25698..aa18a0d7 100644 --- a/src/pluralkit/bot/commands/import_commands.py +++ b/src/pluralkit/bot/commands/import_commands.py @@ -1,10 +1,8 @@ import asyncio import re from datetime import datetime -import logging from typing import List -from pluralkit.bot import utils from pluralkit.bot.commands import * logger = logging.getLogger("pluralkit.commands") @@ -16,7 +14,7 @@ async def import_tupperware(ctx: CommandContext, args: List[str]): # Check if there's any Tupperware bot on the server if not tupperware_members: - raise CommandError("This command only works in a server where the Tupperware bot is also present.") + return embeds.error("This command only works in a server where the Tupperware bot is also present.") # Make sure at least one of the bts have send/read permissions here for bot_member in tupperware_members: @@ -26,7 +24,7 @@ async def import_tupperware(ctx: CommandContext, args: List[str]): break else: # If no bots have permission (ie. loop doesn't break), throw error - raise CommandError("This command only works in a channel where the Tupperware bot has read/send access.") + return embeds.error("This command only works in a channel where the Tupperware bot has read/send access.") await ctx.reply(embed=utils.make_default_embed("Please reply to this message with `tul!list` (or the server equivalent).")) @@ -43,12 +41,12 @@ async def import_tupperware(ctx: CommandContext, args: List[str]): return tw_msg.embeds[0]["title"].startswith("{}#{}".format(ctx.message.author.name, ctx.message.author.discriminator)) - embeds = [] + tupperware_page_embeds = [] tw_msg: discord.Message = await ctx.client.wait_for_message(channel=ctx.message.channel, timeout=60.0, check=ensure_account) if not tw_msg: - raise CommandError("Tupperware import timed out.") - embeds.append(tw_msg.embeds[0]) + return embeds.error("Tupperware import timed out.") + tupperware_page_embeds.append(tw_msg.embeds[0]) # Handle Tupperware pagination def match_pagination(): @@ -84,11 +82,11 @@ async def import_tupperware(ctx: CommandContext, args: List[str]): # Make sure it doesn't spin here for too long, time out after 30 seconds since last new page if (datetime.utcnow() - last_found_time).seconds > 30: - raise CommandError("Pagination scan timed out.") + return embeds.error("Pagination scan timed out.") # Now that we've got all the pages, put them in the embeds list # Make sure to erase the original one we put in above too - embeds = list([embed for page, embed in sorted(pages_found.items(), key=lambda x: x[0])]) + tupperware_page_embeds = list([embed for page, embed in sorted(pages_found.items(), key=lambda x: x[0])]) # Also edit the status message to indicate we're now importing, and it may take a while because there's probably a lot of members await ctx.client.edit_message(status_msg, "All pages read. Now importing...") @@ -103,7 +101,7 @@ async def import_tupperware(ctx: CommandContext, args: List[str]): system = await db.create_system(ctx.conn, system_name=None, system_hid=hid) await db.link_account(ctx.conn, system_id=system.id, account_id=ctx.message.author.id) - for embed in embeds: + for embed in tupperware_page_embeds: for field in embed["fields"]: name = field["name"] lines = field["value"].split("\n") @@ -150,4 +148,4 @@ async def import_tupperware(ctx: CommandContext, args: List[str]): await db.update_member_field(ctx.conn, member_id=existing_member.id, field="birthday", value=member_birthdate) await db.update_member_field(ctx.conn, member_id=existing_member.id, field="description", value=member_description) - return "System information imported. Try using `pk;system` now.\nYou should probably remove your members from Tupperware to avoid double-posting." + return embeds.success("System information imported. Try using `pk;system` now.\nYou should probably remove your members from Tupperware to avoid double-posting.") diff --git a/src/pluralkit/bot/commands/member_commands.py b/src/pluralkit/bot/commands/member_commands.py index 16555da3..2288a7ed 100644 --- a/src/pluralkit/bot/commands/member_commands.py +++ b/src/pluralkit/bot/commands/member_commands.py @@ -4,7 +4,7 @@ from datetime import datetime from typing import List from urllib.parse import urlparse -from pluralkit.bot import utils +from pluralkit.bot import utils, embeds from pluralkit.bot.commands import * logger = logging.getLogger("pluralkit.commands") @@ -21,14 +21,14 @@ async def new_member(ctx: MemberCommandContext, args: List[str]): name = " ".join(args) bounds_error = utils.bounds_check_member_name(name, ctx.system.tag) if bounds_error: - raise CommandError(bounds_error) + return embeds.error(bounds_error) # TODO: figure out what to do if this errors out on collision on generate_hid hid = utils.generate_hid() # Insert member row await db.create_member(ctx.conn, system_id=ctx.system.id, member_name=name, member_hid=hid) - return "Member \"{}\" (`{}`) registered!".format(name, hid) + return embeds.success("Member \"{}\" (`{}`) registered!".format(name, hid)) @member_command(cmd="member set", usage=" [value]", description="Edits a member property. Leave [value] blank to clear.", category="Member commands") @@ -48,7 +48,7 @@ async def member_set(ctx: MemberCommandContext, args: List[str]): prop = args[0] if prop not in allowed_properties: - raise CommandError("Unknown property {}. Allowed properties are {}.".format(prop, ", ".join(allowed_properties))) + return embeds.error("Unknown property {}. Allowed properties are {}.".format(prop, ", ".join(allowed_properties))) if len(args) >= 2: value = " ".join(args[1:]) @@ -57,12 +57,12 @@ async def member_set(ctx: MemberCommandContext, args: List[str]): if prop == "name": bounds_error = utils.bounds_check_member_name(value, ctx.system.tag) if bounds_error: - raise CommandError(bounds_error) + return embeds.error(bounds_error) if prop == "color": match = re.fullmatch("#?([0-9A-Fa-f]{6})", value) if not match: - raise CommandError("Color must be a valid hex color (eg. #ff0000)") + return embeds.error("Color must be a valid hex color (eg. #ff0000)") value = match.group(1).lower() @@ -76,7 +76,7 @@ async def member_set(ctx: MemberCommandContext, args: List[str]): # Useful if you want your birthday to be displayed yearless. value = datetime.strptime("0001-" + value, "%Y-%m-%d").date() except ValueError: - raise CommandError("Invalid date. Date must be in ISO-8601 format (eg. 1999-07-25).") + return embeds.error("Invalid date. Date must be in ISO-8601 format (eg. 1999-07-25).") if prop == "avatar": user = await utils.parse_mention(ctx.client, value) @@ -90,11 +90,11 @@ async def member_set(ctx: MemberCommandContext, args: List[str]): if u.scheme in ["http", "https"] and u.netloc and u.path: value = value else: - raise CommandError("Invalid URL.") + return embeds.error("Invalid URL.") else: # Can't clear member name if prop == "name": - raise CommandError("Can't clear member name.") + return embeds.error("Can't clear member name.") # Clear from DB value = None @@ -102,7 +102,7 @@ async def member_set(ctx: MemberCommandContext, args: List[str]): db_prop = db_properties[prop] await db.update_member_field(ctx.conn, member_id=ctx.member.id, field=db_prop, value=value) - response = utils.make_default_embed("{} {}'s {}.".format("Updated" if value else "Cleared", ctx.member.name, prop)) + response = embeds.success("{} {}'s {}.".format("Updated" if value else "Cleared", ctx.member.name, prop)) if prop == "avatar" and value: response.set_image(url=value) if prop == "color" and value: @@ -117,10 +117,10 @@ async def member_proxy(ctx: MemberCommandContext, args: List[str]): # Sanity checking example = " ".join(args) if "text" not in example: - raise CommandError("Example proxy message must contain the string 'text'.") + return embeds.error("Example proxy message must contain the string 'text'.") if example.count("text") != 1: - raise CommandError("Example proxy message must contain the string 'text' exactly once.") + return embeds.error("Example proxy message must contain the string 'text' exactly once.") # Extract prefix and suffix prefix = example[:example.index("text")].strip() @@ -136,7 +136,7 @@ async def member_proxy(ctx: MemberCommandContext, args: List[str]): async with ctx.conn.transaction(): await db.update_member_field(ctx.conn, member_id=ctx.member.id, field="prefix", value=prefix) await db.update_member_field(ctx.conn, member_id=ctx.member.id, field="suffix", value=suffix) - return "Proxy settings updated." if prefix or suffix else "Proxy settings cleared." + return embeds.success("Proxy settings updated." if prefix or suffix else "Proxy settings cleared.") @member_command("member delete", description="Deletes a member from your system ***permanently***.", category="Member commands") async def member_delete(ctx: MemberCommandContext, args: List[str]): @@ -145,6 +145,6 @@ async def member_delete(ctx: MemberCommandContext, args: List[str]): msg = await ctx.client.wait_for_message(author=ctx.message.author, channel=ctx.message.channel, timeout=60.0) if msg and msg.content.lower() == ctx.member.hid.lower(): await db.delete_member(ctx.conn, member_id=ctx.member.id) - return "Member deleted." + return embeds.success("Member deleted.") else: - return "Member deletion cancelled." \ No newline at end of file + return embeds.success("Member deletion cancelled.") \ No newline at end of file diff --git a/src/pluralkit/bot/commands/message_commands.py b/src/pluralkit/bot/commands/message_commands.py index cd0c7cc0..4a597fd4 100644 --- a/src/pluralkit/bot/commands/message_commands.py +++ b/src/pluralkit/bot/commands/message_commands.py @@ -1,7 +1,7 @@ import logging from typing import List -from pluralkit.bot import utils +from pluralkit.bot import utils, embeds from pluralkit.bot.commands import * logger = logging.getLogger("pluralkit.commands") @@ -21,7 +21,7 @@ async def message_info(ctx: CommandContext, args: List[str]): # Find the message in the DB message = await db.get_message(ctx.conn, str(mid)) if not message: - raise CommandError("Message not found.") + raise embeds.error("Message with ID '{}' not found.".format(args[0])) # Get the original sender of the messages try: diff --git a/src/pluralkit/bot/commands/misc_commands.py b/src/pluralkit/bot/commands/misc_commands.py index c8b443fe..3204d4b1 100644 --- a/src/pluralkit/bot/commands/misc_commands.py +++ b/src/pluralkit/bot/commands/misc_commands.py @@ -7,7 +7,7 @@ from typing import List from discord.utils import oauth_url import pluralkit.utils -from pluralkit.bot import utils +from pluralkit.bot import utils, embeds from pluralkit.bot.commands import * logger = logging.getLogger("pluralkit.commands") @@ -47,7 +47,7 @@ async def invite_link(ctx: CommandContext, args: List[str]): url = oauth_url(client_id, permissions) logger.debug("Sending invite URL: {}".format(url)) - return url + return embeds.success("Use this link to add PluralKit to your server: {}".format(url)) @command(cmd="export", description="Exports system data to a machine-readable format.") async def export(ctx: CommandContext, args: List[str]): diff --git a/src/pluralkit/bot/commands/mod_commands.py b/src/pluralkit/bot/commands/mod_commands.py index 10df6f14..a1c928cd 100644 --- a/src/pluralkit/bot/commands/mod_commands.py +++ b/src/pluralkit/bot/commands/mod_commands.py @@ -1,7 +1,7 @@ import logging from typing import List -from pluralkit.bot import utils +from pluralkit.bot import utils, embeds from pluralkit.bot.commands import * logger = logging.getLogger("pluralkit.commands") @@ -9,7 +9,7 @@ logger = logging.getLogger("pluralkit.commands") @command(cmd="mod log", usage="[channel]", description="Sets the bot to log events to a specified channel. Leave blank to disable.", category="Moderation commands", system_required=False) async def set_log(ctx: CommandContext, args: List[str]): if not ctx.message.author.server_permissions.administrator: - raise CommandError("You must be a server administrator to use this command.") + return embeds.error("You must be a server administrator to use this command.") server = ctx.message.server if len(args) == 0: @@ -17,8 +17,8 @@ async def set_log(ctx: CommandContext, args: List[str]): else: channel = utils.parse_channel_mention(args[0], server=server) if not channel: - raise CommandError("Channel not found.") + return embeds.error("Channel not found.") channel_id = channel.id await db.update_server(ctx.conn, server.id, logging_channel_id=channel_id) - return "Updated logging channel." if channel_id else "Cleared logging channel." + return embeds.success("Updated logging channel." if channel_id else "Cleared logging channel.") diff --git a/src/pluralkit/bot/commands/switch_commands.py b/src/pluralkit/bot/commands/switch_commands.py index e4ee781c..d87e855f 100644 --- a/src/pluralkit/bot/commands/switch_commands.py +++ b/src/pluralkit/bot/commands/switch_commands.py @@ -7,7 +7,7 @@ import humanize import pluralkit.utils from pluralkit import Member -from pluralkit.bot import utils +from pluralkit.bot import utils, embeds from pluralkit.bot.commands import * logger = logging.getLogger("pluralkit.commands") @@ -22,7 +22,7 @@ async def switch_member(ctx: MemberCommandContext, args: List[str]): # Find the member member = await utils.get_member_fuzzy(ctx.conn, ctx.system.id, member_name) if not member: - raise CommandError("Couldn't find member \"{}\".".format(member_name)) + return embeds.error("Couldn't find member \"{}\".".format(member_name)) members.append(member) # Compare requested switch IDs and existing fronter IDs to check for existing switches @@ -31,12 +31,12 @@ async def switch_member(ctx: MemberCommandContext, args: List[str]): fronter_ids = (await pluralkit.utils.get_fronter_ids(ctx.conn, ctx.system.id))[0] if member_ids == fronter_ids: if len(members) == 1: - raise CommandError("{} is already fronting.".format(members[0].name)) - raise CommandError("Members {} are already fronting.".format(", ".join([m.name for m in members]))) + return embeds.error("{} is already fronting.".format(members[0].name)) + return embeds.error("Members {} are already fronting.".format(", ".join([m.name for m in members]))) # Also make sure there aren't any duplicates if len(set(member_ids)) != len(member_ids): - raise CommandError("Duplicate members in switch list.") + return embeds.error("Duplicate members in switch list.") # Log the switch async with ctx.conn.transaction(): @@ -45,20 +45,20 @@ async def switch_member(ctx: MemberCommandContext, args: List[str]): await db.add_switch_member(ctx.conn, switch_id=switch_id, member_id=member.id) if len(members) == 1: - return "Switch registered. Current fronter is now {}.".format(members[0].name) + return embeds.success("Switch registered. Current fronter is now {}.".format(members[0].name)) else: - return "Switch registered. Current fronters are now {}.".format(", ".join([m.name for m in members])) + return embeds.success("Switch registered. Current fronters are now {}.".format(", ".join([m.name for m in members]))) @command(cmd="switch out", description="Registers a switch with no one in front.", category="Switching commands") async def switch_out(ctx: MemberCommandContext, args: List[str]): # Get current fronters fronters, _ = await pluralkit.utils.get_fronter_ids(ctx.conn, system_id=ctx.system.id) if not fronters: - raise CommandError("There's already no one in front.") + raise embeds.error("There's already no one in front.") # Log it, and don't log any members await db.add_switch(ctx.conn, system_id=ctx.system.id) - return "Switch-out registered." + return embeds.success("Switch-out registered.") @command(cmd="switch move", usage="