github.com/System-Glitch/goyave/v2@v2.10.3-0.20200819142921-51011e75d504/validation/rules.go (about) 1 package validation 2 3 import ( 4 "math" 5 "reflect" 6 "strconv" 7 "strings" 8 9 "github.com/Code-Hex/uniseg" 10 "github.com/System-Glitch/goyave/v2/helper" 11 "github.com/System-Glitch/goyave/v2/helper/filesystem" 12 ) 13 14 func validateRequired(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 15 val, ok := form[field] 16 if ok { 17 if str, okStr := val.(string); okStr && str == "" { 18 return false 19 } 20 } 21 return ok 22 } 23 24 func validateMin(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 25 min, err := strconv.ParseFloat(parameters[0], 64) 26 if err != nil { 27 panic(err) 28 } 29 switch GetFieldType(value) { 30 case "numeric": 31 floatValue, _ := helper.ToFloat64(value) 32 return floatValue >= min 33 case "string": 34 return uniseg.GraphemeClusterCount(value.(string)) >= int(min) 35 case "array": 36 list := reflect.ValueOf(value) 37 return list.Len() >= int(min) 38 case "file": 39 files, _ := value.([]filesystem.File) 40 for _, file := range files { 41 if file.Header.Size < int64(min)*1024 { 42 return false 43 } 44 } 45 return true 46 } 47 48 return true // Pass if field type cannot be checked (bool, dates, ...) 49 } 50 51 func validateMax(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 52 max, err := strconv.ParseFloat(parameters[0], 64) 53 if err != nil { 54 panic(err) 55 } 56 switch GetFieldType(value) { 57 case "numeric": 58 floatValue, _ := helper.ToFloat64(value) 59 return floatValue <= max 60 case "string": 61 return uniseg.GraphemeClusterCount(value.(string)) <= int(max) 62 case "array": 63 list := reflect.ValueOf(value) 64 return list.Len() <= int(max) 65 case "file": 66 files, _ := value.([]filesystem.File) 67 for _, file := range files { 68 if file.Header.Size > int64(max)*1024 { 69 return false 70 } 71 } 72 return true 73 } 74 75 return true // Pass if field type cannot be checked (bool, dates, ...) 76 } 77 78 func validateBetween(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 79 min, errMin := strconv.ParseFloat(parameters[0], 64) 80 max, errMax := strconv.ParseFloat(parameters[1], 64) 81 if errMin != nil { 82 panic(errMin) 83 } 84 if errMax != nil { 85 panic(errMax) 86 } 87 88 switch GetFieldType(value) { 89 case "numeric": 90 floatValue, _ := helper.ToFloat64(value) 91 return floatValue >= min && floatValue <= max 92 case "string": 93 length := uniseg.GraphemeClusterCount(value.(string)) 94 return length >= int(min) && length <= int(max) 95 case "array": 96 list := reflect.ValueOf(value) 97 length := list.Len() 98 return length >= int(min) && length <= int(max) 99 case "file": 100 files, _ := value.([]filesystem.File) 101 for _, file := range files { 102 minSize := int64(min) * 1024 103 maxSize := int64(max) * 1024 104 if file.Header.Size < minSize || file.Header.Size > maxSize { 105 return false 106 } 107 } 108 return true 109 } 110 111 return true // Pass if field type cannot be checked (bool, dates, ...) 112 } 113 114 func validateGreaterThan(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 115 valueType := GetFieldType(value) 116 117 compared, exists := form[parameters[0]] 118 if !exists || valueType != GetFieldType(compared) { 119 return false // Can't compare two different types or missing field 120 } 121 122 switch valueType { 123 case "numeric": 124 floatValue, _ := helper.ToFloat64(value) 125 comparedFloatValue, _ := helper.ToFloat64(compared) 126 return floatValue > comparedFloatValue 127 case "string": 128 return uniseg.GraphemeClusterCount(value.(string)) > uniseg.GraphemeClusterCount(compared.(string)) 129 case "array": 130 return reflect.ValueOf(value).Len() > reflect.ValueOf(compared).Len() 131 case "file": 132 files, _ := value.([]filesystem.File) 133 comparedFiles, _ := compared.([]filesystem.File) 134 for _, file := range files { 135 for _, comparedFile := range comparedFiles { 136 if file.Header.Size <= comparedFile.Header.Size { 137 return false 138 } 139 } 140 } 141 return true 142 } 143 144 return true // Pass if field type cannot be checked (bool, dates, ...) 145 } 146 147 func validateGreaterThanEqual(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 148 valueType := GetFieldType(value) 149 150 compared, exists := form[parameters[0]] 151 if !exists || valueType != GetFieldType(compared) { 152 return false // Can't compare two different types or missing field 153 } 154 155 switch valueType { 156 case "numeric": 157 floatValue, _ := helper.ToFloat64(value) 158 comparedFloatValue, _ := helper.ToFloat64(compared) 159 return floatValue >= comparedFloatValue 160 case "string": 161 return uniseg.GraphemeClusterCount(value.(string)) >= uniseg.GraphemeClusterCount(compared.(string)) 162 case "array": 163 return reflect.ValueOf(value).Len() >= reflect.ValueOf(compared).Len() 164 case "file": 165 files, _ := value.([]filesystem.File) 166 comparedFiles, _ := compared.([]filesystem.File) 167 for _, file := range files { 168 for _, comparedFile := range comparedFiles { 169 if file.Header.Size < comparedFile.Header.Size { 170 return false 171 } 172 } 173 } 174 return true 175 } 176 177 return true // Pass if field type cannot be checked (bool, dates, ...) 178 } 179 180 func validateLowerThan(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 181 valueType := GetFieldType(value) 182 183 compared, exists := form[parameters[0]] 184 if !exists || valueType != GetFieldType(compared) { 185 return false // Can't compare two different types or missing field 186 } 187 188 switch valueType { 189 case "numeric": 190 floatValue, _ := helper.ToFloat64(value) 191 comparedFloatValue, _ := helper.ToFloat64(compared) 192 return floatValue < comparedFloatValue 193 case "string": 194 return uniseg.GraphemeClusterCount(value.(string)) < uniseg.GraphemeClusterCount(compared.(string)) 195 case "array": 196 return reflect.ValueOf(value).Len() < reflect.ValueOf(compared).Len() 197 case "file": 198 files, _ := value.([]filesystem.File) 199 comparedFiles, _ := compared.([]filesystem.File) 200 for _, file := range files { 201 for _, comparedFile := range comparedFiles { 202 if file.Header.Size >= comparedFile.Header.Size { 203 return false 204 } 205 } 206 } 207 return true 208 } 209 210 return true // Pass if field type cannot be checked (bool, dates, ...) 211 } 212 213 func validateLowerThanEqual(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 214 valueType := GetFieldType(value) 215 216 compared, exists := form[parameters[0]] 217 if !exists || valueType != GetFieldType(compared) { 218 return false // Can't compare two different types or missing field 219 } 220 221 switch valueType { 222 case "numeric": 223 floatValue, _ := helper.ToFloat64(value) 224 comparedFloatValue, _ := helper.ToFloat64(compared) 225 return floatValue <= comparedFloatValue 226 case "string": 227 return uniseg.GraphemeClusterCount(value.(string)) <= uniseg.GraphemeClusterCount(compared.(string)) 228 case "array": 229 return reflect.ValueOf(value).Len() <= reflect.ValueOf(compared).Len() 230 case "file": 231 files, _ := value.([]filesystem.File) 232 comparedFiles, _ := compared.([]filesystem.File) 233 for _, file := range files { 234 for _, comparedFile := range comparedFiles { 235 if file.Header.Size > comparedFile.Header.Size { 236 return false 237 } 238 } 239 } 240 return true 241 } 242 243 return true // Pass if field type cannot be checked (bool, dates, ...) 244 } 245 246 func validateBool(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 247 rv := reflect.ValueOf(value) 248 kind := rv.Kind().String() 249 switch { 250 case kind == "bool": 251 return true 252 case strings.HasPrefix(kind, "int"), strings.HasPrefix(kind, "uint") && kind != "uintptr": 253 v, _ := helper.ToFloat64(value) 254 if v == 1 { 255 form[field] = true 256 return true 257 } else if v == 0 { 258 form[field] = false 259 return true 260 } 261 case kind == "string": 262 v, _ := value.(string) 263 switch v { 264 case "1", "on", "true", "yes": 265 form[field] = true 266 return true 267 case "0", "off", "false", "no": 268 form[field] = false 269 return true 270 } 271 } 272 return false 273 } 274 275 func validateSame(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 276 other, exists := form[parameters[0]] 277 if exists { 278 valueType := GetFieldType(value) 279 otherType := GetFieldType(other) 280 if valueType == otherType { 281 switch valueType { 282 case "numeric": 283 f1, _ := helper.ToFloat64(value) 284 f2, _ := helper.ToFloat64(other) 285 return f1 == f2 286 case "string": 287 s1, _ := value.(string) 288 s2, _ := other.(string) 289 return s1 == s2 290 case "array": 291 return helper.SliceEqual(value, other) 292 } 293 // Don't check files 294 } 295 } 296 return false 297 } 298 299 func validateDifferent(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 300 return !validateSame(field, value, parameters, form) 301 } 302 303 func validateConfirmed(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 304 params := []string{field + "_confirmation"} 305 return validateSame(field, value, params, form) 306 } 307 308 func validateSize(field string, value interface{}, parameters []string, form map[string]interface{}) bool { 309 size, err := strconv.Atoi(parameters[0]) 310 if err != nil { 311 panic(err) 312 } 313 314 switch GetFieldType(value) { 315 case "numeric": 316 floatVal, _ := helper.ToFloat64(value) 317 return floatVal == float64(size) 318 case "string": 319 return uniseg.GraphemeClusterCount(value.(string)) == size 320 case "array": 321 list := reflect.ValueOf(value) 322 return list.Len() == size 323 case "file": 324 files, _ := value.([]filesystem.File) 325 for _, file := range files { 326 if int64(math.Round(float64(file.Header.Size)/1024.0)) != int64(size) { 327 return false 328 } 329 } 330 return true 331 } 332 333 return true // Pass if field type cannot be checked (bool, dates, ...) 334 }