aboutsummaryrefslogtreecommitdiffstats
path: root/internal/store/design.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/store/design.go')
-rw-r--r--internal/store/design.go69
1 files changed, 69 insertions, 0 deletions
diff --git a/internal/store/design.go b/internal/store/design.go
new file mode 100644
index 0000000..4556d96
--- /dev/null
+++ b/internal/store/design.go
@@ -0,0 +1,69 @@
+package store
+
+import (
+ "context"
+ "encoding/json"
+)
+
+// SaveDesign stores the design form in one go: the theme, the modules of every
+// area and the menu, so a half-applied save is impossible. mods and menu are
+// the complete new state in display order: rows with an ID are updated, rows
+// without one inserted, and anything else is deleted.
+func (bs *BlogStore) SaveDesign(ctx context.Context, theme json.RawMessage, mods []Module, menu []MenuItem) error {
+ tx, err := bs.db.Begin(ctx)
+ if err != nil {
+ return err
+ }
+ defer tx.Rollback(ctx)
+ if _, err := tx.Exec(ctx, `UPDATE settings SET theme=$1, updated_at=now()`, theme); err != nil {
+ return err
+ }
+
+ keep := []int64{}
+ for _, m := range mods {
+ if m.ID != 0 {
+ keep = append(keep, m.ID)
+ }
+ }
+ if _, err := tx.Exec(ctx, `DELETE FROM modules WHERE id <> ALL($1)`, keep); err != nil {
+ return err
+ }
+ order := map[string]int{} // sort_order restarts in every area
+ for _, m := range mods {
+ pos := order[m.Area]
+ order[m.Area]++
+ if m.ID != 0 { // area and kind never change
+ _, err = tx.Exec(ctx, `UPDATE modules SET title=$2, body=$3, count=$4, sort_order=$5, updated_at=now() WHERE id=$1`, m.ID, m.Title, m.Body, m.Count, pos)
+ } else {
+ _, err = tx.Exec(ctx, `INSERT INTO modules (area, kind, title, body, count, sort_order) VALUES ($1,$2,$3,$4,$5,$6)`, m.Area, m.Kind, m.Title, m.Body, m.Count, pos)
+ }
+ if err != nil {
+ return wrap(err)
+ }
+ }
+
+ keep = keep[:0]
+ for _, it := range menu {
+ if it.ID != 0 {
+ keep = append(keep, it.ID)
+ }
+ }
+ if _, err := tx.Exec(ctx, `DELETE FROM menu_items WHERE id <> ALL($1)`, keep); err != nil {
+ return err
+ }
+ for i, it := range menu {
+ switch {
+ case it.ID != 0:
+ _, err = tx.Exec(ctx, `UPDATE menu_items SET label=$2, url=$3, sort_order=$4 WHERE id=$1`, it.ID, it.Label, it.URL, i)
+ case it.PageID != nil: // a page deleted meanwhile simply adds nothing
+ _, err = tx.Exec(ctx, `INSERT INTO menu_items (page_id, sort_order) SELECT id, $2 FROM pages WHERE id=$1
+ ON CONFLICT (page_id) WHERE page_id IS NOT NULL DO UPDATE SET sort_order=excluded.sort_order`, *it.PageID, i)
+ default:
+ _, err = tx.Exec(ctx, `INSERT INTO menu_items (label, url, sort_order) VALUES ($1,$2,$3)`, it.Label, it.URL, i)
+ }
+ if err != nil {
+ return wrap(err)
+ }
+ }
+ return tx.Commit(ctx)
+}