rewrite(statistics): Minor statistics refactor.
This commit is contained in:
@@ -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(
|
||||||
|
|||||||
@@ -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)",
|
||||||
|
|||||||
@@ -15,7 +15,14 @@ async def get_goals_card(
|
|||||||
):
|
):
|
||||||
data: StatsData = bot.get_cog('StatsCog').data
|
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
|
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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
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
|
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, '#????')
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
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
|
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, '#????')
|
||||||
|
|
||||||
|
|||||||
28
src/modules/statistics/settings.py
Normal file
28
src/modules/statistics/settings.py
Normal 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
|
||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user