spread

https://git.tonybtw.com/spread.git git://git.tonybtw.com/spread.git
4,456 bytes raw
1
package app
2
3
import (
4
	"net/http"
5
	"net/url"
6
	"strconv"
7
	"strings"
8
)
9
10
func (a *App) redirect(w http.ResponseWriter, r *http.Request, path string) {
11
	http.Redirect(w, r, path, http.StatusSeeOther)
12
}
13
14
// flash builds a redirect target with a notice or error query param.
15
func flash(path, key, msg string) string {
16
	return path + "?" + key + "=" + url.QueryEscape(msg)
17
}
18
19
func (a *App) handleAdmin(w http.ResponseWriter, r *http.Request) {
20
	u, s, _ := current(r)
21
	d := pageData{Title: "Overview", User: u, Sub: s}
22
	d.Counts.Subs, d.Counts.Users, d.Counts.Catalog, d.Counts.Boms = a.counts(r.Context())
23
	a.render(w, r, http.StatusOK, "admin", d)
24
}
25
26
// --- catalog --------------------------------------------------------------
27
28
func (a *App) handleCatalog(w http.ResponseWriter, r *http.Request) {
29
	ctx := r.Context()
30
	entries, err := a.listCatalog(ctx)
31
	if err != nil {
32
		http.Error(w, err.Error(), http.StatusInternalServerError)
33
		return
34
	}
35
	d := pageData{
36
		Title:   "Catalog",
37
		Catalog: entries,
38
		Notice:  r.URL.Query().Get("notice"),
39
		Error:   r.URL.Query().Get("err"),
40
	}
41
	if pn := r.URL.Query().Get("edit"); pn != "" {
42
		if e, err := a.getCatalogEntry(ctx, pn); err == nil {
43
			d.Edit = &e
44
		}
45
	}
46
	a.render(w, r, http.StatusOK, "catalog", d)
47
}
48
49
func (a *App) handleCatalogSave(w http.ResponseWriter, r *http.Request) {
50
	pn := strings.TrimSpace(r.PostFormValue("part_number"))
51
	desc := strings.TrimSpace(r.PostFormValue("description"))
52
	price, perr := strconv.ParseFloat(strings.TrimSpace(r.PostFormValue("spread_price")), 64)
53
	if pn == "" || perr != nil || price <= 0 {
54
		a.redirect(w, r, flash("/admin/catalog", "err", "Part number and a positive spread price are required."))
55
		return
56
	}
57
	if err := a.upsertCatalog(r.Context(), pn, desc, price); err != nil {
58
		a.redirect(w, r, flash("/admin/catalog", "err", err.Error()))
59
		return
60
	}
61
	a.redirect(w, r, flash("/admin/catalog", "notice", "Saved "+pn+"."))
62
}
63
64
func (a *App) handleCatalogDelete(w http.ResponseWriter, r *http.Request) {
65
	pn := strings.TrimSpace(r.PostFormValue("part_number"))
66
	if pn != "" {
67
		_ = a.deleteCatalog(r.Context(), pn)
68
	}
69
	a.redirect(w, r, flash("/admin/catalog", "notice", "Deleted "+pn+"."))
70
}
71
72
func (a *App) handleCatalogSeed(w http.ResponseWriter, r *http.Request) {
73
	if err := a.seedDemoCatalog(r.Context()); err != nil {
74
		a.redirect(w, r, flash("/admin/catalog", "err", err.Error()))
75
		return
76
	}
77
	a.redirect(w, r, flash("/admin/catalog", "notice", "Seeded the demo catalog."))
78
}
79
80
// --- subscribers & users --------------------------------------------------
81
82
func (a *App) handleSubscribers(w http.ResponseWriter, r *http.Request) {
83
	subs, err := a.listSubscribers(r.Context())
84
	if err != nil {
85
		http.Error(w, err.Error(), http.StatusInternalServerError)
86
		return
87
	}
88
	a.render(w, r, http.StatusOK, "subscribers", pageData{
89
		Title:  "Subscribers",
90
		Subs:   subs,
91
		Notice: r.URL.Query().Get("notice"),
92
		Error:  r.URL.Query().Get("err"),
93
	})
94
}
95
96
func (a *App) handleSubscriberCreate(w http.ResponseWriter, r *http.Request) {
97
	name := strings.TrimSpace(r.PostFormValue("name"))
98
	if name == "" {
99
		a.redirect(w, r, flash("/admin/subscribers", "err", "Subscriber name is required."))
100
		return
101
	}
102
	if _, err := a.createSubscriber(r.Context(), name); err != nil {
103
		a.redirect(w, r, flash("/admin/subscribers", "err", err.Error()))
104
		return
105
	}
106
	a.redirect(w, r, flash("/admin/subscribers", "notice", "Created subscriber "+name+"."))
107
}
108
109
func (a *App) handleUserCreate(w http.ResponseWriter, r *http.Request) {
110
	subID, _ := strconv.ParseInt(r.PostFormValue("subscriber_id"), 10, 64)
111
	email := strings.TrimSpace(r.PostFormValue("email"))
112
	name := strings.TrimSpace(r.PostFormValue("name"))
113
	password := r.PostFormValue("password")
114
	if subID == 0 || email == "" {
115
		a.redirect(w, r, flash("/admin/subscribers", "err", "Subscriber and email are required."))
116
		return
117
	}
118
	uid, err := a.createUser(r.Context(), subID, email, name, password)
119
	if err != nil {
120
		a.redirect(w, r, flash("/admin/subscribers", "err", err.Error()))
121
		return
122
	}
123
	if password == "" {
124
		if err := a.sendInvite(r.Context(), uid, email); err != nil {
125
			a.redirect(w, r, flash("/admin/subscribers", "err", "Created "+email+", but the invite email failed: "+err.Error()))
126
			return
127
		}
128
		a.redirect(w, r, flash("/admin/subscribers", "notice", "Created "+email+" and emailed an invite to set a password."))
129
		return
130
	}
131
	a.redirect(w, r, flash("/admin/subscribers", "notice", "Created user "+email+"."))
132
}