async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): guild = self.bot.get_guild(payload.guild_id) if guild is None: return user = guild.get_member(payload.user_id) if guild.me.id == payload.user_id: return try: message = await self.bot.get_channel( payload.channel_id).get_message(payload.message_id) except discord.NotFound: pass else: if str(payload.emoji) == str(Emoji.get_emoji('LEFT')): if await Pages.update(self.bot, message, "PREV", payload.user_id): try: await message.remove_reaction(Emoji.get_emoji('LEFT'), user) except discord.Forbidden: pass elif str(payload.emoji) == str(Emoji.get_emoji('RIGHT')): if await Pages.update(self.bot, message, "NEXT", payload.user_id): try: await message.remove_reaction(Emoji.get_emoji('RIGHT'), user) except discord.Forbidden: pass
async def self_roles(bot, message, user_id, reaction, **kwargs): user = message.channel.guild.get_member(user_id) if user is None: if user_id is not 0: await remove_reaction(message, reaction, await bot.fetch_user(user_id)) return kwargs bot.loop.create_task(remove_reaction(message, reaction, user)) left = Emoji.get_chat_emoji('LEFT') right = Emoji.get_chat_emoji('RIGHT') refresh = Emoji.get_chat_emoji('REFRESH') r2 = "🔁" page_num = int(kwargs.get("page_num", 0)) add = reaction not in [left, right, refresh, r2] if str(reaction) == left: page_num -= 1 add = False elif str(reaction) == right: page_num += 1 add = False elif str(reaction) in [refresh, r2]: if not message.channel.permissions_for(message.channel.guild.me).manage_messages: return kwargs await message.clear_reactions() await asyncio.sleep(0.2) add = False if add: for i in range(10): if str(reaction) == str(Emoji.get_emoji(str(i+1))): roles = Configuration.get_var(message.guild.id, "SELF_ROLES") role = message.channel.guild.get_role(roles[page_num*10 + i]) if role is None: await Selfroles.validate_self_roles(bot, message.channel.guild) return add_role = role not in user.roles try: await (user.add_roles if add_role else user.remove_roles)(role) except Forbidden: if message.channel.permissions_for(message.channel.guild.me).send_messages: await MessageUtils.send_to(message.channel, "NO", "role_too_high_add", role=role.name) return kwargs else: if message.channel.permissions_for(message.channel.guild.me).send_messages: await MessageUtils.send_to(message.channel, "YES", "role_joined" if add_role else "role_left", role_name=await Utils.clean(role.name), delete_after=10) bot.loop.create_task(remove_reaction(message, reaction, user)) return kwargs return kwargs pages = Selfroles.gen_role_pages(message.channel.guild) if page_num >= len(pages): page_num = 0 elif page_num < 0: page_num = len(pages) - 1 kwargs["page_num"] = page_num embed = Embed(title=Translator.translate("assignable_roles", message.channel, server_name=message.channel.guild.name, page_num=page_num+1, page_count=len(pages)), colour=Colour(0xbffdd), description=pages[page_num]) await message.edit(embed=embed) await Selfroles.update_reactions(message, pages[page_num], len(pages) > 1) bot.loop.create_task(bot.redis_pool.expire(f"self_role:{message.channel.guild.id}", int(kwargs.get("duration", 60 * 60 * 24 * 7)))) return kwargs
async def on_ready(): if not bot.STARTUP_COMPLETE: await Util.readyBot(bot) Emoji.on_ready(bot) Utils.on_ready(bot) Translator.on_ready(bot) bot.loop.create_task( keepDBalive()) # ping DB every hour so it doesn't run off #shutdown handler for clean exit on linux try: for signame in ('SIGINT', 'SIGTERM'): asyncio.get_event_loop().add_signal_handler( getattr(signal, signame), lambda: asyncio.ensure_future( Utils.cleanExit(bot, signame))) except Exception: pass #doesn't work on windows bot.aiosession = aiohttp.ClientSession() bot.start_time = datetime.datetime.utcnow() GearbotLogging.info("Loading cogs...") for extension in extensions: try: bot.load_extension("Cogs." + extension) except Exception as e: GearbotLogging.exception( f"Failed to load extention {extension}", e) GearbotLogging.info("Cogs loaded") if Configuration.getMasterConfigVar("CROWDIN_KEY") is not None: bot.loop.create_task(translation_task()) bot.STARTUP_COMPLETE = True await bot.change_presence( activity=discord.Activity(type=3, name='the gears turn'))
async def remind_me(self, ctx, duration: Duration, *, reminder: ReminderText): """remind_me_help""" if duration.unit is None: parts = reminder.split(" ") duration.unit = parts[0] reminder = " ".join(parts[1:]) duration_seconds = duration.to_seconds(ctx) if duration_seconds <= 0: await MessageUtils.send_to(ctx, "NO", "reminder_time_travel") return if ctx.guild is not None: message = f'{Emoji.get_chat_emoji("QUESTION")} {Translator.translate("remind_question", ctx)}' one = Emoji.get_emoji("1") two = Emoji.get_emoji("2") no = Emoji.get_emoji("NO") embed = Embed(description=f""" {Emoji.get_chat_emoji("1")} {Translator.translate("remind_option_here", ctx)} {Emoji.get_chat_emoji("2")} {Translator.translate("remind_option_dm", ctx)} {Emoji.get_chat_emoji("NO")} {Translator.translate("remind_option_cancel", ctx)} """) m = await ctx.send(message, embed=embed) for e in [one, two, no]: await m.add_reaction(e) try: reaction, user = await ctx.bot.wait_for( 'reaction_add', timeout=30, check=lambda reaction, user: user == ctx.message.author and reaction.emoji in [one, two, no]) except asyncio.TimeoutError: await MessageUtils.send_to(ctx, "NO", "confirmation_timeout", timeout=30) return else: if reaction.emoji == no: await MessageUtils.send_to(ctx, "NO", "command_canceled") return else: dm = reaction.emoji == two finally: await m.delete() else: dm = True Reminder.create(user_id=ctx.author.id, channel_id=ctx.channel.id, dm=dm, to_remind=await Utils.clean(reminder, markdown=False), time=time.time() + duration_seconds, status=ReminderStatus.Pending) mode = "dm" if dm else "here" await MessageUtils.send_to(ctx, "YES", f"reminder_confirmation_{mode}", duration=duration.length, duration_identifier=duration.unit)
async def update_reactions(message, page, has_multiple): left = Emoji.get_emoji("LEFT") if has_multiple and not any(left == r.emoji and r.me for r in message.reactions): await message.add_reaction(left) # add numbered reactions needed = int(len(page.splitlines()) / 2) added = False try: for i in range(10): reaction = Emoji.get_emoji(str(i + 1)) if i < needed: added = True await message.add_reaction(reaction) elif any(reaction == r.emoji and r.me for r in message.reactions): await message.remove_reaction(reaction, message.channel.guild.me) right = Emoji.get_emoji("RIGHT") has_right = any(right == r.emoji and r.me for r in message.reactions) if added and has_right: await message.remove_reaction(right, message.channel.guild.me) has_right = False if not has_right and has_multiple: await message.add_reaction(right) has_left = any(left == r.emoji and r.me for r in message.reactions) if has_left and has_multiple: await message.remove_reaction(left, message.channel.guild.me) except Forbidden: pass # we lost access
async def create_new(type, ctx, **kwargs): text, embed, has_pages, emoji = await page_handlers[type]["init"](ctx, **kwargs) message: discord.Message = await ctx.channel.send(text, embed=embed) if has_pages or len(emoji) > 0: data = { "type": type, "page": 0, "trigger": ctx.message.id, "sender": ctx.author.id } for k, v in kwargs.items(): data[k] = v known_messages[str(message.id)] = data try: if has_pages: await message.add_reaction(Emoji.get_emoji('LEFT')) for e in emoji: await message.add_reaction(e) if has_pages: await message.add_reaction(Emoji.get_emoji('RIGHT')) except discord.Forbidden: await ctx.send( f"{Emoji.get_chat_emoji('WARNING')} {Translator.translate('paginator_missing_perms', ctx, prev=Emoji.get_chat_emoji('LEFT'), next=Emoji.get_chat_emoji('RIGHT'))} {Emoji.get_chat_emoji('WARNING')}" ) if len(known_messages.keys()) > 500: del known_messages[list(known_messages.keys())[0]] save_to_disc()
async def initialize(bot): #lock event handling while we get ready bot.locked = True try: #database GearbotLogging.info("Connecting to the database.") DatabaseConnector.init() bot.database_connection = DatabaseConnector.connection GearbotLogging.info("Database connection established.") GearbotLogging.initialize_pump(bot) Emoji.initialize(bot) Pages.initialize(bot) Utils.initialize(bot) Translator.initialize(bot) InfractionUtils.initialize(bot) bot.data = { "forced_exits": set(), "unbans": set(), "message_deletes": set() } await GearbotLogging.initialize( bot, Configuration.get_master_var("BOT_LOG_CHANNEL")) if bot.redis_pool is None or not hasattr( bot, 'redis_raid_pool') or bot.redis_raid_pool is None: try: bot.redis_pool = await aioredis.create_redis_pool( (Configuration.get_master_var('REDIS_HOST', "localhost"), Configuration.get_master_var('REDIS_PORT', 6379)), encoding="utf-8", db=0) bot.redis_raid_pool = await aioredis.create_redis_pool( (Configuration.get_master_var('REDIS_HOST', "localhost"), Configuration.get_master_var('REDIS_PORT', 6379)), encoding="utf-8", db=1) except OSError: GearbotLogging.error( "==============Failed to connect to redis==============") await GearbotLogging.bot_log( f"{Emoji.get_chat_emoji('NO')} Failed to connect to redis, caching and anti-raid connections unavailable" ) else: GearbotLogging.info("Redis connection established") await GearbotLogging.bot_log( f"{Emoji.get_chat_emoji('YES')} Redis connection established, caching and anti-raid connections established" ) if bot.aiosession is None: bot.aiosession = aiohttp.ClientSession() bot.being_cleaned.clear() await Configuration.initialize(bot) except Exception as ex: #make sure we always unlock, even when something went wrong! bot.locked = False raise ex bot.locked = False
async def initialize(bot, startup=False): #lock event handling while we get ready bot.locked = True try: #database GearbotLogging.info("Connecting to the database.") DatabaseConnector.init() bot.database_connection = DatabaseConnector.connection GearbotLogging.info("Database connection established.") Emoji.initialize(bot) Utils.initialize(bot) InfractionUtils.initialize(bot) bot.data = { "forced_exits": set(), "unbans": set(), "message_deletes": set(), "nickname_changes": set() } await GearbotLogging.initialize(bot, Configuration.get_master_var("BOT_LOG_CHANNEL")) if startup: c = await Utils.get_commit() bot.version = c GearbotLogging.info(f"GearBot spinning up version {c}") await GearbotLogging.bot_log(f"{Emoji.get_chat_emoji('ALTER')} GearBot spinning up version {c}") if bot.redis_pool is None: try: socket = Configuration.get_master_var("REDIS_SOCKET", "") if socket == "": bot.redis_pool = await aioredis.create_redis_pool((Configuration.get_master_var('REDIS_HOST', "localhost"), Configuration.get_master_var('REDIS_PORT', 6379)), encoding="utf-8", db=0) else: bot.redis_pool = await aioredis.create_redis_pool(socket, encoding="utf-8", db=0) except OSError: GearbotLogging.error("==============Failed to connect to redis==============") await GearbotLogging.bot_log(f"{Emoji.get_chat_emoji('NO')} Failed to connect to redis, caching unavailable") else: GearbotLogging.info("Redis connection established") await GearbotLogging.bot_log(f"{Emoji.get_chat_emoji('YES')} Redis connection established, let's go full speed!") if bot.aiosession is None: bot.aiosession = aiohttp.ClientSession() await Translator.initialize(bot) bot.being_cleaned.clear() await Configuration.initialize(bot) DashConfig.initialize(bot) except Exception as ex: #make sure we always unlock, even when something went wrong! bot.locked = False raise ex bot.locked = False
async def create_new(bot, type, ctx, **kwargs): text, embed, has_pages = await page_handlers[type]["init"](ctx, **kwargs) message: discord.Message = await ctx.channel.send(text, embed=embed) if has_pages: await ReactionManager.register(bot, message.id, message.channel.id, "paged", subtype=type, duration=60 * 60 * 24, **kwargs) try: if has_pages: await message.add_reaction(Emoji.get_emoji('LEFT')) if has_pages: await message.add_reaction(Emoji.get_emoji('RIGHT')) except discord.Forbidden: await MessageUtils.send_to(ctx, 'WARNING', 'paginator_missing_perms', prev=Emoji.get_chat_emoji('LEFT'), next=Emoji.get_chat_emoji('RIGHT')) except discord.NotFound: await MessageUtils.send_to(ctx, 'WARNING', 'fix_censor')
async def inf_update(message, query, fields, amount, page_num): if str(query).isnumeric(): query = int(query) guild_id = message.channel.guild.id old = message.content key = get_key(guild_id, query, fields, amount) # do we have pages? count = await bot.redis_pool.llen(key) if count == 0: count = await fetch_infraction_pages(guild_id, query, amount, fields, page_num) if page_num >= count: page_num = 0 elif page_num < 0: page_num = count - 1 page = (await bot.wait_for( "page_assembled", check=lambda l: l["key"] == key and l["page_num"] == page_num) )["page"] else: if page_num >= count: page_num = 0 elif page_num < 0: page_num = count - 1 page = await bot.redis_pool.lindex(key, page_num) name = await Utils.username(query) if isinstance( query, int) else await Utils.clean(bot.get_guild(guild_id).name) new = f"{Emoji.get_chat_emoji('SEARCH')} {Translator.translate('inf_search_header', message.channel.guild.id, name=name, page_num=page_num + 1, pages=count)}\n{page}" if old != new: try: await message.edit(content=new) if count > 1: left = Emoji.get_emoji('LEFT') if not any(left == r.emoji and r.me for r in message.reactions): await message.add_reaction(Emoji.get_emoji('LEFT')) await message.add_reaction(Emoji.get_emoji('RIGHT')) except NotFound: pass parts = { "page_num": page_num, "cache_key": key, } if len(fields) != 0: parts["fields"] = "-".join(fields) if query is not None: parts["query"] = query if amount != 100: parts["amount"] = 100 return parts
async def inf_search(bot, message, user_id, reaction, **kwargs): user = await Utils.get_member(bot, message.channel.guild, user_id) left = Emoji.get_chat_emoji('LEFT') right = Emoji.get_chat_emoji('RIGHT') refresh = Emoji.get_chat_emoji('REFRESH') r2 = "🔁" if str(reaction) not in [left, right, refresh, r2]: return kwargs page_num = int(kwargs.get("page_num", 0)) if str(reaction) == left: page_num -= 1 elif str(reaction) == right: page_num += 1 if user is not None: bot.loop.create_task(remove_reaction(message, reaction, user))
async def on_ready(bot): if not bot.STARTUP_COMPLETE: GearbotLogging.initialize_pump(bot) await GearbotLogging.onReady( bot, Configuration.get_master_var("BOT_LOG_CHANNEL")) info = await bot.application_info() await GearbotLogging.bot_log(message="Spinning up the gears!") await Util.readyBot(bot) Emoji.on_ready(bot) Utils.on_ready(bot) Translator.on_ready(bot) bot.loop.create_task( keepDBalive(bot)) # ping DB every hour so it doesn't run off #shutdown handler for clean exit on linux try: for signame in ('SIGINT', 'SIGTERM'): asyncio.get_event_loop().add_signal_handler( getattr(signal, signame), lambda: asyncio.ensure_future( Utils.cleanExit(bot, signame))) except Exception: pass #doesn't work on windows bot.aiosession = aiohttp.ClientSession() bot.start_time = datetime.datetime.utcnow() GearbotLogging.info("Loading cogs...") for extension in Configuration.get_master_var("COGS"): try: bot.load_extension("Cogs." + extension) except Exception as e: GearbotLogging.exception( f"Failed to load extention {extension}", e) GearbotLogging.info("Cogs loaded") if Configuration.get_master_var("CROWDIN_KEY") is not None: bot.loop.create_task(translation_task(bot)) await DocUtils.update_docs(bot) bot.STARTUP_COMPLETE = True await GearbotLogging.bot_log( message=f"All gears turning at full speed, {info.name} ready to go!" ) await bot.change_presence( activity=discord.Activity(type=3, name='the gears turn')) else: await bot.change_presence( activity=discord.Activity(type=3, name='the gears turn'))
async def confirm(ctx: commands.Context, text, timeout=30, on_yes=None, on_no=None, delete=True, confirm_cancel=True): yes = str(Emoji.get_emoji("YES")) no = str(Emoji.get_emoji("NO")) message: discord.Message = await ctx.send(text) await message.add_reaction(yes) await message.add_reaction(no) def check(reaction: discord.RawReactionActionEvent): return reaction.user_id == ctx.message.author.id and str( reaction.emoji) in (yes, no) and reaction.message_id == message.id try: reaction = await ctx.bot.wait_for('raw_reaction_add', timeout=timeout, check=check) except asyncio.TimeoutError: try: await message.delete() except NotFound: pass # someone deleted it await MessageUtils.send_to(ctx, "NO", "confirmation_timeout", timeout=30) return if str(reaction.emoji) == yes and on_yes is not None: if delete: try: await message.delete() except (discord.Forbidden, discord.NotFound): pass await on_yes() elif str(reaction.emoji) == no: if delete: try: await message.delete() except (discord.Forbidden, discord.NotFound): pass if on_no is not None: await on_no() elif confirm_cancel: await MessageUtils.send_to(ctx, "NO", "command_canceled")
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 ctx.send( 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 ctx.send( 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 ctx.send( 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 ctx.send(error) elif isinstance(error, commands.CheckFailure): if ctx.command.qualified_name is not "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 ctx.send(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 ctx.send( 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 ctx.send( 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 ctx.send( 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 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. If this keeps happening please report it on support server (DM me ``!about`` or check the website for an invite) {e}" )
def __init__(self, filters, pages, guild_id, userid, current_page=0): super().__init__(timeout=None) self.id = "" if pages > 0: start = f"einf_search:{userid}:{current_page}" self.add_item( Button(label=Translator.translate('first_page', guild_id), custom_id=f'{start}:first_page', disabled=current_page == 0, style=ButtonStyle.blurple)) self.add_item( Button(label=Translator.translate('prev_page', guild_id), custom_id=f'{start}:prev_page', disabled=current_page == 0, style=ButtonStyle.blurple)) self.add_item( Button(emoji=Emoji.get_emoji('AE'), style=ButtonStyle.grey, custom_id=f'{start}:blank', label=None)) self.add_item( Button(label=Translator.translate('next_page', guild_id), custom_id=f'{start}:next_page', disabled=current_page >= pages - 1, style=ButtonStyle.blurple)) self.add_item( Button(label=Translator.translate('last_page', guild_id), custom_id=f'{start}:last_page', disabled=current_page >= pages - 1, style=ButtonStyle.blurple)) self.stop()
async def inf_search(bot, message, user_id, reaction, **kwargs): user = message.channel.guild.get_member(user_id) left = Emoji.get_chat_emoji('LEFT') right = Emoji.get_chat_emoji('RIGHT') refresh = Emoji.get_chat_emoji('REFRESH') r2 = "🔁" if str(reaction) not in [left, right, refresh, r2]: return kwargs page_num = int(kwargs.get("page_num", 0)) if str(reaction) == left: page_num -= 1 elif str(reaction) == right: page_num += 1 if user is not None: bot.loop.create_task(remove_reaction(message, reaction, user)) return await InfractionUtils.inf_update(message, kwargs.get("query", None), kwargs.get("fields", "").split("-"), kwargs.get("amount", 100), page_num)
async def on_ready(bot): if not bot.STARTUP_COMPLETE: await initialize(bot, True) #shutdown handler for clean exit on linux try: for signame in ('SIGINT', 'SIGTERM'): asyncio.get_event_loop().add_signal_handler(getattr(signal, signame), lambda: asyncio.ensure_future(Utils.cleanExit(bot, signame))) except Exception: pass #doesn't work on windows bot.start_time = datetime.utcnow() GearbotLogging.info("Loading cogs...") for extension in Configuration.get_master_var("COGS"): try: bot.load_extension("Cogs." + extension) except Exception as e: await handle_exception(f"Failed to load cog {extension}", bot, e) GearbotLogging.info("Cogs loaded") to_unload = Configuration.get_master_var("DISABLED_COMMANDS", []) for c in to_unload: bot.remove_command(c) bot.STARTUP_COMPLETE = True info = await bot.application_info() bot.loop.create_task(keepDBalive(bot)) # ping DB every hour so it doesn't run off gears = [Emoji.get_chat_emoji(e) for e in ["WOOD", "STONE", "IRON", "GOLD", "DIAMOND"]] a = " ".join(gears) b = " ".join(reversed(gears)) await GearbotLogging.bot_log(message=f"{a} All gears turning at full speed, {info.name} ready to go! {b}") await bot.change_presence(activity=Activity(type=3, name='the gears turn')) else: await bot.change_presence(activity=Activity(type=3, name='the gears turn'))
async def on_command_error(bot, ctx: commands.Context, error): if isinstance(error, commands.BotMissingPermissions): GearbotLogging.error(f"Encountered a permission error while executing {ctx.command}: {error}") await ctx.send(error) elif isinstance(error, commands.CheckFailure): if ctx.command.qualified_name is not "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 ctx.send(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 ctx.send( 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 ctx.send(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 ctx.send(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, PeeweeException): await handle_database_error(bot) 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}")
async def init_help(self, ctx, query=None, **kwargs): pages = await self.get_help_pages(ctx, query) if pages is None: query_clean = await clean_content().convert(ctx, query) return await clean_content().convert(ctx, Translator.translate( "help_not_found" if len(query) < 1500 else "help_no_wall_allowed", ctx, query=query_clean)), None, False eyes = Emoji.get_chat_emoji('EYES') return f"{eyes} **{Translator.translate('help_title', ctx, page_num=1, pages=len(pages))}** {eyes}```diff\n{pages[0]}```", None, len(pages) > 1
async def paged(bot, message, user_id, reaction, **kwargs): user = await Utils.get_member(bot, message.channel.guild, user_id) if user is None: await remove_reaction(message, reaction, await bot.fetch_user(user_id)) return left = Emoji.get_chat_emoji('LEFT') right = Emoji.get_chat_emoji('RIGHT') refresh = Emoji.get_chat_emoji('REFRESH') r2 = "🔁" if str(reaction) not in [left, right, refresh, r2]: return kwargs action = "REFRESH" if str(reaction) == left: action = "PREV" elif str(reaction) == right: action = "NEXT" bot.loop.create_task(remove_reaction(message, reaction, user)) return await Pages.update(bot, message, action, user_id, **kwargs)
def __init__(self, filters, pages, guild_id, current_page=0, ephemeral=False, userid=""): super().__init__(timeout=None) self.id="" if pages > 0: self.add_item(CallbackButton(Translator.translate('first_page', guild_id), self.on_first_page, 'inf_search:first_page', disabled=current_page == 0)) self.add_item(CallbackButton(Translator.translate('prev_page', guild_id), self.on_prev_page, 'inf_search:prev_page', disabled=current_page == 0)) self.add_item(CallbackButton(emoji=Emoji.get_emoji('AE'), style=ButtonStyle.grey, cid='inf_search:blank', callback=self.hi, label=None)) self.add_item(CallbackButton(Translator.translate('next_page', guild_id), self.on_next_page, 'inf_search:next_page', disabled=current_page >= pages-1)) self.add_item(CallbackButton(Translator.translate('last_page', guild_id), self.on_last_page, 'inf_search:last_page', disabled=current_page >= pages-1))
async def confirm(ctx: commands.Context, text, timeout=30, on_yes=None, on_no=None, delete=True): yes = Emoji.get_emoji("YES") no = Emoji.get_emoji("NO") message: discord.Message = await ctx.send(text) await message.add_reaction(yes) await message.add_reaction(no) def check(reaction: discord.Reaction, user): return user == ctx.message.author and reaction.emoji in ( yes, no) and reaction.message.id == message.id try: reaction, user = await ctx.bot.wait_for('reaction_add', timeout=timeout, check=check) except asyncio.TimeoutError: await message.delete() await MessageUtils.send_to(ctx, "NO", "confirmation_timeout", timeout=30) return if reaction.emoji == yes and on_yes is not None: if delete: try: await message.delete() except (discord.Forbidden, discord.NotFound): pass await on_yes() elif reaction.emoji == no: if delete: try: await message.delete() except (discord.Forbidden, discord.NotFound): pass if on_no is not None: await on_no() else: await MessageUtils.send_to(ctx, "NO", "command_canceled")
async def confirm(ctx: commands.Context, text, timeout=30, on_yes=None, on_no=None, delete=True): yes = Emoji.get_emoji("YES") no = Emoji.get_emoji("NO") message: discord.Message = await ctx.send(text) await message.add_reaction(yes) await message.add_reaction(no) def check(reaction: discord.Reaction, user): return user == ctx.message.author and reaction.emoji in ( yes, no) and reaction.message.id == message.id try: reaction, user = await ctx.bot.wait_for('reaction_add', timeout=timeout, check=check) except asyncio.TimeoutError: await message.delete() await ctx.send(f"I got no answer within {timeout} seconds.. Aborting.") return GearbotLogging.info( f"CONFIRMATOR RESPONCE RECEIVED:\nreaction: {reaction}\nemoji: {reaction.emoji}\non_yes: {on_yes}\non_no: {on_no}" ) if reaction.emoji == yes and on_yes is not None: if delete: try: await message.delete() except discord.Forbidden: pass await on_yes() elif reaction.emoji == no: if delete: try: await message.delete() except discord.Forbidden: pass if on_no is not None: await on_no() else: await GearbotLogging.send_to(ctx, "NO", "command_canceled")
async def eval(self, ctx:commands.Context, *, code: str): output = None env = { 'bot': self.bot, 'ctx': ctx, 'channel': ctx.channel, 'author': ctx.author, 'guild': ctx.guild, 'message': ctx.message } env.update(globals()) if code.startswith('```'): code = "\n".join(code.split("\n")[1:-1]) out = io.StringIO() to_compile = f'async def func():\n{textwrap.indent(code, " ")}' try: exec(to_compile, env) except Exception as e: output = f'{e.__class__.__name__}: {e}' else: func = env['func'] try: with contextlib.redirect_stdout(out): ret = await func() except Exception as e: value = out.getvalue() output = f'{value}{traceback.format_exc()}' else: value = out.getvalue() if ret is None: if value: output = value else: output = f'{value}{ret}' if output is not None: pipe = self.bot.redis_pool.pipeline() k = f'eval:{ctx.message.id}' pipe.set(k, output) pipe.expire(k, 7*24*60*60) await pipe.execute() pages = Pages.paginate(output, prefix='```py\n', suffix='```') content, view, _ = SimplePager.get_parts(pages, 0, ctx.guild.id if ctx.guild is not None else 0, f'eval:{ctx.message.id}') await ctx.send(f'Eval output 1/{len(pages)}{content}', view=view) else: await ctx.message.add_reaction(Emoji.get_emoji("YES"))
async def eval(self, ctx: commands.Context, *, code: str): output = None env = { 'bot': self.bot, 'ctx': ctx, 'channel': ctx.channel, 'author': ctx.author, 'guild': ctx.guild, 'message': ctx.message } env.update(globals()) if code.startswith('```'): code = "\n".join(code.split("\n")[1:-1]) out = io.StringIO() to_compile = f'async def func():\n{textwrap.indent(code, " ")}' try: exec(to_compile, env) except Exception as e: output = f'{e.__class__.__name__}: {e}' else: func = env['func'] try: with contextlib.redirect_stdout(out): ret = await func() except Exception as e: value = out.getvalue() output = f'{value}{traceback.format_exc()}' else: value = out.getvalue() if ret is None: if value: output = value else: output = f'{value}{ret}' if output is not None: await Pages.create_new(self.bot, "eval", ctx, pages="----NEW PAGE----".join( Pages.paginate(output)), code=code, trigger=ctx.message.id, sender=ctx.author.id) else: await ctx.message.add_reaction(Emoji.get_emoji("YES"))
async def init_role(self, ctx): pages = self.gen_role_pages(ctx.guild) page = pages[0] emoji = [] for i in range( 10 if len(pages) > 1 else round(len(page.splitlines()) / 2)): emoji.append(Emoji.get_emoji(str(i + 1))) embed = discord.Embed(title=Translator.translate( "assignable_roles", ctx, server_name=ctx.guild.name, page_num=1, page_count=len(pages)), colour=discord.Colour(0xbffdd), description=page) return None, embed, len(pages) > 1, emoji
async def message_parts(bot, query, guild, member, page_num): view = None raw_pages = await get_help_pages(query, guild, member, bot) if raw_pages is None: if query in [cog.lower() for cog in bot.cogs]: raw_pages = [Translator.translate('no_runnable_commands', guild)] else: return Translator.translate("help_not_found" if len(query) < 1500 else "help_no_wall_allowed", guild, query=await Utils.clean(query, emoji=False)), None if page_num >= len(raw_pages): page_num = 0 eyes = Emoji.get_chat_emoji('EYES') content = f"{eyes} **{Translator.translate('help_title', guild, page_num=page_num + 1, pages=len(raw_pages))}** {eyes}```diff\n{raw_pages[page_num]}```" cog_names = [cog.lower() for cog in bot.cogs] if query is None or query.lower() in cog_names or len(raw_pages) > 1: view = HelpView(bot, guild, query, page_num, len(raw_pages), True) return content, view
async def update_help(self, ctx, message, page_num, action, data): pages = await self.get_help_pages(ctx, data.get("query", None)) page, page_num = Pages.basic_pages(pages, page_num, action) eyes = Emoji.get_chat_emoji('EYES') data["page"] = page_num return f"{eyes} **{Translator.translate('help_title', ctx, page_num=page_num + 1, pages=len(pages))}**{eyes}```diff\n{page}```", None, data
async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): guild = self.bot.get_guild(payload.guild_id) if guild is None: return if guild.me.id == payload.user_id: return try: message = await self.bot.get_channel( payload.channel_id).get_message(payload.message_id) except discord.NotFound: pass else: if str(payload.message_id) in Pages.known_messages: info = Pages.known_messages[str(payload.message_id)] if info["type"] == "role": for i in range(10): e = Emoji.get_emoji(str(i + 1)) if payload.emoji.name == e: roles = Configuration.get_var( guild.id, "SELF_ROLES") channel = self.bot.get_channel(payload.channel_id) number = info['page'] * 10 + i if number >= len(roles): await GearbotLogging.send_to( channel, "NO", "role_not_on_page", requested=number + 1, max=len(roles) % 10, delete_after=10) return role = guild.get_role(roles[number]) if role is None: return member = guild.get_member(payload.user_id) try: if role in member.roles: await member.remove_roles(role) added = False else: await member.add_roles(role) added = True except discord.Forbidden: emessage = f"{Emoji.get_chat_emoji('NO')} {Translator.translate('mute_role_to_high', payload.guild_id, role=role.name)}" try: await channel.send(emessage) except discord.Forbidden: try: member.send(emessage) except discord.Forbidden: pass else: try: action_type = 'role_joined' if added else 'role_left' await channel.send( f"{member.mention} {Translator.translate(action_type, payload.guild_id, role_name=role.name)}", delete_after=10) except discord.Forbidden: pass if channel.permissions_for( guild.me).manage_messages: await message.remove_reaction(e, member) break
async def on_interaction(self, interaction): guild = self.bot.get_guild(interaction.guild_id) if interaction.type == InteractionType.component: cid = interaction.data.custom_id if cid.startswith('self_role'): parts = cid.split(':') if parts[1] == 'role': rid = parts[2] if rid.isnumeric(): rid = int(rid) roles = Configuration.get_var(interaction.guild_id, "ROLES", "SELF_ROLES") if rid in roles: role = guild.get_role(rid) if role is None: roles.remove(rid) Configuration.set_var(interaction.guild_id, "ROLES", "SELF_ROLES", roles) v = SelfRoleView(guild=guild, page=0) interaction.response.edit_message( content=Translator.translate( "assignable_roles", interaction.guild_id, server_name=guild.name, page_num=1, page_count=v.pages), view=v) interaction.followup.send_message( MessageUtils.assemble( interaction.guild_id, 'WARNING', 'self_role_missing'), ephemeral=True) else: try: if role in interaction.user.roles: await interaction.user.remove_roles( role) await interaction.response.send_message( Translator.translate( "role_left", interaction.guild_id, role_name=role.name, user=interaction.user), ephemeral=True) else: await interaction.user.add_roles(role) await interaction.response.send_message( Translator.translate( "role_joined", interaction.guild_id, role_name=role.name, user=interaction.user), ephemeral=True) except disnake.Forbidden: await interaction.response.send_message( f"{Emoji.get_chat_emoji('NO')} {Translator.translate('role_too_high_add', interaction.guild_id, role=role.name)}", ephemeral=True) elif parts[1] == "page": v = SelfRoleView(guild=interaction.guild, page=int(parts[2])) await interaction.response.edit_message( content=Translator.translate( "assignable_roles", interaction.guild_id, server_name=interaction.guild.name, page_num=int(parts[2]) + 1, page_count=v.pages), view=v) elif cid.startswith('help:'): parts = cid.split(':') if parts[1] == 'page': q = parts[3] if parts[3] != 'None' else None content, view = await Help.message_parts( self.bot, q, guild, interaction.user, int(parts[2])) await interaction.response.edit_message(content=content, view=view) elif parts[1] == 'selector': q = interaction.values[0] q = q if q != 'None' else None content, view = await Help.message_parts( self.bot, q, guild, interaction.user, 0) await interaction.response.edit_message(content=content, view=view) elif cid.startswith('pager:'): parts = cid.split(':') t = parts[2] if t == 'eval': if interaction.user.id not in Configuration.get_master_var( 'BOT_ADMINS'): return output = await self.bot.redis_pool.get(f'eval:{parts[3]}') if output is None: await interaction.response.send_message( "Eval output no longer available", ephemeral=True) else: pages = Pages.paginate(output, prefix='```py\n', suffix='```') content, view, page_num = SimplePager.get_parts( pages, int(parts[1]), interaction.guild_id, f'eval:{parts[3]}') await interaction.response.edit_message( content= f'Eval output {page_num + 1}/{len(pages)}{content}', view=view) elif t == 'commands': cog = self.bot.get_command("CustCommands") if cog is not None: pages = cog.get_command_pages(interaction.guild_id) content, view, page_num = SimplePager.get_parts( pages, int(parts[1]), guild.id, 'commands') page = cog.gen_command_page(pages, page_num, interaction.guild) await interaction.response.edit_message(embed=page, view=view) elif t == 'emoji': cog = self.bot.get_cog('Emoji') if cog is not None: amount = len(guild.emojis) + 1 content, view, page_num = SimplePager.get_parts( range(amount), int(parts[1]), interaction.guild.id, 'emoji') await interaction.response.edit_message( embed=cog.gen_emoji_page(guild, page_num), view=view) elif t == 'role_list': cog = self.bot.get_cog('Moderation') if cog is not None: pages = cog.gen_roles_pages(interaction.guild, parts[3]) content, view, page_num = SimplePager.get_parts( pages, int(parts[1]), guild.id, f'role_list:{parts[3]}') await interaction.response.edit_message( content= f"**{Translator.translate('roles', interaction.guild_id, server_name=guild.name, page_num=page_num + 1, pages=len(pages))}**```\n{pages[page_num]}```", view=view) elif t == 'censor_list': cog = self.bot.get_cog('Moderation') if cog is not None: censor_list = Configuration.get_var( interaction.guild.id, "CENSORING", "TOKEN_CENSORLIST") pages = Pages.paginate("\n".join(censor_list)) page, view, page_num = SimplePager.get_parts( pages, int(parts[1]), interaction.guild.id, 'censor_list') await interaction.response.edit_message( content= f"**{Translator.translate(f'censor_list', guild, server=guild.name, page_num=page_num + 1, pages=len(pages))}**```\n{page}```", view=view) elif t == 'word_censor_list': cog = self.bot.get_cog('Moderation') if cog is not None: censor_list = Configuration.get_var( guild.id, "CENSORING", "WORD_CENSORLIST") pages = Pages.paginate("\n".join(censor_list)) page, view, page_num = SimplePager.get_parts( pages, int(parts[1]), guild.id, 'word_censor_list') await interaction.response.edit_message( content= f"**{Translator.translate(f'word_censor_list', guild, server=guild.name, page_num=page_num + 1, pages=len(pages))}**```\n{page}```", view=view) elif t == 'full_censor_list': cog = self.bot.get_cog('Moderation') if cog is not None: censor_list = Configuration.get_var( guild.id, "CENSORING", "FULL_MESSAGE_LIST") pages = Pages.paginate("\n".join(censor_list)) page, view, page_num = SimplePager.get_parts( pages, int(parts[1]), guild.id, 'full_censor_list') await interaction.response.edit_message( content= f"**{Translator.translate(f'full_censor_list', guild, server=guild.name, page_num=page_num + 1, pages=len(pages))}**```\n{page}```", view=view) elif t == 'flag_list': cog = self.bot.get_cog('Moderation') if cog is not None: censor_list = Configuration.get_var( guild.id, "FLAGGING", "TOKEN_LIST") pages = Pages.paginate("\n".join(censor_list)) page, view, page_num = SimplePager.get_parts( pages, int(parts[1]), guild.id, 'flag_list') await interaction.response.edit_message( content= f"**{Translator.translate(f'flagged_list', guild, server=guild.name, page_num=page_num + 1, pages=len(pages))}**```\n{page}```", view=view) elif t == 'word_flag_list': cog = self.bot.get_cog('Moderation') if cog is not None: censor_list = Configuration.get_var( guild.id, "FLAGGING", "WORD_LIST") pages = Pages.paginate("\n".join(censor_list)) page, view, page_num = SimplePager.get_parts( pages, int(parts[1]), guild.id, 'word_flag_list') await interaction.response.edit_message( content= f"**{Translator.translate(f'flagged_word_list', guild, server=guild.name, page_num=page_num + 1, pages=len(pages))}**```\n{page}```", view=view) elif t == 'mass_failures': output = await self.bot.redis_pool.get( f'mass_failures:{parts[3]}') if output is None: await interaction.response.send_message( MessageUtils.assemble(interaction.guild_id, 'NO', 'view_expired'), ephemeral=True) else: pages = Pages.paginate(output, prefix='```\n', suffix='```') content, view, page_num = SimplePager.get_parts( pages, int(parts[1]), interaction.guild_id, f'mass_failures:{parts[3]}:{parts[4]}') await interaction.response.edit_message( content= f"**{Translator.translate(f'mass_failures_{parts[4]}', interaction.guild_id, page_num=page_num+1, pages=len(pages))}**{content}", view=view) elif cid.startswith('einf_search:'): parts = cid.split(':') uid = int(parts[1]) old_page = int(parts[2]) t = parts[3] if t == 'first_page': page, current, pages, query, fields = await get_ephemeral_cached_page( interaction, uid, 0) await interaction.response.edit_message( content=await InfractionUtils.assemble_message( interaction.guild_id, page, query, current, pages), view=EphemeralInfSearch(filters=fields, pages=pages, current_page=current, guild_id=interaction.guild_id, userid=uid)) elif t == 'prev_page': page, current, pages, query, fields = await get_ephemeral_cached_page( interaction, uid, old_page - 1) await interaction.response.edit_message( content=await InfractionUtils.assemble_message( interaction.guild_id, page, query, current, pages), view=EphemeralInfSearch(filters=fields, pages=pages, current_page=current, guild_id=interaction.guild_id, userid=uid)) elif t == 'blank': await interaction.response.send_message( Emoji.get_chat_emoji('AE'), ephemeral=True) elif t == 'next_page': page, current, pages, query, fields = await get_ephemeral_cached_page( interaction, uid, old_page + 1) await interaction.response.edit_message( content=await InfractionUtils.assemble_message( interaction.guild_id, page, query, current, pages), view=EphemeralInfSearch(filters=fields, pages=pages, current_page=current, guild_id=interaction.guild_id, userid=uid)) elif t == 'last_page': page, current, pages, query, fields = await get_ephemeral_cached_page( interaction, uid, 1000) await interaction.response.edit_message( content=await InfractionUtils.assemble_message( interaction.guild_id, page, query, current, pages), view=EphemeralInfSearch(filters=fields, pages=pages, current_page=current, guild_id=interaction.guild_id, userid=uid)) elif interaction.type == InteractionType.application_command: if interaction.data.name == "Extract user IDs": self.bot.metrics.uid_usage.labels( type="channel", cluster=self.bot.cluster).inc() await interaction.response.defer(ephemeral=True) parts = await Utils.get_user_ids(interaction.target.content) if len(parts) > 0: for chunk in Pages.paginate("\n".join(parts), 200): await interaction.followup.send(chunk) else: await interaction.followup.send( MessageUtils.assemble(interaction.guild, "NO", "no_uids_found")) elif interaction.data.name == "Send user IDs to DM": self.bot.metrics.uid_usage.labels( type="DM", cluster=self.bot.cluster).inc() await interaction.response.defer(ephemeral=True) parts = await Utils.get_user_ids(interaction.target.content) if len(parts) > 0: try: for chunk in Pages.paginate("\n".join(parts), 200): await interaction.user.send(chunk) except Forbidden: await interaction.followup.send("Unable to send DM") else: await interaction.followup.send("IDs sent in DM") else: try: await interaction.user.send( MessageUtils.assemble(interaction.guild, "NO", "no_uids_found")) except Forbidden: await interaction.followup.send("Unable to send DM") else: await interaction.followup.send("IDs sent in DM") elif interaction.data.name == "Userinfo": if await Permissioncheckers.check_permission( self.bot.get_command("userinfo"), interaction.guild, interaction.user, self.bot): t = "allowed" target = interaction.data.target embed = await Utils.generate_userinfo_embed( target, target if isinstance(target, Member) else None, interaction.guild, interaction.user) await interaction.response.send_message(embed=embed, ephemeral=True) else: t = "denied" await interaction.response.send_message( MessageUtils.assemble(interaction.guild, 'LOCK', 'permission_denied'), ephemeral=True) self.bot.metrics.userinfo_usage.labels( type=t, cluster=self.bot.cluster).inc() elif interaction.data.name == "Search Infractions": if await Permissioncheckers.check_permission( self.bot.get_command("inf search"), interaction.guild, interaction.user, self.bot): uid = interaction.data.target.id t = "allowed" await interaction.response.send_message( MessageUtils.assemble(interaction.guild, 'SEARCH', 'inf_search_compiling'), ephemeral=True) pages = await InfractionUtils.fetch_infraction_pages( interaction.guild.id, uid, 100, ["[user]", "[mod]", "[reason]"], 0) page = await self.bot.wait_for( 'page_assembled', check=lambda l: l['key'] == get_key( interaction.guild.id, uid, [ "[user]", "[mod]", "[reason]" ], 100) and l['page_num'] == 0) await interaction.edit_original_message( content=await InfractionUtils.assemble_message( interaction.guild.id, page['page'], uid, 0, pages), view=EphemeralInfSearch( filters=["[user]", "[mod]", "[reason]"], pages=pages, guild_id=interaction.guild.id, userid=uid)) else: t = "denied" await interaction.response.send_message( MessageUtils.assemble(interaction.guild, 'LOCK', 'permission_denied'), ephemeral=True) self.bot.metrics.inf_search_usage.labels( type=t, cluster=self.bot.cluster).inc()