better configuration strategy
This commit is contained in:
parent
513bcced9a
commit
3086b8fcd6
8 changed files with 38 additions and 25 deletions
|
@ -1,4 +1,4 @@
|
||||||
package middleware
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
|
@ -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) },
|
"uppercase": func(s string) string { return strings.ToUpper(s) },
|
||||||
"firstWord": func(s string) string {
|
"firstWord": func(s string) string {
|
||||||
words := strings.Fields(s)
|
words := strings.Fields(s)
|
|
@ -4,6 +4,15 @@ import (
|
||||||
"strings"
|
"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 {
|
func capitalize(s string) string {
|
||||||
words := strings.Fields(s)
|
words := strings.Fields(s)
|
||||||
for i, word := range words {
|
for i, word := range words {
|
||||||
|
|
|
@ -9,23 +9,6 @@ import (
|
||||||
"strings"
|
"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) {
|
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 {
|
||||||
|
@ -184,8 +167,8 @@ func parseValidators(tag string) []struct {
|
||||||
Name string
|
Name string
|
||||||
Param string
|
Param string
|
||||||
}
|
}
|
||||||
parts := strings.SplitSeq(tag, ",")
|
parts := strings.Split(tag, ",")
|
||||||
for part := range parts {
|
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]})
|
||||||
|
|
|
@ -4,20 +4,32 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"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 {
|
func nonzero(field string, value any, _ string) error {
|
||||||
v := reflect.ValueOf(value)
|
v := reflect.ValueOf(value)
|
||||||
|
|
||||||
if v.Kind() == reflect.String && v.Len() == 0 {
|
if v.Kind() == reflect.String && v.Len() == 0 {
|
||||||
return fmt.Errorf("field '%s' must not be empty", field)
|
return fmt.Errorf("field '%s' must not be empty", field)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Kind() == reflect.Slice && v.Len() == 0 {
|
if v.Kind() == reflect.Slice && v.Len() == 0 {
|
||||||
return fmt.Errorf("field '%s' must not be empty", field)
|
return fmt.Errorf("field '%s' must not be empty", field)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Kind() >= reflect.Int && v.Kind() <= reflect.Float64 && v.IsZero() {
|
if v.Kind() >= reflect.Int && v.Kind() <= reflect.Float64 && v.IsZero() {
|
||||||
return fmt.Errorf("field '%s' must be non-zero", field)
|
return fmt.Errorf("field '%s' must be non-zero", field)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,16 +38,24 @@ func minlen(field string, value any, param string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid minlen param for field '%s'", field)
|
return fmt.Errorf("invalid minlen param for field '%s'", field)
|
||||||
}
|
}
|
||||||
|
|
||||||
if str, ok := value.(string); ok && len(str) < min {
|
if str, ok := value.(string); ok && len(str) < min {
|
||||||
return fmt.Errorf("field '%s' must be at least %d characters", field, min)
|
return fmt.Errorf("field '%s' must be at least %d characters", field, min)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func email(field string, value any, _ string) error {
|
func email(field string, value any, _ string) error {
|
||||||
str, ok := value.(string)
|
str, ok := value.(string)
|
||||||
if !ok || !strings.Contains(str, "@") {
|
if !ok {
|
||||||
return fmt.Errorf("field '%s' must be a valid email address", field)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
2
main.go
2
main.go
|
@ -39,7 +39,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := views.Init(viewFS, config.ViewMap, config.FuncMap)
|
err := views.Init(viewFS, config.ViewMap, config.ViewFormatters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to initialize templates: %v", err)
|
log.Fatalf("failed to initialize templates: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"git.tavo.one/tavo/axiom/config"
|
||||||
"git.tavo.one/tavo/axiom/handlers"
|
"git.tavo.one/tavo/axiom/handlers"
|
||||||
"git.tavo.one/tavo/axiom/middleware"
|
"git.tavo.one/tavo/axiom/middleware"
|
||||||
)
|
)
|
||||||
|
@ -11,7 +12,7 @@ func routes(handler *handlers.Handler) *http.ServeMux {
|
||||||
router := http.NewServeMux()
|
router := http.NewServeMux()
|
||||||
|
|
||||||
protectedStack := middleware.Stack(
|
protectedStack := middleware.Stack(
|
||||||
middleware.AuthCheck,
|
config.AuthCheck,
|
||||||
)
|
)
|
||||||
|
|
||||||
router.HandleFunc(
|
router.HandleFunc(
|
||||||
|
|
Loading…
Reference in a new issue