Skip to content

System Cogs

These Cogs provide general system functionality and help features.

Architecture

classDiagram
    class HelpCog {
        +bot : Bot
        +help(interaction)
    }

    class HelpView {
        +selected_command : str
        +_build_content()
    }

    class ExamplesCog {
        +sample_data : list
        +colors(interaction)
        +pagination(interaction)
        +buttons(interaction)
    }

    class ButtonsView {
        +primary(interaction, button)
        +secondary(interaction, button)
        +setup()
    }

    HelpCog ..> HelpView : creates
    ExamplesCog ..> ButtonsView : creates
    ExamplesCog ..> PaginatedView : creates

Help System

The help command (/help) opens a dynamic view allowing users to browse different help topics. It fully supports Internationalization (i18n).

The topic list is built from COMMAND_TEXTS in src.util.translations, keyed by the real command name, and every entry has an answer behind it in HELP_ANSWERS. A test asserts that both dictionaries hold the same keys, so a command cannot be listed in the help without an explanation, and the help cannot advertise a command that does not exist.

The Help Cog

src.oscar.cogs.help.Help

Help(bot: Bot)

Bases: Cog

Class for the help cog.

Source code in src/oscar/cogs/help.py
def __init__(self, bot: commands.Bot):
    self.bot: commands.Bot = bot
    logger.info("Loaded Help cog")

contacts async

contacts(interaction: Interaction)

Command to display key contact persons at FIN and OVGU.

Source code in src/oscar/cogs/help.py
@app_commands.command(
    name=locale_str("contacts", de="ansprechpartner"),
    description=locale_str(
        "Key contacts at the FIN and the OVGU, with a link to their page",
        de="Wichtige Ansprechpartner der FIN und OVGU, mit Link zur Seite",
    ),
)
async def contacts(self, interaction: discord.Interaction):
    """ Command to display key contact persons at FIN and OVGU."""
    await open_contacts(interaction)

elearning async

elearning(interaction: Interaction)

Command to display guide on faculty learning management systems.

Source code in src/oscar/cogs/help.py
@app_commands.command(
    name=locale_str("elearning", de="lms"),
    description=locale_str(
        "The university portals: eLearning, LSF, module handbook, GitLab",
        de="Lernplattformen der OVGU: eLearning, LSF, Modulhandbuch, GitLab",
    ),
)
async def elearning(self, interaction: discord.Interaction):
    """Command to display guide on faculty learning management systems."""
    await open_platforms(interaction)

help async

help(interaction: Interaction)

Command to open the help dialog.

Source code in src/oscar/cogs/help.py
@app_commands.command(description="Hilfe zu allen Befehlen (help for every command)")
async def help(self, interaction: discord.Interaction):
    """ Command to open the help dialog."""
    # \/ important (makes the bot say its thinking)
    _ = await interaction.response.defer(
        ephemeral=True
    )

    # the help opened in english for everybody, whatever they had picked in /start
    language: LanguageCode = get_user_language(interaction.user.id)
    await interaction.followup.send(view=HelpView(language), ephemeral=True)

Module Setup

src.oscar.cogs.help.setup async

setup(bot: Bot)

Setup the Help cog.

Source code in src/oscar/cogs/help.py
async def setup(bot: commands.Bot):
    """ Setup the Help cog."""
    await bot.add_cog(Help(bot))

Help View

The view logic implementing the dropdown menu and language toggle.

src.oscar.cogs.help.HelpView

HelpView(default_language: LanguageCode = LanguageCode.EN)

Bases: TranslatedView

Help view that extends TranslatedView for language switching.

It answers two different kinds of question. "What does this command do" comes from COMMAND_TEXTS, "why does this not work" comes from FAQ_QUESTIONS. Both selects are shown at once, and picking in one clears the other, so exactly one answer is on screen.

Source code in src/oscar/cogs/help.py
def __init__(self, default_language: LanguageCode = LanguageCode.EN):
    # set before the base class builds the content, they are read while building
    self.selected_command: str | None = None
    self.selected_question: str | None = None
    self.opened: str | None = None
    super().__init__(default_language)

_build_content

_build_content()

Build the help view content with current language.

Source code in src/oscar/cogs/help.py
@override
def _build_content(self):
    """Build the help view content with current language."""
    _ = self.add_item(
        item=Container(
            Section[LayoutView](
                TextDisplay(f"# {HELP_LANGUAGES['help'][self.language_code]}"),
                accessory=self._create_language_toggle(),
            ),
            Separator(),
            ActionRow(self._open_select()),
            ActionRow(self._command_select()),
            ActionRow(self._faq_select()),
            Separator(),
            TextDisplay(self._answer()),
            accent_color=0x4378D5,
        ),
    )

