256 lines
6.9 KiB
Go
256 lines
6.9 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"time"
|
|
|
|
"printer.backend/internal/model"
|
|
"printer.backend/internal/printjob"
|
|
"printer.backend/internal/store"
|
|
)
|
|
|
|
func registerPrintJobRoutes(
|
|
mux *http.ServeMux,
|
|
jobs *store.PrintJobStore,
|
|
configs *store.ConfigurationStore,
|
|
plates *store.PlateStore,
|
|
items *store.ItemStore,
|
|
orders *store.OrderStore,
|
|
) {
|
|
mux.HandleFunc("GET /print-jobs", listPrintJobs(jobs, configs, plates, items, orders))
|
|
mux.HandleFunc("POST /print-jobs", savePrintJob(jobs, configs, orders))
|
|
mux.HandleFunc("GET /print-jobs/{id}", getPrintJob(jobs, configs, plates, items, orders))
|
|
mux.HandleFunc("PUT /print-jobs/{id}", updatePrintJob(jobs, configs, orders))
|
|
mux.HandleFunc("DELETE /print-jobs/{id}", deletePrintJob(jobs))
|
|
mux.HandleFunc("GET /print-jobs/{id}/summary", printJobSummary(jobs, configs, plates, items, orders))
|
|
mux.HandleFunc("GET /print-jobs/{id}/pdf", printJobPDF(jobs, configs, plates, items, orders))
|
|
}
|
|
|
|
type printJobResponse struct {
|
|
model.PrintJob
|
|
Summary *model.PrintJobSummary `json:"summary,omitempty"`
|
|
}
|
|
|
|
type savePrintJobRequest struct {
|
|
Name string `json:"name"`
|
|
ConfigurationID string `json:"configuration_id"`
|
|
OrderIDs []string `json:"order_ids"`
|
|
}
|
|
|
|
func listPrintJobs(
|
|
jobs *store.PrintJobStore,
|
|
configs *store.ConfigurationStore,
|
|
plates *store.PlateStore,
|
|
items *store.ItemStore,
|
|
orders *store.OrderStore,
|
|
) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, _ *http.Request) {
|
|
list, err := jobs.List()
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
if list == nil {
|
|
list = []model.PrintJob{}
|
|
}
|
|
out := make([]printJobResponse, 0, len(list))
|
|
for _, j := range list {
|
|
out = append(out, printJobResponseFor(j, configs, plates, items, orders))
|
|
}
|
|
writeJSON(w, http.StatusOK, out)
|
|
}
|
|
}
|
|
|
|
func savePrintJob(jobs *store.PrintJobStore, configs *store.ConfigurationStore, orders *store.OrderStore) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
var req savePrintJobRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
if err := validatePrintJobRequest(req, configs, orders); err != nil {
|
|
writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
j := model.PrintJob{
|
|
Name: req.Name,
|
|
ConfigurationID: req.ConfigurationID,
|
|
OrderIDs: req.OrderIDs,
|
|
CreatedAt: time.Now().UTC(),
|
|
}
|
|
saved, err := jobs.Save(j)
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusCreated, saved)
|
|
}
|
|
}
|
|
|
|
func getPrintJob(
|
|
jobs *store.PrintJobStore,
|
|
configs *store.ConfigurationStore,
|
|
plates *store.PlateStore,
|
|
items *store.ItemStore,
|
|
orders *store.OrderStore,
|
|
) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
j, err := jobs.Get(r.PathValue("id"))
|
|
if err != nil {
|
|
writeError(w, http.StatusNotFound, err)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, printJobResponseFor(j, configs, plates, items, orders))
|
|
}
|
|
}
|
|
|
|
func updatePrintJob(jobs *store.PrintJobStore, configs *store.ConfigurationStore, orders *store.OrderStore) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
id := r.PathValue("id")
|
|
var req savePrintJobRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
if err := validatePrintJobRequest(req, configs, orders); err != nil {
|
|
writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
j := model.PrintJob{
|
|
Name: req.Name,
|
|
ConfigurationID: req.ConfigurationID,
|
|
OrderIDs: req.OrderIDs,
|
|
}
|
|
saved, err := jobs.Update(id, j)
|
|
if err != nil {
|
|
writeError(w, http.StatusNotFound, err)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, saved)
|
|
}
|
|
}
|
|
|
|
func deletePrintJob(jobs *store.PrintJobStore) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
if err := jobs.Delete(r.PathValue("id")); err != nil {
|
|
writeError(w, http.StatusNotFound, err)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
}
|
|
|
|
func printJobSummary(
|
|
jobs *store.PrintJobStore,
|
|
configs *store.ConfigurationStore,
|
|
plates *store.PlateStore,
|
|
items *store.ItemStore,
|
|
orders *store.OrderStore,
|
|
) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
j, err := jobs.Get(r.PathValue("id"))
|
|
if err != nil {
|
|
writeError(w, http.StatusNotFound, err)
|
|
return
|
|
}
|
|
summary, err := buildPrintJobSummary(j, configs, plates, items, orders)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, summary)
|
|
}
|
|
}
|
|
|
|
func printJobPDF(
|
|
jobs *store.PrintJobStore,
|
|
configs *store.ConfigurationStore,
|
|
plates *store.PlateStore,
|
|
items *store.ItemStore,
|
|
orders *store.OrderStore,
|
|
) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
j, err := jobs.Get(r.PathValue("id"))
|
|
if err != nil {
|
|
writeError(w, http.StatusNotFound, err)
|
|
return
|
|
}
|
|
|
|
pdf, summary, err := printjob.RenderPDF(j, configs, plates, items, orders)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
if summary.ImageOverflow {
|
|
w.Header().Set("X-Print-Job-Warning", summary.Warning)
|
|
}
|
|
name := j.Name
|
|
if name == "" {
|
|
name = "print-job-" + j.ID[:8]
|
|
}
|
|
servePDF(w, pdf, sanitizeFilename(name)+".pdf")
|
|
}
|
|
}
|
|
|
|
func validatePrintJobRequest(req savePrintJobRequest, configs *store.ConfigurationStore, orders *store.OrderStore) error {
|
|
if req.ConfigurationID == "" {
|
|
return errors.New("configuration_id is required")
|
|
}
|
|
if _, err := configs.Get(req.ConfigurationID); err != nil {
|
|
return errors.New("configuration not found: " + req.ConfigurationID)
|
|
}
|
|
if len(req.OrderIDs) == 0 {
|
|
return errors.New("at least one order_id is required")
|
|
}
|
|
for _, id := range req.OrderIDs {
|
|
if _, err := orders.Get(id); err != nil {
|
|
return errors.New("order not found: " + id)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func printJobResponseFor(
|
|
j model.PrintJob,
|
|
configs *store.ConfigurationStore,
|
|
plates *store.PlateStore,
|
|
items *store.ItemStore,
|
|
orders *store.OrderStore,
|
|
) printJobResponse {
|
|
resp := printJobResponse{PrintJob: j}
|
|
if summary, err := buildPrintJobSummary(j, configs, plates, items, orders); err == nil {
|
|
resp.Summary = &summary
|
|
}
|
|
return resp
|
|
}
|
|
|
|
func buildPrintJobSummary(
|
|
j model.PrintJob,
|
|
configs *store.ConfigurationStore,
|
|
plates *store.PlateStore,
|
|
items *store.ItemStore,
|
|
orders *store.OrderStore,
|
|
) (model.PrintJobSummary, error) {
|
|
cfg, err := configs.Get(j.ConfigurationID)
|
|
if err != nil {
|
|
return model.PrintJobSummary{}, err
|
|
}
|
|
preview, err := buildPreview(plates, items, cfg.PlateID, cfg.ItemID, cfg.SpacingMM)
|
|
if err != nil {
|
|
return model.PrintJobSummary{}, err
|
|
}
|
|
orderList := make([]model.Order, 0, len(j.OrderIDs))
|
|
for _, id := range j.OrderIDs {
|
|
o, err := orders.Get(id)
|
|
if err != nil {
|
|
return model.PrintJobSummary{}, err
|
|
}
|
|
orderList = append(orderList, o)
|
|
}
|
|
return printjob.Summary(orderList, preview), nil
|
|
}
|