better configuration strategy

This commit is contained in:
tavo 2025-07-01 00:29:14 -06:00
parent 513bcced9a
commit 3086b8fcd6
8 changed files with 38 additions and 25 deletions

View file

@ -1,4 +1,4 @@
package middleware
package config
import (
"log"

View file

@ -25,7 +25,7 @@ var ViewMap = map[string][]string{
),
}
var FuncMap = map[string]any{
var ViewFormatters = map[string]any{
"uppercase": func(s string) string { return strings.ToUpper(s) },
"firstWord": func(s string) string {
words := strings.Fields(s)

View file

@ -4,6 +4,15 @@ import (
"strings"
)
type Formatter func(string) string
var Formatters = map[string]Formatter{
"trim": strings.TrimSpace,
"lower": strings.ToLower,
"upper": strings.ToUpper,
"capitalize": capitalize,
}
func capitalize(s string) string {
words := strings.Fields(s)
for i, word := range words {

View file

@ -9,23 +9,6 @@ import (
"strings"
)
type Formatter func(string) string
var Formatters = map[string]Formatter{
"trim": strings.TrimSpace,
"lower": strings.ToLower,
"upper": strings.ToUpper,
"capitalize": capitalize,
}
type Validator func(fieldName string, value any, param string) error
var Validators = map[string]Validator{
"nonzero": nonzero,
"minlen": minlen,
"email": email,
}
func FormToStruct[T any](r *http.Request) (T, error) {
var target T
if err := r.ParseForm(); err != nil {
@ -184,8 +167,8 @@ func parseValidators(tag string) []struct {
Name string
Param string
}
parts := strings.SplitSeq(tag, ",")
for part := range parts {
parts := strings.Split(tag, ",")
for _, part := range parts {
pair := strings.SplitN(part, ":", 2)
if len(pair) == 2 {
result = append(result, struct{ Name, Param string }{pair[0], pair[1]})

View file

@ -4,20 +4,32 @@ import (
"fmt"
"reflect"
"strconv"
"strings"
"net/mail"
)
type Validator func(fieldName string, value any, param string) error
var Validators = map[string]Validator{
"nonzero": nonzero,
"minlen": minlen,
"email": email,
}
func nonzero(field string, value any, _ string) error {
v := reflect.ValueOf(value)
if v.Kind() == reflect.String && v.Len() == 0 {
return fmt.Errorf("field '%s' must not be empty", field)
}
if v.Kind() == reflect.Slice && v.Len() == 0 {
return fmt.Errorf("field '%s' must not be empty", field)
}
if v.Kind() >= reflect.Int && v.Kind() <= reflect.Float64 && v.IsZero() {
return fmt.Errorf("field '%s' must be non-zero", field)
}
return nil
}
@ -26,16 +38,24 @@ func minlen(field string, value any, param string) error {
if err != nil {
return fmt.Errorf("invalid minlen param for field '%s'", field)
}
if str, ok := value.(string); ok && len(str) < min {
return fmt.Errorf("field '%s' must be at least %d characters", field, min)
}
return nil
}
func email(field string, value any, _ string) error {
str, ok := value.(string)
if !ok || !strings.Contains(str, "@") {
if !ok {
return fmt.Errorf("field '%s' must be a valid email address", field)
}
_, err := mail.ParseAddress(str)
if err != nil {
return fmt.Errorf("invalid email address: %v", err)
}
return nil
}

View file

@ -39,7 +39,7 @@ func init() {
}
func main() {
err := views.Init(viewFS, config.ViewMap, config.FuncMap)
err := views.Init(viewFS, config.ViewMap, config.ViewFormatters)
if err != nil {
log.Fatalf("failed to initialize templates: %v", err)
}

View file

@ -3,6 +3,7 @@ package main
import (
"net/http"
"git.tavo.one/tavo/axiom/config"
"git.tavo.one/tavo/axiom/handlers"
"git.tavo.one/tavo/axiom/middleware"
)
@ -11,7 +12,7 @@ func routes(handler *handlers.Handler) *http.ServeMux {
router := http.NewServeMux()
protectedStack := middleware.Stack(
middleware.AuthCheck,
config.AuthCheck,
)
router.HandleFunc(