Example #1
0
    async def ping_roles(self, ctx):
        """Returns a list of roles that have been made pingable and their cooldown."""
        ping_roles = ctx.bot.config[ctx.guild.id]["pingable_roles"]

        if ping_roles == {}:
            raise utils.CustomCheckFailure("There are no roles added!")

        role_list = []

        for role in ping_roles.keys():
            role_obj = ctx.guild.get_role(int(role))
            period_delta = datetime.timedelta(
                seconds=ping_roles[role]['time_period'])

            if role_obj != None:
                role_list.append(
                    f"`{role_obj.name}, {humanize.precisedelta(period_delta, format='%0.1f')} cooldown`"
                )
            else:
                del ctx.bot.config[ctx.guild.id]["pingable_roles"][role]

        if role_list != []:
            role_str = ", ".join(role_list)
            await ctx.send(f"Pingable roles: {role_str}")
        else:
            raise utils.CustomCheckFailure("There are no roles added!")
Example #2
0
    async def ping_role(self, ctx, *,
                        role_obj: common.classes.FuzzyRoleConverter):
        """Pings the role specified if the role isn't on cooldown and has been added to a list."""

        ping_roles = self.bot.config[ctx.guild.id]["pingable_roles"]

        if ping_roles == {}:
            raise utils.CustomCheckFailure(
                "There are no roles for you to ping!")

        if not str(role_obj.id) in ping_roles.keys():
            raise commands.BadArgument("That role isn't pingable!")

        role_entry = ping_roles[str(role_obj.id)]

        now = datetime.datetime.utcnow()
        time_period = datetime.timedelta(seconds=role_entry["time_period"])
        last_used = datetime.datetime.utcfromtimestamp(role_entry["last_used"])
        next_use = last_used + time_period

        if now < next_use:
            till_next_time = next_use - now
            time_text = humanize.precisedelta(till_next_time, format='%0.1f')
            raise utils.CustomCheckFailure(
                f"You cannot ping that role yet! Please wait: `{time_text}` before trying to ping the role again."
            )
        else:
            await ctx.send(
                role_obj.mention,
                allowed_mentions=discord.AllowedMentions(roles=True))

            self.bot.config[ctx.guild.id]["pingable_roles"][str(
                role_obj.id)]["last_used"] = now.timestamp()
Example #3
0
    async def pinall(self, ctx):
        """Retroactively moves overflowing pins from the channel this command is used in to the destination channel.
        Useful if you just mapped a channel and need to move old pin entries.
        Requires Manage Server permissions or higher."""

        if not str(ctx.channel.id) in self.bot.config[ctx.guild.id]["pin_config"].keys():
            raise commands.BadArgument("This channel isn't mapped!")

        chan_entry = self.bot.config[ctx.guild.id]["pin_config"][str(ctx.channel.id)]

        pins = await ctx.channel.pins()
        pins.reverse() # pins are retrived newest -> oldest, we want to do the opposite

        if not len(pins) > chan_entry["limit"]:
            raise utils.CustomCheckFailure("The number of pins is below or at the limit!")

        des_chan = self.bot.get_channel(chan_entry["destination"])
        if des_chan == None:
            raise utils.CustomCheckFailure("The destination channel doesn't exist anymore! Please fix this in the config.")

        dif = len(pins) - chan_entry["limit"]
        pins_subset = pins[-dif:]

        for pin in pins_subset:
            send_embed = await star_mes.star_generate(self.bot, pin)
            send_embed.color = discord.Colour.default()

            await des_chan.send(embed = send_embed)
            await pin.unpin()

        await ctx.send("Done!")
async def add(
    ctx,
    role: fuzzys.FuzzyRoleConverter,
    *,
    cooldown: common.classes.TimeDurationConverter,
):
    """Adds the role to the roles able to be pinged.
    The role can be an ID, a mention, or a name. If it's a name and the name is more than one word, that it must be in quotes.
    The cooldown can be in seconds, minutes, hours, days, months, and/or years (ex. 1s, 1m, 1h 20.5m)."""

    top_role = ctx.guild.me.top_role

    if role > top_role:
        raise utils.CustomCheckFailure(
            "The role provided is a role that is higher than the roles I can edit."
            " Please move either that role or my role so that " +
            "my role is higher than the role you want to be pingable.")

    pingable_roles = ctx.bot.config.getattr(ctx.guild.id, "pingable_roles")

    if str(role.id) in pingable_roles:
        raise utils.CustomCheckFailure("That role is already pingable!")

    period = cooldown.total_seconds()

    pingable_roles[str(role.id)] = {"time_period": period, "last_used": 0}
    ctx.bot.config.setattr(ctx.guild.id, pingable_roles=pingable_roles)

    await ctx.reply("Role added!")
