async def yes(): failures = await Actions.mass_action(ctx, "warning", targets, self._warn, max_targets=10, allow_bots=False, message=False, reason=reason, dm_action=True, require_on_server=False) await MessageUtils.send_to(ctx, "YES", "mwarn_confirmation", count=len(targets) - len(failures)) if len(failures) > 0: await Pages.create_new(self.bot, "mass_failures", ctx, action_type="warn", failures="----NEW PAGE----".join(Pages.paginate("\n".join(failures))))
async def uid(self, ctx, *, text: str): """uid_help""" parts = await Utils.get_user_ids(text) if len(parts) > 0: for chunk in Pages.paginate("\n".join(parts), 200): await ctx.send(chunk) else: await MessageUtils.send_to(ctx, "NO", "no_uids_found")
def gen_roles_pages(guild: discord.Guild): role_list = dict() longest_name = 1 for role in guild.roles: role_list[f"{role.name} - {role.id}"] = role longest_name = max(longest_name, len(role.name)) return Pages.paginate("\n".join( f"{role_list[r].name} {' ' * (longest_name - len(role_list[r].name))} - {role_list[r].id}" for r in sorted(role_list.keys())))
async def mutuals(self, ctx, user: UserID): mutuals = [] for guild in self.bot.guilds: if guild.get_member(user) is not None: mutuals.append(guild) for page in Pages.paginate("\n".join(f"{guild.id} - {guild.name}" for guild in mutuals), prefix="```py\n", suffix="```"): await ctx.send(page)
async def gen_cog_help(bot, cog, member, guild): commands, longest = await cog_commands(bot, cog, member, guild) output = f'- {cog}\n' if commands is not None: for command_name, info in commands.items(): output += command_name + ( " " * (longest - len(command_name) + 4)) + info + "\n" return Pages.paginate(output) else: return None
def gen_role_pages(self, guild: discord.Guild): roles = Configuration.get_var(guild.id, "SELF_ROLES") current_roles = "" count = 1 for role in roles: current_roles += f"{count}) <@&{role}>\n\n" count += 1 if count > 10: count = 1 return Pages.paginate(current_roles, max_lines=20)
async def fetch_infraction_pages(guild_id, query, amount, fields, requested): key = get_key(guild_id, query, fields, amount) if query == "": infs = await Infraction.filter(guild_id=guild_id ).order_by("-id").limit(50) else: subfilters = [] if "[user]" in fields and isinstance(query, int): subfilters.append(Q(user_id=query)) if "[mod]" in fields and isinstance(query, int): subfilters.append(Q(mod_id=query)) if "[reason]" in fields: subfilters.append(Q(reason__icontains=str(query))) infs = await Infraction.filter( Q(Q(*subfilters, join_type="OR"), guild_id=guild_id, join_type="AND")).order_by("-id").limit(int(amount)) longest_type = 4 longest_id = len(str(infs[0].id)) if len(infs) > 0 else len( Translator.translate('id', guild_id)) longest_timestamp = max(len(Translator.translate('timestamp', guild_id)), 19) types = dict() for inf in infs: t = inf.type.lower() longest_type = max(longest_type, len(Translator.translate(t, guild_id))) if t not in types: types[t] = 1 else: types[t] += 1 header = ", ".join( Translator.translate(f"{k}s", guild_id, count=v) for k, v in types.items()) name = await Utils.username(query) if isinstance( query, int) else await Utils.clean(bot.get_guild(guild_id).name) title = f"{Emoji.get_chat_emoji('SEARCH')} {Translator.translate('inf_search_header', guild_id, name=name, page_num=100, pages=100)}\n```md\n\n```" page_header = get_header(longest_id, 37, longest_type, longest_timestamp, guild_id) mcount = 2000 - len(header) - len(page_header) - len(title) out = "\n".join( f"{Utils.pad(str(inf.id), longest_id)} | <@{Utils.pad(str(inf.user_id), 37)}> | <@{Utils.pad(str(inf.mod_id), 37)}> | {datetime.fromtimestamp(inf.start)} | {Utils.pad(Translator.translate(inf.type.lower(), guild_id), longest_type)} | {Utils.trim_message(inf.reason, 1000)}" for inf in infs) pages = Pages.paginate(out, max_chars=mcount) if bot.redis_pool is not None: GearbotLogging.debug(f"Pushing placeholders for {key}") pipe = bot.redis_pool.pipeline() for page in pages: pipe.lpush(key, "---NO PAGE YET---") await pipe.execute() bot.loop.create_task( update_pages(guild_id, query, fields, amount, pages, requested, longest_id, longest_type, longest_timestamp, header)) return len(pages)
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 pull(self, ctx): """Pulls from github so an upgrade can be performed without full restart""" async with ctx.typing(): code, out, error = await Utils.execute(["git pull origin master"]) if code is 0: await Pages.create_new( "pull", ctx, title= f"{Emoji.get_chat_emoji('YES')} Pull completed with exit code {code}", pages=Pages.paginate(out.decode('utf-8'))) else: await ctx.send( f"{Emoji.get_chat_emoji('NO')} Pull completed with exit code {code}```yaml\n{out.decode('utf-8')}\n{error.decode('utf-8')}```" )
async def gen_command_help(bot, ctx, command): if ctx.prefix is None: ctx.prefix = "" bot.help_command.context = ctx usage = ctx.bot.help_command.get_command_signature(command) sub_info = None if isinstance(command, GroupMixin) and hasattr(command, "all_commands"): subcommands, longest = await gen_commands_list(bot, ctx, command.all_commands.values()) if subcommands is not None: sub_info = "\nSub commands:\n" for command_name, info in subcommands.items(): sub_info += " " + command_name + (" " * (longest - len(command_name) + 4)) + info + "\n" sub_info += Translator.translate('help_footer', ctx, prefix=ctx.prefix, signature=ctx.bot.help_command.get_command_signature(command).replace(ctx.prefix, "")) return Pages.paginate(f"{usage}\n\n{Translator.translate(command.help, ctx)}\n{'' if sub_info is None else sub_info}".replace(ctx.me.mention, f"@{ctx.me.name}"))
async def gen_command_help(bot, ctx, command): usage = ctx.prefix.replace(ctx.me.mention, f"@{ctx.me.name}") + command.signature sub_info = None if isinstance(command, GroupMixin) and hasattr(command, "all_commands"): subcommands, longest = await gen_commands_list( bot, ctx, command.all_commands.values()) if subcommands is not None: sub_info = "\nSub commands:\n" for command_name, info in subcommands.items(): sub_info += " " + command_name + ( " " * (longest - len(command_name) + 4)) + info + "\n" sub_info += f"You can get more info about a command (params and subcommands) by using '{ctx.prefix}help {command.signature} <subcommand>'\nCommands followed by ↪ have subcommands".replace( ctx.me.mention, f"@{ctx.me.name}") + command.signature return Pages.paginate( f"{usage}\n\n{Translator.translate(command.help, ctx)}\n{'' if sub_info is None else sub_info}" .replace(ctx.me.mention, f"@{ctx.me.name}"))
async def list(self, ctx): """remind_list_help""" reminders = await Reminder.filter(status=ReminderStatus.Pending, user_id=ctx.author.id) if len(reminders) == 0: await MessageUtils.send_to(ctx, "WARNING", "reminder_none") return items = "\n".join( f"{str(r.id).ljust(5)} | {timeago.format(r.send).ljust(14)} | {timeago.format(r.time).ljust(14)} | {Utils.clean_name(r.to_remind)}" for r in reminders) header = "ID | Scheduled | Delivery | Content" pages = Pages.paginate( items, prefix=f"```md\n{header}\n{'-' * len(header)}\n", suffix="```") await Pages.create_new(self.bot, "reminder_list", ctx, pages=json.dumps(pages))
def dict_to_pages(dict, suffix=""): pages = [] output = "" for out in dict.values(): if len(output) + len(out) > 1000: pages.append(f"{output}\n{suffix}") output = out else: if output == "": output = Utils.trim_message(out, 2000 - 15 - len(suffix)) else: output += out + "\n" pages.append(f"{output}\n{suffix}") # if some page does end up over 2k, split it real_pages = [] for p in pages: for page in Pages.paginate(p, max_lines=100): real_pages.append(page) return real_pages
async def yes(): pmessage = await MessageUtils.send_to(ctx, "REFRESH", "processing") failures = await Actions.mass_action(ctx, "warning", targets, self._warn, max_targets=10, allow_bots=False, message=False, reason=reason) await pmessage.delete() await MessageUtils.send_to(ctx, "YES", "mwarn_confirmation", count=len(targets) - len(failures)) if len(failures) > 0: await Pages.create_new(self.bot, "mass_failures", ctx, action="warn", failures="----NEW PAGE----".join( Pages.paginate( "\n".join(failures))))
async def _blacklist_init(ctx): pages = Pages.paginate("\n".join(Configuration.get_var(ctx.guild.id, "WORD_BLACKLIST"))) return f"**{Translator.translate(f'blacklist_list', ctx, server=ctx.guild.name, page_num=1, pages=len(pages))}**```\n{pages[0]}```", None, len(pages) > 1, []
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()
async def updater(cog: BCVersionChecker): GearbotLogging.info("Started BC version checking background task") session: aiohttp.ClientSession = cog.bot.aiosession lastUpdate = 0 while cog.running: try: # check for a newer bc version async with session.get( 'https://www.mod-buildcraft.com/build_info_full/last_change.txt' ) as reply: stamp = await reply.text() stamp = int(stamp[:-1]) if stamp > lastUpdate: GearbotLogging.info("New BC version somewhere!") lastUpdate = stamp cog.BC_VERSION_LIST = await getList(session, "BuildCraft") cog.BCC_VERSION_LIST = await getList( session, "BuildCraftCompat") highestMC = VersionInfo.getLatest( cog.BC_VERSION_LIST.keys()) latestBC = VersionInfo.getLatest( cog.BC_VERSION_LIST[highestMC]) generalID = 309218657798455298 channel: discord.TextChannel = cog.bot.get_channel( generalID) old_latest = Configuration.get_persistent_var( "latest_bc", "0.0.0") Configuration.set_persistent_var( "latest_bc", latestBC ) # save already so we don't get stuck and keep trying over and over if something goes wrong if channel is not None and latestBC != old_latest: GearbotLogging.info( f"New BuildCraft version found: {latestBC}") notify_channel = cog.bot.get_channel( 349517224320565258) await notify_channel.send( f"{Emoji.get_chat_emoji('WRENCH')} New BuildCraft version detected ({latestBC})" ) GearbotLogging.info( f"Fetching metadata for BuildCraft {latestBC}") message = await notify_channel.send( f"{Emoji.get_chat_emoji('REFRESH')} Fetching metadata..." ) info = await cog.getVersionDetails( "BuildCraft", latestBC) GearbotLogging.info(f"Metadata acquired: {info}") await message.edit( content= f"{Emoji.get_chat_emoji('YES')} Metadata acquired") if 'blog_entry' in info: message = await notify_channel.send( f"{Emoji.get_chat_emoji('REFRESH')} Updating general topic..." ) newTopic = f"General discussions about BuildCraft.\n" \ f"Latest version: {latestBC}\n" \ f"Full changelog and download: {info['blog_entry']}" await channel.edit(topic=newTopic) await message.edit( content= f"{Emoji.get_chat_emoji('YES')} Topic updated") else: notify_channel.send( f"{Emoji.get_chat_emoji('WARNING')} No blog post data found, notifying <@180057061353193472>" ) # message = await notify_channel.send(f"{Emoji.get_chat_emoji('REFRESH')} Uploading files to CurseForge...") # code, output, errors = await Utils.execute(f'cd BuildCraft/uploader && gradle curseforge -Pnew_version="{latestBC}"') # GearbotLogging.info(f"Upload to CF complete\n)------stdout------\n{output}\n------stderr------\n{errors}") # if code is 0: # content = f"{Emoji.get_chat_emoji('YES')} All archives successfully uploaded" # await message.edit(content=content) # else: # content = f"{Emoji.get_chat_emoji('NO')} Upload failed with code {code}, notifying <@106354106196570112>" # await notify_channel.send(content) # update FAQs if needed async with session.get( 'https://mod-buildcraft.com/website_src/faq.md') as reply: data = await reply.text() h = hashlib.md5(data.encode('utf-8')).hexdigest() old = Configuration.get_persistent_var("BCFAQ", "") channel = cog.bot.get_channel(361557801492938762) # FAQs if channel is not None and h != old: Configuration.set_persistent_var("BCFAQ", h) #clean the old stuff await channel.purge() #send banner with open("BuildCraft/FAQs.png", "rb") as file: await channel.send(file=File(file, filename="FAQs.png") ) #send content out = "" parts = [ d.strip("#").strip() for d in data.split("##")[1:] ] for part in parts: lines = part.splitlines() content = '\n'.join(lines[1:]) out += f"**```{lines[0].strip()}```**{content}\n" for page in Pages.paginate(out, max_chars=2048, max_lines=50): embed = Embed(description=page) await channel.send(embed=embed) pass except CancelledError: pass # bot shutdown except Exception as ex: cog.bot.errors = cog.bot.errors + 1 GearbotLogging.error( "Something went wrong in the BC version checker task") GearbotLogging.error(traceback.format_exc()) embed = discord.Embed(colour=discord.Colour(0xff0000), timestamp=datetime.datetime.utcfromtimestamp( time.time())) embed.set_author( name="Something went wrong in the BC version checker task:") embed.add_field(name="Exception", value=str(ex)) v = "" for line in traceback.format_exc().splitlines(): if len(v) + len(line) >= 1024: embed.add_field(name="Stacktrace", value=v) v = "" v = f"{v}\n{line}" if len(v) > 0: embed.add_field(name="Stacktrace", value=v) await GearbotLogging.bot_log(embed=embed) for i in range(1, 60): if cog.force or not cog.running: break await asyncio.sleep(10) GearbotLogging.info("BC version checking background task terminated")
async def handle_exception(exception_type, bot, exception, event=None, message=None, ctx=None, *args, **kwargs): if bot is not None: bot.errors = bot.errors + 1 with sentry_sdk.push_scope() as scope: embed = Embed(colour=Colour(0xff0000), timestamp=datetime.utcfromtimestamp(time.time())) # something went wrong and it might have been in on_command_error, make sure we log to the log file first lines = [ "\n===========================================EXCEPTION CAUGHT, DUMPING ALL AVAILABLE INFO===========================================", f"Type: {exception_type}" ] arg_info = "" for arg in list(args): arg_info += extract_info(arg) + "\n" if arg_info == "": arg_info = "No arguments" kwarg_info = "" for name, arg in kwargs.items(): kwarg_info += "{}: {}\n".format(name, extract_info(arg)) if kwarg_info == "": kwarg_info = "No keyword arguments" lines.append("======================Exception======================") lines.append(f"{str(exception)} ({type(exception)})") lines.append("======================ARG INFO======================") lines.append(arg_info) sentry_sdk.add_breadcrumb(category='arg info', message=arg_info, level='info') lines.append("======================KWARG INFO======================") lines.append(kwarg_info) sentry_sdk.add_breadcrumb(category='kwarg info', message=kwarg_info, level='info') lines.append("======================STACKTRACE======================") tb = "".join(traceback.format_tb(exception.__traceback__)) lines.append(tb) if message is None and event is not None and hasattr(event, "message"): message = event.message if message is None and ctx is not None: message = ctx.message if message is not None and hasattr(message, "content"): lines.append( "======================ORIGINAL MESSAGE======================") lines.append(message.content) if message.content is None or message.content == "": content = "<no content>" else: content = message.content scope.set_tag('message content', content) embed.add_field(name="Original message", value=Utils.trim_message(content, 1000), inline=False) lines.append( "======================ORIGINAL MESSAGE (DETAILED)======================" ) lines.append(extract_info(message)) if event is not None: lines.append( "======================EVENT NAME======================") lines.append(event) scope.set_tag('event name', event) embed.add_field(name="Event", value=event) if ctx is not None: lines.append( "======================COMMAND INFO======================") lines.append(f"Command: {ctx.command.name}") embed.add_field(name="Command", value=ctx.command.name) scope.set_tag('command', ctx.command.name) channel_name = 'Private Message' if isinstance( ctx.channel, PrivateChannel) else f"{ctx.channel.name} (`{ctx.channel.id}`)" lines.append(f"Channel: {channel_name}") embed.add_field(name="Channel", value=channel_name, inline=False) scope.set_tag('channel', channel_name) sender = f"{str(ctx.author)} (`{ctx.author.id}`)" scope.user = dict(id=ctx.author.id, username=str(ctx.author)) lines.append(f"Sender: {sender}") embed.add_field(name="Sender", value=sender, inline=False) lines.append( "===========================================DATA DUMP COMPLETE===========================================" ) GearbotLogging.error("\n".join(lines)) for t in [ConnectionClosed, ClientOSError, ServerDisconnectedError]: if isinstance(exception, t): return #nice embed for info on discord embed.set_author(name=exception_type) embed.add_field(name="Exception", value=f"{str(exception)} (`{type(exception)}`)", inline=False) parts = Pages.paginate(tb, max_chars=1024) num = 1 for part in parts: embed.add_field(name=f"Traceback {num}/{len(parts)}", value=part) num += 1 sentry_sdk.capture_exception(exception) # try logging to botlog, wrapped in an try catch as there is no higher lvl catching to prevent taking down the bot (and if we ended here it might have even been due to trying to log to botlog try: await GearbotLogging.bot_log(embed=embed) except Exception as ex: GearbotLogging.error( f"Failed to log to botlog, either Discord broke or something is seriously wrong!\n{ex}" ) GearbotLogging.error(traceback.format_exc())
async def send_buffer(channel, buffer): pages = Pages.paginate(buffer, max_lines=500) for page in pages: await channel.send(page)
async def _blacklist_update(ctx, message, page_num, action, data): pages = Pages.paginate("\n".join(Configuration.get_var(ctx.guild.id, "WORD_BLACKLIST"))) page, page_num = Pages.basic_pages(pages, page_num, action) return f"**{Translator.translate(f'blacklist_list', ctx, server=message.channel.guild.name, page_num=page_num + 1, pages=len(pages))}**```\n{page}```", None, page_num