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  }