This commit is contained in:
tavo 2025-07-01 09:57:53 -06:00
parent 7889571c5c
commit 5d4c925130
5 changed files with 24 additions and 6 deletions

View file

@ -15,10 +15,12 @@ var Formatters = map[string]Formatter{
func capitalize(s string) string { func capitalize(s string) string {
words := strings.Fields(s) words := strings.Fields(s)
for i, word := range words { for i, word := range words {
if len(word) > 0 { if len(word) > 0 {
words[i] = strings.ToUpper(string(word[0])) + strings.ToLower(word[1:]) words[i] = strings.ToUpper(string(word[0])) + strings.ToLower(word[1:])
} }
} }
return strings.Join(words, " ") return strings.Join(words, " ")
} }

View file

@ -11,9 +11,11 @@ import (
func FormToStruct[T any](r *http.Request) (T, error) { func FormToStruct[T any](r *http.Request) (T, error) {
var target T var target T
if err := r.ParseForm(); err != nil { if err := r.ParseForm(); err != nil {
return target, fmt.Errorf("error parsing form: %v", err) return target, fmt.Errorf("error parsing form: %v", err)
} }
err := UrlValuesToStruct(r.Form, &target) err := UrlValuesToStruct(r.Form, &target)
return target, err return target, err
} }
@ -26,7 +28,6 @@ func UrlValuesToStruct(form url.Values, dst any) error {
v = v.Elem() v = v.Elem()
t := v.Type() t := v.Type()
for i := 0; i < t.NumField(); i++ { for i := 0; i < t.NumField(); i++ {
field := t.Field(i) field := t.Field(i)
fieldValue := v.Field(i) fieldValue := v.Field(i)
@ -119,24 +120,28 @@ func castStringToType(value string, kind reflect.Kind) (any, error) {
switch kind { switch kind {
case reflect.String: case reflect.String:
return value, nil return value, nil
case reflect.Int, reflect.Int64: case reflect.Int, reflect.Int64:
new, err := strconv.Atoi(value) new, err := strconv.Atoi(value)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to cast string to integer: %v", err) return nil, fmt.Errorf("failed to cast string to integer: %v", err)
} }
return new, nil return new, nil
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
new, err := strconv.ParseFloat(value, 64) new, err := strconv.ParseFloat(value, 64)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to cast string to float64: %v", err) return nil, fmt.Errorf("failed to cast string to float64: %v", err)
} }
return new, nil return new, nil
case reflect.Bool: case reflect.Bool:
new, err := strconv.ParseBool(value) new, err := strconv.ParseBool(value)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to cast string to boolean: %v", err) return nil, fmt.Errorf("failed to cast string to boolean: %v", err)
} }
return new, nil return new, nil
default: default:
return nil, fmt.Errorf("unsupported kind: %s", kind) return nil, fmt.Errorf("unsupported kind: %s", kind)
} }
@ -146,13 +151,16 @@ func parseFormatters(tag string) []func(string) string {
if tag == "" { if tag == "" {
return nil return nil
} }
parts := strings.Split(tag, ",")
var fns []func(string) string var fns []func(string) string
for _, p := range parts {
parts := strings.SplitSeq(tag, ",")
for p := range parts {
if fn, ok := Formatters[strings.TrimSpace(p)]; ok { if fn, ok := Formatters[strings.TrimSpace(p)]; ok {
fns = append(fns, fn) fns = append(fns, fn)
} }
} }
return fns return fns
} }
@ -163,12 +171,14 @@ func parseValidators(tag string) []struct {
if tag == "" { if tag == "" {
return nil return nil
} }
var result []struct { var result []struct {
Name string Name string
Param string Param string
} }
parts := strings.Split(tag, ",")
for _, part := range parts { parts := strings.SplitSeq(tag, ",")
for part := range parts {
pair := strings.SplitN(part, ":", 2) pair := strings.SplitN(part, ":", 2)
if len(pair) == 2 { if len(pair) == 2 {
result = append(result, struct{ Name, Param string }{pair[0], pair[1]}) result = append(result, struct{ Name, Param string }{pair[0], pair[1]})
@ -176,5 +186,6 @@ func parseValidators(tag string) []struct {
result = append(result, struct{ Name, Param string }{pair[0], ""}) result = append(result, struct{ Name, Param string }{pair[0], ""})
} }
} }
return result return result
} }

View file

@ -2,9 +2,9 @@ package forms
import ( import (
"fmt" "fmt"
"net/mail"
"reflect" "reflect"
"strconv" "strconv"
"net/mail"
) )
type Validator func(fieldName string, value any, param string) error type Validator func(fieldName string, value any, param string) error

View file

@ -183,9 +183,11 @@ func (s *Auth) write(writer *multipart.Writer, contentType, content string) erro
partHeader := make(textproto.MIMEHeader) partHeader := make(textproto.MIMEHeader)
partHeader.Set("Content-Type", contentType) partHeader.Set("Content-Type", contentType)
part, err := writer.CreatePart(partHeader) part, err := writer.CreatePart(partHeader)
if err != nil { if err != nil {
return fmt.Errorf("failed to create part: %w", err) return fmt.Errorf("failed to create part: %w", err)
} }
_, err = part.Write([]byte(content)) _, err = part.Write([]byte(content))
return err return err
} }
@ -195,9 +197,11 @@ func (s *Auth) attach(writer *multipart.Writer, filename string, fileBuffer *byt
attachmentHeader.Set("Content-Type", "application/octet-stream") attachmentHeader.Set("Content-Type", "application/octet-stream")
attachmentHeader.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename)) attachmentHeader.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename))
attachment, err := writer.CreatePart(attachmentHeader) attachment, err := writer.CreatePart(attachmentHeader)
if err != nil { if err != nil {
return fmt.Errorf("failed to create attachment part: %w", err) return fmt.Errorf("failed to create attachment part: %w", err)
} }
_, err = attachment.Write(fileBuffer.Bytes()) _, err = attachment.Write(fileBuffer.Bytes())
return err return err
} }

View file

@ -9,6 +9,7 @@ func Stack(xs ...Middleware) Middleware {
for i := len(xs) - 1; i >= 0; i-- { for i := len(xs) - 1; i >= 0; i-- {
next = xs[i](next) next = xs[i](next)
} }
return next return next
} }
} }