admin page updates
This commit is contained in:
@@ -24,6 +24,10 @@ func (f *FormGetter) Get(key string) string {
|
||||
return f.r.FormValue(key)
|
||||
}
|
||||
|
||||
func (f *FormGetter) GetList(key string) []string {
|
||||
return f.r.Form[key]
|
||||
}
|
||||
|
||||
func (f *FormGetter) getChecks() []*ValidationRule {
|
||||
return f.checks
|
||||
}
|
||||
@@ -48,6 +52,14 @@ func (f *FormGetter) Time(key string, format *timefmt.Format) *TimeField {
|
||||
return newTimeField(key, format, f)
|
||||
}
|
||||
|
||||
func (f *FormGetter) StringList(key string) *StringList {
|
||||
return newStringList(key, f)
|
||||
}
|
||||
|
||||
func (f *FormGetter) IntList(key string) *IntList {
|
||||
return newIntList(key, f)
|
||||
}
|
||||
|
||||
func ParseForm(r *http.Request) (*FormGetter, error) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
type IntField struct {
|
||||
Field
|
||||
FieldBase
|
||||
Value int
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ func newIntField(key string, g Getter) *IntField {
|
||||
}
|
||||
}
|
||||
return &IntField{
|
||||
Value: val,
|
||||
Field: newField(key, g),
|
||||
Value: val,
|
||||
FieldBase: newField(key, g),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
105
internal/validation/intlist.go
Normal file
105
internal/validation/intlist.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// IntList represents a list of IntFields for validating multiple integer values
|
||||
type IntList struct {
|
||||
FieldBase
|
||||
Fields []*IntField
|
||||
}
|
||||
|
||||
// newIntList creates a new IntList from form/query values
|
||||
func newIntList(key string, g Getter) *IntList {
|
||||
items := g.GetList(key)
|
||||
list := &IntList{
|
||||
FieldBase: newField(key, g),
|
||||
Fields: make([]*IntField, 0, len(items)),
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
if item == "" {
|
||||
continue // Skip empty values
|
||||
}
|
||||
|
||||
var val int
|
||||
var err error
|
||||
val, err = strconv.Atoi(item)
|
||||
if err != nil {
|
||||
g.AddCheck(newFailedCheck(
|
||||
"Value is not a number",
|
||||
fmt.Sprintf("%s contains invalid integer: %s", key, item),
|
||||
))
|
||||
continue
|
||||
}
|
||||
|
||||
// Create an IntField directly with the value
|
||||
field := &IntField{
|
||||
Value: val,
|
||||
FieldBase: newField(key, g),
|
||||
}
|
||||
list.Fields = append(list.Fields, field)
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
// Values returns all int values in the list
|
||||
func (l *IntList) Values() []int {
|
||||
values := make([]int, len(l.Fields))
|
||||
for i, field := range l.Fields {
|
||||
values[i] = field.Value
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
// Required enforces at least one value in the list
|
||||
func (l *IntList) Required() *IntList {
|
||||
if len(l.Fields) == 0 {
|
||||
l.getter.AddCheck(newFailedCheck(
|
||||
"Field not provided",
|
||||
fmt.Sprintf("%s is required", l.Key),
|
||||
))
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// MinItems enforces a minimum number of items in the list
|
||||
func (l *IntList) MinItems(min int) *IntList {
|
||||
if len(l.Fields) < min {
|
||||
l.getter.AddCheck(newFailedCheck(
|
||||
"Too few items",
|
||||
fmt.Sprintf("%s requires at least %d item(s)", l.Key, min),
|
||||
))
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// MaxItems enforces a maximum number of items in the list
|
||||
func (l *IntList) MaxItems(max int) *IntList {
|
||||
if len(l.Fields) > max {
|
||||
l.getter.AddCheck(newFailedCheck(
|
||||
"Too many items",
|
||||
fmt.Sprintf("%s allows at most %d item(s)", l.Key, max),
|
||||
))
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// Max enforces a maximum value for each item
|
||||
func (l *IntList) Max(max int) *IntList {
|
||||
for _, field := range l.Fields {
|
||||
field.Max(max)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// Min enforces a minimum value for each item
|
||||
func (l *IntList) Min(min int) *IntList {
|
||||
for _, field := range l.Fields {
|
||||
field.Min(min)
|
||||
}
|
||||
return l
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package validation
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"git.haelnorr.com/h/golib/hws"
|
||||
"git.haelnorr.com/h/timefmt"
|
||||
@@ -21,6 +22,10 @@ func (q *QueryGetter) Get(key string) string {
|
||||
return q.r.URL.Query().Get(key)
|
||||
}
|
||||
|
||||
func (q *QueryGetter) GetList(key string) []string {
|
||||
return strings.Split(q.Get(key), ",")
|
||||
}
|
||||
|
||||
func (q *QueryGetter) getChecks() []*ValidationRule {
|
||||
return q.checks
|
||||
}
|
||||
@@ -45,6 +50,14 @@ func (q *QueryGetter) Time(key string, format *timefmt.Format) *TimeField {
|
||||
return newTimeField(key, format, q)
|
||||
}
|
||||
|
||||
func (q *QueryGetter) StringList(key string) *StringList {
|
||||
return newStringList(key, q)
|
||||
}
|
||||
|
||||
func (q *QueryGetter) IntList(key string) *IntList {
|
||||
return newIntList(key, q)
|
||||
}
|
||||
|
||||
func (q *QueryGetter) Validate() bool {
|
||||
return len(validate(q)) == 0
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ import (
|
||||
)
|
||||
|
||||
type StringField struct {
|
||||
Field
|
||||
FieldBase
|
||||
Value string
|
||||
}
|
||||
|
||||
func newStringField(key string, g Getter) *StringField {
|
||||
return &StringField{
|
||||
Value: g.Get(key),
|
||||
Field: newField(key, g),
|
||||
Value: g.Get(key),
|
||||
FieldBase: newField(key, g),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
124
internal/validation/stringlist.go
Normal file
124
internal/validation/stringlist.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// StringList represents a list of StringFields for validating multiple string values
|
||||
type StringList struct {
|
||||
FieldBase
|
||||
Fields []*StringField
|
||||
}
|
||||
|
||||
// newStringList creates a new StringList from form/query values
|
||||
func newStringList(key string, g Getter) *StringList {
|
||||
items := g.GetList(key)
|
||||
list := &StringList{
|
||||
FieldBase: newField(key, g),
|
||||
Fields: make([]*StringField, 0, len(items)),
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
if item == "" {
|
||||
continue // Skip empty values
|
||||
}
|
||||
// Create a StringField directly with the value
|
||||
field := &StringField{
|
||||
Value: item,
|
||||
FieldBase: newField(key, g),
|
||||
}
|
||||
list.Fields = append(list.Fields, field)
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
// Values returns all string values in the list
|
||||
func (l *StringList) Values() []string {
|
||||
values := make([]string, len(l.Fields))
|
||||
for i, field := range l.Fields {
|
||||
values[i] = field.Value
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
// Required enforces at least one non-empty value in the list
|
||||
func (l *StringList) Required() *StringList {
|
||||
if len(l.Fields) == 0 {
|
||||
l.getter.AddCheck(newFailedCheck(
|
||||
"Field not provided",
|
||||
fmt.Sprintf("%s is required", l.Key),
|
||||
))
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// MinItems enforces a minimum number of items in the list
|
||||
func (l *StringList) MinItems(min int) *StringList {
|
||||
if len(l.Fields) < min {
|
||||
l.getter.AddCheck(newFailedCheck(
|
||||
"Too few items",
|
||||
fmt.Sprintf("%s requires at least %d item(s)", l.Key, min),
|
||||
))
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// MaxItems enforces a maximum number of items in the list
|
||||
func (l *StringList) MaxItems(max int) *StringList {
|
||||
if len(l.Fields) > max {
|
||||
l.getter.AddCheck(newFailedCheck(
|
||||
"Too many items",
|
||||
fmt.Sprintf("%s allows at most %d item(s)", l.Key, max),
|
||||
))
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// MaxLength enforces a maximum string length for each item
|
||||
func (l *StringList) MaxLength(length int) *StringList {
|
||||
for _, field := range l.Fields {
|
||||
field.MaxLength(length)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// MinLength enforces a minimum string length for each item
|
||||
func (l *StringList) MinLength(length int) *StringList {
|
||||
for _, field := range l.Fields {
|
||||
field.MinLength(length)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// AllowedValues enforces each item must be in the allowed list
|
||||
func (l *StringList) AllowedValues(allowed []string) *StringList {
|
||||
for _, field := range l.Fields {
|
||||
field.AllowedValues(allowed)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// ToUpper transforms all strings to uppercase
|
||||
func (l *StringList) ToUpper() *StringList {
|
||||
for _, field := range l.Fields {
|
||||
field.ToUpper()
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// ToLower transforms all strings to lowercase
|
||||
func (l *StringList) ToLower() *StringList {
|
||||
for _, field := range l.Fields {
|
||||
field.ToLower()
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// TrimSpace removes leading and trailing whitespace from all items
|
||||
func (l *StringList) TrimSpace() *StringList {
|
||||
for _, field := range l.Fields {
|
||||
field.TrimSpace()
|
||||
}
|
||||
return l
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
type TimeField struct {
|
||||
Field
|
||||
FieldBase
|
||||
Value time.Time
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ func newTimeField(key string, format *timefmt.Format, g Getter) *TimeField {
|
||||
}
|
||||
}
|
||||
return &TimeField{
|
||||
Value: startDate,
|
||||
Field: newField(key, g),
|
||||
Value: startDate,
|
||||
FieldBase: newField(key, g),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,13 @@ type ValidationRule struct {
|
||||
// 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
|
||||
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
|
||||
@@ -32,14 +35,14 @@ type Getter interface {
|
||||
|
||||
getChecks() []*ValidationRule
|
||||
}
|
||||
type Field struct {
|
||||
type FieldBase struct {
|
||||
Key string
|
||||
optional bool
|
||||
getter Getter
|
||||
}
|
||||
|
||||
func newField(key string, g Getter) Field {
|
||||
return Field{
|
||||
func newField(key string, g Getter) FieldBase {
|
||||
return FieldBase{
|
||||
Key: key,
|
||||
getter: g,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user