예제 #1
0
    async def mywarnings(self, ctx: commands.Context):
        """List warnings for yourself."""

        user = ctx.author

        msg = ""
        member_settings = self.config.member(user)
        async with member_settings.warnings() as user_warnings:
            if not user_warnings.keys():  # no warnings for the user
                await ctx.send(_("You have no warnings!"))
            else:
                for key in user_warnings.keys():
                    mod_id = user_warnings[key]["mod"]
                    if mod_id == 0xDE1:
                        mod = _("Deleted Moderator")
                    else:
                        bot = ctx.bot
                        mod = bot.get_user(mod_id) or _(
                            "Unknown Moderator ({})").format(mod_id)
                    msg += _(
                        "{num_points} point warning {reason_name} issued by {user} for "
                        "{description}\n").format(
                            num_points=user_warnings[key]["points"],
                            reason_name=key,
                            user=mod,
                            description=user_warnings[key]["description"],
                        )
                await ctx.send_interactive(
                    pagify(msg, shorten_by=58),
                    box_lang=_("Warnings for {user}").format(user=user),
                )
예제 #2
0
    async def listcases(self, ctx: commands.Context, *,
                        member: Union[discord.Member, int]):
        """List cases for the specified member."""
        async with ctx.typing():
            try:
                if isinstance(member, int):
                    cases = await modlog.get_cases_for_member(bot=ctx.bot,
                                                              guild=ctx.guild,
                                                              member_id=member)
                else:
                    cases = await modlog.get_cases_for_member(bot=ctx.bot,
                                                              guild=ctx.guild,
                                                              member=member)
            except discord.NotFound:
                return await ctx.send(_("That user does not exist."))
            except discord.HTTPException:
                return await ctx.send(
                    _("Something unexpected went wrong while fetching that user by ID."
                      ))
            if not cases:
                return await ctx.send(_("That user does not have any cases."))

            rendered_cases = []
            message = ""
            for case in cases:
                message += _("{case}\n**Timestamp:** {timestamp}\n\n").format(
                    case=await case.message_content(embed=False),
                    timestamp=datetime.utcfromtimestamp(
                        case.created_at).strftime("%Y-%m-%d %H:%M:%S UTC"),
                )
            for page in pagify(message, ["\n\n", "\n"], priority=True):
                rendered_cases.append(page)
        await menu(ctx, rendered_cases, DEFAULT_CONTROLS)
예제 #3
0
    async def send_leaderboard(self, ctx: commands.Context, data: dict,
                               key: str, top: int):
        """Send the leaderboard from the given data.

        Parameters
        ----------
        ctx : commands.Context
            The context to send the leaderboard to.
        data : dict
            The data for the leaderboard. This must map `discord.Member` ->
            `dict`.
        key : str
            The field to sort the data by. Can be ``wins``, ``total_score``,
            ``games`` or ``average_score``.
        top : int
            The number of members to display on the leaderboard.

        Returns
        -------
        `list` of `discord.Message`
            The sent leaderboard messages.

        """
        if not data:
            await ctx.send(_("There are no scores on record!"))
            return
        leaderboard = self._get_leaderboard(data, key, top)
        ret = []
        for page in pagify(leaderboard, shorten_by=10):
            ret.append(await ctx.send(box(page, lang="py")))
        return ret
