aboutsummaryrefslogtreecommitdiffstats
path: root/arthur/exts/fun/devops_rules.py
blob: 24c41f276080af862948bb6a90956faba018a930 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
"""The rules all devops members must follow."""

from typing import TypedDict

import discord
from discord.ext.commands import Cog, Context, Greedy, group

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"
        }

    @group(name="rules", aliases=("rule",))
    async def rules_group(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",
        ))

    @rules_group.command(name="refresh", aliases=("fetch", "update"))
    async def update_rules(self, ctx: Context) -> None:
        """Re-fetch the list of rules from notion."""
        await self.cog_load()


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))