async def cog_overrides(self, ctx): """cog_overrides_help""" if ctx.invoked_subcommand is self.cog_overrides: overrides = Configuration.get_var(ctx.guild.id, "PERM_OVERRIDES") desc = "" for k, v in overrides.items(): lvl = v["required"] if lvl >= 0: desc += f"{k}: {lvl} ({Translator.translate(f'perm_lvl_{lvl}', ctx)})\n" if desc == "": desc = Translator.translate('no_overrides', ctx) embed = discord.Embed(color=6008770, title=Translator.translate('cog_overrides', ctx), description=desc) await ctx.send(embed=embed)
async def dismiss_raid(self, channel, raid_info): """Dismiss raid as false alarm, will also remove the mute role from all of them again""" await channel.send("Dismissing raid") targets = [m for m in raid_info["TODO"]] failures = [] # terminate raid if channel.guild.id in self.under_raid: await self._terminate_raid(channel.guild, dismised=True) message = await channel.send("Unmuting people...") # remove mute role from people who have been detected for target in targets: member = channel.guild.get_member(target) if member is not None: role = member.guild.get_role( Configuration.get_var(member.guild.id, "MUTE_ROLE")) if role is not None: try: await member.remove_roles( role, reason="Raid alarm dismissed") raid_info['RAIDERS'][str( target)]["state"] = "Dismissed" except discord.HTTPException: failures.append(str(target)) await channel.send(f"{len(targets) - len(failures)} have been unmuted") if len(failures) > 0: people = '\n'.join(failures) out = f"Failed to unmute the following people:\n{people}" for page in Utils.paginate(out): await channel.send(page) # notify it was just a false alarm so they can stand down for other_guild in self.bot.guilds: if other_guild != channel.guild: new_channel = self.bot.get_channel( Configuration.get_var(other_guild.id, f"MOD_CHANNEL")) if new_channel is not None: await new_channel.send( f"Raid over at {channel.guild} turned out to not be an actual raid and has been dismissed." )
async def cat(self, ctx): """cat_help""" await ctx.trigger_typing() future_fact = self.get_json("https://animal.gearbot.rocks/cat/fact") key = Configuration.get_master_var("CAT_KEY", "") future_cat = self.get_json( "https://api.thecatapi.com/v1/images/search?limit=1&size=full", {'x-api-key': key}) fact_json, cat_json = await asyncio.gather(future_fact, future_cat) embed = discord.Embed(description=fact_json["content"]) if key != "": embed.set_image(url=cat_json[0]["url"]) await ctx.send(embed=embed)
async def on_guild_update(before, after): if after.owner is not None and after.owner.id in Configuration.get_persistent_var( "user_blacklist", []): GearbotLogging.info( f"Someone transferred {after.name} ({after.id}) to ({after.owner} ({after.owner.id})) but they are blacklisted" ) try: await after.owner.send( f"Someone transferred {after.name} (``{after.id}``) to you, but you have been blacklisted due to bot abuse, so i left" ) except Exception: pass await after.leave()
def check_permission(ctx: commands.Context): if ctx.guild is None: return 0 >= get_required(ctx, ctx.cog.permissions) else: overrides = Configuration.get_var(ctx.guild.id, "PERM_OVERRIDES") cog_name = type(ctx.cog).__name__ required = -1 if cog_name in overrides: required = get_required(ctx, overrides[cog_name]) if required == -1: required = get_required(ctx, ctx.cog.permissions) return get_user_lvl(ctx) >= (ctx.cog.permissions["required"] if required == -1 else required)
async def on_raw_bulk_message_delete( self, event: discord.RawBulkMessageDeleteEvent): channel_id = Configuration.getConfigVar(event.guild_id, "MINOR_LOGS") if channel_id is not 0: message_list = dict() for mid in event.message_ids: message = LoggedMessage.get_or_none( LoggedMessage.messageid == mid) if message is not None: message_list[mid] = message await Archive.archive( self.bot, event.guild_id, collections.OrderedDict(sorted(message_list.items())))
async def on_message(self, message: discord.Message): if message.author.bot or message.webhook_id is not None: return if not hasattr(message.channel, "guild") or message.channel.guild is None: return me = message.guild.me if me is None: me = Utils.get_member(self.bot, message.guild, self.bot.user.id) permissions = message.channel.permissions_for(me) if me is None: return if not (permissions.read_messages and permissions.send_messages and permissions.embed_links): return role_list = Configuration.get_var(message.guild.id, "CUSTOM_COMMANDS", "ROLES") role_required = Configuration.get_var(message.guild.id, "CUSTOM_COMMANDS", "ROLE_REQUIRED") channel_list = Configuration.get_var(message.guild.id, "CUSTOM_COMMANDS", "CHANNELS") channels_ignored = Configuration.get_var(message.guild.id, "CUSTOM_COMMANDS", "CHANNELS_IGNORED") mod_bypass = Configuration.get_var(message.guild.id, "CUSTOM_COMMANDS", "MOD_BYPASS") is_mod = message.author is not None and Permissioncheckers.is_mod(message.author) if (message.channel.id in channel_list) is channels_ignored and not (is_mod and mod_bypass): return has_role = False if message.author is not None and hasattr(message.author, "roles"): for role in message.author.roles: if role.id in role_list: has_role = True break if has_role is not role_required and not (is_mod and mod_bypass): return prefix = Configuration.get_var(message.guild.id, "GENERAL", "PREFIX") if message.content.startswith(prefix, 0) and message.guild.id in self.commands: for trigger in self.commands[message.guild.id]: if message.content.lower() == prefix + trigger or ( message.content.lower().startswith(trigger, len(prefix)) and message.content.lower()[len(prefix + trigger)] == " "): info = self.commands[message.guild.id][trigger] images = IMAGE_MATCHER.findall(info.content) image = None if len(images) == 1: image = images[0] description = info.content.replace(image, "") else: description = info.content embed = Embed(description=description) if info.created_by is not None: creator = await Utils.get_user(info.created_by) embed.set_footer(text=f"Created by {str(creator)} ({info.created_by})", icon_url=creator.avatar_url) if image is not None: embed.set_image(url=image) await message.channel.send(embed=embed) self.bot.custom_command_count += 1
async def pack_messages(messages, guild_id): out = "" for message in messages: name = await Utils.username(message.author, clean=False) reply = "" if message.reply_to is not None: reply = f" | In reply to https://discord.com/channels/{message.server}/{message.channel}/{message.reply_to}" timestamp = datetime.datetime.strftime( discord.Object(message.messageid).created_at.astimezone( pytz.timezone( Configuration.get_var(guild_id, 'GENERAL', 'TIMEZONE'))), '%H:%M:%S') out += f"{timestamp} {message.server} - {message.channel} - {message.messageid} | {name} ({message.author}) | {message.content}{reply} | {(', '.join(Utils.assemble_attachment(message.channel, attachment.id, attachment.name) for attachment in message.attachments))}\r\n" return out
async def dog(self, ctx): """dog_help""" await ctx.trigger_typing() future_fact = self.get_json( "https://dog-api.kinduff.com/api/facts?number=1") key = Configuration.get_master_var("DOG_KEY", "") future_dog = self.get_json( "https://api.thedogapi.com/v1/images/search?limit=1&size=full", {'x-api-key': key}, key != "") fact_json, dog_json = await asyncio.gather(future_fact, future_dog) embed = discord.Embed(description=fact_json["facts"][0]) if key != "": embed.set_image(url=dog_json[0]["url"]) await ctx.send(embed=embed)
async def init(self): try: self.redis_link = await aioredis.create_redis_pool( (Configuration.get_master_var('REDIS_HOST', "localhost"), Configuration.get_master_var('REDIS_PORT', 6379)), encoding="utf-8", db=0, maxsize=2) # size 2: one send, one receive self.bot.loop.create_task(self._receiver()) if Configuration.get_master_var("DASH_OUTAGE")["outage_detection"]: self.bot.loop.create_task(self.dash_monitor()) await self.redis_link.subscribe( self.receiver.channel("dash-bot-messages")) await self.redis_link.publish_json( "bot-dash-messages", { 'type': 'cache_info', 'message': await self.cache_info() }) except OSError: await GearbotLogging.bot_log("Failed to connect to the dash!")
async def update(): message = await GearbotLogging.bot_log( f"{Emoji.get_chat_emoji('REFRESH')} Updating translations") crowdin_data = Configuration.get_master_var("CROWDIN") session: aiohttp.ClientSession = BOT.aiosession async with session.get( f"https://api.crowdin.com/api/project/Gearbot/export?login={crowdin_data['login']}&account-key={crowdin_data['key']}&json", ) as reply: if reply.status is not 200: await GearbotLogging.bot_log( f"{Emoji.get_chat_emoji('WARNING')} Crowdin api error, got response code {reply.status}" ) else: response = await reply.json() if response["success"][ "status"] == "built": # only update translations if we actually got a new build, should be every time though unless this runs 2x within 30 mins for some reason async with session.get( f"https://api.crowdin.com/api/project/Gearbot/download/all.zip?login={crowdin_data['login']}&account-key={crowdin_data['key']}" ) as reply: data = await reply.read() with open("zip.zip", "wb") as file: file.write(data) with zipfile.ZipFile("zip.zip", "r") as archive: tempdir = os.path.abspath("temp") if os.path.isdir(tempdir): shutil.rmtree(tempdir, ignore_errors=True) os.mkdir(tempdir) archive.extractall("temp") for entry in archive.filelist: if not entry.filename.endswith(".json"): continue filename = entry.filename[-10:] if os.path.isfile( os.path.abspath(f"lang/{filename}")): os.remove(os.path.abspath(f"lang/{filename}")) archive.extract(entry, tempdir) os.rename( os.path.abspath(f"temp/{entry.filename}"), os.path.abspath(f"lang/{filename}")) shutil.rmtree("temp", ignore_errors=True) load_translations() await message.edit( content= f"{Emoji.get_chat_emoji('YES')} Translations have been updated" ) else: await message.edit( content= f"{Emoji.get_chat_emoji('WARNING')} Crowdin build status was `{response['success']['status']}`, no translation update required" )
async def on_message(self, message: discord.Message): if message.guild is not None or len( message.content ) > 1800 or message.author.id == self.bot.user.id: return if not message.content.startswith("!"): channel = self.bot.get_channel( Configuration.get_master_var("inbox", 0)) if channel is not None: await channel.send( f"[`{message.created_at.strftime('%c')}`] {message.author} (`{message.author.id}`) said: {message.clean_content}" ) for attachement in message.attachments: await channel.send(attachement.url)
async def mute_role(self, ctx:commands.Context, role:discord.Role): """configure_mute_help""" if role == ctx.guild.default_role: return await ctx.send( f"{Emoji.get_chat_emoji('NO')} {Translator.translate(f'default_role_forbidden', ctx)}") guild:discord.Guild = ctx.guild perms = guild.me.guild_permissions if not perms.manage_roles: await ctx.send(f"{Emoji.get_chat_emoji('NO')} {Translator.translate('mute_missing_perm', ctx)}") return if not guild.me.top_role > role: await ctx.send(f"{Emoji.get_chat_emoji('NO')} {Translator.translate('mute_missing_perm', ctx, role=role.mention)}") return Configuration.set_var(ctx.guild.id, "MUTE_ROLE", int(role.id)) await ctx.send(f"{Emoji.get_chat_emoji('YES')} {Translator.translate('mute_role_confirmation', ctx, role=role.mention)}") failed = [] for channel in guild.text_channels: try: await channel.set_permissions(role, reason=Translator.translate('mute_setup', ctx), send_messages=False, add_reactions=False) except discord.Forbidden as ex: failed.append(channel.mention) for channel in guild.voice_channels: try: await channel.set_permissions(role, reason=Translator.translate('mute_setup', ctx), speak=False, connect=False) except discord.Forbidden as ex: failed.append(Translator.translate('voice_channel', ctx, channel=channel.name)) if len(failed) > 0: message = f"{Emoji.get_chat_emoji('WARNING')} {Translator.translate('mute_setup_failures', ctx, role=role.mention)}\n" for fail in failed: if len(message) + len(fail) > 2048: await ctx.send(message) message = "" message = message + fail if len(message) > 0: await ctx.send(message) else: await ctx.send(f"{Emoji.get_chat_emoji('YES')} {Translator.translate('mute_setup_complete', ctx)}")
async def on_raw_message_delete(self, data: RawMessageDeleteEvent): if data.message_id in self.bot.data["message_deletes"]: self.bot.data["message_deletes"].remove(data.message_id) return message = LoggedMessage.get_or_none(messageid=data.message_id) if message is not None and Features.is_logged(message.server, "EDIT_LOGS"): guild = self.bot.get_guild(message.server) user: discord.User = self.bot.get_user(message.author) hasUser = user is not None if not hasUser or user.id in Configuration.get_var(guild.id, "IGNORED_USERS") or user.id == guild.me.id: return attachments = LoggedAttachment.select().where(LoggedAttachment.messageid == data.message_id) channel = self.bot.get_channel(message.channel) name = Utils.clean_user(user) if hasUser else str(message.author) GearbotLogging.log_to(guild.id, "EDIT_LOGS", f":wastebasket: {Translator.translate('message_removed', guild.id, name=name, user_id=user.id if hasUser else 'WEBHOOK', channel=channel.mention)}") if Configuration.get_var(channel.guild.id, "EMBED_EDIT_LOGS"): embed = discord.Embed(timestamp=datetime.datetime.utcfromtimestamp(time.time()), description=message.content) embed.set_author(name=user.name if hasUser else message.author, icon_url=user.avatar_url if hasUser else EmptyEmbed) embed.set_footer(text=f"Sent in #{channel.name}") if len(attachments) > 0: embed.add_field(name=Translator.translate('attachment_link', guild), value="\n".join(attachment.url for attachment in attachments)) GearbotLogging.log_to(guild.id, "EDIT_LOGS", embed=embed) else: cleaned_content = await Utils.clean(message.content, channel.guild) GearbotLogging.log_to(guild.id, "EDIT_LOGS", f"**Content:** {cleaned_content}", can_stamp=False) count = 1 for attachment in attachments: GearbotLogging.log_to(guild.id, "EDIT_LOGS", f"**Attachment{f' {count}' if len(attachments) > 1 else ''}:** <{attachment.url}>", can_stamp=False) count += 1
async def temp_ban_punishment(self, v: Violation): reason = self.assemble_reason(v) duration = v.bucket["PUNISHMENT"]["DURATION"] until = time.time() + duration await self.bot.redis_pool.psetex(f"forced_exits:{v.guild.id}-{v.member.id}", 8000, 1) await v.guild.ban(v.member, reason=reason, delete_message_days=0) i = await InfractionUtils.add_infraction(v.guild.id, v.member.id, self.bot.user.id, 'Tempban', reason, end=until) if Configuration.get_var(v.guild.id, "INFRACTIONS", "DM_ON_TEMPBAN"): dur = Utils.to_pretty_time(duration, None) asyncio.create_task(Utils.send_infraction(self.bot, v.member, v.guild, 'BAN', 'tempban', "Spam", duration=dur)) GearbotLogging.log_key(v.guild.id, 'tempban_log', user=Utils.clean_user(v.member), user_id=v.member.id, moderator=Utils.clean_user(v.guild.me), moderator_id=v.guild.me.id, reason=reason, until=datetime.datetime.utcfromtimestamp(until), inf=i.id)
async def on_message(self, message: discord.Message): if message.guild is None or message.webhook_id is not None or message.channel is None or isinstance( message.channel, DMChannel) or not Configuration.get_var( message.channel.guild.id, "CENSORING", "ENABLED") or self.bot.user.id == message.author.id: return member = message.guild.get_member(message.author.id) #d.py is weird if member is None: return if message.reference is not None and message.reference.channel_id == message.channel.id: reply = message.reference.message_id else: reply = None await self.check_message(member, message.content, message.channel, message.id, False, reply, message.attachments)
async def init(): await Tortoise.init( config={ 'connections': { 'default': { 'engine': 'tortoise.backends.mysql', 'credentials': { 'host': Configuration.get_master_var('DATABASE_HOST'), 'port': Configuration.get_master_var('DATABASE_PORT'), 'user': Configuration.get_master_var('DATABASE_USER'), 'password': Configuration.get_master_var( 'DATABASE_PASS'), 'database': Configuration.get_master_var( 'DATABASE_NAME') } } }, 'apps': { 'models': { 'models': ['database.DatabaseConnector'] } } }) await Tortoise.generate_schemas()
def __init__(self, bot): super().__init__(bot, { "min": 0, "max": 6, "required": 0, "commands": {} }) to_remove = { "CAT_KEY": "cat", "DOG_KEY": "dog", "APEX_KEY": "apexstats" } for k, v in to_remove.items(): if Configuration.get_master_var(k, "0") == "0": bot.remove_command(v)
def log_raw(guild_id, key, message=None, embed=None, file=None): # logging category, emoji and info = LOG_TYPES[key] # determine where it should be logged so we don't need to bother assembling everything when it's just gona be voided anyways targets = [] channels = Configuration.get_var(guild_id, "LOG_CHANNELS") for cid, settings in channels.items(): if info.category in settings["CATEGORIES"] and info.config_key not in settings["DISABLED_KEYS"]: targets.append(cid) # no targets? no logging if len(targets) is 0: return log_to(guild_id, targets, Utils.trim_message(message, 2000) if message is not None else None, embed, file, None)
async def voice_spam_detector(self): while self.running: try: member = None before = None after = None (member, before, after) = await self.bot.wait_for("voice_state_update") # make sure our cog is still running so we don't handle it twice if not self.running: return # make sure anti-spam is enabled cfg = Configuration.get_var(member.guild.id, "ANTI_SPAM") if after.channel is None or before.channel == after.channel or member is None or not cfg.get("ENABLED", False) or self.is_exempt(member.guild.id, member): continue buckets = Configuration.get_var(member.guild.id, "ANTI_SPAM", "BUCKETS", []) count = 0 for b in buckets: t = b["TYPE"] if t == "voice_joins": now = int(datetime.datetime.utcnow().timestamp()) bucket = self.get_bucket(member.guild.id, f"voice_channel_join", b, member.id) if bucket is not None and await bucket.check(member.id, now, message=now, amount=1): count = await bucket.count(member.id, now, expire=False) period = await bucket.size(member.id, now, expire=False) self.bot.loop.create_task( self.violate(Violation("max_voice_joins", member.guild, f"{Translator.translate('spam_max_voice_join', member.guild)} ({count}/{period}s)", member, None, set(), b, count))) except CancelledError: pass except Exception as e: await TheRealGearBot.handle_exception("voice spam join detector", self.bot, e)
async def command_overrides(self, ctx): """command_overrides_help""" if ctx.invoked_subcommand is self.command_overrides: overrides = Configuration.get_var(ctx.guild.id, "PERM_OVERRIDES") embed = discord.Embed(color=6008770, title=Translator.translate('command_overrides', ctx)) has_overrides = False for cog in self.bot.cogs: if cog in overrides: out = gen_override_strings(ctx, overrides[cog]) if out != "": has_overrides = True embed.add_field(name=cog, value=out) if not has_overrides: embed.description = Translator.translate('no_overrides', ctx) await ctx.send(embed=embed)
async def on_member_join(self, member: discord.Member): if Features.is_logged(member.guild.id, "TRAVEL_LOGS"): dif = (datetime.datetime.utcfromtimestamp(time.time()) - member.created_at) new_user_threshold = Configuration.get_var(member.guild.id, "GENERAL", "NEW_USER_THRESHOLD") minutes, seconds = divmod(dif.days * 86400 + dif.seconds, 60) hours, minutes = divmod(minutes, 60) age = (Translator.translate('days', member.guild.id, amount=dif.days)) if dif.days > 0 else Translator.translate('hours', member.guild.id, hours=hours, minutes=minutes) if new_user_threshold > dif.total_seconds(): GearbotLogging.log_key(member.guild.id, 'join_logging_new', user=Utils.clean_user(member), user_id=member.id, age=age) else: GearbotLogging.log_key(member.guild.id, 'join_logging', user=Utils.clean_user(member), user_id=member.id, age=age)
async def on_member_join(self, member: discord.Member): channelid = Configuration.getConfigVar(member.guild.id, "JOIN_LOGS") if channelid is not 0: logChannel: discord.TextChannel = self.bot.get_channel(channelid) if logChannel is not None: dif = (datetime.datetime.utcnow() - member.created_at) minutes, seconds = divmod(dif.days * 86400 + dif.seconds, 60) hours, minutes = divmod(minutes, 60) age = (Translator.translate( 'days', member.guild.id, days=dif.days)) if dif.days > 0 else Translator.translate( 'hours', member.guild.id, hours=hours, minutes=minutes) await logChannel.send( f"{Emoji.get_chat_emoji('JOIN')} {Translator.translate('join_logging', member.guild.id, user=Utils.clean_user(member), user_id=member.id, age=age)}" )
async def on_raw_bulk_message_delete(self, event: discord.RawBulkMessageDeleteEvent): if Features.is_logged(event.guild_id, "MESSAGE_LOGS"): if event.channel_id in Configuration.get_var(event.guild_id, "MESSAGE_LOGS", "IGNORED_CHANNELS_OTHER"): return if event.channel_id in self.bot.being_cleaned: for mid in event.message_ids: self.bot.being_cleaned[event.channel_id].add(mid) return message_list = dict() for mid in event.message_ids: message = await MessageUtils.get_message_data(self.bot, mid) if message is not None: message_list[mid] = message if len(message_list) > 0: await Archive.archive_purge(self.bot, event.guild_id, collections.OrderedDict(sorted(message_list.items())))
async def _warn(ctx, target, *, reason, message=True, dm_action=True): i = await InfractionUtils.add_infraction(ctx.guild.id, target.id, ctx.author.id, "Warn", reason) name = Utils.clean_user(target) if message: await MessageUtils.send_to(ctx, 'YES', 'warning_added', user=name, inf=i.id) aname = Utils.clean_user(ctx.author) GearbotLogging.log_key(ctx.guild.id, 'warning_added_modlog', user=name, moderator=aname, reason=reason, user_id=target.id, moderator_id=ctx.author.id, inf=i.id) if Configuration.get_var(ctx.guild.id, "INFRACTIONS", "DM_ON_WARN") and dm_action: try: dm_channel = await target.create_dm() await dm_channel.send( f"{Emoji.get_chat_emoji('WARNING')} {Translator.translate('warning_dm', ctx.guild.id, server=ctx.guild.name)}```{reason}```") except discord.Forbidden: GearbotLogging.log_key(ctx.guild.id, 'warning_could_not_dm', user=name, userid=target.id)
async def on_message(self, message: discord.Message): if message.author.bot: return if not hasattr(message.channel, "guild") or message.channel.guild is None: return prefix = Configuration.getConfigVar(message.guild.id, "PREFIX") if message.content.startswith(prefix, 0): for trigger in self.commands[message.guild.id]: if message.content.lower() == prefix + trigger or ( message.content.lower().startswith( trigger, len(prefix)) and message.content.lower()[len(prefix + trigger)] == " "): await message.channel.send( self.commands[message.guild.id][trigger]) self.bot.commandCount = self.bot.commandCount + 1
async def user_info_request(self, message): user_id = message["user_id"] user_info = await self.bot.fetch_user(user_id) return_info = { "username": user_info.name, "discrim": user_info.discriminator, "avatar_url": str(user_info.avatar_url_as(size=256)), "bot_admin_status": await self.bot.is_owner(user_info) or user_id in Configuration.get_master_var("BOT_ADMINS", []) } return return_info
async def on_raw_message_edit(self, event: discord.RawMessageUpdateEvent): channel = self.bot.get_channel(int(event.data["channel_id"])) if channel is None or isinstance( channel, DMChannel) or not Configuration.get_var( channel.guild.id, "CENSORING", "ENABLED"): return permissions = channel.permissions_for(channel.guild.me) if permissions.read_messages and permissions.read_message_history: try: message = await channel.fetch_message(event.message_id) except (discord.NotFound, discord.Forbidden ): # we should never get forbidden, be we do, somehow pass else: if self.bot.user.id != message.author.id: await self.check_message(message)
async def on_ready(): global STARTED if not STARTED: await Logging.onReady(bot, Configuration.get_master_var("BOT_LOG_CHANNEL")) await Configuration.on_ready(bot) for e in ["Maintenance", "Moderation", "BadNames"]: try: bot.load_extension("Cogs." + e) except Exception as ex: Logging.error(f"Failed to load cog {e}") await handle_exception(f"Loading cog {e}", ex) Logging.info("Cogs loaded") await Logging.bot_log("Outboard engine running at full speed!") STARTED = True
async def on_command_error(bot, ctx: commands.Context, error): if isinstance(error, NotCachedException): if bot.loading_task is not None: if bot.initial_fill_complete: await send(ctx, f"{Emoji.get_chat_emoji('CLOCK')} Due to a earlier connection failure the cached data for this guild is no longer up to date and is being rebuild. Please try again in a few minutes.") else: await send(ctx, f"{Emoji.get_chat_emoji('CLOCK')} GearBot is in the process of starting up and has not received the member info for this guild. Please try again in a few minutes.") else: await send(ctx, f"{Emoji.get_chat_emoji('CLOCK')} GearBot only just joined this guild and is still receiving the initial member info for this guild, please try again in a few seconds") if isinstance(error, commands.BotMissingPermissions): GearbotLogging.error(f"Encountered a permission error while executing {ctx.command}: {error}") await send(ctx, error) elif isinstance(error, commands.CheckFailure): if ctx.command.qualified_name != "latest" and ctx.guild is not None and Configuration.get_var(ctx.guild.id, "GENERAL", "PERM_DENIED_MESSAGE"): await MessageUtils.send_to(ctx, 'LOCK', 'permission_denied') elif isinstance(error, commands.CommandOnCooldown): await send(ctx, error) elif isinstance(error, commands.MissingRequiredArgument): param = list(ctx.command.params.values())[min(len(ctx.args) + len(ctx.kwargs), len(ctx.command.params))] bot.help_command.context = ctx await send(ctx, f"{Emoji.get_chat_emoji('NO')} {Translator.translate('missing_arg', ctx, arg=param._name, error=Utils.replace_lookalikes(str(error)))}\n{Emoji.get_chat_emoji('WRENCH')} {Translator.translate('command_usage', ctx, usage=bot.help_command.get_command_signature(ctx.command))}") elif isinstance(error, PostParseError): bot.help_command.context = ctx await send(ctx, f"{Emoji.get_chat_emoji('NO')} {Translator.translate('bad_argument', ctx, type=error.type, error=Utils.replace_lookalikes(str(error.error)))}\n{Emoji.get_chat_emoji('WRENCH')} {Translator.translate('command_usage', ctx, usage=bot.help_command.get_command_signature(ctx.command))}") elif isinstance(error, commands.BadArgument): param = list(ctx.command.params.values())[min(len(ctx.args) + len(ctx.kwargs), len(ctx.command.params))] bot.help_command.context = ctx await send(ctx, f"{Emoji.get_chat_emoji('NO')} {Translator.translate('bad_argument', ctx, type=param._name, error=Utils.replace_lookalikes(str(error)))}\n{Emoji.get_chat_emoji('WRENCH')} {Translator.translate('command_usage', ctx, usage=bot.help_command.get_command_signature(ctx.command))}") elif isinstance(error, commands.CommandNotFound): return elif isinstance(error, NotFound): e = Emoji.get_chat_emoji('BUG') await send(ctx, f"{e} Command failed because the discord api responded with \"not found\" If you didn't delete anything manually and this keeps happening please report it on support server (DM me ``!about`` or check the website for an invite) {e}") elif isinstance(error, Forbidden): e = Emoji.get_chat_emoji('BUG') await ctx.send(f"{e} Command failed because the discord api responded with \"forbidden\" reply. Please make sure the bot has the permissions and roles required to perform this command {e}") elif isinstance(error, UnexpectedQuoteError) or isinstance(error, InvalidEndOfQuotedStringError): e = Emoji.get_chat_emoji('BUG') await ctx.send(f"{e} Command parsing failed, unexpected or unclosed quote encountered {e}") else: await handle_exception("Command execution failed", bot, error.original if hasattr(error, "original") else error, ctx=ctx) # notify caller e = Emoji.get_chat_emoji('BUG') if ctx.channel.permissions_for(ctx.me).send_messages: await ctx.send(f"{e} Something went wrong while executing that command {e}")