spread

https://git.tonybtw.com/spread.git git://git.tonybtw.com/spread.git
2,417 bytes raw
1
package app
2
3
import (
4
	"io"
5
	"net/http"
6
	"path/filepath"
7
	"strconv"
8
	"strings"
9
10
	"spread/internal/spread"
11
)
12
13
const maxUpload = 8 << 20
14
15
// handleAppAnalyze accepts a customer's uploaded BOM, re-quotes it against the
16
// live DB catalog, persists it under their subscriber, and shows the result.
17
func (a *App) handleAppAnalyze(w http.ResponseWriter, r *http.Request) {
18
	u, s, _ := current(r)
19
	ctx := r.Context()
20
21
	if err := r.ParseMultipartForm(maxUpload); err != nil {
22
		a.redirect(w, r, flash("/app", "err", "Could not read the upload."))
23
		return
24
	}
25
	f, hdr, err := r.FormFile("bom")
26
	if err != nil {
27
		a.redirect(w, r, flash("/app", "err", "Choose a BOM file to upload."))
28
		return
29
	}
30
	defer f.Close()
31
	data, _ := io.ReadAll(io.LimitReader(f, maxUpload))
32
33
	items, err := spread.ParseBOM(hdr.Filename, data)
34
	if err != nil {
35
		a.redirect(w, r, flash("/app", "err", err.Error()))
36
		return
37
	}
38
39
	cat, err := a.catalogSource(ctx)
40
	if err != nil {
41
		http.Error(w, err.Error(), http.StatusInternalServerError)
42
		return
43
	}
44
45
	ref := strings.TrimSpace(strings.TrimSuffix(filepath.Base(hdr.Filename), filepath.Ext(hdr.Filename)))
46
	if ref == "" {
47
		ref = "BOM"
48
	}
49
	rep := spread.AnalyzeWith(ref, items, cat)
50
51
	id, err := a.saveBOM(ctx, s.ID, u.ID, rep, hdr.Filename)
52
	if err != nil {
53
		http.Error(w, err.Error(), http.StatusInternalServerError)
54
		return
55
	}
56
	a.redirect(w, r, "/app/bom/"+strconv.FormatInt(id, 10))
57
}
58
59
// handleBOM shows one saved BOM. Customers see only their own; the internal
60
// subscriber can view any (admin BOM review).
61
func (a *App) handleBOM(w http.ResponseWriter, r *http.Request) {
62
	u, s, _ := current(r)
63
	id, _ := strconv.ParseInt(r.PathValue("id"), 10, 64)
64
65
	d, err := a.getBOM(r.Context(), id)
66
	if err != nil {
67
		http.Error(w, "BOM not found", http.StatusNotFound)
68
		return
69
	}
70
	if !s.IsInternal && d.SubscriberID != s.ID {
71
		http.Redirect(w, r, "/app", http.StatusSeeOther)
72
		return
73
	}
74
75
	back := "/app"
76
	if s.IsInternal {
77
		back = "/admin/boms"
78
	}
79
	a.render(w, r, http.StatusOK, "bom", pageData{Title: d.Ref, User: u, Sub: s, BOM: &d, BackURL: back})
80
}
81
82
// handleBOMs is the admin BOM-review list across all subscribers.
83
func (a *App) handleBOMs(w http.ResponseWriter, r *http.Request) {
84
	boms, err := a.listBOMs(r.Context(), nil)
85
	if err != nil {
86
		http.Error(w, err.Error(), http.StatusInternalServerError)
87
		return
88
	}
89
	a.render(w, r, http.StatusOK, "boms", pageData{Title: "BOMs", BOMs: boms})
90
}