// Package validation provides utilities for parsing and validating request data package validation import ( "errors" "fmt" "net/http" "git.haelnorr.com/h/golib/hws" "git.haelnorr.com/h/oslstats/internal/notify" "git.haelnorr.com/h/oslstats/internal/throw" "git.haelnorr.com/h/timefmt" ) type ValidationRule struct { Condition bool // Condition on which to fail validation Title string // Title for warning message Message string // Warning message } // Getter abstracts getting values from either form or query type Getter interface { Get(key string) string GetList(key string) []string AddCheck(check *ValidationRule) String(key string) *StringField Int(key string) *IntField Bool(key string) *BoolField Time(key string, format *timefmt.Format) *TimeField StringList(key string) *StringList IntList(key string) *IntList ValidateChecks() []*ValidationRule Validate() bool ValidateAndNotify(s *hws.Server, w http.ResponseWriter, r *http.Request) bool ValidateAndError(s *hws.Server, w http.ResponseWriter, r *http.Request) bool getChecks() []*ValidationRule } type FieldBase struct { Key string optional bool getter Getter } func newField(key string, g Getter) FieldBase { return FieldBase{ Key: key, getter: g, } } func newFailedCheck(title, message string) *ValidationRule { return &ValidationRule{ Condition: true, Title: title, Message: message, } } func validate(g Getter) []*ValidationRule { failed := []*ValidationRule{} for _, check := range g.getChecks() { if check != nil && check.Condition { failed = append(failed, check) } } return failed } func validateAndNotify( s *hws.Server, w http.ResponseWriter, r *http.Request, g Getter, ) bool { failedChecks := g.ValidateChecks() for _, check := range failedChecks { notify.Warn(s, w, r, check.Title, check.Message, nil) } return len(failedChecks) == 0 } func validateAndError( s *hws.Server, w http.ResponseWriter, r *http.Request, g Getter, ) bool { failedChecks := g.ValidateChecks() var err error for _, check := range failedChecks { err_ := fmt.Errorf("%s: %s", check.Title, check.Message) err = errors.Join(err, err_) } if len(failedChecks) > 0 { throw.BadRequest(s, w, r, "Invalid form data", err) } return len(failedChecks) == 0 }