Examples

A playground Cog (src.oscar.cogs.examples) useful for developers to test UI capabilities and copy-paste reference implementations.

Included Commands: * /colors: Displays all valid Discord ANSI color codes for embeds. * /pagination: Generates 64 sample items to test the PaginatedView navigation. * /buttons: Displays all button styles (Primary, Secondary, Success, Danger, Link, Premium).

src.oscar.cogs.examples.Examples

Examples(bot: Bot)

Bases: Cog

Cog Class holding various examples

Source code in src/oscar/cogs/examples.py
def __init__(self, bot: commands.Bot):
    self.bot: commands.Bot = bot
    logger.info("Loaded Examples cog")

    # Generate sample data (64 items as requested)
    self.sample_data: list[dict[str, int|str]] = []
    statuses = ["Active", "Inactive", "Pending", "Error"]

    for i in range(1, 65):  # Example 1 to 64
        self.sample_data.append({
            "id": i,
            "name": f"Example {i}",
            "value": f"Val_{i:03d}",
            "status": statuses[(i - 1) % len(statuses)]
        })

buttons async

buttons(interaction: Interaction, enabled: bool = True)

Slash command to display all possible discord embed button styles

Source code in src/oscar/cogs/examples.py
@app_commands.command(name = 'buttons',description = 'Display all possible button styles')
@app_commands.describe(enabled = 'Weather the buttons are enabled or disabled')
async def buttons(self, interaction: discord.Interaction, enabled:bool = True):
    """Slash command to display all possible discord embed button styles"""

    await ButtonsView(interaction=interaction, enabled=enabled).setup()

colors async

colors(interaction: Interaction)

Slash command to display all possible text and background colors

Source code in src/oscar/cogs/examples.py
    @app_commands.command(name='colors', description='display all text and background colors')
    async def colors(self, interaction: discord.Interaction):
        """Slash command to display all possible text and background colors"""

        embed: discord.Embed = discord.Embed(
            title='Text Colors',
            # pylint: disable=C0301 # (line-too-long)
            url='https://www.pythondiscord.com/pages/guides/python-guides/discord-messages-with-colors/',
            description="""
To be able to send a colored text, you need to use the ansi language for your code block and provide a prefix of this format before writing your text:
```
\\u001b[{format};{color}m
```
All possible formats are:
```ansi
• 0: \u001b[0;00mNormal\u001b[0m
• 1: \u001b[1;00mBold\u001b[0m
• 4: \u001b[4;00mUnderline\u001b[0m
```

All possible colors are:
```ansi
\u001b[1;30;40m Text \u001b[1;30;41m Text \u001b[1;30;42m Text \u001b[1;30;43m Text \u001b[1;30;44m Text \u001b[1;30;45m Text \u001b[1;30;46m Text \u001b[1;30;47m Text
\u001b[1;31;40m Text \u001b[1;31;41m Text \u001b[1;31;42m Text \u001b[1;31;43m Text \u001b[1;31;44m Text \u001b[1;31;45m Text \u001b[1;31;46m Text \u001b[1;31;47m Text
\u001b[1;32;40m Text \u001b[1;32;41m Text \u001b[1;32;42m Text \u001b[1;32;43m Text \u001b[1;32;44m Text \u001b[1;32;45m Text \u001b[1;32;46m Text \u001b[1;32;47m Text
\u001b[1;33;40m Text \u001b[1;33;41m Text \u001b[1;33;42m Text \u001b[1;33;43m Text \u001b[1;33;44m Text \u001b[1;33;45m Text \u001b[1;33;46m Text \u001b[1;33;47m Text
\u001b[1;34;40m Text \u001b[1;34;41m Text \u001b[1;34;42m Text \u001b[1;34;43m Text \u001b[1;34;44m Text \u001b[1;34;45m Text \u001b[1;34;46m Text \u001b[1;34;47m Text
\u001b[1;35;40m Text \u001b[1;35;41m Text \u001b[1;35;42m Text \u001b[1;35;43m Text \u001b[1;35;44m Text \u001b[1;35;45m Text \u001b[1;35;46m Text \u001b[1;35;47m Text
\u001b[1;36;40m Text \u001b[1;36;41m Text \u001b[1;36;42m Text \u001b[1;36;43m Text \u001b[1;36;44m Text \u001b[1;36;45m Text \u001b[1;36;46m Text \u001b[1;36;47m Text
\u001b[1;37;40m Text \u001b[1;37;41m Text \u001b[1;37;42m Text \u001b[1;37;43m Text \u001b[1;37;44m Text \u001b[1;37;45m Text \u001b[1;37;46m Text \u001b[1;37;47m Text
```
"""
        )

        _ =await interaction.response.send_message(embed=embed)

