You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

binding.go 4.3KB

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