Exemple #1
0
    def get_category_ch_update_embed(
            cls, before: discord.CategoryChannel,
            after: discord.CategoryChannel) -> Optional[discord.Embed]:
        """Constructs the embed for the 'on_guild_channel_update' event for categories."""
        embed = discord.Embed(
            title="Category Updated",
            description=f"Update info for category <#{after.id}>",
            timestamp=datetime.utcnow(),
            color=discord.Color.blurple())

        embed.set_footer(text=f"Category ID: {after.id}")

        if before.name != after.name:
            embed.add_field(
                name="Name Changed:",
                value=
                f"{before_txt}**{before.name}**\n{now_txt}**{after.name}**")

        if before.is_nsfw() != after.is_nsfw():
            before_nsfw = "Yes" if before.is_nsfw() else "No"
            after_nsfw = "Yes" if after.is_nsfw() else "No"
            embed.add_field(
                name="NSFW Status Changed:",
                value=
                f"{before_txt}**{before_nsfw}**\n{now_txt}**{after_nsfw}**")

        if before.overwrites != after.overwrites:
            embed = cls.determine_changed_overrides(embed, before, after)

        return embed if len(embed.fields) > 0 else None
    async def addcategory(self, ctx: commands.Context,
                          category: discord.CategoryChannel, *, time: str):
        """Add a category cooldown.

        Time format can be the following:
        - `1 hour`
        - `1h`
        - `1 hour 5 minutes`
        - `2h30m10s`
        """
        if not category.permissions_for(ctx.me).manage_messages:
            await ctx.send(
                "I require the 'Manage messages' permission to let you use this command."
            )
        cooldown_categories = await self.config.guild(ctx.guild
                                                      ).cooldown_categories()
        if str(category.id) in cooldown_categories:
            await ctx.send(
                "This category is already added to the cooldown. If you want to edit"
                " the cooldown time, use `{prefix}slow channel edit`.".format(
                    prefix=ctx.clean_prefix))
            return
        time = self._return_time(time)
        if time:
            await self._update_category_data(ctx, category, time)
            await ctx.send(
                "Done! Every {category}'s channels are now set at 1 message every "
                "{time} seconds. Channels from this category are moderated but new channel "
                "won't be moderated. If you add channels that you want to also add cooldown"
                ", use `{prefix}slow category update`".format(
                    category=category.name, time=time,
                    prefix=ctx.clean_prefix))
        else:
            await ctx.send("Your time is not correct to me.")
Exemple #3
0
    async def category(self, ctx, category: discord.CategoryChannel):
        """Set the category to create ticket channels under."""
        if not category.permissions_for(ctx.guild.me).manage_channels:
            await ctx.send(
                'I require "Manage Channels" permissions in that category to execute that command.'
            )
            return

        await self.config.guild(ctx.guild).category.set(category.id)
        await ctx.send(f"Ticket channels will now be created in the {category.name} category")
def bot_can_manage_category(category: discord.CategoryChannel) -> Result[bool]:
    """
    Checks if the bot can manage channels in the specified category.
    :param category: Discord server category.
    :return: Result of the check, with error message if not successful.
    """
    if category.permissions_for(member=category.guild.me).manage_channels:
        return Result(success=True, value=True, error=None)
    return Result(
        success=False, value=False, error="The bot does not have permissions to manage channels in that category."
    )
Exemple #5
0
    async def archive_category(self, ctx, category: discord.CategoryChannel):
        """Set the category to move closed ticket channels to."""
        if not category.permissions_for(ctx.guild.me).manage_channels:
            await ctx.send(
                'I require "Manage Channels" permissions in that category to execute that command.'
            )
            return

        async with self.config.guild(ctx.guild).archive() as data:
            data["category"] = category.id
        await ctx.send(
            f"Closed ticket channels will now be moved to the {category.name} category, "
            "if Archive mode is enabled.")
    async def gdc_setup(
        self,
        ctx: commands.Context,
        team: HockeyTeams,
        category: discord.CategoryChannel = None,
        delete_gdc: bool = True,
    ) -> None:
        """
        Setup game day channels for a single team or all teams

        Required parameters:
        `<team>` must use quotes if a space is in the name will search for partial team name

        Optional Parameters:
        `[category]` You must use the category ID or use this command in a channel already in the
        desired category

        `[delete_gdc=True]` will tell the bot whether or not to delete game day channels automatically
        must be either `True` or `False`. Defaults to `True` if not provided.
        """
        guild = ctx.message.guild
        if team is None:
            return await ctx.send(_("You must provide a valid current team."))
        if category is None and ctx.channel.category is not None:
            category = guild.get_channel(ctx.channel.category_id)
        else:
            return await ctx.send(
                _("You must specify a channel category for game day channels to be created under."
                  ))
        if not category.permissions_for(guild.me).manage_channels:
            await ctx.send(_("I don't have manage channels permission!"))
            return
        await self.config.guild(guild).category.set(category.id)
        await self.config.guild(guild).gdc_team.set(team)
        await self.config.guild(guild).delete_gdc.set(delete_gdc)
        await self.config.guild(guild).create_channels.set(True)
        if team.lower() != "all":
            await self.create_gdc(guild)
        else:
            game_list = await Game.get_games(session=self.session)
            for game in game_list:
                await self.create_gdc(guild, game)
        await ctx.send(
            _("Game Day Channels for ") + team + _(" setup in ") +
            category.name)