예제 #4
0
    async def discover_guild(
        self,
        author: discord.User,
        *,
        mod: bool = False,
        permissions: Union[discord.Permissions, dict] = None,
        prompt: str = "",
    ):
        """
        discovers which of shared guilds between the bot
        and provided user based on conditions (mod or permissions is an or)

        prompt is for providing a user prompt for selection
        """
        shared_guilds = []
        if permissions is None:
            perms = discord.Permissions()
        elif isinstance(permissions, discord.Permissions):
            perms = permissions
        else:
            perms = discord.Permissions(**permissions)

        async for guild in AsyncIter(self.bot.guilds, steps=100):
            x = guild.get_member(author.id)
            if x is not None:
                if await self.internal_filter(x, mod, perms):
                    shared_guilds.append(guild)
        if len(shared_guilds) == 0:
            raise ValueError("No Qualifying Shared Guilds")
        if len(shared_guilds) == 1:
            return shared_guilds[0]
        output = ""
        guilds = sorted(shared_guilds, key=lambda g: g.name)
        for i, guild in enumerate(guilds, 1):
            output += "{}: {}\n".format(i, guild.name)
        output += "\n{}".format(prompt)

        for page in pagify(output, delims=["\n"]):
            await author.send(box(page))

        try:
            message = await self.bot.wait_for(
                "message",
                check=MessagePredicate.same_context(channel=author.dm_channel, user=author),
                timeout=45,
            )
        except asyncio.TimeoutError:
            await author.send(_("You took too long to select. Try again later."))
            return None

        try:
            message = int(message.content.strip())
            guild = guilds[message - 1]
        except (ValueError, IndexError):
            await author.send(_("That wasn't a valid choice."))
            return None
        else:
            return guild
예제 #5
0
    async def cc_list(self, ctx: commands.Context):
        """List all available custom commands.

        The list displays a preview of each command's response, with
        markdown escaped and newlines replaced with spaces.
        """
        cc_dict = await CommandObj.get_commands(self.config.guild(ctx.guild))

        if not cc_dict:
            await ctx.send(
                _(
                    "There are no custom commands in this server."
                    " Use `{command}` to start adding some."
                ).format(command=f"{ctx.clean_prefix}customcom create")
            )
            return

        results = self.prepare_command_list(ctx, sorted(cc_dict.items(), key=lambda t: t[0]))

        if await ctx.embed_requested():
            # We need a space before the newline incase the CC preview ends in link (GH-2295)
            content = " \n".join(map("**{0[0]}** {0[1]}".format, results))
            pages = list(pagify(content, page_length=1024))
            embed_pages = []
            for idx, page in enumerate(pages, start=1):
                embed = discord.Embed(
                    title=_("Custom Command List"),
                    description=page,
                    colour=await ctx.embed_colour(),
                )
                embed.set_footer(text=_("Page {num}/{total}").format(num=idx, total=len(pages)))
                embed_pages.append(embed)
            await menus.menu(ctx, embed_pages, menus.DEFAULT_CONTROLS)
        else:
            content = "\n".join(map("{0[0]:<12} : {0[1]}".format, results))
            pages = list(map(box, pagify(content, page_length=2000, shorten_by=10)))
            await menus.menu(ctx, pages, menus.DEFAULT_CONTROLS)
예제 #6
0
    async def message_forwarder(
        *,
        destination: discord.abc.Messageable,
        content: str = None,
        embed=None,
        files: Optional[List[discord.File]] = None,
    ) -> List[discord.Message]:
        """
        This does the actual sending, use this instead of a full tunnel
        if you are using command initiated reactions instead of persistent
        event based ones

        Parameters
        ----------
        destination: discord.abc.Messageable
            Where to send
        content: str
            The message content
        embed: discord.Embed
            The embed to send
        files: Optional[List[discord.File]]
            A list of files to send.

        Returns
        -------
        List[discord.Message]
            The messages sent as a result.

        Raises
        ------
        discord.Forbidden
            see `discord.abc.Messageable.send`
        discord.HTTPException
            see `discord.abc.Messageable.send`
        """
        rets = []
        if content:
            for page in pagify(content):
                rets.append(await destination.send(page,
                                                   files=files,
                                                   embed=embed))
                if files:
                    del files
                if embed:
                    del embed
        elif embed or files:
            rets.append(await destination.send(files=files, embed=embed))
        return rets
예제 #7
0
 async def _channel_list(self, ctx: commands.Context):
     """Send a list of the channel's filtered words."""
     channel = ctx.channel
     author = ctx.author
     word_list = await self.config.channel(channel).filter()
     if not word_list:
         await ctx.send(
             _("There is no current words setup to be filtered in this channel."
               ))
         return
     words = humanize_list(word_list)
     words = _("Filtered in this channel:") + "\n\n" + words
     try:
         for page in pagify(words, delims=[" ", "\n"], shorten_by=8):
             await author.send(page)
     except discord.Forbidden:
         await ctx.send(_("I can't send direct messages to you."))
