rewrite (core): Refactor lion* classes.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
from .cog import CoreCog
|
||||
from .config import ConfigCog
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(CoreCog(bot))
|
||||
await bot.add_cog(ConfigCog(bot))
|
||||
|
||||
35
src/core/config.py
Normal file
35
src/core/config.py
Normal 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
|
||||
@@ -67,6 +67,7 @@ class CoreData(Registry, name="core"):
|
||||
CREATE TABLE user_config(
|
||||
userid BIGINT PRIMARY KEY,
|
||||
timezone TEXT,
|
||||
show_global_stats BOOLEAN,
|
||||
topgg_vote_reminder BOOLEAN,
|
||||
avatar_hash TEXT,
|
||||
name TEXT,
|
||||
@@ -84,6 +85,7 @@ class CoreData(Registry, name="core"):
|
||||
|
||||
userid = Integer(primary=True)
|
||||
timezone = String()
|
||||
show_global_stats = Bool()
|
||||
topgg_vote_reminder = Bool()
|
||||
avatar_hash = String()
|
||||
name = String()
|
||||
|
||||
85
src/core/lion_guild.py
Normal file
85
src/core/lion_guild.py
Normal 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
84
src/core/lion_member.py
Normal 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
71
src/core/lion_user.py
Normal 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
15
src/core/settings.py
Normal 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
|
||||
Reference in New Issue
Block a user