| 1 | package calendar |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "time" |
| 6 | |
| 7 | "amadan.net/rastrillo/rastrillo/scope" |
| 8 | "gorm.io/gorm" |
| 9 | ) |
| 10 | |
| 11 | // An exception belongs to the series containing its original occurrence, |
| 12 | // even when someone moved it across the split date. Cancelled exceptions |
| 13 | // move too, so splitting cannot restore a deleted occurrence. |
| 14 | func moveSplitOverrides(tx *gorm.DB, personID int64, master, tail Event, cut time.Time) error { |
| 15 | writable := func() *gorm.DB { |
| 16 | return splitWritableEvents(tx, personID, master.CalendarID).Where("series_id = ?", master.ID) |
| 17 | } |
| 18 | var overrides []Event |
| 19 | if err := writable().Find(&overrides).Error; err != nil { |
| 20 | return err |
| 21 | } |
| 22 | loc, err := Zone(master.TZ) |
| 23 | if err != nil { |
| 24 | return err |
| 25 | } |
| 26 | now := time.Now().UTC() |
| 27 | for _, override := range overrides { |
| 28 | original, _, err := ParseLocal(override.RecurrenceIDLocal, loc) |
| 29 | if err != nil { |
| 30 | return fmt.Errorf("calendar: read split occurrence: %w", err) |
| 31 | } |
| 32 | if original.Before(cut) { |
| 33 | continue |
| 34 | } |
| 35 | updates := map[string]any{"series_id": tail.ID, "uid_hash": tail.UIDHash, "uid_sealed": tail.UIDSealed, "sequence": gorm.Expr("sequence + 1"), "updated_at": now} |
| 36 | result := writable().Where("id = ?", override.ID). |
| 37 | Select("series_id", "uid_hash", "uid_sealed", "sequence", "updated_at").Updates(updates) |
| 38 | if result.Error != nil { |
| 39 | return result.Error |
| 40 | } |
| 41 | if result.RowsAffected != 1 { |
| 42 | return ErrNotFound |
| 43 | } |
| 44 | } |
| 45 | return nil |
| 46 | } |
| 47 | |
| 48 | func splitWritableEvents(tx *gorm.DB, personID, calendarID int64) *gorm.DB { |
| 49 | calendars := scope.OwnedBy(tx.Model(&Grant{}), "person_id", personID). |
| 50 | Select("calendar_id").Where("role IN ?", []string{RoleOwner, RoleEditor}) |
| 51 | return tx.Model(&Event{}).Where("calendar_id = ? AND calendar_id IN (?)", calendarID, calendars) |
| 52 | } |
| 53 | |