Module aethersprite.extensions.base.only

Only cog

Expand source code
"""Only cog"""

# TODO server whitelist

# 3rd party
from discord import DMChannel
from discord.channel import TextChannel
from discord.ext.commands import Cog, command, Context
from sqlitedict import SqliteDict

# local
from aethersprite import data_folder, log
from aethersprite.authz import channel_only, require_admin

onlies = SqliteDict(
    f"{data_folder}only.sqlite3", tablename="onlies", autocommit=True
)
"""Only whitelist database"""


class Only(Cog):
    """Only commands; disable all commands except for those in a whitelist"""

    def __init__(self, bot):
        self.bot = bot

    @command(name="only.add")
    async def add(
        self,
        ctx: Context,
        command: str,
        channel: TextChannel | None = None,
    ):
        """
        Add the given command to the Only whitelist

        Enables <command> in this channel.

        You may specify a channel other than the current one.

        Examples:
            !only.add test
            !only.add test #lobby
        """

        assert ctx.guild

        if not channel:
            channel = ctx.channel  # type: ignore
            assert channel

        chan_id = str(channel.id)
        guild = str(ctx.guild.id)

        if guild not in onlies:
            onlies[guild] = dict()

        ours = onlies[guild]

        if chan_id not in ours:
            ours[chan_id] = set([])

        ourchan = ours[chan_id]

        if command in ourchan:
            await ctx.send(":newspaper: Already done.")

            return

        ourchan.add(command)
        ours[chan_id] = ourchan
        onlies[guild] = ours
        log.info(f"{ctx.author} added {command} to {channel} whitelist")
        await ctx.send(":shield: Done.")

    @command(name="only.remove")
    async def remove(
        self,
        ctx: Context,
        command: str,
        channel: TextChannel | None = None,
    ):
        """
        Remove the given command from the Only whitelist

        If whitelisting is enabled for this channel, the removed command can no longer be executed.

        You may provide a channel other than the current one.

        Examples:
            !only.remove test
            !only.remove test #lobby
        """

        assert ctx.guild

        if not channel:
            channel = ctx.channel  # type: ignore
            assert channel

        chan_id = str(channel.id)
        guild = str(ctx.guild.id)
        ours = onlies[guild] if guild in onlies else {}
        ourchan = (
            ours[chan_id] if ours is not None and chan_id in ours else None
        )

        if ourchan is None:
            await ctx.send(":person_shrugging: None set.")

            return

        ourchan.remove(command)

        if len(ourchan) == 0:
            del ours[chan_id]
        else:
            ours[chan_id] = ourchan

        if len(ours) == 0:
            del onlies[guild]
        else:
            onlies[guild] = ours

        log.info(f"{ctx.author} removed {command} from {channel} whitelist")
        await ctx.send(":wastebasket: Removed.")

    @command(name="only.list")
    async def list(
        self,
        ctx: Context,
        channel: TextChannel | None = None,
    ):
        """
        List all current channel's whitelisted commands

        You may provide a channel other than the current one.

        Examples:
            !only.list
            !only.list #lobby
        """

        assert ctx.guild

        if not channel:
            channel = ctx.channel  # type: ignore
            assert channel

        chan_id = str(channel.id)
        guild = str(ctx.guild.id)

        if guild not in onlies:
            onlies[guild] = dict()

        ours = onlies[guild]

        if channel not in ours:
            ours[channel] = set([])

        output = "**, **".join(ours.get(chan_id, []))

        if not len(output):
            output = "None"

        log.info(f"{ctx.author} viewed command whitelist for {channel}")
        await ctx.send(f":guard: **{output}**")

    @command(name="only.reset")
    async def reset(
        self,
        ctx: Context,
        channel: TextChannel | None = None,
    ):
        """
        Reset Only whitelist

        Using this command will disable whitelisting behavior and remove the existing whitelist.

        You may provide a channel other than the current one.

        Examples:
            !only.reset
            !only.reset #lobby
        """

        assert ctx.guild

        if not channel:
            channel = ctx.channel  # type: ignore
            assert channel

        chan_id = str(channel.id)
        guild = str(ctx.guild.id)
        ours = onlies[guild] if guild in onlies else {}
        ourchan = (
            ours[chan_id] if ours is not None and chan_id in ours else None
        )

        if ourchan is None:
            await ctx.send(":person_shrugging: None set.")

            return

        del ours[chan_id]

        if len(ours) == 0:
            del onlies[guild]
        else:
            onlies[guild] = ours

        await ctx.send(":boom: Reset.")
        log.info(f"{ctx.author} reset Only whitelist for {channel}")


async def check_only(ctx: Context):
    """Check that command is in the Only whitelist"""

    assert ctx.guild
    assert ctx.command

    if isinstance(ctx.channel, DMChannel):
        # can't whitelist commands via DM, since we need a guild to check
        # settings values
        return True

    guild = str(ctx.guild.id)
    channel = str(ctx.channel.id)
    ours = onlies[guild] if guild in onlies else None
    ourchan = ours[channel] if ours is not None and channel in ours else None

    if ourchan is None:
        # none set for this channel; bail
        return True

    cmd = ctx.command.name

    if cmd not in ourchan and cmd[0:5] != "only.":
        log.debug(
            f"Suppressing non-whitelisted command from {ctx.author}: "
            f"{ctx.command.name} in #{ctx.channel} ({ctx.guild})"
        )

        return False

    return True


async def setup(bot):
    bot.add_check(check_only)
    cog = Only(bot)

    for c in cog.get_commands():
        c.add_check(channel_only)
        c.add_check(require_admin)

    await bot.add_cog(cog)

