From e735e4673883b2c4310457df1c4289eb5bdb547a Mon Sep 17 00:00:00 2001 From: Johnny Gear Date: Thu, 5 Mar 2026 20:16:31 -0600 Subject: [PATCH] Skip days stored per user --- db/models.py | 8 +++++ db/queries.py | 16 ++++----- migrations/017_delete_skip_days.py | 52 +++++++++++++++++++++++++++++ migrations/018_add_skip_days.py | 53 ++++++++++++++++++++++++++++++ scheduling.py | 3 +- telegram/commands.py | 15 ++++++--- telegram/telegram.py | 6 ++-- 7 files changed, 135 insertions(+), 18 deletions(-) create mode 100644 migrations/017_delete_skip_days.py create mode 100644 migrations/018_add_skip_days.py diff --git a/db/models.py b/db/models.py index 87df9b7..6e8a2d8 100644 --- a/db/models.py +++ b/db/models.py @@ -180,5 +180,13 @@ class Repeat(BaseModel): class SkipDay(BaseModel): date = DateField(unique=True) + user = ForeignKeyField( + User, + column_name='user_id', + field='id', + null=False, + backref='skip_days' + ) + class Meta: table_name = 'skip_day' diff --git a/db/queries.py b/db/queries.py index 53585f5..4830fb3 100644 --- a/db/queries.py +++ b/db/queries.py @@ -108,21 +108,21 @@ def repeat_clear(id): q = Repeat.delete() q.execute() -def skip_day_put(date): - return SkipDay.create(date=date) +def skip_day_put(user, date): + return SkipDay.create(user=user, date=date) -def skip_day_delete(date): - q = SkipDay.delete().where(SkipDay.date == date) +def skip_day_delete(user, date): + q = SkipDay.delete().where(SkipDay.user == user and SkipDay.date == date) return q.execute() -def skip_days_upcoming(): +def skip_days_upcoming(user): return (SkipDay.select() - .where(SkipDay.date >= datetime.date.today()) + .where(SkipDay.user == user and SkipDay.date >= datetime.date.today()) .order_by(SkipDay.date) .limit(10)) -def skip_day_contains(date): - q = SkipDay.select().where(SkipDay.date == date) +def skip_day_contains(user, date): + q = SkipDay.select().where(SkipDay.user == user and SkipDay.date == date) return len(q) > 0 def order_status_put(orders_pool, user, mastodon_id, created_at, due_at, text, punishment_for=None): diff --git a/migrations/017_delete_skip_days.py b/migrations/017_delete_skip_days.py new file mode 100644 index 0000000..37b6feb --- /dev/null +++ b/migrations/017_delete_skip_days.py @@ -0,0 +1,52 @@ +"""Peewee migrations -- 017_delete_skip_days.py. + +Some examples (model - class or model name):: + + > Model = migrator.orm['table_name'] # Return model in current state by name + > Model = migrator.ModelClass # Return model in current state by name + + > migrator.sql(sql) # Run custom SQL + > migrator.run(func, *args, **kwargs) # Run python function with the given args + > migrator.create_model(Model) # Create a model (could be used as decorator) + > migrator.remove_model(model, cascade=True) # Remove a model + > migrator.add_fields(model, **fields) # Add fields to a model + > migrator.change_fields(model, **fields) # Change fields + > migrator.remove_fields(model, *field_names, cascade=True) + > migrator.rename_field(model, old_field_name, new_field_name) + > migrator.rename_table(model, new_table_name) + > migrator.add_index(model, *col_names, unique=False) + > migrator.add_not_null(model, *field_names) + > migrator.add_default(model, field_name, default) + > migrator.add_constraint(model, name, sql) + > migrator.drop_index(model, *col_names) + > migrator.drop_not_null(model, *field_names) + > migrator.drop_constraints(model, *constraints) + +""" + +from contextlib import suppress + +import peewee as pw +from peewee_migrate import Migrator + + +with suppress(ImportError): + import playhouse.postgres_ext as pw_pext + + +def migrate(migrator: Migrator, database: pw.Database, *, fake=False): + """Write your migrations here.""" + + migrator.remove_model('skip_day') + + +def rollback(migrator: Migrator, database: pw.Database, *, fake=False): + """Write your rollback migrations here.""" + + @migrator.create_model + class SkipDay(pw.Model): + id = pw.AutoField() + date = pw.DateField(unique=True) + + class Meta: + table_name = "skip_day" diff --git a/migrations/018_add_skip_days.py b/migrations/018_add_skip_days.py new file mode 100644 index 0000000..eb1d068 --- /dev/null +++ b/migrations/018_add_skip_days.py @@ -0,0 +1,53 @@ +"""Peewee migrations -- 018_add_skip_days.py. + +Some examples (model - class or model name):: + + > Model = migrator.orm['table_name'] # Return model in current state by name + > Model = migrator.ModelClass # Return model in current state by name + + > migrator.sql(sql) # Run custom SQL + > migrator.run(func, *args, **kwargs) # Run python function with the given args + > migrator.create_model(Model) # Create a model (could be used as decorator) + > migrator.remove_model(model, cascade=True) # Remove a model + > migrator.add_fields(model, **fields) # Add fields to a model + > migrator.change_fields(model, **fields) # Change fields + > migrator.remove_fields(model, *field_names, cascade=True) + > migrator.rename_field(model, old_field_name, new_field_name) + > migrator.rename_table(model, new_table_name) + > migrator.add_index(model, *col_names, unique=False) + > migrator.add_not_null(model, *field_names) + > migrator.add_default(model, field_name, default) + > migrator.add_constraint(model, name, sql) + > migrator.drop_index(model, *col_names) + > migrator.drop_not_null(model, *field_names) + > migrator.drop_constraints(model, *constraints) + +""" + +from contextlib import suppress + +import peewee as pw +from peewee_migrate import Migrator + + +with suppress(ImportError): + import playhouse.postgres_ext as pw_pext + + +def migrate(migrator: Migrator, database: pw.Database, *, fake=False): + """Write your migrations here.""" + + @migrator.create_model + class SkipDay(pw.Model): + id = pw.AutoField() + date = pw.DateField(unique=True) + user = pw.ForeignKeyField(column_name='user_id', field='id', model=migrator.orm['user']) + + class Meta: + table_name = "skip_day" + + +def rollback(migrator: Migrator, database: pw.Database, *, fake=False): + """Write your rollback migrations here.""" + + migrator.remove_model('skip_day') diff --git a/scheduling.py b/scheduling.py index e3f4a99..a0b979c 100644 --- a/scheduling.py +++ b/scheduling.py @@ -51,10 +51,9 @@ class OrderScheduler(): return # Skip stored dates - # TODO: Store these per user today = datetime.datetime.now(tz=self.tz).strftime("%Y-%m-%d") logger.info('Today %s' % today) - if (skip_day_contains(today)): + if (skip_day_contains(orders_pool.user, today)): logger.info('Today is a skip day') return diff --git a/telegram/commands.py b/telegram/commands.py index 42b5d4b..1809f83 100644 --- a/telegram/commands.py +++ b/telegram/commands.py @@ -45,7 +45,7 @@ class DomAddCommand(TelegramCommand): yield f"Successfully added {dom_username} to your list of doms" t = Telegram(session) - await t.message_send(f"@{sub_username} has added you as a dom. You may administer their orders at {FLASK_URL}", dom.telegram_chat_id) + await t.message_send(dom.telegram_chat_id, f"@{sub_username} has added you as a dom. You may administer their orders at {FLASK_URL}") class DomRemoveCommand(TelegramCommand): command_regex = re.compile(r"^\/dom_remove( (?P@?\w+))$") @@ -72,7 +72,7 @@ class DomRemoveCommand(TelegramCommand): yield f"Successfully removed {dom_username} from your list of doms" t = Telegram(session) - await t.message_send(f"@{sub_username} has removed you as a dom.", dom.telegram_chat_id) + await t.message_send(dom.telegram_chat_id, f"@{sub_username} has removed you as a dom.") class SkipDayAddCommand(TelegramCommand): @@ -84,8 +84,10 @@ class SkipDayAddCommand(TelegramCommand): response = await forResponse() + user = user_get(update['message']['chat']['username']) + skip_day = datetime.date.fromisoformat(response) - skip_day_put(skip_day) + skip_day_put(user, skip_day) yield f"Skip day {response} has been added" except ValueError: @@ -102,8 +104,10 @@ class SkipDayDeleteCommand(TelegramCommand): response = await forResponse() + user = user_get(update['message']['chat']['username']) + skip_day = datetime.date.fromisoformat(response) - rows = skip_day_delete(skip_day) + rows = skip_day_delete(user, skip_day) if rows > 0: yield f"Skip day {skip_day} has been deleted" @@ -116,7 +120,8 @@ class SkipDaysCommand(TelegramCommand): command_text = "/skip_days" async def exec_inner(self, text, update, session, forResponse=None, reply=None): - dates = skip_days_upcoming() + user = user_get(update['message']['chat']['username']) + dates = skip_days_upcoming(user) yield ("Upcoming skip days -\n" + "\n".join([d.date.isoformat() for d in dates])) diff --git a/telegram/telegram.py b/telegram/telegram.py index 76e2413..04c651c 100644 --- a/telegram/telegram.py +++ b/telegram/telegram.py @@ -126,14 +126,14 @@ async def handle_commands(commands=[], loop=None): session, forResponse=forResponse ): - await t.message_send(reply, chat_id) + await t.message_send(chat_id, reply) except TimeoutError: if chat_id in command_futures: del command_futures[chat_id] - await t.message_send("Your command has timed out", chat_id) + await t.message_send(chat_id, "Your command has timed out") except Exception: - await t.message_send('There was a problem with your command', chat_id) + await t.message_send(chat_id, 'There was a problem with your command') logger.exception('Problem while executing a command') task = asyncio.create_task(