示例#1
0
 async def process_kwargs(
     self,
     author: UnionUser,
     channel: UnionChannel,
     jump_url: str,
     *,
     content: Optional[str],
     attachments: List[discord.Attachment],
 ) -> Dict[str, Any]:
     guild: Optional[discord.Guild] = getattr(channel, "guild", None)
     oga = author
     if guild:
         author = guild.get_member(author.id) or self.bot.get_user(
             author.id)
         assert author
     if not await self.bot.allowed_by_whitelist_blacklist(author):
         raise RiftError(_("You are not permitted to use the bot here."))
     is_owner = await self.bot.is_owner(author)
     me = (guild or channel).me  # type: ignore
     author_perms = self.permissions(channel, author, is_owner)
     bot_perms = self.permissions(channel, me)
     both_perms = discord.Permissions(author_perms.value & bot_perms.value)
     if guild and content and not is_owner and not await self.bot.is_automod_immune(
             author):
         assert isinstance(channel, discord.TextChannel)
         filt: Optional["Filter"] = self.bot.get_cog(
             "Filter")  # type: ignore
         if filt and await filt.filter_hits(content, channel):
             raise RiftError(_("Your message was filtered."))
     embed: Optional[discord.Embed]
     if await self.bot.embed_requested(channel,
                                       getattr(channel, "recipient",
                                               author),
                                       command=self.rift):
         embed = discord.Embed(colour=oga.colour
                               or await self.bot.get_embed_color(channel),
                               url=jump_url)
         ogg: Optional[discord.Guild]
         if ogg := getattr(oga, "guild", None):
             assert isinstance(oga, discord.Member)
             if oga.top_role != ogg.default_role:
                 embed.title = filter_invites(f"{oga.top_role} in {ogg}")
             else:
                 embed.title = filter_invites(f"in {ogg}")
         embed.set_author(
             name=filter_invites(str(author)),
             icon_url=author.avatar_url_as(size=32),
         )
示例#2
0
    async def listguilds(self, ctx):
        """List the guilds|servers the bot is in."""
        asciidoc = lambda m: "```asciidoc\n{}\n```".format(m)
        guilds = sorted(self.bot.guilds, key=lambda g: -g.member_count)
        header = ("```\n" "The bot is in the following {} server{}:\n" "```").format(
            len(guilds), "s" if len(guilds) > 1 else ""
        )

        max_zpadding = max([len(str(g.member_count)) for g in guilds])
        form = "{gid} :: {mems:0{zpadding}} :: {name}"
        all_forms = [
            form.format(
                gid=g.id,
                mems=g.member_count,
                name=filter_invites(cf.escape(g.name)),
                zpadding=max_zpadding
            )
            for g in guilds
        ]
        final = "\n".join(all_forms)

        await ctx.send(header)
        page_list = []
        for page in cf.pagify(final, delims=["\n"], page_length=1000):
            page_list.append(asciidoc(page))

        if len(page_list) == 1:
            return await ctx.send(asciidoc(page))
        await menu(ctx, page_list, DEFAULT_CONTROLS)
示例#3
0
    async def get_names_and_nicks(self, member: Union[discord.Member, discord.User]):
        try:
            mod = self.bot.cogs["Mod"]
        except KeyError:
            return [], []

        names = await mod.settings.user(member).past_names()
        nicks = (
            await mod.settings.member(member).past_nicks()
            if isinstance(member, discord.Member)
            else []
        )

        if names:
            names = [filter_invites(escape(name, mass_mentions=True)) for name in names if name]
        if nicks:
            nicks = [filter_invites(escape(nick, mass_mentions=True)) for nick in nicks if nick]
        return names, nicks
示例#4
0
文件: rift.py 项目: bobloy/FluffyCogs
 async def process_message(self, rift, message, destination):
     if isinstance(destination, discord.Message):
         send_coro = destination.edit
     else:
         send_coro = destination.send
     channel = (
         message.author if isinstance(message.channel, discord.DMChannel) else message.channel
     )
     send = channel == rift.source
     destination = rift.destination if send else rift.source
     author = message.author
     me = (
         destination.dm_channel.me
         if isinstance(destination, discord.User)
         else destination.guild.me
     )
     is_owner = await self.bot.is_owner(author)
     author_perms = self.permissions(destination, author, is_owner)
     bot_perms = self.permissions(destination, me)
     content = message.content
     if not is_owner:
         if not author_perms.administrator:
             content = common_filters.filter_invites(content)
         if not author_perms.mention_everyone:
             content = common_filters.filter_mass_mentions(content)
     attachments = message.attachments
     files = []
     embed = None
     if attachments and author_perms.attach_files and bot_perms.attach_files:
         overs = await asyncio.gather(*(self.save_attach(file, files) for file in attachments))
         overs = list(filter(bool, overs))
         if overs:
             if bot_perms.embed_links:
                 embed = await self.get_embed(destination, overs)
             else:
                 content += (
                     "\n\n"
                     + _("Attachments:")
                     + "\n"
                     + "\n".join(f"({self.xbytes(a.size)}) {a.url}" for a in attachments)
                 )
     if not any((content, files, embed)):
         raise RiftError(_("No content to send."))
     if not is_owner or not send:
         content = f"{author}: {content}"
     return await send_coro(content=content, files=files, embed=embed)
示例#5
0
文件: rift.py 项目: muddyfish/079COGS
 async def process_message(self, rift, message, destination):
     if isinstance(destination, discord.Message):
         send_coro = destination.edit
     else:
         send_coro = destination.send
     channel = (
         message.author if isinstance(message.channel, discord.DMChannel) else message.channel
     )
     send = channel == rift.source
     destination = rift.destination if send else rift.source
     source = rift.source if send else rift.destination
     author = message.author
     me = (
         destination.dm_channel.me
         if isinstance(destination, discord.User)
         else destination.guild.me
     )
     is_owner = await self.bot.is_owner(author)
     author_perms = self.permissions(destination, author, is_owner)
     bot_perms = self.permissions(destination, me)
     content = message.content
     if not is_owner:
         if not author_perms.administrator:
             content = common_filters.filter_invites(content)
         if not author_perms.mention_everyone:
             content = common_filters.filter_mass_mentions(content)
     attachments = message.attachments
     files = []
     embed = None
     if attachments and author_perms.attach_files and bot_perms.attach_files:
         overs = await asyncio.gather(*(self.save_attach(file, files) for file in attachments))
         overs = list(filter(bool, overs))
         if overs:
             content += (
                 "\n\n"
                 + _("Attachments:")
                 + "\n"
                 + "\n".join(f"({self.xbytes(a.size)}) {a.url}" for a in attachments)
             )
     if not any((content, files, embed)):
         raise RiftError(_("No content to send."))
     msg_embed = await self.create_message_embed(ctx=message, source=source, content=content, files=attachments)
     return await send_coro(embed=msg_embed)
