feat: complete SOP version management
This commit is contained in:
30
internal/scenario/field_validation_test.go
Normal file
30
internal/scenario/field_validation_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package scenario
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateFieldInput(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input fieldInput
|
||||
wantErr bool
|
||||
}{
|
||||
{name: "text without options", input: fieldInput{FieldKey: "customer_name", FieldType: "text"}},
|
||||
{name: "select options", input: fieldInput{FieldKey: "pet_type", FieldType: "select", Options: json.RawMessage(`["猫","狗"]`)}},
|
||||
{name: "select missing options", input: fieldInput{FieldKey: "pet_type", FieldType: "select"}, wantErr: true},
|
||||
{name: "invalid key", input: fieldInput{FieldKey: "1pet", FieldType: "text"}, wantErr: true},
|
||||
{name: "options object", input: fieldInput{FieldKey: "pet_type", FieldType: "select", Options: json.RawMessage(`{"猫":1}`)}, wantErr: true},
|
||||
{name: "options null", input: fieldInput{FieldKey: "pet_note", FieldType: "text", Options: json.RawMessage(`null`)}, wantErr: true},
|
||||
{name: "validation array", input: fieldInput{FieldKey: "pet_age", FieldType: "number", Validation: json.RawMessage(`[1]`)}, wantErr: true},
|
||||
{name: "validation null", input: fieldInput{FieldKey: "pet_age", FieldType: "number", Validation: json.RawMessage(`null`)}, wantErr: true},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if err := validateFieldInput(test.input); (err != nil) != test.wantErr {
|
||||
t.Fatalf("validateFieldInput() error = %v, wantErr %v", err, test.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.iwork-ai.com/xdc/iqudo-top1/internal/access"
|
||||
"git.iwork-ai.com/xdc/iqudo-top1/internal/audit"
|
||||
@@ -188,8 +189,8 @@ func (h *Handler) CreateField(c *gin.Context) {
|
||||
response.Error(c, http.StatusBadRequest, "INVALID_ARGUMENT", "字段配置不正确")
|
||||
return
|
||||
}
|
||||
if !fieldKeyPattern.MatchString(input.FieldKey) {
|
||||
response.Error(c, http.StatusBadRequest, "INVALID_ARGUMENT", "字段标识必须以字母开头,且只能包含字母、数字和下划线")
|
||||
if err := validateFieldInput(input); err != nil {
|
||||
response.Error(c, http.StatusBadRequest, "INVALID_ARGUMENT", err.Error())
|
||||
return
|
||||
}
|
||||
item := model.ScenarioField{TenantID: p.TenantID, ScenarioID: scenarioID, FieldKey: input.FieldKey, FieldName: input.FieldName, FieldType: input.FieldType, Required: input.Required, Options: normalizedJSON(input.Options, `[]`), Validation: normalizedJSON(input.Validation, `{}`), SortOrder: input.SortOrder}
|
||||
@@ -221,8 +222,8 @@ func (h *Handler) UpdateField(c *gin.Context) {
|
||||
response.Error(c, http.StatusBadRequest, "INVALID_ARGUMENT", "字段配置不正确")
|
||||
return
|
||||
}
|
||||
if !fieldKeyPattern.MatchString(input.FieldKey) {
|
||||
response.Error(c, http.StatusBadRequest, "INVALID_ARGUMENT", "字段标识必须以字母开头,且只能包含字母、数字和下划线")
|
||||
if err := validateFieldInput(input); err != nil {
|
||||
response.Error(c, http.StatusBadRequest, "INVALID_ARGUMENT", err.Error())
|
||||
return
|
||||
}
|
||||
updates := map[string]interface{}{"field_key": input.FieldKey, "field_name": input.FieldName, "field_type": input.FieldType, "required": input.Required, "options": normalizedJSON(input.Options, `[]`), "validation": normalizedJSON(input.Validation, `{}`), "sort_order": input.SortOrder}
|
||||
@@ -268,6 +269,35 @@ func normalizedJSON(value json.RawMessage, fallback string) datatypes.JSON {
|
||||
return datatypes.JSON(value)
|
||||
}
|
||||
|
||||
func validateFieldInput(input fieldInput) error {
|
||||
if !fieldKeyPattern.MatchString(input.FieldKey) {
|
||||
return errors.New("字段标识必须以字母开头,且只能包含字母、数字和下划线")
|
||||
}
|
||||
if len(input.Options) > 0 {
|
||||
var options []string
|
||||
if err := json.Unmarshal(input.Options, &options); err != nil || options == nil {
|
||||
return errors.New("字段选项必须是文本数组")
|
||||
}
|
||||
for _, option := range options {
|
||||
if strings.TrimSpace(option) == "" {
|
||||
return errors.New("字段选项不能为空")
|
||||
}
|
||||
}
|
||||
if (input.FieldType == "select" || input.FieldType == "multiselect") && len(options) == 0 {
|
||||
return errors.New("单选或多选字段至少需要一个选项")
|
||||
}
|
||||
} else if input.FieldType == "select" || input.FieldType == "multiselect" {
|
||||
return errors.New("单选或多选字段至少需要一个选项")
|
||||
}
|
||||
if len(input.Validation) > 0 {
|
||||
var validation map[string]interface{}
|
||||
if err := json.Unmarshal(input.Validation, &validation); err != nil || validation == nil {
|
||||
return errors.New("字段校验规则必须是 JSON 对象")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func idParam(c *gin.Context, key string) (uint64, bool) {
|
||||
id, err := strconv.ParseUint(c.Param(key), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
|
||||
Reference in New Issue
Block a user