diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-19 20:46:23 -0400 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-19 20:46:23 -0400 |
| commit | d6a995b9090ca35190e59e765d5c14daf887e9d8 (patch) | |
| tree | 9069e0b49068690dad26d69a6cc3a5e1d46f2b25 /tests/fixtures | |
| parent | 8911d161f7ef38f8a1b03fba6316b71da1011174 (diff) | |
| download | dotemacs-d6a995b9090ca35190e59e765d5c14daf887e9d8.tar.gz dotemacs-d6a995b9090ca35190e59e765d5c14daf887e9d8.zip | |
feat(calendar-sync): add Python helper for Google Calendar API sync
Google's .ics export drops per-occurrence response statuses on recurring events. When OOO auto-declines a meeting, the master event keeps PARTSTAT=ACCEPTED and declined instances inherit it. The .ics path can't filter the declines out. The API path expands recurrences server-side via singleEvents=True, and each occurrence carries its own attendees[].self.responseStatus.
scripts/calendar_sync_api.py fetches events and renders them as org entries. OAuth is one-time per account. The refresh token lives at ~/.config/calendar-sync/token-<account>.json under 0600. Output matches the existing .ics shape: heading sanitization, LOCATION/ORGANIZER/STATUS/URL property drawer, HTML-stripped descriptions, org timestamps with weekday abbreviations.
I wrote 30 stdlib-unittest tests against fixture JSON, covering rendering, filtering, timestamp formatting, and HTML cleanup. I left auth and HTTP uncovered — they're thin wrappers around the Google client libraries, best checked by running the script once after OAuth setup.
docs/calendar-sync-api-setup.org walks through the Google Cloud OAuth client setup and the per-account auth bootstrap. .gitignore picks up Python bytecode now that the project has a Python helper.
The Elisp dispatch (:fetcher 'api routing in calendar-sync.el) lands in a follow-up commit.
Diffstat (limited to 'tests/fixtures')
4 files changed, 49 insertions, 0 deletions
diff --git a/tests/fixtures/calendar-sync-api/accepted-with-conference.json b/tests/fixtures/calendar-sync-api/accepted-with-conference.json new file mode 100644 index 00000000..63d4e0be --- /dev/null +++ b/tests/fixtures/calendar-sync-api/accepted-with-conference.json @@ -0,0 +1,19 @@ +{ + "id": "6hh36pj364sjibb161i3gb9kckr32bb161hjebb671hjcp9g6so68ob5c8", + "summary": "Breakout: Machine Speed, Human Will", + "location": "Marriott Water Street: Florida Salon V - VI / Breakout Room 2", + "start": {"dateTime": "2026-05-19T14:45:00-04:00", "timeZone": "America/New_York"}, + "end": {"dateTime": "2026-05-19T15:45:00-04:00", "timeZone": "America/New_York"}, + "description": "AI's role in the future of special operations.<br/><br/>Bring your laptop.", + "status": "confirmed", + "organizer": {"email": "eric@deepsat.com", "displayName": "Eric Bell"}, + "attendees": [ + {"email": "craig.jennings@deepsat.com", "responseStatus": "accepted", "self": true}, + {"email": "eric@deepsat.com", "responseStatus": "accepted", "organizer": true} + ], + "conferenceData": { + "entryPoints": [ + {"entryPointType": "video", "uri": "https://meet.google.com/abc-defg-hij"} + ] + } +} diff --git a/tests/fixtures/calendar-sync-api/all-day-multi.json b/tests/fixtures/calendar-sync-api/all-day-multi.json new file mode 100644 index 00000000..96d9e0ed --- /dev/null +++ b/tests/fixtures/calendar-sync-api/all-day-multi.json @@ -0,0 +1,8 @@ +{ + "id": "fjamsabuds9porc82vh8r7tsl4", + "summary": "SOFWeek — Tampa", + "location": "Tampa, FL", + "start": {"date": "2026-05-17"}, + "end": {"date": "2026-05-22"}, + "status": "confirmed" +} diff --git a/tests/fixtures/calendar-sync-api/all-day-single.json b/tests/fixtures/calendar-sync-api/all-day-single.json new file mode 100644 index 00000000..99d2a2a2 --- /dev/null +++ b/tests/fixtures/calendar-sync-api/all-day-single.json @@ -0,0 +1,7 @@ +{ + "id": "2jn8q2k837d2v29alsvcfqljek_20260519", + "summary": "Home", + "start": {"date": "2026-05-19"}, + "end": {"date": "2026-05-20"}, + "status": "confirmed" +} diff --git a/tests/fixtures/calendar-sync-api/declined-recurring.json b/tests/fixtures/calendar-sync-api/declined-recurring.json new file mode 100644 index 00000000..fad6a862 --- /dev/null +++ b/tests/fixtures/calendar-sync-api/declined-recurring.json @@ -0,0 +1,15 @@ +{ + "id": "4lu91bb3spgmru2bfndh0a4rrk_20260519T160000Z", + "summary": "STRATFI/FR Standup/IPM/Grooming", + "start": {"dateTime": "2026-05-19T12:00:00-04:00", "timeZone": "America/Los_Angeles"}, + "end": {"dateTime": "2026-05-19T13:00:00-04:00", "timeZone": "America/Los_Angeles"}, + "status": "confirmed", + "organizer": {"email": "ryan@deepsat.com"}, + "attendees": [ + {"email": "nerses@deepsat.com", "responseStatus": "accepted"}, + {"email": "ryan@deepsat.com", "responseStatus": "declined", "organizer": true}, + {"email": "craig.jennings@deepsat.com", "responseStatus": "declined", "self": true, + "comment": "Out of office for SOFWeek (Tampa) through Friday 5/22."} + ], + "hangoutLink": "https://meet.google.com/suw-ornf-iuv" +} |
