Refactor with registry.

This commit is contained in:
2025-09-03 23:43:12 +10:00
parent 26f29e6de7
commit fda6847671
7 changed files with 127 additions and 49 deletions

View File

@@ -0,0 +1 @@
from .koans import *

View File

@@ -0,0 +1,20 @@
BEGIN;
-- Koan data {{{
INSERT INTO version_history (component, from_version, to_version, author)
VALUES ('KOANS', 0, 1, 'Initial Creation');
---- !koans lists koans. !koan gives a random koan. !koans add name ... !koans del name ...
CREATE TABLE koans(
koanid INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
communityid INTEGER NOT NULL REFERENCES communities ON UPDATE CASCADE ON DELETE CASCADE,
name TEXT NOT NULL,
message TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
_timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TRIGGER koans_timestamp BEFORE UPDATE ON koans
FOR EACH ROW EXECUTE FUNCTION update_timestamp_column();
-- }}}
COMMIT;

View File

@@ -2,6 +2,4 @@ import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
async def setup(bot): from .twitch import setup as twitch_setup
from .component import KoanComponent
await bot.add_component(KoanComponent(bot))

View File

@@ -0,0 +1,32 @@
from data import Registry, RowModel
from data.columns import String, Timestamp, Integer
class Koan(RowModel):
"""
Schema
======
CREATE TABLE koans(
koanid INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
communityid INTEGER NOT NULL REFERENCES communities ON UPDATE CASCADE ON DELETE CASCADE,
name TEXT NOT NULL,
message TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
_timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
"""
_tablename_ = 'koans'
_cache_ = {}
koanid = Integer(primary=True)
communityid = Integer()
name = String()
message = String()
created_at = Timestamp()
_timestamp = Timestamp()
class KoanData(Registry):
VERSION = ('KOANS', 1)
koans = Koan.table

View File

@@ -0,0 +1,34 @@
from typing import Optional
from .data import Koan, KoanData
class KoanRegistry:
def __init__(self, data: KoanData):
self.data = data
async def init(self):
await self.data.init()
async def get_community_koans(self, communityid: int) -> list[Koan]:
return await Koan.fetch_where(communityid=communityid)
async def get_koan(self, koanid: int) -> Optional[Koan]:
return await Koan.fetch(koanid)
async def get_koan_named(self, communityid: int, name: str) -> Optional[Koan]:
name = name.lower()
koans = await Koan.fetch_where(communityid=communityid, name=name)
if koans:
return koans[0]
else:
return None
async def create_koan(self, communityid: int, name: str, message: str) -> Koan:
name = name.lower()
await Koan.table.delete_where(communityid=communityid, name=name)
koan = await Koan.create(
communityid=communityid,
name=name,
message=message
)
return koan

5
koans/twitch/__init__.py Normal file
View File

@@ -0,0 +1,5 @@
from .. import logger
async def setup(bot):
from .component import KoanComponent
await bot.add_component(KoanComponent(bot))

View File

@@ -3,14 +3,23 @@ import random
import twitchio import twitchio
from twitchio.ext import commands as cmds from twitchio.ext import commands as cmds
from datamodels import Koan, Communities from meta import Bot, Context
from . import logger from . import logger
from ..koans import KoanRegistry
from ..data import KoanData
class KoanComponent(cmds.Component): class KoanComponent(cmds.Component):
def __init__(self, bot): def __init__(self, bot: Bot):
self.bot = bot self.bot = bot
self.data = bot.dbconn.load_registry(KoanData())
self.koans = KoanRegistry(self.data)
async def component_load(self):
await self.data.init()
await self.bot.version_check(*self.data.VERSION)
await self.koans.init()
@cmds.Component.listener() @cmds.Component.listener()
async def event_message(self, payload: twitchio.ChatMessage) -> None: async def event_message(self, payload: twitchio.ChatMessage) -> None:
@@ -23,10 +32,11 @@ class KoanComponent(cmds.Component):
!koans !koans
""" """
community = await Communities.fetch_or_create(twitchid=ctx.channel.id, name=ctx.channel.name) community = await self.bot.profiles.fetch_community(ctx.broadcaster)
cid = community.communityid cid = community.communityid
koans = await Koan.fetch_where(communityid=cid) koans = await self.koans.get_community_koans(cid)
if koans: if koans:
names = ', '.join(koan.name for koan in koans) names = ', '.join(koan.name for koan in koans)
await ctx.reply( await ctx.reply(
@@ -36,58 +46,40 @@ class KoanComponent(cmds.Component):
await ctx.reply("No koans have been made in this channel!") await ctx.reply("No koans have been made in this channel!")
@koans.command(name='add', aliases=['new', 'create']) @koans.command(name='add', aliases=['new', 'create'])
@cmds.is_moderator()
async def koans_add(self, ctx: cmds.Context, name: str, *, text: str): async def koans_add(self, ctx: cmds.Context, name: str, *, text: str):
""" """
Add or overwrite a koan to this channel. Add or overwrite a koan to this channel.
!koans add wind This is a wind koan !koans add wind This is a wind koan
""" """
community = await Communities.fetch_or_create(twitchid=ctx.channel.id, name=ctx.channel.name) community = await self.bot.profiles.fetch_community(ctx.broadcaster)
cid = community.communityid cid = community.communityid
name = name.lower() name = name.lower()
existing = await self.koans.get_koan_named(cid, name)
await self.koans.create_koan(cid, name, text)
assert isinstance(ctx.author, twitchio.Chatter)
if (ctx.author.moderator or ctx.author.broadcaster):
# Delete the koan with this name if it exists
existing = await Koan.table.delete_where(
communityid=cid,
name=name,
)
# Insert the new koan
await Koan.create(
communityid=cid,
name=name,
message=text
)
# Ack
if existing: if existing:
await ctx.reply(f"Updated the koan '{name}'") await ctx.reply(f"Updated the koan '{name}'")
else: else:
await ctx.reply(f"Created the new koan '{name}'") await ctx.reply(f"Created the new koan '{name}'")
@koans.command(name='del', aliases=['delete', 'rm', 'remove']) @koans.command(name='del', aliases=['delete', 'rm', 'remove'])
@cmds.is_moderator()
async def koans_del(self, ctx: cmds.Context, name: str): async def koans_del(self, ctx: cmds.Context, name: str):
""" """
Remove a koan from this channel by name. Remove a koan from this channel by name.
!koans del wind !koans del wind
""" """
community = await Communities.fetch_or_create(twitchid=ctx.channel.id, name=ctx.channel.name) community = await self.bot.profiles.fetch_community(ctx.broadcaster)
cid = community.communityid cid = community.communityid
name = name.lower() name = name.lower()
koan = await self.koans.get_koan_named(cid, name)
assert isinstance(ctx.author, twitchio.Chatter) if koan:
if (ctx.author.moderator or ctx.author.broadcaster): await koan.delete()
# Delete the koan with this name if it exists
existing = await Koan.table.delete_where(
communityid=cid,
name=name,
)
if existing:
await ctx.reply(f"Deleted the koan '{name}'") await ctx.reply(f"Deleted the koan '{name}'")
else: else:
await ctx.reply(f"The koan '{name}' does not exist to delete!") await ctx.reply(f"The koan '{name}' does not exist to delete!")
@@ -100,22 +92,18 @@ class KoanComponent(cmds.Component):
!koan !koan
!koan wind !koan wind
""" """
community = await Communities.fetch_or_create(twitchid=ctx.channel.id, name=ctx.channel.name) community = await self.bot.profiles.fetch_community(ctx.broadcaster)
cid = community.communityid cid = community.communityid
if name is not None: if name is not None:
name = name.lower() name = name.lower()
koans = await Koan.fetch_where( koan = await self.koans.get_koan_named(cid, name)
communityid=cid, if koan:
name=name
)
if koans:
koan = koans[0]
await ctx.reply(koan.message) await ctx.reply(koan.message)
else: else:
await ctx.reply(f"The requested koan '{name}' does not exist! Use '{ctx.prefix}koans' to see all the koans.") await ctx.reply(f"The requested koan '{name}' does not exist! Use '{ctx.prefix}koans' to see all the koans.")
else: else:
koans = await Koan.fetch_where(communityid=cid) koans = await self.koan.get_community_koans(communityid=cid)
if koans: if koans:
koan = random.choice(koans) koan = random.choice(koans)
await ctx.reply(koan.message) await ctx.reply(koan.message)