Skip to content

Commit 2c687c7

Browse files
committed
Clean up reminder schedule after completing the job if the recurrence is once and update the object to the next scheduled date if recurrence is otherwise and add list_reminders button
1 parent bbb1b40 commit 2c687c7

File tree

8 files changed

+118
-23
lines changed

8 files changed

+118
-23
lines changed

backend/apps/nest/schedulers/calendar_events/base.py

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from django_rq import get_scheduler
44

5+
from django.utils import timezone
56
from apps.nest.models.reminder_schedule import ReminderSchedule
67

78

@@ -22,30 +23,44 @@ def schedule(self):
2223
message=self.reminder_schedule.reminder.message,
2324
channel_id=self.reminder_schedule.reminder.channel_id,
2425
).get_id()
25-
self.reminder_schedule.save()
26-
return
27-
28-
self.reminder_schedule.job_id = self.scheduler.cron(
29-
self.reminder_schedule.cron_expression,
30-
func=self.__class__.send_message,
31-
args=(
32-
self.reminder_schedule.reminder.message,
33-
self.reminder_schedule.reminder.channel_id,
34-
),
35-
queue_name="default",
36-
use_local_timezone=True,
37-
result_ttl=500,
38-
).get_id()
39-
self.reminder_schedule.save()
26+
27+
# Schedule deletion of the reminder after sending the message
28+
self.scheduler.enqueue_at(
29+
self.reminder_schedule.scheduled_time + timezone.timedelta(minutes=1),
30+
self.reminder_schedule.reminder.delete,
31+
)
32+
else:
33+
self.reminder_schedule.job_id = self.scheduler.cron(
34+
self.reminder_schedule.cron_expression,
35+
func=self.__class__.send_message_and_update,
36+
args=(
37+
self.reminder_schedule.reminder.message,
38+
self.reminder_schedule.reminder.channel_id,
39+
self.reminder_schedule,
40+
),
41+
queue_name="default",
42+
use_local_timezone=True,
43+
result_ttl=500,
44+
).get_id()
45+
46+
self.reminder_schedule.save(update_fields=["job_id"])
4047

4148
def cancel(self):
4249
"""Cancel the scheduled reminder."""
4350
if self.reminder_schedule.job_id:
4451
self.scheduler.cancel(self.reminder_schedule.job_id)
45-
self.reminder_schedule.delete()
52+
self.reminder_schedule.reminder.delete()
4653

4754
@staticmethod
4855
def send_message(message: str, channel_id: str):
4956
"""Send message to the specified channel. To be implemented by subclasses."""
5057
error_message = "Subclasses must implement this method."
5158
raise NotImplementedError(error_message)
59+
60+
@staticmethod
61+
def send_message_and_update(
62+
message: str, channel_id: str, reminder_schedule: ReminderSchedule
63+
):
64+
"""Send message and update the reminder schedule."""
65+
error_message = "Subclasses must implement this method."
66+
raise NotImplementedError(error_message)