Exemple #7
0
    async def setup_auto_pickems(self,
                                 ctx: commands.Context,
                                 category: discord.CategoryChannel = None):
        """
        Sets up automatically created pickems channels every week.

        `[category]` the channel category where pickems channels will be created.
        This must be the category ID. If not provided this will use the current
        channels category if it exists.
        """

        if category is None and not ctx.channel.category:
            return await ctx.send(_("A channel category is required."))
        elif category is None and ctx.channel.category is not None:
            category = ctx.channel.category

        if not category.permissions_for(ctx.me).manage_channels:
            await ctx.send(_("I don't have manage channels permission!"))
            return

        await self.config.guild(ctx.guild).pickems_category.set(category.id)
        existing_channels = await self.config.guild(ctx.guild
                                                    ).pickems_channels()
        if existing_channels:
            cant_delete = []
            for chan_id in existing_channels:
                channel = ctx.guild.get_channel(chan_id)
                if channel:
                    try:
                        await channel.delete()
                    except discord.errors.Forbidden:
                        cant_delete.append(chan_id)
                await self.config.guild(ctx.guild).pickems_channels.clear()
                if cant_delete:
                    chans = humanize_list([f"<#{_id}>" for _id in cant_delete])
                    await ctx.send(
                        _("I tried to delete the following channels without success:\n{chans}"
                          ).format(chans=chans))
        async with self.pickems_save_lock:
            log.debug("Locking save")
            await Pickems.create_weekly_pickems_pages(self.bot, [ctx.guild],
                                                      Game)
        await ctx.send(
            _("I will now automatically create pickems pages every Sunday."))
Exemple #8
0
def test_server_info_command(time_since_patch, cog, ctx, moderator_role):
    time_since_patch.return_value = '2 days ago'

    ctx.guild.created_at = datetime(2001, 1, 1)
    ctx.guild.features = ('lemons', 'apples')
    ctx.guild.region = 'The Moon'
    ctx.guild.roles = [moderator_role]
    ctx.guild.channels = [
        TextChannel(state={},
                    guild=ctx.guild,
                    data={
                        'id': 42,
                        'name': 'lemons-offering',
                        'position': 22,
                        'type': 'text'
                    }),
        CategoryChannel(state={},
                        guild=ctx.guild,
                        data={
                            'id': 5125,
                            'name': 'the-lemon-collection',
                            'position': 22,
                            'type': 'category'
                        }),
        VoiceChannel(state={},
                     guild=ctx.guild,
                     data={
                         'id': 15290,
                         'name': 'listen-to-lemon',
                         'position': 22,
                         'type': 'voice'
                     })
    ]
    ctx.guild.members = [
        member('online'),
        member('online'),
        member('idle'),
        member('dnd'),
        member('dnd'),
        member('dnd'),
        member('dnd'),
        member('offline'),
        member('offline'),
        member('offline')
    ]
    ctx.guild.member_count = 1_234
    ctx.guild.icon_url = 'a-lemon.png'

    coroutine = cog.server_info.callback(cog, ctx)
    assert asyncio.run(coroutine) is None  # no rval

    time_since_patch.assert_called_once_with(ctx.guild.created_at,
                                             precision='days')
    _, kwargs = ctx.send.call_args
    embed = kwargs.pop('embed')
    assert embed.colour == Colour.blurple()
    assert embed.description == textwrap.dedent(f"""
        **Server information**
        Created: {time_since_patch.return_value}
        Voice region: {ctx.guild.region}
        Features: {', '.join(ctx.guild.features)}

        **Counts**
        Members: {ctx.guild.member_count:,}
        Roles: {len(ctx.guild.roles)}
        Text: 1
        Voice: 1
        Channel categories: 1

        **Members**
        {Emojis.status_online} 2
        {Emojis.status_idle} 1
        {Emojis.status_dnd} 4
        {Emojis.status_offline} 3
        """)
    assert embed.thumbnail.url == 'a-lemon.png'
