diff options
| author | 2022-10-07 21:49:38 +0100 | |
|---|---|---|
| committer | 2022-10-07 21:49:38 +0100 | |
| commit | fc4721411cc74b06df83a9d3e472de7d608d6945 (patch) | |
| tree | fefa8c07b5a25b853b78f8ebc9d6026283d9568e | |
| parent | Merge pull request #25 from python-discord/poetry-1.2 (diff) | |
| parent | Return error if no devops rule match searched indicies (diff) | |
Merge pull request #27 from python-discord/devops-rukes
| -rw-r--r-- | arthur/config.py | 5 | ||||
| -rw-r--r-- | arthur/exts/fun/devops_rules.py | 108 | 
2 files changed, 113 insertions, 0 deletions
diff --git a/arthur/config.py b/arthur/config.py index 1fcf11d..d754696 100644 --- a/arthur/config.py +++ b/arthur/config.py @@ -1,4 +1,6 @@  """Utilities for interacting with the config for King Arthur.""" +from typing import Optional +  from pydantic import BaseSettings @@ -20,6 +22,9 @@ class Config(BaseSettings):      # Guild id      guild_id: int = 267624335836053506 +    # Token for authorising with the Notion API +    notion_api_token: Optional[str] = None +      class Config:  # noqa: D106          env_file = ".env"          env_prefix = "KING_ARTHUR_" diff --git a/arthur/exts/fun/devops_rules.py b/arthur/exts/fun/devops_rules.py new file mode 100644 index 0000000..9c231d8 --- /dev/null +++ b/arthur/exts/fun/devops_rules.py @@ -0,0 +1,108 @@ +"""The rules all devops members must follow.""" + +from typing import TypedDict + +import discord +from discord.ext.commands import Cog, Context, Greedy, command + +from arthur.bot import KingArthur, logger +from arthur.config import CONFIG + +NOTION_API_BASE_URL = "https://api.notion.com/v1" +DEVOPS_RULES_PAGE_CONTENT = ( +    f"{NOTION_API_BASE_URL}/blocks/149bc48f-6f79-47af-add8-036f11d4e9a7/children" +) +DISCORD_MARKDOWN_LOOKUP = { +    "bold": "**{}**", +    "italic": "_{}_", +    "strikethrough": "~~{}~~", +    "underline": "__{}__", +} + + +class NotionAnnotations(TypedDict): +    """The markdown annotations attached to a block of text in Notion.""" + +    bold: bool +    italic: bool +    strikethrough: bool +    underline: bool + + +class NotionRichText(TypedDict): +    """A block of text with markdown annotations attached.""" + +    plain_text: str +    annotations: NotionAnnotations + + +def notion_block_to_discord_markdown(block: list[NotionRichText]) -> str: +    """Convert the given notion API "block" into Discord markdown text.""" +    block_string_parts = [] +    for rich_text_part in block: +        block_string_part = rich_text_part["plain_text"] +        for annotation, enabled in rich_text_part["annotations"].items(): +            if enabled and annotation in DISCORD_MARKDOWN_LOOKUP: +                block_string_part = DISCORD_MARKDOWN_LOOKUP[annotation].format(block_string_part) +        block_string_parts.append(block_string_part) +    return "".join(block_string_parts) + + +class Rules(Cog): +    """The rules all devops members must follow.""" + +    def __init__(self, bot: KingArthur) -> None: +        self.bot = bot +        self.rules: dict + +    async def cog_load(self) -> None: +        """Fetch Devops rules from notion of cog load.""" +        headers = { +            "Authorization": f"Bearer {CONFIG.notion_api_token}", +            "accept": "application/json", +            "Notion-Version": "2022-06-28", +        } +        async with self.bot.http_session.get(DEVOPS_RULES_PAGE_CONTENT, headers=headers) as resp: +            resp.raise_for_status() +            page_content = await resp.json() + +        self.rules = { +            i: notion_block_to_discord_markdown(block["numbered_list_item"]["rich_text"]) +            for i, block in enumerate(page_content["results"], 1) +            if block.get("type") == "numbered_list_item" +        } + +    @command(name="rules", aliases=("rule",)) +    async def get_rules(self, ctx: Context, rules: Greedy[int]) -> None: +        """List the requested rule(s), or all of them if not defined.""" +        if rules: +            output_rules = set(rules) & set(self.rules.keys()) +        else: +            output_rules = self.rules.keys() + +        if not output_rules: +            await ctx.send(f":x: Rule{'s'[:len(rules)^1]} not found.") +            return + +        output = "\n".join( +            f"{key}: {value}" +            for key, value in self.rules.items() +            if key in output_rules +        ) +        await ctx.send(embed=discord.Embed( +            title=f"Rule{'s'[:len(output_rules)^1]}", +            description=output, +            colour=discord.Colour.og_blurple(), +            url="https://www.notion.so/pythondiscord/Rules-149bc48f6f7947afadd8036f11d4e9a7", +        )) + + +async def setup(bot: KingArthur) -> None: +    """Add cog to bot.""" +    if not CONFIG.notion_api_token: +        logger.info( +            f"Not loading {__name__} as env var " +            f"{CONFIG.Config.env_prefix}NOTION_API_TOKEN is not set." +        ) +        return +    await bot.add_cog(Rules(bot))  |