Added PDF Generation
This commit is contained in:
@@ -18,6 +18,7 @@ func registerConfigurationRoutes(mux *http.ServeMux, configs *store.Configuratio
|
||||
mux.HandleFunc("DELETE /configurations/{id}", deleteConfiguration(configs))
|
||||
mux.HandleFunc("GET /configurations/{id}/preview", previewConfiguration(configs, plates, items))
|
||||
mux.HandleFunc("GET /layout/preview", layoutPreview(plates, items))
|
||||
registerPDFRoutes(mux, configs, plates, items)
|
||||
}
|
||||
|
||||
type configurationResponse struct {
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user