Ejemplo n.º 1
0
def get_unbanish_duration(
    ctx: Context, template_engine: TemplateEngine, args: Tuple[str, ...]
) -> Tuple[Optional[datetime.timedelta], Optional[datetime.datetime]]:
    """Return appropriate duration and end date for a banish."""
    duration, end_date = time.extract_time(args)

    if duration is None:
        forever = any([arg.lower() in forever_words for arg in args])

        if not forever:
            command_type = template_engine.get_command_type(ctx.invoked_with)
            current_time = datetime.datetime.now()

            try:
                if command_type == MuteCommandType.MICRO:
                    duration = datetime.timedelta(seconds=10)
                elif command_type == MuteCommandType.SUPER:
                    duration = datetime.timedelta(weeks=1)
                elif command_type == MuteCommandType.MEGA:
                    duration = datetime.timedelta(days=365)
                else:
                    duration = datetime.timedelta(minutes=5)

                end_date = current_time + duration

            except OverflowError:
                end_date = datetime.datetime.max
                duration = end_date - current_time

    return duration, end_date
Ejemplo n.º 2
0
async def run_command(ctx: Context, coginfo: CogInfo,
                      template_engine: TemplateEngine,
                      args: Tuple[str, ...]) -> None:
    """Interpret the command and delegate task to the appropriate sub-function."""
    if template_engine.get_command_type(
            ctx.invoked_with) == MuteCommandType.UNDO:
        msg = await attempt_unbanish(ctx, coginfo, template_engine)
        await ctx.send(msg)
    else:
        await banish(ctx, coginfo, template_engine, args)
Ejemplo n.º 3
0
async def attempt_unbanish(ctx: Context, coginfo: CogInfo,
                           template_engine: TemplateEngine) -> str:
    """Undo one or more banishes."""
    if coginfo.bot:
        bot: MrFreeze = coginfo.bot

    mentions = ctx.message.mentions
    victims = [
        u for u in mentions
        if not u.guild_permissions.administrator and u != bot.user
    ]
    success_list: List[Member] = list()
    fails_list: List[Member] = list()
    success_string = ""
    fails_string = ""
    error_string = ""
    http_exception = False
    forbidden_exception = False
    other_exception = False

    for victim in victims:
        error = await mute_db.carry_out_unbanish(bot, victim, logger)
        if isinstance(error, Exception):
            fails_list.append(victim)
            if isinstance(error, discord.HTTPException):
                http_exception = True
            elif isinstance(error, discord.Forbidden):
                forbidden_exception = True
            else:
                other_exception = True

        else:
            success_list.append(victim)

        success_string = default.mentions_list(success_list)
        fails_string = default.mentions_list(fails_list)
        error_string = get_error_string(http_exception, forbidden_exception,
                                        other_exception)

    template = get_mute_response_type(success_list, fails_list, undo=True)
    logger.debug(f"attempt_banish(): Setting template to {template}")

    response_template = template_engine.get_template(ctx.invoked_with,
                                                     template)
    if response_template:
        response = response_template.substitute(
            author=ctx.author.mention,
            victims=success_string,
            fails=fails_string,
            errors=error_string,
        )
        return f"{ctx.author.mention} {response}"
    else:
        return f"{ctx.author.mention} Something went wrong, I'm literally at a loss for words."
Ejemplo n.º 4
0
async def banish(ctx: Context, coginfo: CogInfo,
                 template_engine: TemplateEngine, args: Tuple[str,
                                                              ...]) -> None:
    """Carry out one or more banishes."""
    if coginfo.bot:
        bot: MrFreeze = coginfo.bot
    else:
        raise InsufficientCogInfo()

    # Parse targetted users
    bot_mentioned = bot.user in ctx.message.mentions
    self_mentioned = ctx.author in ctx.message.mentions
    mentions = ctx.message.mentions
    mods = [
        u for u in mentions
        if u.guild_permissions.administrator and u != bot.user
    ]
    users = [
        u for u in mentions
        if not u.guild_permissions.administrator and u != bot.user
    ]

    if bot_mentioned or self_mentioned or mods:
        # Illegal banish, prepare silly response.
        if bot_mentioned and len(mentions) == 1:
            logger.debug("Setting template to MuteResponseType.FREEZE")
            template = MuteResponseType.FREEZE
            fails_list = [bot.user]
        elif bot_mentioned and self_mentioned and len(mentions) == 2:
            logger.debug("Setting template to MuteResponseType.FREEZE_SELF")
            template = MuteResponseType.FREEZE_SELF
            fails_list = [bot.user, ctx.author]
        elif bot_mentioned:
            logger.debug("Setting template to MuteResponseType.FREEZE_OTHERS")
            template = MuteResponseType.FREEZE_OTHERS
            fails_list = mods + users
        elif self_mentioned and len(mentions) == 1:
            logger.debug("Setting template to MuteResponseType.SELF")
            template = MuteResponseType.SELF
            fails_list = mods
        elif mods and len(mentions) == 1:
            logger.debug("Setting template to MuteResponseType.MOD")
            template = MuteResponseType.MOD
            fails_list = mods
        elif mods:
            logger.debug("Setting template to MuteResponseType.MODS")
            template = MuteResponseType.MODS
            fails_list = mods
        else:
            logger.warn("Setting template to MuteResponseType.INVALID")
            logger.warn(
                f"bot_mentioned={bot_mentioned}, self_mentioned={self_mentioned}"
            )
            logger.warn(f"{len(mentions)} mentions={mentions}")
            logger.warn(f"{len(mods)} mods={mods}")
            logger.warn(f"{len(users)} users={users}")
            template = MuteResponseType.INVALID
            fails_list = mentions

        banish_template = template_engine.get_template(ctx.invoked_with,
                                                       template)
        mention_fails = default.mentions_list(fails_list)
        if banish_template:
            msg = banish_template.substitute(author=ctx.author.mention,
                                             fails=mention_fails)
            await ctx.send(msg)

    else:
        # Legal banish, attempt banish.
        msg = await attempt_banish(ctx, coginfo, template_engine, users, args)
        await ctx.send(msg)