backend/apps/nest/schedulers/calendar_events/slack.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Slack Scheduler for Nest Calendar Events."""
22

33
from apps.nest.schedulers.calendar_events.base import BaseScheduler
4+
from apps.nest.utils.calendar_events import update_reminder_schedule_date
45
from apps.slack.apps import SlackConfig
56

67

@@ -15,3 +16,9 @@ def send_message(message: str, channel_id: str):
1516
channel=channel_id,
1617
text=message,
1718
)
19+
20+
@staticmethod
21+
def send_message_and_update(message: str, channel_id: str, reminder_schedule):
22+
"""Send message and update the reminder schedule."""
23+
SlackScheduler.send_message(message, channel_id)
24+
update_reminder_schedule_date(reminder_schedule)

backend/apps/nest/utils/calendar_events.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
import shlex
44
from argparse import ArgumentParser
5+
from datetime import timedelta
6+
7+
from dateutil.relativedelta import relativedelta
8+
from django.utils import timezone
9+
10+
from apps.nest.models.reminder_schedule import ReminderSchedule
511

612

713
def parse_reminder_args(text: str):
@@ -43,3 +49,29 @@ def parse_reminder_args(text: str):
4349
)
4450

4551
return parser.parse_args(shlex.split(text or ""))
52+
53+
54+
def update_reminder_schedule_date(reminder_schedule: ReminderSchedule) -> None:
55+
"""Update the scheduled_time of a ReminderSchedule based on its recurrence pattern.
56+
57+
Args:
58+
reminder_schedule (ReminderSchedule): The ReminderSchedule instance to update.
59+
60+
Returns:
61+
None: The function updates the instance in place and saves it.
62+
63+
"""
64+
if reminder_schedule.scheduled_time > timezone.now():
65+
return # No update needed if the scheduled time is in the future
66+
67+
match reminder_schedule.recurrence:
68+
case ReminderSchedule.Recurrence.DAILY:
69+
reminder_schedule.scheduled_time += timedelta(days=1)
70+
case ReminderSchedule.Recurrence.WEEKLY:
71+
reminder_schedule.scheduled_time += timedelta(weeks=1)
72+
case ReminderSchedule.Recurrence.MONTHLY:
73+
reminder_schedule.scheduled_time += relativedelta(months=1)
74+
case _:
75+
return # No update for 'once' or unrecognized recurrence
76+
77+
reminder_schedule.save(update_fields=["scheduled_time"])

backend/apps/slack/actions/home.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
VIEW_PROJECTS_ACTION,
3535
VIEW_PROJECTS_ACTION_NEXT,
3636
VIEW_PROJECTS_ACTION_PREV,
37+
VIEW_REMINDERS_ACTION,
3738
)
3839

3940
logger: logging.Logger = logging.getLogger(__name__)
@@ -95,7 +96,7 @@ def handle_home_actions(ack, body, client: WebClient) -> None:
9596
VIEW_CALENDAR_EVENTS_ACTION_PREV,
9697
VIEW_CALENDAR_EVENTS_ACTION_NEXT,
9798
}:
98-
blocks = calendar_events.get_blocks(
99+
blocks = calendar_events.get_events_blocks(
99100
slack_user_id=user_id,
100101
page=page,
101102
presentation=home_presentation,
@@ -107,6 +108,8 @@ def handle_home_actions(ack, body, client: WebClient) -> None:
107108
blocks = [markdown("Error signing in with Google")]
108109
logger.exception("Google authentication error for user {user_id}")
109110

111+
case action if action == VIEW_REMINDERS_ACTION:
112+
blocks = calendar_events.get_reminders_blocks(slack_user_id=user_id)
110113
case _:
111114
blocks = [markdown("Invalid action, please try again.")]
112115

@@ -143,6 +146,7 @@ def handle_home_actions(ack, body, client: WebClient) -> None:
143146
VIEW_PROJECTS_ACTION_NEXT,
144147
VIEW_PROJECTS_ACTION_PREV,
145148
VIEW_PROJECTS_ACTION,
149+
VIEW_REMINDERS_ACTION,
146150
)
147151
for action in actions:
148152
SlackConfig.app.action(action)(handle_home_actions)

backend/apps/slack/blocks.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,22 @@ def get_header() -> list[dict[str, Any]]:
9999
"type": "button",
100100
"text": {
101101
"type": "plain_text",
102-
"text": "View Calendar Events",
102+
"text": "Calendar Events",
103103
"emoji": True,
104104
},
105105
"value": "view_calendar_events",
106106
"action_id": "view_calendar_events_action",
107107
},
108+
{
109+
"type": "button",
110+
"text": {
111+
"type": "plain_text",
112+
"text": "Reminders",
113+
"emoji": True,
114+
},
115+
"value": "view_reminders",
116+
"action_id": "view_reminders_action",
117+
},
108118
],
109119
},
110120
]

backend/apps/slack/commands/set_reminder.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
"""Slack Set Reminder Command."""
22

3-
from apps.nest.utils.calendar_events import parse_reminder_args
43
from apps.slack.blocks import markdown
54
from apps.slack.commands.command import CommandBase
6-
from apps.slack.common.handlers.calendar_events import get_reminder_blocks
5+
from apps.slack.common.handlers.calendar_events import get_setting_reminder_blocks
76

87

98
class SetReminder(CommandBase):
@@ -16,9 +15,11 @@ def command_name(self):
1615

1716
def render_blocks(self, command):
1817
"""Render the blocks for the command."""
18+
from apps.nest.utils.calendar_events import parse_reminder_args
19+
1920
try:
2021
args = parse_reminder_args(command["text"])
2122
except SystemExit:
2223
return [markdown("*Invalid command format. Please check your input and try again.*")]
2324
else:
24-
return get_reminder_blocks(args, self.get_user_id(command))
25+
return get_setting_reminder_blocks(args, self.get_user_id(command))

backend/apps/slack/common/handlers/calendar_events.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from apps.slack.blocks import get_pagination_buttons, markdown
1010

1111

12-
def get_blocks(slack_user_id: str, presentation, page: int = 1) -> list[dict]:
12+
def get_events_blocks(slack_user_id: str, presentation, page: int = 1) -> list[dict]:
1313
"""Get Google Calendar events blocks for Slack home view."""
1414
from apps.nest.clients.google_calendar import GoogleCalendarClient
1515
from apps.nest.models.google_account_authorization import GoogleAccountAuthorization
@@ -60,7 +60,31 @@ def get_blocks(slack_user_id: str, presentation, page: int = 1) -> list[dict]:
6060
return blocks
6161

6262

63-
def get_reminder_blocks(args, slack_user_id: str) -> list[dict]:
63+
def get_reminders_blocks(slack_user_id: str) -> list[dict]:
64+
"""Get reminders blocks for Slack home view."""
65+
from apps.nest.models.reminder_schedule import ReminderSchedule
66+
67+
reminders_schedules = ReminderSchedule.objects.filter(
68+
reminder__member__slack_user_id=slack_user_id,
69+
).order_by("scheduled_time")
70+
if not reminders_schedules:
71+
return [markdown("*No reminders found. You can set one with `/set-reminder`*")]
72+
blocks = [markdown("*Your upcoming reminders:*")]
73+
blocks.extend(
74+
markdown(
75+
f"{NL}- Reminder Number: {reminder_schedule.pk}"
76+
f"{NL}- Channel: {reminder_schedule.reminder.channel_id}"
77+
f"{NL}- Scheduled Time: "
78+
f"{reminder_schedule.scheduled_time.strftime('%Y-%m-%d, %H:%M %Z')}"
79+
f"{NL}- Recurrence: {reminder_schedule.recurrence}"
80+
f"{NL}- Message: {reminder_schedule.reminder.message or 'No message'}"
81+
)
82+
for reminder_schedule in reminders_schedules
83+
)
84+
return blocks
85+
86+
87+
def get_setting_reminder_blocks(args, slack_user_id: str) -> list[dict]:
6488
"""Get the blocks for setting a reminder."""
6589
from apps.nest.controllers.calendar_events import set_reminder
6690
from apps.nest.schedulers.calendar_events.slack import SlackScheduler

backend/apps/slack/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
VIEW_PROJECTS_ACTION_NEXT = "view_projects_action_next"
3535
VIEW_PROJECTS_ACTION_PREV = "view_projects_action_prev"
3636

37+
VIEW_REMINDERS_ACTION = "view_reminders_action"
38+
3739
VIEW_COMMITTEES_ACTION = "view_committees_action"
3840
VIEW_COMMITTEES_ACTION_NEXT = "view_committees_action_next"
3941
VIEW_COMMITTEES_ACTION_PREV = "view_committees_action_prev"

0 commit comments

Comments
 (0)