diff --git a/internal/bootstrap/routes.go b/internal/bootstrap/routes.go index 007584d..4bf9778 100644 --- a/internal/bootstrap/routes.go +++ b/internal/bootstrap/routes.go @@ -226,7 +226,7 @@ func registerDashboardAIConfigRoutes(group *gin.RouterGroup) { group.Any("/list", dashboard.AIConfigAnyList) group.Any("/list_all", dashboard.AIConfigAnyList_all) group.POST("/update", dashboard.AIConfigPostUpdate) - group.POST("/update_sort", dashboard.AIConfigPostUpdate_sort) + group.POST("/update_sort", dashboard.AIConfigPostUpdateSort) group.POST("/update_status", dashboard.AIConfigPostUpdate_status) } diff --git a/internal/handlers/dashboard/ai_config_handler.go b/internal/handlers/dashboard/ai_config_handler.go index d3ef8a1..659f827 100644 --- a/internal/handlers/dashboard/ai_config_handler.go +++ b/internal/handlers/dashboard/ai_config_handler.go @@ -25,7 +25,7 @@ func AIConfigAnyList(ctx *gin.Context) { params.QueryFilter{ParamName: "modelType"}, params.QueryFilter{ParamName: "name", Op: params.Like}, params.QueryFilter{ParamName: "modelName", Op: params.Like}, - ).Desc("sort_no").Desc("id")) + ).Asc("sort_no").Desc("id")) results := make([]response.AIConfigResponse, 0, len(list)) for _, item := range list { results = append(results, response.BuildAIConfigResponse(&item)) @@ -145,7 +145,7 @@ func AIConfigPostUpdate_status(ctx *gin.Context) { httpx.WriteJSON(ctx, nil) } -func AIConfigPostUpdate_sort(ctx *gin.Context) { +func AIConfigPostUpdateSort(ctx *gin.Context) { if _, err := services.AuthService.RequirePermission(ctx, constants.PermissionAIConfigUpdate); err != nil { httpx.WriteJSON(ctx, err) return diff --git a/internal/pkg/httpx/params/params.go b/internal/pkg/httpx/params/params.go index 39eae9b..b510775 100644 --- a/internal/pkg/httpx/params/params.go +++ b/internal/pkg/httpx/params/params.go @@ -5,6 +5,7 @@ import ( "fmt" "log/slog" "net/http" + "reflect" "strconv" "strings" "time" @@ -54,7 +55,7 @@ func ReadForm(ctx *gin.Context, obj any) error { if err := decoder.Decode(obj, values); err != nil { return err } - return validate.Struct(obj) + return validateStruct(obj) } func ReadJSON(ctx *gin.Context, obj any) error { @@ -64,6 +65,23 @@ func ReadJSON(ctx *gin.Context, obj any) error { 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) } diff --git a/internal/pkg/httpx/params/params_test.go b/internal/pkg/httpx/params/params_test.go new file mode 100644 index 0000000..cb9532f --- /dev/null +++ b/internal/pkg/httpx/params/params_test.go @@ -0,0 +1,31 @@ +package params + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/gin-gonic/gin" +) + +func newJSONContext(body string) *gin.Context { + gin.SetMode(gin.TestMode) + w := httptest.NewRecorder() + ctx, _ := gin.CreateTestContext(w) + ctx.Request = httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body)) + ctx.Request.Header.Set("Content-Type", "application/json") + return ctx +} + +func TestReadJSONAcceptsRootArray(t *testing.T) { + var ids []int64 + + if err := ReadJSON(newJSONContext(`[3,4]`), &ids); err != nil { + t.Fatalf("ReadJSON returned error: %v", err) + } + + if len(ids) != 2 || ids[0] != 3 || ids[1] != 4 { + t.Fatalf("expected ids [3 4], got %#v", ids) + } +}