From 304a54c28394c1ae8c26397a4fcf0c6be929f514 Mon Sep 17 00:00:00 2001 From: Stephen Adamson Date: Sun, 31 May 2026 18:49:02 +0100 Subject: [PATCH] fix(admin): replace string(rune) with strconv.Itoa and validate status param Fix query parameter construction by using strconv.Itoa instead of string(rune('0'+argNum)). Add status filter validation against allowed values. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- backend/handlers/admin/discount_campaigns.go | 32 ++++++++++++-------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/backend/handlers/admin/discount_campaigns.go b/backend/handlers/admin/discount_campaigns.go index b8f1b17..0879eef 100644 --- a/backend/handlers/admin/discount_campaigns.go +++ b/backend/handlers/admin/discount_campaigns.go @@ -8,6 +8,7 @@ import ( "encoding/json" "log" "net/http" + "strconv" "time" "github.com/go-chi/chi/v5" @@ -76,6 +77,13 @@ type CampaignStats struct { // Optional query param ?status=active to filter by status func GetDiscountCampaigns(w http.ResponseWriter, r *http.Request) { statusFilter := r.URL.Query().Get("status") + if statusFilter != "" { + validStatuses := map[string]bool{"active": true, "paused": true, "cancelled": true, "expired": true} + if !validStatuses[statusFilter] { + http.Error(w, "invalid status filter", http.StatusBadRequest) + return + } + } var query string var rows pgx.Rows @@ -407,12 +415,12 @@ func UpdateDiscountCampaign(w http.ResponseWriter, r *http.Request) { argNum := 1 if req.Name != nil { - query += ", name = $" + string(rune('0'+argNum)) + query += ", name = $" + strconv.Itoa(argNum) args = append(args, *req.Name) argNum++ } if req.Description != nil { - query += ", description = $" + string(rune('0'+argNum)) + query += ", description = $" + strconv.Itoa(argNum) args = append(args, *req.Description) argNum++ } @@ -421,12 +429,12 @@ func UpdateDiscountCampaign(w http.ResponseWriter, r *http.Request) { http.Error(w, "Discount percent must be greater than 0 and less than or equal to 100", http.StatusBadRequest) return } - query += ", discount_percent = $" + string(rune('0'+argNum)) + query += ", discount_percent = $" + strconv.Itoa(argNum) args = append(args, *req.DiscountPercent) argNum++ } if req.Scope != nil { - query += ", scope = $" + string(rune('0'+argNum)) + query += ", scope = $" + strconv.Itoa(argNum) args = append(args, *req.Scope) argNum++ } @@ -436,7 +444,7 @@ func UpdateDiscountCampaign(w http.ResponseWriter, r *http.Request) { http.Error(w, "Invalid start date format. Use ISO 8601 format", http.StatusBadRequest) return } - query += ", start_date = $" + string(rune('0'+argNum)) + query += ", start_date = $" + strconv.Itoa(argNum) args = append(args, startTime) argNum++ } @@ -446,12 +454,12 @@ func UpdateDiscountCampaign(w http.ResponseWriter, r *http.Request) { http.Error(w, "Invalid end date format. Use ISO 8601 format", http.StatusBadRequest) return } - query += ", end_date = $" + string(rune('0'+argNum)) + query += ", end_date = $" + strconv.Itoa(argNum) args = append(args, endTime) argNum++ } if req.MilestoneType != nil { - query += ", milestone_type = $" + string(rune('0'+argNum)) + query += ", milestone_type = $" + strconv.Itoa(argNum) args = append(args, *req.MilestoneType) argNum++ } @@ -460,12 +468,12 @@ func UpdateDiscountCampaign(w http.ResponseWriter, r *http.Request) { http.Error(w, "Milestone value must be greater than 0", http.StatusBadRequest) return } - query += ", milestone_value = $" + string(rune('0'+argNum)) + query += ", milestone_value = $" + strconv.Itoa(argNum) args = append(args, *req.MilestoneValue) argNum++ } if req.MilestoneUnit != nil { - query += ", milestone_unit = $" + string(rune('0'+argNum)) + query += ", milestone_unit = $" + strconv.Itoa(argNum) args = append(args, *req.MilestoneUnit) argNum++ } @@ -474,17 +482,17 @@ func UpdateDiscountCampaign(w http.ResponseWriter, r *http.Request) { http.Error(w, "Status must be 'active', 'cancelled', or 'completed'", http.StatusBadRequest) return } - query += ", status = $" + string(rune('0'+argNum)) + query += ", status = $" + strconv.Itoa(argNum) args = append(args, *req.Status) argNum++ } if req.MaxRedemptions != nil { - query += ", max_redemptions = $" + string(rune('0'+argNum)) + query += ", max_redemptions = $" + strconv.Itoa(argNum) args = append(args, *req.MaxRedemptions) argNum++ } - query += " WHERE id = $" + string(rune('0'+argNum)) + query += " WHERE id = $" + strconv.Itoa(argNum) args = append(args, campaignID) _, err = db.DB.Exec(r.Context(), query, args...)