rewrite (core): Refactor lion* classes.

This commit is contained in:
2023-03-08 11:57:53 +02:00
parent cf7558d030
commit 65a34852a0
7 changed files with 294 additions and 0 deletions

View File

@@ -1,5 +1,7 @@
from .cog import CoreCog from .cog import CoreCog
from .config import ConfigCog
async def setup(bot): async def setup(bot):
await bot.add_cog(CoreCog(bot)) await bot.add_cog(CoreCog(bot))
await bot.add_cog(ConfigCog(bot))

35
src/core/config.py Normal file
View File

@@ -0,0 +1,35 @@
from discord import app_commands as appcmds
from discord.ext import commands as cmds
from meta import LionBot, LionContext, LionCog
from babel.translator import LocalBabel
babel = LocalBabel('core_config')
_p = babel._p
class ConfigCog(LionCog):
"""
Core guild config cog.
Primarily used to expose the `configure` base command group at a high level.
"""
def __init__(self, bot: LionBot):
self.bot = bot
async def cog_load(self):
...
async def cog_unload(self):
...
@cmds.hybrid_group(
name=_p('group:configure', "configure"),
)
@appcmds.guild_only
async def configure_group(self, ctx: LionContext):
"""
Bare command group, has no function.
"""
return

View File

@@ -67,6 +67,7 @@ class CoreData(Registry, name="core"):
CREATE TABLE user_config( CREATE TABLE user_config(
userid BIGINT PRIMARY KEY, userid BIGINT PRIMARY KEY,
timezone TEXT, timezone TEXT,
show_global_stats BOOLEAN,
topgg_vote_reminder BOOLEAN, topgg_vote_reminder BOOLEAN,
avatar_hash TEXT, avatar_hash TEXT,
name TEXT, name TEXT,
@@ -84,6 +85,7 @@ class CoreData(Registry, name="core"):
userid = Integer(primary=True) userid = Integer(primary=True)
timezone = String() timezone = String()
show_global_stats = Bool()
topgg_vote_reminder = Bool() topgg_vote_reminder = Bool()
avatar_hash = String() avatar_hash = String()
name = String() name = String()

85
src/core/lion_guild.py Normal file
View File

@@ -0,0 +1,85 @@
from typing import Optional, TYPE_CHECKING
from enum import Enum
import pytz
import discord
from meta import LionBot
from utils.lib import Timezoned
from settings.groups import ModelConfig, SettingDotDict
from .data import CoreData
if TYPE_CHECKING:
# TODO: Import Settings for Config type hinting
pass
class VoiceMode(Enum):
STUDY = 0
VOICE = 1
class GuildMode(Enum):
StudyGuild = (VoiceMode.STUDY,)
VoiceGuild = (VoiceMode.VOICE,)
TextGuild = (VoiceMode.VOICE,)
@property
def voice(self):
return self.value[0]
class GuildConfig(ModelConfig):
settings = SettingDotDict()
_model_settings = set()
model = CoreData.Guild
@property
def timezone(self):
return self.get('timezone')
class LionGuild(Timezoned):
"""
Represents a Guild in the LionBot paradigm.
Provides central access to cached data and configuration for a Guild.
No guarantee is made that the client is in the corresponding Guild,
or that the corresponding Guild even exists.
"""
__slots__ = ('bot', 'data', 'guildid', 'config', '_guild', '__weakref__')
Config = GuildConfig
settings = Config.settings
def __init__(self, bot: LionBot, data: CoreData.Guild, guild: Optional[discord.Guild] = None):
self.bot = bot
self.data = data
self.guildid = data.guildid
self._guild = guild
self.config = self.Config(self.guildid, data)
@property
def guild(self):
if self._guild is None:
self._guild = self.bot.get_guild(self.guildid)
return self._guild
@property
def guild_mode(self):
# TODO: Configuration, data, and settings for this...
return GuildMode.StudyGuild
@property
def timezone(self) -> pytz.timezone:
return self.config.timezone.value
async def touch_discord_model(self, guild: discord.Guild):
"""
Update saved Discord model attributes for this guild.
"""
if self.data.name != guild.name:
await self.data.update(name=guild.name)

84
src/core/lion_member.py Normal file
View File

@@ -0,0 +1,84 @@
from typing import Optional
import datetime as dt
import pytz
import discord
from meta import LionBot
from utils.lib import Timezoned
from settings.groups import ModelConfig, SettingDotDict
from .data import CoreData
from .lion_user import LionUser
from .lion_guild import LionGuild
class MemberConfig(ModelConfig):
settings = SettingDotDict()
_model_settings = set()
model = CoreData.Member
class LionMember(Timezoned):
"""
Represents a member in the LionBot paradigm.
Acts as a central interface to the member, user, and guild configurations.
No guarantee is made that any corresponding Discord objects are accessible (or exist).
"""
__slots__ = ('bot', 'data', 'userid', 'guildid', 'config', 'luser', 'lguild', '_member', '__weakref__')
Config = MemberConfig
settings = Config.settings
def __init__(
self,
bot: LionBot, data: CoreData.Member,
lguild: LionGuild, luser: LionUser,
member: Optional[discord.Member] = None
):
self.bot = bot
self.data = data
self.userid = data.userid
self.guildid = data.guildid
self.lguild = lguild
self.luser = luser
self._member = member
@property
def member(self):
"""
The associated Discord member, if accessible.
"""
if self._member is None:
if (guild := self.lguild.guild) is not None:
self._member = guild.get_member(self.userid)
return self._member
@property
def timezone(self) -> pytz.timezone:
user_timezone = self.luser.config.timezone
guild_timezone = self.lguild.config.timezone
return user_timezone.value if user_timezone._data is not None else guild_timezone.value
async def touch_discord_model(self, member: discord.Member):
"""
Update saved Discord model attributes for this member.
"""
if member.display_name != self.data.display_name:
await self.data.update(display_name=member.display_name)
async def fetch_member(self) -> Optional[discord.Member]:
"""
Fetches the associated member through the API. Respects cache.
"""
if (member := self.member) is None:
if (guild := self.lguild.guild) is not None:
try:
member = await guild.fetch_member(self.userid)
self._member = member
except discord.HTTPException:
pass
return member

71
src/core/lion_user.py Normal file
View File

@@ -0,0 +1,71 @@
from typing import Optional
import discord
import pytz
from meta import LionBot
from utils.lib import utc_now, Timezoned
from settings.groups import ModelConfig, SettingDotDict
from .data import CoreData
class UserConfig(ModelConfig):
settings = SettingDotDict()
_model_settings = set()
model = CoreData.User
@property
def timezone(self) -> pytz.timezone:
return self.get('timezone')
class LionUser(Timezoned):
"""
Represents a User in the LionBot paradigm.
Provides central access to cached data and configuration for a User.
No guarantee is made that the client has access to this User.
"""
__slots__ = ('bot', 'data', 'userid', '_user', 'config', '__weakref__')
Config = UserConfig
settings = Config.settings
def __init__(self, bot: LionBot, data: CoreData.User, user: Optional[discord.User] = None):
self.bot = bot
self.data = data
self.userid = data.userid
self._user = user
self.config = self.Config(self.userid, data)
@property
def user(self):
if self._user is None:
self._user = self.bot.get_user(self.userid)
return self._user
@property
def timezone(self) -> pytz.timezone:
return self.config.timezone.value
async def touch_discord_model(self, user: discord.User, seen=True):
"""
Updated stored Discord model attributes for this user.
"""
to_update = {}
avatar_key = user.avatar.key if user.avatar else None
if self.data.avatar_hash != avatar_key:
to_update['avatar_hash'] = avatar_key
if self.data.name != user.name:
to_update['name'] = user.name
if seen:
to_update['last_seen'] = utc_now()
if to_update:
await self.data.update(**to_update)

15
src/core/settings.py Normal file
View File

@@ -0,0 +1,15 @@
from settings.groups import ModelConfig, SettingDotDict
from .data import CoreData
class GuildConfig(ModelConfig):
settings = SettingDotDict()
_model_settings = set()
model = CoreData.Guild
class UserConfig(ModelConfig):
settings = SettingDotDict()
_model_settings = set()
model = CoreData.User