Example #1
0
    async def misctools_unload(self, ctx: commands.Context, *toolsets_: str):
        if not toolsets_:
            await ctx.send_help()
            return

        unloaded = []
        output = []

        for toolset in toolsets_:
            try:
                self.unload(toolset)
            except UnknownToolset:
                output.append(translate("toolset_not_found", set=toolset))
            except NotLoaded:
                output.append(translate("toolset_already_unloaded", set=toolset))
            else:
                unloaded.append(toolset)
                async with config.toolsets() as toolsets__:
                    for ts in toolsets__.copy():
                        if ts.lower() == toolset.lower():
                            toolsets__.remove(ts)

        if unloaded:
            output.append(
                translate(
                    "toolset_unloaded",
                    count=len(unloaded),
                    sets=Humanize([inline(x) for x in unloaded]),
                )
            )

        for page in pagify("\n".join(output)):
            await ctx.send(page)
Example #2
0
def try_import(*imports: str, extra: str = None) -> None:
    """Try to import required modules and raise an exception if any fail to import

    Keyword Arguments
    -----------------
    extra: str
        If this is provided, this will be logged as extra information alongside any
        import failures in the bot's logging.

    Raises
    -------
    CogLoadError
        Raised if one or more given imports fail to import
    """
    failed: List[str] = []
    for import_ in imports:
        try:
            importlib.import_module(import_)
        except Exception as e:  # pylint:disable=broad-except
            log.exception("Failed to import required library %r",
                          import_,
                          exc_info=e)
            failed.append(import_)

    if failed:
        if extra:
            log.warning(
                "Extra information provided for the above import failures: %s",
                extra)

        raise CogLoadError(
            translate("checks.import_failed",
                      libs=Humanize([inline(x) for x in failed]),
                      n=len(failed)))
Example #3
0
    async def remindme(self, ctx: commands.Context, in_time: str, *, to: str):
        if len(to) > 1000:
            await ctx.send(translate("content_too_long"))
            return

        in_time = FutureTime.get_seconds(in_time)
        if in_time is None or in_time < 60:
            raise commands.BadArgument(translate("invalid_time"))

        reminder = await Reminder.create(ctx.author, to, in_time)
        if await ctx.embed_requested():
            embed = discord.Embed(
                colour=await ctx.embed_colour(),
                description=reminder.message,
                title=translate("reminder_created"),
                timestamp=reminder.due_on,
            )
            embed.set_footer(text=translate("will_send_on"))
            await ctx.send(embed=embed)
        else:
            await ctx.send(
                tick(
                    translate(
                        "reminder_set",
                        date=Humanize(reminder.due_on,
                                      format="long",
                                      tzinfo=get_localzone()),
                    )))
Example #4
0
    async def snowflake_delta(self, ctx: commands.Context, starting: int, ending: int):
        starting, ending = (
            discord.utils.snowflake_time(starting),
            discord.utils.snowflake_time(ending),
        )
        now = datetime.utcnow()

        await ctx.send(
            translate(
                "snowflake_delta",
                start_delta=Humanize(starting - now, add_direction=True),
                start_date=Humanize(starting),
                end_delta=Humanize(ending - now, add_direction=True),
                end_date=Humanize(ending),
                difference=Humanize(ending - starting),
            )
        )
Example #5
0
    def reminder_text(self):
        from .remindme import translate

        return translate(
            "reminder_message",
            set_on=Humanize(self.set_on, format="long",
                            tzinfo=get_localzone()),
            message=self.message,
        )
Example #6
0
 async def ping(self, ctx: commands.Context):
     await ctx.send(
         translate(
             "ping",
             latency=Humanize(
                 format_unit,
                 dict(self.bot.latencies)
                 [ctx.guild.shard_id if ctx.guild else 0] * 1000,
                 "millisecond",
             ),
         ))
Example #7
0
 async def __build_xkcd_embed(ctx: commands.Context, comic: "Comic"):
     return (
         discord.Embed(
             title=f"#{comic.number} \N{EM DASH} {comic.title}",
             colour=await ctx.embed_colour(),
             url=comic.link,
             description=translate(
                 "description",
                 image=comic.image,
                 explain=comic.explain,
                 date=Humanize(comic.timestamp),
             ),
         ).set_footer(text=comic.alt or discord.Embed.Empty)
         # the image may be an empty string in the case of comic #404
         .set_image(url=comic.image or discord.Embed.Empty)
     )
Example #8
0
    async def timedmute(
        self,
        ctx: commands.Context,
        member: discord.Member,
        duration: TimeConverter,
        *,
        reason: str = None,
    ):
        from timedrole.api import TempRole

        if not await hierarchy_allows(self.bot, mod=ctx.author, member=member):
            await ctx.send(warning(translate("hierarchy_disallows")))
            return

        role = await self.get_punished_role(ctx.guild)
        if role is None:
            tmp_msg = await ctx.send(translate("setting_up"))
            async with ctx.typing():
                role = await self.setup_role(ctx.guild)
            await tmp_msg.delete()

        if role in member.roles:
            await ctx.send(warning(translate("already_muted")))
            return

        role = await TempRole.create(
            member, role, duration=duration, added_by=ctx.author, reason=reason
        )
        await role.apply_role(reason=reason)

        try:
            await modlog.create_case(
                bot=self.bot,
                guild=ctx.guild,
                user=member,
                moderator=ctx.author,
                reason=reason,
                until=role.expires_at,
                action_type="timedmute",
                created_at=role.added_at,
            )
        except RuntimeError:
            pass

        await ctx.send(tick(translate("member_muted", member=member, duration=Humanize(duration))))