示例#6
0
class ModInfo(MixinMeta):
    """
    Commands regarding names, userinfo, etc.
    """
    async def get_names_and_nicks(self, user):
        names = await self.config.user(user).past_names()
        nicks = await self.config.member(user).past_nicks()
        if names:
            names = [
                escape_spoilers_and_mass_mentions(name) for name in names
                if name
            ]
        if nicks:
            nicks = [
                escape_spoilers_and_mass_mentions(nick) for nick in nicks
                if nick
            ]
        return names, nicks

    @commands.command()
    @commands.guild_only()
    @commands.bot_has_permissions(manage_nicknames=True)
    @checks.admin_or_permissions(manage_nicknames=True)
    async def rename(self,
                     ctx: commands.Context,
                     member: discord.Member,
                     *,
                     nickname: str = ""):
        """Change a member's nickname.

        Leaving the nickname empty will remove it.
        """
        nickname = nickname.strip()
        me = cast(discord.Member, ctx.me)
        if not nickname:
            nickname = None
        elif not 2 <= len(nickname) <= 32:
            await ctx.send(
                _("Nicknames must be between 2 and 32 characters long."))
            return
        if not ((me.guild_permissions.manage_nicknames
                 or me.guild_permissions.administrator) and
                me.top_role > member.top_role and member != ctx.guild.owner):
            await ctx.send(
                _("I do not have permission to rename that member. They may be higher than or "
                  "equal to me in the role hierarchy."))
        elif ctx.author != member and not await is_allowed_by_hierarchy(
                self.bot, self.config, ctx.guild, ctx.author, member):
            await ctx.send(
                _("I cannot let you do that. You are "
                  "not higher than the user in the role "
                  "hierarchy."))
        else:
            try:
                await member.edit(reason=get_audit_reason(ctx.author, None),
                                  nick=nickname)
            except discord.Forbidden:
                # Just in case we missed something in the permissions check above
                await ctx.send(
                    _("I do not have permission to rename that member."))
            except discord.HTTPException as exc:
                if exc.status == 400:  # BAD REQUEST
                    await ctx.send(_("That nickname is invalid."))
                else:
                    await ctx.send(_("An unexpected error has occured."))
            else:
                await ctx.send(_("Done."))

    def handle_custom(self, user):
        a = [
            c for c in user.activities if c.type == discord.ActivityType.custom
        ]
        if not a:
            return None, discord.ActivityType.custom
        a = a[0]
        c_status = None
        if not a.name and not a.emoji:
            return None, discord.ActivityType.custom
        elif a.name and a.emoji:
            c_status = _("Custom: {emoji} {name}").format(emoji=a.emoji,
                                                          name=a.name)
        elif a.emoji:
            c_status = _("Custom: {emoji}").format(emoji=a.emoji)
        elif a.name:
            c_status = _("Custom: {name}").format(name=a.name)
        return c_status, discord.ActivityType.custom

    def handle_playing(self, user):
        p_acts = [
            c for c in user.activities
            if c.type == discord.ActivityType.playing
        ]
        if not p_acts:
            return None, discord.ActivityType.playing
        p_act = p_acts[0]
        act = _("Playing: {name}").format(name=p_act.name)
        return act, discord.ActivityType.playing

    def handle_streaming(self, user):
        s_acts = [
            c for c in user.activities
            if c.type == discord.ActivityType.streaming
        ]
        if not s_acts:
            return None, discord.ActivityType.streaming
        s_act = s_acts[0]
        if isinstance(s_act, discord.Streaming):
            act = _("Streaming: [{name}{sep}{game}]({url})").format(
                name=discord.utils.escape_markdown(s_act.name),
                sep=" | " if s_act.game else "",
                game=discord.utils.escape_markdown(s_act.game)
                if s_act.game else "",
                url=s_act.url,
            )
        else:
            act = _("Streaming: {name}").format(name=s_act.name)
        return act, discord.ActivityType.streaming

    def handle_listening(self, user):
        l_acts = [
            c for c in user.activities
            if c.type == discord.ActivityType.listening
        ]
        if not l_acts:
            return None, discord.ActivityType.listening
        l_act = l_acts[0]
        if isinstance(l_act, discord.Spotify):
            act = _("Listening: [{title}{sep}{artist}]({url})").format(
                title=discord.utils.escape_markdown(l_act.title),
                sep=" | " if l_act.artist else "",
                artist=discord.utils.escape_markdown(l_act.artist)
                if l_act.artist else "",
                url=f"https://open.spotify.com/track/{l_act.track_id}",
            )
        else:
            act = _("Listening: {title}").format(title=l_act.name)
        return act, discord.ActivityType.listening

    def handle_watching(self, user):
        w_acts = [
            c for c in user.activities
            if c.type == discord.ActivityType.watching
        ]
        if not w_acts:
            return None, discord.ActivityType.watching
        w_act = w_acts[0]
        act = _("Watching: {name}").format(name=w_act.name)
        return act, discord.ActivityType.watching

    def handle_competing(self, user):
        w_acts = [
            c for c in user.activities
            if c.type == discord.ActivityType.competing
        ]
        if not w_acts:
            return None, discord.ActivityType.competing
        w_act = w_acts[0]
        act = _("Competing in: {competing}").format(competing=w_act.name)
        return act, discord.ActivityType.competing

    def get_status_string(self, user):
        string = ""
        for a in [
                self.handle_custom(user),
                self.handle_playing(user),
                self.handle_listening(user),
                self.handle_streaming(user),
                self.handle_watching(user),
                self.handle_competing(user),
        ]:
            status_string, status_type = a
            if status_string is None:
                continue
            string += f"{status_string}\n"
        return string

    @commands.command()
    @commands.guild_only()
    @commands.bot_has_permissions(embed_links=True)
    async def userinfo(self, ctx, *, member: discord.Member = None):
        """Show information about a member.

        This includes fields for status, discord join date, server
        join date, voice state and previous names/nicknames.

        If the member has no roles, previous names or previous nicknames,
        these fields will be omitted.
        """
        author = ctx.author
        guild = ctx.guild

        if not member:
            member = author

        #  A special case for a special someone :^)
        special_date = datetime.datetime(2016, 1, 10, 6, 8, 4, 443000,
                                         datetime.timezone.utc)
        is_special = member.id == 96130341705637888 and guild.id == 133049272517001216

        roles = member.roles[-1:0:-1]
        names, nicks = await self.get_names_and_nicks(member)

        if is_special:
            joined_at = special_date
        elif joined_at := member.joined_at:
            joined_at = joined_at.replace(tzinfo=datetime.timezone.utc)
        user_created = int(
            member.created_at.replace(
                tzinfo=datetime.timezone.utc).timestamp())
        voice_state = member.voice
        member_number = (sorted(
            guild.members,
            key=lambda m: m.joined_at or ctx.message.created_at).index(member)
                         + 1)

        created_on = "<t:{0}>\n(<t:{0}:R>)".format(user_created)
        if joined_at is not None:
            joined_on = "<t:{0}>\n(<t:{0}:R>)".format(
                int(joined_at.timestamp()))
        else:
            joined_on = _("Unknown")

        if any(a.type is discord.ActivityType.streaming
               for a in member.activities):
            statusemoji = "\N{LARGE PURPLE CIRCLE}"
        elif member.status.name == "online":
            statusemoji = "\N{LARGE GREEN CIRCLE}"
        elif member.status.name == "offline":
            statusemoji = "\N{MEDIUM WHITE CIRCLE}\N{VARIATION SELECTOR-16}"
        elif member.status.name == "dnd":
            statusemoji = "\N{LARGE RED CIRCLE}"
        elif member.status.name == "idle":
            statusemoji = "\N{LARGE ORANGE CIRCLE}"
        activity = _("Chilling in {} status").format(member.status)
        status_string = self.get_status_string(member)

        if roles:

            role_str = ", ".join([x.mention for x in roles])
            # 400 BAD REQUEST (error code: 50035): Invalid Form Body
            # In embed.fields.2.value: Must be 1024 or fewer in length.
            if len(role_str) > 1024:
                # Alternative string building time.
                # This is not the most optimal, but if you're hitting this, you are losing more time
                # to every single check running on users than the occasional user info invoke
                # We don't start by building this way, since the number of times we hit this should be
                # infinitesimally small compared to when we don't across all uses of Red.
                continuation_string = _(
                    "and {numeric_number} more roles not displayed due to embed limits."
                )
                available_length = 1024 - len(
                    continuation_string)  # do not attempt to tweak, i18n

                role_chunks = []
                remaining_roles = 0

                for r in roles:
                    chunk = f"{r.mention}, "
                    chunk_size = len(chunk)

                    if chunk_size < available_length:
                        available_length -= chunk_size
                        role_chunks.append(chunk)
                    else:
                        remaining_roles += 1

                role_chunks.append(
                    continuation_string.format(numeric_number=remaining_roles))

                role_str = "".join(role_chunks)

        else:
            role_str = None

        data = discord.Embed(description=status_string or activity,
                             colour=member.colour)

        data.add_field(name=_("Joined Discord on"), value=created_on)
        data.add_field(name=_("Joined this server on"), value=joined_on)
        if role_str is not None:
            data.add_field(name=_("Roles") if len(roles) > 1 else _("Role"),
                           value=role_str,
                           inline=False)
        if names:
            # May need sanitizing later, but mentions do not ping in embeds currently
            val = filter_invites(", ".join(names))
            data.add_field(
                name=_("Previous Names")
                if len(names) > 1 else _("Previous Name"),
                value=val,
                inline=False,
            )
        if nicks:
            # May need sanitizing later, but mentions do not ping in embeds currently
            val = filter_invites(", ".join(nicks))
            data.add_field(
                name=_("Previous Nicknames")
                if len(nicks) > 1 else _("Previous Nickname"),
                value=val,
                inline=False,
            )
        if voice_state and voice_state.channel:
            data.add_field(
                name=_("Current voice channel"),
                value="{0.mention} ID: {0.id}".format(voice_state.channel),
                inline=False,
            )
        data.set_footer(text=_("Member #{} | User ID: {}").format(
            member_number, member.id))

        name = str(member)
        name = " ~ ".join((name, member.nick)) if member.nick else name
        name = filter_invites(name)

        avatar = member.avatar_url_as(static_format="png")
        data.set_author(name=f"{statusemoji} {name}", url=avatar)
        data.set_thumbnail(url=avatar)

        await ctx.send(embed=data)