Example #5
0
    async def ping_role(self, ctx, *, role: fuzzys.FuzzyRoleConverter):
        """Pings the role specified if the role isn't on cooldown and has been added to a list."""

        ping_roles = self.bot.config.getattr(ctx.guild.id, "pingable_roles")

        if ping_roles == {}:
            raise utils.CustomCheckFailure("There are no roles for you to ping!")

        if str(role.id) not in ping_roles.keys():
            raise commands.BadArgument("That role isn't pingable!")

        role_entry = ping_roles[str(role.id)]

        now = discord.utils.utcnow()
        time_period = datetime.timedelta(seconds=role_entry["time_period"])
        last_used = datetime.datetime.utcfromtimestamp(role_entry["last_used"]).replace(
            tzinfo=datetime.timezone.utc
        )
        next_use = last_used + time_period

        if now < next_use:
            raise utils.CustomCheckFailure(
                "You cannot ping that role yet! Please try again "
                + discord.utils.format_dt(next_use, style="R")
            )

        await ctx.reply(
            role.mention, allowed_mentions=discord.AllowedMentions(roles=True)
        )

        ping_roles[str(role.id)]["last_used"] = now.timestamp()
        self.bot.config.setattr(ctx.guild.id, pingable_roles=ping_roles)
Example #6
0
    async def random(self, ctx: commands.Context):
        """Gets a random starboard entry from the server it's being run in.
        May not work 100% of the time, but it should be reliable enough."""

        await ctx.trigger_typing()

        random_entry = await self.bot.starboard.get_random(ctx.guild.id)

        if not random_entry:
            raise utils.CustomCheckFailure(
                "There are no starboard entries for me to pick!"
            )

        ori_url = f"https://discordapp.com/channels/{ctx.guild.id}/{random_entry.ori_chan_id}/{random_entry.ori_mes_id}"

        try:
            star_mes = await self.bot.get_partial_messageable(
                random_entry.starboard_id
            ).fetch_message(random_entry.star_var_id)
        except discord.HTTPException:
            raise utils.CustomCheckFailure(
                "I picked an entry, but I couldn't get the starboard message.\n"
                + f"This might be the message I was trying to get: {ori_url}"
            )

        star_content = star_mes.content
        star_embed = star_mes.embeds[0]

        star_embed.add_field(
            name="Starboard Variant",
            value=f"[Jump]({ori_url})",
            inline=True,
        )

        await ctx.reply(star_content, embed=star_embed)
Example #7
0
    async def ping_roles(self, ctx):
        """Returns a list of roles that have been made pingable and their cooldown."""
        ping_roles = self.bot.config.getattr(ctx.guild.id, "pingable_roles")

        if ping_roles == {}:
            raise utils.CustomCheckFailure("There are no roles added!")

        role_list = []

        for role in ping_roles.keys():
            role_obj = ctx.guild.get_role(int(role))

            if role_obj:
                period_delta = datetime.timedelta(
                    seconds=ping_roles[role]["time_period"]
                )
                time_text = None

                now = discord.utils.utcnow()
                last_used = datetime.datetime.utcfromtimestamp(
                    ping_roles[role]["last_used"]
                ).replace(tzinfo=datetime.timezone.utc)
                next_use = last_used + period_delta

                if now < next_use:
                    till_next_time = next_use - now
                    time_text = humanize.precisedelta(till_next_time, format="%0.1f")

                if time_text:
                    role_list.append(
                        (
                            role_obj.name,
                            f"{humanize.precisedelta(period_delta, format='%0.1f')} cooldown\n{time_text} until"
                            " next use",
                        )
                    )
                else:
                    role_list.append(
                        (
                            role_obj.name,
                            f"{humanize.precisedelta(period_delta, format='%0.1f')} cooldown",
                        )
                    )

            else:
                del ping_roles["pingable_roles"][role]
                self.bot.config.setattr(ctx.guild.id, pingable_roles=ping_roles)

        if role_list:
            to_pag = paginator.FieldPages(ctx, entries=role_list)
            await to_pag.paginate()
        else:
            raise utils.CustomCheckFailure("There are no roles added!")
