diff options
Diffstat (limited to 'internal/store/pages.go')
| -rw-r--r-- | internal/store/pages.go | 70 |
1 files changed, 64 insertions, 6 deletions
diff --git a/internal/store/pages.go b/internal/store/pages.go index 3fdc492..2a69d99 100644 --- a/internal/store/pages.go +++ b/internal/store/pages.go @@ -3,10 +3,20 @@ package store import ( "context" "time" + + "github.com/google/uuid" +) + +// Page kinds: what a page shows under its intro. Everything but posts is a +// "special page"; the list is also a CHECK constraint on pages.kind. +const ( + PageKindPosts = "posts" + PageKindGallery = "gallery" // every library image, except the hidden ones ) type Page struct { ID int64 + Kind string // PageKindPosts | PageKindGallery; set at creation, never changed Slug string Title string IntroMD string @@ -22,11 +32,21 @@ type Page struct { PostCount int // filled by ListPages only } -const pageCols = `id, slug, title, intro_md, intro_html, outro_md, outro_html, format, nav_order, EXISTS (SELECT 1 FROM menu_items m WHERE m.page_id=pages.id), show_notices, is_home, created_at` +// Special is a page that shows something other than posts. +func (p *Page) Special() bool { return p.Kind != PageKindPosts } + +func kindOrPosts(k string) string { + if k == PageKindGallery { + return k + } + return PageKindPosts +} + +const pageCols = `id, kind, slug, title, intro_md, intro_html, outro_md, outro_html, format, nav_order, EXISTS (SELECT 1 FROM menu_items m WHERE m.page_id=pages.id), show_notices, is_home, created_at` func scanPage(row interface{ Scan(...any) error }) (*Page, error) { var p Page - err := row.Scan(&p.ID, &p.Slug, &p.Title, &p.IntroMD, &p.IntroHTML, &p.OutroMD, &p.OutroHTML, &p.Format, &p.NavOrder, &p.ShowInNav, &p.ShowNotices, &p.IsHome, &p.CreatedAt) + err := row.Scan(&p.ID, &p.Kind, &p.Slug, &p.Title, &p.IntroMD, &p.IntroHTML, &p.OutroMD, &p.OutroHTML, &p.Format, &p.NavOrder, &p.ShowInNav, &p.ShowNotices, &p.IsHome, &p.CreatedAt) if err != nil { return nil, wrap(err) } @@ -43,7 +63,7 @@ func (bs *BlogStore) ListPages(ctx context.Context) ([]Page, error) { var out []Page for rows.Next() { var p Page - if err := rows.Scan(&p.ID, &p.Slug, &p.Title, &p.IntroMD, &p.IntroHTML, &p.OutroMD, &p.OutroHTML, &p.Format, &p.NavOrder, &p.ShowInNav, &p.ShowNotices, &p.IsHome, &p.CreatedAt, &p.PostCount); err != nil { + if err := rows.Scan(&p.ID, &p.Kind, &p.Slug, &p.Title, &p.IntroMD, &p.IntroHTML, &p.OutroMD, &p.OutroHTML, &p.Format, &p.NavOrder, &p.ShowInNav, &p.ShowNotices, &p.IsHome, &p.CreatedAt, &p.PostCount); err != nil { return nil, err } out = append(out, p) @@ -71,9 +91,9 @@ func (bs *BlogStore) CreatePage(ctx context.Context, p *Page) (*Page, error) { return nil, err } defer tx.Rollback(ctx) - created, err := scanPage(tx.QueryRow(ctx, `INSERT INTO pages (slug, title, intro_md, intro_html, outro_md, outro_html, format, show_notices, nav_order) - VALUES ($1,$2,$3,$4,$5,$6,$7,$8,(SELECT coalesce(max(nav_order),-1)+1 FROM pages)) RETURNING `+pageCols, - p.Slug, p.Title, p.IntroMD, p.IntroHTML, p.OutroMD, p.OutroHTML, formatOrMD(p.Format), p.ShowNotices)) + created, err := scanPage(tx.QueryRow(ctx, `INSERT INTO pages (kind, slug, title, intro_md, intro_html, outro_md, outro_html, format, show_notices, nav_order) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,(SELECT coalesce(max(nav_order),-1)+1 FROM pages)) RETURNING `+pageCols, + kindOrPosts(p.Kind), p.Slug, p.Title, p.IntroMD, p.IntroHTML, p.OutroMD, p.OutroHTML, formatOrMD(p.Format), p.ShowNotices)) if err != nil { return nil, err } @@ -87,6 +107,7 @@ func (bs *BlogStore) CreatePage(ctx context.Context, p *Page) (*Page, error) { } // UpdatePage saves the page and keeps its menu entry in step with ShowInNav. +// The kind is not touched: a page is what it was created as. func (bs *BlogStore) UpdatePage(ctx context.Context, p *Page) error { tx, err := bs.db.Begin(ctx) if err != nil { @@ -160,3 +181,40 @@ func (bs *BlogStore) MovePage(ctx context.Context, id int64, dir int) error { } return tx.Commit(ctx) } + +// HiddenFiles lists the library files a gallery page leaves out. +func (bs *BlogStore) HiddenFiles(ctx context.Context, pageID int64) (map[string]bool, error) { + rows, err := bs.db.Query(ctx, `SELECT file_id FROM page_hidden_files WHERE page_id=$1`, pageID) + if err != nil { + return nil, err + } + defer rows.Close() + out := map[string]bool{} + for rows.Next() { + var id uuid.UUID + if err := rows.Scan(&id); err != nil { + return nil, err + } + out[id.String()] = true + } + return out, rows.Err() +} + +// SetHiddenFiles makes ids the files a gallery page leaves out. Ids of files +// that are gone are skipped rather than refused: the form was rendered before +// the deletion. +func (bs *BlogStore) SetHiddenFiles(ctx context.Context, pageID int64, ids []uuid.UUID) error { + tx, err := bs.db.Begin(ctx) + if err != nil { + return err + } + defer tx.Rollback(ctx) + if _, err := tx.Exec(ctx, `DELETE FROM page_hidden_files WHERE page_id=$1`, pageID); err != nil { + return err + } + if _, err := tx.Exec(ctx, `INSERT INTO page_hidden_files (page_id, file_id) + SELECT $1, id FROM files WHERE id = ANY($2)`, pageID, ids); err != nil { + return err + } + return tx.Commit(ctx) +} |
