From b5c16e24b0a793871e0fcbfd7659ee0d1c702bcb Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 28 Jun 2019 09:10:27 +0200 Subject: [PATCH] Swapped the custom param binder with the merged one from echo --- handler/create.go | 2 +- handler/delete.go | 2 +- handler/paramBinder.go | 287 ----------------------------------------- handler/read_all.go | 2 +- handler/read_one.go | 2 +- handler/update.go | 2 +- 6 files changed, 5 insertions(+), 292 deletions(-) delete mode 100644 handler/paramBinder.go diff --git a/handler/create.go b/handler/create.go index a140f13..6a2bc03 100644 --- a/handler/create.go +++ b/handler/create.go @@ -26,7 +26,7 @@ func (c *WebHandler) CreateWeb(ctx echo.Context) error { currentStruct := c.EmptyStruct() // Get the object & bind params to struct - if err := ParamBinder(currentStruct, ctx); err != nil { + if err := ctx.Bind(currentStruct); err != nil { return echo.NewHTTPError(http.StatusBadRequest, "No or invalid model provided.") } diff --git a/handler/delete.go b/handler/delete.go index 715adc4..6053bc0 100644 --- a/handler/delete.go +++ b/handler/delete.go @@ -31,7 +31,7 @@ func (c *WebHandler) DeleteWeb(ctx echo.Context) error { currentStruct := c.EmptyStruct() // Bind params to struct - if err := ParamBinder(currentStruct, ctx); err != nil { + if err := ctx.Bind(currentStruct); err != nil { return echo.NewHTTPError(http.StatusBadRequest, "Invalid URL param.") } diff --git a/handler/paramBinder.go b/handler/paramBinder.go deleted file mode 100644 index e24eb2a..0000000 --- a/handler/paramBinder.go +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright (c) 2018 Vikunja and contributors. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see . - -package handler - -import ( - "errors" - "github.com/labstack/echo/v4" - "reflect" - "strconv" - "strings" -) - -const paramTagName = "param" - -// ParamBinder binds parameters to a struct. -// Currently a working implementation, waiting to implement this officially into echo. -func ParamBinder(i interface{}, c echo.Context) (err error) { - - // Default binder - db := new(echo.DefaultBinder) - if err = db.Bind(i, c); err != nil { - return - } - - paramNames := c.ParamNames() - paramValues := c.ParamValues() - paramVars := make(map[string][]string) - for in, name := range paramNames { - // Hotfix for an echo bug where a param name would show up which dont exist - names := strings.Split(name, ",") - for _, n := range names { - paramVars[n] = append(paramVars[name], paramValues[in]) - } - } - - b := Binder{} - err = b.bindData(i, paramVars, paramTagName) - - /* - // Our custom magic starts here - paramNames := c.ParamNames() - paramValues := c.ParamValues() - - v := reflect.ValueOf(i) - t := reflect.TypeOf(i) - s := reflect.ValueOf(i).Elem() - for i := 0; i < v.NumField(); i++ { - field := t.Field(i) - f := s.Field(i) - - // Check if it has a param tag - tag := field.Tag.Get(paramTagName) - if tag != "" { - // If it has one, range over all url parameters to see if we have a match - for in, name := range paramNames { - // Found match - if tag == name { - // Put the value of that match in our sruct - switch field.Type.Name() { - case "int64": // SetInt only accepts int64, so the struct field can only have int64 of int (no int32/16/int...) - intParam, err := strconv.ParseInt(paramValues[in], 10, 64) - f.SetInt(intParam) - - if err != nil { - return err - } - case "string": - f.SetString(paramValues[in]) - } - } - } - } - - - - - //f.SetString("blub") - - }*/ - - return -} - -// Binder represents a binder -type Binder struct{} - -func (b *Binder) bindData(ptr interface{}, data map[string][]string, tag string) error { - typ := reflect.TypeOf(ptr).Elem() - val := reflect.ValueOf(ptr).Elem() - - if typ.Kind() != reflect.Struct { - return errors.New("Binding element must be a struct") - } - - for i := 0; i < typ.NumField(); i++ { - typeField := typ.Field(i) - structField := val.Field(i) - if !structField.CanSet() { - continue - } - structFieldKind := structField.Kind() - inputFieldName := typeField.Tag.Get(tag) - - if inputFieldName == "" { - inputFieldName = typeField.Name - // If tag is nil, we inspect if the field is a struct. - if _, ok := bindUnmarshaler(structField); !ok && structFieldKind == reflect.Struct { - err := b.bindData(structField.Addr().Interface(), data, tag) - if err != nil { - return err - } - continue - } - } - inputValue, exists := data[inputFieldName] - if !exists { - continue - } - - // Call this first, in case we're dealing with an alias to an array type - if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok { - if err != nil { - return err - } - continue - } - - numElems := len(inputValue) - if structFieldKind == reflect.Slice && numElems > 0 { - sliceOf := structField.Type().Elem().Kind() - slice := reflect.MakeSlice(structField.Type(), numElems, numElems) - for j := 0; j < numElems; j++ { - if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil { - return err - } - } - val.Field(i).Set(slice) - } else { - if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil { - return err - } - } - } - return nil -} - -func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error { - // But also call it here, in case we're dealing with an array of BindUnmarshalers - if ok, err := unmarshalField(valueKind, val, structField); ok { - return err - } - - switch valueKind { - case reflect.Int: - return setIntField(val, 0, structField) - case reflect.Int8: - return setIntField(val, 8, structField) - case reflect.Int16: - return setIntField(val, 16, structField) - case reflect.Int32: - return setIntField(val, 32, structField) - case reflect.Int64: - return setIntField(val, 64, structField) - case reflect.Uint: - return setUintField(val, 0, structField) - case reflect.Uint8: - return setUintField(val, 8, structField) - case reflect.Uint16: - return setUintField(val, 16, structField) - case reflect.Uint32: - return setUintField(val, 32, structField) - case reflect.Uint64: - return setUintField(val, 64, structField) - case reflect.Bool: - return setBoolField(val, structField) - case reflect.Float32: - return setFloatField(val, 32, structField) - case reflect.Float64: - return setFloatField(val, 64, structField) - case reflect.String: - structField.SetString(val) - default: - return errors.New("unknown type") - } - return nil -} - -func setIntField(value string, bitSize int, field reflect.Value) error { - if value == "" { - value = "0" - } - intVal, err := strconv.ParseInt(value, 10, bitSize) - if err == nil { - field.SetInt(intVal) - } - return err -} - -func setUintField(value string, bitSize int, field reflect.Value) error { - if value == "" { - value = "0" - } - uintVal, err := strconv.ParseUint(value, 10, bitSize) - if err == nil { - field.SetUint(uintVal) - } - return err -} - -func setBoolField(value string, field reflect.Value) error { - if value == "" { - value = "false" - } - boolVal, err := strconv.ParseBool(value) - if err == nil { - field.SetBool(boolVal) - } - return err -} - -func setFloatField(value string, bitSize int, field reflect.Value) error { - if value == "" { - value = "0.0" - } - floatVal, err := strconv.ParseFloat(value, bitSize) - if err == nil { - field.SetFloat(floatVal) - } - return err -} - -// BindUnmarshaler type -type BindUnmarshaler interface { - // UnmarshalParam decodes and assigns a value from an form or query param. - UnmarshalParam(param string) error -} - -// bindUnmarshaler attempts to unmarshal a reflect.Value into a BindUnmarshaler -func bindUnmarshaler(field reflect.Value) (BindUnmarshaler, bool) { - ptr := reflect.New(field.Type()) - if ptr.CanInterface() { - iface := ptr.Interface() - if unmarshaler, ok := iface.(BindUnmarshaler); ok { - return unmarshaler, ok - } - } - return nil, false -} - -func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) { - switch valueKind { - case reflect.Ptr: - return unmarshalFieldPtr(val, field) - default: - return unmarshalFieldNonPtr(val, field) - } -} - -func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) { - if unmarshaler, ok := bindUnmarshaler(field); ok { - err := unmarshaler.UnmarshalParam(value) - field.Set(reflect.ValueOf(unmarshaler).Elem()) - return true, err - } - return false, nil -} - -func unmarshalFieldPtr(value string, field reflect.Value) (bool, error) { - if field.IsNil() { - // Initialize the pointer to a nil value - field.Set(reflect.New(field.Type().Elem())) - } - return unmarshalFieldNonPtr(value, field.Elem()) -} diff --git a/handler/read_all.go b/handler/read_all.go index 24dc7e4..1fd5db7 100644 --- a/handler/read_all.go +++ b/handler/read_all.go @@ -32,7 +32,7 @@ func (c *WebHandler) ReadAllWeb(ctx echo.Context) error { } // Get the object & bind params to struct - if err := ParamBinder(currentStruct, ctx); err != nil { + if err := ctx.Bind(currentStruct); err != nil { return echo.NewHTTPError(http.StatusBadRequest, "No or invalid model provided.") } diff --git a/handler/read_one.go b/handler/read_one.go index d461370..6de14ec 100644 --- a/handler/read_one.go +++ b/handler/read_one.go @@ -26,7 +26,7 @@ func (c *WebHandler) ReadOneWeb(ctx echo.Context) error { currentStruct := c.EmptyStruct() // Get the object & bind params to struct - if err := ParamBinder(currentStruct, ctx); err != nil { + if err := ctx.Bind(currentStruct); err != nil { return echo.NewHTTPError(http.StatusBadRequest, "No or invalid model provided.") } diff --git a/handler/update.go b/handler/update.go index ef9834a..189fa12 100644 --- a/handler/update.go +++ b/handler/update.go @@ -27,7 +27,7 @@ func (c *WebHandler) UpdateWeb(ctx echo.Context) error { currentStruct := c.EmptyStruct() // Get the object & bind params to struct - if err := ParamBinder(currentStruct, ctx); err != nil { + if err := ctx.Bind(currentStruct); err != nil { return echo.NewHTTPError(http.StatusBadRequest, "No or invalid model provided.") }