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  }