示例#7
0
    async def userinfo(self, ctx, *, user: discord.Member = None):
        """Show userinfo with some more detail."""
        mod = self.bot.get_cog("Mod")
        async with ctx.typing():
            author = ctx.author
            guild = ctx.guild

            if not user:
                user = author
            sharedguilds = {
                guild
                async for guild in AsyncIter(self.bot.guilds, steps=100)
                if user in guild.members
            }
            roles = user.roles[-1:0:-1]
            names, nicks = await mod.get_names_and_nicks(user)

            joined_at = user.joined_at
            since_created = int((ctx.message.created_at - user.created_at).days)
            if joined_at is not None:
                since_joined = int((ctx.message.created_at - joined_at).days)
                user_joined = joined_at.strftime("%d %b %Y %H:%M")
            else:
                since_joined = "?"
                user_joined = "Unknown"
            user_created = user.created_at.strftime("%d %b %Y %H:%M")
            voice_state = user.voice
            member_number = (
                sorted(guild.members, key=lambda m: m.joined_at or ctx.message.created_at).index(
                    user
                )
                + 1
            )

            created_on = "{}\n({} day{} ago)".format(
                user_created, since_created, "" if since_created == 1 else "s"
            )
            joined_on = "{}\n({} day{} ago)".format(
                user_joined, since_joined, "" if since_joined == 1 else "s"
            )
            if user.is_on_mobile():
                statusemoji = (
                    self.status_emojis["mobile"]
                    if self.status_emojis["mobile"]
                    else "\N{MOBILE PHONE}"
                )
            elif any(a.type is discord.ActivityType.streaming for a in user.activities):
                statusemoji = (
                    self.status_emojis["streaming"]
                    if self.status_emojis["streaming"]
                    else "\N{LARGE PURPLE CIRCLE}"
                )
            elif user.status.name == "online":
                statusemoji = (
                    self.status_emojis["online"]
                    if self.status_emojis["online"]
                    else "\N{LARGE GREEN CIRCLE}"
                )
            elif user.status.name == "offline":
                statusemoji = (
                    self.status_emojis["offline"]
                    if self.status_emojis["offline"]
                    else "\N{MEDIUM WHITE CIRCLE}"
                )
            elif user.status.name == "dnd":
                statusemoji = (
                    self.status_emojis["dnd"]
                    if self.status_emojis["dnd"]
                    else "\N{LARGE RED CIRCLE}"
                )
            elif user.status.name == "idle":
                statusemoji = (
                    self.status_emojis["away"]
                    if self.status_emojis["away"]
                    else "\N{LARGE ORANGE CIRCLE}"
                )
            else:
                statusemoji = "\N{MEDIUM BLACK CIRCLE}\N{VARIATION SELECTOR-16}"
            activity = "Chilling in {} status".format(user.status)
            status_string = mod.get_status_string(user)

            if roles:

                role_str = ", ".join([x.mention for x in roles])
                # 400 BAD REQUEST (error code: 50035): Invalid Form Body
                # In embed.fields.2.value: Must be 1024 or fewer in length.
                if len(role_str) > 1024:
                    # Alternative string building time.
                    # This is not the most optimal, but if you're hitting this, you are losing more time
                    # to every single check running on users than the occasional user info invoke
                    # We don't start by building this way, since the number of times we hit this should be
                    # infintesimally small compared to when we don't across all uses of Red.
                    continuation_string = (
                        "and {numeric_number} more roles not displayed due to embed limits."
                    )

                    available_length = 1024 - len(
                        continuation_string
                    )  # do not attempt to tweak, i18n

                    role_chunks = []
                    remaining_roles = 0

                    for r in roles:
                        chunk = f"{r.mention}, "
                        chunk_size = len(chunk)

                        if chunk_size < available_length:
                            available_length -= chunk_size
                            role_chunks.append(chunk)
                        else:
                            remaining_roles += 1
                    role_chunks.append(continuation_string.format(numeric_number=remaining_roles))

                    role_str = "".join(role_chunks)
            else:
                role_str = None
            data = discord.Embed(
                description=(status_string or activity)
                + f"\n\n{len(sharedguilds)} shared servers."
                if len(sharedguilds) > 1
                else f"\n\n{len(sharedguilds)} shared server.",
                colour=user.colour,
            )

            data.add_field(name="Joined Discord on", value=created_on)
            data.add_field(name="Joined this server on", value=joined_on)
            if role_str is not None:
                data.add_field(name="Roles", value=role_str, inline=False)
            if names:
                # May need sanitizing later, but mentions do not ping in embeds currently
                val = filter_invites(", ".join(names))
                data.add_field(name="Previous Names", value=val, inline=False)
            if nicks:
                # May need sanitizing later, but mentions do not ping in embeds currently
                val = filter_invites(", ".join(nicks))
                data.add_field(name="Previous Nicknames", value=val, inline=False)
            if voice_state and voice_state.channel:
                data.add_field(
                    name="Current voice channel",
                    value="{0.mention} ID: {0.id}".format(voice_state.channel),
                    inline=False,
                )
            data.set_footer(text="Member #{} | User ID: {}".format(member_number, user.id))

            name = str(user)
            name = " ~ ".join((name, user.nick)) if user.nick else name
            name = filter_invites(name)

            avatar = user.avatar_url_as(static_format="png")
            data.title = f"{statusemoji} {name}"
            data.set_thumbnail(url=avatar)

            flags = [f.name for f in user.public_flags.all()]
            badges = ""
            badge_count = 0
            if flags:
                for badge in sorted(flags):
                    if badge == "verified_bot":
                        emoji1 = self.badge_emojis["verified_bot"]
                        emoji2 = self.badge_emojis["verified_bot2"]
                        if emoji1:
                            emoji = f"{emoji1}{emoji2}"
                        else:
                            emoji = None
                    else:
                        emoji = self.badge_emojis[badge]
                    if emoji:
                        badges += f"{emoji} {badge.replace('_', ' ').title()}\n"
                    else:
                        badges += f"\N{BLACK QUESTION MARK ORNAMENT}\N{VARIATION SELECTOR-16} {badge.replace('_', ' ').title()}\n"
                    badge_count += 1
            if badges:
                data.add_field(name="Badges" if badge_count > 1 else "Badge", value=badges)
            if "Economy" in self.bot.cogs:
                balance_count = 1
                bankstat = f"**Bank**: {str(humanize_number(await bank.get_balance(user)))} {await bank.get_currency_name(ctx.guild)}\n"
                if "Unbelievaboat" in self.bot.cogs:
                    cog = self.bot.get_cog("Unbelievaboat")
                    state = await cog.walletdisabledcheck(ctx)
                    if not state:
                        balance_count += 1
                        balance = await cog.walletbalance(user)
                        bankstat += f"**Wallet**: {str(humanize_number(balance))} {await bank.get_currency_name(ctx.guild)}\n"
                if "Adventure" in self.bot.cogs:
                    cog = self.bot.get_cog("Adventure")
                    if getattr(cog, "_separate_economy", False):
                        global adventure_bank
                        if adventure_bank is None:
                            try:
                                from adventure import bank as adventure_bank
                            except:
                                pass
                        if adventure_bank:
                            adventure_currency = await adventure_bank.get_balance(user)
                            balance_count += 1
                            bankstat += f"**Adventure**: {str(humanize_number(adventure_currency))} {await adventure_bank.get_currency_name(ctx.guild)}"
                data.add_field(name="Balances" if balance_count > 1 else "Balance", value=bankstat)
            await ctx.send(embed=data)
