mirror of https://github.com/harness/drone.git
95 lines
2.7 KiB
Go
95 lines
2.7 KiB
Go
// Copyright 2023 Harness, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package utils
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
// fillFromForm uses reflection to fill fields of 'data' from r.FormValue.
|
|
// It looks for a 'json' struct tag and uses that as the key in FormValue.
|
|
func FillFromForm(r *http.Request, data interface{}) error {
|
|
// Make sure form data is parsed
|
|
if err := r.ParseForm(); err != nil {
|
|
return err
|
|
}
|
|
if err := r.ParseMultipartForm(32 << 22); err != nil {
|
|
return err
|
|
}
|
|
|
|
v := reflect.ValueOf(data).Elem()
|
|
t := v.Type()
|
|
|
|
for i := 0; i < t.NumField(); i++ {
|
|
field := t.Field(i)
|
|
jsonTag := field.Tag.Get("json")
|
|
if jsonTag == "" {
|
|
// Skip fields with no json tag
|
|
continue
|
|
}
|
|
|
|
// The tag might be `json:"author,omitempty"`, so split on comma to isolate the key
|
|
tagParts := strings.Split(jsonTag, ",")
|
|
key := tagParts[0]
|
|
|
|
// Single-value retrieval:
|
|
formVal := r.FormValue(key)
|
|
|
|
// Now decide how to set based on the field type
|
|
fieldVal := v.Field(i)
|
|
switch fieldVal.Kind() { // nolint:exhaustive
|
|
case reflect.String:
|
|
// Just set the string
|
|
fieldVal.SetString(formVal)
|
|
|
|
case reflect.Slice:
|
|
// Check if it's a slice of strings
|
|
if fieldVal.Type().Elem().Kind() == reflect.String {
|
|
// For slices, let's fetch all form values under that key
|
|
// e.g. name=foo&name=bar => r.Form["name"] = []string{"foo","bar"}
|
|
values := r.Form[key]
|
|
fieldVal.Set(reflect.ValueOf(values))
|
|
}
|
|
|
|
case reflect.Map:
|
|
// Check if it's a map[string]string
|
|
if fieldVal.Type().Key().Kind() == reflect.String &&
|
|
fieldVal.Type().Elem().Kind() == reflect.String {
|
|
// We'll assume the form value is a JSON string. For example:
|
|
// extra={"foo":"bar","something":"else"}
|
|
if formVal == "" {
|
|
// If nothing is provided, just set an empty map
|
|
fieldVal.Set(reflect.ValueOf(map[string]string{}))
|
|
} else {
|
|
m := make(map[string]string)
|
|
if err := json.Unmarshal([]byte(formVal), &m); err != nil {
|
|
return fmt.Errorf("cannot unmarshal map from key %q: %w", key, err)
|
|
}
|
|
fieldVal.Set(reflect.ValueOf(m))
|
|
}
|
|
}
|
|
default:
|
|
log.Warn().Ctx(r.Context()).Msgf("Unsupported field type %v", fieldVal.Kind())
|
|
}
|
|
}
|
|
return nil
|
|
}
|