async def get_cases_for_member( guild: discord.Guild, bot: Red, *, member: discord.Member = None, member_id: int = None ) -> List[Case]: """ Gets all cases for the specified member or member id in a guild. Parameters ---------- guild: `discord.Guild` The guild to get the cases from bot: Red The bot's instance member: `discord.Member` The member to get cases about member_id: int The id of the member to get cases about Returns ------- list A list of all matching cases. Raises ------ ValueError If at least one of member or member_id is not provided `discord.Forbidden` The bot does not have permission to fetch the modlog message which was sent. `discord.HTTPException` Fetching the user failed. """ cases = await _config.custom(_CASES, str(guild.id)).all() if not (member_id or member): raise ValueError("Expected a member or a member id to be provided.") from None if not member_id: member_id = member.id if not member: member = bot.get_user(member_id) or member_id try: modlog_channel = await get_modlog_channel(guild) except RuntimeError: modlog_channel = None cases = [ await Case.from_json(modlog_channel, bot, case_number, case_data, user=member, guild=guild) for case_number, case_data in cases.items() if case_data["user"] == member_id ] return cases
def red(config_fr): from beastbot.core.cli import parse_cli_flags cli_flags = parse_cli_flags(["ignore_me"]) description = "Red v3 - Alpha" Config.get_core_conf = lambda *args, **kwargs: config_fr red = Red(cli_flags=cli_flags, description=description, dm_help=None, owner_ids=set()) yield red
def handle_edit(cli_flags: Namespace): """ This one exists to not log all the things like it's a full run of the bot. """ loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) data_manager.load_basic_configuration(cli_flags.instance_name) red = Red(cli_flags=cli_flags, description="Red V3", dm_help=None) try: driver_cls = drivers.get_driver_class() loop.run_until_complete( driver_cls.initialize(**data_manager.storage_details())) loop.run_until_complete(edit_instance(red, cli_flags)) loop.run_until_complete(driver_cls.teardown()) except (KeyboardInterrupt, EOFError): print("Aborted!") finally: loop.run_until_complete(asyncio.sleep(1)) asyncio.set_event_loop(None) loop.stop() loop.close() sys.exit(0)
async def setup(bot: Red) -> None: cog = Filter(bot) await cog.initialize() bot.add_cog(cog)
def setup(bot: Red): bot.add_cog(ModLog(bot))
async def _init(bot: Red): global _config global _bot_ref _bot_ref = bot _config = Config.get_conf(None, 1354799444, cog_name="ModLog") _config.register_global(schema_version=1) _config.register_guild(mod_log=None, casetypes={}, latest_case_number=0) _config.init_custom(_CASETYPES, 1) _config.init_custom(_CASES, 2) _config.register_custom(_CASETYPES) _config.register_custom(_CASES) await _migrate_config(from_version=await _config.schema_version(), to_version=_SCHEMA_VERSION) await register_casetypes(all_generics) async def on_member_ban(guild: discord.Guild, member: discord.Member): if not guild.me.guild_permissions.view_audit_log: return try: await get_modlog_channel(guild) except RuntimeError: return # No modlog channel so no point in continuing when = datetime.utcnow() before = when + timedelta(minutes=1) after = when - timedelta(minutes=1) await asyncio.sleep(10) # prevent small delays from causing a 5 minute delay on entry attempts = 0 # wait up to an hour to find a matching case while attempts < 12 and guild.me.guild_permissions.view_audit_log: attempts += 1 try: entry = await guild.audit_logs( action=discord.AuditLogAction.ban, before=before, after=after ).find(lambda e: e.target.id == member.id and after < e.created_at < before) except discord.Forbidden: break except discord.HTTPException: pass else: if entry: if entry.user.id != guild.me.id: # Don't create modlog entires for the bot's own bans, cogs do this. mod, reason = entry.user, entry.reason date = entry.created_at.replace(tzinfo=timezone.utc) await create_case(_bot_ref, guild, date, "ban", member, mod, reason) return await asyncio.sleep(300) async def on_member_unban(guild: discord.Guild, user: discord.User): if not guild.me.guild_permissions.view_audit_log: return try: await get_modlog_channel(guild) except RuntimeError: return # No modlog channel so no point in continuing when = datetime.utcnow() before = when + timedelta(minutes=1) after = when - timedelta(minutes=1) await asyncio.sleep(10) # prevent small delays from causing a 5 minute delay on entry attempts = 0 # wait up to an hour to find a matching case while attempts < 12 and guild.me.guild_permissions.view_audit_log: attempts += 1 try: entry = await guild.audit_logs( action=discord.AuditLogAction.unban, before=before, after=after ).find(lambda e: e.target.id == user.id and after < e.created_at < before) except discord.Forbidden: break except discord.HTTPException: pass else: if entry: if entry.user.id != guild.me.id: # Don't create modlog entires for the bot's own unbans, cogs do this. mod, reason = entry.user, entry.reason date = entry.created_at.replace(tzinfo=timezone.utc) await create_case(_bot_ref, guild, date, "unban", user, mod, reason) return await asyncio.sleep(300) bot.add_listener(on_member_ban) bot.add_listener(on_member_unban)
async def from_json( cls, mod_channel: discord.TextChannel, bot: Red, case_number: int, data: dict, **kwargs ): """Get a Case object from the provided information Parameters ---------- mod_channel: discord.TextChannel The mod log channel for the guild bot: Red The bot's instance. Needed to get the target user case_number: int The case's number. data: dict The JSON representation of the case to be gotten **kwargs Extra attributes for the Case instance which override values in the data dict. These should be complete objects and not IDs, where possible. Returns ------- Case The case object for the requested case Raises ------ `discord.NotFound` The user the case is for no longer exists `discord.Forbidden` Cannot read message history to fetch the original message. `discord.HTTPException` A generic API issue """ guild = kwargs.get("guild") or mod_channel.guild message = kwargs.get("message") if message is None: message_id = data.get("message") if message_id is not None: message = discord.utils.get(bot.cached_messages, id=message_id) if message is None: try: message = await mod_channel.fetch_message(message_id) except discord.HTTPException: message = None else: message = None user_objects = {"user": None, "moderator": None, "amended_by": None} for user_key in tuple(user_objects): user_object = kwargs.get(user_key) if user_object is None: user_id = data.get(user_key) if user_id is None: user_object = None else: user_object = bot.get_user(user_id) or user_id user_objects[user_key] = user_object channel = kwargs.get("channel") or guild.get_channel(data["channel"]) or data["channel"] case_guild = kwargs.get("guild") or bot.get_guild(data["guild"]) return cls( bot=bot, guild=case_guild, created_at=data["created_at"], action_type=data["action_type"], case_number=case_number, reason=data["reason"], until=data["until"], channel=channel, modified_at=data["modified_at"], message=message, last_known_username=data.get("last_known_username"), **user_objects, )
def setup(bot: Red): bot.add_cog(Economy(bot))
async def setup(bot: Red): cog = Mutes(bot) bot.add_cog(cog) await cog.initialize()
def main(): red = None # Error handling for users misusing the bot cli_flags = parse_cli_flags(sys.argv[1:]) handle_early_exit_flags(cli_flags) if cli_flags.edit: handle_edit(cli_flags) return try: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) if cli_flags.no_instance: print( "\033[1m" "Warning: The data will be placed in a temporary folder and removed on next system " "reboot." "\033[0m") cli_flags.instance_name = "temporary_red" data_manager.create_temp_config() data_manager.load_basic_configuration(cli_flags.instance_name) red = Red(cli_flags=cli_flags, description="Red V3", dm_help=None) if os.name != "nt": # None of this works on windows. # At least it's not a redundant handler... signals = (signal.SIGHUP, signal.SIGTERM, signal.SIGINT) for s in signals: loop.add_signal_handler( s, lambda s=s: asyncio.create_task(shutdown_handler(red, s))) exc_handler = functools.partial(global_exception_handler, red) loop.set_exception_handler(exc_handler) # We actually can't (just) use asyncio.run here # We probably could if we didn't support windows, but we might run into # a scenario where this isn't true if anyone works on RPC more in the future fut = loop.create_task(run_bot(red, cli_flags)) r_exc_handler = functools.partial(red_exception_handler, red) fut.add_done_callback(r_exc_handler) loop.run_forever() except KeyboardInterrupt: # We still have to catch this here too. (*joy*) log.warning( "Please do not use Ctrl+C to Shutdown Red! (attempting to die gracefully...)" ) log.error("Received KeyboardInterrupt, treating as interrupt") if red is not None: loop.run_until_complete(shutdown_handler(red, signal.SIGINT)) except SystemExit as exc: # We also have to catch this one here. Basically any exception which normally # Kills the python interpreter (Base Exceptions minus asyncio.cancelled) # We need to do something with prior to having the loop close log.info("Shutting down with exit code: %s", exc.code) if red is not None: loop.run_until_complete(shutdown_handler(red, None, exc.code)) except Exception as exc: # Non standard case. log.exception("Unexpected exception (%s): ", type(exc), exc_info=exc) if red is not None: loop.run_until_complete( shutdown_handler(red, None, ExitCodes.CRITICAL)) finally: # Allows transports to close properly, and prevent new ones from being opened. # Transports may still not be closed correctly on windows, see below loop.run_until_complete(loop.shutdown_asyncgens()) # *we* aren't cleaning up more here, but it prevents # a runtime error at the event loop on windows # with resources which require longer to clean up. # With other event loops, a failure to cleanup prior to here # results in a resource warning instead log.info("Please wait, cleaning up a bit more") loop.run_until_complete(asyncio.sleep(2)) asyncio.set_event_loop(None) loop.stop() loop.close() exit_code = red._shutdown_mode if red is not None else 1 sys.exit(exit_code)
async def setup(bot: Red): cog = Alias(bot) bot.add_cog(cog) cog.sync_init()
def setup(bot: Red): bot.add_cog(Cleanup(bot))
def setup(bot: Red): bot.add_cog(Reports(bot))
def setup(bot: Red): cog = Audio(bot) bot.add_cog(cog) cog.start_up_task()