Skip to content

Commit 9e4fcb9

Browse files
Merge pull request #82 from PortableProgrammer/dev
Make calendar lookahead configurable
2 parents 7adaea1 + 69f3241 commit 9e4fcb9

File tree

5 files changed

+50
-10
lines changed

5 files changed

+50
-10
lines changed

README.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ services:
6565
- "ACTIVE_DAYS=Monday,Tuesday,Wednesday,Thursday,Friday"
6666
- "ACTIVE_HOURS_START=08:00:00"
6767
- "ACTIVE_HOURS_END=17:00:00"
68+
- "CALENDAR_LOOKAHEAD=5"
6869
- "SLEEP_SECONDS=5"
6970
- "LOGLEVEL=INFO"
7071
volumes:
@@ -158,13 +159,13 @@ If specificed, requires at least one of the available options. This will control
158159
#### `AVAILABLE_STATUS`
159160

160161
- Default value: `active`
161-
- By default, denotes that there is no ongoing collaboration call or meeting, and no calendar meetings scheduled within the next `5` minutes.
162+
- By default, denotes that there is no ongoing collaboration call or meeting, and no calendar meetings scheduled within the configured [`CALENDAR_LOOKAHEAD`](#calendar_lookahead) interval.
162163
- This is the default *not busy* state. See [`OFF_STATUS`](#off_status) for an explanation of why the calendar `free` status is not included in this list by default, and why you may want to change that.
163164

164165
#### `SCHEDULED_STATUS`
165166

166167
- Default value: `busy,tentative`
167-
- By default, denotes that there is no ongoing collaboration call or meeting, but a calendar meeting, that was either accepted or tentatively accepted, is scheduled within the next `5` minutes.
168+
- By default, denotes that there is no ongoing collaboration call or meeting, but a calendar meeting, that was either accepted or tentatively accepted, is scheduled within the configured [`CALENDAR_LOOKAHEAD`](#calendar_lookahead) interval.
168169
- This is the default *about to be busy* state.
169170

170171
#### `BUSY_STATUS`
@@ -183,7 +184,8 @@ If specificed, requires at least one of the available options. This will control
183184
- In the case of `outofoffice` and `workingelsewhere`, this is a personal preference. I don't need Status-Light to tell my family that I'm somewhere else; they can see that.
184185
- In the case of `free`, there are a few reasons why it's in `OFF_STATUS` by default.
185186
- Typically, if the user is asking for both collaboration and calendar statuses, the user will be `active` (from collaboration) and `free` (from calendar) simultaneously, so `active` will always win.
186-
- Status-Light makes a determination of `free`/`busy`/`tentative` by checking the user's availability within the next `5` minutes. There is typically no 'off-hours' status in calendaring applications, which means, at the end of the working day, the user is technically `free`. In that instance, the light would be on during off hours, showing the selected [`AVAIALBLE_COLOR`](#available_color). Again, this is a personal preference; I don't want the light on while I'm not at work, and I am using Webex to handle [`AVAILABLE_STATUS`](#available_status).
187+
- Status-Light makes a determination of `free`/`busy`/`tentative` by checking the user's calendar availability within the configured [`CALENDAR_LOOKAHEAD`](#calendar_lookahead) interval. There is typically no 'off-hours' status in calendaring applications, which means, at the end of the working day, the user is technically `free`. In that instance, the light would be on during off hours, showing the selected [`AVAIALBLE_COLOR`](#available_color). Again, this is a personal preference; I don't want the light on while I'm not at work, and I am using Webex to handle [`AVAILABLE_STATUS`](#available_status).
188+
- This behavior can be further refined with the [`ACTIVE_*`](#active-times) variables.
187189
- In the case that no collaboration sources are present in [`SOURCES`](#sources), it is recommended to move `free` to [`AVAILABLE_STATUS`](#available_status), but the caveat above will apply in that scenario: the light may stay on all the time.
188190

189191
**Note 1:** Status-Light makes no attempt to handle invalid values in a list. In the case of an error, Status-Light will simply revert to the default value for that list.
@@ -390,6 +392,8 @@ To retrieve your `SLACK_BOT_TOKEN`, see below:
390392

391393
### **Office 365**
392394

395+
**Note:** See [`CALENDAR_LOOKAHEAD`](#calendar_lookahead) to configure lookahead timing for Calendar sources.
396+
393397
#### `O365_APPID`
394398

395399
#### `O365_APPSECRET`
@@ -416,6 +420,8 @@ Defines a writable location on disk where the Office 365 tokens are stored. This
416420

417421
### **Google**
418422

423+
**Note:** See [`CALENDAR_LOOKAHEAD`](#calendar_lookahead) to configure lookahead timing for Calendar sources.
424+
419425
#### `GOOGLE_CREDENTIALSTORE`
420426

421427
- *Optional, only valid if `google` is present in [`SOURCES`](#sources)*
@@ -480,6 +486,16 @@ A time, in 24-hour format, signifying the start and end of the active hours on a
480486

481487
---
482488

489+
### `CALENDAR_LOOKAHEAD`
490+
491+
- *Optional*
492+
- Acceptable range: `5`-`60`
493+
- Default value: `5`
494+
495+
Set the number of minutes that Calendar [`SOURCES`](#sources) lookahead to determine free/busy.
496+
497+
---
498+
483499
### `SLEEP_SECONDS`
484500

485501
- *Optional*

status-light/sources/calendar/google.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ class GoogleCalendarAPI:
3232
credentialStore = '~'
3333
tokenStore = '~'
3434

35+
# 81 - Make calendar lookahead configurable
36+
lookahead: int
37+
3538
CREDENTIALS_FILENAME = 'client_secret.json'
3639

3740
# If modifying these scopes, delete the file token.json.
@@ -77,17 +80,17 @@ def get_calendar_service(self):
7780

7881
def get_current_status(self):
7982
"""Connects to the Google Calendar API to retrieve the user's free/busy
80-
status within the next 5 minutes.
83+
status within the lookahead period.
8184
8285
Returns the status returned from Google, or 'unknown' if an error occurs."""
8386
try:
8487
service = self.get_calendar_service()
8588
now = datetime.utcnow().isoformat() + 'Z'
86-
now_plus = (datetime.utcnow() +
87-
timedelta(minutes=5)).isoformat() + 'Z'
89+
now_plus_lookahead = (datetime.utcnow() +
90+
timedelta(minutes=self.lookahead)).isoformat() + 'Z'
8891
query = {
8992
"timeMin": now,
90-
"timeMax": now_plus,
93+
"timeMax": now_plus_lookahead,
9194
"items": [
9295
{
9396
"id": "primary"

status-light/sources/calendar/office365.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ class OfficeAPI:
2727
tokenStore = '~'
2828
account: Account
2929

30+
# 81 - Make calendar lookahead configurable
31+
lookahead: int
32+
3033
def authenticate(self):
3134
"""Authenticates against Office 365"""
3235
token_backend = FileSystemTokenBackend(token_path=self.tokenStore,
@@ -47,19 +50,22 @@ def get_calendar(self):
4750
return self.account.schedule().get_default_calendar()
4851

4952
def get_current_status(self):
50-
"""Retrieves the Office 365 status within the next 5 minutes"""
53+
"""Retrieves the Office 365 status within the lookahead period"""
5154
try:
5255
schedule = self.get_schedule()
5356
schedules = [self.account.get_current_user().mail] # type: ignore
5457
availability = schedule.get_availability(schedules, datetime.now(),
55-
datetime.now() + timedelta(minutes=5), 5)
58+
datetime.now() + timedelta(
59+
minutes=self.lookahead
60+
),
61+
self.lookahead)
5662
availability_view = availability[0]["availabilityView"][0]
5763
logger.debug('Got availabilityView: %s', availability_view)
5864

5965
return enum.Status[availability_view.replace(' ', '').lower()]
6066
except (SystemExit, KeyboardInterrupt):
6167
return enum.Status.UNKNOWN
62-
except Exception as ex: # pylint: disable=broad-except
68+
except Exception as ex: # pylint: disable=broad-except
6369
logger.warning('Exception while getting Office 365 status: %s', ex)
6470
logger.exception(ex)
6571
return enum.Status.UNKNOWN

status-light/status-light.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def init(self):
5757
self.local_env.get_colors(),
5858
self.local_env.get_status(),
5959
self.local_env.get_active_time(),
60+
self.local_env.get_lookahead(),
6061
self.local_env.get_sleep(),
6162
self.local_env.get_log_level()]:
6263

@@ -106,6 +107,8 @@ def init(self):
106107
self.office_api.appID = self.local_env.office_app_id
107108
self.office_api.appSecret = self.local_env.office_app_secret
108109
self.office_api.tokenStore = self.local_env.office_token_store
110+
# 81 - Make calendar lookahead configurable
111+
self.office_api.lookahead = self.local_env.calendar_lookahead
109112
self.office_api.authenticate()
110113
else:
111114
logger.error(
@@ -118,6 +121,8 @@ def init(self):
118121
logger.info('Requested Google')
119122
self.google_api.credentialStore = self.local_env.google_credential_store
120123
self.google_api.tokenStore = self.local_env.google_token_store
124+
# 81 - Make calendar lookahead configurable
125+
self.google_api.lookahead = self.local_env.calendar_lookahead
121126
else:
122127
logger.error(
123128
'Requested Google, but could not find all environment variables!')

status-light/utility/env.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ class Environment:
8181
active_hours_start: time = time(hour=0, minute=0, second=0)
8282
active_hours_end: time = time(hour=23, minute=59, second=59)
8383

84+
# 81 - Make calendar lookahead configurable
85+
calendar_lookahead: int = 5
86+
8487
# 22 - Make sleep timeout configurable
8588
sleep_seconds: int = 5
8689

@@ -221,6 +224,13 @@ def get_active_time(self) -> bool:
221224
return ('' not in [self.active_days, self.active_hours_start,
222225
self.active_hours_end])
223226

227+
def get_lookahead(self) -> bool:
228+
"""Retrieves and validates the `CALENDAR_LOOKAHEAD` variable."""
229+
# 41: Replace decorator with utility function
230+
self.calendar_lookahead = util.try_parse_int(os.environ.get('CALENDAR_LOOKAHEAD', ''),
231+
self.calendar_lookahead)
232+
return self.calendar_lookahead >= 5 and self.calendar_lookahead <= 60
233+
224234
def get_sleep(self) -> bool:
225235
"""Retrieves and validates the `SLEEP_SECONDS` variable."""
226236
# 41: Replace decorator with utility function

0 commit comments

Comments
 (0)