예제 #8
0
 async def paginate_alias_list(self, ctx: commands.Context,
                               alias_list: List[AliasEntry]) -> None:
     names = sorted(["+ " + a.name for a in alias_list])
     message = "\n".join(names)
     temp = list(pagify(message, delims=["\n"], page_length=1850))
     alias_list = []
     count = 0
     for page in temp:
         count += 1
         page = page.lstrip("\n")
         page = (_("Aliases:\n") + page +
                 _("\n\nPage {page}/{total}").format(page=count,
                                                     total=len(temp)))
         alias_list.append(box("".join(page), "diff"))
     if len(alias_list) == 1:
         await ctx.send(alias_list[0])
         return
     await menu(ctx, alias_list, DEFAULT_CONTROLS)
예제 #9
0
    async def command_audiostats(self, ctx: commands.Context):
        """Audio stats."""
        server_num = len(lavalink.active_players())
        total_num = len(lavalink.all_players())

        msg = ""
        async for p in AsyncIter(lavalink.all_players()):
            connect_start = p.fetch("connect")
            connect_dur = self.get_time_string(
                int((datetime.datetime.utcnow() -
                     connect_start).total_seconds()))
            try:
                if not p.current:
                    raise AttributeError
                current_title = await self.get_track_description(
                    p.current, self.local_folder_current_path)
                msg += "{} [`{}`]: {}\n".format(p.channel.guild.name,
                                                connect_dur, current_title)
            except AttributeError:
                msg += "{} [`{}`]: **{}**\n".format(p.channel.guild.name,
                                                    connect_dur,
                                                    _("Nothing playing."))

        if total_num == 0:
            return await self.send_embed_msg(
                ctx, title=_("Not connected anywhere."))
        servers_embed = []
        pages = 1
        for page in pagify(msg, delims=["\n"], page_length=1500):
            em = discord.Embed(
                colour=await ctx.embed_colour(),
                title=_("Playing in {num}/{total} servers:").format(
                    num=humanize_number(server_num),
                    total=humanize_number(total_num)),
                description=page,
            )
            em.set_footer(text=_("Page {}/{}").format(
                humanize_number(pages),
                humanize_number((math.ceil(len(msg) / 1500)))))
            pages += 1
            servers_embed.append(em)

        await menu(ctx, servers_embed, DEFAULT_CONTROLS)
예제 #10
0
    async def streamalert_list(self, ctx: commands.Context):
        """List all active stream alerts in this server."""
        streams_list = defaultdict(list)
        guild_channels_ids = [c.id for c in ctx.guild.channels]
        msg = _("Active alerts:\n\n")

        for stream in self.streams:
            for channel_id in stream.channels:
                if channel_id in guild_channels_ids:
                    streams_list[channel_id].append(stream.name.lower())

        if not streams_list:
            await ctx.send(_("There are no active alerts in this server."))
            return

        for channel_id, streams in streams_list.items():
            channel = ctx.guild.get_channel(channel_id)
            msg += "** - #{}**\n{}\n".format(channel, ", ".join(streams))

        for page in pagify(msg):
            await ctx.send(page)
예제 #11
0
    async def warnings(self, ctx: commands.Context, user: Union[discord.Member,
                                                                int]):
        """List the warnings for the specified user."""

        try:
            userid: int = user.id
        except AttributeError:
            userid: int = user
            user = ctx.guild.get_member(userid)
            user = user or namedtuple("Member", "id guild")(userid, ctx.guild)

        msg = ""
        member_settings = self.config.member(user)
        async with member_settings.warnings() as user_warnings:
            if not user_warnings.keys():  # no warnings for the user
                await ctx.send(_("That user has no warnings!"))
            else:
                for key in user_warnings.keys():
                    mod_id = user_warnings[key]["mod"]
                    if mod_id == 0xDE1:
                        mod = _("Deleted Moderator")
                    else:
                        bot = ctx.bot
                        mod = bot.get_user(mod_id) or _(
                            "Unknown Moderator ({})").format(mod_id)
                    msg += _(
                        "{num_points} point warning {reason_name} issued by {user} for "
                        "{description}\n").format(
                            num_points=user_warnings[key]["points"],
                            reason_name=key,
                            user=mod,
                            description=user_warnings[key]["description"],
                        )
                await ctx.send_interactive(
                    pagify(msg, shorten_by=58),
                    box_lang=_("Warnings for {user}").format(user=user),
                )