Example #9
0
    async def list(self, ctx: commands.Context):
        reminders = await self.config.user(ctx.author).reminders()
        if not reminders:
            await ctx.send(translate("no_set_reminders", prefix=ctx.prefix))
            return

        pages = list(chunks(reminders, 5))
        page_count = len(pages)
        colour = await ctx.embed_colour()
        # noinspection PyUnresolvedReferences
        for page in pages.copy():
            index = pages.index(page)
            embed = discord.Embed(colour=colour)
            embed.set_author(
                name=translate("set_reminders", user=ctx.author),
                icon_url=ctx.author.avatar_url_as(format="png"),
            )
            embed.set_footer(
                text=translate("page", total=page_count, current=index + 1))

            for reminder in page:
                remind_on = datetime.utcfromtimestamp(reminder["remind_on"])
                embed.add_field(
                    name=translate(
                        "reminder_title",
                        id=(index * 5) + (page.index(reminder) + 1),
                        delta=Humanize(remind_on - datetime.utcnow(),
                                       add_direction=True),
                    ),
                    value=shorten(reminder["message"],
                                  width=700,
                                  placeholder=" \N{HORIZONTAL ELLIPSIS}"),
                    inline=False,
                )

            pages[index] = embed

        await PaginatedMenu(pages=pages,
                            bot=self.bot,
                            member=ctx.author,
                            channel=ctx.channel).prompt()
Example #10
0
    async def misctools_load(self, ctx: commands.Context, *toolsets_: str):
        if not toolsets_:
            await ctx.send_help()
            return

        loaded = []
        output = []

        for toolset in toolsets_:
            try:
                await self.load(toolset)
            except AlreadyLoaded:
                output.append(translate("toolset_already_loaded", set=toolset))
            except UnknownToolset:
                output.append(translate("toolset_not_found", set=toolset))
            except InternalLoadError as e:
                output.append(str(e.translated))
            except Exception as e:  # pylint:disable=broad-except
                log.exception("Failed to load toolset %r", toolset.lower(), exc_info=e)
                output.append(translate("toolset_errored", set=toolset))
            else:
                async with config.toolsets() as toolsets__:
                    ts = self.find(toolset).__name__
                    if ts not in toolsets__:
                        toolsets__.append(ts)
                loaded.append(toolset)

        if loaded:
            output.append(
                translate(
                    "toolset_loaded", count=len(loaded), sets=Humanize([inline(x) for x in loaded])
                )
            )

        for page in pagify("\n".join(output)):
            await ctx.send(page)
Example #11
0
 def __trim_to_three(roles: List[discord.Role]) -> List[str]:
     new_list = [mention(x) for x in roles[:3]]
     if len(roles) > 3:
         new_list.append(translate("n_more", n=Humanize(len(roles) - 3)))
     return new_list
Example #12
0
 async def rndactivity_delay(self, ctx: commands.Context, *,
                             duration: Delay):
     await self.config.delay.set(duration.total_seconds())
     await ctx.send(
         tick(translate("delay_set", duration=Humanize(duration))))
Example #13
0
    async def build_description(self, member: Union[discord.Member, discord.User]) -> str:
        in_guild = isinstance(member, discord.Member)
        desc = []

        if in_guild:
            desc.append(
                translate(f"status.{str(member.status)}")
                if f"status.{str(member.status)}" in translate
                else translate("status.unknown")
            )

            for activity in member.activities:
                desc.append(
                    translate(
                        "activity",
                        activity.type.name
                        if not isinstance(activity, discord.Spotify)
                        else "spotify",
                        artists=Humanize(getattr(member.activity, "artists", [])),
                        title=getattr(member.activity, "title", "???"),
                        name=member.activity.name,
                        url=getattr(member.activity, "url", None),
                        default=None,
                    )
                )

            if member.is_on_mobile():
                desc.append(translate("on_mobile"))

            if member.voice:
                desc.append(translate("voice", channel=member.voice.channel.mention))

        if member.bot:
            desc.append(translate("role.bot"))
        else:
            if await self.bot.is_owner(member):
                desc.append(translate("role.bot_owner"))
            if in_guild:
                if member.guild.owner.id == member.id:
                    desc.append(translate("role.guild_owner"))
                elif await self.bot.is_admin(member):
                    desc.append(translate("role.guild_admin"))
                elif await self.bot.is_mod(member):
                    desc.append(translate("role.guild_mod"))
                else:
                    desc.append(translate("role.guild_member"))
            else:
                desc.append(translate("role.non_member"))

        if in_guild:
            # This will only be visible on Red versions 3.1.4+
            boost_since: Optional[datetime] = getattr(member, "premium_since", None)
            if boost_since:
                desc.append(
                    translate(
                        "nitro_boost",
                        delta=Humanize(boost_since - datetime.utcnow()),
                        date=Humanize(boost_since, tzinfo=get_localzone(), format=DATETIME_FORMAT),
                    )
                )

            if member.nick:
                desc.append(translate("nickname", nick=bold(escape(member.nick, formatting=True))))

        # noinspection PyTypeChecker
        return "\n".join(filter(bool, desc))
Example #14
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)