diff options
Diffstat (limited to 'internal/store')
| -rw-r--r-- | internal/store/sections.go | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/internal/store/sections.go b/internal/store/sections.go new file mode 100644 index 0000000..f112102 --- /dev/null +++ b/internal/store/sections.go @@ -0,0 +1,114 @@ +package store + +import ( + "context" + "time" +) + +// Section is an announcement shown on every page and post of a blog. +type Section struct { + ID int64 + BlogID int64 + Title string + BodyMD string + BodyHTML string + Placement string // above | below | sidebar + Style string // plain | note | warning + Enabled bool + SortOrder int + CreatedAt time.Time + UpdatedAt time.Time +} + +const sectionCols = `id, blog_id, title, body_md, body_html, placement, style, enabled, sort_order, created_at, updated_at` + +func scanSection(row interface{ Scan(...any) error }) (*Section, error) { + var s Section + err := row.Scan(&s.ID, &s.BlogID, &s.Title, &s.BodyMD, &s.BodyHTML, &s.Placement, &s.Style, &s.Enabled, &s.SortOrder, &s.CreatedAt, &s.UpdatedAt) + if err != nil { + return nil, wrap(err) + } + return &s, nil +} + +func (s *Store) collectSections(ctx context.Context, q string, args ...any) ([]Section, error) { + rows, err := s.db.Query(ctx, q, args...) + if err != nil { + return nil, err + } + defer rows.Close() + var out []Section + for rows.Next() { + sec, err := scanSection(rows) + if err != nil { + return nil, err + } + out = append(out, *sec) + } + return out, rows.Err() +} + +func (s *Store) ListSections(ctx context.Context, blogID int64) ([]Section, error) { + return s.collectSections(ctx, `SELECT `+sectionCols+` FROM sections WHERE blog_id=$1 ORDER BY sort_order, id`, blogID) +} + +// EnabledSections is what the public blog renders. +func (s *Store) EnabledSections(ctx context.Context, blogID int64) ([]Section, error) { + return s.collectSections(ctx, `SELECT `+sectionCols+` FROM sections WHERE blog_id=$1 AND enabled ORDER BY sort_order, id`, blogID) +} + +func (s *Store) SectionByID(ctx context.Context, blogID, id int64) (*Section, error) { + return scanSection(s.db.QueryRow(ctx, `SELECT `+sectionCols+` FROM sections WHERE blog_id=$1 AND id=$2`, blogID, id)) +} + +func (s *Store) CreateSection(ctx context.Context, sec *Section) (*Section, error) { + return scanSection(s.db.QueryRow(ctx, `INSERT INTO sections (blog_id, title, body_md, body_html, placement, style, enabled, sort_order) + VALUES ($1,$2,$3,$4,$5,$6,$7,(SELECT coalesce(max(sort_order),-1)+1 FROM sections WHERE blog_id=$1)) RETURNING `+sectionCols, + sec.BlogID, sec.Title, sec.BodyMD, sec.BodyHTML, sec.Placement, sec.Style, sec.Enabled)) +} + +func (s *Store) UpdateSection(ctx context.Context, sec *Section) error { + _, err := s.db.Exec(ctx, `UPDATE sections SET title=$3, body_md=$4, body_html=$5, placement=$6, style=$7, enabled=$8, updated_at=now() WHERE blog_id=$1 AND id=$2`, + sec.BlogID, sec.ID, sec.Title, sec.BodyMD, sec.BodyHTML, sec.Placement, sec.Style, sec.Enabled) + return wrap(err) +} + +func (s *Store) SetSectionEnabled(ctx context.Context, blogID, id int64, on bool) error { + _, err := s.db.Exec(ctx, `UPDATE sections SET enabled=$3, updated_at=now() WHERE blog_id=$1 AND id=$2`, blogID, id, on) + return err +} + +func (s *Store) DeleteSection(ctx context.Context, blogID, id int64) error { + _, err := s.db.Exec(ctx, `DELETE FROM sections WHERE blog_id=$1 AND id=$2`, blogID, id) + return err +} + +// MoveSection swaps sort_order with the neighbouring section (dir = -1 up, +1 down). +func (s *Store) MoveSection(ctx context.Context, blogID, id int64, dir int) error { + secs, err := s.ListSections(ctx, blogID) + if err != nil { + return err + } + idx := -1 + for i := range secs { + if secs[i].ID == id { + idx = i + } + } + j := idx + dir + if idx < 0 || j < 0 || j >= len(secs) { + return nil + } + secs[idx], secs[j] = secs[j], secs[idx] + tx, err := s.db.Begin(ctx) + if err != nil { + return err + } + defer tx.Rollback(ctx) + for i, sec := range secs { // renumber everything; keeps orders dense + if _, err := tx.Exec(ctx, `UPDATE sections SET sort_order=$3 WHERE blog_id=$1 AND id=$2`, blogID, sec.ID, i); err != nil { + return err + } + } + return tx.Commit(ctx) +} |