예제 #12
0
    async def command_equalizer_list(self, ctx: commands.Context):
        """List saved eq presets."""
        eq_presets = await self.config.custom("EQUALIZER",
                                              ctx.guild.id).eq_presets()
        if not eq_presets.keys():
            return await self.send_embed_msg(
                ctx, title=_("No saved equalizer presets."))

        space = "\N{EN SPACE}"
        header_name = _("Preset Name")
        header_author = _("Author")
        header = box(
            "[{header_name}]{space}[{header_author}]\n".format(
                header_name=header_name,
                space=space * 9,
                header_author=header_author),
            lang="ini",
        )
        preset_list = ""
        for preset, bands in eq_presets.items():
            try:
                author = self.bot.get_user(bands["author"])
            except TypeError:
                author = "None"
            msg = f"{preset}{space * (22 - len(preset))}{author}\n"
            preset_list += msg

        page_list = []
        colour = await ctx.embed_colour()
        for page in pagify(preset_list, delims=[", "], page_length=1000):
            formatted_page = box(page, lang="ini")
            embed = discord.Embed(colour=colour,
                                  description=f"{header}\n{formatted_page}")
            embed.set_footer(text=_("{num} preset(s)").format(
                num=humanize_number(len(list(eq_presets.keys())))))
            page_list.append(embed)
        await menu(ctx, page_list, DEFAULT_CONTROLS)
예제 #13
0
            command_name=command_name, author=author, created_at=cmd["created_at"], type=_type
        )

        cooldowns = cmd.get("cooldowns", {})

        if cooldowns:
            cooldown_text = _("Cooldowns:\n")
            for rate, per in cooldowns.items():
                cooldown_text += _("{num} seconds per {period}\n").format(num=per, period=rate)
            text += cooldown_text

        text += _("Responses:\n")
        responses = ["- " + r for r in responses]
        text += "\n".join(responses)

        for p in pagify(text):
            await ctx.send(box(p, lang="yaml"))

    @commands.Cog.listener()
    async def on_message_without_command(self, message):
        is_private = isinstance(message.channel, discord.abc.PrivateChannel)

        # user_allowed check, will be replaced with self.bot.user_allowed or
        # something similar once it's added
        user_allowed = True

        if len(message.content) < 2 or is_private or not user_allowed or message.author.bot:
            return

        if await self.bot.cog_disabled_in_guild(self, message.guild):
            return
