feature (stats): Weekly and monthly goals.
Add a new editing interface for weekly and monthly goals. Textual viewing interface is currently a stub. Add `month_timestamp` and `week_timestamp` lion properties.
This commit is contained in:
@@ -146,6 +146,37 @@ class Lion:
|
||||
now = datetime.now(tz=self.timezone)
|
||||
return now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
@property
|
||||
def day_timestamp(self):
|
||||
"""
|
||||
EPOCH timestamp representing the current day for the user.
|
||||
NOTE: This is the timestamp of the start of the current UTC day with the same date as the user's day.
|
||||
This is *not* the start of the current user's day, either in UTC or their own timezone.
|
||||
This may also not be the start of the current day in UTC (consider 23:00 for a user in UTC-2).
|
||||
"""
|
||||
now = datetime.now(tz=self.timezone)
|
||||
day_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
return int(day_start.replace(tzinfo=pytz.utc).timestamp())
|
||||
|
||||
@property
|
||||
def week_timestamp(self):
|
||||
"""
|
||||
EPOCH timestamp representing the current week for the user.
|
||||
"""
|
||||
now = datetime.now(tz=self.timezone)
|
||||
day_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
week_start = day_start - timedelta(days=day_start.weekday())
|
||||
return int(week_start.replace(tzinfo=pytz.utc).timestamp())
|
||||
|
||||
@property
|
||||
def month_timestamp(self):
|
||||
"""
|
||||
EPOCH timestamp representing the current month for the user.
|
||||
"""
|
||||
now = datetime.now(tz=self.timezone)
|
||||
month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||
return int(month_start.replace(tzinfo=pytz.utc).timestamp())
|
||||
|
||||
@property
|
||||
def remaining_in_day(self):
|
||||
return ((self.day_start + timedelta(days=1)) - datetime.now(self.timezone)).total_seconds()
|
||||
|
||||
@@ -4,3 +4,4 @@ from . import data
|
||||
from . import profile
|
||||
from . import setprofile
|
||||
from . import top_cmd
|
||||
from . import goals
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from data import Table
|
||||
from cachetools import TTLCache
|
||||
|
||||
from data import Table, RowTable
|
||||
|
||||
|
||||
profile_tags = Table('member_profile_tags', attach_as='profile_tags')
|
||||
@@ -11,3 +13,27 @@ def get_tags_for(guildid, userid):
|
||||
_extra="ORDER BY tagid ASC"
|
||||
)
|
||||
return [row['tag'] for row in rows]
|
||||
|
||||
|
||||
weekly_goals = RowTable(
|
||||
'member_weekly_goals',
|
||||
('guildid', 'userid', 'weekid', 'study_goal', 'task_goal'),
|
||||
('guildid', 'userid', 'weekid'),
|
||||
cache=TTLCache(5000, 60 * 60 * 24),
|
||||
attach_as='weekly_goals'
|
||||
)
|
||||
|
||||
|
||||
# NOTE: Not using a RowTable here since these will almost always be mass-selected
|
||||
weekly_tasks = Table('member_weekly_goal_tasks')
|
||||
|
||||
|
||||
monthly_goals = RowTable(
|
||||
'member_monthly_goals',
|
||||
('guildid', 'userid', 'monthid', 'study_goal', 'task_goal'),
|
||||
('guildid', 'userid', 'monthid'),
|
||||
cache=TTLCache(5000, 60 * 60 * 24),
|
||||
attach_as='monthly_goals'
|
||||
)
|
||||
|
||||
monthly_tasks = Table('member_monthly_goal_tasks')
|
||||
|
||||
@@ -167,7 +167,7 @@ async def cmd_setprofile(ctx, flags):
|
||||
# Ack with user
|
||||
embed = discord.Embed(
|
||||
colour=discord.Colour.green(),
|
||||
description="Profile tags updated!"
|
||||
title="Profile tags updated!"
|
||||
)
|
||||
embed.add_field(
|
||||
name="New tags",
|
||||
@@ -175,10 +175,14 @@ async def cmd_setprofile(ctx, flags):
|
||||
)
|
||||
if deleted_rows:
|
||||
embed.add_field(
|
||||
name="Previous tags",
|
||||
name="Replaced tags",
|
||||
value='\n'.join(row['tag'].upper() for row in deleted_rows),
|
||||
inline=False
|
||||
)
|
||||
if len(to_add) == 1:
|
||||
embed.set_footer(
|
||||
text=f"TIP: Add multiple tags with {ctx.best_prefix}setprofile tag1, tag2, ..."
|
||||
)
|
||||
await ctx.reply(embed=embed)
|
||||
else:
|
||||
# No input was provided
|
||||
|
||||
@@ -21,6 +21,56 @@ CREATE TABLE member_profile_tags(
|
||||
_timestamp TIMESTAMPTZ DEFAULT now(),
|
||||
FOREIGN KEY (guildid, userid) REFERENCES members (guildid, userid)
|
||||
);
|
||||
CREATE INDEX member_profile_tags_members ON member_profile_tags (guildid, userid);
|
||||
|
||||
|
||||
-- New member weekly and monthly goals
|
||||
CREATE TABLE member_weekly_goals(
|
||||
guildid BIGINT NOT NULL,
|
||||
userid BIGINT NOT NULL,
|
||||
weekid INTEGER NOT NULL, -- Epoch time of the start of the UTC week
|
||||
study_goal INTEGER,
|
||||
task_goal INTEGER,
|
||||
_timestamp TIMESTAMPTZ DEFAULT now(),
|
||||
PRIMARY KEY (guildid, userid, weekid),
|
||||
FOREIGN KEY (guildid, userid) REFERENCES members (guildid, userid) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX member_weekly_goals_members ON member_weekly_goals (guildid, userid);
|
||||
|
||||
CREATE TABLE member_weekly_goal_tasks(
|
||||
taskid SERIAL PRIMARY KEY,
|
||||
guildid BIGINT NOT NULL,
|
||||
userid BIGINT NOT NULL,
|
||||
weekid INTEGER NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
completed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
_timestamp TIMESTAMPTZ DEFAULT now(),
|
||||
FOREIGN KEY (weekid, guildid, userid) REFERENCES member_weekly_goals (weekid, guildid, userid) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX member_weekly_goal_tasks_members_weekly ON member_weekly_goal_tasks (guildid, userid, weekid);
|
||||
|
||||
CREATE TABLE member_monthly_goals(
|
||||
guildid BIGINT NOT NULL,
|
||||
userid BIGINT NOT NULL,
|
||||
monthid INTEGER NOT NULL, -- Epoch time of the start of the UTC month
|
||||
study_goal INTEGER,
|
||||
task_goal INTEGER,
|
||||
_timestamp TIMESTAMPTZ DEFAULT now(),
|
||||
PRIMARY KEY (guildid, userid, monthid),
|
||||
FOREIGN KEY (guildid, userid) REFERENCES members (guildid, userid) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX member_monthly_goals_members ON member_monthly_goals (guildid, userid);
|
||||
|
||||
CREATE TABLE member_monthly_goal_tasks(
|
||||
taskid SERIAL PRIMARY KEY,
|
||||
guildid BIGINT NOT NULL,
|
||||
userid BIGINT NOT NULL,
|
||||
monthid INTEGER NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
completed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
_timestamp TIMESTAMPTZ DEFAULT now(),
|
||||
FOREIGN KEY (monthid, guildid, userid) REFERENCES member_monthly_goals (monthid, guildid, userid) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX member_monthly_goal_tasks_members_monthly ON member_monthly_goal_tasks (guildid, userid, monthid);
|
||||
|
||||
INSERT INTO VersionHistory (version, author) VALUES (7, 'v6-v7 migration');
|
||||
|
||||
@@ -692,9 +692,57 @@ CREATE TABLE member_profile_tags(
|
||||
_timestamp TIMESTAMPTZ DEFAULT now(),
|
||||
FOREIGN KEY (guildid, userid) REFERENCES members (guildid, userid)
|
||||
);
|
||||
CREATE INDEX member_profile_tags_members ON member_profile_tags (guildid, userid);
|
||||
-- }}}
|
||||
|
||||
-- Member goals {{{
|
||||
CREATE TABLE member_weekly_goals(
|
||||
guildid BIGINT NOT NULL,
|
||||
userid BIGINT NOT NULL,
|
||||
weekid INTEGER NOT NULL, -- Epoch time of the start of the UTC week
|
||||
study_goal INTEGER,
|
||||
task_goal INTEGER,
|
||||
_timestamp TIMESTAMPTZ DEFAULT now(),
|
||||
PRIMARY KEY (guildid, userid, weekid),
|
||||
FOREIGN KEY (guildid, userid) REFERENCES members (guildid, userid) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX member_weekly_goals_members ON member_weekly_goals (guildid, userid);
|
||||
|
||||
CREATE TABLE member_weekly_goal_tasks(
|
||||
taskid SERIAL PRIMARY KEY,
|
||||
guildid BIGINT NOT NULL,
|
||||
userid BIGINT NOT NULL,
|
||||
weekid INTEGER NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
completed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
_timestamp TIMESTAMPTZ DEFAULT now(),
|
||||
FOREIGN KEY (weekid, guildid, userid) REFERENCES member_weekly_goals (weekid, guildid, userid) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX member_weekly_goal_tasks_members_weekly ON member_weekly_goal_tasks (guildid, userid, weekid);
|
||||
|
||||
CREATE TABLE member_monthly_goals(
|
||||
guildid BIGINT NOT NULL,
|
||||
userid BIGINT NOT NULL,
|
||||
monthid INTEGER NOT NULL, -- Epoch time of the start of the UTC month
|
||||
study_goal INTEGER,
|
||||
task_goal INTEGER,
|
||||
_timestamp TIMESTAMPTZ DEFAULT now(),
|
||||
PRIMARY KEY (guildid, userid, monthid),
|
||||
FOREIGN KEY (guildid, userid) REFERENCES members (guildid, userid) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX member_monthly_goals_members ON member_monthly_goals (guildid, userid);
|
||||
|
||||
CREATE TABLE member_monthly_goal_tasks(
|
||||
taskid SERIAL PRIMARY KEY,
|
||||
guildid BIGINT NOT NULL,
|
||||
userid BIGINT NOT NULL,
|
||||
monthid INTEGER NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
completed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
_timestamp TIMESTAMPTZ DEFAULT now(),
|
||||
FOREIGN KEY (monthid, guildid, userid) REFERENCES member_monthly_goals (monthid, guildid, userid) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX member_monthly_goal_tasks_members_monthly ON member_monthly_goal_tasks (guildid, userid, monthid);
|
||||
|
||||
-- }}}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user