code.gitea.io/gitea@v1.19.3/modules/web/middleware/binding.go (about) 1 // Copyright 2014 The Gogs Authors. All rights reserved. 2 // Copyright 2019 The Gitea Authors. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 5 package middleware 6 7 import ( 8 "reflect" 9 "strings" 10 11 "code.gitea.io/gitea/modules/translation" 12 "code.gitea.io/gitea/modules/util" 13 "code.gitea.io/gitea/modules/validation" 14 15 "gitea.com/go-chi/binding" 16 ) 17 18 // Form form binding interface 19 type Form interface { 20 binding.Validator 21 } 22 23 func init() { 24 binding.SetNameMapper(util.ToSnakeCase) 25 } 26 27 // AssignForm assign form values back to the template data. 28 func AssignForm(form interface{}, data map[string]interface{}) { 29 typ := reflect.TypeOf(form) 30 val := reflect.ValueOf(form) 31 32 for typ.Kind() == reflect.Ptr { 33 typ = typ.Elem() 34 val = val.Elem() 35 } 36 37 for i := 0; i < typ.NumField(); i++ { 38 field := typ.Field(i) 39 40 fieldName := field.Tag.Get("form") 41 // Allow ignored fields in the struct 42 if fieldName == "-" { 43 continue 44 } else if len(fieldName) == 0 { 45 fieldName = util.ToSnakeCase(field.Name) 46 } 47 48 data[fieldName] = val.Field(i).Interface() 49 } 50 } 51 52 func getRuleBody(field reflect.StructField, prefix string) string { 53 for _, rule := range strings.Split(field.Tag.Get("binding"), ";") { 54 if strings.HasPrefix(rule, prefix) { 55 return rule[len(prefix) : len(rule)-1] 56 } 57 } 58 return "" 59 } 60 61 // GetSize get size int form tag 62 func GetSize(field reflect.StructField) string { 63 return getRuleBody(field, "Size(") 64 } 65 66 // GetMinSize get minimal size in form tag 67 func GetMinSize(field reflect.StructField) string { 68 return getRuleBody(field, "MinSize(") 69 } 70 71 // GetMaxSize get max size in form tag 72 func GetMaxSize(field reflect.StructField) string { 73 return getRuleBody(field, "MaxSize(") 74 } 75 76 // GetInclude get include in form tag 77 func GetInclude(field reflect.StructField) string { 78 return getRuleBody(field, "Include(") 79 } 80 81 // Validate validate TODO: 82 func Validate(errs binding.Errors, data map[string]interface{}, f Form, l translation.Locale) binding.Errors { 83 if errs.Len() == 0 { 84 return errs 85 } 86 87 data["HasError"] = true 88 // If the field with name errs[0].FieldNames[0] is not found in form 89 // somehow, some code later on will panic on Data["ErrorMsg"].(string). 90 // So initialize it to some default. 91 data["ErrorMsg"] = l.Tr("form.unknown_error") 92 AssignForm(f, data) 93 94 typ := reflect.TypeOf(f) 95 96 if typ.Kind() == reflect.Ptr { 97 typ = typ.Elem() 98 } 99 100 if field, ok := typ.FieldByName(errs[0].FieldNames[0]); ok { 101 fieldName := field.Tag.Get("form") 102 if fieldName != "-" { 103 data["Err_"+field.Name] = true 104 105 trName := field.Tag.Get("locale") 106 if len(trName) == 0 { 107 trName = l.Tr("form." + field.Name) 108 } else { 109 trName = l.Tr(trName) 110 } 111 112 switch errs[0].Classification { 113 case binding.ERR_REQUIRED: 114 data["ErrorMsg"] = trName + l.Tr("form.require_error") 115 case binding.ERR_ALPHA_DASH: 116 data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_error") 117 case binding.ERR_ALPHA_DASH_DOT: 118 data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_error") 119 case validation.ErrGitRefName: 120 data["ErrorMsg"] = trName + l.Tr("form.git_ref_name_error") 121 case binding.ERR_SIZE: 122 data["ErrorMsg"] = trName + l.Tr("form.size_error", GetSize(field)) 123 case binding.ERR_MIN_SIZE: 124 data["ErrorMsg"] = trName + l.Tr("form.min_size_error", GetMinSize(field)) 125 case binding.ERR_MAX_SIZE: 126 data["ErrorMsg"] = trName + l.Tr("form.max_size_error", GetMaxSize(field)) 127 case binding.ERR_EMAIL: 128 data["ErrorMsg"] = trName + l.Tr("form.email_error") 129 case binding.ERR_URL: 130 data["ErrorMsg"] = trName + l.Tr("form.url_error", errs[0].Message) 131 case binding.ERR_INCLUDE: 132 data["ErrorMsg"] = trName + l.Tr("form.include_error", GetInclude(field)) 133 case validation.ErrGlobPattern: 134 data["ErrorMsg"] = trName + l.Tr("form.glob_pattern_error", errs[0].Message) 135 case validation.ErrRegexPattern: 136 data["ErrorMsg"] = trName + l.Tr("form.regex_pattern_error", errs[0].Message) 137 case validation.ErrUsername: 138 data["ErrorMsg"] = trName + l.Tr("form.username_error") 139 case validation.ErrInvalidGroupTeamMap: 140 data["ErrorMsg"] = trName + l.Tr("form.invalid_group_team_map_error", errs[0].Message) 141 default: 142 msg := errs[0].Classification 143 if msg != "" && errs[0].Message != "" { 144 msg += ": " 145 } 146 147 msg += errs[0].Message 148 if msg == "" { 149 msg = l.Tr("form.unknown_error") 150 } 151 data["ErrorMsg"] = trName + ": " + msg 152 } 153 return errs 154 } 155 } 156 return errs 157 }