示例#8
0
    async def userinfo(self, ctx, *, user: discord.Member = None):
        """Show information about a user.

        This includes fields for status, discord join date, server
        join date, voice state and previous names/nicknames.

        If the user has no roles, previous names or previous nicknames,
        these fields will be omitted.
        """
        author = ctx.author
        guild = ctx.guild

        if not user:
            user = author

        #  A special case for a special someone :^)
        special_date = datetime(2016, 1, 10, 6, 8, 4, 443000)
        is_special = user.id == 96130341705637888 and guild.id == 133049272517001216

        roles = user.roles[-1:0:-1]
        names, nicks = await self.get_names_and_nicks(user)

        joined_at = user.joined_at if not is_special else special_date
        since_created = (ctx.message.created_at - user.created_at).days
        if joined_at is not None:
            since_joined = (ctx.message.created_at - joined_at).days
            user_joined = joined_at.strftime("%d %b %Y %H:%M")
        else:
            since_joined = "?"
            user_joined = _("Unknown")
        user_created = user.created_at.strftime("%d %b %Y %H:%M")
        voice_state = user.voice
        member_number = (sorted(
            guild.members,
            key=lambda m: m.joined_at or ctx.message.created_at).index(user) +
                         1)

        created_on = _("{}\n({} days ago)").format(user_created, since_created)
        joined_on = _("{}\n({} days ago)").format(user_joined, since_joined)

        if any(a.type is discord.ActivityType.streaming
               for a in user.activities):
            statusemoji = "\N{LARGE PURPLE CIRCLE}"
        elif user.status.name == "online":
            statusemoji = "\N{LARGE GREEN CIRCLE}"
        elif user.status.name == "offline":
            statusemoji = "\N{MEDIUM WHITE CIRCLE}\N{VARIATION SELECTOR-16}"
        elif user.status.name == "dnd":
            statusemoji = "\N{LARGE RED CIRCLE}"
        elif user.status.name == "idle":
            statusemoji = "\N{LARGE ORANGE CIRCLE}"
        activity = _("Chilling in {} status").format(user.status)
        status_string = self.get_status_string(user)

        if roles:

            role_str = ", ".join([x.mention for x in roles])
            # 400 BAD REQUEST (error code: 50035): Invalid Form Body
            # In embed.fields.2.value: Must be 1024 or fewer in length.
            if len(role_str) > 1024:
                # Alternative string building time.
                # This is not the most optimal, but if you're hitting this, you are losing more time
                # to every single check running on users than the occasional user info invoke
                # We don't start by building this way, since the number of times we hit this should be
                # infintesimally small compared to when we don't across all uses of Red.
                continuation_string = _(
                    "and {numeric_number} more roles not displayed due to embed limits."
                )
                available_length = 1024 - len(
                    continuation_string)  # do not attempt to tweak, i18n

                role_chunks = []
                remaining_roles = 0

                for r in roles:
                    chunk = f"{r.mention}, "
                    chunk_size = len(chunk)

                    if chunk_size < available_length:
                        available_length -= chunk_size
                        role_chunks.append(chunk)
                    else:
                        remaining_roles += 1

                role_chunks.append(
                    continuation_string.format(numeric_number=remaining_roles))

                role_str = "".join(role_chunks)

        else:
            role_str = None

        data = discord.Embed(description=status_string or activity,
                             colour=user.colour)

        data.add_field(name=_("Joined Discord on"), value=created_on)
        data.add_field(name=_("Joined this server on"), value=joined_on)
        if role_str is not None:
            data.add_field(name=_("Roles"), value=role_str, inline=False)
        if names:
            # May need sanitizing later, but mentions do not ping in embeds currently
            val = filter_invites(", ".join(names))
            data.add_field(name=_("Previous Names"), value=val, inline=False)
        if nicks:
            # May need sanitizing later, but mentions do not ping in embeds currently
            val = filter_invites(", ".join(nicks))
            data.add_field(name=_("Previous Nicknames"),
                           value=val,
                           inline=False)
        if voice_state and voice_state.channel:
            data.add_field(
                name=_("Current voice channel"),
                value="{0.mention} ID: {0.id}".format(voice_state.channel),
                inline=False,
            )
        data.set_footer(
            text=_("Member #{} | User ID: {}").format(member_number, user.id))

        name = str(user)
        name = " ~ ".join((name, user.nick)) if user.nick else name
        name = filter_invites(name)

        avatar = user.avatar_url_as(static_format="png")
        data.set_author(name=f"{statusemoji} {name}", url=avatar)
        data.set_thumbnail(url=avatar)

        await ctx.send(embed=data)