pagination async

pagination(interaction: Interaction)

Slash command to display paginated data

Source code in src/oscar/cogs/examples.py
@app_commands.command(
    name = 'pagination',
    description = 'Display paginated data with navigation buttons'
)
async def pagination(self, interaction: discord.Interaction):
    """Slash command to display paginated data"""

    await PaginatedView(
        interaction = interaction,
        total_pages = 4,
        get_page = get_pagination_embed
    ).setup()

Module Setup

Warning: This Cog is currently disabled in the code (commented out in setup).

src.oscar.cogs.examples.setup async

setup(bot: Bot)

Setup the Examples cog.

Source code in src/oscar/cogs/examples.py
async def setup(bot: commands.Bot):  # pylint: disable=unused-argument
    """ Setup the Examples cog."""

Local Helper Classes

Example implementations of UI elements used within the commands above.

src.oscar.cogs.examples.ButtonsView

ButtonsView(interaction: Interaction, enabled: bool = True)

Bases: View

Class for displaying each button type

Source code in src/oscar/cogs/examples.py
def __init__(self, interaction: discord.Interaction, enabled: bool = True):
    self.interaction: Interaction[Client] = interaction
    self.enabled: bool = enabled
    super().__init__(timeout=300)  # doesn't accept new interaction after <timeout> seconds

    link_button: Button[LayoutView] =     Button(
        emoji = '5️⃣',
        label = 'link / _url_',
        style = discord.ButtonStyle.link,
        url = 'https://github.com/combifightet',
        disabled=not self.enabled
    )
    _ = self.add_item(link_button)

    premium_button: Button[LayoutView] =     Button(
        style = discord.ButtonStyle.premium,
        sku_id = 1416080458093170820, # 'buy me a coffe'
        disabled = not self.enabled
    )
    _ = self.add_item(premium_button)
primary async
primary(_interaction: Interaction, _button: Button[LayoutView])

Empty example callback

Source code in src/oscar/cogs/examples.py
@discord.ui.button(
        emoji='1️⃣',
        label='primary / _blurple_',
        style=discord.ButtonStyle.primary
    )
async def primary(self, _interaction: discord.Interaction, _button: Button[LayoutView]):
    """ Empty example callback"""
secondary async
secondary(_interaction: Interaction, _button: Button[LayoutView])

Empty example callback

Source code in src/oscar/cogs/examples.py
@discord.ui.button(
        emoji='2️⃣',
        label='secondary / _grey_ /_gray_',
        style=discord.ButtonStyle.secondary)
async def secondary(self, _interaction: discord.Interaction, _button: Button[LayoutView]):
    """ Empty example callback"""
success async
success(_interaction: Interaction, _button: Button[LayoutView])

Empty example callback

Source code in src/oscar/cogs/examples.py
@discord.ui.button(
        emoji='3️⃣',
        label='success / _green_',
        style=discord.ButtonStyle.success
    )
async def success(self, _interaction: discord.Interaction, _button: Button[LayoutView]):
    """ Empty example callback"""
danger async
danger(_interaction: Interaction, _button: Button[LayoutView])

Empty example callback

Source code in src/oscar/cogs/examples.py
@discord.ui.button(
        emoji='4️⃣',
        label='danger / _red_',
        style=discord.ButtonStyle.danger
    )
async def danger(self, _interaction: discord.Interaction, _button: Button[LayoutView]):
    """ Empty example callback"""
setup async
setup()

Setup button states and embed

Source code in src/oscar/cogs/examples.py
async def setup(self):
    """ Setup button states and embed"""
    # Set the disabled state of all buttons after initialization
    for item in self.children:
        if isinstance(item, Button):
            item.disabled = not self.enabled

    embed:discord.Embed = discord.Embed(
        colour=0xac91b4,
        title='Buttons - Example',
        description='A small Embed to display all 6 different button types',
    )
    _ = embed.set_author(
        name='Combifightet',
        url='https://github.com/combifightet',
        icon_url='https://avatars.githubusercontent.com/u/47188809'
    )
    _ = await self.interaction.response.send_message(embed=embed, view=self)