rewrite (core): Refactor lion* classes.
This commit is contained in:
@@ -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
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(
|
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
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