Global variables

var onlies

Only whitelist database

Functions

async def check_only(ctx: discord.ext.commands.context.Context)

Check that command is in the Only whitelist

Expand source code
async def check_only(ctx: Context):
    """Check that command is in the Only whitelist"""

    assert ctx.guild
    assert ctx.command

    if isinstance(ctx.channel, DMChannel):
        # can't whitelist commands via DM, since we need a guild to check
        # settings values
        return True

    guild = str(ctx.guild.id)
    channel = str(ctx.channel.id)
    ours = onlies[guild] if guild in onlies else None
    ourchan = ours[channel] if ours is not None and channel in ours else None

    if ourchan is None:
        # none set for this channel; bail
        return True

    cmd = ctx.command.name

    if cmd not in ourchan and cmd[0:5] != "only.":
        log.debug(
            f"Suppressing non-whitelisted command from {ctx.author}: "
            f"{ctx.command.name} in #{ctx.channel} ({ctx.guild})"
        )

        return False

    return True
async def setup(bot)
Expand source code
async def setup(bot):
    bot.add_check(check_only)
    cog = Only(bot)

    for c in cog.get_commands():
        c.add_check(channel_only)
        c.add_check(require_admin)

    await bot.add_cog(cog)

Classes

class Only (bot)

Only commands; disable all commands except for those in a whitelist

Expand source code
class Only(Cog):
    """Only commands; disable all commands except for those in a whitelist"""

    def __init__(self, bot):
        self.bot = bot

    @command(name="only.add")
    async def add(
        self,
        ctx: Context,
        command: str,
        channel: TextChannel | None = None,
    ):
        """
        Add the given command to the Only whitelist

        Enables <command> in this channel.

        You may specify a channel other than the current one.

        Examples:
            !only.add test
            !only.add test #lobby
        """

        assert ctx.guild

        if not channel:
            channel = ctx.channel  # type: ignore
            assert channel

        chan_id = str(channel.id)
        guild = str(ctx.guild.id)

        if guild not in onlies:
            onlies[guild] = dict()

        ours = onlies[guild]

        if chan_id not in ours:
            ours[chan_id] = set([])

        ourchan = ours[chan_id]

        if command in ourchan:
            await ctx.send(":newspaper: Already done.")

            return

        ourchan.add(command)
        ours[chan_id] = ourchan
        onlies[guild] = ours
        log.info(f"{ctx.author} added {command} to {channel} whitelist")
        await ctx.send(":shield: Done.")

    @command(name="only.remove")
    async def remove(
        self,
        ctx: Context,
        command: str,
        channel: TextChannel | None = None,
    ):
        """
        Remove the given command from the Only whitelist

        If whitelisting is enabled for this channel, the removed command can no longer be executed.

        You may provide a channel other than the current one.

        Examples:
            !only.remove test
            !only.remove test #lobby
        """

        assert ctx.guild

        if not channel:
            channel = ctx.channel  # type: ignore
            assert channel

        chan_id = str(channel.id)
        guild = str(ctx.guild.id)
        ours = onlies[guild] if guild in onlies else {}
        ourchan = (
            ours[chan_id] if ours is not None and chan_id in ours else None
        )

        if ourchan is None:
            await ctx.send(":person_shrugging: None set.")

            return

        ourchan.remove(command)

        if len(ourchan) == 0:
            del ours[chan_id]
        else:
            ours[chan_id] = ourchan

        if len(ours) == 0:
            del onlies[guild]
        else:
            onlies[guild] = ours

        log.info(f"{ctx.author} removed {command} from {channel} whitelist")
        await ctx.send(":wastebasket: Removed.")

    @command(name="only.list")
    async def list(
        self,
        ctx: Context,
        channel: TextChannel | None = None,
    ):
        """
        List all current channel's whitelisted commands

        You may provide a channel other than the current one.

        Examples:
            !only.list
            !only.list #lobby
        """

        assert ctx.guild

        if not channel:
            channel = ctx.channel  # type: ignore
            assert channel

        chan_id = str(channel.id)
        guild = str(ctx.guild.id)

        if guild not in onlies:
            onlies[guild] = dict()

        ours = onlies[guild]

        if channel not in ours:
            ours[channel] = set([])

        output = "**, **".join(ours.get(chan_id, []))

        if not len(output):
            output = "None"

        log.info(f"{ctx.author} viewed command whitelist for {channel}")
        await ctx.send(f":guard: **{output}**")

    @command(name="only.reset")
    async def reset(
        self,
        ctx: Context,
        channel: TextChannel | None = None,
    ):
        """
        Reset Only whitelist

        Using this command will disable whitelisting behavior and remove the existing whitelist.

        You may provide a channel other than the current one.

        Examples:
            !only.reset
            !only.reset #lobby
        """

        assert ctx.guild

        if not channel:
            channel = ctx.channel  # type: ignore
            assert channel

        chan_id = str(channel.id)
        guild = str(ctx.guild.id)
        ours = onlies[guild] if guild in onlies else {}
        ourchan = (
            ours[chan_id] if ours is not None and chan_id in ours else None
        )

        if ourchan is None:
            await ctx.send(":person_shrugging: None set.")

            return

        del ours[chan_id]

        if len(ours) == 0:
            del onlies[guild]
        else:
            onlies[guild] = ours

        await ctx.send(":boom: Reset.")
        log.info(f"{ctx.author} reset Only whitelist for {channel}")

Ancestors

  • discord.ext.commands.cog.Cog

Class variables

var add
var list
var remove
var reset