Skip to content

Commit 12864e8

Browse files
Feat: Use reminder overrides for events.
1 parent 50a9579 commit 12864e8

File tree

1 file changed

+51
-20
lines changed

1 file changed

+51
-20
lines changed

zulip/integrations/google/google-calendar

+51-20
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,14 @@ class Event(TypedDict):
4040
description: str
4141
organizer: str
4242
hangout_link: str
43+
reminder: int
4344

4445

4546
# Our cached view of the calendar, updated periodically.
4647
events: List[Event] = []
4748

48-
# Unique keys for events we've already sent, so we don't remind twice.
49-
sent: Set[Tuple[int, datetime.datetime]] = set()
49+
# Unique keys for reminders we've already sent, so we don't remind twice.
50+
sent: Set[Tuple[int, datetime.datetime, int]] = set()
5051

5152
sys.path.append(os.path.dirname(__file__))
5253

@@ -73,12 +74,11 @@ google-calendar --calendar calendarID@example.calendar.google.com
7374

7475

7576
parser.add_argument(
76-
"--interval",
77-
dest="interval",
78-
default=30,
77+
"--override",
78+
dest="override",
7979
type=int,
8080
action="store",
81-
help="Minutes before event for reminder [default: 30]",
81+
help="Override the reminder time for all events.",
8282
metavar="MINUTES",
8383
)
8484

@@ -125,13 +125,12 @@ def get_credentials() -> Credentials:
125125
def populate_events() -> Optional[None]:
126126
creds = get_credentials()
127127
service = build("calendar", "v3", credentials=creds)
128-
now = datetime.datetime.now(pytz.utc).isoformat()
129128
feed = (
130129
service.events()
131130
.list(
132131
calendarId=options.calendarID,
133-
timeMin=now,
134-
maxResults=5,
132+
timeMin=datetime.datetime.now(pytz.utc).isoformat(),
133+
timeMax=datetime.datetime.now(pytz.utc).isoformat().split("T")[0] + "T23:59:59Z",
135134
singleEvents=True,
136135
orderBy="startTime",
137136
)
@@ -162,6 +161,9 @@ def populate_events() -> Optional[None]:
162161
# of the tzinfo base class.
163162
start = calendar_timezone.localize(start_naive)
164163
end = calendar_timezone.localize(end_naive)
164+
now = datetime.datetime.now(tz=start.tzinfo)
165+
if start < now:
166+
continue
165167
id = event["id"]
166168
summary = event.get("summary", "(No Title)")
167169
html_link = event["htmlLink"]
@@ -176,7 +178,25 @@ def populate_events() -> Optional[None]:
176178
else event["organizer"].get("displayName", event["organizer"]["email"])
177179
)
178180
hangout_link = event.get("hangoutLink", "")
179-
events.append(
181+
reminders = event["reminders"]
182+
# If the user has specified an override, we use that for all events.
183+
# If the event uses the calendar's default reminders, we use that.
184+
# If the event has overrides on Google Calendar, we use that.
185+
# If none of the above, we don't set a reminder.
186+
if options.override:
187+
reminder_minutes = [options.override]
188+
elif reminders.get("useDefault"):
189+
calendar_list = service.calendarList().get(calendarId=options.calendarID).execute()
190+
reminder_minutes = (
191+
[reminder["minutes"] for reminder in calendar_list["defaultReminders"]]
192+
if calendar_list.get("defaultReminders")
193+
else []
194+
)
195+
elif reminders.get("overrides"):
196+
reminder_minutes = [reminder["minutes"] for reminder in reminders["overrides"]]
197+
else:
198+
reminder_minutes = []
199+
events.extend(
180200
{
181201
"id": id,
182202
"start": start,
@@ -188,7 +208,9 @@ def populate_events() -> Optional[None]:
188208
"description": description,
189209
"organizer": organizer,
190210
"hangout_link": hangout_link,
211+
"reminder": reminder,
191212
}
213+
for reminder in reminder_minutes
192214
)
193215

194216

@@ -218,21 +240,30 @@ def event_to_message(event: Event) -> str:
218240

219241

220242
def send_reminders() -> Optional[None]:
221-
messages = []
243+
messages: List[str] = []
222244
keys = set()
223-
now = datetime.datetime.now(tz=pytz.utc)
224-
225-
for event in events:
226-
dt = event["start"] - now
227-
if dt.days == 0 and dt.seconds < 60 * options.interval:
228-
# The unique key includes the start time, because of
229-
# repeating events.
230-
key = (event["id"], event["start"])
245+
# Sort events by the time of the reminder.
246+
events.sort(
247+
key=lambda event: (event["start"] - datetime.timedelta(minutes=event["reminder"])),
248+
reverse=True,
249+
)
250+
# Iterate through the events and send reminders for those whose reminder time has come or passed and remove them from the list.
251+
# The instant a reminder's time is greater than the current time, we stop sending reminders and break out of the loop.
252+
while len(events):
253+
event = events[-1]
254+
now = datetime.datetime.now(tz=event["start"].tzinfo)
255+
dt = event["start"] - datetime.timedelta(minutes=event["reminder"])
256+
if dt <= now:
257+
key = (event["id"], event["start"], event["reminder"])
231258
if key not in sent:
232259
line = event_to_message(event)
233260
print("Sending reminder:", line)
234-
messages.append(line)
261+
messages = [line, *messages]
235262
keys.add(key)
263+
events.pop()
264+
else:
265+
break
266+
236267
if not messages:
237268
return
238269

0 commit comments

Comments
 (0)