diff --git a/.gitignore b/.gitignore index 72cabe6..5cc6aa8 100644 --- a/.gitignore +++ b/.gitignore @@ -139,4 +139,5 @@ cython_debug/ # Custom storage/ -.vscode/ \ No newline at end of file +.vscode/ +.history/ \ No newline at end of file diff --git a/bot.py b/bot.py index 098cfff..1be707d 100644 --- a/bot.py +++ b/bot.py @@ -1,17 +1,13 @@ import discord import os -import json -import sys -import traceback +import sys import datetime -import inspect import math import random import asyncio import DiscordUtils import humanize import asyncpg -import pytest import ext.helpers as helpers from dotenv import load_dotenv from discord.ext import commands, tasks @@ -19,23 +15,15 @@ async def prefix(bot, message): - return commands.when_mentioned_or(*(await helpers.prefix(bot, message)))(bot, message) + return commands.when_mentioned_or(*(await helpers.prefix(bot, message)))( + bot, message) + class CustomHelp(commands.HelpCommand): - """This is an example of a HelpCommand that utilizes embeds. - It's pretty basic but it lacks some nuances that people might expect. - 1. It breaks if you have more than 25 cogs or more than 25 subcommands. (Most people don't reach this) - 2. It doesn't DM users. To do this, you have to override `get_destination`. It's simple. - Other than those two things this is a basic skeleton to get you started. It should - be simple to modify if you desire some other behaviour. - - To use this, pass it to the bot constructor e.g.: - - bot = commands.Bot(help_command=EmbedHelpCommand()) - """ def get_ending_note(self): - return 'Use {0}{1} [command] for more info on a command.'.format(self.clean_prefix, self.invoked_with) + return 'Use {0}{1} [command] for more info on a command.'.format( + self.clean_prefix, self.invoked_with) def get_command_signature(self, command): parent = command.full_parent_name @@ -55,11 +43,11 @@ async def send_bot_help(self, mapping): if description: embed.description = description - for cog, commands in mapping.items(): + for cog, cmds in mapping.items(): name = 'No Category' if cog is None else cog.qualified_name - filtered = await self.filter_commands(commands, sort=True) + filtered = await self.filter_commands(cmds, sort=True) if filtered: - value = '\u2002'.join(c.name for c in commands) + value = '\u2002'.join(c.name for c in cmds) if cog and cog.description: value = '{0}\n{1}'.format(cog.description, value) @@ -75,7 +63,8 @@ async def send_cog_help(self, cog): filtered = await self.filter_commands(cog.get_commands(), sort=True) for command in filtered: - embed.add_field(name=self.get_command_signature(command), value=command.short_doc or '...', inline=False) + embed.add_field(name=self.get_command_signature(command), + value=command.short_doc or '...', inline=False) embed.set_footer(text=self.get_ending_note()) await self.get_destination().send(embed=embed) @@ -88,7 +77,8 @@ async def send_group_help(self, group): if isinstance(group, commands.Group): filtered = await self.filter_commands(group.commands, sort=True) for command in filtered: - embed.add_field(name=self.get_command_signature(command), value=command.short_doc or '...', inline=False) + embed.add_field(name=self.get_command_signature(command), + value=command.short_doc or '...', inline=False) embed.set_footer(text=self.get_ending_note()) await self.get_destination().send(embed=embed) @@ -98,8 +88,10 @@ async def send_group_help(self, group): # If you want to make regular command help look different then override it send_command_help = send_group_help -bot = helpers.Bot(command_prefix=prefix,description='Coding Bot v4',case_insensitive=True,embed_color=discord.Color.blurple(),intents=discord.Intents.all(), help_command=CustomHelp()) +bot = helpers.Bot(command_prefix=prefix, description='Coding Bot v4', + case_insensitive=True, embed_color=discord.Color.blurple(), + intents=discord.Intents.all(), help_command=CustomHelp()) load_dotenv() if len(sys.argv) > 2: bot.token = sys.argv[2] @@ -108,12 +100,13 @@ async def send_group_help(self, group): bot.default_owner = os.getenv('OWNER_ID') os.environ["JISHAKU_NO_UNDERSCORE"] = "True" os.environ['JISHAKU_RETAIN'] = "True" -from jishaku.modules import ExtensionConverter # has to be after environ stuff ree data = helpers.storage(bot) class pools: - config = asyncpg.create_pool(database='codingbot_db', init=helpers.init_connection) + config = asyncpg.create_pool(database='codingbot_db', + init=helpers.init_connection) + bot.helpers = helpers bot.tracker = DiscordUtils.InviteTracker(bot) @@ -132,17 +125,19 @@ class pools: try: bot.load_extension(cog) print(cog) - except: + except discord.DiscordException: if __name__ == "__main__": print(f'!!! {cog} !!!') else: raise + @bot.event async def on_message(message): ctx = await bot.get_context(message, cls=helpers.Context) await bot.invoke(ctx) + @bot.event async def on_ready(): await bot.tracker.cache_invites() @@ -155,64 +150,98 @@ async def on_ready(): await channel.send(embed=embed) if not __name__ == "__main__": await bot.logout() - + + @bot.event async def on_invite_create(invite): await bot.tracker.update_invite_cache(invite) + @bot.event async def on_guild_join(guild): await bot.tracker.update_guild_cache(guild) + @bot.event async def on_invite_delete(invite): await bot.tracker.remove_invite_cache(invite) + @bot.event async def on_guild_remove(guild): await bot.tracker.remove_guild_cache(guild) - + + @bot.event async def on_member_join(member): if not member.guild.id == 681882711945641997: return - try: - inviter = await bot.tracker.fetch_inviter(member) - except: - inviter = None - embed = discord.Embed(title='Welcome to The Coding Academy!', - description=f'''Welcome {member.mention}, we're glad you joined! Before you get started, here are some things to check out: -**Read the Rules:** {member.guild.rules_channel.mention} -**Get roles:** <#726074137168183356> and <#806909970482069556> -**Want help? Read here:** <#799527165863395338> and <#754712400757784709> -''', - timestamp=datetime.datetime.utcnow()) - message = f'{member} (ID: {member.id}) joined, {"invited by " + str(inviter) + "(ID: " + str(inviter.id) + ")" if inviter else "but I could not find who invited them"}' + inviter = await bot.tracker.fetch_inviter(member) + rules = member.guild.rules_channel.mention + embed = discord.Embed( + title='Welcome to The Coding Academy!', + description=( + f'Welcome {member.mention}, we\'re glad you joined! Before you get' + ' started, here are some things to check out: \n**Read the Rules:' + f'** {rules} \n**Get roles:** <#726074137168183356> and ' + '<#806909970482069556> \n**Want help? Read here:** ' + '<#799527165863395338> and <#754712400757784709>'), + timestamp=datetime.datetime.utcnow()) + emojis = ( + '', '', + '') + if inviter: + inv = sum(i.uses for i in (await member.guild.invites()) if i.inviter + and i.inviter.id == inviter.id) + by = (f'Invited by **{inviter.name}** (ID: {inviter.id}, {inv} invites' + f') {emojis[1]}') + else: + try: + invite = await member.guild.vanity_invite() + by = (f'Joined using vanity invite code: *{invite.code}* (' + f'{invite.uses} uses)') + except discord.errors.HTTPException: + by = 'but I couldn\'t find who invited them' + ago = datetime.datetime.utcnow() - member.created_at + char = '\U000027a5' + message = ( + f'Welcome to *{member.guild.name}*, {member.mention}! {emojis[0]} \n' + f'{char} {by} \n➥ Account made {ago.days} days ago {emojis[2]} {char}') channel = member.guild.get_channel(743817386792058971) - #await channel.send(content=message) + await channel.send(content=message) try: await member.send(embed=embed) - except: + except discord.errors.Forbidden: pass + @bot.event async def on_error(event_method, *args, **kwargs): await helpers.log_error(bot, event_method, *args, *kwargs) + @bot.event async def on_command_error(ctx, error): exception = error if hasattr(ctx.command, 'on_error'): pass - #ignored = (commands.MissingRequiredArgument, commands.BadArgument, commands.NoPrivateMessage, commands.CheckFailure, commands.CommandNotFound, commands.DisabledCommand, commands.CommandInvokeError, commands.TooManyArguments, commands.UserInputError, commands.CommandOnCooldown, commands.NotOwner, commands.MissingPermissions, commands.BotMissingPermissions) error = getattr(error, 'original', error) if ctx.author.id in ctx.bot.owner_ids: - if isinstance(error, commands.DisabledCommand) or isinstance(error, commands.CommandOnCooldown) or isinstance(error, commands.MissingPermissions) or isinstance(error, commands.MaxConcurrencyReached): + if (isinstance(error, ( + commands.DisabledCommand, commands.CommandOnCooldown, + commands.MissingPermissions, commands.MaxConcurrencyReached))): return await ctx.reinvoke() - if isinstance(error, commands.BadArgument) or isinstance(error, commands.MissingRequiredArgument) or isinstance(error, commands.NoPrivateMessage) or isinstance(error, commands.CheckFailure) or isinstance(error, commands.DisabledCommand) or isinstance(error, commands.CommandInvokeError) or isinstance(error, commands.TooManyArguments) or isinstance(error, commands.UserInputError) or isinstance(error, commands.NotOwner) or isinstance(error, commands.MissingPermissions) or isinstance(error, commands.BotMissingPermissions) or isinstance(error, commands.MaxConcurrencyReached) or isinstance(error, commands.CommandNotFound): - await helpers.log_command_error(ctx,exception,True) + if (isinstance(error, ( + commands.BadArgument, commands.MissingRequiredArgument, + commands.NoPrivateMessage, commands.CheckFailure, + commands.DisabledCommand, commands.CommandInvokeError, + commands.TooManyArguments, commands.UserInputError, + commands.NotOwner, commands.MissingPermissions, + commands.BotMissingPermissions, commands.MaxConcurrencyReached, + commands.CommandNotFound))): + await helpers.log_command_error(ctx, exception, True) if not isinstance(error, commands.CommandNotFound): if await helpers.is_disabled(ctx): return @@ -221,51 +250,73 @@ async def on_command_error(ctx, error): if bot.disabled: text = 'The bot is currently disabled. It will be back soon.' if not isinstance(error, commands.CommandNotFound): - error=str(error) - await ctx.send(embed=ctx.embed(title="Error",description=text or error,color=discord.Color.red()).set_author(name=ctx.author,icon_url=ctx.author.avatar_url).set_footer(icon_url=bot.user.avatar_url,text=f'If you think this is a mistake please contact {bot.get_user(ctx.bot.owner_ids[0])}')) + embed = ctx.embed(title="Error", description=text or str(error), + color=discord.Color.red()) + embed.set_author(name=ctx.author, icon_url=ctx.author.avatar_url) + owner = bot.get_user(ctx.bot.owner_ids[0]) + embed.set_footer( + icon_url=bot.user.avatar_url, + text=f'If you think this is a mistake please contact {owner}') + await ctx.send(embed=embed) elif isinstance(error, commands.CommandOnCooldown): - await helpers.log_command_error(ctx,exception,True) + await helpers.log_command_error(ctx, exception, True) time = datetime.timedelta(seconds=math.ceil(error.retry_after)) - error = f'You are on cooldown. Try again after {humanize.precisedelta(time)}' - await ctx.send(embed=ctx.embed(title="Error",description=error,color=discord.Color.red()).set_author(name=ctx.author,icon_url=ctx.author.avatar_url).set_footer(icon_url=bot.user.avatar_url,text=f'If you think this is a mistake please contact {bot.get_user(ctx.bot.owner_ids[0])}')) - + error = (f'You are on cooldown. Try again after ' + f'{humanize.precisedelta(time)}') + ctx.embed(title="Error", description=error, + color=discord.Color.red()) + embed.set_author(name=ctx.author, icon_url=ctx.author.avatar_url) + owner = bot.get_user(ctx.bot.owner_ids[0]) + embed.set_footer( + icon_url=bot.user.avatar_url, + text=f'If you think this is a mistake please contact {owner}') + await ctx.send(embed=embed) + else: try: - embed = ctx.embed(title='Oh no!',description=f"An error occurred. My developer has been notified of it, but if it continues to occur please DM <@{ctx.bot.owner_ids[0]}>",color=discord.Color.red()) + embed = ctx.embed(title='Oh no!', description=( + 'An error occurred. My developer has been notified of it, ' + 'but if it continues to occur please DM ' + f'<@{ctx.bot.owner_ids[0]}>'), color=discord.Color.red()) await ctx.send(embed=embed) - except: + except discord.errors.Forbidden: pass - await helpers.log_command_error(ctx,exception,False) + await helpers.log_command_error(ctx, exception, False) + class Developer(commands.Cog): - + def __init__(self, bot): self.bot = bot - @commands.command(name='load',aliases=['l']) + @commands.command(name='load', aliases=['l']) @commands.is_owner() - async def _load(self, ctx, cog, save: bool=False): + async def _load(self, ctx, cog, save: bool = False): if save: helpers.storage(self.bot, key='cogs', value=cog, method='append') self.bot.load_extension(cog) - embed = ctx.embed(title='Success', description='Saved Preference' if save else None, color=discord.Color.green()) + embed = ctx.embed( + title='Success', description='Saved Preference' if save else None, + color=discord.Color.green()) await ctx.send(embed=embed) - @commands.command(name='unload',aliases=['u']) + @commands.command(name='unload', aliases=['u']) @commands.is_owner() - async def _unload(self, ctx, cog, save: bool=False): + async def _unload(self, ctx, cog, save: bool = False): if save: helpers.storage(self.bot, key='cogs', value=cog, method='remove') self.bot.unload_extension(cog) - embed = ctx.embed(title='Success',description='Saved Preference' if save else None,color=discord.Color.green()) + embed = ctx.embed( + title='Success', description='Saved Preference' if save else None, + color=discord.Color.green()) await ctx.send(embed=embed) - @commands.command(name='reload',aliases=['r']) + @commands.command(name='reload', aliases=['r']) @commands.is_owner() async def _reload(self, ctx, cog): self.bot.reload_extension(cog) - embed = ctx.embed(title='Success',color=discord.Color.green()) + embed = ctx.embed(title='Success', color=discord.Color.green()) await ctx.send(embed=embed) @commands.command(name='loadall', aliases=['la']) @@ -282,15 +333,16 @@ async def _loadall(self, ctx): try: self.bot.load_extension(cog) cogs['loaded'].append(cog) - except: + except discord.DiscordException: cogs['not'].append(cog) - embed = ctx.embed(title='Load all cogs',description='\n'.join([('\U00002705' if cog in cogs['loaded'] else '\U0000274c') + cog for cog in data['cogs']])) + embed = ctx.embed(title='Load all cogs', description='\n'.join([ + ('\U00002705' if cog in cogs['loaded'] else '\U0000274c') + + cog for cog in data['cogs']])) await ctx.send(embed=embed) - @commands.command(name='unloadall',aliases=['ua']) + @commands.command(name='unloadall', aliases=['ua']) @commands.is_owner() async def _unloadall(self, ctx): - data = helpers.storage(self.bot) cogs = { 'unloaded': [], 'not': [] @@ -300,15 +352,16 @@ async def _unloadall(self, ctx): try: self.bot.unload_extension(cog) cogs['unloaded'].append(cog) - except: + except discord.DiscordException: cogs['not'].append(cog) - embed = ctx.embed(title='Unload all cogs',description='\n'.join([('\U00002705' if cog in cogs['unloaded'] else '\U0000274c') + cog for cog in processing])) + embed = ctx.embed(title='Unload all cogs', description='\n'.join([ + ('\U00002705' if cog in cogs['unloaded'] else '\U0000274c') + + cog for cog in processing])) await ctx.send(embed=embed) - @commands.command(name='reloadall',aliases=['ra']) + @commands.command(name='reloadall', aliases=['ra']) @commands.is_owner() async def _reloadall(self, ctx): - data = helpers.storage(self.bot) cogs = { 'reloaded': [], 'not': [] @@ -318,11 +371,14 @@ async def _reloadall(self, ctx): try: self.bot.reload_extension(cog) cogs['reloaded'].append(cog) - except: + except discord.DiscordException: cogs['not'].append(cog) - embed = ctx.embed(title='Reload all cogs',description='\n'.join([('\U00002705' if cog in cogs['reloaded'] else '\U0000274c') + cog for cog in processing])) + embed = ctx.embed(title='Reload all cogs', description='\n'.join([ + ('\U00002705' if cog in cogs['reloaded'] else '\U0000274c') + + cog for cog in processing])) await ctx.send(embed=embed) + bot.add_cog(Developer(bot)) @@ -330,41 +386,60 @@ async def _reloadall(self, ctx): async def before_invoke(ctx): bot.processing_commands += 1 + @bot.after_invoke async def after_invoke(ctx): bot.processing_commands -= 1 + @tasks.loop(seconds=60) async def status_change(): statuses = ['over TCA', 'you', 'swas', '@everyone', 'general chat'] - await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name=random.choice(statuses) + ' | ' + bot.default_prefixes[0] + 'help')) + await bot.change_presence(activity=discord.Activity( + type=discord.ActivityType.watching, + name=random.choice( + statuses) + ' | ' + bot.default_prefixes[0] + 'help')) + @status_change.before_loop async def before_status_change(): await bot.wait_until_ready() - await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name=f'Starting up...')) + await bot.change_presence(activity=discord.Activity( + type=discord.ActivityType.watching, name='Starting up...')) await asyncio.sleep(15) + @bot.check def blacklist(ctx): - return not ctx.author.id in bot.blacklisted or ctx.author.id in bot.owner_ids + return (ctx.author.id not in bot.blacklisted + or ctx.author.id in bot.owner_ids) + @bot.check def disabled(ctx): return (not bot.disabled) or ctx.author.id in bot.owner_ids + @bot.check async def disabled_command(ctx): - return (not await helpers.is_disabled(ctx)) or ctx.author.id in bot.owner_ids or ctx.author.id == ctx.guild.owner.id + return ((not await helpers.is_disabled(ctx)) + or ctx.author.id in bot.owner_ids + or ctx.author.id == ctx.guild.owner.id) @bot.slash.slash(name='help', description='Get the help for the bot') async def slash_help(ctx: SlashContext): - await ctx.send(embeds=[discord.Embed(title='Hello There!', description=f'I use special command prefixes for my commands. Please type \n{bot.user.mention + " help"} \nfor my full help menu!')]) + await ctx.send(embeds=[discord.Embed(title='Hello There!', description=( + 'I use special command prefixes for my commands. Please type \n' + f'{bot.user.mention + " help"} \nfor my full help menu!'))]) + @bot.slash.slash(name='invite', description='Invite the bot to your server') async def slash_invite(ctx: SlashContext): - embed = discord.Embed(title='Invite', description=f"[Click Here](https://discord.com/oauth2/authorize?client_id={bot.user.id}&permissions=8&scope=bot%20applications.commands) to invite me!", timestamp=datetime.datetime.utcnow()) + embed = discord.Embed(title='Invite', description=( + '[Click Here](https://discord.com/oauth2/authorize?client_id=' + f'{bot.user.id}&permissions=8&scope=bot%20applications.commands) ' + 'to invite me!'), timestamp=datetime.datetime.utcnow()) await ctx.send(embeds=[embed]) status_change.start() diff --git a/cogs/config.py b/cogs/config.py index 1faac45..da3658d 100644 --- a/cogs/config.py +++ b/cogs/config.py @@ -1,23 +1,28 @@ import discord -import json +import asyncpg from discord.ext import commands + async def convert(ctx, target): try: - target = await discord.ext.commands.MemberConverter().convert(ctx,target) + target = await discord.ext.commands.MemberConverter().convert(ctx, + target) except discord.ext.commands.errors.MemberNotFound: try: - target = await discord.ext.commands.TextChannelConverter().convert(ctx,target) + target = await discord.ext.commands.TextChannelConverter().convert( + ctx, target) except discord.ext.commands.errors.ChannelNotFound: try: - target = await discord.ext.commands.RoleConverter().convert(ctx,target) + target = await discord.ext.commands.RoleConverter().convert( + ctx, target) except discord.ext.commands.errors.RoleNotFound: - await ctx.send(f'I couldnt find `{target}`') + await ctx.send(f'I couldn\'t find `{target}`') return None return target + class Config(commands.Cog): - + def __init__(self, bot): self.bot = bot @@ -32,29 +37,47 @@ async def config(self, ctx): @commands.has_guild_permissions(manage_guild=True) async def _prefix(self, ctx, *prefixes): prefixes = list(prefixes) - prefixes = prefixes if not (prefixes == ['default'] or prefixes == self.bot.default_prefixes) else None + prefixes = (prefixes if not (prefixes == ['default'] + or prefixes == self.bot.default_prefixes) else None) previous_prefixes = self.bot.default_prefixes try: async with self.bot.pools.config.acquire() as connection: - data = await connection.fetchval('SELECT prefixes FROM serverconf WHERE id = $1', ctx.guild.id) - insert = self.bot.default_prefixes if prefixes is None else prefixes + data = await connection.fetchval( + 'SELECT prefixes FROM serverconf WHERE id = $1', + ctx.guild.id) + insert = ( + self.bot.default_prefixes if prefixes is None + else prefixes) if prefixes == []: previous_prefixes = data or previous_prefixes else: if not data: - await connection.execute(f'INSERT INTO serverconf (prefixes, id) VALUES (ARRAY{insert}, {ctx.guild.id})') + await connection.execute( + f'''INSERT INTO serverconf (prefixes, id) + VALUES (ARRAY{insert}, {ctx.guild.id})''') else: - await connection.execute(f'UPDATE serverconf SET prefixes = ARRAY{insert} WHERE id = {ctx.guild.id}') - except: + await connection.execute( + f'''UPDATE serverconf + SET prefixes = ARRAY{insert} + WHERE id = {ctx.guild.id}''') + except asyncpg.exceptions._base.InterfaceError: pass if prefixes == []: - embed = ctx.embed(title='Prefix',description=f'Current Prefix(es): `{"`, `".join(previous_prefixes)}`\n\nOr, you can mention me as a prefix (try "{self.bot.user.mention} help")') - embed.add_field(name='To reset:',value=f'`{ctx.prefix + ctx.command.qualified_name} default` to reset the prefix to default, or replace default with your own prefix') + embed = ctx.embed(title='Prefix', description=( + f'Current Prefix(es): `{"`, `".join(previous_prefixes)}`\n\nOr' + ', you can mention me as a prefix (try "' + f'{self.bot.user.mention} help")')) + embed.add_field(name='To reset:', value=( + f'`{ctx.prefix + ctx.command.qualified_name} default` to reset' + ' the prefix to default, or replace default with your own ' + 'prefix')) return await ctx.send(embed=embed) prefixes = prefixes or ['set to default'] - embed = ctx.embed(title='Successfully changed prefix', description=f'Prefixes are now `{"`, `".join(prefixes)}``' if len(prefixes) > 1 else f'Prefix is now {prefixes[0]}') + embed = ctx.embed(title='Successfully changed prefix', description=( + f'Prefixes are now `{"`, `".join(prefixes)}``' + if len(prefixes) > 1 else f'Prefix is now {prefixes[0]}')) await self.bot.helpers.prepare(self.bot, ctx.guild) await ctx.send(embed=embed) @@ -67,7 +90,7 @@ async def disabled(self, ctx): """ try: commands = self.bot.server_cache[ctx.guild.id]['commands'] - except KeyError as error: + except KeyError: await self.bot.helpers.prepare(self.bot, ctx.guild) commands = self.bot.server_cache[ctx.guild.id]['commands'] if not commands: @@ -75,9 +98,13 @@ async def disabled(self, ctx): if len(commands) == 0: return await ctx.send(embed=ctx.error('No commands are disabled')) - content = '\n'.join([(await convert(ctx, command)).mention + ': ' + (('`' + '`, `'.join(commands[command]) + '`.') if not True in commands[command] else 'All Commands') for command in commands if commands.get(command, None)]) or 'No Commands are disabled' + content = ('\n'.join([ + (await convert(ctx, command)).mention + ': ' + + (('`' + '`, `'.join(commands[command]) + '`.') + if True not in commands[command] else 'All Commands') + for command in commands if commands.get(command, None)]) + or 'No Commands are disabled') await ctx.send(embed=ctx.embed(content, title='Disabled Commands')) - @config.group(invoke_without_command=True) @commands.guild_only() @@ -102,37 +129,49 @@ async def enable(self, ctx): @commands.has_guild_permissions(manage_guild=True) async def _disable_command(self, ctx, command, *, target=None): """ - Disable a command on the bot. Target can be a member, channel, or role. The command will be disabled for the target. If no target is specified, it will disable the command for the whole server. If the command contains a space you must "wrap it in quotes like this." + Disable a command on the bot. Target can be a member, channel, or role. + The command will be disabled for the target. If no target is specified, + it will disable the command for the whole server. If the command + contains a space you must "wrap it in quotes like this." """ - if not target is None: + if target is not None: try: - target = await discord.ext.commands.MemberConverter().convert(ctx,target) + target = await discord.ext.commands.MemberConverter().convert( + ctx, target) except discord.ext.commands.errors.MemberNotFound: try: - target = await discord.ext.commands.TextChannelConverter().convert(ctx,target) + target = (await discord.ext.commands.TextChannelConverter() + ).convert(ctx, target) except discord.ext.commands.errors.ChannelNotFound: try: - target = await discord.ext.commands.RoleConverter().convert(ctx,target) + target = (await discord.ext.commands.RoleConverter() + ).convert(ctx, target) except discord.ext.commands.errors.RoleNotFound: - return await ctx.send(f'I couldnt find `{target}`') + return await ctx.send(f'I couldn\'t find `{target}`') the_for = ' for ' + target.mention else: target = ctx.guild the_for = '' command = self.bot.get_command(command) if not command: - return await ctx.send(embed=ctx.error('That isnt a command!')) + return await ctx.send(embed=ctx.error('That isn\'t a command!')) if command.qualified_name.split()[0] in ['config', 'help']: - return await ctx.send(embed=ctx.error("You cannot disable the config or help commands.")) - embed = ctx.embed(title='Command Disabled', description=f'I will now ignore the command {command.qualified_name}{the_for}.') + return await ctx.send(embed=ctx.error( + "You cannot disable the config or help commands.")) + embed = ctx.embed(title='Command Disabled', description=( + f'I will now ignore the command {command.qualified_name}{the_for}.' + )) async with self.bot.pools.config.acquire() as connection: - data = await connection.fetchrow('SELECT * FROM serverconf WHERE id = $1', ctx.guild.id) + data = await connection.fetchrow( + 'SELECT * FROM serverconf WHERE id = $1', ctx.guild.id) if not data: commands = { str(target.id): [command.qualified_name] } - await connection.execute('INSERT INTO serverconf (id, commands) VALUES ($1, $2::json)', ctx.guild.id, commands) + await connection.execute( + '''INSERT INTO serverconf (id, commands) + VALUES ($1, $2::json)''', ctx.guild.id, commands) else: commands = data['commands'] if isinstance(commands, dict): @@ -142,9 +181,13 @@ async def _disable_command(self, ctx, command, *, target=None): str(target.id): [command.qualified_name] } if command.qualified_name in commands[str(target.id)]: - return await ctx.send(embed=ctx.error(f'`{command.qualified_name}` is already disabled{the_for}.')) + return await ctx.send(embed=ctx.error(( + f'`{command.qualified_name}` is already disabled' + f'{the_for}.'))) commands[str(target.id)].append(command.qualified_name) - await connection.execute('UPDATE serverconf SET commands = $1 WHERE id = $2', commands, ctx.guild.id) + await connection.execute( + 'UPDATE serverconf SET commands = $1 WHERE id = $2', + commands, ctx.guild.id) await self.bot.helpers.prepare(self.bot, ctx.guild) await ctx.send(embed=embed) @@ -152,29 +195,41 @@ async def _disable_command(self, ctx, command, *, target=None): @commands.guild_only() @commands.has_guild_permissions(manage_guild=True) async def _disable_all(self, ctx, *, target=None): - if not target is None: + query = target + target = None + if query is not None: try: - target = await discord.ext.commands.MemberConverter().convert(ctx,target) + target = await discord.ext.commands.MemberConverter().convert( + ctx, query) except discord.ext.commands.errors.MemberNotFound: - try: - target = await discord.ext.commands.TextChannelConverter().convert(ctx,target) - except discord.ext.commands.errors.ChannelNotFound: - try: - target = await discord.ext.commands.RoleConverter().convert(ctx,target) - except discord.ext.commands.errors.RoleNotFound: - return await ctx.send(f'I couldnt find `{target}`') + pass else: target = ctx.channel + if target is None: + try: + target = await discord.ext.commands.TextChannelConverter( + ).convert(ctx, query) + except discord.ext.commands.errors.ChannelNotFound: + pass + if target is None: + try: + target = await discord.ext.commands.RoleConverter().convert( + ctx, query) + except discord.ext.commands.errors.RoleNotFound: + return await ctx.send(f'I couldn\'t find `{query}`') the_for = ' for ' + target.mention - embed = ctx.embed(title='Commands Disabled', description=f'I will now ignore all commands{the_for}.') + embed = ctx.embed(title='Commands Disabled', description=( + f'I will now ignore all commands{the_for}.')) async with self.bot.pools.config.acquire() as connection: - data = await connection.fetchrow('SELECT * FROM serverconf WHERE id = $1', ctx.guild.id) + data = await connection.fetchrow( + 'SELECT * FROM serverconf WHERE id = $1', ctx.guild.id) if not data: commands = { str(target.id): [True] } - await connection.execute('INSERT INTO serverconf (id, commands) VALUES ($1, $2::json)', ctx.guild.id, commands) + await connection.execute('''INSERT INTO serverconf (id, commands) + VALUES ($1, $2::json)''', ctx.guild.id, commands) else: commands = data['commands'] if isinstance(commands, dict): @@ -184,9 +239,12 @@ async def _disable_all(self, ctx, *, target=None): str(target.id): [True] } if True in commands[str(target.id)]: - return await ctx.send(embed=ctx.error(f'All commands are already disabled{the_for}.')) + return await ctx.send(embed=ctx.error( + f'All commands are already disabled{the_for}.')) commands[str(target.id)].append(True) - await connection.execute('UPDATE serverconf SET commands = $1::json WHERE id = $2', commands, ctx.guild.id) + await connection.execute( + 'UPDATE serverconf SET commands = $1::json WHERE id = $2', + commands, ctx.guild.id) await self.bot.helpers.prepare(self.bot, ctx.guild) await ctx.send(embed=embed) @@ -195,39 +253,58 @@ async def _disable_all(self, ctx, *, target=None): @commands.has_guild_permissions(manage_guild=True) async def _enable_all(self, ctx, *, target=None): """ - Enable a command on the bot. Target can be a member, channel, or role. The command will be disabled for the target. If no target is specified, it will enable the command for the whole server. If the command contains a space you must "wrap it in quotes like this." + Enable a command on the bot. Target can be a member, channel, or role. + The command will be disabled for the target. If no target is specified, + it will enable the command for the whole server. If the command + contains a space you must "wrap it in quotes like this." """ - if not target is None: + query = target + target = None + if query is not None: try: - target = await discord.ext.commands.MemberConverter().convert(ctx,target) + target = await discord.ext.commands.MemberConverter().convert( + ctx, query) except discord.ext.commands.errors.MemberNotFound: - try: - target = await discord.ext.commands.TextChannelConverter().convert(ctx,target) - except discord.ext.commands.errors.ChannelNotFound: - try: - target = await discord.ext.commands.RoleConverter().convert(ctx,target) - except discord.ext.commands.errors.RoleNotFound: - return await ctx.send(embed=ctx.error(f'I couldnt find `{target}`')) + pass else: target = ctx.channel + if target is None: + try: + target = await discord.ext.commands.TextChannelConverter( + ).convert(ctx, query) + except discord.ext.commands.errors.ChannelNotFound: + pass + if target is None: + try: + target = await discord.ext.commands.RoleConverter().convert( + ctx, query) + except discord.ext.commands.errors.RoleNotFound: + return await ctx.send(f'I couldn\'t find `{query}`') the_for = ' for ' + target.mention - embed = ctx.embed(title='Commands Enabled', description=f'I will now stop ignoring all commands{the_for}.') + embed = ctx.embed(title='Commands Enabled', description=( + f'I will now stop ignoring all commands{the_for}.')) async with self.bot.pools.config.acquire() as connection: - data = await connection.fetchrow('SELECT * FROM serverconf WHERE id = $1', ctx.guild.id) + data = await connection.fetchrow( + 'SELECT * FROM serverconf WHERE id = $1', ctx.guild.id) if not data: - return await ctx.send(embed=ctx.error(f'Commands are not disabled{the_for}.')) + return await ctx.send(embed=ctx.error( + f'Commands are not disabled{the_for}.')) else: commands = data['commands'] if isinstance(commands, dict): commands[str(target.id)] = commands.get(str(target.id), []) else: - return await ctx.send(embed=ctx.error(f'Commands are not disabled{the_for}.')) + return await ctx.send(embed=ctx.error( + f'Commands are not disabled{the_for}.')) try: commands[str(target.id)].remove(True) - except: - return await ctx.send(embed=ctx.error(f'Commands are not disabled{the_for}.')) - await connection.execute('UPDATE serverconf SET commands = $1::json WHERE id = $2', commands, ctx.guild.id) + except ValueError: + return await ctx.send(embed=ctx.error( + f'Commands are not disabled{the_for}.')) + await connection.execute('''UPDATE serverconf + SET commands = $1::json WHERE id = $2''', commands, + ctx.guild.id) await self.bot.helpers.prepare(self.bot, ctx.guild) await ctx.send(embed=embed) @@ -236,47 +313,71 @@ async def _enable_all(self, ctx, *, target=None): @commands.has_guild_permissions(manage_guild=True) async def _enable_command(self, ctx, command, *, target=None): """ - Enable a command on the bot. Target can be a member, channel, or role. The command will be disabled for the target. If no target is specified, it will enable the command for the whole server. If the command contains a space you must "wrap it in quotes like this." + Enable a command on the bot. Target can be a member, channel, or role. + The command will be disabled for the target. If no target is specified, + it will enable the command for the whole server. If the command + contains a space you must "wrap it in quotes like this." """ - if not target is None: + query = target + target = None + the_for = '' + if query is not None: try: - target = await discord.ext.commands.MemberConverter().convert(ctx,target) + target = await discord.ext.commands.MemberConverter().convert( + ctx, query) except discord.ext.commands.errors.MemberNotFound: - try: - target = await discord.ext.commands.TextChannelConverter().convert(ctx,target) - except discord.ext.commands.errors.ChannelNotFound: - try: - target = await discord.ext.commands.RoleConverter().convert(ctx,target) - except discord.ext.commands.errors.RoleNotFound: - return await ctx.send(f'I couldnt find `{target}`') - the_for = ' for ' + target.mention + pass else: target = ctx.guild the_for = '' + if target is None: + try: + target = await discord.ext.commands.TextChannelConverter( + ).convert(ctx, query) + except discord.ext.commands.errors.ChannelNotFound: + pass + if target is None: + try: + target = await discord.ext.commands.RoleConverter().convert( + ctx, query) + except discord.ext.commands.errors.RoleNotFound: + return await ctx.send(f'I couldn\'t find `{query}`') + if the_for is None: + the_for = ' for ' + target.mention command = self.bot.get_command(command) try: assert command except AssertionError: - return await ctx.send(embed=ctx.error('That isnt a command!')) - embed = ctx.embed(title='Command Enabled', description=f'I will now stop ignoring the command {command.qualified_name}{the_for}.') + return await ctx.send(embed=ctx.error('That isn\'t a command!')) + embed = ctx.embed(title='Command Enabled', description=( + f'I will now stop ignoring the command {command.qualified_name}' + f'{the_for}.')) async with self.bot.pools.config.acquire() as connection: - data = await connection.fetchrow('SELECT * FROM serverconf WHERE id = $1', ctx.guild.id) + data = await connection.fetchrow( + 'SELECT * FROM serverconf WHERE id = $1', ctx.guild.id) if not data: - return await ctx.send(embed=ctx.error(f'`{command.qualified_name}` is not disabled{the_for}.')) + return await ctx.send(embed=ctx.error( + f'`{command.qualified_name}` is not disabled{the_for}.')) else: commands = data['commands'] if isinstance(commands, dict): commands[str(target.id)] = commands.get(str(target.id), []) else: - return await ctx.send(embed=ctx.error(f'Commands are not disabled{the_for}.')) + return await ctx.send(embed=ctx.error( + f'Commands are not disabled{the_for}.')) try: commands[str(target.id)].remove(command.qualified_name) - except: - return await ctx.send(embed=ctx.error(f'`{command.qualified_name}` is not disabled{the_for}.')) - await connection.execute('UPDATE serverconf SET commands = $1::json WHERE id = $2', commands, ctx.guild.id) + except ValueError: + return await ctx.send(embed=ctx.error( + f'`{command.qualified_name}` is not disabled{the_for}.' + )) + await connection.execute('''UPDATE serverconf + SET commands = $1::json WHERE id = $2''', commands, + ctx.guild.id) await self.bot.helpers.prepare(self.bot, ctx.guild) await ctx.send(embed=embed) + def setup(bot): bot.add_cog(Config(bot)) diff --git a/cogs/general.py b/cogs/general.py index 1a8738d..b6e4d21 100644 --- a/cogs/general.py +++ b/cogs/general.py @@ -3,13 +3,16 @@ ~~~~~~~~~~~~~~~~~~ This file contains elements that are under the following licenses: Copyright (c) 2015 Rapptz -license MIT, see https://github.com/Rapptz/RoboDanny/blob/e1c3c28fe20eb192463f7fc224a399141f0d915d/LICENSE.txt for more details. +license MIT, see +https://github.com/Rapptz/RoboDanny/blob/e1c3c28fe20eb192463f7fc224a399141f0d915d/LICENSE.txt +for more details. """ import discord import time import asyncio import re +import asyncpg import os import url_parser import inspect @@ -22,45 +25,50 @@ async def filter_links(bot, message): return if message.author.permissions_in(message.channel).manage_messages: return - regex = r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+' + regex = (r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*(),]|' + r'(?:%[0-9a-fA-F][0-9a-fA-F]))+') matches = re.findall(regex, message.content, re.MULTILINE) urls = [] for link in matches: try: - urls = [] #[url_parser.get_url(link)] #[''.join(url_parser.get_base_url(str(link)).split('//')[1:])] + urls = [] async with bot.http._HTTPClient__session.get(link) as resp: urls.append(url_parser.get_url(link)._asdict()) for redirect in resp.history: - urls.append(url_parser.get_url(redirect.real_url)._asdict()) - #str(''.join(url_parser.get_base_url(str(resp.real_url)).split('//')[1:]))) + urls.append( + url_parser.get_url(redirect.real_url)._asdict()) for url in urls: - for blocked in [ # "*" means any - # [http[s]://][sub.].[/path] # Reason - ######################################################################## - - '*.grabify.link/*', # Ip Grabber - '*.pornhub.com/*', # Porn + for blocked in [ # "*" means any + # [http[s]://][sub.].[/path] # Reason + ########################################################### + + '*.grabify.link/*', # Ip Grabber + '*.pornhub.com/*', # Porn ]: - parsed_blocked = url_parser.get_url(blocked.replace('*','-'))._asdict() + parsed_blocked = url_parser.get_url( + blocked.replace('*', '-'))._asdict() for k, v in parsed_blocked.items(): - if k in ['protocol', 'www', 'dir', 'file', 'fragment', 'query']: + if k in ['protocol', 'www', 'dir', 'file', 'fragment', + 'query']: continue if v == url[k]: continue if isinstance(v, str): - if v.replace('.','') == '-': + if v.replace('.', '') == '-': continue if k == 'path': if v[1:] == '-': continue - return + return await message.delete() - await message.channel.send(f':warning: {message.author.mention} That link is not allowed :warning:', delete_after=15) + await message.channel.send(( + f':warning: {message.author.mention} That link is not ' + 'allowed :warning:'), delete_after=15) return except Exception as e: print(e) - + async def filter_invite(bot, message, content=None): if message.author.permissions_in(message.channel).manage_messages: @@ -70,34 +78,40 @@ async def filter_invite(bot, message, content=None): 801641781028454420 ]: return - pattern = r"discord(?:(?:(?:app)?\.com)\/invite|\.gg)/([a-zA-z0-9\-]{2,})(?!\S)" - matches = re.findall(pattern,message.content, re.MULTILINE) + pattern = ( + r'discord(?:(?:(?:app)?\.com)\/invite|\.gg)/([a-zA-z0-9\-]{2,})(?!\S)') + matches = re.findall(pattern, message.content, re.MULTILINE) if len(matches) > 5: await message.delete() - await message.channel.send(f':warning: {message.author.mention} Invite links are not allowed :warning:', delete_after=15) + await message.channel.send(( + f':warning: {message.author.mention} Invite links are not allowed ' + ':warning:'), delete_after=15) return True for code in matches: try: invite = await bot.fetch_invite(code) except discord.errors.NotFound: - invite = None # invite is fine + invite = None # invite is fine if invite: - if not invite.guild.id in [message.guild.id, 681882711945641997, 782903894468198450]: + if invite.guild.id not in [message.guild.id, 681882711945641997, + 782903894468198450]: await message.delete() - await message.channel.send(f':warning: {message.author.mention} Invite links are not allowed :warning:', delete_after=15) + await message.channel.send(( + f':warning: {message.author.mention} Invite links are not ' + 'allowed :warning:'), delete_after=15) return True - + class General(commands.Cog): def __init__(self, bot): self.bot = bot - @commands.Cog.listener() async def on_message_edit(self, before, after): - if before.content != after.content: # invoke the command again if it is edited - ctx = await self.bot.get_context(after, cls=self.bot.helpers.Context) + if before.content != after.content: # invoke the command again on edit + ctx = await self.bot.get_context(after, + cls=self.bot.helpers.Context) await self.bot.invoke(ctx) if after.guild: if after.guild.id == 681882711945641997: @@ -112,7 +126,7 @@ async def on_message(self, message): invite = await filter_invite(self.bot, message) if not invite: await filter_links(self.bot, message) - + @commands.command(name="source", aliases=["github", "code"]) @commands.cooldown(1, 1, commands.BucketType.channel) async def _source(self, ctx, *, command: str = None): @@ -135,8 +149,6 @@ async def _source(self, ctx, *, command: str = None): if obj is None: return await ctx.send('Could not find command.') - # since we found the command we're looking for, presumably anyway, let's - # try to access the code itself src = obj.callback.__code__ module = obj.callback.__module__ filename = src.co_filename @@ -150,67 +162,96 @@ async def _source(self, ctx, *, command: str = None): source_url = 'https://github.com/Rapptz/discord.py' branch = 'master' - final_url = f'<{source_url}/blob/{branch}/{location}#L{firstlineno}-L{firstlineno + len(lines) - 1}>' - embed = ctx.embed(title='<:githubwhite:804344724621230091> GitHub <:githubwhite:804344724621230091>', description=f'[Click Here]({final_url})') + final_url = (f'<{source_url}/blob/{branch}/{location}#L{firstlineno}-L' + f'{firstlineno + len(lines) - 1}>') + github = '<:githubwhite:804344724621230091>' + embed = ctx.embed(title=f'{github} GitHub {github}', + description=f'[Click Here]({final_url})') await ctx.send(embed=embed) - @commands.command(name="mystbin",aliases=["mb"]) + @commands.command(name="mystbin", aliases=["mb"]) @commands.cooldown(1, 1, commands.BucketType.channel) async def _mystbin(self, ctx, *, code: codeblock_converter = None): - """Send your code to Mystb.in. You may use codeblocks, no codeblocks, or inside a file.""" + """Send your code to Mystb.in. You may use codeblocks if you want, + or use code from inside a file.""" code = code.content if code else None attachments = None if len(ctx.message.attachments) != 0: attachments = ctx.message.attachments elif ctx.message.reference: - message = await ctx.channel.fetch_message(ctx.message.reference.message_id) + message = await ctx.channel.fetch_message( + ctx.message.reference.message_id) attachments = message.attachments if attachments: for attachment in attachments: code = await attachment.read() if not code: - return await ctx.send(embed=ctx.error('Please either provide code in the command, attach a file, or react to a message that contains a file.')) - async with self.bot.http._HTTPClient__session.post('https://mystb.in/documents', data=code) as r: + return await ctx.send(embed=ctx.error(( + 'Please either provide code in the command, attach a file, or ' + 'react to a message that contains a file.'))) + async with self.bot.http._HTTPClient__session.post( + 'https://mystb.in/documents', data=code) as r: res = await r.json() key = res["key"] - embed = ctx.embed(title="Mystb.in Link", description='I pasted your code into a bin, click on the title access it!', url=f'https://mystb.in/{key}').set_thumbnail(url='https://cdn.discordapp.com/avatars/569566608817782824/14f120e096fb515d770eea38f9cddd88.png') + embed = ctx.embed(title="Mystb.in Link", description=( + 'I pasted your code into a bin, click on the title access it!'), + url=f'https://mystb.in/{key}') + embed.set_thumbnail(url=( + 'https://cdn.discordapp.com/avatars/569566608817782824/' + '14f120e096fb515d770eea38f9cddd88.png')) await ctx.send(embed=embed) @commands.command(name='ping') async def _ping(self, ctx): - embed = ctx.embed(title='PONG! :ping_pong:',description=f'** Websocket:** {(self.bot.latency * 1000):.2f}ms\n**:repeat: Round-Trip:** Calculating...\n**:elephant: Database:** Calculating...') + loading = '' + embed = ctx.embed(title='PONG! :ping_pong:', description=( + f'**<{loading} Websocket:** {(self.bot.latency * 1000):.2f}ms\n**' + ':repeat: Round-Trip:** Calculating...\n**:elephant: Database:** ' + 'Calculating...')) start = time.perf_counter() message = await ctx.send(embed=embed) await asyncio.sleep(0.5) end = time.perf_counter() trip = end - start - embed.description = f'** Websocket:** {(self.bot.latency * 1000):.2f}ms\n**:repeat: Round-Trip:** {(trip * 1000):.2f}ms\n**:elephant: Database:** Calcuating...' + embed.description = ( + f'**{loading} Websocket:** {(self.bot.latency * 1000):.2f}ms\n**' + f':repeat: Round-Trip:** {(trip * 1000):.2f}ms\n**:elephant: ' + 'Database:** Calculating...') await message.edit(embed=embed) await asyncio.sleep(0.5) start = time.perf_counter() try: async with self.bot.pools.config.acquire() as connection: - await connection.fetchval('SELECT prefixes FROM serverconf WHERE id = 0') + await connection.fetchval( + 'SELECT prefixes FROM serverconf WHERE id = 0') end = time.perf_counter() database = end - start - embed.description = f'** Websocket:** {(self.bot.latency * 1000):.2f}ms\n**:repeat: Round-Trip:** {(trip * 1000):.2f}ms\n**:elephant: Database:** {(database * 1000):.2f}ms' - except: - embed.description = f'** Websocket:** {(self.bot.latency * 1000):.2f}ms\n**:repeat: Round-Trip:** {(trip * 1000):.2f}ms\n**:elephant: Database:** *Did not respond!*' + embed.description = ( + f'**{loading} Websocket:** {(self.bot.latency * 1000):.2f}ms\n' + f'**:repeat: Round-Trip:** {(trip * 1000):.2f}ms\n**:elephant:' + f' Database:** {(database * 1000):.2f}ms') + except asyncpg.exceptions._base.InterfaceError: + embed.description = ( + f'**<{loading} Websocket:** {(self.bot.latency * 1000):.2f}ms' + f'\n**:repeat: Round-Trip:** {(trip * 1000):.2f}ms\n**' + ':elephant: Database:** *Did not respond!*') await message.edit(embed=embed) - - @commands.command(name='revive', aliases=['revivechat', 'chatrevive', 'revchat', 'chatrev']) + + @commands.command(name='revive', aliases=['revivechat', 'chatrevive', + 'revchat', 'chatrev']) @commands.guild_only() @commands.cooldown(1, 1800, commands.BucketType.guild) - @commands.has_any_role(729530191109554237, 795136568805294097, 725899526350831616) + @commands.has_any_role(729530191109554237, 795136568805294097, + 725899526350831616) # Senior Mod + async def _revive(self, ctx): - try: - mention = ctx.guild.get_role(759219083639783448).mention - except: - mention = f'<@&759219083639783448>' - embed = ctx.embed(title='Revive Chat Ping!', description='Come back to chat and make it alive again!') + mention = ctx.guild.get_role(759219083639783448).mention + embed = ctx.embed( + title='Revive Chat Ping!', + description='Come back to chat and make it alive again!') await ctx.send(content=mention, embed=embed) + def setup(bot): bot.add_cog(General(bot)) diff --git a/cogs/help.py b/cogs/help.py index 1c11788..c1b7225 100644 --- a/cogs/help.py +++ b/cogs/help.py @@ -1,9 +1,9 @@ -import discord import re import datetime import asyncio from discord.ext import commands + class Help(commands.Cog): def __init__(self, bot): @@ -13,7 +13,8 @@ def __init__(self, bot): async def callstaff_check(self): if self.guild: if self.guild.id == 681882711945641997: - if (datetime.datetime.utcnow() - self.author.joined_at).days > 1: + if (datetime.datetime.utcnow() + - self.author.joined_at).days > 1: return True return False @@ -22,23 +23,25 @@ async def helper_check(self): if self.guild: if self.guild.id == 681882711945641997: if self.channel.id in [ - 767641462179233792, # help-a - 767641487210315796, # help-b - 767641504092913674, # help-c - 776272365223018516, # help-d - 776272386856583178, # help-e - 797861120185991198, # exclusive-help - 681892318915330084, # python - 731170873221972049, # java - 681893466682425407, # javascript - 681892921074778184, # html-css-php - 725880738293219479, # c-cpp-cs - 726028249922273351, # discord-py - 726028289939996713 # discord-js + 767641462179233792, # help-a + 767641487210315796, # help-b + 767641504092913674, # help-c + 776272365223018516, # help-d + 776272386856583178, # help-e + 797861120185991198, # exclusive-help + 681892318915330084, # python + 731170873221972049, # java + 681893466682425407, # javascript + 681892921074778184, # html-css-php + 725880738293219479, # c-cpp-cs + 726028249922273351, # discord-py + 726028289939996713, # discord-js ]: return True - # if self.guild.get_role(726029173067481129) in self.author.roles: - # if (datetime.datetime.utcnow() - self.author.joined_at).days > 7: + # active = self.guild.get_role(726029173067481129) + # if active in self.author.roles: + # if (datetime.datetime.utcnow() + # - self.author.joined_at).days > 7: # return True return False @@ -48,7 +51,8 @@ async def helper_check(self): @commands.cooldown(1, 1800, commands.BucketType.user) async def helper(self, ctx, language=None, *, description=None): """ - Request help for your code. Misusing this command may result in a punishment. + Request help for your code. Misusing this command may result in a + punishment. """ roles = { 'Python': 807098700589301791, @@ -60,41 +64,45 @@ async def helper(self, ctx, language=None, *, description=None): 'Other': 806920884441972767 } if not language: - msg = await ctx.send(embed=ctx.embed(title='What would you like help with?', description=f'**Options:** `{"`, `".join(roles)}`')) - check = lambda m: m.channel == ctx.channel and m.author == ctx.author + msg = await ctx.send(embed=ctx.embed( + title='What would you like help with?', + description=f'**Options:** `{"`, `".join(roles)}`')) + + def check(m): + return m.channel == ctx.channel and m.author == ctx.author try: - message = await self.bot.wait_for('message', check=check, timeout=30) + message = await self.bot.wait_for( + 'message', check=check, timeout=30) await msg.delete() except asyncio.TimeoutError: ctx.command.reset_cooldown(ctx) return await ctx.send(embed=ctx.error('Timed out!')) language = message.clean_content - language.replace('py','python').replace('js','javascript').replace('cpp','c++').replace('csharp','c#').replace('html','HTML/CSS').replace('css','HTML/CSS') rep = { "Python": [ - "python", - 'py' - ], + "python", + 'py', + ], "JavaScript": [ - "javascript", - 'js' - ], + "javascript", + 'js', + ], 'Java': 'java', 'C++': [ - 'cpp', - 'c++' - ], + 'cpp', + 'c++', + ], 'C#': [ - 'csharp', + 'csharp', 'c#', - 'cs' - ], + 'cs', + ], 'HTML/CSS': [ - 'html', - 'css', - 'html/css' + 'html', + 'css', + 'html/css', ], - 'Other': 'other' + 'Other': 'other', } items = [] for k, v in rep.items(): @@ -103,24 +111,32 @@ async def helper(self, ctx, language=None, *, description=None): items.append((k, e)) else: items.append((k, v)) - rep = dict((re.escape(v), k) for k, v in items) + rep = dict((re.escape(v), k) for k, v in items) pattern = re.compile("|".join(rep.keys())) - language = pattern.sub(lambda m: rep[re.escape(m.group(0))], language.lower()) - if not language in roles: + language = pattern.sub(lambda m: rep[re.escape(m.group(0))], + language.lower()) + if language not in roles: ctx.command.reset_cooldown(ctx) - return await ctx.send(embed=ctx.error('That is not a valid help role, please try again')) + return await ctx.send(embed=ctx.error( + 'That is not a valid help role, please try again')) try: guild = self.bot.get_guild(681882711945641997) channel = guild.get_channel(814129029236916274) mention = guild.get_role(roles[language]).mention - except: + except AttributeError: channel = self.bot.get_channel(814129029236916274) mention = '<@&{}>'.format(roles[language]) if not description: - message = await ctx.send(embed=ctx.embed('Please give a short description of what you need help with. (10-100 characters)', title='What do you need help with?')) - check = lambda m: m.channel == message.channel and m.author.id == ctx.author.id + message = await ctx.send(embed=ctx.embed(( + 'Please give a short description of what you need help with. ' + '(10-100 characters)'), + title='What do you need help with?')) + + def check(m): + return m.channel == message.channel and m.author == ctx.author try: - msg = await self.bot.wait_for('message', check=check, timeout=30) + msg = await self.bot.wait_for('message', check=check, + timeout=30) description = msg.content await message.delete() await msg.delete() @@ -129,16 +145,28 @@ async def helper(self, ctx, language=None, *, description=None): return await ctx.send(embed=ctx.error('Timed out!')) if len(description) < 10 or len(description) > 100: ctx.command.reset_cooldown(ctx) - return await ctx.send(embed=ctx.error('Your reason must be 10-100 total characters')) + return await ctx.send(embed=ctx.error( + 'Your reason must be 10-100 total characters')) if not description.isascii(): ctx.command.reset_cooldown(ctx) return await ctx.send(embed=ctx.error('Invalid description')) - message = await ctx.send(embed=ctx.embed(f'Are you sure that you want to ping for {language} help? By reacting to this message you confirm that you have read <#799527165863395338> and <#754712400757784709>, and that you will follow them. Failure to follow the help rules may result in a punishment from the moderation team. Failure to follow the "how to get help" instructions may result in you not being helped.',title='Please Confirm')) + message = await ctx.send(embed=ctx.embed(( + f'Are you sure that you want to ping for {language} help? By ' + 'reacting to this message you confirm that you have read ' + '<#799527165863395338> and <#754712400757784709>, and that you ' + 'will follow them. Failure to follow the help rules may result in ' + 'a punishment from the moderation team. Failure to follow the "how' + ' to get help" instructions may result in you not being helped.'), + title='Please Confirm')) await message.add_reaction('\U00002705') await message.add_reaction('\U0000274c') - check = lambda reaction, user: str(reaction.emoji) in ['\U00002705', '\U0000274c'] and user.id == ctx.author.id + + def check(reaction, user): + return (str(reaction.emoji) in ['\U00002705', '\U0000274c'] + and user.id == ctx.author.id) try: - reaction, user = await self.bot.wait_for('reaction_add', check=check, timeout=30) + reaction, user = await self.bot.wait_for('reaction_add', + check=check, timeout=30) except asyncio.TimeoutError: ctx.command.reset_cooldown(ctx) return await ctx.send(embed=ctx.error('Timed out!')) @@ -146,19 +174,34 @@ async def helper(self, ctx, language=None, *, description=None): if str(reaction.emoji) == '\U0000274c': ctx.command.reset_cooldown(ctx) return await ctx.send(embed=ctx.embed(title='Cancelled!')) - await channel.send(content=mention, embed=ctx.embed('[Click Here]({0.message.jump_url}) to help {0.author.mention}'.format(ctx), title=f'{language} Help').add_field(name='Description',value=description)) - await ctx.send(embed=ctx.embed('Submitted your request for help. Please keep in mind that our helpers are human and may not be available immediately.', title='Success')) + embed = ctx.embed(( + '[Click Here]({0.message.jump_url}) to help {0.author.mention}' + ).format(ctx), title=f'{language} Help' + ) + embed.add_field(name='Description', value=description) + await channel.send(content=mention, + embed=embed) + await ctx.send(embed=ctx.embed(( + 'Submitted your request for help. Please keep in mind that our ' + 'helpers are human and may not be available immediately.'), + title='Success')) @commands.command(name='callstaff') - @commands.is_owner() # disabled for now + @commands.is_owner() # disabled for now @callstaff_check - @commands.cooldown(1, 600, commands.BucketType.user) # ten minute cooldown + @commands.cooldown(1, 600, commands.BucketType.user) # ten minute cooldown async def _callstaff(self, ctx, reason=None): """ - Request help in chat from staff. For less important issues, please @mention a single online staff member, and only use this command for larger issues such as raid, NSFW, staff abusing powers, etc. + Request help in chat from staff. For less important issues, please + @mention a single online staff member, and only use this command for + larger issues such as raid, NSFW, staff abusing powers, etc. """ - message = await ctx.send(embed=ctx.embed('Please give a short reason of why are calling staff. (10-100 characters)', title='Reason')) - check = lambda m: m.channel == message.channel and m.author.id == ctx.author.id + message = await ctx.send(embed=ctx.embed(( + 'Please give a short reason of why are calling staff. (10-100 ' + 'characters)'), title='Reason')) + + def check(m): + return m.channel == message.channel and m.author == ctx.author try: msg = await self.bot.wait_for('message', check=check, timeout=30) reason = msg.content @@ -169,19 +212,31 @@ async def _callstaff(self, ctx, reason=None): return await ctx.send(embed=ctx.error('Timed out!')) if len(reason) < 10 or len(reason) > 100: ctx.command.reset_cooldown(ctx) - return await ctx.send(embed=ctx.error('Your reason must be 10-100 total characters')) + return await ctx.send(embed=ctx.error( + 'Your reason must be 10-100 total characters')) if not reason.isascii(): ctx.command.reset_cooldown(ctx) return await ctx.send(embed=ctx.error('Invalid reason')) - channel = ctx.guild.get_channel(725747936776159243) # staff chat for now, will change later most likely + channel = ctx.guild.get_channel(725747936776159243) # staff chat rn mention = ctx.guild.get_role(681895900070543411).mention - message = await ctx.send(embed=ctx.embed(f'Are you sure that you want to request staff help? We always want to help keep our server friendly for everyone, so we will be glad to help. However, using this command without a valid reason or misusing it can and will result in a punishment. For less important issues, please @mention a single online staff member, and only use this command for larger issues such as raid, NSFW, staff abusing powers, etc.',title='Please Confirm')) + message = await ctx.send(embed=ctx.embed(( + 'Are you sure that you want to request staff help? We always want' + ' to help keep our server friendly for everyone, so we will be ' + 'glad to help. However, using this command without a valid reason ' + 'or misusing it can and will result in a punishment. For less ' + 'important issues, please @mention a single online staff member, ' + 'and only use this command for larger issues such as raid, NSFW, ' + 'staff abusing powers, etc.'), title='Please Confirm')) await message.add_reaction('\U00002705') await message.add_reaction('\U0000274c') - check = lambda reaction, user: str(reaction.emoji) in ['\U00002705', '\U0000274c'] and user.id == ctx.author.id + + def check(reaction, user): + return (str(reaction.emoji) in ['\U00002705', '\U0000274c'] + and user.id == ctx.author.id) try: - reaction, user = await self.bot.wait_for('reaction_add', check=check, timeout=30) + reaction, user = await self.bot.wait_for('reaction_add', + check=check, timeout=30) except asyncio.TimeoutError: ctx.command.reset_cooldown(ctx) return await ctx.send(embed=ctx.error('Timed out!')) @@ -189,15 +244,20 @@ async def _callstaff(self, ctx, reason=None): if str(reaction.emoji) == '\U0000274c': ctx.command.reset_cooldown(ctx) return await ctx.send(embed=ctx.embed(title='Cancelled!')) - try: - message = await channel.send(content=f'`{mention}`', embed=ctx.embed('{0.author.mention} is requesting assistance in {0.channel.mention}. [Click Here]({0.message.jump_url}) to help them, and react with \U00002705 when the situation is **completely** under control.'.format(ctx), title='Report Submitted').add_field(name='Reason',value=reason)) - except: - message = await ctx.send(content=f'`{mention}`', embed=ctx.embed('{0.author.mention} is requesting assistance in {0.channel.mention}. [Click Here]({0.message.jump_url}) to help them, and react with \U00002705 when the situation is **completely** under control.'.format(ctx), title='Report Submitted').add_field(name='Reason',value=reason)) # because bot might not have perms to talk there. - # neither of the messages above actually pings mods for now + message = await channel.send( + content=f'`{mention}`', # Not pinging mods for now until its done + embed=ctx.embed(( + '{0.author.mention} is requesting assistance in ' + '{0.channel.mention}. [Click Here]({0.message.jump_url}) to ' + 'help them, and react with \U00002705 when the situation is **' + 'completely** under control.').format(ctx), + title='Report Submitted').add_field(name='Reason', + value=reason)) await message.add_reaction('\U00002705') - await ctx.send(embed=ctx.embed('Submitted your request for a moderator.', title='Success')) + await ctx.send(embed=ctx.embed( + 'Submitted your request for a moderator.', + title='Success')) + - - def setup(bot): bot.add_cog(Help(bot)) diff --git a/cogs/owner.py b/cogs/owner.py index 5069132..2348d9d 100644 --- a/cogs/owner.py +++ b/cogs/owner.py @@ -7,6 +7,7 @@ from discord.ext import commands from jishaku.codeblocks import codeblock_converter + class Owner(commands.Cog): def __init__(self, bot): @@ -17,42 +18,59 @@ async def _eval(self, ctx, *, code: codeblock_converter): """Eval some code""" cog = self.bot.get_cog("Jishaku") await cog.jsk_python(ctx, argument=code) - + @commands.command(name='refresh') async def _refresh(self, ctx): """Refresh the bot by invoking `jsk git pull` and `restart`""" cog = self.bot.get_cog("Jishaku") await cog.jsk_git(ctx, argument=codeblock_converter('pull')) - await asyncio.sleep(2) # allow jsk git pull to finish before restarting + await asyncio.sleep(2) # allow jsk git pull to finish restart = self.bot.get_command('restart') await ctx.invoke(restart) @commands.command(name='restart') async def _restart(self, ctx, flag=None): """ - Restart the bot. Will wait for any running commands to stop. Use --force to ignore any running commands and proceed with the restart + Restart the bot. Will wait for any running commands to stop (if + --force is not used). """ if not (flag == '--force' or flag == '-f'): if self.bot.processing_commands > 1: - embed = discord.Embed(title='Commands in progress...', description=f'Retrying in 30 seconds. Use `{ctx.prefix}restart --force` to force restart.', timestamp=ctx.message.created_at) - embed.set_footer(text=f'{self.bot.processing_commands - 1} commands currently in progess') + embed = discord.Embed( + title='Commands in progress...', + description=(f'Retrying in 30 seconds. Use `{ctx.prefix}' + 'restart --force` to force restart.'), + timestamp=ctx.message.created_at) + embed.set_footer(text=(f'{self.bot.processing_commands - 1} ' + 'commands currently in progess')) await ctx.send(embed=embed) for i in range(10): await asyncio.sleep(30) if self.bot.processing_commands > 1: - embed = discord.Embed(title='Commands in progress...', description=f'Retrying in 30 seconds. Use `{ctx.prefix}restart --force` to force restart.', timestamp=ctx.message.created_at) - embed.set_footer(text=f'{self.bot.processing_commands - 1} commands currently in progess') + embed = discord.Embed( + title='Commands in progress...', + description=('Retrying in 30 seconds. Use `' + f'{ctx.prefix}restart --force` to ' + 'force restart.'), + timestamp=ctx.message.created_at) + embed.set_footer( + text=(f'{self.bot.processing_commands - 1} ' + 'commands currently in progess') + ) await ctx.send(embed=embed) else: break if self.bot.processing_commands > 1: - embed = discord.Embed(title='Restart Failed', description=f'{self.bot.processing_commands - 1} commands currently in progess. Use `{ctx.prefix}restart --force` to force restart.', timestamp=ctx.message.created_at) + embed = discord.Embed(title='Restart Failed', description=( + f'{self.bot.processing_commands - 1} commands ' + f'currently in progess. Use `{ctx.prefix}restart ' + '--force` to force restart.'), + timestamp=ctx.message.created_at) return await ctx.send(embed=embed) embed = discord.Embed(title="Be right back!") await ctx.send(embed=embed) self.bot.helpers.storage(self.bot, 'restart_channel', ctx.channel.id) - if sys.stdin.isatty(): # if the bot was run from the command line instead of from systemctl - # os.execv('sudo python', sys.argv) os.path.abspath(__file__) + if sys.stdin.isatty(): # if the bot was run from the command line try: p = psutil.Process(os.getpid()) for handler in p.open_files() + p.connections(): @@ -65,18 +83,28 @@ async def _restart(self, ctx, flag=None): embed = ctx.error('Failed to restart') await ctx.send(embed=embed) - @commands.command(name='shutdown',aliases=['off','die','shut','kill']) + @commands.command(name='shutdown', aliases=['off', 'die', 'shut', 'kill']) async def _shutdown(self, ctx, flag=None): if flag == '--wait' or flag == '-w': if self.bot.processing_commands > 1: - embed = discord.Embed(title='Commands in progress...', description=f'Retrying in 30 seconds.', timestamp=ctx.message.created_at) - embed.set_footer(text=f'{self.bot.processing_commands - 1} commands currently in progess') + embed = discord.Embed(title='Commands in progress...', + description='Retrying in 30 seconds.', + timestamp=ctx.message.created_at) + embed.set_footer(text=( + f'{self.bot.processing_commands - 1} commands currently ' + 'in progess')) await ctx.send(embed=embed) for i in range(10): await asyncio.sleep(30) if self.bot.processing_commands > 1: - embed = discord.Embed(title='Commands in progress...', description=f'Retrying in 30 seconds.', timestamp=ctx.message.created_at) - embed.set_footer(text=f'{self.bot.processing_commands - 1} commands currently in progess') + embed = discord.Embed( + title='Commands in progress...', + description='Retrying in 30 seconds.', + timestamp=ctx.message.created_at + ) + embed.set_footer( + text=(f'{self.bot.processing_commands - 1} ' + 'commands currently in progess')) await ctx.send(embed=embed) else: break @@ -85,27 +113,40 @@ async def _shutdown(self, ctx, flag=None): await self.bot.logout() else: if len(sys.argv) > 1: - os.system(f"sudo {'stoprewrite' if sys.argv[1] == 'rewrite' else 'stopmain'}") + if sys.argv[1] == 'rewrite': + query = 'stoprewrite' + else: + query = 'stopmain' + os.system(f"sudo {query}") await asyncio.sleep(1) - await ctx.send(embed=ctx.error('Failed to stop systemd service, attempting to shut down both services')) - os.system(f'sudo stopall') + await ctx.send(embed=ctx.error(( + 'Failed to stop systemd service, attempting to shut down both ' + 'services' + ))) + os.system('sudo stopall') await asyncio.sleep(1) - await ctx.send(embed=ctx.error('Failed to stop systemd service, attempting to logout normally')) + await ctx.send(embed=ctx.error(( + 'Failed to stop systemd service, attempting to logout normally' + ))) await self.bot.logout() @commands.command(name='disable') async def _disable(self, ctx, toggle: bool = None): """ - Disable the bot in case of an exploit, major bug, or other emergency. The bot will remain online, but only bot owners will be able to run commands on it + Disable the bot in case of an exploit, major bug, or other emergency. + The bot will remain online, but only bot owners will be able to run + commands on it. """ self.bot.disabled = not self.bot.disabled if toggle is None else toggle embed = ctx.embed(title='Bot Status', timestamp=ctx.message.created_at) - embed.add_field(name='Disabled',value=self.bot.disabled) - self.bot.helpers.storage(self.bot, key='disabled', value=self.bot.disabled) + embed.add_field(name='Disabled', value=self.bot.disabled) + self.bot.helpers.storage(self.bot, key='disabled', + value=self.bot.disabled) await ctx.send(embed=embed) async def cog_check(self, ctx): return ctx.author.id in self.bot.owner_ids + def setup(bot): bot.add_cog(Owner(bot)) diff --git a/ext/helpers.py b/ext/helpers.py index 82061cb..9b91dc3 100644 --- a/ext/helpers.py +++ b/ext/helpers.py @@ -5,16 +5,13 @@ import datetime import asyncpg import asyncio -import discord -import inspect from discord.ext import commands -from discord_slash import SlashContext as SlashCtx class Bot(commands.Bot): async def logout(self, *args, **kwargs): - if hasattr(self.pools,'config'): + if hasattr(self.pools, 'config'): try: await asyncio.wait_for(self.pools.config.close(), timeout=5) except Exception as e: @@ -24,30 +21,34 @@ async def logout(self, *args, **kwargs): await asyncio.wait_for(self.sr_api.close(), timeout=5) except Exception as e: print(e) - if hasattr(self,'wavelink'): + if hasattr(self, 'wavelink'): if not self.wavelink.session.closed: - await asyncio.wait_for(self.wavelink.session.close(), timeout=5) + await asyncio.wait_for(self.wavelink.session.close(), + timeout=5) await super().logout(*args, **kwargs) + class Embed(discord.Embed): def __repr__(self): return self.description or '' + class Context(commands.Context): Embed = Embed - def embed(self, description=None, *args,**kwargs): + def embed(self, description=None, *args, **kwargs): default = { 'timestamp': self.message.created_at, 'description': description } default.update(kwargs) - return_embed = self.Embed(*args,**default) - return_embed.set_footer(icon_url=self.author.avatar_url,text=f'Requested by {self.author}') + return_embed = self.Embed(*args, **default) + return_embed.set_footer(icon_url=self.author.avatar_url, + text=f'Requested by {self.author}') return return_embed - def error(self, description=None, *args,**kwargs): + def error(self, description=None, *args, **kwargs): default = { 'title': 'Error', 'color': discord.Color.red(), @@ -55,9 +56,12 @@ def error(self, description=None, *args,**kwargs): 'description': description } default.update(kwargs) - return_embed = self.Embed(*args,**default) - return_embed.set_author(name=self.author,icon_url=self.author.avatar_url) - return_embed.set_footer(icon_url=self.bot.user.avatar_url,text=f'If you think this is a mistake please contact {self.bot.get_user(self.bot.owner_ids[0])}') + return_embed = self.Embed(*args, **default) + return_embed.set_author(name=self.author, + icon_url=self.author.avatar_url) + return_embed.set_footer(icon_url=self.bot.user.avatar_url, text=( + 'If you think this is a mistake please contact ' + f'{self.bot.get_user(self.bot.owner_ids[0])}')) return return_embed @@ -69,44 +73,51 @@ async def init_connection(connection): schema='pg_catalog' ) + def storage(bot, key=None, value=None, method=None, override=False): try: - with open('./storage/config.json','r') as f: + with open('./storage/config.json', 'r') as f: data = json.load(f) - except: - with open('./storage/config.json','w+') as f: + except OSError: + with open('./storage/config.json', 'w+') as f: f.write('{}') - with open('./storage/config.json','r') as f: + with open('./storage/config.json', 'r') as f: data = json.load(f) data['cogs'] = data.get('cogs', []) data['blacklisted'] = data.get('blacklisted', []) data['disabled'] = data.get('disabled', False) - data['owners'] = data.get('owners', [int(bot.default_owner) if bot.default_owner else 690420846774321221]) + if bot.default_owner: + temp_owner = int(bot.default_owner) + else: + temp_owner = 690420846774321221 + data['owners'] = data.get('owners', [temp_owner]) bot.restart_channel = data.get('restart_channel', None) data['restart_channel'] = None if key and value: if method == 'append': - if not value in data[key] or override: + if value not in data[key] or override: data[key].append(value) elif method == 'remove': if value in data[key] or override: data[key].remove(value) else: data[key] = value - with open('./storage/config.json','w') as f: - json.dump(data,f,indent=4) + with open('./storage/config.json', 'w') as f: + json.dump(data, f, indent=4) return data + async def prepare(bot, guild=None): try: connection = await bot.pools.config.acquire() await bot.pools.config.release(connection) - except: + except asyncpg.exceptions._base.InterfaceError: try: - bot.pools.config = await asyncio.wait_for(asyncpg.create_pool(database='codingbot_db', init=init_connection), timeout=5) + bot.pools.config = await asyncio.wait_for(asyncpg.create_pool( + database='codingbot_db', init=init_connection), timeout=5) connection = await bot.pools.config.acquire() await bot.pools.config.release(connection) - except: + except (OSError, asyncpg.exceptions._base.InterfaceError): if guild: bot.server_cache[guild.id] = bot.server_cache.get(guild.id, { 'prefixes': bot.default_prefixes.copy(), @@ -122,7 +133,8 @@ async def prepare(bot, guild=None): prefixes text[] ); ''') - data = await connection.fetchrow('SELECT * FROM serverconf WHERE id = $1', guild.id) + data = await connection.fetchrow( + 'SELECT * FROM serverconf WHERE id = $1', guild.id) bot.server_cache[guild.id] = bot.server_cache.get(guild.id, { 'prefixes': bot.default_prefixes.copy(), 'commands': {} @@ -133,24 +145,28 @@ async def prepare(bot, guild=None): if isinstance(data['commands'], dict): bot.server_cache[guild.id]['commands'] = data['commands'] + async def is_disabled(ctx): if not ctx.guild: return False try: data = ctx.bot.server_cache[ctx.guild.id].copy() - except: + except KeyError: await prepare(ctx.bot, ctx.guild) try: data = ctx.bot.server_cache[ctx.guild.id].copy() - except: + except KeyError: data = {} - ids_to_check = [ctx.guild.id, ctx.channel.id, ctx.author.id] + [r.id for r in ctx.author.roles] + ids_to_check = [ctx.guild.id, ctx.channel.id, ctx.author.id] + ids_to_check += [r.id for r in ctx.author.roles] for id_ in ids_to_check: data[int(id_)] = data.get(int(id_), []) - if True in data[int(id_)] or ctx.command.qualified_name in data[int(id_)]: + if (True in data[int(id_)] + or ctx.command.qualified_name in data[int(id_)]): return True return False + async def prefix(bot, message): return_prefixes = bot.default_prefixes.copy() if not message.guild: @@ -158,47 +174,58 @@ async def prefix(bot, message): else: try: data = bot.server_cache[message.guild.id]['prefixes'] - except: + except KeyError: try: - bot.server_cache[message.guild.id] = bot.server_cache.get(message.guild.id, { - 'prefixes': return_prefixes, - 'commands': {} - }) + bot.server_cache[message.guild.id] = bot.server_cache.get( + message.guild.id, { + 'prefixes': return_prefixes, + 'commands': {} + }) bot.loop.create_task(prepare(bot, message.guild)) data = bot.server_cache[message.guild.id]['prefixes'] - except: + except KeyError: data = bot.default_prefixes return_prefixes = data or return_prefixes return return_prefixes -async def log_command_error(ctx,error,handled): +async def log_command_error(ctx, error, handled): if not handled: channel = ctx.bot.get_channel(787461422896513104) else: channel = ctx.bot.get_channel(787476834689744926) title = 'Ignoring exception in command {}:'.format(ctx.command) - err = ''.join(traceback.format_exception(type(error), error, error.__traceback__)) + err = ''.join(traceback.format_exception( + type(error), error, error.__traceback__)) try: - embed = discord.Embed(title=title,description=f'```py\n{err}```',timestamp=ctx.message.created_at,color=discord.Color.red()).set_author(name=ctx.author,icon_url=ctx.author.avatar_url) + embed = discord.Embed(title=title, description=f'```py\n{err}```', + timestamp=ctx.message.created_at, + color=discord.Color.red()) + embed.set_author(name=ctx.author, icon_url=ctx.author.avatar_url) await channel.send(embed=embed) - except: + except discord.errors.Forbidden: try: - await channel.send(f"**<@{ctx.bot.owner_ids[0]}> An error occurred but I couldn't log it here**") - except: + await channel.send((f"**<@{ctx.bot.owner_ids[0]}> An error " + "occurred but I couldn't log it here**")) + except discord.errors.Forbidden: pass - print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr) - traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr) + print('Ignoring exception in command {}:'.format(ctx.command), + file=sys.stderr) + traceback.print_exception(type(error), error, error.__traceback__, + file=sys.stderr) finally: return + async def log_error(bot, event_method, *args, **kwargs): channel = bot.get_channel(812359854890156073) try: title = 'Ignoring exception in {}'.format(event_method) err = ''.join(traceback.format_exc()) - embed = discord.Embed(title=title,description=f'```py\n{err}```',timestamp=datetime.datetime.utcnow(),color=discord.Color.red()) + embed = discord.Embed(title=title, description=f'```py\n{err}```', + timestamp=datetime.datetime.utcnow(), + color=discord.Color.red()) await channel.send(embed=embed) - except: + except discord.errors.Forbidden: print('Ignoring exception in {}'.format(event_method), file=sys.stderr) traceback.print_exc() diff --git a/requirements.txt b/requirements.txt index 8b9544e..904b212 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,5 @@ DiscordUtils pytest aiosqlite_pool.zip time-str -discord-flags \ No newline at end of file +discord-flags +url-parser \ No newline at end of file diff --git a/test.py b/test.py index a268d4b..5cc9a74 100644 --- a/test.py +++ b/test.py @@ -1,5 +1,5 @@ -import pytest import bot + def test(token): bot.bot.run(token)