| Age | Commit message (Collapse) | Author | |
|---|---|---|---|
| 2026-09-20 | gofmt the files added in the previous commit | Peter Stone | |
| Only the files this session added; the other gofmt findings in internal/ predate it and are left alone rather than mixed into a feature change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B | |||
| 2026-09-20 | Fix Google Tasks: token refresh used a cancelled context | Peter Stone | |
| main.go builds the Tasks client with a short-lived init context and calls cancel() the moment construction returns. dbTokenSource captured that context and reused it for every subsequent token refresh, so the first refresh after the startup access token aged out — roughly an hour in — failed with "context canceled", and so did every one after it. That is the whole reason Google Tasks has not been working: all four task lists, the same error on every fetch, recovering only for an hour after each restart. The message pointed at a transport problem, which is why it read as flaky networking rather than a lifetime bug. A token refresh is not logically part of whichever request happened to trigger it, so it now gets its own background context with its own timeout. oauth2's client is likewise built on context.Background(), since NewClient binds the context it is given to the returned transport for its lifetime; per-call contexts still come from the tasks service methods. Regression test drives a refresh through a stub token endpoint with an already-cancelled construction context, which fails on the old code with exactly the production error. Also covers Google omitting refresh_token on a refresh response, which would otherwise blank the stored one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B | |||
| 2026-08-16 | Replace Google Tasks service-account auth with real OAuth | Peter Stone | |
| Service-account auth structurally cannot see a regular user's personal task lists (no equivalent of Calendar's per-item sharing model) -- confirmed via GetTaskLists returning exactly the service account's own empty "My Tasks" list, never the real user's three lists. Zero rows were ever cached in production as a result. Adds a standard 3-legged OAuth flow: /settings/google-tasks/connect redirects to Google's consent screen (AccessTypeOffline+ApprovalForce so a refresh_token is always issued), /callback exchanges the code and persists the token (new oauth_tokens table), /disconnect clears it. GoogleTasksClient now takes an option.ClientOption instead of a credentials file path; NewGoogleTasksOAuthClient wraps it with a dbTokenSource that reloads/refreshes from the DB on each access-token expiry and re-persists -- carefully preserving the original refresh_token when Google's refresh response omits one (it usually does), which would otherwise silently and permanently break future refreshes. Settings page shows connection status and a Connect/Disconnect button. Calendar keeps using service-account auth (that one actually works). Requires a one-time manual step: create an OAuth 2.0 Client ID in Google Cloud Console and set GOOGLE_OAUTH_CLIENT_ID/SECRET in .env -- documented in .env.example. | |||