示例#9
0
 async def process_discord_message(self, message, destination):
     author = message.author
     if not await self.bot.allowed_by_whitelist_blacklist(author):
         return
     is_owner = await self.bot.is_owner(author)
     if isinstance(destination, discord.Message):
         channel = destination.channel
     else:
         channel = getattr(destination, "dm_channel", destination)
     guild = getattr(channel, "guild", None)
     me = (guild or channel).me
     if not is_owner and guild:
         dest_author = guild.get_member(author.id)
         if dest_author:
             is_automod_immune = await self.bot.is_automod_immune(dest_author)
         else:
             is_automod_immune = False
     else:
         is_automod_immune = True
     author_perms = self.permissions(destination, author, is_owner)
     bot_perms = self.permissions(destination, me)
     both_perms = discord.Permissions(author_perms.value & bot_perms.value)
     content = message.content
     if not is_automod_immune:
         filt: "Filter" = self.bot.get_cog("Filter")
         if filt and await filt.filter_hits(content, destination):
             raise RiftError("Your message was filtered at the destination.")
     attachments = message.attachments
     embed = None
     if attachments and author_perms.attach_files:
         if bot_perms.embed_links:
             embed = await self.get_embed(destination, attachments)
         else:
             if content:
                 content = f"{content}\n\n{_('Attachments:')}\n"
             else:
                 content = _("Attachments:")
             content += "\n".join(f"({self.xbytes(a.size)}) {a.url}" for a in attachments)
     if not content and not embed:
         raise RiftError(_("No content to send."))
     allowed_mentions = discord.AllowedMentions()
     if not is_owner:
         top_role = getattr(author, "top_role", None)
         if top_role and top_role != top_role.guild.default_role:
             content = f"[{author.top_role}] {author}\n>>> {content}"
         else:
             content = f"{author}\n>>> {content}"
         if not both_perms.administrator:
             content = common_filters.filter_invites(content)
         if not both_perms.mention_everyone:
             allowed_mentions = discord.AllowedMentions(users=True, everyone=True, roles=True)
         else:
             allowed_mentions = discord.AllowedMentions(users=True)
     try:
         if isinstance(destination, discord.Message):
             coro = destination.edit
         else:
             coro = destination.send
         return await coro(content=content, embed=embed, allowed_mentions=allowed_mentions)
     except discord.Forbidden:
         if not channel.permissions_for(me).send_messages:
             # we can't send here anymore, may as well remove it
             self.rifts.remove_vertices(getattr(channel, "recipient", channel))
         raise
