def __get_member(self, action: proto.Action) -> discord.Member: assert action.HasField('user_id') # FIXME: This will not work once the bot is larger than a single process. guild = self.__get_guild(action) if guild is None: return None return utils.get_member_async(guild, action.user_id)
async def _apply_ban(self, action: proto.Action) -> None: assert action.WhichOneof('details') == 'ban' guild = self.__get_guild(action) if guild is None: return assert action.HasField('user_id') user = fake.FakeSnowflake(id=action.user_id) if action.ban.type != proto.BanMember.UNBAN: await guild.ban(user, reason=_get_reason(action), delete_message_days=action.ban.delete_message_days) if action.ban.type != proto.BanMember.BAN: await guild.unban(user, reason=_get_reason(action))
def invert_action(action: proto.Action) -> proto.Action: new_action = proto.Action() new_action.CopyFrom(action) if action.HasField('reason'): new_action.reason = 'Undo: ' + action.reason new_action.ClearField('duration') try: INVERT_MAPPING[action.WhichOneof('details')](new_action) except KeyError: raise ValueError('Provided action cannot be inverted.') return new_action
async def _apply_command(self, action: proto.Action) -> None: assert action.WhichOneof('details') == 'command' channel = self.bot.get_channel(action.command.channel_id) try: guild = channel.guild except AttributeError: guild = self.bot.get_guild(action.guild_id) if action.HasField('user_id'): user = (await self.__get_member(action)) if guild is not None \ else (await self.__get_user(action)) else: user = (guild.me if guild is not None else self.bot.user) ctx = await self.bot.get_automated_context( content=action.command.command, author=user, channel=channel, guild=guild) async with ctx: await self.bot.invoke(ctx)
async def execute(self, action: proto.Action) -> None: action_type = action.WhichOneof('details') try: await getattr(self, "_apply_" + action_type)(action) if not action.HasField('duration'): return # Schedule an undo duration = timedelta(seconds=action.duration) self.bot.action_manager.schedule(datetime.utcnow() + duration, invert_action(action)) except AttributeError: raise ValueError(f'Action type not supported: {action_type}') except discord.NotFound: # If the guild or the target is not found, silence the error pass except discord.Forbidden: # TODO(james7132): Properly report missing permissions # If the guild or the target is not found, silence the error pass self.bot.logger.exception('Error while executing action:') except Exception: self.bot.logger.exception('Error while executing action:')
def _get_reason(action: proto.Action) -> str: if action.HasField('reason'): return action.reason return None
def __get_user(self, action: proto.Action) -> discord.User: assert action.HasField('user_id') return utils.get_user_async(self.bot, action.user_id)
def __get_guild(self, action: proto.Action) -> discord.Guild: assert action.HasField('guild_id') return self.bot.get_guild(action.guild_id)