Ejemplo n.º 5
0
async def attempt_banish(ctx: Context, coginfo: CogInfo,
                         template_engine: TemplateEngine,
                         victims: List[Member], args: Tuple[str, ...]) -> str:
    """Attempt to carry banish some people, then return an appropriate response."""
    if coginfo.bot:
        bot: MrFreeze = coginfo.bot

    success_list: List[Member] = list()
    fails_list: List[Member] = list()
    success_string = ""
    fails_string = ""
    error_string = ""
    http_exception = False
    forbidden_exception = False
    other_exception = False
    duration, end_date = get_unbanish_duration(ctx, template_engine, args)

    for victim in victims:
        error = await mute_db.carry_out_banish(bot, victim, logger, end_date)
        if isinstance(error, Exception):
            fails_list.append(victim)
            if isinstance(error, discord.HTTPException):
                http_exception = True
            elif isinstance(error, discord.Forbidden):
                forbidden_exception = True
            else:
                other_exception = True

        else:
            success_list.append(victim)

        success_string = default.mentions_list(success_list)
        fails_string = default.mentions_list(fails_list)
        error_string = get_error_string(http_exception, forbidden_exception,
                                        other_exception)

    template = get_mute_response_type(success_list, fails_list)
    logger.debug(f"attempt_banish(): Setting template to {template}")

    timestamp_template = template_engine.get_template(
        ctx.invoked_with, MuteResponseType.TIMESTAMP)
    if timestamp_template:
        timestamp = timestamp_template.substitute(
            duration=time.parse_timedelta(duration))
    else:
        logger.warn(
            f"template_engine.get_template({ctx.invoked_with}, TIMESTAMP) returned None!"
        )
        timestamp = ""

    response_template = template_engine.get_template(ctx.invoked_with,
                                                     template)
    if response_template:
        response = response_template.substitute(author=ctx.author.mention,
                                                victims=success_string,
                                                fails=fails_string,
                                                errors=error_string,
                                                timestamp=timestamp)
        return f"{ctx.author.mention} {response}"
    else:
        return f"{ctx.author.mention} Something went wrong, I'm literally at a loss for words."
Ejemplo n.º 6
0
async def run_command(ctx: Context, coginfo: CogInfo,
                      template_engine: TemplateEngine,
                      error: Exception) -> None:
    """
    Trigger on unauthorized banish, i.e. when a non-administrator try to banish people.

    When _banish() encounters an error this method is automatically triggered. If the error
    is an instance of discord.ext.commands.CheckFailure the user will be punished accordingly,
    if not the error is raised again.

    There are four relevant templates that can be used when sending the response.
    USER_NONE     User invoked mute with no arguments
    USER_SELF     User tried muting themselves
    USER_USER     User tried muting other user(s)
    USER_MIXED    User tried musing themselves and other user(s)
    """
    if coginfo.bot and coginfo.default_self_mute_time and coginfo.logger:
        bot: MrFreeze = coginfo.bot
        default_self_mute_time: int = coginfo.default_self_mute_time
        logger: Logger = coginfo.logger
    else:
        raise InsufficientCogInfo

    if not isinstance(error, CheckFailure):
        # Only run this on Check Failure.
        return

    mentions = ctx.message.mentions
    author = ctx.author
    server = ctx.guild

    none = (len(mentions) == 0)
    selfmute = (len(mentions) == 1 and author in mentions)
    mix = (not selfmute and author in mentions)
    user = (not selfmute and not mix and len(mentions) > 0)
    fails = default.mentions_list(
        [mention for mention in mentions if mention != author])

    if none:
        template = MuteResponseType.USER_NONE
    elif selfmute:
        template = MuteResponseType.USER_SELF
    elif user:
        template = MuteResponseType.USER_USER
    elif mix:
        template = MuteResponseType.USER_MIXED

    self_mute_time: int = bot.get_self_mute_time(
        server) or default_self_mute_time
    duration = datetime.timedelta(minutes=float(self_mute_time))
    end_date = datetime.datetime.now() + duration
    duration = time.parse_timedelta(duration)

    # Carry out the banish with resulting end date
    banish_error = await mute_db.carry_out_banish(bot, author, logger,
                                                  end_date)
    error_msg = "unspecified error"

    if isinstance(banish_error, Exception):
        if isinstance(banish_error, discord.Forbidden):
            error_msg = "**a lack of privilegies**"
        elif isinstance(banish_error, discord.HTTPException):
            error_msg = "**an HTTP exception**"
        else:
            error_msg = "**an unknown error**"
        template = MuteResponseType.USER_FAIL

    banish_template = template_engine.get_template(ctx.invoked_with, template)
    if banish_template:
        reply = banish_template.substitute(author=author.mention,
                                           fails=fails,
                                           errors=error_msg,
                                           timestamp=duration)
        await ctx.send(reply)
    else:
        reply = "I couldn't find an appropriate response, but anyway... you're not "
        reply += f"allowed to do that! Bad {ctx.author.mention}!"
        await ctx.send(reply)