예제 #14
0
    async def voice_mute(
        self,
        ctx: commands.Context,
        users: commands.Greedy[discord.Member],
        *,
        time_and_reason: MuteTime = {},
    ):
        """Mute a user in their current voice channel.

        `<users...>` is a space separated list of usernames, ID's, or mentions.
        `[time_and_reason]` is the time to mute for and reason. Time is
        any valid time length such as `30 minutes` or `2 days`. If nothing
        is provided the mute will use the set default time or indefinite if not set.

        Examples:
        `[p]voicemute @member1 @member2 spam 5 hours`
        `[p]voicemute @member1 3 days`"""
        if not users:
            return await ctx.send_help()
        if ctx.me in users:
            return await ctx.send(_("You cannot mute me."))
        if ctx.author in users:
            return await ctx.send(_("You cannot mute yourself."))
        async with ctx.typing():
            success_list = []
            issue_list = []
            for user in users:
                user_voice_state = user.voice
                can_move, perm_reason = await self._voice_perm_check(
                    ctx,
                    user_voice_state,
                    mute_members=True,
                    manage_permissions=True)
                if not can_move:
                    issue_list.append((user, perm_reason))
                    continue
                duration = time_and_reason.get("duration", None)
                reason = time_and_reason.get("reason", None)
                time = ""
                until = None
                if duration:
                    until = datetime.now(timezone.utc) + duration
                    time = _(" for {duration}").format(
                        duration=humanize_timedelta(timedelta=duration))
                else:
                    default_duration = await self.config.guild(
                        ctx.guild).default_time()
                    if default_duration:
                        until = datetime.now(
                            timezone.utc) + timedelta(seconds=default_duration)
                        time = _(" for {duration}").format(
                            duration=humanize_timedelta(timedelta=timedelta(
                                seconds=default_duration)))
                guild = ctx.guild
                author = ctx.author
                channel = user_voice_state.channel
                audit_reason = get_audit_reason(author, reason, shorten=True)

                success = await self.channel_mute_user(guild, channel, author,
                                                       user, until,
                                                       audit_reason)

                if success["success"]:
                    if "reason" in success and success["reason"]:
                        issue_list.append((user, success["reason"]))
                    else:
                        success_list.append(user)
                    await modlog.create_case(
                        self.bot,
                        guild,
                        ctx.message.created_at.replace(tzinfo=timezone.utc),
                        "vmute",
                        user,
                        author,
                        reason,
                        until=until,
                        channel=channel,
                    )
                    await self._send_dm_notification(user, author, guild,
                                                     _("Voice mute"), reason,
                                                     duration)
                    async with self.config.member(user).perms_cache() as cache:
                        cache[channel.id] = success["old_overs"]
                else:
                    issue_list.append((user, success["reason"]))

        if success_list:
            msg = _("{users} has been muted in this channel{time}.")
            if len(success_list) > 1:
                msg = _("{users} have been muted in this channel{time}.")
            await ctx.send(
                msg.format(users=humanize_list([f"{u}" for u in success_list]),
                           time=time))
        if issue_list:
            msg = _("The following users could not be muted\n")
            for user, issue in issue_list:
                msg += f"{user}: {issue}\n"
            await ctx.send_interactive(pagify(msg))
예제 #15
0
    async def unmute_voice(
        self,
        ctx: commands.Context,
        users: commands.Greedy[discord.Member],
        *,
        reason: Optional[str] = None,
    ):
        """Unmute a user in their current voice channel.

        `<users...>` is a space separated list of usernames, ID's, or mentions.
        `[reason]` is the reason for the unmute."""
        if not users:
            return await ctx.send_help()
        if ctx.me in users:
            return await ctx.send(_("You cannot unmute me."))
        if ctx.author in users:
            return await ctx.send(_("You cannot unmute yourself."))
        async with ctx.typing():
            issue_list = []
            success_list = []
            for user in users:
                user_voice_state = user.voice
                can_move, perm_reason = await self._voice_perm_check(
                    ctx,
                    user_voice_state,
                    mute_members=True,
                    manage_permissions=True)
                if not can_move:
                    issue_list.append((user, perm_reason))
                    continue
                guild = ctx.guild
                author = ctx.author
                channel = user_voice_state.channel
                audit_reason = get_audit_reason(author, reason, shorten=True)

                success = await self.channel_unmute_user(
                    guild, channel, author, user, audit_reason)

                if success["success"]:
                    if "reason" in success and success["reason"]:
                        issue_list.append((user, success["reason"]))
                    else:
                        success_list.append(user)
                    await modlog.create_case(
                        self.bot,
                        guild,
                        ctx.message.created_at.replace(tzinfo=timezone.utc),
                        "vunmute",
                        user,
                        author,
                        reason,
                        until=None,
                        channel=channel,
                    )
                    await self._send_dm_notification(user, author, guild,
                                                     _("Voice unmute"), reason)
                else:
                    issue_list.append((user, success["reason"]))
        if success_list:
            if channel.id in self._channel_mutes and self._channel_mutes[
                    channel.id]:
                await self.config.channel(channel).muted_users.set(
                    self._channel_mutes[channel.id])
            else:
                await self.config.channel(channel).muted_users.clear()
            await ctx.send(
                _("{users} unmuted in this channel.").format(
                    users=humanize_list([f"{u}" for u in success_list])))
        if issue_list:
            msg = _("The following users could not be unmuted\n")
            for user, issue in issue_list:
                msg += f"{user}: {issue}\n"
            await ctx.send_interactive(pagify(msg))