121 lines
3.4 KiB
Go
121 lines
3.4 KiB
Go
package api
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"printer.backend/internal/model"
|
|
"printer.backend/internal/platepdf"
|
|
"printer.backend/internal/store"
|
|
)
|
|
|
|
func registerPDFRoutes(mux *http.ServeMux, configs *store.ConfigurationStore, plates *store.PlateStore, items *store.ItemStore) {
|
|
mux.HandleFunc("GET /layout/pdf", layoutPDF(plates, items))
|
|
mux.HandleFunc("GET /configurations/{id}/pdf", configurationPDF(configs, plates, items))
|
|
}
|
|
|
|
func layoutPDF(plates *store.PlateStore, items *store.ItemStore) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
plateID := r.URL.Query().Get("plate_id")
|
|
itemID := r.URL.Query().Get("item_id")
|
|
if plateID == "" || itemID == "" {
|
|
writeError(w, http.StatusBadRequest, errors.New("plate_id and item_id query params are required"))
|
|
return
|
|
}
|
|
spacing, err := parseSpacing(r.URL.Query().Get("spacing_mm"))
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
plate, item, preview, svgPath, err := resolveLayoutPDF(plates, items, plateID, itemID, spacing)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
pdf, err := platepdf.Generate(plate, item.Spec, svgPath, preview)
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
servePDF(w, pdf, "layout-preview.pdf")
|
|
}
|
|
}
|
|
|
|
func configurationPDF(configs *store.ConfigurationStore, plates *store.PlateStore, items *store.ItemStore) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
id := r.PathValue("id")
|
|
c, err := configs.Get(id)
|
|
if err != nil {
|
|
writeError(w, http.StatusNotFound, err)
|
|
return
|
|
}
|
|
|
|
plate, item, preview, svgPath, err := resolveLayoutPDF(plates, items, c.PlateID, c.ItemID, c.SpacingMM)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
pdf, err := platepdf.Generate(plate, item.Spec, svgPath, preview)
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
name := c.Name
|
|
if name == "" {
|
|
name = "configuration-" + id[:8]
|
|
}
|
|
servePDF(w, pdf, sanitizeFilename(name)+".pdf")
|
|
}
|
|
}
|
|
|
|
func resolveLayoutPDF(plates *store.PlateStore, items *store.ItemStore, plateID, itemID string, spacingMM float64) (
|
|
plate model.Plate, item model.Item, preview model.LayoutPreview, svgPath string, err error,
|
|
) {
|
|
plate, err = findPlate(plates, plateID)
|
|
if err != nil {
|
|
return plate, item, preview, "", err
|
|
}
|
|
item, err = items.Get(itemID)
|
|
if err != nil {
|
|
return plate, item, preview, "", err
|
|
}
|
|
svgPath, err = items.SVGPath(itemID)
|
|
if err != nil {
|
|
return plate, item, preview, "", err
|
|
}
|
|
preview, err = buildPreview(plates, items, plateID, itemID, spacingMM)
|
|
if err != nil {
|
|
return plate, item, preview, "", err
|
|
}
|
|
preview.PlateID = plateID
|
|
preview.ItemID = itemID
|
|
return plate, item, preview, svgPath, nil
|
|
}
|
|
|
|
func servePDF(w http.ResponseWriter, pdf []byte, filename string) {
|
|
w.Header().Set("Content-Type", "application/pdf")
|
|
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename))
|
|
w.Header().Set("Cache-Control", "no-cache")
|
|
_, _ = w.Write(pdf)
|
|
}
|
|
|
|
func sanitizeFilename(name string) string {
|
|
var b []byte
|
|
for i := 0; i < len(name); i++ {
|
|
c := name[i]
|
|
if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '_' {
|
|
b = append(b, c)
|
|
} else if c == ' ' {
|
|
b = append(b, '_')
|
|
}
|
|
}
|
|
if len(b) == 0 {
|
|
return "preview"
|
|
}
|
|
return string(b)
|
|
}
|