From 4716123f6bfd2af7ade27115e906c26cf6ce5208 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Fri, 7 Oct 2022 13:54:54 +0100 Subject: Add devops rules command --- arthur/exts/fun/devops_rules.py | 94 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 arthur/exts/fun/devops_rules.py (limited to 'arthur/exts/fun/devops_rules.py') diff --git a/arthur/exts/fun/devops_rules.py b/arthur/exts/fun/devops_rules.py new file mode 100644 index 0000000..47d1720 --- /dev/null +++ b/arthur/exts/fun/devops_rules.py @@ -0,0 +1,94 @@ +"""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 +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.""" + output_rules = set(rules) or self.rules.keys() + 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.""" + await bot.add_cog(Rules(bot)) -- cgit v1.2.3 From d475961e051751c3b2d0dd9efdded86093a895c4 Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Fri, 7 Oct 2022 21:04:41 +0100 Subject: Don't load devops rules if notion api key isn't set --- arthur/config.py | 4 +++- arthur/exts/fun/devops_rules.py | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'arthur/exts/fun/devops_rules.py') diff --git a/arthur/config.py b/arthur/config.py index 77748ec..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 @@ -21,7 +23,7 @@ class Config(BaseSettings): guild_id: int = 267624335836053506 # Token for authorising with the Notion API - notion_api_token: str + notion_api_token: Optional[str] = None class Config: # noqa: D106 env_file = ".env" diff --git a/arthur/exts/fun/devops_rules.py b/arthur/exts/fun/devops_rules.py index 47d1720..e6be444 100644 --- a/arthur/exts/fun/devops_rules.py +++ b/arthur/exts/fun/devops_rules.py @@ -5,7 +5,7 @@ from typing import TypedDict import discord from discord.ext.commands import Cog, Context, Greedy, command -from arthur.bot import KingArthur +from arthur.bot import KingArthur, logger from arthur.config import CONFIG NOTION_API_BASE_URL = "https://api.notion.com/v1" @@ -91,4 +91,10 @@ class Rules(Cog): 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)) -- cgit v1.2.3 From 68ec38d62b420dd9701469fff316fd8d4eec9fff Mon Sep 17 00:00:00 2001 From: Chris Lovering Date: Fri, 7 Oct 2022 21:48:33 +0100 Subject: Return error if no devops rule match searched indicies --- arthur/exts/fun/devops_rules.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'arthur/exts/fun/devops_rules.py') diff --git a/arthur/exts/fun/devops_rules.py b/arthur/exts/fun/devops_rules.py index e6be444..9c231d8 100644 --- a/arthur/exts/fun/devops_rules.py +++ b/arthur/exts/fun/devops_rules.py @@ -75,7 +75,15 @@ class Rules(Cog): @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.""" - output_rules = set(rules) or self.rules.keys() + 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() -- cgit v1.2.3