feat: validate admin and time-blocker request structs

Ultraworked with Sisyphus (https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-05-31 10:54:59 +01:00
co-authored by Sisyphus
parent 605c1422b9
commit 965b8b2794
3 changed files with 38 additions and 12 deletions
+14 -4
View File
@@ -37,8 +37,8 @@ type DiscountCampaign struct {
// CreateCampaignRequest represents the request payload for creating a new campaign
type CreateCampaignRequest struct {
Name string `json:"name"`
Description *string `json:"description,omitempty"`
Name string `json:"name" validate:"required,min=1,max=200"`
Description *string `json:"description,omitempty" validate:"omitempty,max=1000"`
CampaignType string `json:"campaign_type"` // "time_based" or "milestone"
DiscountPercent float64 `json:"discount_percent"`
Scope *string `json:"scope,omitempty"`
@@ -52,8 +52,8 @@ type CreateCampaignRequest struct {
// UpdateCampaignRequest represents the request payload for updating a campaign
type UpdateCampaignRequest struct {
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
Name *string `json:"name,omitempty" validate:"omitempty,min=1,max=200"`
Description *string `json:"description,omitempty" validate:"omitempty,max=1000"`
DiscountPercent *float64 `json:"discount_percent,omitempty"`
Scope *string `json:"scope,omitempty"`
StartDate *string `json:"start_date,omitempty"`
@@ -206,6 +206,11 @@ func CreateDiscountCampaign(w http.ResponseWriter, r *http.Request) {
return
}
if err := validators.Validate.Struct(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Validate required fields
if req.Name == "" {
http.Error(w, "Name is required", http.StatusBadRequest)
@@ -391,6 +396,11 @@ func UpdateDiscountCampaign(w http.ResponseWriter, r *http.Request) {
return
}
if err := validators.Validate.Struct(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Build dynamic update query
query := "UPDATE discount_campaigns SET updated_at = NOW()"
args := []interface{}{}
+14 -4
View File
@@ -23,8 +23,8 @@ type PatchTest struct {
// CreatePatchTestRequest represents the request payload
type CreatePatchTestRequest struct {
Name string `json:"name"`
Description *string `json:"description,omitempty"`
Name string `json:"name" validate:"required,min=1,max=200"`
Description *string `json:"description,omitempty" validate:"omitempty,max=1000"`
NoticeDurationHours int `json:"notice_duration_hours"`
ExpiryMonths int `json:"expiry_months"`
ServiceIDs []string `json:"service_ids"`
@@ -32,8 +32,8 @@ type CreatePatchTestRequest struct {
// UpdatePatchTestRequest represents the request payload
type UpdatePatchTestRequest struct {
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
Name *string `json:"name,omitempty" validate:"omitempty,min=1,max=200"`
Description *string `json:"description,omitempty" validate:"omitempty,max=1000"`
NoticeDurationHours *int `json:"notice_duration_hours,omitempty"`
ExpiryMonths *int `json:"expiry_months,omitempty"`
ServiceIDs []string `json:"service_ids,omitempty"`
@@ -81,6 +81,11 @@ func CreatePatchTest(w http.ResponseWriter, r *http.Request) {
return
}
if err := validators.Validate.Struct(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
query := `
INSERT INTO patch_tests (name, description, notice_duration_hours, expiry_months, service_ids)
VALUES ($1, $2, $3, $4, $5)
@@ -112,6 +117,11 @@ func UpdatePatchTest(w http.ResponseWriter, r *http.Request) {
return
}
if err := validators.Validate.Struct(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
query := "UPDATE patch_tests SET "
args := []interface{}{}
i := 1
+10 -4
View File
@@ -9,6 +9,7 @@ import (
"time"
"crussell/db"
"crussell/internal/validators"
"crussell/mw"
"github.com/go-chi/chi/v5"
@@ -29,10 +30,10 @@ type TimeBlocker struct {
}
type CreateTimeBlockerRequest struct {
StartTime time.Time `json:"start_time"`
DurationMinutes int `json:"duration_minutes"`
Description string `json:"description,omitempty"`
CronExpression *string `json:"cron_expression,omitempty"`
StartTime time.Time `json:"start_time" validate:"required"`
DurationMinutes int `json:"duration_minutes" validate:"required,gt=0"`
Description string `json:"description,omitempty" validate:"omitempty,max=500"`
CronExpression *string `json:"cron_expression,omitempty" validate:"omitempty,max=500"`
}
// --- List Time Blockers ---
@@ -123,6 +124,11 @@ func CreateTimeBlocker(w http.ResponseWriter, r *http.Request) {
return
}
if err := validators.Validate.Struct(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Validate required fields
if req.StartTime.IsZero() {
http.Error(w, "start_time is required", http.StatusBadRequest)