Exemple #9
0
    async def check_perms_source_dest(
        self,
        autoroom_source: discord.VoiceChannel,
        category_dest: discord.CategoryChannel,
        detailed=False,
    ):
        """Check if the permissions in an AutoRoom Source and a destination category are sufficient."""
        source = autoroom_source.permissions_for(autoroom_source.guild.me)
        dest = category_dest.permissions_for(category_dest.guild.me)
        # Check the basics
        result = (source.move_members and source.view_channel
                  and source.connect and dest.view_channel
                  and dest.manage_channels and dest.manage_messages
                  and dest.connect and dest.move_members)
        if not detailed and not result:
            return False
        # Check the @everyone overwrites if they exist
        override_section = None
        if (autoroom_source.overwrites and autoroom_source.guild.default_role
                in autoroom_source.overwrites):
            overwrites = autoroom_source.overwrites[
                autoroom_source.guild.default_role]
            # Skip permissions we can't give (manage_roles) or are required to be True (view_channel/connect)
            overwrites.update(view_channel=None,
                              manage_roles=None,
                              connect=None)
            for overwrite in overwrites:
                if overwrite[1] is not None:
                    check_result = getattr(dest, overwrite[0])
                    if detailed:
                        result = result and check_result
                        if not override_section:
                            override_section = SettingDisplay(
                                f"Optional @everyone Permissions")
                        override_section.add(
                            overwrite[0].capitalize().replace("_", " "),
                            check_result)
                    elif not check_result:
                        return False

        if not detailed:
            return True

        source_section = SettingDisplay(
            f"Required on Source: {autoroom_source.name}")
        source_section.add("Move members", source.move_members)
        source_section.add("View channels", source.view_channel)
        source_section.add("Connect", source.connect)

        dest_section = SettingDisplay(
            f"Required on Destination: {category_dest.name}")
        dest_section.add("View channels", dest.view_channel)
        dest_section.add("Manage channels", dest.manage_channels)
        dest_section.add("Manage messages", dest.manage_messages)
        dest_section.add("Connect", dest.connect)
        dest_section.add("Move members", dest.move_members)

        autoroom_sections = [dest_section]
        if override_section:
            autoroom_sections.append(override_section)
        return result, source_section.display(*autoroom_sections)
Exemple #10
0
 def _bot_can_manage_category(self,
                              category: discord.CategoryChannel) -> bool:
     return category.permissions_for(category.guild.me).manage_channels
Exemple #11
0
    def check_perms_source_dest(
        self,
        autoroom_source: discord.VoiceChannel,
        category_dest: discord.CategoryChannel,
        with_manage_roles_guild=False,
        with_text_channel=False,
        with_optional_clone_perms=False,
        split_required_optional_check=False,
        detailed=False,
    ):
        """Check if the permissions in an AutoRoom Source and a destination category are sufficient."""
        source = autoroom_source.permissions_for(autoroom_source.guild.me)
        dest = category_dest.permissions_for(category_dest.guild.me)
        result_required = True
        result_optional = True
        # Required
        for perm_name in self.perms_bot_source:
            result_required = result_required and getattr(source, perm_name)
        for perm_name in self.perms_bot_dest:
            result_required = result_required and getattr(dest, perm_name)
        if with_manage_roles_guild:
            result_required = (
                result_required
                and category_dest.guild.me.guild_permissions.manage_roles
            )
        # Optional
        if with_text_channel:
            for perm_name in self.perms_bot_dest_text:
                result_optional = result_optional and getattr(dest, perm_name)
        clone_section = None
        if with_optional_clone_perms:
            if detailed:
                clone_result, clone_section = self._check_perms_source_dest_optional(
                    autoroom_source, dest, detailed=True
                )
            else:
                clone_result = self._check_perms_source_dest_optional(
                    autoroom_source, dest
                )
            result_optional = result_optional and clone_result
        result = result_required and result_optional
        if not detailed:
            if split_required_optional_check:
                return result_required, result_optional
            else:
                return result

        source_section = SettingDisplay("Required on Source Voice Channel")
        for perm_name in self.perms_bot_source:
            source_section.add(
                perm_name.capitalize().replace("_", " "), getattr(source, perm_name)
            )

        dest_section = SettingDisplay("Required on Destination Category")
        for perm_name in self.perms_bot_dest:
            dest_section.add(
                perm_name.capitalize().replace("_", " "), getattr(dest, perm_name)
            )
        autoroom_sections = [dest_section]

        if with_manage_roles_guild:
            guild_section = SettingDisplay("Required in Guild")
            guild_section.add(
                "Manage roles", category_dest.guild.me.guild_permissions.manage_roles
            )
            autoroom_sections.append(guild_section)

        if with_text_channel:
            text_section = SettingDisplay(
                "Optional on Destination Category (for text channel)"
            )
            for perm_name in self.perms_bot_dest_text:
                text_section.add(
                    perm_name.capitalize().replace("_", " "), getattr(dest, perm_name)
                )
            autoroom_sections.append(text_section)

        if clone_section:
            autoroom_sections.append(clone_section)

        status_emoji = "\N{NO ENTRY SIGN}"
        if result:
            status_emoji = "\N{WHITE HEAVY CHECK MARK}"
        elif result_required:
            status_emoji = "\N{WARNING SIGN}\N{VARIATION SELECTOR-16}"
        result_str = (
            f"\n{status_emoji} Source VC: {autoroom_source.mention} -> Dest Category: {category_dest.mention}"
            "\n"
            f"{source_section.display(*autoroom_sections)}"
        )
        if split_required_optional_check:
            return result_required, result_optional, result_str
        else:
            return result, result_str