示例#10
0
            if embed:
                embed = self.get_embed(attachments, embed=embed)
            else:
                if content:
                    content = f"{content}\n\n{_('Attachments:')}\n"
                else:
                    content = _("Attachments:")
                content += "\n".join(f"({self.xbytes(a.size)}) {a.url}"
                                     for a in attachments)
        if not content and not embed:
            raise RiftError(_("Nothing to send."))
        if is_owner:
            allowed_mentions = discord.AllowedMentions.all()
        else:
            if content and not both_perms.administrator:
                content = filter_invites(content)
            if both_perms.mention_everyone:
                allowed_mentions = discord.AllowedMentions.all()
            else:
                allowed_mentions = discord.AllowedMentions(users=True)
        return {
            "allowed_mentions": allowed_mentions,
            "embed": embed,
            "content": content
        }

    async def try_or_remove(self, coro: Awaitable[T],
                            channel: UnionChannel) -> T:
        guild: Optional[discord.Guild] = getattr(channel, "guild", None)
        if guild:
            me = guild.me
示例#11
0
             content = f"{content}\n\n{_('Attachments:')}\n"
         else:
             content = _("Attachments:")
         content += "\n".join(f"({self.xbytes(a.size)}) {a.url}"
                              for a in attachments)
 if not content and not embed:
     raise RiftError(_("No content to send."))
 allowed_mentions = discord.AllowedMentions()
 if not is_owner:
     top_role = getattr(author, "top_role", None)
     if top_role and top_role != top_role.guild.default_role:
         content = f"[{author.top_role}] {author}\n>>> {content}"
     else:
         content = f"{author}\n>>> {content}"
     if not both_perms.administrator:
         content = common_filters.filter_invites(content)
     if not both_perms.mention_everyone:
         allowed_mentions = discord.AllowedMentions(users=True,
                                                    everyone=True,
                                                    roles=True)
     else:
         allowed_mentions = discord.AllowedMentions(users=True)
 try:
     if isinstance(destination, discord.Message):
         coro = destination.edit
     else:
         coro = destination.send
     return await coro(content=content,
                       embed=embed,
                       allowed_mentions=allowed_mentions)
 except discord.Forbidden:
示例#12
0
    async def _user_info(self, ctx: commands.Context, member: Union[discord.Member, discord.User]):
        in_guild = isinstance(member, discord.Member)
        embed = discord.Embed(
            title=filter_invites(str(member)),
            colour=member.colour if member.colour.value != 0 else discord.Embed.Empty,
            description=await self.build_description(member),
        ).set_thumbnail(
            # discord.py 1.0.0 changes this to an Asset instance, which causes PyCharm to start
            # flipping the f**k out since it doesn't match the expected str type, despite
            # working perfectly fine.
            url=str(member.avatar_url_as(static_format="png"))
        )

        now = datetime.utcnow()
        member_n = (
            (sorted(member.guild.members, key=lambda m: m.joined_at or now).index(member) + 1)
            if in_guild
            else None
        )
        embed.set_footer(
            text=translate(
                "member_footer" if member_n is not None else "user_footer", n=member_n, id=member.id
            )
        )

        if in_guild:
            if member.joined_at is None:
                joined_guild = translate("unknown_join_date")
            else:
                joined_guild = translate(
                    "joined_server",
                    delta=Humanize(member.joined_at - ctx.message.created_at, add_direction=True),
                    absolute=Humanize(member.joined_at, DATETIME_FORMAT, tzinfo=get_localzone()),
                )
        else:
            joined_guild = None

        joined_discord = translate(
            "joined_discord",
            delta=Humanize(member.created_at - ctx.message.created_at, add_direction=True),
            absolute=Humanize(member.created_at, DATETIME_FORMAT, tzinfo=get_localzone()),
        )

        embed.add_field(
            name=translate("account_age"),
            value="\n".join(x for x in [joined_discord, joined_guild] if x is not None),
        )

        if in_guild:
            roles = list(reversed([mention(x) for x in member.roles if not x.is_default()]))
            cap = 40
            if len(roles) > cap:
                roles = [*roles[:cap], translate("more_roles", num=len(roles) - cap)]
            if roles:
                embed.add_field(
                    name=translate("server_roles"),
                    value=format_list(roles, locale=translate.locale.babel),
                    inline=False,
                )

        names, nicks = await self.get_names_and_nicks(member)
        if names:
            embed.add_field(name=translate("past_names"), value=", ".join(names), inline=False)
        if nicks:
            embed.add_field(name=translate("past_nicks"), value=", ".join(nicks), inline=False)

        await ctx.send(embed=embed)
