Forget pushed event ids when Google Calendar is disconnected (Feature 16)
Disconnect deleted the connection but left every pushed plan synced with its stored event ids, though no calendar was chosen any more. It now deletes the connection and runs the same invalidation as choosing another calendar (forgetEvents: MarkCalendarPlansEdited, ClearCalendarEvents) in one transaction, under the account lock. A refused revoke still changes nothing. Tests push three weeks, disconnect, and check each is changed with no event id; then connect again, choose a calendar and push the whole week to it. Also: a refused revoke keeps every week synced, and a disconnect during a push waits for its record and then forgets it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+22
-11
@@ -96,10 +96,11 @@ func (s *Service) SelectCalendar(ctx context.Context, id string) (Selection, err
|
||||
// saveSelection stores sel as the chosen calendar. Choosing another calendar
|
||||
// than the one stored also forgets every plan day's calendar event id, in
|
||||
// the same transaction, since those events are on the calendar no longer
|
||||
// chosen: each plan with one is edited, so a synced plan becomes changed and
|
||||
// its next push writes every day to sel. The caller holds s.account, which a
|
||||
// push also holds from its event writes through recording them, so a push
|
||||
// never records events written to another calendar than the chosen one.
|
||||
// chosen (forgetEvents): each plan with one is edited, so a synced plan
|
||||
// becomes changed and its next push writes every day to sel. The caller
|
||||
// holds s.account, which a push also holds from its event writes through
|
||||
// recording them, so a push never records events written to another
|
||||
// calendar than the chosen one.
|
||||
func (s *Service) saveSelection(ctx context.Context, sel Selection) error {
|
||||
return s.st.WithTx(ctx, func(tx *sql.Tx) error {
|
||||
q := db.New(tx)
|
||||
@@ -123,16 +124,26 @@ func (s *Service) saveSelection(ctx context.Context, sel Selection) error {
|
||||
if row.CalendarID.Valid && row.CalendarID.String == sel.CalendarID {
|
||||
return nil
|
||||
}
|
||||
if err := q.MarkCalendarPlansEdited(ctx, now); err != nil {
|
||||
return fmt.Errorf("gcal: mark plans pushed to the earlier calendar edited: %w", err)
|
||||
}
|
||||
if err := q.ClearCalendarEvents(ctx, now); err != nil {
|
||||
return fmt.Errorf("gcal: forget events on the earlier calendar: %w", err)
|
||||
}
|
||||
return nil
|
||||
return forgetEvents(ctx, q, now)
|
||||
})
|
||||
}
|
||||
|
||||
// forgetEvents records, in the caller's transaction q, that no calendar
|
||||
// event id stored is on the chosen calendar any more: every plan with one is
|
||||
// edited (a synced plan becomes changed, and a push that read it before is
|
||||
// refused), then every id is cleared. Every change that ends the chosen
|
||||
// calendar — choosing another (saveSelection) or disconnecting
|
||||
// (Disconnect) — runs it in the transaction that makes the change.
|
||||
func forgetEvents(ctx context.Context, q *db.Queries, now string) error {
|
||||
if err := q.MarkCalendarPlansEdited(ctx, now); err != nil {
|
||||
return fmt.Errorf("gcal: mark plans pushed to the earlier calendar edited: %w", err)
|
||||
}
|
||||
if err := q.ClearCalendarEvents(ctx, now); err != nil {
|
||||
return fmt.Errorf("gcal: forget events on the earlier calendar: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// calendars lists the writable calendars, each once, with the stored refresh
|
||||
// token. The caller holds s.account.
|
||||
func (s *Service) calendars(ctx context.Context) ([]Calendar, error) {
|
||||
|
||||
Reference in New Issue
Block a user