2bbf42b741
Remove Agent Desk users, roles, login sessions, tokens, and local permission persistence. Expose the backend as an embeddable ai-agent module with host-provided subject lookup and operation authorization callbacks, and complete the frontend/backend repository split.
290 lines
5.9 KiB
Go
290 lines
5.9 KiB
Go
package params
|
|
|
|
import (
|
|
"code.tczkiot.com/wlw/ai-agent/internal/pkg/errorsx"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/go-playground/validator/v10"
|
|
"github.com/gorilla/schema"
|
|
"github.com/mlogclub/simple/common/dates"
|
|
"github.com/mlogclub/simple/common/jsons"
|
|
"github.com/mlogclub/simple/common/strs"
|
|
"github.com/mlogclub/simple/sqls"
|
|
"github.com/spf13/cast"
|
|
)
|
|
|
|
var (
|
|
decoder = schema.NewDecoder()
|
|
validate = validator.New()
|
|
)
|
|
|
|
func init() {
|
|
decoder.SetAliasTag("form")
|
|
decoder.ZeroEmpty(true)
|
|
decoder.IgnoreUnknownKeys(true)
|
|
}
|
|
|
|
func paramError(name string) error {
|
|
return fmt.Errorf("unable to find param value '%s'", name)
|
|
}
|
|
|
|
func ReadForm(ctx *gin.Context, obj any) error {
|
|
if ctx == nil {
|
|
return errors.New("request context is nil")
|
|
}
|
|
if err := ctx.Request.ParseForm(); err != nil {
|
|
return err
|
|
}
|
|
values := ctx.Request.Form
|
|
if len(values) == 0 {
|
|
if err := ctx.Request.ParseMultipartForm(32 << 20); err != nil && !errors.Is(err, http.ErrNotMultipart) {
|
|
return err
|
|
}
|
|
values = ctx.Request.Form
|
|
}
|
|
if len(values) == 0 {
|
|
return nil
|
|
}
|
|
if err := decoder.Decode(obj, values); err != nil {
|
|
return err
|
|
}
|
|
return validateStruct(obj)
|
|
}
|
|
|
|
func ReadJSON(ctx *gin.Context, obj any) error {
|
|
if ctx == nil {
|
|
return errors.New("request context is nil")
|
|
}
|
|
if err := ctx.ShouldBindJSON(obj); err != nil {
|
|
return err
|
|
}
|
|
return validateStruct(obj)
|
|
}
|
|
|
|
func validateStruct(obj any) error {
|
|
if obj == nil {
|
|
return nil
|
|
}
|
|
value := reflect.ValueOf(obj)
|
|
for value.Kind() == reflect.Pointer {
|
|
if value.IsNil() {
|
|
return validate.Struct(obj)
|
|
}
|
|
value = value.Elem()
|
|
}
|
|
if value.Kind() != reflect.Struct {
|
|
return nil
|
|
}
|
|
return validate.Struct(obj)
|
|
}
|
|
|
|
func Get(ctx *gin.Context, name string) (string, bool) {
|
|
str := FormValue(ctx, name)
|
|
return str, str != ""
|
|
}
|
|
|
|
func GetInt64(ctx *gin.Context, name string) (int64, bool) {
|
|
str, ok := Get(ctx, name)
|
|
if !ok {
|
|
return 0, false
|
|
}
|
|
value, err := cast.ToInt64E(str)
|
|
if err != nil {
|
|
return 0, false
|
|
}
|
|
return value, true
|
|
}
|
|
|
|
func GetInt(ctx *gin.Context, name string) (int, bool) {
|
|
str, ok := Get(ctx, name)
|
|
if !ok {
|
|
return 0, false
|
|
}
|
|
value, err := cast.ToIntE(str)
|
|
if err != nil {
|
|
return 0, false
|
|
}
|
|
return value, true
|
|
}
|
|
|
|
func GetBool(ctx *gin.Context, name string) (bool, bool) {
|
|
str, ok := Get(ctx, name)
|
|
if !ok {
|
|
return false, false
|
|
}
|
|
value, err := cast.ToBoolE(str)
|
|
if err != nil {
|
|
return false, false
|
|
}
|
|
return value, true
|
|
}
|
|
|
|
func GetTime(ctx *gin.Context, name string) *time.Time {
|
|
value, _ := Get(ctx, name)
|
|
if strs.IsBlank(value) {
|
|
return nil
|
|
}
|
|
layouts := []string{dates.FmtDateTime, dates.FmtDate, dates.FmtDateTimeNoSeconds}
|
|
for _, layout := range layouts {
|
|
if ret, err := dates.Parse(value, layout); err == nil {
|
|
return &ret
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetInt64Arr(ctx *gin.Context, name string) []int64 {
|
|
str, ok := Get(ctx, name)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
str = strings.TrimSpace(str)
|
|
if strings.HasPrefix(str, "[") && strings.HasSuffix(str, "]") {
|
|
var ret []int64
|
|
if err := jsons.Parse(str, &ret); err != nil {
|
|
slog.Error(err.Error())
|
|
}
|
|
return ret
|
|
}
|
|
return StrSplitToInt64Arr(str)
|
|
}
|
|
|
|
func StrSplitToInt64Arr(str string) (ret []int64) {
|
|
if strs.IsBlank(str) {
|
|
return ret
|
|
}
|
|
for _, s := range strings.Split(str, ",") {
|
|
i, err := cast.ToInt64E(strings.TrimSpace(s))
|
|
if err == nil {
|
|
ret = append(ret, i)
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func FormValue(ctx *gin.Context, name string) string {
|
|
if ctx == nil {
|
|
return ""
|
|
}
|
|
if value := ctx.PostForm(name); value != "" {
|
|
return value
|
|
}
|
|
return ctx.Query(name)
|
|
}
|
|
|
|
func FormValueRequired(ctx *gin.Context, name string) (string, error) {
|
|
str := FormValue(ctx, name)
|
|
if len(str) == 0 {
|
|
return "", errorsx.InvalidParamI18n("error.param.required", name)
|
|
}
|
|
return str, nil
|
|
}
|
|
|
|
func FormValueDefault(ctx *gin.Context, name, def string) string {
|
|
if value := FormValue(ctx, name); value != "" {
|
|
return value
|
|
}
|
|
return def
|
|
}
|
|
|
|
func FormValueInt(ctx *gin.Context, name string) (int, error) {
|
|
str := FormValue(ctx, name)
|
|
if str == "" {
|
|
return 0, paramError(name)
|
|
}
|
|
return strconv.Atoi(str)
|
|
}
|
|
|
|
func FormValueIntDefault(ctx *gin.Context, name string, def int) int {
|
|
if v, err := FormValueInt(ctx, name); err == nil {
|
|
return v
|
|
}
|
|
return def
|
|
}
|
|
|
|
func FormValueInt64(ctx *gin.Context, name string) (int64, error) {
|
|
str := FormValue(ctx, name)
|
|
if str == "" {
|
|
return 0, paramError(name)
|
|
}
|
|
return strconv.ParseInt(str, 10, 64)
|
|
}
|
|
|
|
func FormValueInt64Default(ctx *gin.Context, name string, def int64) int64 {
|
|
if v, err := FormValueInt64(ctx, name); err == nil {
|
|
return v
|
|
}
|
|
return def
|
|
}
|
|
|
|
func FormValueInt64Array(ctx *gin.Context, name string) []int64 {
|
|
str := strings.TrimSpace(FormValue(ctx, name))
|
|
if strings.HasPrefix(str, "[") && strings.HasSuffix(str, "]") {
|
|
var ret []int64
|
|
if err := jsons.Parse(str, &ret); err != nil {
|
|
slog.Error(err.Error())
|
|
}
|
|
return ret
|
|
}
|
|
return StrSplitToInt64Arr(str)
|
|
}
|
|
|
|
func FormValueStringArray(ctx *gin.Context, name string) []string {
|
|
str := FormValue(ctx, name)
|
|
if len(str) == 0 {
|
|
return nil
|
|
}
|
|
var ret []string
|
|
for _, s := range strings.Split(str, ",") {
|
|
s = strings.TrimSpace(s)
|
|
if len(s) > 0 {
|
|
ret = append(ret, s)
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func FormValueBool(ctx *gin.Context, name string) (bool, error) {
|
|
str := FormValue(ctx, name)
|
|
if str == "" {
|
|
return false, paramError(name)
|
|
}
|
|
return strconv.ParseBool(str)
|
|
}
|
|
|
|
func FormValueBoolDefault(ctx *gin.Context, name string, def bool) bool {
|
|
str := FormValue(ctx, name)
|
|
if str == "" {
|
|
return def
|
|
}
|
|
value, err := strconv.ParseBool(str)
|
|
if err != nil {
|
|
return def
|
|
}
|
|
return value
|
|
}
|
|
|
|
func FormDate(ctx *gin.Context, name string) *time.Time {
|
|
return GetTime(ctx, name)
|
|
}
|
|
|
|
func GetPaging(ctx *gin.Context) *sqls.Paging {
|
|
page := FormValueIntDefault(ctx, "page", 1)
|
|
limit := FormValueIntDefault(ctx, "limit", 20)
|
|
if page <= 0 {
|
|
page = 1
|
|
}
|
|
if limit <= 0 {
|
|
limit = 20
|
|
}
|
|
return &sqls.Paging{Page: page, Limit: limit}
|
|
}
|