Example #8
0
    async def toggle_nsfw(self, ctx, channel: typing.Optional[discord.TextChannel]):
        """Toggles either the provided channel or the channel the command is used it on or off NSFW mode.
        Useful for mobile devices, which for some reason cannot do this.
        Requires Manage Server permissions or higher."""

        if channel is None:
            channel = ctx.channel

        toggle = not channel.is_nsfw()

        try:
            await channel.edit(nsfw=toggle)
            await ctx.reply(
                f"{channel.mention}'s' NSFW mode has been set to: {toggle}."
            )
        except discord.HTTPException as e:
            raise utils.CustomCheckFailure(
                "".join(
                    (
                        "I was unable to change this channel's NSFW mode! This might be"
                        " due to me not having the ",
                        "permissions to or some other weird funkyness with Discord."
                        " Maybe this error will help you.\n\n",
                        f"Error: `{e}`",
                    )
                )
            )
Example #9
0
    async def selection_handler(self, ctx, options):
        entries = [o[0] for o in options]
        selection_embed = self.norm_embed_gen(ctx, entries)
        await ctx.send(embed=selection_embed)

        def check(m):
            return m.channel == ctx.channel and m.author == ctx.author

        try:
            msg = await ctx.bot.wait_for('message', timeout=15.0, check=check)
        except asyncio.TimeoutError:
            raise commands.BadArgument("No entry selected. Canceling command.")

        else:
            if msg.content.lower() == "cancel":
                raise utils.CustomCheckFailure("Canceled command.")
            elif not msg.content.isdigit():
                raise commands.BadArgument("Invalid input. Canceled command.")
            else:
                selection = int(msg.content)
                if selection > len(entries):
                    raise commands.BadArgument(
                        "Invalid number. Canceled command.")
                else:
                    return entries[selection - 1]
Example #10
0
    async def pos(self, ctx, *, user=None):
        """Allows you to get either your or whoever you mentioned’s position in the star leaderboard (like the top command, but only for one person).
        The user can be mentioned, searched up by ID, or you can say their name and the bot will attempt to search for that person."""

        if user != None:
            member = await common.classes.FuzzyMemberConverter().convert(
                ctx, user)
        else:
            member = ctx.author

        user_star_list = self.get_star_rankings(ctx)

        if user_star_list != None:
            if user != None:
                placing = f"{member.display_name}'s {self.get_user_placing(user_star_list, member.id)}"
            else:
                placing = f"Your {self.get_user_placing(user_star_list, member.id)}"

            place_embed = discord.Embed(colour=discord.Colour(0xcfca76),
                                        description=placing,
                                        timestamp=datetime.datetime.utcnow())
            place_embed.set_author(
                name=f"{self.bot.user.name}",
                icon_url=
                f"{str(ctx.guild.me.avatar_url_as(format=None,static_format='jpg',size=128))}"
            )
            place_embed.set_footer(text="Sent")

            await ctx.send(embed=place_embed)
        else:
            raise utils.CustomCheckFailure(
                "There are no starboard entries for this server!")
Example #11
0
async def _list(ctx: commands.Context):
    """Returns a list of channels that have their pins mapped to another channel, and the max limit before they overflow to that other channel."""

    pin_config = ctx.bot.config.getattr(ctx.guild.id, "pin_config")

    if pin_config == {}:
        raise utils.CustomCheckFailure("There are no entries for this server!")

    entries_list = collections.deque()
    entries_list.append("Channels mapped:\n")

    for entry in pin_config.keys():
        entry_text = None
        try:
            entry_chan = ctx.guild.get_channel(int(entry))
            entry_text = entry_chan.mention
        except ValueError or AttributeError:
            if entry == "default":
                entry_text = entry
            else:
                raise utils.CustomCheckFailure(
                    "Something weird happened when trying to run this command, and I"
                    " couldn't get something. " +
                    "Join the support server to report this.")

        des_chan = ctx.guild.get_channel(pin_config[entry]["destination"])

        if entry_text and des_chan:
            limit = pin_config[entry]["limit"]
            reversed = pin_config[entry]["reversed"]

            entries_list.append(
                f"{entry_text} -> {des_chan.mention} (Limit: {limit}, reversed:"
                f" {reversed})")
        else:
            del pin_config[entry]
            ctx.bot.config.setattr(ctx.guild.id, pin_config=pin_config)

    if entries_list != []:
        entries_str = "\n".join(entries_list)
        to_pagniate = pagniator.TextPages(ctx,
                                          entries_str,
                                          prefix="",
                                          suffix="")
        await to_pagniate.paginate()
    else:
        raise utils.CustomCheckFailure("There are no entries for this server!")
