Eric Bower
·
2026-03-10
auto_form.go
1package pgs
2
3import (
4 "net/http"
5
6 "github.com/picosh/pico/pkg/shared/router"
7)
8
9func handleAutoForm(w http.ResponseWriter, r *http.Request, cfg *PgsConfig) {
10 formName := r.PathValue("fname")
11 if r.Method != http.MethodPost {
12 http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
13 return
14 }
15
16 err := r.ParseForm()
17 if err != nil {
18 cfg.Logger.Error("failed to parse auto form", "err", err)
19 http.Error(w, "failed to parse auto form", http.StatusBadRequest)
20 return
21 }
22
23 formValues := make(map[string]interface{})
24 for key, values := range r.PostForm {
25 if len(values) == 1 {
26 formValues[key] = values[0]
27 } else if len(values) > 1 {
28 formValues[key] = values
29 }
30 }
31
32 subdomain := router.GetSubdomainFromRequest(r, cfg.Domain, cfg.TxtPrefix)
33 props, err := router.GetProjectFromSubdomain(subdomain)
34 if err != nil {
35 cfg.Logger.Error("could not get project from subdomain", "subdomain", subdomain, "err", err)
36 http.Error(w, "not found", http.StatusNotFound)
37 return
38 }
39
40 user, err := cfg.DB.FindUserByName(props.Username)
41 if err != nil {
42 cfg.Logger.Error("user not found", "username", props.Username)
43 http.Error(w, "not found", http.StatusNotFound)
44 return
45 }
46
47 ff, err := cfg.DB.FindFeature(user.ID, "plus")
48 if err != nil || (ff != nil && !ff.IsValid()) {
49 cfg.Logger.Error("pico+ required for auto-forms", "username", props.Username)
50 http.Error(w, "pico+ required for auto-forms", http.StatusPaymentRequired)
51 return
52 }
53
54 err = cfg.DB.InsertFormEntry(user.ID, formName, formValues)
55 if err != nil {
56 cfg.Logger.Error("failed to save form data", "err", err)
57 http.Error(w, "failed to save form data", http.StatusInternalServerError)
58 return
59 }
60
61 serveAutoFormSubmitted(w, r, cfg)
62}
63
64type FormData struct {
65 Error string
66}
67
68func serveAutoFormSubmitted(w http.ResponseWriter, r *http.Request, cfg *PgsConfig) {
69 errorMsg := r.URL.Query().Get("error")
70 data := loginFormData{
71 Error: errorMsg,
72 }
73
74 w.WriteHeader(http.StatusUnprocessableEntity)
75
76 ts, err := renderTemplate(cfg, []string{cfg.StaticPath("html/auto_form.page.tmpl")})
77 if err != nil {
78 cfg.Logger.Error("could not render auto form template", "err", err.Error())
79 http.Error(w, "Server error", http.StatusInternalServerError)
80 return
81 }
82
83 err = ts.Execute(w, data)
84 if err != nil {
85 cfg.Logger.Error("could not execute login template", "err", err.Error())
86 http.Error(w, "Server error", http.StatusInternalServerError)
87 }
88}