package handlers import ( "encoding/json" "net/http" "git.warky.dev/wdevs/whatshooked/pkg/utils" "git.warky.dev/wdevs/whatshooked/pkg/whatsapp/businessapi" "go.mau.fi/whatsmeow/types" ) // ListCatalogs returns product catalogs for a Business API account. // POST /api/catalogs {"account_id"} func (h *Handlers) ListCatalogs(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var req struct { AccountID string `json:"account_id"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } baClient, err := h.getBusinessAPIClient(req.AccountID) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } resp, err := baClient.ListCatalogs(r.Context()) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } writeJSON(w, resp) } // ListProducts returns products in a specific catalog. // POST /api/catalogs/products {"account_id","catalog_id"} func (h *Handlers) ListProducts(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var req struct { AccountID string `json:"account_id"` CatalogID string `json:"catalog_id"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if req.CatalogID == "" { http.Error(w, "catalog_id is required", http.StatusBadRequest) return } baClient, err := h.getBusinessAPIClient(req.AccountID) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } resp, err := baClient.ListProducts(r.Context(), req.CatalogID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } writeJSON(w, resp) } // SendCatalogMessage sends a catalog message that shares the full product catalog. // POST /api/send/catalog {"account_id","to","body_text","thumbnail_product_retailer_id"} func (h *Handlers) SendCatalogMessage(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var req struct { AccountID string `json:"account_id"` To string `json:"to"` BodyText string `json:"body_text"` ThumbnailProductRetailerID string `json:"thumbnail_product_retailer_id"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if req.BodyText == "" { http.Error(w, "body_text is required", http.StatusBadRequest) return } baClient, err := h.getBusinessAPIClient(req.AccountID) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } jid, err := types.ParseJID(utils.FormatPhoneToJID(req.To, h.config.Server.DefaultCountryCode)) if err != nil { http.Error(w, "Invalid phone number", http.StatusBadRequest) return } if _, err := baClient.SendCatalogMessage(r.Context(), jid, req.BodyText, req.ThumbnailProductRetailerID); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } writeJSON(w, map[string]string{"status": "ok"}) } // SendSingleProduct sends a single-product interactive message. // POST /api/send/product {"account_id","to","catalog_id","product_retailer_id","body_text","footer_text"} func (h *Handlers) SendSingleProduct(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var req struct { AccountID string `json:"account_id"` To string `json:"to"` CatalogID string `json:"catalog_id"` ProductRetailerID string `json:"product_retailer_id"` BodyText string `json:"body_text"` FooterText string `json:"footer_text"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if req.CatalogID == "" || req.ProductRetailerID == "" || req.BodyText == "" { http.Error(w, "catalog_id, product_retailer_id, and body_text are required", http.StatusBadRequest) return } baClient, err := h.getBusinessAPIClient(req.AccountID) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } jid, err := types.ParseJID(utils.FormatPhoneToJID(req.To, h.config.Server.DefaultCountryCode)) if err != nil { http.Error(w, "Invalid phone number", http.StatusBadRequest) return } if _, err := baClient.SendSingleProduct(r.Context(), jid, req.CatalogID, req.ProductRetailerID, req.BodyText, req.FooterText); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } writeJSON(w, map[string]string{"status": "ok"}) } // SendProductList sends a multi-product list message (up to 30 products across up to 10 sections). // POST /api/send/product-list {"account_id","to","header_text","body_text","footer_text","catalog_id","sections":[...]} func (h *Handlers) SendProductList(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var req struct { AccountID string `json:"account_id"` To string `json:"to"` HeaderText string `json:"header_text"` BodyText string `json:"body_text"` FooterText string `json:"footer_text"` CatalogID string `json:"catalog_id"` Sections []businessapi.ProductListSection `json:"sections"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if req.CatalogID == "" || req.HeaderText == "" || req.BodyText == "" || len(req.Sections) == 0 { http.Error(w, "catalog_id, header_text, body_text, and sections are required", http.StatusBadRequest) return } baClient, err := h.getBusinessAPIClient(req.AccountID) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } jid, err := types.ParseJID(utils.FormatPhoneToJID(req.To, h.config.Server.DefaultCountryCode)) if err != nil { http.Error(w, "Invalid phone number", http.StatusBadRequest) return } if _, err := baClient.SendProductList(r.Context(), jid, req.HeaderText, req.BodyText, req.FooterText, req.CatalogID, req.Sections); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } writeJSON(w, map[string]string{"status": "ok"}) }