Example #12
0
    async def refresh(
        self,
        ctx: utils.SeraContextBase,
        msg: typing.Union[discord.Message, discord.Object],
    ):
        """Refreshes a starboard entry, using the internal generator to remake the starboard message.
        Useful if you want to use the new starboard message features or if you want to update the avatar.
        The original message must also still exist.
        The message either needs to be a message ID of a message,
        a {channel id}-{message id} format, or the message link itself.
        You must have Manage Server permissions or higher to run this command."""

        await ctx.trigger_typing()

        starboard_entry = await self.initial_get(
            ctx, msg, do_not_create=True, bypass_int_check=True
        )

        starboard_chan = ctx.guild.get_channel_or_thread(starboard_entry.starboard_id)
        try:
            starboard_msg = await starboard_chan.fetch_message(
                starboard_entry.star_var_id
            )
        except discord.HTTPException or AttributeError:
            raise utils.CustomCheckFailure(
                "The starboard message cannot be found! Make sure the bot can see the"
                " channel."
            )

        ori_chan = ctx.guild.get_channel_or_thread(starboard_entry.ori_chan_id)
        try:
            ori_msg = await ori_chan.fetch_message(starboard_entry.ori_mes_id)
        except discord.HTTPException or AttributeError:
            raise utils.CustomCheckFailure(
                "The original message cannot be found! Make sure the bot can see the"
                " channel."
            )

        new_embed = await star_mes.star_generate(self.bot, ori_msg)
        new_content = star_utils.generate_content_str(starboard_entry)

        await starboard_msg.edit(content=new_content, embed=new_embed)
        await ctx.reply(
            f"Updated! Check out {starboard_msg.jump_url} to see the updated message!"
        )
Example #13
0
    async def pinall(self, ctx: commands.Context):
        """Retroactively moves overflowing pins from the channel this command is used in to the destination channel.
        Useful if you just mapped a channel and need to move old pin entries.
        Requires Manage Server permissions or higher."""

        pin_config = self.bot.config.getattr(ctx.guild.id, "pin_config")
        chan_entry = pin_config.get(str(ctx.channel.id))
        if not chan_entry:
            chan_entry = pin_config.get("default")
        if not chan_entry:
            raise commands.BadArgument("This channel isn't mapped!")

        pins = await ctx.channel.pins()
        pins.reverse()  # pins are retrived newest -> oldest, we want to do the opposite

        if len(pins) <= chan_entry["limit"]:
            raise utils.CustomCheckFailure(
                "The number of pins is below or at the limit!"
            )

        des_chan = ctx.guild.get_channel(chan_entry["destination"])
        if des_chan is None:
            raise utils.CustomCheckFailure(
                "The destination channel doesn't exist anymore! Please fix this in the"
                " config."
            )

        dif = len(pins) - chan_entry["limit"]
        if not chan_entry["reversed"]:
            pins_subset = pins[-dif:]
            pins_subset.reverse()
        else:
            pins_subset = pins[:dif]

        for pin in pins_subset:
            send_embed = await star_mes.star_generate(self.bot, pin)
            send_embed.color = discord.Colour.default()
            new_url = f"{send_embed.author.icon_url}&userid={pin.author.id}"
            send_embed.set_author(name=send_embed.author.name, icon_url=new_url)

            await des_chan.send(embed=send_embed)
            await pin.unpin()

        await ctx.reply("Done!")
Example #14
0
    async def timeout(
        self,
        ctx: commands.Context,
        user: discord.Member,
        duration: custom_classes.TimeDurationConverter,
        *,
        reason: typing.Optional[str] = None,
    ):
        """Times out the user specified for the duration specified for the reason specified if given (repetitve, huh?).
        The user can be a ping of the user, their ID, or their name.
        The duration can be in seconds, minutes, hours, days, or months (ex. 1s, 1m, 1h20m).
        It must be less than 28 days - this is a Discord limitation.
        The reason is optional.
        Requires Manage Server permissions or higher.
        """
        if user.top_role >= ctx.guild.me.top_role or ctx.guild.owner_id == user.id:
            raise commands.BadArgument(
                "I cannot timeout this user as their rank is higher than mine!"
            )
        if user.top_role >= ctx.author.top_role:
            raise commands.BadArgument(
                "I cannot timeout this user as their rank is higher than yours!"
            )

        assert isinstance(duration, datetime.timedelta)
        if duration.total_seconds() > 2419200:  # 28 days
            raise commands.BadArgument(
                "The duration provided is over 28 days, the max Discord allows."
            )
        elif duration.total_seconds() < 10:
            raise commands.BadArgument(
                "The duration provided is below 10 seconds, the minimum Discord allows."
            )

        disabled_until = ctx.message.created_at + duration
        try:
            await user.edit(timed_out_until=disabled_until, reason=reason)
            await ctx.reply(
                f"Timed out {user.mention} until"
                f" {discord.utils.format_dt(disabled_until)}.",
                allowed_mentions=utils.deny_mentions(ctx.author),
            )
        except discord.HTTPException as e:
            raise utils.CustomCheckFailure(
                "".join(
                    (
                        "I was unable to timeout this user! This might be due to me not"
                        " having the ",
                        "permissions to do so or duration being too long. Maybe this"
                        " error will help you.\n\n",
                        f"Error: `{e}`",
                    )
                )
            )
