package main import ( "fmt" "strings" ) // UpsertChannel — create or update a channel. Channels are lightweight tags. type UpsertChannel struct { Slug string Name string Description string } func (m *UpsertChannel) Kind() string { return "upsert_channel" } func (m *UpsertChannel) AffectedAuthors() []string { return nil // channels don't attribute to an author } func (m *UpsertChannel) Validate(s *Store) error { if strings.TrimSpace(m.Slug) == "" { return &ValidationError{Field: "slug", Message: "required"} } for _, r := range m.Slug { if r == ' ' || r == '\t' || r == '\n' || r == '/' { return &ValidationError{Field: "slug", Message: "must not contain whitespace or slashes"} } } if strings.TrimSpace(m.Name) == "" { return &ValidationError{Field: "name", Message: "required"} } return nil } func (m *UpsertChannel) Apply(s *Store, lock LockRegion) error { now := s.Now() c := &Channel{ Slug: m.Slug, Name: m.Name, Description: m.Description, CreatedAt: now, } s.mu.Lock() defer s.mu.Unlock() if existing, ok := s.channels[m.Slug]; ok { c.CreatedAt = existing.CreatedAt } s.channels[m.Slug] = c return nil } var _ = fmt.Sprintf // keep fmt for future error formatting