示例#13
0
    async def userinfo(self, ctx, *, user: discord.Member = None):
        """Show userinfo with some more detail."""
        mod = self.bot.get_cog("Mod")
        if mod is None:
            return await ctx.send("This requires the mod cog to be loaded.")
        author = ctx.author
        guild = ctx.guild

        if not user:
            user = author
        sharedguilds = {
            guild
            async for guild in AsyncIter(self.bot.guilds)
            if user in guild.members
        }
        roles = user.roles[-1:0:-1]
        names, nicks = await mod.get_names_and_nicks(user)

        joined_at = user.joined_at
        since_created = (ctx.message.created_at - user.created_at).days
        if joined_at is not None:
            since_joined = (ctx.message.created_at - joined_at).days
            user_joined = joined_at.strftime("%d %b %Y %H:%M")
        else:
            since_joined = "?"
            user_joined = "Unknown"
        user_created = user.created_at.strftime("%d %b %Y %H:%M")
        voice_state = user.voice
        member_number = (sorted(
            guild.members,
            key=lambda m: m.joined_at or ctx.message.created_at).index(user) +
                         1)

        created_on = "{}\n({} days ago)".format(user_created, since_created)
        joined_on = "{}\n({} days ago)".format(user_joined, since_joined)

        if any(a.type is discord.ActivityType.streaming
               for a in user.activities):
            statusemoji = "\N{LARGE PURPLE CIRCLE}"
        elif user.status.name == "online":
            statusemoji = "\N{LARGE GREEN CIRCLE}"
        elif user.status.name == "offline":
            statusemoji = "\N{MEDIUM WHITE CIRCLE}"
        elif user.status.name == "dnd":
            statusemoji = "\N{LARGE RED CIRCLE}"
        elif user.status.name == "idle":
            statusemoji = "\N{LARGE ORANGE CIRCLE}"
        activity = "Chilling in {} status".format(user.status)
        status_string = mod.get_status_string(user)

        if roles:

            role_str = ", ".join([x.mention for x in roles])
            # 400 BAD REQUEST (error code: 50035): Invalid Form Body
            # In embed.fields.2.value: Must be 1024 or fewer in length.
            if len(role_str) > 1024:
                # Alternative string building time.
                # This is not the most optimal, but if you're hitting this, you are losing more time
                # to every single check running on users than the occasional user info invoke
                # We don't start by building this way, since the number of times we hit this should be
                # infintesimally small compared to when we don't across all uses of Red.
                continuation_string = (
                    "and {numeric_number} more roles not displayed due to embed limits."
                )

                available_length = 1024 - len(
                    continuation_string)  # do not attempt to tweak, i18n

                role_chunks = []
                remaining_roles = 0

                for r in roles:
                    chunk = f"{r.mention}, "
                    chunk_size = len(chunk)

                    if chunk_size < available_length:
                        available_length -= chunk_size
                        role_chunks.append(chunk)
                    else:
                        remaining_roles += 1

                role_chunks.append(
                    continuation_string.format(numeric_number=remaining_roles))

                role_str = "".join(role_chunks)

        else:
            role_str = None

        data = discord.Embed(
            description=(status_string or activity) +
            f"\n\n{len(sharedguilds)} shared servers.",
            colour=user.colour,
        )

        data.add_field(name="Joined Discord on", value=created_on)
        data.add_field(name="Joined this server on", value=joined_on)
        if role_str is not None:
            data.add_field(name="Roles", value=role_str, inline=False)
        if names:
            # May need sanitizing later, but mentions do not ping in embeds currently
            val = filter_invites(", ".join(names))
            data.add_field(name="Previous Names", value=val, inline=False)
        if nicks:
            # May need sanitizing later, but mentions do not ping in embeds currently
            val = filter_invites(", ".join(nicks))
            data.add_field(name="Previous Nicknames", value=val, inline=False)
        if voice_state and voice_state.channel:
            data.add_field(
                name="Current voice channel",
                value="{0.mention} ID: {0.id}".format(voice_state.channel),
                inline=False,
            )
        data.set_footer(
            text="Member #{} | User ID: {}".format(member_number, user.id))

        name = str(user)
        name = " ~ ".join((name, user.nick)) if user.nick else name
        name = filter_invites(name)

        avatar = user.avatar_url_as(static_format="png")
        data.set_author(name=f"{statusemoji} {name}", url=avatar)
        data.set_thumbnail(url=avatar)

        flags = await discord_py(user)
        badges = ""
        for badge in sorted(flags):
            if badge == "verified_bot":
                emoji1 = discord.utils.get(self.bot.emojis,
                                           id=EMOJIS["verified_bot"])
                emoji2 = discord.utils.get(self.bot.emojis,
                                           id=EMOJIS["verified_bot2"])
                if emoji1:
                    emoji = f"{emoji1}{emoji2}"
                else:
                    emoji = None
            else:
                emoji = discord.utils.get(self.bot.emojis, id=EMOJIS[badge])
            if emoji:
                badges += f"{emoji} {badge.replace('_', ' ').title()}\n"
            else:
                badges += f"\N{BLACK QUESTION MARK ORNAMENT}\N{VARIATION SELECTOR-16} {badge.replace('_', ' ').title()}\n"
        if badges:
            data.add_field(name="Badges", value=badges)
        await ctx.send(embed=data)