Example #15
0
async def toggle(ctx, toggle: typing.Optional[bool]):
    """Allows you to either see if all starboard-related commands and actions are on or off (no argument) or allows you to toggle that (with argument).
    If you wish to set the toggle, both the starboard channel and the star limit must be set first."""

    if toggle != None:
        guild_config = ctx.bot.config[ctx.guild.id]
        if guild_config["starboard_id"] != None and guild_config["star_limit"] != None:
            ctx.bot.config[ctx.guild.id]["star_toggle"] = toggle
            await ctx.send(f"Toggled starboard to {toggle} for this server!")
        else:
            raise utils.CustomCheckFailure("Either you forgot to set the starboard channel or the star limit. Please try again.")
    else:
        await ctx.send(f"Star toggle: {ctx.bot.config[ctx.guild.id]['star_toggle']}")
Example #16
0
    async def force(self, ctx, msg: discord.Message):
        """Forces a message onto the starboard, regardless of how many stars it has.
        The message either needs to be a message ID of a message in the channel the command is being run in,
        a {channel id}-{message id} format, or the message link itself.
        This message cannot be taken off the starboard unless it is deleted from it manually.
        You must have Manage Server permissions or higher to run this command."""

        if not self.bot.config[ctx.guild.id]["star_toggle"]:
            raise utils.CustomCheckFailure(
                "Starboard is not turned on for this server!")

        starboard_entry = star_utils.get_star_entry(self.bot, msg.id)
        if starboard_entry == []:
            author_id = star_utils.get_author_id(msg, self.bot)

            self.bot.starboard[msg.id] = {
                "ori_chan_id": msg.channel.id,
                "star_var_id": None,
                "starboard_id": None,
                "author_id": author_id,
                "ori_reactors": [],
                "var_reactors": [],
                "guild_id": msg.guild.id,
                "forced": False,
                "ori_mes_id_bac": msg.id,
                "updated": True
            }
            starboard_entry = self.bot.starboard[msg.id]

            await star_utils.sync_prev_reactors(self.bot,
                                                msg,
                                                author_id,
                                                starboard_entry,
                                                "ori_reactors",
                                                remove=False)

        if starboard_entry["star_var_id"] == None:
            starboard_entry["forced"] == True
        else:
            raise commands.BadArgument(
                "This message is already on the starboard!")

        unique_stars = star_utils.get_num_stars(starboard_entry)
        self.bot.star_queue[msg.id] = {
            "mes": msg,
            "unique_stars": unique_stars,
            "forced": True
        }

        await ctx.send(
            "Done! Please wait a couple of seconds for the message to appear.")
Example #17
0
    async def add(self, ctx, prefix):
        """Addes the prefix to the bot for the server this command is used in, allowing it to be used for commands of the bot.
        If it's more than one word or has a space at the end, surround the prefix with quotes so it doesn't get lost."""

        if len(self.bot.config[ctx.guild.id]["prefixes"]) >= 10:
            raise utils.CustomCheckFailure(
                "You have too many prefixes! You can only have up to 10 prefixes."
            )

        if not prefix in self.bot.config[ctx.guild.id]["prefixes"]:
            self.bot.config[ctx.guild.id]["prefixes"].append(prefix)
            await ctx.send(f"Added `{prefix}`!")
        else:
            raise commands.BadArgument("The server already has this prefix!")
