2021-05-12 12:38:18 +00:00
|
|
|
package admin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/url"
|
|
|
|
"reflect"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
queryAdminPath = "/admin"
|
|
|
|
)
|
|
|
|
|
|
|
|
func buildQueryPath(endpoint, path, args string) string {
|
2021-06-04 11:22:52 +00:00
|
|
|
// Sometimes the API requires single URL key with no values
|
|
|
|
// For instance, the Quota code uses the admin API path to "/user?quota"
|
|
|
|
// This is done this way since url.Values does not support adding keys without values.
|
|
|
|
//
|
|
|
|
// So Quota code passes the begining of the query (indicated with a marker "?") in its path already, so we need to escape it
|
|
|
|
// and add a separator key instead
|
|
|
|
// So we can get something like "/admin/user?quota&" instead of passing two beginning query markers ("?")
|
|
|
|
if strings.Contains(path, "?") {
|
|
|
|
return fmt.Sprintf("%s%s%s&%s", endpoint, queryAdminPath, path, args)
|
|
|
|
}
|
|
|
|
|
2021-05-12 12:38:18 +00:00
|
|
|
return fmt.Sprintf("%s%s%s?%s", endpoint, queryAdminPath, path, args)
|
|
|
|
}
|
|
|
|
|
|
|
|
// valueToURLParams encodes structs into URL query parameters.
|
2022-02-11 13:18:34 +00:00
|
|
|
func valueToURLParams(i interface{}, accpetableFields []string) url.Values {
|
2021-05-12 12:38:18 +00:00
|
|
|
values := url.Values{}
|
|
|
|
|
|
|
|
// Always return json
|
|
|
|
values.Add("format", "json")
|
|
|
|
|
2022-02-11 13:18:34 +00:00
|
|
|
getReflect(i, accpetableFields, &values)
|
2021-05-12 12:38:18 +00:00
|
|
|
return values
|
|
|
|
}
|
|
|
|
|
2022-02-11 13:18:34 +00:00
|
|
|
func addToURLParams(v *url.Values, i interface{}, acceptableFields []string) {
|
|
|
|
getReflect(i, acceptableFields, v)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: we use linear search here, as none of the API endpoints
|
|
|
|
// supports more than 10 parameters, in this case asymptotics don't
|
|
|
|
// matter and we are likely faster this way (even when compared to a
|
|
|
|
// map).
|
|
|
|
func contains(tagList []string, tag string) bool {
|
|
|
|
for _, tag2 := range tagList {
|
|
|
|
if tag == tag2 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func getReflect(i interface{}, acceptableFields []string, values *url.Values) {
|
2021-05-12 12:38:18 +00:00
|
|
|
t := reflect.TypeOf(i)
|
|
|
|
v := reflect.ValueOf(i)
|
|
|
|
|
|
|
|
for b := 0; b < v.NumField(); b++ {
|
|
|
|
v2 := v.Field(b)
|
2022-02-11 13:18:34 +00:00
|
|
|
tag := t.Field(b).Tag.Get("url")
|
|
|
|
if tag == "-" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
tagList := strings.Split(tag, ",")
|
|
|
|
name := tagList[0]
|
|
|
|
if len(name) == 0 {
|
|
|
|
name = t.Field(b).Name
|
|
|
|
}
|
2021-05-12 12:38:18 +00:00
|
|
|
|
2022-02-11 13:18:34 +00:00
|
|
|
if v2.Kind() == reflect.Struct {
|
|
|
|
getReflect(v2.Interface(), acceptableFields, values)
|
|
|
|
continue
|
|
|
|
}
|
2021-05-12 12:38:18 +00:00
|
|
|
|
2022-02-11 13:18:34 +00:00
|
|
|
if v2.Kind() == reflect.Slice {
|
|
|
|
for i := 0; i < v2.Len(); i++ {
|
|
|
|
item := v2.Index(i)
|
|
|
|
getReflect(item.Interface(), acceptableFields, values)
|
2021-05-12 12:38:18 +00:00
|
|
|
}
|
2022-02-11 13:18:34 +00:00
|
|
|
continue
|
|
|
|
}
|
2021-05-12 12:38:18 +00:00
|
|
|
|
2022-02-11 13:18:34 +00:00
|
|
|
if v2.Kind() == reflect.String ||
|
|
|
|
v2.Kind() == reflect.Bool ||
|
|
|
|
v2.Kind() == reflect.Int {
|
2021-05-12 12:38:18 +00:00
|
|
|
|
2022-02-11 13:18:34 +00:00
|
|
|
_v2 := fmt.Sprint(v2)
|
|
|
|
if len(_v2) > 0 && contains(acceptableFields, name) {
|
|
|
|
values.Add(name, _v2)
|
2021-05-12 12:38:18 +00:00
|
|
|
}
|
2022-02-11 13:18:34 +00:00
|
|
|
continue
|
|
|
|
}
|
2021-05-12 12:38:18 +00:00
|
|
|
|
2022-02-11 13:18:34 +00:00
|
|
|
if v2.Kind() == reflect.Ptr && v2.IsValid() && !v2.IsNil() {
|
|
|
|
_v2 := fmt.Sprint(v2.Elem())
|
|
|
|
if len(_v2) > 0 && contains(acceptableFields, name) {
|
2021-05-12 12:38:18 +00:00
|
|
|
values.Add(name, _v2)
|
|
|
|
}
|
2022-02-11 13:18:34 +00:00
|
|
|
continue
|
2021-05-12 12:38:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|