90 lines
2.6 KiB
Go
90 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// handleSettings persists the listing view/sort/order to the folder's
|
|
// .page-settings file. Values are validated against the allowed sets (unknown
|
|
// values fall back to defaults). Triggered by POST /{path}?settings.
|
|
func (h *handler) handleSettings(w http.ResponseWriter, r *http.Request, urlPath, fsPath string) {
|
|
if err := r.ParseForm(); err != nil {
|
|
http.Error(w, "bad request", http.StatusBadRequest)
|
|
return
|
|
}
|
|
view := validateView(r.FormValue("view"))
|
|
sortKey := validateSort(r.FormValue("sort"))
|
|
order := validateOrder(r.FormValue("order"))
|
|
|
|
if err := writePageSettings(fsPath, view, sortKey, order); err != nil {
|
|
http.Error(w, "write failed: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
http.Redirect(w, r, urlPath, http.StatusSeeOther)
|
|
}
|
|
|
|
// writePageSettings performs a read-modify-write of <dir>/.page-settings,
|
|
// updating the view/sort/order lines while preserving every other line
|
|
// (other keys, comments, blank lines, ordering) verbatim. Missing keys are
|
|
// appended. The write is atomic (temp file + rename).
|
|
func writePageSettings(dir, view, sortKey, order string) error {
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
return err
|
|
}
|
|
p := filepath.Join(dir, ".page-settings")
|
|
existing, err := os.ReadFile(p)
|
|
if err != nil && !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
updated := updateSettingsLines(existing, view, sortKey, order)
|
|
return writeFileAtomic(p, updated, 0644)
|
|
}
|
|
|
|
// updateSettingsLines rewrites the view/sort/order lines in existing while
|
|
// leaving all other lines untouched. Every occurrence of a known key is
|
|
// updated (so the reader's last-wins parse stays consistent); keys absent from
|
|
// the file are appended in a stable order. The result always ends in a newline.
|
|
func updateSettingsLines(existing []byte, view, sortKey, order string) []byte {
|
|
targets := map[string]string{"view": view, "sort": sortKey, "order": order}
|
|
appendOrder := []string{"view", "sort", "order"}
|
|
seen := map[string]bool{}
|
|
|
|
var lines []string
|
|
if len(existing) > 0 {
|
|
s := string(existing)
|
|
s = strings.TrimSuffix(s, "\n")
|
|
lines = strings.Split(s, "\n")
|
|
}
|
|
|
|
for i, line := range lines {
|
|
trimmed := strings.TrimSpace(line)
|
|
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
|
|
continue
|
|
}
|
|
eq := strings.IndexByte(line, '=')
|
|
if eq < 0 {
|
|
continue
|
|
}
|
|
key := strings.TrimSpace(line[:eq])
|
|
if val, ok := targets[key]; ok {
|
|
lines[i] = key + " = " + val
|
|
seen[key] = true
|
|
}
|
|
}
|
|
|
|
for _, k := range appendOrder {
|
|
if !seen[k] {
|
|
lines = append(lines, k+" = "+targets[k])
|
|
}
|
|
}
|
|
|
|
out := strings.Join(lines, "\n")
|
|
if out != "" {
|
|
out += "\n"
|
|
}
|
|
return []byte(out)
|
|
}
|