Example #18
0
    async def copy_emoji(self, ctx: commands.Context, emoji: discord.PartialEmoji):
        """Adds the emoji given to the server the command is run in, thus copying it.
        Useful if you have Discord Nitro and want to add some emojis from other servers into yours.
        This is essentially just the add-emoji command but if it only accepted an emoji and if it did not require you to put in a name.
        Thus, the same limitations as that command apply.
        Requires Manage Server permissions or higher."""

        add_emoji_cmd = self.bot.get_command("add_emoji")
        if not add_emoji_cmd:  # this should never happen
            raise utils.CustomCheckFailure(
                "For some reason, I cannot get the add-emoji command, which is needed"
                " for this. Join the support server to report this."
            )

        await ctx.invoke(add_emoji_cmd, emoji.name, emoji)
Example #19
0
    async def publish(self, ctx, msg: discord.Message):
        """Publishes a message in a news channel. Useful if you're on mobile.
        The message either needs to be a message ID of a message in the channel the command is being run in,
        a {channel id}-{message id} format, or the message link itself.
        Both you and the bot need Manage Server permissions to use this."""

        if msg.channel.type != discord.ChannelType.news:
            raise commands.BadArgument("This channel isn't a news channel!")
        elif not msg.channel.permissions_for(ctx.guild.me).manage_messages:
            raise utils.CustomCheckFailure("I do not have the proper permissions to do that!")

        try:
            await msg.publish()
            await ctx.send("Published!")
        except discord.HTTPException as e:
            await ctx.send(f"An error occured. This shouldn't happen, but here's the error (it might be useful to you): {e}")
Example #20
0
async def add(ctx, channel: discord.TextChannel):
    """Adds the channel to the blacklist."""

    chan_perms = channel.permissions_for(ctx.guild.me)
    chan_check = utils.chan_perm_check(channel, chan_perms)
    if chan_check != "OK":
        raise utils.CustomCheckFailure(chan_check)

    channel_id_list = ctx.bot.config[ctx.guild.id]["star_blacklist"]

    if not channel.id in channel_id_list:
        channel_id_list.append(channel.id)
        ctx.bot.config[ctx.guild.id]["blacklist"] = channel_id_list
        await ctx.send(f"Addded {channel.mention} to the blacklist!")
    else:
        raise commands.BadArgument("That channel's already in the blacklist!")
Example #21
0
    async def setup(self, ctx: commands.Context):
        """An alias for `setup starboard`. Use the help command for that for more information."""
        sb_setup_cmd: typing.Optional[commands.Command] = ctx.bot.get_command(
            "setup starboard"
        )
        if not sb_setup_cmd:
            raise utils.CustomCheckFailure(
                "I couldn't find the command `setup starboard`. This should never"
                " happen, so join the support server to report this."
            )

        try:
            await sb_setup_cmd.can_run(ctx)
        except commands.CommandError:
            raise commands.CheckFailure

        await ctx.invoke(sb_setup_cmd)
Example #22
0
async def remove(ctx, *, role: common.classes.FuzzyRoleConverter):
    """Removes that role from the roles able to be pinged. 
    The role can be an ID, a mention, or a name. If it's a name, it does not need to be in quotes."""

    ping_roles = ctx.bot.config[ctx.guild.id]["pingable_roles"]

    if ping_roles == {}:
        raise utils.CustomCheckFailure(
            "There are no pingable roles to remove!")

    if not str(role.id) in ping_roles.keys():
        raise commands.BadArgument("That role isn't on the ping list!")

    del ctx.bot.config[ctx.guild.id]["pingable_roles"][str(role.id)]

    await ctx.send(f"Deleted {role.mention}!",
                   allowed_mentions=discord.AllowedMentions(roles=False))
Example #23
0
    async def msgtop(self, ctx):
        """Allows you to view the top 10 starred messages on a server. Cooldown of once every 5 seconds per user."""

        guild_entries = [
            self.bot.starboard[k] for k in self.bot.starboard.keys()
            if self.bot.starboard[k]["guild_id"] == ctx.guild.id
        ]
        if guild_entries != []:
            top_embed = discord.Embed(
                title=f"Top starred messages in {ctx.guild.name}",
                colour=discord.Colour(0xcfca76),
                timestamp=datetime.datetime.utcnow())
            top_embed.set_author(
                name=f"{self.bot.user.name}",
                icon_url=
                f"{str(ctx.guild.me.avatar_url_as(format=None,static_format='jpg', size=128))}"
            )
            top_embed.set_footer(text="As of")

            guild_entries.sort(reverse=True,
                               key=lambda e: star_utils.get_num_stars(e))

            for i in range(len(guild_entries)):
                if i > 9:
                    break

                entry = guild_entries[i]
                starboard_id = entry['starboard_id']

                url = f"https://discordapp.com/channels/{ctx.guild.id}/{starboard_id}/{entry['star_var_id']}"
                num_stars = star_utils.get_num_stars(entry)
                member = await utils.user_from_id(self.bot, ctx.guild,
                                                  entry['author_id'])
                author_str = f"{member.display_name} ({str(member)})" if member != None else f"User ID: {entry['author_id']}"

                top_embed.add_field(
                    name=f"#{i+1}: {num_stars} ⭐ from {author_str}",
                    value=f"[Message]({url})\n",
                    inline=False)

            await ctx.send(embed=top_embed)
        else:
            raise utils.CustomCheckFailure(
                "There are no starboard entries for this server!")
