From bc073363b9ffd514ed3cc0ed7f47bb519375c687 Mon Sep 17 00:00:00 2001 From: Interitio Date: Fri, 6 Sep 2024 10:59:13 +1000 Subject: [PATCH] feat: Start merged profiles and communities. --- data/schema.sql | 67 ++++++++++++++++ src/modules/profiles/__init__.py | 8 ++ src/modules/profiles/cog.py | 72 +++++++++++++++++ src/modules/profiles/data.py | 134 +++++++++++++++++++++++++++++++ 4 files changed, 281 insertions(+) create mode 100644 src/modules/profiles/__init__.py create mode 100644 src/modules/profiles/cog.py create mode 100644 src/modules/profiles/data.py diff --git a/data/schema.sql b/data/schema.sql index 504ae859..24fd294b 100644 --- a/data/schema.sql +++ b/data/schema.sql @@ -1485,6 +1485,73 @@ CREATE UNIQUE INDEX channel_tags_channelid_name ON channel_tags (channelid, name -- }}} +-- User and Community Profiles {{{ + +CREATE TABLE user_profiles( + profileid SERIAL PRIMARY KEY, + nickname TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE TABLE profiles_discord( + linkid SERIAL PRIMARY KEY, + profileid INTEGER NOT NULL REFERENCES user_profiles (profileid) ON DELETE CASCADE ON UPDATE CASCADE, + userid BIGINT NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); +CREATE UNIQUE INDEX profiles_discord_profileid ON profiles_discord (profileid); +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, + 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() +); + +CREATE TABLE communities_discord( + guildid BIGINT PRIMARY KEY, + communityid INTEGER NOT NULL REFERENCES communities (communityid) ON DELETE CASCADE ON UPDATE CASCADE, + linked_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); +CREATE UNIQUE INDEX communities_discord_communityid ON communities_discord (communityid); + +CREATE TABLE communities_twitch( + channelid BIGINT PRIMARY KEY, + communityid INTEGER NOT NULL REFERENCES communities (communityid) ON DELETE CASCADE ON UPDATE CASCADE, + linked_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); +CREATE UNIQUE INDEX communities_twitch_communityid ON communities_twitch (communityid); + +CREATE TABLE community_members( + memberid SERIAL PRIMARY KEY, + communityid INTEGER NOT NULL REFERENCES communities (communityud) 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); +-- }}} + +-- Twitch Auth {{ +CREATE TABLE twitch_tokens( + userid BIGINT PRIMARY KEY, + access_token TEXT NOT NULL, + expires_at TIMESTAMPTZ NOT NULL, + refresh_token TEXT NOT NULL, + obtained_at TIMESTAMPTZ +); +-- }} + + + + -- Analytics Data {{{ CREATE SCHEMA "analytics"; diff --git a/src/modules/profiles/__init__.py b/src/modules/profiles/__init__.py new file mode 100644 index 00000000..67decbfe --- /dev/null +++ b/src/modules/profiles/__init__.py @@ -0,0 +1,8 @@ +import logging + +logger = logging.getLogger(__name__) + +from .cog import ProfileCog + +async def setup(bot): + await bot.add_cog(ProfileCog(bot)) diff --git a/src/modules/profiles/cog.py b/src/modules/profiles/cog.py new file mode 100644 index 00000000..85beb3af --- /dev/null +++ b/src/modules/profiles/cog.py @@ -0,0 +1,72 @@ +import asyncio +from enum import Enum +from typing import Optional +from datetime import timedelta + +import discord +from discord.ext import commands as cmds +import twitchio +from twitchio.ext import commands + + +from data.queries import ORDER +from meta import LionCog, LionBot, CrocBot +from utils.lib import utc_now +from . import logger +from .data import ProfileData + + +class UserProfile: + def __init__(self): + ... + + +class ProfileCog(LionCog): + def __init__(self, bot: LionBot): + self.bot = bot + self.data = bot.db.load_registry(ProfileData()) + + async def cog_load(self): + await self.data.init() + + async def cog_check(self, ctx): + return True + + # Profile API + async def fetch_profile_discord(self, userid: int, create=True): + """ + Fetch or create a UserProfile from the given Discord userid. + """ + ... + + async def fetch_profile_twitch(self, userid: int, create=True): + """ + Fetch or create a UserProfile from the given Twitch userid. + """ + ... + + async def fetch_profile(self, profileid: int): + """ + Fetch a UserProfile by the given id. + """ + ... + + async def merge_profiles(self, sourceid: int, targetid: int): + """ + Merge two UserProfiles by id. + Merges the 'sourceid' into the 'targetid'. + """ + ... + + async def fetch_community_discord(self, guildid: int, create=True): + ... + + async def fetch_community_twitch(self, guildid: int, create=True): + ... + + async def fetch_community(self, communityid: int): + ... + + # ----- Profile Commands ----- + + # Link twitch profile diff --git a/src/modules/profiles/data.py b/src/modules/profiles/data.py new file mode 100644 index 00000000..f9af7e42 --- /dev/null +++ b/src/modules/profiles/data.py @@ -0,0 +1,134 @@ +from data import Registry, RowModel +from data.columns import Integer, String, Timestamp + + +class ProfileData(Registry): + class UserProfileRow(RowModel): + """ + Schema + ------ + CREATE TABLE user_profiles( + profileid SERIAL PRIMARY KEY, + nickname TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ); + """ + _tablename_ = 'user_profiles' + _cache_ = {} + + profileid = Integer(primary=True) + nickname = String() + created_at = Timestamp() + + class DiscordProfileRow(RowModel): + """ + Schema + ------ + CREATE TABLE profiles_discord( + linkid SERIAL PRIMARY KEY, + profileid INTEGER NOT NULL REFERENCES user_profiles (profileid) ON DELETE CASCADE ON UPDATE CASCADE, + userid BIGINT NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ); + CREATE UNIQUE INDEX profiles_discord_profileid ON profiles_discord (profileid); + CREATE INDEX profiles_discord_userid ON profiles_discord (userid); + """ + _tablename_ = 'profiles_discord' + _cache_ = {} + + linkid = Integer(primary=True) + profileid = Integer() + userid = Integer() + created_at = Integer() + + class TwitchProfileRow(RowModel): + """ + Schema + ------ + 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, + 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); + """ + _tablename_ = 'profiles_twitch' + _cache_ = {} + + linkid = Integer(primary=True) + profileid = Integer() + userid = Integer() + created_at = Timestamp() + + class CommunityRow(RowModel): + """ + Schema + ------ + CREATE TABLE communities( + communityid SERIAL PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ); + """ + _tablename_ = 'communities' + _cache_ = {} + + communityid = Integer(primary=True) + created_at = Timestamp() + + class DiscordCommunityRow(RowModel): + """ + Schema + ------ + CREATE TABLE communities_discord( + guildid BIGINT PRIMARY KEY, + communityid INTEGER NOT NULL REFERENCES communities (communityid) ON DELETE CASCADE ON UPDATE CASCADE, + linked_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ); + CREATE UNIQUE INDEX communities_discord_communityid ON communities_discord (communityid); + """ + _tablename_ = 'communities_discord' + _cache_ = {} + + guildid = Integer(primary=True) + communityid = Integer() + linked_at = Timestamp() + + class TwitchCommunityRow(RowModel): + """ + Schema + ------ + CREATE TABLE communities_twitch( + channelid BIGINT PRIMARY KEY, + communityid INTEGER NOT NULL REFERENCES communities (communityid) ON DELETE CASCADE ON UPDATE CASCADE, + linked_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ); + CREATE UNIQUE INDEX communities_twitch_communityid ON communities_twitch (communityid); + """ + _tablename_ = 'communities_twitch' + _cache_ = {} + + channelid = Integer(primary=True) + communityid = Integer() + linked_at = Timestamp() + + 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, + 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' + _cache_ = {} + + memberid = Integer(primary=True) + communityid = Integer() + profileid = Integer() + created_at = Timestamp()