From 9d0d19d046c889f3de97fa645c6cd73231566b1c Mon Sep 17 00:00:00 2001 From: Interitio Date: Thu, 26 Sep 2024 21:22:42 +1000 Subject: [PATCH] (profiles): Start internal API. --- data/schema.sql | 9 +++--- src/modules/profiles/cog.py | 53 ++++++++++++++++++++++++++++++++++-- src/modules/profiles/data.py | 33 ++++++++++++++++++---- 3 files changed, 83 insertions(+), 12 deletions(-) diff --git a/data/schema.sql b/data/schema.sql index 535389b1..87cf829b 100644 --- a/data/schema.sql +++ b/data/schema.sql @@ -1505,12 +1505,13 @@ CREATE INDEX profiles_discord_userid ON profiles_discord (userid); CREATE TABLE profiles_twitch( linkid SERIAL PRIMARY KEY, profileid INTEGER NOT NULL REFERENCES user_profiles (profileid) ON DELETE CASCADE ON UPDATE CASCADE, - userid BIGINT NOT NULL, + userid TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE UNIQUE INDEX profiles_twitch_profileid ON profiles_twitch (profileid); CREATE INDEX profiles_twitch_userid ON profiles_twitch (userid); + CREATE TABLE communities( communityid SERIAL PRIMARY KEY, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() @@ -1524,7 +1525,7 @@ CREATE TABLE communities_discord( CREATE UNIQUE INDEX communities_discord_communityid ON communities_discord (communityid); CREATE TABLE communities_twitch( - channelid BIGINT PRIMARY KEY, + channelid TEXT PRIMARY KEY, communityid INTEGER NOT NULL REFERENCES communities (communityid) ON DELETE CASCADE ON UPDATE CASCADE, linked_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); @@ -1532,10 +1533,10 @@ CREATE UNIQUE INDEX communities_twitch_communityid ON communities_twitch (commun CREATE TABLE community_members( memberid SERIAL PRIMARY KEY, - communityid INTEGER NOT NULL REFERENCES communities (communityud) ON DELETE CASCADE ON UPDATE CASCADE, + communityid INTEGER NOT NULL REFERENCES communities (communityid) ON DELETE CASCADE ON UPDATE CASCADE, profileid INTEGER NOT NULL REFERENCES user_profiles (profileid) ON DELETE CASCADE ON UPDATE CASCADE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() -) +); CREATE UNIQUE INDEX community_members_communityid_profileid ON community_members (communityid, profileid); -- }}} diff --git a/src/modules/profiles/cog.py b/src/modules/profiles/cog.py index 85beb3af..ed2eb756 100644 --- a/src/modules/profiles/cog.py +++ b/src/modules/profiles/cog.py @@ -7,6 +7,7 @@ import discord from discord.ext import commands as cmds import twitchio from twitchio.ext import commands +from twitchAPI.object.api import TwitchUser from data.queries import ORDER @@ -17,9 +18,53 @@ from .data import ProfileData class UserProfile: - def __init__(self): + def __init__(self, data, profile_row, *, discord_row=None, twitch_row=None): + self.data: ProfileData = data + self.profile_row: ProfileData.UserProfileRow = profile_row + + self.discord_row: Optional[ProfileData.DiscordProfileRow] = discord_row + self.twitch_row: Optional[ProfileData.TwitchProfileRow] = twitch_row + + @property + def profileid(self): + return self.profile_row.profileid + + async def attach_discord(self, user: discord.User | discord.Member): + """ + Attach a new discord user to this profile. + """ + # TODO: Attach whatever other data we want to cache here. + # Currently Lion also caches most of this data + discord_row = await self.data.DiscordProfileRow.create( + profileid=self.profileid, + userid=user.id + ) + + async def attach_twitch(self, user: TwitchUser): + """ + Attach a new Twitch user to this profile. + """ ... + @classmethod + async def fetch_profile( + cls, data: ProfileData, + *, + profile_id: Optional[int] = None, + profile_row: Optional[ProfileData.UserProfileRow] = None, + discord_row: Optional[ProfileData.DiscordProfileRow] = None, + twitch_row: Optional[ProfileData.TwitchProfileRow] = None, + ): + if not any((profile_id, profile_row, discord_row, twitch_row)): + raise ValueError("UserProfile needs an id or a data row to construct.") + if profile_id is None: + profile_id = (profile_row or discord_row or twitch_row).profileid + profile_row = profile_row or await data.UserProfileRow.fetch(profile_id) + discord_row = discord_row or await data.DiscordProfileRow.fetch_profile(profile_id) + twitch_row = twitch_row or await data.TwitchProfileRow.fetch_profile(profile_id) + + return cls(data, profile_row, discord_row=discord_row, twitch_row=twitch_row) + class ProfileCog(LionCog): def __init__(self, bot: LionBot): @@ -37,7 +82,11 @@ class ProfileCog(LionCog): """ Fetch or create a UserProfile from the given Discord userid. """ - ... + # TODO: (Extension) May be context dependent + # Current model assumes profile (one->0..n) discord + discord_row = next(await self.data.DiscordProfileRow.fetch_where(userid=userid), None) + if discord_row is None: + profile_row = await self.data.UserProfileRow.create() async def fetch_profile_twitch(self, userid: int, create=True): """ diff --git a/src/modules/profiles/data.py b/src/modules/profiles/data.py index f9af7e42..dc85eb1e 100644 --- a/src/modules/profiles/data.py +++ b/src/modules/profiles/data.py @@ -41,6 +41,12 @@ class ProfileData(Registry): userid = Integer() created_at = Integer() + @classmethod + async def fetch_profile(cls, profileid: int): + rows = await cls.fetch_where(profiled=profileid) + return next(rows, None) + + class TwitchProfileRow(RowModel): """ Schema @@ -48,7 +54,7 @@ class ProfileData(Registry): CREATE TABLE profiles_twitch( linkid SERIAL PRIMARY KEY, profileid INTEGER NOT NULL REFERENCES user_profiles (profileid) ON DELETE CASCADE ON UPDATE CASCADE, - userid BIGINT NOT NULL, + userid TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE UNIQUE INDEX profiles_twitch_profileid ON profiles_twitch (profileid); @@ -59,9 +65,14 @@ class ProfileData(Registry): linkid = Integer(primary=True) profileid = Integer() - userid = Integer() + userid = String() created_at = Timestamp() + @classmethod + async def fetch_profile(cls, profileid: int): + rows = await cls.fetch_where(profiled=profileid) + return next(rows, None) + class CommunityRow(RowModel): """ Schema @@ -95,12 +106,17 @@ class ProfileData(Registry): communityid = Integer() linked_at = Timestamp() + @classmethod + async def fetch_community(cls, communityid: int): + rows = await cls.fetch_where(communityd=communityid) + return next(rows, None) + class TwitchCommunityRow(RowModel): """ Schema ------ CREATE TABLE communities_twitch( - channelid BIGINT PRIMARY KEY, + channelid TEXT PRIMARY KEY, communityid INTEGER NOT NULL REFERENCES communities (communityid) ON DELETE CASCADE ON UPDATE CASCADE, linked_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); @@ -109,20 +125,25 @@ class ProfileData(Registry): _tablename_ = 'communities_twitch' _cache_ = {} - channelid = Integer(primary=True) + channelid = String(primary=True) communityid = Integer() linked_at = Timestamp() + @classmethod + async def fetch_community(cls, communityid: int): + rows = await cls.fetch_where(communityd=communityid) + return next(rows, None) + class CommunityMemberRow(RowModel): """ Schema ------ CREATE TABLE community_members( memberid SERIAL PRIMARY KEY, - communityid INTEGER NOT NULL REFERENCES communities (communityud) ON DELETE CASCADE ON UPDATE CASCADE, + communityid INTEGER NOT NULL REFERENCES communities (communityid) ON DELETE CASCADE ON UPDATE CASCADE, profileid INTEGER NOT NULL REFERENCES user_profiles (profileid) ON DELETE CASCADE ON UPDATE CASCADE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() - ) + ); CREATE UNIQUE INDEX community_members_communityid_profileid ON community_members (communityid, profileid); """ _tablename_ = 'community_members'