Example #24
0
    async def initial_get(
        self,
        ctx,
        msg,
        forced=False,
        do_not_create=False,
        bypass_int_check=False,
    ) -> star_classes.StarboardEntry:
        if not ctx.bot.config.getattr(ctx.guild.id, "star_toggle"):
            raise utils.CustomCheckFailure(
                "Starboard is not turned on for this server!"
            )

        if (
            not isinstance(msg, discord.Message)
            and do_not_create
            and not bypass_int_check
        ):
            raise commands.BadArgument(
                "The message must be in the channel the command is being run in."
            )

        starboard_entry = await ctx.bot.starboard.get(msg.id)
        if not starboard_entry:
            if not do_not_create:
                author_id = star_utils.get_author_id(msg, ctx.bot)
                starboard_entry = star_classes.StarboardEntry.new_entry(
                    msg, author_id, None, forced=forced
                )
                ctx.bot.starboard.add(starboard_entry)

                await star_utils.sync_prev_reactors(
                    ctx.bot, author_id, starboard_entry, remove=False
                )
            else:
                raise commands.BadArgument(
                    "This message does not have an entry here internally."
                )
        elif starboard_entry.guild_id != ctx.guild.id:
            raise commands.BadArgument("Invalid entry!")

        return starboard_entry
async def remove(ctx, *, role: fuzzys.FuzzyRoleConverter):
    """Removes that role from the roles able to be pinged.
    The role can be an ID, a mention, or a name. If it's a name, it does not need to be in quotes."""

    ping_roles = ctx.bot.config.getattr(ctx.guild.id, "pingable_roles")

    if ping_roles == {}:
        raise utils.CustomCheckFailure(
            "There are no pingable roles to remove!")

    if str(role.id) not in ping_roles.keys():
        raise commands.BadArgument("That role isn't on the ping list!")

    del ping_roles[str(role.id)]
    ctx.bot.config.setattr(ctx.guild.id, pingable_roles=ping_roles)

    await ctx.reply(
        f"Deleted {role.mention}!",
        allowed_mentions=discord.AllowedMentions(roles=False),
    )
Example #26
0
async def _list(ctx):
    """Returns a list of channels that have been blacklisted. Messages from channels that are blacklisted won’t be starred."""

    channel_id_list = ctx.bot.config[ctx.guild.id]["star_blacklist"]
    if channel_id_list != []:
        channel_mentions = []

        for channel_id in channel_id_list.copy():
            channel = ctx.bot.get_channel(channel_id)

            if channel != None:
                channel_mentions.append(channel.mention)
            else:
                ctx.bot.config[ctx.guild.id]["star_blacklist"].remove(channel_id)

        if channel_mentions != []:
            await ctx.send(f"Blacklisted channels: {', '.join(channel_mentions)}")
            return
            
    raise utils.CustomCheckFailure("There's no blacklisted channels for this guild!")
Example #27
0
    async def random(self, ctx):
        """Gets a random starboard entry from the server it's being run in.
        May not work 100% of the time, but it should be reliable enough."""

        valid_entries = [
            e for e in self.bot.starboard.values()
            if e["guild_id"] == ctx.guild.id and e["star_var_id"] != None
        ]

        if valid_entries:
            random_entry = random.choice(valid_entries)
            starboard_id = random_entry['starboard_id']

            starboard_chan = ctx.guild.get_channel(starboard_id)
            if starboard_chan == None:
                raise utils.CustomCheckFailure(
                    "I couldn't find the starboard channel for the entry I picked."
                )

            try:
                star_mes = await starboard_chan.fetch_message(
                    random_entry["star_var_id"])
            except discord.HTTPException:
                ori_url = f"https://discordapp.com/channels/{ctx.guild.id}/{random_entry['ori_chan_id']}/{random_entry['ori_mes_id_bac']}"
                await ctx.send(
                    "I picked an entry, but I couldn't get the starboard message.\n"
                    +
                    f"This might be the message I was trying to get: {ori_url}"
                )
                return

            star_content = star_mes.content
            star_embed = star_mes.embeds[0]

            star_embed.add_field(name="Starboard Variant",
                                 value=f"[Jump]({star_mes.jump_url})",
                                 inline=True)

            await ctx.send(star_content, embed=star_embed)
        else:
            await ctx.send("There are no starboard entries for me to pick!")