示例#14
0
    async def build_user_info_embed(self):
        """Stolen from core red cogs and adapted where needed.."""
        user = self.member
        message = self.message
        fortnite_guild_id = await self.config.fortnite_guild_id()
        fortnite_guild = self.bot.get_guild(fortnite_guild_id)
        user = fortnite_guild.get_member(user.id)

        roles = user.roles[-1:0:-1]

        activity = "Chilling in {} status".format(user.status)
        if user.activity is None:  # Default status
            pass
        elif user.activity.type == discord.ActivityType.playing:
            activity = "Playing {}".format(user.activity.name)
        elif user.activity.type == discord.ActivityType.streaming:
            activity = "Streaming [{}]({})".format(user.activity.name,
                                                   user.activity.url)
        elif user.activity.type == discord.ActivityType.listening:
            activity = "Listening to {}".format(user.activity.name)
        elif user.activity.type == discord.ActivityType.watching:
            activity = "Watching {}".format(user.activity.name)

        if roles:
            roles = ", ".join([x.name for x in roles])
        else:
            roles = None

        joined_at = user.joined_at
        since_created = (message.created_at - user.created_at).days

        if joined_at is not None:
            since_joined = (message.created_at - joined_at).days
            user_joined = joined_at.strftime("%d %b %Y %H:%M")
        else:
            since_joined = "?"
            user_joined = "Unknown"

        user_created = user.created_at.strftime("%d %b %Y %H:%M")
        voice_state = user.voice
        member_number = (sorted(
            fortnite_guild.members,
            key=lambda m: m.joined_at or message.created_at).index(user) + 1)

        created_on = "{}\n({} days ago)".format(user_created, since_created)
        joined_on = "{}\n({} days ago)".format(user_joined, since_joined)

        embed = discord.Embed(color=discord.Color.green(),
                              description=activity)

        embed.add_field(name="Joined Discord on", value=created_on)
        embed.add_field(name="Joined Official Fortnite server on",
                        value=joined_on)
        if roles is not None:
            embed.add_field(name="Roles", value=roles, inline=False)
        if voice_state and voice_state.channel:
            embed.add_field(
                name="Current voice channel",
                value="{0.mention} ID: {0.id}".format(voice_state.channel),
                inline=False,
            )
        embed.set_footer(
            text=("Member #{} | User ID: {}").format(member_number, user.id))

        name = str(user)
        name = " ~ ".join((name, user.nick)) if user.nick else name
        name = filter_invites(name)

        if user.avatar:
            avatar = user.avatar_url_as(static_format="png")
            embed.set_author(name=name, url=avatar)
            embed.set_thumbnail(url=avatar)
        else:
            embed.set_author(name=name)

        return embed
示例#15
0
    async def userinfo(self, ctx, *, user: discord.Member = None):
        """Show information about a user.

        This includes fields for status, discord join date, server
        join date, voice state and previous names/nicknames.

        If the user has no roles, previous names or previous nicknames,
        these fields will be omitted.
        """
        author = ctx.author
        guild = ctx.guild

        if not user:
            user = author

        roles = user.roles[-1:0:-1]
        names, nicks = await self.get_names_and_nicks(user)

        joined_at = user.joined_at
        since_created = (ctx.message.created_at - user.created_at).days
        if joined_at is not None:
            since_joined = (ctx.message.created_at - joined_at).days
            user_joined = joined_at.strftime("%d %b %Y %H:%M")
        else:
            since_joined = "?"
            user_joined = _("Unknown")
        user_created = user.created_at.strftime("%d %b %Y %H:%M")
        voice_state = user.voice
        member_number = (sorted(
            guild.members,
            key=lambda m: m.joined_at or ctx.message.created_at).index(user) +
                         1)

        created_on = _("{}\n({} days ago)").format(user_created, since_created)
        joined_on = _("{}\n({} days ago)").format(user_joined, since_joined)

        activity = _("Chilling in {} status").format(user.status)
        if user.activity is None:  # Default status
            pass
        elif user.activity.type == discord.ActivityType.playing:
            activity = _("Playing {}").format(user.activity.name)
        elif user.activity.type == discord.ActivityType.streaming:
            activity = _("Streaming [{}]({})").format(user.activity.name,
                                                      user.activity.url)
        elif user.activity.type == discord.ActivityType.listening:
            activity = _("Listening to {}").format(user.activity.name)
        elif user.activity.type == discord.ActivityType.watching:
            activity = _("Watching {}").format(user.activity.name)

        if roles:

            role_str = ", ".join([x.mention for x in roles])
            # 400 BAD REQUEST (error code: 50035): Invalid Form Body
            # In embed.fields.2.value: Must be 1024 or fewer in length.
            if len(role_str) > 1024:
                # Alternative string building time.
                # This is not the most optimal, but if you're hitting this, you are losing more time
                # to every single check running on users than the occasional user info invoke
                # We don't start by building this way, since the number of times we hit this should be
                # infintesimally small compared to when we don't across all uses of Red.
                continuation_string = _(
                    "and {numeric_number} more roles not displayed due to embed limits."
                )
                available_length = 1024 - len(
                    continuation_string)  # do not attempt to tweak, i18n

                role_chunks = []
                remaining_roles = 0

                for r in roles:
                    chunk = f"{r.mention}, "
                    chunk_size = len(chunk)

                    if chunk_size < available_length:
                        available_length -= chunk_size
                        role_chunks.append(chunk)
                    else:
                        remaining_roles += 1

                role_chunks.append(
                    continuation_string.format(numeric_number=remaining_roles))

                role_str = "".join(role_chunks)

        else:
            role_str = None

        data = discord.Embed(description=activity, colour=user.colour)
        data.add_field(name=_("Joined Discord on"), value=created_on)
        data.add_field(name=_("Joined this server on"), value=joined_on)
        if role_str is not None:
            data.add_field(name=_("Roles"), value=role_str, inline=False)
        if names:
            # May need sanitizing later, but mentions do not ping in embeds currently
            val = filter_invites(", ".join(names))
            data.add_field(name=_("Previous Names"), value=val, inline=False)
        if nicks:
            # May need sanitizing later, but mentions do not ping in embeds currently
            val = filter_invites(", ".join(nicks))
            data.add_field(name=_("Previous Nicknames"),
                           value=val,
                           inline=False)
        if voice_state and voice_state.channel:
            data.add_field(
                name=_("Current voice channel"),
                value="{0.mention} ID: {0.id}".format(voice_state.channel),
                inline=False,
            )
        data.set_footer(
            text=_("Member #{} | User ID: {}").format(member_number, user.id))

        name = str(user)
        name = " ~ ".join((name, user.nick)) if user.nick else name
        name = filter_invites(name)

        if user.avatar:
            avatar = user.avatar_url_as(static_format="png")
            data.set_author(name=name, url=avatar)
            data.set_thumbnail(url=avatar)
        else:
            data.set_author(name=name)

        await ctx.send(embed=data)