form.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright 2017 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package form
  5. import (
  6. "fmt"
  7. "reflect"
  8. "strings"
  9. "github.com/go-macaron/binding"
  10. "github.com/unknwon/com"
  11. "gopkg.in/macaron.v1"
  12. "gogs.io/gogs/internal/lazyregexp"
  13. )
  14. const ERR_ALPHA_DASH_DOT_SLASH = "AlphaDashDotSlashError"
  15. var AlphaDashDotSlashPattern = lazyregexp.New("[^\\d\\w-_\\./]")
  16. func init() {
  17. binding.SetNameMapper(com.ToSnakeCase)
  18. binding.AddRule(&binding.Rule{
  19. IsMatch: func(rule string) bool {
  20. return rule == "AlphaDashDotSlash"
  21. },
  22. IsValid: func(errs binding.Errors, name string, v any) (bool, binding.Errors) {
  23. if AlphaDashDotSlashPattern.MatchString(fmt.Sprintf("%v", v)) {
  24. errs.Add([]string{name}, ERR_ALPHA_DASH_DOT_SLASH, "AlphaDashDotSlash")
  25. return false, errs
  26. }
  27. return true, errs
  28. },
  29. })
  30. }
  31. type Form interface {
  32. binding.Validator
  33. }
  34. // Assign assign form values back to the template data.
  35. func Assign(form any, data map[string]any) {
  36. typ := reflect.TypeOf(form)
  37. val := reflect.ValueOf(form)
  38. if typ.Kind() == reflect.Ptr {
  39. typ = typ.Elem()
  40. val = val.Elem()
  41. }
  42. for i := 0; i < typ.NumField(); i++ {
  43. field := typ.Field(i)
  44. fieldName := field.Tag.Get("form")
  45. // Allow ignored fields in the struct
  46. if fieldName == "-" {
  47. continue
  48. } else if fieldName == "" {
  49. fieldName = com.ToSnakeCase(field.Name)
  50. }
  51. data[fieldName] = val.Field(i).Interface()
  52. }
  53. }
  54. func getRuleBody(field reflect.StructField, prefix string) string {
  55. for _, rule := range strings.Split(field.Tag.Get("binding"), ";") {
  56. if strings.HasPrefix(rule, prefix) {
  57. return rule[len(prefix) : len(rule)-1]
  58. }
  59. }
  60. return ""
  61. }
  62. func getSize(field reflect.StructField) string {
  63. return getRuleBody(field, "Size(")
  64. }
  65. func getMinSize(field reflect.StructField) string {
  66. return getRuleBody(field, "MinSize(")
  67. }
  68. func getMaxSize(field reflect.StructField) string {
  69. return getRuleBody(field, "MaxSize(")
  70. }
  71. func getInclude(field reflect.StructField) string {
  72. return getRuleBody(field, "Include(")
  73. }
  74. func validate(errs binding.Errors, data map[string]any, f Form, l macaron.Locale) binding.Errors {
  75. if errs.Len() == 0 {
  76. return errs
  77. }
  78. data["HasError"] = true
  79. Assign(f, data)
  80. typ := reflect.TypeOf(f)
  81. if typ.Kind() == reflect.Ptr {
  82. typ = typ.Elem()
  83. }
  84. for i := 0; i < typ.NumField(); i++ {
  85. field := typ.Field(i)
  86. fieldName := field.Tag.Get("form")
  87. // Allow ignored fields in the struct
  88. if fieldName == "-" {
  89. continue
  90. }
  91. if errs[0].FieldNames[0] == field.Name {
  92. data["Err_"+field.Name] = true
  93. trName := field.Tag.Get("locale")
  94. if trName == "" {
  95. trName = l.Tr("form." + field.Name)
  96. } else {
  97. trName = l.Tr(trName)
  98. }
  99. switch errs[0].Classification {
  100. case binding.ERR_REQUIRED:
  101. data["ErrorMsg"] = trName + l.Tr("form.require_error")
  102. case binding.ERR_ALPHA_DASH:
  103. data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_error")
  104. case binding.ERR_ALPHA_DASH_DOT:
  105. data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_error")
  106. case ERR_ALPHA_DASH_DOT_SLASH:
  107. data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_slash_error")
  108. case binding.ERR_SIZE:
  109. data["ErrorMsg"] = trName + l.Tr("form.size_error", getSize(field))
  110. case binding.ERR_MIN_SIZE:
  111. data["ErrorMsg"] = trName + l.Tr("form.min_size_error", getMinSize(field))
  112. case binding.ERR_MAX_SIZE:
  113. data["ErrorMsg"] = trName + l.Tr("form.max_size_error", getMaxSize(field))
  114. case binding.ERR_EMAIL:
  115. data["ErrorMsg"] = trName + l.Tr("form.email_error")
  116. case binding.ERR_URL:
  117. data["ErrorMsg"] = trName + l.Tr("form.url_error")
  118. case binding.ERR_INCLUDE:
  119. data["ErrorMsg"] = trName + l.Tr("form.include_error", getInclude(field))
  120. default:
  121. data["ErrorMsg"] = l.Tr("form.unknown_error") + " " + errs[0].Classification
  122. }
  123. return errs
  124. }
  125. }
  126. return errs
  127. }