package models import ( "bytes" "context" "fmt" "time" community "tangled.org/pds.dad/whens-lunch/api/community" "github.com/bluesky-social/indigo/atproto/syntax" "gorm.io/gorm" "gorm.io/gorm/clause" ) type JetStreamCursor struct { Url string `gorm:"primaryKey"` Cursor int64 `gorm:"not null"` } type CalendarEvent struct { URI string `gorm:"primaryKey;column:uri"` RepoDID string `gorm:"not null;column:repo_did"` StartsAt time.Time `gorm:"column:starts_at;index:idx_starts_at"` EndsAt time.Time `gorm:"column:ends_at"` RecordCreatedAt time.Time `gorm:"column:record_created_at"` CreatedAt time.Time `gorm:"column:created_at"` UpdatedAt time.Time `gorm:"column:updated_at"` Record []byte `gorm:"not null;column:record"` } func AddOrUpdateEvent(ctx context.Context, DB *gorm.DB, event *community.CalendarEvent, aturi syntax.ATURI) error { repoDID := aturi.Authority().String() buf := bytes.Buffer{} err := event.MarshalCBOR(&buf) if err != nil { return fmt.Errorf("failed to marshal event: %w", err) } createdAt, err := time.Parse(time.RFC3339, event.CreatedAt) if err != nil { return fmt.Errorf("invalid createdAt: %w", err) } dbEvent := &CalendarEvent{ URI: aturi.String(), RepoDID: repoDID, Record: buf.Bytes(), RecordCreatedAt: createdAt, } if event.StartsAt != nil { startsAt, err := time.Parse(time.RFC3339, *event.StartsAt) if err != nil { return fmt.Errorf("invalid startsAt: %w", err) } dbEvent.StartsAt = startsAt } if event.EndsAt != nil { endsAt, err := time.Parse(time.RFC3339, *event.EndsAt) if err != nil { return fmt.Errorf("invalid endsAt: %w", err) } dbEvent.EndsAt = endsAt } err = DB.WithContext(ctx).Save(dbEvent).Error if err != nil { return fmt.Errorf("failed to add/update event: %w", err) } return nil } type RsvpEvent struct { URI string `gorm:"primaryKey;column:uri"` RepoDID string `gorm:"not null;column:repo_did;index;uniqueIndex:idx_rsvp_repo_event"` EventURI string `gorm:"not null;column:event_uri;index;uniqueIndex:idx_rsvp_repo_event"` Status string `gorm:"not null;column:status"` CreatedAt time.Time `gorm:"column:created_at"` UpdatedAt time.Time `gorm:"column:updated_at"` Record []byte `gorm:"not null;column:record"` Event CalendarEvent `gorm:"foreignKey:EventURI;references:URI"` } func AddOrUpdateRsvp(ctx context.Context, DB *gorm.DB, rsvp *community.CalendarRsvp, aturi syntax.ATURI) error { repoDID := aturi.Authority().String() buf := bytes.Buffer{} err := rsvp.MarshalCBOR(&buf) if err != nil { return fmt.Errorf("failed to marshal rsvp: %w", err) } if rsvp.Subject == nil { return fmt.Errorf("rsvp subject is nil") } dbRsvp := &RsvpEvent{ URI: aturi.String(), RepoDID: repoDID, EventURI: rsvp.Subject.Uri, Status: rsvp.Status, Record: buf.Bytes(), } err = DB.WithContext(ctx).Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "repo_did"}, {Name: "event_uri"}}, UpdateAll: true, }).Create(dbRsvp).Error if err != nil { return fmt.Errorf("failed to add/update rsvp: %w", err) } return nil }