diff --git a/matchy/cogs/matcher.py b/matchy/cogs/matcher.py index d8f9d39..394fb79 100644 --- a/matchy/cogs/matcher.py +++ b/matchy/cogs/matcher.py @@ -92,8 +92,8 @@ class MatcherCog(commands.Cog): msg += "\n" + strings.paused_matchees(mentions) + "\n" tasks = state.State.get_channel_match_tasks(interaction.channel.id) - for (day, hour, min, cadence, cadence_start) in tasks: - next_run = util.get_next_datetime_with_cadence(day, hour, datetime.now(), cadence, cadence_start) + for (day, hour, min) in tasks: + next_run = util.get_next_datetime(day, hour) msg += "\n" + strings.scheduled(next_run, min) if not msg: @@ -110,8 +110,7 @@ class MatcherCog(commands.Cog): interaction: discord.Interaction, members_min: int | None = None, weekday: int | None = None, - hour: int | None = None, - cadence: int | None = None): + hour: int | None = None): """Schedule a match using the input parameters""" # Set all the defaults @@ -121,8 +120,6 @@ class MatcherCog(commands.Cog): weekday = 0 if hour is None: hour = 9 - if cadence is None or cadence == 0: - cadence = 1 channel_id = str(interaction.channel.id) # Bail if not a matcher @@ -132,19 +129,19 @@ class MatcherCog(commands.Cog): return # Add the scheduled task and save - (_, _, _, _, cadence_start) = state.State.set_channel_match_task( - channel_id, members_min, weekday, hour, cadence) + state.State.set_channel_match_task( + channel_id, members_min, weekday, hour) # Let the user know what happened - logger.info("Scheduled new match task in %s with min %s weekday %s hour %s and cadence %s", - channel_id, members_min, weekday, hour, cadence) - next_run = util.get_next_datetime_with_cadence(weekday, hour, datetime.now(), cadence, cadence_start) + logger.info("Scheduled new match task in %s with min %s weekday %s hour %s", + channel_id, members_min, weekday, hour) + next_run = util.get_next_datetime(weekday, hour) view = discord.ui.View(timeout=None) view.add_item(ScheduleButton()) await interaction.response.send_message( - strings.scheduled_success(next_run, cadence), + strings.scheduled_success(next_run), ephemeral=True, silent=True, view=view) @app_commands.command(description="Cancel all scheduled matches in this channel") @@ -307,8 +304,8 @@ class ScheduleButton(discord.ui.Button): msg += strings.scheduled_matches() if tasks: - for (day, hour, min, cadence, cadence_start) in tasks: - next_run = util.get_next_datetime(day, hour, datetime.now(), cadence, cadence_start) + for (day, hour, min) in tasks: + next_run = util.get_next_datetime(day, hour) msg += strings.scheduled(next_run, min) await interaction.channel.send(msg) diff --git a/matchy/cogs/strings.py b/matchy/cogs/strings.py index a617194..297e51b 100644 --- a/matchy/cogs/strings.py +++ b/matchy/cogs/strings.py @@ -85,11 +85,11 @@ def need_matcher_scope(): return [ @randomised -def scheduled_success(d, cadence): return [ - f"Done :) Next run will be at {datetime_as_discord_time(d)} and every {cadence} week(s) after", - f"Woohoo! Scheduled for {datetime_as_discord_time(d)} plus each {cadence} week(s) after", - f"Yessir, will do a matcho every {cadence} week(s), first one is {datetime_as_discord_time(d)}", - f"Arf Arf! Bork bork bark {datetime_as_discord_time(d)} berk {cadence} week(s) arf", +def scheduled_success(d): return [ + f"Done :) Next run will be at {datetime_as_discord_time(d)}", + f"Woohoo! Scheduled for {datetime_as_discord_time(d)}", + f"Yessir, will do a matcho at {datetime_as_discord_time(d)}", + f"Arf Arf! Bork bork bark {datetime_as_discord_time(d)}", ] diff --git a/matchy/state.py b/matchy/state.py index 5af6096..d498af6 100644 --- a/matchy/state.py +++ b/matchy/state.py @@ -16,7 +16,7 @@ logger = logging.getLogger("state") logger.setLevel(logging.INFO) # Warning: Changing any of the below needs proper thought to ensure backwards compatibility -_VERSION = 5 +_VERSION = 4 def _migrate_to_v1(d: dict): @@ -64,24 +64,12 @@ def _migrate_to_v4(d: dict): del d[_Key._HISTORY] -def _migrate_to_v5(d: dict): - """v5 added weekly cadence""" - tasks = d.get(_Key.TASKS, {}) - for tasks in tasks.values(): - match_tasks = tasks.get(_Key.MATCH_TASKS, []) - for match in match_tasks: - # All previous matches were every week starting from now - match[_Key.CADENCE] = 1 - match[_Key.CADENCE_START] = datetime_to_ts(datetime.now()) - - # Set of migration functions to apply _MIGRATIONS = [ _migrate_to_v1, _migrate_to_v2, _migrate_to_v3, _migrate_to_v4, - _migrate_to_v5 ] @@ -106,8 +94,6 @@ class _Key(str): MEMBERS_MIN = "members_min" WEEKDAY = "weekdays" HOUR = "hours" - CADENCE = "cadence" - CADENCE_START = "cadence_start" # Unused _MATCHEES = "matchees" @@ -153,8 +139,6 @@ _SCHEMA = Schema( _Key.MEMBERS_MIN: Use(int), _Key.WEEKDAY: Use(int), _Key.HOUR: Use(int), - _Key.CADENCE: Use(int), - _Key.CADENCE_START: Use(str), } ] } @@ -232,12 +216,11 @@ class _State(): @wraps(func) def inner(self, *args, **kwargs): tmp = _State(self._dict, self._file) - ret = func(tmp, *args, **kwargs) + func(tmp, *args, **kwargs) _SCHEMA.validate(tmp._dict) if tmp._file: _save(tmp._file, tmp._dict) self._dict = tmp._dict - return ret return inner @@ -341,10 +324,7 @@ class _State(): for channel, tasks in self._tasks.items(): for match in tasks.get(_Key.MATCH_TASKS, []): - # Take into account the weekly cadence - start = ts_to_datetime(match[_Key.CADENCE_START]) - weeks = int((time - start).days / 7) - if match[_Key.WEEKDAY] == weekday and match[_Key.HOUR] == hour and weeks % match[_Key.CADENCE] == 0: + if match[_Key.WEEKDAY] == weekday and match[_Key.HOUR] == hour: yield (channel, match[_Key.MEMBERS_MIN]) def get_channel_match_tasks(self, channel_id: str) -> Generator[int, int, int]: @@ -358,35 +338,30 @@ class _State(): ) for tasks in all_tasks: for task in tasks: - yield _task_to_tuple(task) + yield (task[_Key.WEEKDAY], task[_Key.HOUR], task[_Key.MEMBERS_MIN]) @safe_write - def set_channel_match_task(self, channel_id: str, members_min: int, weekday: int, hour: int, cadence: int): + def set_channel_match_task(self, channel_id: str, members_min: int, weekday: int, hour: int): """Set up a match task on a channel""" channel = self._tasks.setdefault(str(channel_id), {}) matches = channel.setdefault(_Key.MATCH_TASKS, []) - for match_task in matches: + found = False + for match in matches: # Specifically check for the combination of weekday and hour - if match_task[_Key.WEEKDAY] == weekday and match_task[_Key.HOUR] == hour: - match_task[_Key.MEMBERS_MIN] = members_min - # If the cadence has changed, update it and reset the start - if cadence != match_task[_Key.CADENCE]: - match_task[_Key.CADENCE] = cadence - match_task[_Key.CADENCE_START] = datetime_to_ts(datetime.now()) - # Return as we've successfully changed the data in place - return _task_to_tuple(match_task) + if match[_Key.WEEKDAY] == weekday and match[_Key.HOUR] == hour: + found = True + match[_Key.MEMBERS_MIN] = members_min + # Return true as we've successfully changed the data in place + return True # If we didn't find it, add it to the schedule - match_task = { - _Key.MEMBERS_MIN: members_min, - _Key.WEEKDAY: weekday, - _Key.HOUR: hour, - _Key.CADENCE: cadence, - _Key.CADENCE_START: datetime_to_ts(datetime.now()) - } - matches.append(match_task) - return _task_to_tuple(match_task) + if not found: + matches.append({ + _Key.MEMBERS_MIN: members_min, + _Key.WEEKDAY: weekday, + _Key.HOUR: hour, + }) @safe_write def remove_channel_match_tasks(self, channel_id: str): @@ -404,14 +379,6 @@ class _State(): return self._dict[_Key.TASKS] -def _task_to_tuple(task): - return (task[_Key.WEEKDAY], - task[_Key.HOUR], - task[_Key.MEMBERS_MIN], - task[_Key.CADENCE], - ts_to_datetime(task[_Key.CADENCE_START])) - - def load_from_file(file: str) -> _State: """ Load the state from a files diff --git a/matchy/util.py b/matchy/util.py index b8fb71e..95274e3 100644 --- a/matchy/util.py +++ b/matchy/util.py @@ -18,32 +18,20 @@ def format_list(list: list) -> str: return list[0] if list else '' -def get_next_datetime(weekday: int, hour: int, start: datetime) -> datetime: +def get_next_datetime(weekday, hour) -> datetime: """Get the next datetime for the given weekday and hour""" - - days_until_next_week_run = (weekday - start.weekday() + 7) % 7 + now = datetime.now() + days_until_next_week = (weekday - now.weekday() + 7) % 7 # Account for when we're already beyond the time now - if days_until_next_week_run == 0 and start.hour >= hour: - days_until_next_week_run = 7 + if days_until_next_week == 0 and now.hour >= hour: + days_until_next_week = 7 # Calculate the next datetime - next_date = start + timedelta(days=days_until_next_week_run) + next_date = now + timedelta(days=days_until_next_week) + next_date = next_date.replace(hour=hour, minute=0, second=0, microsecond=0) - return next_date.replace(hour=hour, minute=0, second=0, microsecond=0) - - -def get_next_datetime_with_cadence(weekday: int, hour: int, start: datetime, cadence: int, cadence_start: datetime): - """Get the next datetime for given weekday, hour and cadence values""" - - # Get the first run based on the cadence - next_time = get_next_datetime(weekday, hour, cadence_start) - - # Walk forwards until we get the actual time - while next_time < start: - next_time += timedelta(weeks=cadence) - - return next_time + return next_date def datetime_as_discord_time(time: datetime) -> str: diff --git a/tests/util_test.py b/tests/util_test.py index 60f6806..9bda465 100644 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -1,6 +1,4 @@ import matchy.util as util -from datetime import datetime -import pytest def test_iterate_all_shifts(): @@ -52,51 +50,3 @@ def test_randomized(): assert util.randomised(string)() == "foo" assert util.randomised(list)() in list() - - -@pytest.mark.parametrize( - "weekday, hour, start, expected", - [ - pytest.param( - 0, 0, datetime(2024, 9, 22), - datetime(2024, 9, 23), id="tomorrow" - ), - pytest.param( - 4, 16, datetime(2024, 9, 22), - datetime(2024, 9, 27, 16), id="complicated" - ), - ], -) -def test_get_next_datetime(weekday, hour, start, expected): - value = util.get_next_datetime(weekday, hour, start) - assert value == expected - - -@pytest.mark.parametrize( - "weekday, hour, start, cadence, cadence_start, expected", - [ - pytest.param( - 0, 0, datetime(2024, 9, 22), - 1, datetime(2024, 9, 22), - datetime(2024, 9, 23), id="tomorrow" - ), - pytest.param( - 0, 0, datetime(2024, 9, 22), - 2, datetime(2024, 9, 22), - datetime(2024, 9, 23), id="every-other" - ), - pytest.param( - 0, 0, datetime(2024, 9, 22), - 2, datetime(2024, 9, 14), - datetime(2024, 9, 30), id="every-other-before" - ), - pytest.param( - 0, 0, datetime(2024, 9, 22), - 3, datetime(2024, 9, 14), - datetime(2024, 10, 7), id="every-third" - ), - ], -) -def test_get_next_datetime_with_cadence(weekday, hour, start, expected, cadence, cadence_start): - value = util.get_next_datetime_with_cadence(weekday, hour, start, cadence, cadence_start) - assert value == expected