rewrite(statistics): Minor statistics refactor.

This commit is contained in:
2023-03-08 11:55:36 +02:00
parent aa174d8a1d
commit 42b68e8913
7 changed files with 70 additions and 69 deletions

View File

@@ -13,6 +13,7 @@ from utils.ui import LeoUI, AButton
from . import babel from . import babel
from .data import StatsData from .data import StatsData
from .ui import ProfileUI, WeeklyMonthlyUI from .ui import ProfileUI, WeeklyMonthlyUI
from .settings import StatsSettings
_p = babel._p _p = babel._p
@@ -24,10 +25,13 @@ class StatsCog(LionCog):
def __init__(self, bot: LionBot): def __init__(self, bot: LionBot):
self.bot = bot self.bot = bot
self.data = bot.db.load_registry(StatsData()) self.data = bot.db.load_registry(StatsData())
self.settings = StatsSettings
async def cog_load(self): async def cog_load(self):
await self.data.init() await self.data.init()
self.bot.core.user_config.register_model_setting(self.settings.UserGlobalStats)
@cmds.hybrid_command( @cmds.hybrid_command(
name=_p('cmd:me', "me"), name=_p('cmd:me', "me"),
description=_p( description=_p(

View File

@@ -9,56 +9,6 @@ from utils.lib import utc_now
class StatsData(Registry): 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): class VoiceSessionStats(RowModel):
""" """
View containing voice session statistics. View containing voice session statistics.
@@ -92,7 +42,7 @@ class StatsData(Registry):
@classmethod @classmethod
async def study_time_between(cls, guildid: int, userid: int, _start, _end) -> int: 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: async with conn.cursor() as cursor:
await cursor.execute( await cursor.execute(
"SELECT study_time_between(%s, %s, %s, %s)", "SELECT study_time_between(%s, %s, %s, %s)",
@@ -130,7 +80,7 @@ class StatsData(Registry):
@classmethod @classmethod
async def study_time_since(cls, guildid: int, userid: int, _start) -> int: 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: async with conn.cursor() as cursor:
await cursor.execute( await cursor.execute(
"SELECT study_time_since(%s, %s, %s)", "SELECT study_time_since(%s, %s, %s)",

View File

@@ -15,7 +15,14 @@ async def get_goals_card(
): ):
data: StatsData = bot.get_cog('StatsCog').data data: StatsData = bot.get_cog('StatsCog').data
if guildid:
lion = await bot.core.lions.fetch_member(guildid, userid) 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 today = lion.today
# Calculate periodid and select the correct model # Calculate periodid and select the correct model
@@ -25,14 +32,14 @@ async def get_goals_card(
start = today - timedelta(days=today.weekday()) start = today - timedelta(days=today.weekday())
start, end = apply_week_offset(start, offset), apply_week_offset(start, offset - 1) start, end = apply_week_offset(start, offset), apply_week_offset(start, offset - 1)
periodid = extract_weekid(start) periodid = extract_weekid(start)
key = {'guildid': guildid, 'userid': userid, 'weekid': periodid} key = {'guildid': guildid or 0, 'userid': userid, 'weekid': periodid}
else: else:
goal_model = data.MonthlyGoals goal_model = data.MonthlyGoals
tasks_model = data.MonthlyTasks tasks_model = data.MonthlyTasks
start = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0) 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) start, end = apply_month_offset(start, offset), apply_month_offset(start, offset - 1)
periodid = extract_monthid(start) periodid = extract_monthid(start)
key = {'guildid': guildid, 'userid': userid, 'monthid': periodid} key = {'guildid': guildid or 0, 'userid': userid, 'monthid': periodid}
# Extract goals and tasks # Extract goals and tasks
goals = await goal_model.fetch_or_create(*key.values()) goals = await goal_model.fetch_or_create(*key.values())
@@ -63,12 +70,12 @@ async def get_goals_card(
sessions_complete = 0.5 sessions_complete = 0.5
# Get member profile # Get member profile
if member := await lion.fetch_member(): if user:
username = (member.display_name, member.discriminator) username = (user.display_name, user.discriminator)
avatar = member.avatar.key avatar = user.avatar.key
else: else:
username = (lion.data.display_name, '#????') username = (lion.data.display_name, '#????')
avatar = lion.user_data.avatar_hash avatar = luser.data.avatar_hash
# Getch badges # Getch badges
badges = await data.ProfileTag.fetch_tags(guildid, userid) badges = await data.ProfileTag.fetch_tags(guildid, userid)

View File

@@ -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: async def get_monthly_card(bot: LionBot, userid: int, guildid: int, offset: int, mode: CardMode) -> MonthlyStatsCard:
data: StatsData = bot.get_cog('StatsCog').data data: StatsData = bot.get_cog('StatsCog').data
if guildid:
lion = await bot.core.lions.fetch_member(guildid, userid) 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 today = lion.today
month_start = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0) month_start = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
target = apply_month_offset(month_start, offset) 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 monthly[i][day.day - 1] = stat / 3600
# Get member profile # Get member profile
if member := await lion.fetch_member(): if user:
username = (member.display_name, member.discriminator) username = (user.display_name, user.discriminator)
else: else:
username = (lion.data.display_name, '#????') username = (lion.data.display_name, '#????')

View File

@@ -12,7 +12,12 @@ from ..data import StatsData
async def get_weekly_card(bot: LionBot, userid: int, guildid: int, offset: int, mode: CardMode) -> WeeklyStatsCard: async def get_weekly_card(bot: LionBot, userid: int, guildid: int, offset: int, mode: CardMode) -> WeeklyStatsCard:
data: StatsData = bot.get_cog('StatsCog').data data: StatsData = bot.get_cog('StatsCog').data
if guildid:
lion = await bot.core.lions.fetch_member(guildid, userid) 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 today = lion.today
week_start = today - timedelta(days=today.weekday()) - timedelta(weeks=offset) 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))] 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) day_stats.append(0)
# Get member profile # Get member profile
if member := await lion.fetch_member(): if user:
username = (member.display_name, member.discriminator) username = (user.display_name, user.discriminator)
else: else:
username = (lion.data.display_name, '#????') username = (lion.data.display_name, '#????')

View File

@@ -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

View File

@@ -693,6 +693,8 @@ class WeeklyMonthlyUI(StatsUI):
await press.response.defer(thinking=True, ephemeral=True) await press.response.defer(thinking=True, ephemeral=True)
self._showing_global = not self._showing_global self._showing_global = not self._showing_global
# TODO: Asynchronously update user preferences # 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) await self.refresh(thinking=press if not self._showing_global else None)
@@ -702,7 +704,8 @@ class WeeklyMonthlyUI(StatsUI):
colour=discord.Colour.orange(), colour=discord.Colour.orange(),
description=t(_p( description=t(_p(
'ui:WeeklyMonthly|button:global|resp:success', '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) await press.edit_original_response(embed=embed)
@@ -843,6 +846,7 @@ class WeeklyMonthlyUI(StatsUI):
""" """
Reload the UI data, applying cache where possible. 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) await self.fetch_cards(*self.key)
async def make_message(self) -> MessageArgs: async def make_message(self) -> MessageArgs:
@@ -858,9 +862,7 @@ class WeeklyMonthlyUI(StatsUI):
Execute the UI using the given interaction. Execute the UI using the given interaction.
""" """
self._original = interaction self._original = interaction
self._showing_global = False
self.lion = await self.bot.core.lions.fetch_member(self.guildid, self.userid) self.lion = await self.bot.core.lions.fetch_member(self.guildid, self.userid)
self._showing_global_setting = self.lion.luser.config.get('show_global_stats')
# TODO: Switch to using data cache in reload to calculate global/local
await self.refresh() await self.refresh()