diff --git a/src/modules/statistics/cog.py b/src/modules/statistics/cog.py index 103c8ff6..492ac8a9 100644 --- a/src/modules/statistics/cog.py +++ b/src/modules/statistics/cog.py @@ -13,6 +13,7 @@ from utils.ui import LeoUI, AButton from . import babel from .data import StatsData from .ui import ProfileUI, WeeklyMonthlyUI +from .settings import StatsSettings _p = babel._p @@ -24,10 +25,13 @@ class StatsCog(LionCog): def __init__(self, bot: LionBot): self.bot = bot self.data = bot.db.load_registry(StatsData()) + self.settings = StatsSettings async def cog_load(self): await self.data.init() + self.bot.core.user_config.register_model_setting(self.settings.UserGlobalStats) + @cmds.hybrid_command( name=_p('cmd:me', "me"), description=_p( diff --git a/src/modules/statistics/data.py b/src/modules/statistics/data.py index e859d7d0..a486c86f 100644 --- a/src/modules/statistics/data.py +++ b/src/modules/statistics/data.py @@ -9,56 +9,6 @@ from utils.lib import utc_now class StatsData(Registry): - class PastSession(RowModel): - """ - Schema - ------ - CREATE TABLE session_history( - sessionid SERIAL PRIMARY KEY, - guildid BIGINT NOT NULL, - userid BIGINT NOT NULL, - channelid BIGINT, - channel_type SessionChannelType, - rating INTEGER, - tag TEXT, - start_time TIMESTAMPTZ NOT NULL, - duration INTEGER NOT NULL, - coins_earned INTEGER NOT NULL, - live_duration INTEGER DEFAULT 0, - stream_duration INTEGER DEFAULT 0, - video_duration INTEGER DEFAULT 0, - FOREIGN KEY (guildid, userid) REFERENCES members (guildid, userid) ON DELETE CASCADE - ); - CREATE INDEX session_history_members ON session_history (guildid, userid, start_time); - """ - _tablename_ = "session_history" - - class CurrentSession(RowModel): - """ - Schema - ------ - CREATE TABLE current_sessions( - guildid BIGINT NOT NULL, - userid BIGINT NOT NULL, - channelid BIGINT, - channel_type SessionChannelType, - rating INTEGER, - tag TEXT, - start_time TIMESTAMPTZ DEFAULT now(), - live_duration INTEGER DEFAULT 0, - live_start TIMESTAMPTZ, - stream_duration INTEGER DEFAULT 0, - stream_start TIMESTAMPTZ, - video_duration INTEGER DEFAULT 0, - video_start TIMESTAMPTZ, - hourly_coins INTEGER NOT NULL, - hourly_live_coins INTEGER NOT NULL, - FOREIGN KEY (guildid, userid) REFERENCES members (guildid, userid) ON DELETE CASCADE - ); - CREATE UNIQUE INDEX current_session_members ON current_sessions (guildid, userid); - """ - _tablename_ = "current_sessions" - class VoiceSessionStats(RowModel): """ View containing voice session statistics. @@ -92,7 +42,7 @@ class StatsData(Registry): @classmethod async def study_time_between(cls, guildid: int, userid: int, _start, _end) -> int: - conn = cls._connector.get_connection() + conn = await cls._connector.get_connection() async with conn.cursor() as cursor: await cursor.execute( "SELECT study_time_between(%s, %s, %s, %s)", @@ -130,7 +80,7 @@ class StatsData(Registry): @classmethod async def study_time_since(cls, guildid: int, userid: int, _start) -> int: - conn = cls._connector.get_connection() + conn = await cls._connector.get_connection() async with conn.cursor() as cursor: await cursor.execute( "SELECT study_time_since(%s, %s, %s)", diff --git a/src/modules/statistics/graphics/goals.py b/src/modules/statistics/graphics/goals.py index 48a9c7f7..2a309e41 100644 --- a/src/modules/statistics/graphics/goals.py +++ b/src/modules/statistics/graphics/goals.py @@ -15,7 +15,14 @@ async def get_goals_card( ): data: StatsData = bot.get_cog('StatsCog').data - lion = await bot.core.lions.fetch_member(guildid, userid) + if guildid: + lion = await bot.core.lions.fetch_member(guildid, userid) + user = await lion.fetch_member() + luser = lion.luser + else: + lion = luser = await bot.core.lions.fetch_user(userid) + user = await bot.fetch_user(userid) + today = lion.today # Calculate periodid and select the correct model @@ -25,14 +32,14 @@ async def get_goals_card( start = today - timedelta(days=today.weekday()) start, end = apply_week_offset(start, offset), apply_week_offset(start, offset - 1) periodid = extract_weekid(start) - key = {'guildid': guildid, 'userid': userid, 'weekid': periodid} + key = {'guildid': guildid or 0, 'userid': userid, 'weekid': periodid} else: goal_model = data.MonthlyGoals tasks_model = data.MonthlyTasks start = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0) start, end = apply_month_offset(start, offset), apply_month_offset(start, offset - 1) periodid = extract_monthid(start) - key = {'guildid': guildid, 'userid': userid, 'monthid': periodid} + key = {'guildid': guildid or 0, 'userid': userid, 'monthid': periodid} # Extract goals and tasks goals = await goal_model.fetch_or_create(*key.values()) @@ -63,12 +70,12 @@ async def get_goals_card( sessions_complete = 0.5 # Get member profile - if member := await lion.fetch_member(): - username = (member.display_name, member.discriminator) - avatar = member.avatar.key + if user: + username = (user.display_name, user.discriminator) + avatar = user.avatar.key else: username = (lion.data.display_name, '#????') - avatar = lion.user_data.avatar_hash + avatar = luser.data.avatar_hash # Getch badges badges = await data.ProfileTag.fetch_tags(guildid, userid) diff --git a/src/modules/statistics/graphics/monthly.py b/src/modules/statistics/graphics/monthly.py index f59e29f6..af06c948 100644 --- a/src/modules/statistics/graphics/monthly.py +++ b/src/modules/statistics/graphics/monthly.py @@ -14,7 +14,12 @@ from ..lib import apply_month_offset async def get_monthly_card(bot: LionBot, userid: int, guildid: int, offset: int, mode: CardMode) -> MonthlyStatsCard: data: StatsData = bot.get_cog('StatsCog').data - lion = await bot.core.lions.fetch_member(guildid, userid) + if guildid: + lion = await bot.core.lions.fetch_member(guildid, userid) + user = await lion.fetch_member() + else: + lion = await bot.core.lions.fetch_user(userid) + user = await bot.fetch_user(userid) today = lion.today month_start = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0) target = apply_month_offset(month_start, offset) @@ -77,8 +82,8 @@ async def get_monthly_card(bot: LionBot, userid: int, guildid: int, offset: int, monthly[i][day.day - 1] = stat / 3600 # Get member profile - if member := await lion.fetch_member(): - username = (member.display_name, member.discriminator) + if user: + username = (user.display_name, user.discriminator) else: username = (lion.data.display_name, '#????') diff --git a/src/modules/statistics/graphics/weekly.py b/src/modules/statistics/graphics/weekly.py index 75d02e2b..2ada7ce1 100644 --- a/src/modules/statistics/graphics/weekly.py +++ b/src/modules/statistics/graphics/weekly.py @@ -12,7 +12,12 @@ from ..data import StatsData async def get_weekly_card(bot: LionBot, userid: int, guildid: int, offset: int, mode: CardMode) -> WeeklyStatsCard: data: StatsData = bot.get_cog('StatsCog').data - lion = await bot.core.lions.fetch_member(guildid, userid) + if guildid: + lion = await bot.core.lions.fetch_member(guildid, userid) + user = await lion.fetch_member() + else: + lion = await bot.core.lions.fetch_user(userid) + user = await bot.fetch_user(userid) today = lion.today week_start = today - timedelta(days=today.weekday()) - timedelta(weeks=offset) days = [week_start + timedelta(i) for i in range(-7, 7 if offset else (today.weekday() + 1))] @@ -34,8 +39,8 @@ async def get_weekly_card(bot: LionBot, userid: int, guildid: int, offset: int, day_stats.append(0) # Get member profile - if member := await lion.fetch_member(): - username = (member.display_name, member.discriminator) + if user: + username = (user.display_name, user.discriminator) else: username = (lion.data.display_name, '#????') diff --git a/src/modules/statistics/settings.py b/src/modules/statistics/settings.py new file mode 100644 index 00000000..b8ac77d0 --- /dev/null +++ b/src/modules/statistics/settings.py @@ -0,0 +1,28 @@ +from settings import ModelData +from settings.setting_types import BoolSetting +from settings.groups import SettingGroup + +from core.data import CoreData + +from . import babel + +_p = babel._p + + +class StatsSettings(SettingGroup): + class UserGlobalStats(ModelData, BoolSetting): + """ + User setting, describing whether to display global statistics or not in servers. + + Exposed via a button on the `/stats` panel. + """ + setting_id = 'show_global_stats' + + _display_name = _p('userset:show_global_stats', "global_stats") + _desc = _p( + 'userset:show_global_stats', + "Whether statistics commands display combined stats for all servers or just your current server." + ) + + _model = CoreData.User + _column = CoreData.User.show_global_stats.name diff --git a/src/modules/statistics/ui/weeklymonthly.py b/src/modules/statistics/ui/weeklymonthly.py index 7520e925..58aa9490 100644 --- a/src/modules/statistics/ui/weeklymonthly.py +++ b/src/modules/statistics/ui/weeklymonthly.py @@ -693,6 +693,8 @@ class WeeklyMonthlyUI(StatsUI): await press.response.defer(thinking=True, ephemeral=True) self._showing_global = not self._showing_global # TODO: Asynchronously update user preferences + self._showing_global_setting.data = self._showing_global + await self._showing_global_setting.write() await self.refresh(thinking=press if not self._showing_global else None) @@ -702,7 +704,8 @@ class WeeklyMonthlyUI(StatsUI): colour=discord.Colour.orange(), description=t(_p( 'ui:WeeklyMonthly|button:global|resp:success', - "You will now see statistics from all you servers (where applicable)! Press again to revert." + "You will now see combined " + "statistics from all your servers (where applicable)! Press again to revert." )) ) await press.edit_original_response(embed=embed) @@ -843,6 +846,7 @@ class WeeklyMonthlyUI(StatsUI): """ Reload the UI data, applying cache where possible. """ + self._showing_global = self._showing_global_setting.value if self.guild else True await self.fetch_cards(*self.key) async def make_message(self) -> MessageArgs: @@ -858,9 +862,7 @@ class WeeklyMonthlyUI(StatsUI): Execute the UI using the given interaction. """ self._original = interaction - self._showing_global = False self.lion = await self.bot.core.lions.fetch_member(self.guildid, self.userid) - - # TODO: Switch to using data cache in reload to calculate global/local + self._showing_global_setting = self.lion.luser.config.get('show_global_stats') await self.refresh()