128 lines
3.1 KiB
Go
128 lines
3.1 KiB
Go
/*
|
|
* Copyright 2024 the KubeSphere Authors.
|
|
* Please refer to the LICENSE file in the root directory of the project.
|
|
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
|
|
*/
|
|
|
|
package params
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/emicklei/go-restful/v3"
|
|
)
|
|
|
|
const (
|
|
PagingParam = "paging"
|
|
OrderByParam = "orderBy"
|
|
ConditionsParam = "conditions"
|
|
ReverseParam = "reverse"
|
|
)
|
|
|
|
const (
|
|
DefaultLimit = 10
|
|
DefaultPage = 1
|
|
)
|
|
|
|
// ParsePaging parse the paging parameters from the request, then returns the limit and offset
|
|
// supported format: ?limit=1&page=1
|
|
// supported format: ?paging=limit=100,page=1
|
|
func ParsePaging(req *restful.Request) (limit, offset int) {
|
|
paging := req.QueryParameter(PagingParam)
|
|
limit = 10
|
|
page := DefaultPage
|
|
if paging != "" {
|
|
if groups := regexp.MustCompile(`^limit=(-?\d+),page=(\d+)$`).FindStringSubmatch(paging); len(groups) == 3 {
|
|
limit = AtoiOrDefault(groups[1], DefaultLimit)
|
|
page = AtoiOrDefault(groups[2], DefaultPage)
|
|
}
|
|
} else {
|
|
// try to parse from format ?limit=10&page=1
|
|
limit = AtoiOrDefault(req.QueryParameter("limit"), DefaultLimit)
|
|
page = AtoiOrDefault(req.QueryParameter("page"), DefaultPage)
|
|
}
|
|
offset = (page - 1) * limit
|
|
|
|
// use the explicit offset
|
|
if start := req.QueryParameter("start"); start != "" {
|
|
offset = AtoiOrDefault(start, offset)
|
|
}
|
|
return
|
|
}
|
|
|
|
func AtoiOrDefault(str string, defVal int) int {
|
|
if result, err := strconv.Atoi(str); err == nil {
|
|
return result
|
|
}
|
|
return defVal
|
|
}
|
|
|
|
var (
|
|
invalidKeyRegex = regexp.MustCompile(`[\s(){}\[\]]`)
|
|
)
|
|
|
|
// Ref: stdlib url.ParseQuery
|
|
func parseConditions(conditionsStr string) (*Conditions, error) {
|
|
// string likes: key1=value1,key2~value2,key3=
|
|
// exact query: key=value, if value is empty means label value must be ""
|
|
// fuzzy query: key~value, if value is empty means label value is "" or label key not exist
|
|
var conditions = &Conditions{Match: make(map[string]string, 0), Fuzzy: make(map[string]string, 0)}
|
|
|
|
for conditionsStr != "" {
|
|
key := conditionsStr
|
|
if i := strings.Index(key, ","); i >= 0 {
|
|
key, conditionsStr = key[:i], key[i+1:]
|
|
} else {
|
|
conditionsStr = ""
|
|
}
|
|
if key == "" {
|
|
continue
|
|
}
|
|
value := ""
|
|
var isFuzzy = false
|
|
if i := strings.IndexAny(key, "~="); i >= 0 {
|
|
if key[i] == '~' {
|
|
isFuzzy = true
|
|
}
|
|
key, value = key[:i], key[i+1:]
|
|
}
|
|
if invalidKeyRegex.MatchString(key) {
|
|
return nil, fmt.Errorf("invalid conditions")
|
|
}
|
|
if isFuzzy {
|
|
conditions.Fuzzy[key] = value
|
|
} else {
|
|
conditions.Match[key] = value
|
|
}
|
|
}
|
|
return conditions, nil
|
|
}
|
|
|
|
func ParseConditions(req *restful.Request) (*Conditions, error) {
|
|
return parseConditions(req.QueryParameter(ConditionsParam))
|
|
}
|
|
|
|
type Conditions struct {
|
|
Match map[string]string
|
|
Fuzzy map[string]string
|
|
}
|
|
|
|
func GetBoolValueWithDefault(req *restful.Request, name string, dv bool) bool {
|
|
reverse := req.QueryParameter(name)
|
|
if v, err := strconv.ParseBool(reverse); err == nil {
|
|
return v
|
|
}
|
|
return dv
|
|
}
|
|
|
|
func GetStringValueWithDefault(req *restful.Request, name string, dv string) string {
|
|
v := req.QueryParameter(name)
|
|
if v == "" {
|
|
v = dv
|
|
}
|
|
return v
|
|
}
|