Example #28
0
async def _list(ctx: commands.Context):
    """Returns a list of channels that have been blacklisted. Messages from channels that are blacklisted won’t be starred."""

    channel_id_list = ctx.bot.config.getattr(ctx.guild.id, "star_blacklist")
    if channel_id_list:
        channel_mentions = []

        for channel_id in channel_id_list.copy():
            channel = ctx.guild.get_channel(channel_id)

            if channel:
                channel_mentions.append(channel.mention)
            else:
                channel_id_list.remove(channel_id)
                ctx.bot.config.setattr(ctx.guild.id, star_blacklist=channel_id_list)

        if channel_mentions:
            await ctx.reply(f"Blacklisted channels: {', '.join(channel_mentions)}")
            return

    raise utils.CustomCheckFailure("There's no blacklisted channels for this guild!")
Example #29
0
    async def add_emoji(self, ctx, emoji_name, url: typing.Optional[image_utils.URLToImage]):
        """Adds the image or URL given as an emoji to this server.
        It must be an image of type GIF, JPG, or PNG. It must also be under 256 KB.
        The name must be at least 2 characters.
        Useful if you're on iOS and transparency gets the best of you or if you want to add an emoji from a URL."""

        if len(emoji_name) < 2:
            raise commands.BadArgument("Emoji name must at least 2 characters!")

        if url == None:
            if ctx.message.attachments:
                if ctx.message.attachments[0].proxy_url.endswith(self.bot.image_extensions):
                    url = ctx.message.attachments[0].proxy_url
                else:
                    raise commands.BadArgument("Attachment provided is not a valid image.")
            else:
                raise commands.BadArgument("No URL or image given!")

        assert url != None

        emoji_count = len(ctx.guild.emojis)
        if emoji_count >= ctx.guild.emoji_limit:
            raise utils.CustomCheckFailure("This guild has no more emoji slots!")

        emoji_data = await image_utils.get_file_bytes(url, 262144, equal_to=False) # 256 KiB, which I assume Discord uses

        try:
            emoji = await ctx.guild.create_custom_emoji(name=emoji_name, image=emoji_data, reason=f"Created by {str(ctx.author)}")
        except discord.HTTPException as e:
            await ctx.send("".join(
                    ("I was unable to add this emoji! This might be due to me not having the ",
                    "permissions or the name being improper in some way. Maybe this error will help you.\n",
                    f"Error: {e}")
                )
            )
            return
        finally:
            del emoji_data

        await ctx.send(f"Added {str(emoji)}!")
Example #30
0
    async def untimeout(
        self,
        ctx: commands.Context,
        user: discord.Member,
        *,
        reason: typing.Optional[str] = None,
    ):
        """Un-timeout out the user specified for the reason specified, if given.
        The user can be a ping of the user, their ID, or their name.
        The reason is optional.
        Requires Manage Server permissions or higher.
        """

        if not user.timed_out_until:
            raise commands.BadArgument("This user is not on timeout!")
        if user.top_role >= ctx.guild.me.top_role or ctx.guild.owner_id == user.id:
            raise commands.BadArgument(
                "I cannot un-timeout this user as their rank is higher than mine!"
            )
        if user.top_role >= ctx.author.top_role:
            raise commands.BadArgument(
                "I cannot un-timeout this user as their rank is higher than yours!"
            )

        try:
            await user.edit(timed_out_until=None, reason=reason)
            await ctx.reply(
                f"Un-timed out {user.mention}.",
                allowed_mentions=utils.deny_mentions(ctx.author),
            )
        except discord.HTTPException as e:
            raise utils.CustomCheckFailure(
                "".join(
                    (
                        "I was unable to un-timeout this user! This might be due to me"
                        " not having the permissions to do. Maybe this error will help"
                        f" you.\n\nError: `{e}`",
                    )
                )
            )