mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-23 21:23:41 +09:00
refactor: form binding validation (#38832)
Make "form-fetch-action" highlight the invalid field as "error"
This commit is contained in:
@@ -18,18 +18,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ErrGitRefName is git reference name error
|
ErrCustomMessage = "CustomMessage"
|
||||||
ErrGitRefName = "GitRefNameError"
|
ErrGitRefName = "GitRefNameError"
|
||||||
// ErrGlobPattern is returned when glob pattern is invalid
|
ErrGlobPattern = "GlobPattern"
|
||||||
ErrGlobPattern = "GlobPattern"
|
ErrRegexPattern = "RegexPattern"
|
||||||
// ErrRegexPattern is returned when a regex pattern is invalid
|
ErrUsername = "UsernameError"
|
||||||
ErrRegexPattern = "RegexPattern"
|
|
||||||
// ErrUsername is username error
|
|
||||||
ErrUsername = "UsernameError"
|
|
||||||
// ErrInvalidGroupTeamMap is returned when a group team mapping is invalid
|
|
||||||
ErrInvalidGroupTeamMap = "InvalidGroupTeamMap"
|
ErrInvalidGroupTeamMap = "InvalidGroupTeamMap"
|
||||||
// ErrInvalidBadgeSlug is returned when a badge slug is invalid
|
ErrInvalidBadgeSlug = "InvalidBadgeSlug"
|
||||||
ErrInvalidBadgeSlug = "InvalidBadgeSlug"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type jsonProvider struct{}
|
type jsonProvider struct{}
|
||||||
@@ -61,7 +56,7 @@ func AddBindingRules() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addGitRefNameBindingRule() {
|
func addGitRefNameBindingRule() {
|
||||||
// Git refname validation rule
|
// Git ref name validation rule
|
||||||
binding.AddRule(&binding.Rule{
|
binding.AddRule(&binding.Rule{
|
||||||
IsMatch: func(rule string) bool {
|
IsMatch: func(rule string) bool {
|
||||||
return rule == "GitRefName"
|
return rule == "GitRefName"
|
||||||
|
|||||||
@@ -5,9 +5,12 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"gitea.dev/modules/reqctx"
|
||||||
|
"gitea.dev/modules/setting"
|
||||||
"gitea.dev/modules/translation"
|
"gitea.dev/modules/translation"
|
||||||
"gitea.dev/modules/util"
|
"gitea.dev/modules/util"
|
||||||
"gitea.dev/modules/validation"
|
"gitea.dev/modules/validation"
|
||||||
@@ -15,6 +18,14 @@ import (
|
|||||||
"gitea.com/go-chi/binding"
|
"gitea.com/go-chi/binding"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ValidateContext is a special context for form validation middleware. It may be different from other contexts.
|
||||||
|
type ValidateContext struct {
|
||||||
|
Locale translation.Locale
|
||||||
|
Data reqctx.ContextData
|
||||||
|
Req *http.Request
|
||||||
|
Resp http.ResponseWriter
|
||||||
|
}
|
||||||
|
|
||||||
// Form form binding interface
|
// Form form binding interface
|
||||||
type Form interface {
|
type Form interface {
|
||||||
binding.Validator
|
binding.Validator
|
||||||
@@ -49,7 +60,8 @@ func AssignForm(form any, data map[string]any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRuleBody(field reflect.StructField, prefix string) string {
|
func getRuleBody(field reflect.StructField, ruleName string) string {
|
||||||
|
prefix := ruleName + "("
|
||||||
for rule := range strings.SplitSeq(field.Tag.Get("binding"), ";") {
|
for rule := range strings.SplitSeq(field.Tag.Get("binding"), ";") {
|
||||||
if strings.HasPrefix(rule, prefix) {
|
if strings.HasPrefix(rule, prefix) {
|
||||||
return rule[len(prefix) : len(rule)-1]
|
return rule[len(prefix) : len(rule)-1]
|
||||||
@@ -58,117 +70,134 @@ func getRuleBody(field reflect.StructField, prefix string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSize get size int form tag
|
func AddValidationError(errs binding.Errors, fieldName, errorMsg string) binding.Errors {
|
||||||
func GetSize(field reflect.StructField) string {
|
errs.Add([]string{fieldName}, validation.ErrCustomMessage, errorMsg)
|
||||||
return getRuleBody(field, "Size(")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMinSize get minimal size in form tag
|
|
||||||
func GetMinSize(field reflect.StructField) string {
|
|
||||||
return getRuleBody(field, "MinSize(")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMaxSize get max size in form tag
|
|
||||||
func GetMaxSize(field reflect.StructField) string {
|
|
||||||
return getRuleBody(field, "MaxSize(")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInclude get include in form tag
|
|
||||||
func GetInclude(field reflect.StructField) string {
|
|
||||||
return getRuleBody(field, "Include(")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ReportValidationError(errs binding.Errors, data map[string]any, fieldName, classification, errorMsg string) binding.Errors {
|
|
||||||
errs.Add([]string{fieldName}, classification, errorMsg)
|
|
||||||
|
|
||||||
data["HasError"] = true
|
|
||||||
data["ErrorMsg"] = fieldName + ": " + errorMsg
|
|
||||||
data["Err_"+fieldName] = true
|
|
||||||
// there is already a reported validation error, so no need to generate default error messages in Validate()
|
|
||||||
data["HasErrorFormValidation"] = true
|
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
func Validate(errs binding.Errors, data map[string]any, f Form, l translation.Locale) binding.Errors {
|
func getFieldDisplayNameForMessage(f Form, l translation.Locale, fieldNames []string) (field reflect.StructField, ok bool, displayName string) {
|
||||||
// try to restore the form's values as much as possible,
|
if len(fieldNames) == 0 {
|
||||||
// especially for RenderWithErrDeprecated to re-render the form with errors
|
return field, false, ""
|
||||||
AssignForm(f, data)
|
|
||||||
|
|
||||||
if errs.Len() == 0 || data["HasErrorFormValidation"] == true {
|
|
||||||
return errs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if HasError=true, then must set default error message
|
|
||||||
// because still a lot of places use `ctx.Data["ErrorMsg"].(string)` even if the error fields can't be found
|
|
||||||
data["HasError"] = true
|
|
||||||
data["ErrorMsg"] = l.TrString("form.unknown_error")
|
|
||||||
|
|
||||||
typ := reflect.TypeOf(f)
|
typ := reflect.TypeOf(f)
|
||||||
if typ.Kind() == reflect.Pointer {
|
if typ.Kind() == reflect.Pointer {
|
||||||
typ = typ.Elem()
|
typ = typ.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
field, fieldExists := typ.FieldByName(errs[0].FieldNames[0])
|
field, fieldExists := typ.FieldByName(fieldNames[0])
|
||||||
if !fieldExists {
|
if !fieldExists {
|
||||||
return errs
|
return field, false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if field.Tag.Get("form") == "-" {
|
if field.Tag.Get("form") == "-" {
|
||||||
|
return field, false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
trKeyFallback := "form." + field.Name
|
||||||
|
trKey := util.IfZero(field.Tag.Get("locale"), trKeyFallback)
|
||||||
|
displayName = l.TrString(trKey)
|
||||||
|
if displayName == trKeyFallback {
|
||||||
|
displayName = field.Name
|
||||||
|
}
|
||||||
|
return field, true, displayName
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildValidationErrorForUser(f Form, l translation.Locale, bindingErrs binding.Errors) (errorMessage, errorFieldName string, fieldNames []string) {
|
||||||
|
if bindingErrs.Len() == 0 {
|
||||||
|
return "", "", nil
|
||||||
|
}
|
||||||
|
bindingErr := bindingErrs[0]
|
||||||
|
fieldNames, classification, bindingErrMsg := bindingErr.FieldNames, bindingErr.Classification, bindingErr.Message
|
||||||
|
field, ok, fieldDisplayName := getFieldDisplayNameForMessage(f, l, fieldNames)
|
||||||
|
if !ok {
|
||||||
|
return l.TrString("error.occurred"), "", fieldNames
|
||||||
|
}
|
||||||
|
|
||||||
|
errorFieldName = field.Name
|
||||||
|
switch classification {
|
||||||
|
case binding.ERR_REQUIRED:
|
||||||
|
errorMessage = l.TrString("form.require_error", fieldDisplayName)
|
||||||
|
case binding.ERR_ALPHA_DASH:
|
||||||
|
errorMessage = l.TrString("form.alpha_dash_error", fieldDisplayName)
|
||||||
|
case binding.ERR_ALPHA_DASH_DOT:
|
||||||
|
errorMessage = l.TrString("form.alpha_dash_dot_error", fieldDisplayName)
|
||||||
|
case binding.ERR_MIN_SIZE:
|
||||||
|
errorMessage = l.TrString("form.min_size_error", fieldDisplayName, getRuleBody(field, "MinSize"))
|
||||||
|
case binding.ERR_MAX_SIZE:
|
||||||
|
errorMessage = l.TrString("form.max_size_error", fieldDisplayName, getRuleBody(field, "MaxSize"))
|
||||||
|
case binding.ERR_RANGE:
|
||||||
|
rangeMin, rangeMax, _ := strings.Cut(getRuleBody(field, "Range"), ",")
|
||||||
|
errorMessage = l.TrString("form.range_error", fieldDisplayName, rangeMin, rangeMax)
|
||||||
|
case binding.ERR_EMAIL:
|
||||||
|
errorMessage = l.TrString("form.email_error", fieldDisplayName)
|
||||||
|
case binding.ERR_URL:
|
||||||
|
errorMessage = l.TrString("form.url_error", fieldDisplayName)
|
||||||
|
case binding.ERR_IN:
|
||||||
|
ruleBody := getRuleBody(field, "In")
|
||||||
|
if strings.HasPrefix(ruleBody, ",") {
|
||||||
|
ruleBody = "(empty)" + ruleBody
|
||||||
|
}
|
||||||
|
errorMessage = l.TrString("form.in_error", fieldDisplayName, ruleBody)
|
||||||
|
case binding.ERR_INCLUDE:
|
||||||
|
errorMessage = l.TrString("form.include_error", fieldDisplayName, getRuleBody(field, "Include"))
|
||||||
|
|
||||||
|
case validation.ErrCustomMessage:
|
||||||
|
errorMessage = bindingErrMsg
|
||||||
|
case validation.ErrGitRefName:
|
||||||
|
errorMessage = l.TrString("form.git_ref_name_error", fieldDisplayName)
|
||||||
|
case validation.ErrGlobPattern:
|
||||||
|
errorMessage = l.TrString("form.glob_pattern_error", fieldDisplayName, bindingErrMsg)
|
||||||
|
case validation.ErrRegexPattern:
|
||||||
|
errorMessage = l.TrString("form.regex_pattern_error", fieldDisplayName, bindingErrMsg)
|
||||||
|
case validation.ErrUsername:
|
||||||
|
errorMessage = l.TrString("form.username_error", fieldDisplayName)
|
||||||
|
case validation.ErrInvalidGroupTeamMap:
|
||||||
|
errorMessage = l.TrString("form.invalid_group_team_map_error", fieldDisplayName, bindingErrMsg)
|
||||||
|
case validation.ErrInvalidBadgeSlug:
|
||||||
|
errorMessage = l.TrString("form.invalid_slug_error", fieldDisplayName)
|
||||||
|
default:
|
||||||
|
setting.PanicInDevOrTesting("unknown binding error classification: %v", classification)
|
||||||
|
var msg string
|
||||||
|
if classification != "" && bindingErrMsg != "" {
|
||||||
|
msg = classification + ": " + bindingErrMsg
|
||||||
|
} else {
|
||||||
|
msg = util.IfZero(bindingErrMsg, classification)
|
||||||
|
if msg == "" {
|
||||||
|
setting.PanicInDevOrTesting("no error message for binding error: %v", bindingErr)
|
||||||
|
}
|
||||||
|
msg = util.IfZero(msg, "unknown error")
|
||||||
|
}
|
||||||
|
errorMessage = l.TrString("form.field_invalid_message", fieldDisplayName, msg)
|
||||||
|
}
|
||||||
|
return errorMessage, errorFieldName, fieldNames
|
||||||
|
}
|
||||||
|
|
||||||
|
type contextKeySkipTmplFormValidationErrorType struct{}
|
||||||
|
|
||||||
|
var contextKeySkipTmplFormValidationError contextKeySkipTmplFormValidationErrorType
|
||||||
|
|
||||||
|
func SkipTmplFormValidationError(ctx reqctx.RequestContext) {
|
||||||
|
ctx.SetContextValue(contextKeySkipTmplFormValidationError, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Validate(ctx *ValidateContext, errs binding.Errors, f Form) binding.Errors {
|
||||||
|
if ctx.Req.Context().Value(contextKeySkipTmplFormValidationError) == true {
|
||||||
|
// if it is not using tmpl-based validation error handling, just return the errors
|
||||||
|
// for example: when using "form-fetch-action", the validation error can be handled by GetFetchActionForm
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
errorMessage, errorFieldName, _ := BuildValidationErrorForUser(f, ctx.Locale, errs)
|
||||||
|
if errorMessage == "" {
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
data["Err_"+field.Name] = true
|
// Legacy template error handling: try to restore the form's values as much as possible,
|
||||||
|
// especially for RenderWithErrDeprecated to re-render the form with errors.
|
||||||
trName := field.Tag.Get("locale")
|
AssignForm(f, ctx.Data)
|
||||||
if len(trName) == 0 {
|
ctx.Data["HasError"] = true
|
||||||
trName = l.TrString("form." + field.Name)
|
ctx.Data["ErrorMsg"] = errorMessage
|
||||||
} else {
|
if errorFieldName != "" {
|
||||||
trName = l.TrString(trName)
|
ctx.Data["Err_"+errorFieldName] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
switch errs[0].Classification {
|
|
||||||
case binding.ERR_REQUIRED:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.require_error")
|
|
||||||
case binding.ERR_ALPHA_DASH:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.alpha_dash_error")
|
|
||||||
case binding.ERR_ALPHA_DASH_DOT:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.alpha_dash_dot_error")
|
|
||||||
case validation.ErrGitRefName:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.git_ref_name_error")
|
|
||||||
case binding.ERR_SIZE:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.size_error", GetSize(field))
|
|
||||||
case binding.ERR_MIN_SIZE:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.min_size_error", GetMinSize(field))
|
|
||||||
case binding.ERR_MAX_SIZE:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.max_size_error", GetMaxSize(field))
|
|
||||||
case binding.ERR_EMAIL:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.email_error")
|
|
||||||
case binding.ERR_URL:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.url_error", errs[0].Message)
|
|
||||||
case binding.ERR_INCLUDE:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.include_error", GetInclude(field))
|
|
||||||
case validation.ErrGlobPattern:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.glob_pattern_error", errs[0].Message)
|
|
||||||
case validation.ErrRegexPattern:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.regex_pattern_error", errs[0].Message)
|
|
||||||
case validation.ErrUsername:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.username_error")
|
|
||||||
case validation.ErrInvalidGroupTeamMap:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.invalid_group_team_map_error", errs[0].Message)
|
|
||||||
case validation.ErrInvalidBadgeSlug:
|
|
||||||
data["ErrorMsg"] = trName + l.TrString("form.invalid_slug_error")
|
|
||||||
default:
|
|
||||||
msg := errs[0].Classification
|
|
||||||
if msg != "" && errs[0].Message != "" {
|
|
||||||
msg += ": "
|
|
||||||
}
|
|
||||||
|
|
||||||
msg += errs[0].Message
|
|
||||||
if msg == "" {
|
|
||||||
msg = l.TrString("form.unknown_error")
|
|
||||||
}
|
|
||||||
data["ErrorMsg"] = trName + ": " + msg
|
|
||||||
}
|
|
||||||
|
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitea.dev/modules/translation"
|
||||||
|
|
||||||
|
"gitea.com/go-chi/binding"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testRangeForm struct {
|
||||||
|
Hours int `binding:"Range(0,1000)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *testRangeForm) Validate(_ *http.Request, errs binding.Errors) binding.Errors { return errs }
|
||||||
|
|
||||||
|
func TestBuildValidationErrorForUser(t *testing.T) {
|
||||||
|
// an out-of-range value must reach its own message instead of the panicking "default" branch
|
||||||
|
form := &testRangeForm{Hours: 2000}
|
||||||
|
errs := binding.Validate(httptest.NewRequest(http.MethodPost, "/", nil), form)
|
||||||
|
errorMessage, errorFieldName, fieldNames := BuildValidationErrorForUser(form, translation.MockLocale{}, errs)
|
||||||
|
assert.Equal(t, "form.range_error:Hours,0,1000", errorMessage)
|
||||||
|
assert.Equal(t, "Hours", errorFieldName)
|
||||||
|
assert.Equal(t, []string{"Hours"}, fieldNames)
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ func Bind[T any](_ T) http.HandlerFunc {
|
|||||||
return func(resp http.ResponseWriter, req *http.Request) {
|
return func(resp http.ResponseWriter, req *http.Request) {
|
||||||
theObj := new(T) // create a new form obj for every request but not use obj directly
|
theObj := new(T) // create a new form obj for every request but not use obj directly
|
||||||
data := middleware.GetContextData(req.Context())
|
data := middleware.GetContextData(req.Context())
|
||||||
binding.Bind(req, theObj)
|
_ = binding.Bind(req, theObj) // no need to handle "errs" here, the errors are handled in our middleware.Validate (binding.go)
|
||||||
SetForm(data, theObj)
|
SetForm(data, theObj)
|
||||||
middleware.AssignForm(theObj, data)
|
middleware.AssignForm(theObj, data)
|
||||||
}
|
}
|
||||||
@@ -37,6 +37,10 @@ func SetForm(dataStore reqctx.ContextDataProvider, obj any) {
|
|||||||
dataStore.GetData()["__form"] = obj
|
dataStore.GetData()["__form"] = obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsFormSet(dataStore reqctx.RequestDataStore) bool {
|
||||||
|
return dataStore.GetData()["__form"] != nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetForm returns the validate form information
|
// GetForm returns the validate form information
|
||||||
func GetForm[T any](dataStore reqctx.RequestDataStore) T {
|
func GetForm[T any](dataStore reqctx.RequestDataStore) T {
|
||||||
form, ok := dataStore.GetData()["__form"].(T)
|
form, ok := dataStore.GetData()["__form"].(T)
|
||||||
|
|||||||
@@ -523,9 +523,6 @@
|
|||||||
"form.RepoName": "Repository name",
|
"form.RepoName": "Repository name",
|
||||||
"form.Email": "Email address",
|
"form.Email": "Email address",
|
||||||
"form.Password": "Password",
|
"form.Password": "Password",
|
||||||
"form.Retype": "Confirm Password",
|
|
||||||
"form.SSHTitle": "SSH key name",
|
|
||||||
"form.HttpsUrl": "HTTPS URL",
|
|
||||||
"form.PayloadUrl": "Payload URL",
|
"form.PayloadUrl": "Payload URL",
|
||||||
"form.TeamName": "Team name",
|
"form.TeamName": "Team name",
|
||||||
"form.AuthName": "Authorization name",
|
"form.AuthName": "Authorization name",
|
||||||
@@ -538,22 +535,24 @@
|
|||||||
"form.Content": "Content",
|
"form.Content": "Content",
|
||||||
"form.SSPISeparatorReplacement": "Separator",
|
"form.SSPISeparatorReplacement": "Separator",
|
||||||
"form.SSPIDefaultLanguage": "Default Language",
|
"form.SSPIDefaultLanguage": "Default Language",
|
||||||
"form.require_error": " cannot be empty.",
|
"form.require_error": "%s cannot be empty.",
|
||||||
"form.alpha_dash_error": " should contain only alphanumeric, dash ('-') and underscore ('_') characters.",
|
"form.alpha_dash_error": "%s should contain only alphanumeric, dash ('-') and underscore ('_') characters.",
|
||||||
"form.alpha_dash_dot_error": " should contain only alphanumeric, dash ('-'), underscore ('_') and dot ('.') characters.",
|
"form.alpha_dash_dot_error": "%s should contain only alphanumeric, dash ('-'), underscore ('_') and dot ('.') characters.",
|
||||||
"form.git_ref_name_error": " must be a well-formed Git reference name.",
|
"form.git_ref_name_error": "%s must be a well-formed Git reference name.",
|
||||||
"form.size_error": " must be size %s.",
|
"form.size_error": "%[1]s must be size %[2]s.",
|
||||||
"form.min_size_error": " must contain at least %s characters.",
|
"form.min_size_error": "%[1]s must contain at least %[2]s characters.",
|
||||||
"form.max_size_error": " must contain at most %s characters.",
|
"form.max_size_error": "%[1]s must contain at most %[2]s characters.",
|
||||||
"form.email_error": " is not a valid email address.",
|
"form.range_error": "%[1]s must be a number from %[2]s to %[3]s.",
|
||||||
"form.url_error": "\"%s\" is not a valid URL.",
|
"form.email_error": "%s is not a valid email address.",
|
||||||
"form.include_error": " must contain substring \"%s\".",
|
"form.url_error": "%s is not a valid URL.",
|
||||||
"form.glob_pattern_error": " glob pattern is invalid: %s.",
|
"form.in_error": "%[1]s must be one of the following: %[2]s.",
|
||||||
"form.regex_pattern_error": " regex pattern is invalid: %s.",
|
"form.include_error": "%[1]s must contain substring \"%[2]s\".",
|
||||||
"form.username_error": " can only contain alphanumeric characters ('0-9','a-z','A-Z'), dash ('-'), underscore ('_') and dot ('.'). It cannot begin or end with non-alphanumeric characters, and consecutive non-alphanumeric characters are also forbidden.",
|
"form.glob_pattern_error": "%[1]s glob pattern is invalid: %[2]s.",
|
||||||
"form.invalid_slug_error": " is invalid.",
|
"form.regex_pattern_error": "%[1]s regex pattern is invalid: %[2]s.",
|
||||||
"form.invalid_group_team_map_error": " mapping is invalid: %s",
|
"form.username_error": "%s can only contain alphanumeric characters ('0-9','a-z','A-Z'), dash ('-'), underscore ('_') and dot ('.'). It cannot begin or end with non-alphanumeric characters, and consecutive non-alphanumeric characters are also forbidden.",
|
||||||
"form.unknown_error": "Unknown error:",
|
"form.invalid_slug_error": "%s is invalid.",
|
||||||
|
"form.invalid_group_team_map_error": "%[1]s mapping is invalid: %[2]s",
|
||||||
|
"form.field_invalid_message": "%[1]s is invalid: %[2]s",
|
||||||
"form.captcha_incorrect": "The CAPTCHA code is incorrect.",
|
"form.captcha_incorrect": "The CAPTCHA code is incorrect.",
|
||||||
"form.password_not_match": "The passwords do not match.",
|
"form.password_not_match": "The passwords do not match.",
|
||||||
"form.lang_select_error": "Select a language from the list.",
|
"form.lang_select_error": "Select a language from the list.",
|
||||||
|
|||||||
@@ -212,11 +212,11 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source {
|
|||||||
func parseSSPIConfig(ctx *context.Context, form forms.AuthenticationForm) (*sspi.Source, error) {
|
func parseSSPIConfig(ctx *context.Context, form forms.AuthenticationForm) (*sspi.Source, error) {
|
||||||
if util.IsEmptyString(form.SSPISeparatorReplacement) {
|
if util.IsEmptyString(form.SSPISeparatorReplacement) {
|
||||||
ctx.Data["Err_SSPISeparatorReplacement"] = true
|
ctx.Data["Err_SSPISeparatorReplacement"] = true
|
||||||
return nil, errors.New(ctx.Locale.TrString("form.SSPISeparatorReplacement") + ctx.Locale.TrString("form.require_error"))
|
return nil, errors.New(ctx.Locale.TrString("form.require_error", ctx.Locale.TrString("form.SSPISeparatorReplacement")))
|
||||||
}
|
}
|
||||||
if separatorAntiPattern.MatchString(form.SSPISeparatorReplacement) {
|
if separatorAntiPattern.MatchString(form.SSPISeparatorReplacement) {
|
||||||
ctx.Data["Err_SSPISeparatorReplacement"] = true
|
ctx.Data["Err_SSPISeparatorReplacement"] = true
|
||||||
return nil, errors.New(ctx.Locale.TrString("form.SSPISeparatorReplacement") + ctx.Locale.TrString("form.alpha_dash_dot_error"))
|
return nil, errors.New(ctx.Locale.TrString("form.alpha_dash_dot_error", ctx.Locale.TrString("form.SSPISeparatorReplacement")))
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.SSPIDefaultLanguage != "" && !langCodePattern.MatchString(form.SSPIDefaultLanguage) {
|
if form.SSPIDefaultLanguage != "" && !langCodePattern.MatchString(form.SSPIDefaultLanguage) {
|
||||||
|
|||||||
@@ -4,13 +4,12 @@
|
|||||||
package setting
|
package setting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
asymkey_model "gitea.dev/models/asymkey"
|
asymkey_model "gitea.dev/models/asymkey"
|
||||||
"gitea.dev/models/db"
|
"gitea.dev/models/db"
|
||||||
"gitea.dev/modules/log"
|
|
||||||
"gitea.dev/modules/setting"
|
"gitea.dev/modules/setting"
|
||||||
"gitea.dev/modules/web"
|
|
||||||
asymkey_service "gitea.dev/services/asymkey"
|
asymkey_service "gitea.dev/services/asymkey"
|
||||||
"gitea.dev/services/context"
|
"gitea.dev/services/context"
|
||||||
"gitea.dev/services/forms"
|
"gitea.dev/services/forms"
|
||||||
@@ -32,69 +31,45 @@ func DeployKeys(ctx *context.Context) {
|
|||||||
ctx.HTML(http.StatusOK, tplDeployKeys)
|
ctx.HTML(http.StatusOK, tplDeployKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeployKeysPost response for adding a deploy key of a repository
|
// DeployKeysPost response for adding a deploy-key of a repository
|
||||||
func DeployKeysPost(ctx *context.Context) {
|
func DeployKeysPost(ctx *context.Context) {
|
||||||
form := web.GetForm[*forms.AddKeyForm](ctx)
|
form := context.GetFetchActionForm[*forms.AddKeyForm](ctx)
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys")
|
if form == nil {
|
||||||
ctx.Data["PageIsSettingsKeys"] = true
|
|
||||||
ctx.Data["DisableSSH"] = setting.SSH.Disabled
|
|
||||||
|
|
||||||
keys, err := db.Find[asymkey_model.DeployKey](ctx, asymkey_model.ListDeployKeysOptions{RepoID: ctx.Repo.Repository.ID})
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("ListDeployKeys", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["Deploykeys"] = keys
|
|
||||||
|
|
||||||
if ctx.HasError() {
|
|
||||||
ctx.HTML(http.StatusOK, tplDeployKeys)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
content, err := asymkey_model.CheckPublicKeyString(form.Content)
|
content, err := asymkey_model.CheckPublicKeyString(form.Content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if db.IsErrSSHDisabled(err) {
|
if db.IsErrSSHDisabled(err) {
|
||||||
ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
|
ctx.JSONError(ctx.Tr("settings.ssh_disabled"))
|
||||||
} else if asymkey_model.IsErrKeyUnableVerify(err) {
|
} else if asymkey_model.IsErrKeyUnableVerify(err) {
|
||||||
ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
|
ctx.JSONErrorWithField(ctx.Tr("form.unable_verify_ssh_key"), "content")
|
||||||
} else if err == asymkey_model.ErrKeyIsPrivate {
|
} else if errors.Is(err, asymkey_model.ErrKeyIsPrivate) {
|
||||||
ctx.Data["HasError"] = true
|
ctx.JSONErrorWithField(ctx.Tr("form.must_use_public_key"), "content")
|
||||||
ctx.Data["Err_Content"] = true
|
|
||||||
ctx.Flash.Error(ctx.Tr("form.must_use_public_key"))
|
|
||||||
} else {
|
} else {
|
||||||
ctx.Data["HasError"] = true
|
ctx.JSONErrorWithField(ctx.Tr("form.invalid_ssh_key", err.Error()), "content")
|
||||||
ctx.Data["Err_Content"] = true
|
|
||||||
ctx.Flash.Error(ctx.Tr("form.invalid_ssh_key", err.Error()))
|
|
||||||
}
|
}
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := asymkey_model.AddDeployKey(ctx, ctx.Repo.Repository.ID, form.Title, content, !form.IsWritable)
|
key, err := asymkey_model.AddDeployKey(ctx, ctx.Repo.Repository.ID, form.Title, content, !form.IsWritable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Data["HasError"] = true
|
|
||||||
switch {
|
switch {
|
||||||
case asymkey_model.IsErrDeployKeyAlreadyExist(err):
|
case asymkey_model.IsErrDeployKeyAlreadyExist(err):
|
||||||
ctx.Data["Err_Content"] = true
|
ctx.JSONErrorWithField(ctx.Tr("repo.settings.key_been_used"), "content")
|
||||||
ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.key_been_used"), tplDeployKeys, &form)
|
|
||||||
case asymkey_model.IsErrKeyAlreadyExist(err):
|
case asymkey_model.IsErrKeyAlreadyExist(err):
|
||||||
ctx.Data["Err_Content"] = true
|
ctx.JSONErrorWithField(ctx.Tr("settings.ssh_key_been_used"), "content")
|
||||||
ctx.RenderWithErrDeprecated(ctx.Tr("settings.ssh_key_been_used"), tplDeployKeys, &form)
|
|
||||||
case asymkey_model.IsErrKeyNameAlreadyUsed(err):
|
case asymkey_model.IsErrKeyNameAlreadyUsed(err):
|
||||||
ctx.Data["Err_Title"] = true
|
ctx.JSONErrorWithField(ctx.Tr("repo.settings.key_name_used"), "title")
|
||||||
ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form)
|
|
||||||
case asymkey_model.IsErrDeployKeyNameAlreadyUsed(err):
|
case asymkey_model.IsErrDeployKeyNameAlreadyUsed(err):
|
||||||
ctx.Data["Err_Title"] = true
|
ctx.JSONErrorWithField(ctx.Tr("repo.settings.key_name_used"), "title")
|
||||||
ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form)
|
|
||||||
default:
|
default:
|
||||||
ctx.ServerError("AddDeployKey", err)
|
ctx.ServerError("AddDeployKey", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace("Deploy key added: %d", ctx.Repo.Repository.ID)
|
|
||||||
ctx.Flash.Success(ctx.Tr("repo.settings.add_key_success", key.Name))
|
ctx.Flash.Success(ctx.Tr("repo.settings.add_key_success", key.Name))
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys")
|
ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/keys")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteDeployKey response for deleting a deploy key
|
// DeleteDeployKey response for deleting a deploy key
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package setting
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
asymkey_model "gitea.dev/models/asymkey"
|
asymkey_model "gitea.dev/models/asymkey"
|
||||||
@@ -27,53 +28,25 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAddReadOnlyDeployKey(t *testing.T) {
|
func TestAddDeployKey(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.SSH.RootPath, t.TempDir())()
|
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
|
t.Run("ReadOnly", func(t *testing.T) {
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1/settings/keys")
|
const testKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICV0MGX/W9IvLA4FXpIuUcdDcbj5KX4syHgsTy7soVgf\n"
|
||||||
|
ctx, _ := contexttest.MockContext(t, "POST /user2/repo1/settings/keys")
|
||||||
contexttest.LoadUser(t, ctx, 2)
|
contexttest.MockRequestPostForm(ctx.Req, url.Values{"title": {"read-only"}, "content": {testKey}})
|
||||||
contexttest.LoadRepo(t, ctx, 2)
|
contexttest.LoadRepo(t, ctx, 2)
|
||||||
|
DeployKeysPost(ctx)
|
||||||
addKeyForm := forms.AddKeyForm{
|
assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
|
||||||
Title: "read-only",
|
unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{Name: "read-only", Content: testKey, Mode: perm.AccessModeRead})
|
||||||
Content: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n",
|
|
||||||
}
|
|
||||||
web.SetForm(ctx, &addKeyForm)
|
|
||||||
DeployKeysPost(ctx)
|
|
||||||
assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
|
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{
|
|
||||||
Name: addKeyForm.Title,
|
|
||||||
Content: addKeyForm.Content,
|
|
||||||
Mode: perm.AccessModeRead,
|
|
||||||
})
|
})
|
||||||
}
|
t.Run("ReadWrite", func(t *testing.T) {
|
||||||
|
const testKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEHjnNEfE88W1pvBLdV3otv28x760gdmPao3lVD5uAt9\n"
|
||||||
func TestAddReadWriteOnlyDeployKey(t *testing.T) {
|
ctx, _ := contexttest.MockContext(t, "POST /user2/repo1/settings/keys")
|
||||||
defer test.MockVariableValue(&setting.SSH.RootPath, t.TempDir())()
|
contexttest.MockRequestPostForm(ctx.Req, url.Values{"title": {"read-write"}, "content": {testKey}, "is_writable": {"on"}})
|
||||||
|
contexttest.LoadRepo(t, ctx, 2)
|
||||||
unittest.PrepareTestEnv(t)
|
DeployKeysPost(ctx)
|
||||||
|
assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1/settings/keys")
|
unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{Name: "read-write", Content: testKey, Mode: perm.AccessModeWrite})
|
||||||
|
|
||||||
contexttest.LoadUser(t, ctx, 2)
|
|
||||||
contexttest.LoadRepo(t, ctx, 2)
|
|
||||||
|
|
||||||
addKeyForm := forms.AddKeyForm{
|
|
||||||
Title: "read-write",
|
|
||||||
Content: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n",
|
|
||||||
IsWritable: true,
|
|
||||||
}
|
|
||||||
web.SetForm(ctx, &addKeyForm)
|
|
||||||
DeployKeysPost(ctx)
|
|
||||||
assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
|
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{
|
|
||||||
Name: addKeyForm.Title,
|
|
||||||
Content: addKeyForm.Content,
|
|
||||||
Mode: perm.AccessModeWrite,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1225,7 +1225,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) {
|
|||||||
|
|
||||||
m.Group("/keys", func() {
|
m.Group("/keys", func() {
|
||||||
m.Combo("").Get(repo_setting.DeployKeys).
|
m.Combo("").Get(repo_setting.DeployKeys).
|
||||||
Post(web.Bind(forms.AddKeyForm{}), repo_setting.DeployKeysPost)
|
Post(repo_setting.DeployKeysPost)
|
||||||
m.Post("/delete", repo_setting.DeleteDeployKey)
|
m.Post("/delete", repo_setting.DeleteDeployKey)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
+49
-14
@@ -26,6 +26,8 @@ import (
|
|||||||
"gitea.dev/modules/web"
|
"gitea.dev/modules/web"
|
||||||
"gitea.dev/modules/web/middleware"
|
"gitea.dev/modules/web/middleware"
|
||||||
web_types "gitea.dev/modules/web/types"
|
web_types "gitea.dev/modules/web/types"
|
||||||
|
|
||||||
|
"gitea.com/go-chi/binding"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Render represents a template render
|
// Render represents a template render
|
||||||
@@ -81,17 +83,22 @@ func GetWebContext(ctx context.Context) *Context {
|
|||||||
return webCtx
|
return webCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateContext is a special context for form validation middleware. It may be different from other contexts.
|
|
||||||
type ValidateContext struct {
|
|
||||||
*Base
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetValidateContext gets a context for middleware form validation
|
// GetValidateContext gets a context for middleware form validation
|
||||||
func GetValidateContext(req *http.Request) (ctx *ValidateContext) {
|
func GetValidateContext(req *http.Request) (ctx *middleware.ValidateContext) {
|
||||||
if ctxAPI, ok := req.Context().Value(apiContextKey).(*APIContext); ok {
|
if ctxAPI, ok := req.Context().Value(apiContextKey).(*APIContext); ok {
|
||||||
ctx = &ValidateContext{Base: ctxAPI.Base}
|
ctx = &middleware.ValidateContext{
|
||||||
|
Data: ctxAPI.Data,
|
||||||
|
Locale: ctxAPI.Locale,
|
||||||
|
Req: ctxAPI.Req,
|
||||||
|
Resp: ctxAPI.Resp,
|
||||||
|
}
|
||||||
} else if ctxWeb, ok := req.Context().Value(WebContextKey).(*Context); ok {
|
} else if ctxWeb, ok := req.Context().Value(WebContextKey).(*Context); ok {
|
||||||
ctx = &ValidateContext{Base: ctxWeb.Base}
|
ctx = &middleware.ValidateContext{
|
||||||
|
Data: ctxWeb.Data,
|
||||||
|
Locale: ctxWeb.Locale,
|
||||||
|
Req: ctxWeb.Req,
|
||||||
|
Resp: ctxWeb.Resp,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
panic("invalid context, expect either APIContext or Context")
|
panic("invalid context, expect either APIContext or Context")
|
||||||
}
|
}
|
||||||
@@ -254,15 +261,24 @@ func (ctx *Context) JSONOK() {
|
|||||||
ctx.JSON(http.StatusOK, map[string]any{"ok": true}) // this is only a dummy response, frontend seldom uses it
|
ctx.JSON(http.StatusOK, map[string]any{"ok": true}) // this is only a dummy response, frontend seldom uses it
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) JSONError(msg any) {
|
func buildJsonErrorMap(msg any) map[string]any {
|
||||||
switch v := msg.(type) {
|
switch v := msg.(type) {
|
||||||
case string:
|
case string:
|
||||||
ctx.JSON(http.StatusBadRequest, map[string]any{"errorMessage": v, "renderFormat": "text"})
|
return map[string]any{"errorMessage": v, "renderFormat": "text"}
|
||||||
case template.HTML:
|
case template.HTML:
|
||||||
ctx.JSON(http.StatusBadRequest, map[string]any{"errorMessage": v, "renderFormat": "html"})
|
return map[string]any{"errorMessage": v, "renderFormat": "html"}
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("unsupported type: %T", msg))
|
|
||||||
}
|
}
|
||||||
|
panic(fmt.Sprintf("unsupported type: %T", msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) JSONError(msg any) {
|
||||||
|
ctx.JSON(http.StatusBadRequest, buildJsonErrorMap(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) JSONErrorWithField(msg any, field string) {
|
||||||
|
m := buildJsonErrorMap(msg)
|
||||||
|
m["errorFields"] = []string{field}
|
||||||
|
ctx.JSON(http.StatusBadRequest, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *Context) JSONErrorNotFound(optMsg ...string) {
|
func (ctx *Context) JSONErrorNotFound(optMsg ...string) {
|
||||||
@@ -270,5 +286,24 @@ func (ctx *Context) JSONErrorNotFound(optMsg ...string) {
|
|||||||
if msg == "" {
|
if msg == "" {
|
||||||
msg = ctx.Locale.TrString("error.not_found")
|
msg = ctx.Locale.TrString("error.not_found")
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusNotFound, map[string]any{"errorMessage": msg, "renderFormat": "text"})
|
ctx.JSON(http.StatusNotFound, buildJsonErrorMap(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFetchActionForm[T interface {
|
||||||
|
*E
|
||||||
|
middleware.Form
|
||||||
|
}, E any](ctx *Context) *E {
|
||||||
|
if web.IsFormSet(ctx) {
|
||||||
|
panic("don't mix fetch-action form validation with template-based form validation")
|
||||||
|
}
|
||||||
|
middleware.SkipTmplFormValidationError(ctx)
|
||||||
|
form := T(new(E))
|
||||||
|
errs := binding.Bind(ctx.Req, form)
|
||||||
|
errorMessage, fieldName, _ := middleware.BuildValidationErrorForUser(form, ctx.Locale, errs)
|
||||||
|
if errorMessage != "" {
|
||||||
|
ctx.Resp.Header().Set("Content-Type", "application/json")
|
||||||
|
ctx.JSONErrorWithField(errorMessage, fieldName)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return form
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,12 @@ func MockPrivateContext(t *testing.T, reqPath string) (*context.PrivateContext,
|
|||||||
return ctx, resp
|
return ctx, resp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MockRequestPostForm(req *http.Request, formData url.Values) {
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.PostForm = formData
|
||||||
|
maps.Copy(req.Form, formData)
|
||||||
|
}
|
||||||
|
|
||||||
// LoadRepo load a repo into a test context.
|
// LoadRepo load a repo into a test context.
|
||||||
func LoadRepo(t *testing.T, ctx gocontext.Context, repoID int64) {
|
func LoadRepo(t *testing.T, ctx gocontext.Context, repoID int64) {
|
||||||
var doer *user_model.User
|
var doer *user_model.User
|
||||||
|
|||||||
@@ -41,19 +41,19 @@ type AdminEditBadgeForm struct {
|
|||||||
// Validate validates form fields
|
// Validate validates form fields
|
||||||
func (f *AdminCreateBadgeForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AdminCreateBadgeForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates form fields
|
// Validate validates form fields
|
||||||
func (f *AdminEditBadgeForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AdminEditBadgeForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates form fields
|
// Validate validates form fields
|
||||||
func (f *AdminCreateUserForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AdminCreateUserForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdminEditUserForm form for admin to create user
|
// AdminEditUserForm form for admin to create user
|
||||||
@@ -82,7 +82,7 @@ type AdminEditUserForm struct {
|
|||||||
// Validate validates form fields
|
// Validate validates form fields
|
||||||
func (f *AdminEditUserForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AdminEditUserForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdminDashboardForm form for admin dashboard operations
|
// AdminDashboardForm form for admin dashboard operations
|
||||||
@@ -94,5 +94,5 @@ type AdminDashboardForm struct {
|
|||||||
// Validate validates form fields
|
// Validate validates form fields
|
||||||
func (f *AdminDashboardForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AdminDashboardForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,5 +100,5 @@ type AuthenticationForm struct {
|
|||||||
// Validate validates fields
|
// Validate validates fields
|
||||||
func (f *AuthenticationForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AuthenticationForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ type CreateOrgForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *CreateOrgForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *CreateOrgForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateOrgSettingForm form for updating organization settings
|
// UpdateOrgSettingForm form for updating organization settings
|
||||||
@@ -48,7 +48,7 @@ type UpdateOrgSettingForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *UpdateOrgSettingForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *UpdateOrgSettingForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RenameOrgForm struct {
|
type RenameOrgForm struct {
|
||||||
@@ -76,5 +76,5 @@ type CreateTeamForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *CreateTeamForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *CreateTeamForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,5 +26,5 @@ type PackageCleanupRuleForm struct {
|
|||||||
|
|
||||||
func (f *PackageCleanupRuleForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *PackageCleanupRuleForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ type NewBranchForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewBranchForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewBranchForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenameBranchForm form for rename a branch
|
// RenameBranchForm form for rename a branch
|
||||||
@@ -34,5 +34,5 @@ type RenameBranchForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *RenameBranchForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *RenameBranchForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-36
@@ -50,7 +50,7 @@ type CreateRepoForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *CreateRepoForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *CreateRepoForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MigrateRepoForm form for migrating repository
|
// MigrateRepoForm form for migrating repository
|
||||||
@@ -86,7 +86,7 @@ type MigrateRepoForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *MigrateRepoForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *MigrateRepoForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RepoSettingForm form for changing repository settings
|
// RepoSettingForm form for changing repository settings
|
||||||
@@ -163,7 +163,7 @@ type RepoSettingForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *RepoSettingForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *RepoSettingForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProtectBranchForm form for changing protected branch settings
|
// ProtectBranchForm form for changing protected branch settings
|
||||||
@@ -205,7 +205,7 @@ type ProtectBranchForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *ProtectBranchForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *ProtectBranchForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebhookForm form for changing web hook
|
// WebhookForm form for changing web hook
|
||||||
@@ -268,7 +268,7 @@ type NewWebhookForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewWebhookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewWebhookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGogshookForm form for creating gogs hook
|
// NewGogshookForm form for creating gogs hook
|
||||||
@@ -281,7 +281,7 @@ type NewGogshookForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewGogshookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewGogshookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSlackHookForm form for creating slack hook
|
// NewSlackHookForm form for creating slack hook
|
||||||
@@ -298,13 +298,9 @@ type NewSlackHookForm struct {
|
|||||||
func (f *NewSlackHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewSlackHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
if !webhook.IsValidSlackChannel(strings.TrimSpace(f.Channel)) {
|
if !webhook.IsValidSlackChannel(strings.TrimSpace(f.Channel)) {
|
||||||
errs = append(errs, binding.Error{
|
errs = middleware.AddValidationError(errs, "Channel", ctx.Locale.TrString("repo.settings.add_webhook.invalid_channel_name"))
|
||||||
FieldNames: []string{"Channel"},
|
|
||||||
Classification: "",
|
|
||||||
Message: ctx.Locale.TrString("repo.settings.add_webhook.invalid_channel_name"),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDiscordHookForm form for creating discord hook
|
// NewDiscordHookForm form for creating discord hook
|
||||||
@@ -318,7 +314,7 @@ type NewDiscordHookForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewDiscordHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewDiscordHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDingtalkHookForm form for creating dingtalk hook
|
// NewDingtalkHookForm form for creating dingtalk hook
|
||||||
@@ -330,7 +326,7 @@ type NewDingtalkHookForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewDingtalkHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewDingtalkHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTelegramHookForm form for creating telegram hook
|
// NewTelegramHookForm form for creating telegram hook
|
||||||
@@ -344,7 +340,7 @@ type NewTelegramHookForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewTelegramHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewTelegramHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMatrixHookForm form for creating Matrix hook
|
// NewMatrixHookForm form for creating Matrix hook
|
||||||
@@ -358,7 +354,7 @@ type NewMatrixHookForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewMatrixHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewMatrixHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMSTeamsHookForm form for creating MS Teams hook
|
// NewMSTeamsHookForm form for creating MS Teams hook
|
||||||
@@ -370,7 +366,7 @@ type NewMSTeamsHookForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewMSTeamsHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewMSTeamsHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFeishuHookForm form for creating feishu hook
|
// NewFeishuHookForm form for creating feishu hook
|
||||||
@@ -382,7 +378,7 @@ type NewFeishuHookForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewFeishuHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewFeishuHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWechatWorkHookForm form for creating wechatwork hook
|
// NewWechatWorkHookForm form for creating wechatwork hook
|
||||||
@@ -394,7 +390,7 @@ type NewWechatWorkHookForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewWechatWorkHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewWechatWorkHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPackagistHookForm form for creating packagist hook
|
// NewPackagistHookForm form for creating packagist hook
|
||||||
@@ -408,7 +404,7 @@ type NewPackagistHookForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewPackagistHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewPackagistHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateIssueForm form for creating issue
|
// CreateIssueForm form for creating issue
|
||||||
@@ -426,7 +422,7 @@ type CreateIssueForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *CreateIssueForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *CreateIssueForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateCommentForm form for creating comment
|
// CreateCommentForm form for creating comment
|
||||||
@@ -439,7 +435,7 @@ type CreateCommentForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *CreateCommentForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *CreateCommentForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReactionForm form for adding and removing reaction
|
// ReactionForm form for adding and removing reaction
|
||||||
@@ -450,7 +446,7 @@ type ReactionForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *ReactionForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *ReactionForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IssueLockForm form for locking an issue
|
// IssueLockForm form for locking an issue
|
||||||
@@ -459,9 +455,9 @@ type IssueLockForm struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (i *IssueLockForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *IssueLockForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, i, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateProjectForm form for creating a project
|
// CreateProjectForm form for creating a project
|
||||||
@@ -489,7 +485,7 @@ type CreateMilestoneForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *CreateMilestoneForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *CreateMilestoneForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateLabelForm form for creating label
|
// CreateLabelForm form for creating label
|
||||||
@@ -506,7 +502,7 @@ type CreateLabelForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *CreateLabelForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *CreateLabelForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitializeLabelsForm form for initializing labels
|
// InitializeLabelsForm form for initializing labels
|
||||||
@@ -517,7 +513,7 @@ type InitializeLabelsForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *InitializeLabelsForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *InitializeLabelsForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MergePullRequestForm form for merging Pull Request
|
// MergePullRequestForm form for merging Pull Request
|
||||||
@@ -571,7 +567,7 @@ func (f *MergePullRequestForm) UnmarshalJSON(b []byte) error {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *MergePullRequestForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *MergePullRequestForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CodeCommentForm form for adding code comments for PRs
|
// CodeCommentForm form for adding code comments for PRs
|
||||||
@@ -590,7 +586,7 @@ type CodeCommentForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *CodeCommentForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *CodeCommentForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubmitReviewForm for submitting a finished code review
|
// SubmitReviewForm for submitting a finished code review
|
||||||
@@ -604,7 +600,7 @@ type SubmitReviewForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *SubmitReviewForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *SubmitReviewForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReviewType will return the corresponding ReviewType for type
|
// ReviewType will return the corresponding ReviewType for type
|
||||||
@@ -665,7 +661,7 @@ type NewReleaseForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewReleaseForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewReleaseForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateReleaseNotesForm retrieves release notes recommendations.
|
// GenerateReleaseNotesForm retrieves release notes recommendations.
|
||||||
@@ -678,7 +674,7 @@ type GenerateReleaseNotesForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *GenerateReleaseNotesForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *GenerateReleaseNotesForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditReleaseForm form for changing release
|
// EditReleaseForm form for changing release
|
||||||
@@ -693,7 +689,7 @@ type EditReleaseForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *EditReleaseForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *EditReleaseForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// __ __.__ __ .__
|
// __ __.__ __ .__
|
||||||
@@ -714,7 +710,7 @@ type NewWikiForm struct {
|
|||||||
// FIXME: use code generation to generate this method.
|
// FIXME: use code generation to generate this method.
|
||||||
func (f *NewWikiForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewWikiForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ___________.__ ___________ __
|
// ___________.__ ___________ __
|
||||||
@@ -733,7 +729,7 @@ type AddTimeManuallyForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *AddTimeManuallyForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AddTimeManuallyForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveTopicForm form for save topics for repository
|
// SaveTopicForm form for save topics for repository
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type CommitCommonForm struct {
|
|||||||
|
|
||||||
func (f *CommitCommonForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *CommitCommonForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommitCommonFormInterface interface {
|
type CommitCommonFormInterface interface {
|
||||||
|
|||||||
@@ -22,5 +22,5 @@ type ProtectTagForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *ProtectTagForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *ProtectTagForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,5 +20,5 @@ type EditRunnerForm struct {
|
|||||||
// Validate validates form fields
|
// Validate validates form fields
|
||||||
func (f *EditRunnerForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *EditRunnerForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-26
@@ -77,7 +77,7 @@ type InstallForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *InstallForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *InstallForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// _____ ____ _________________ ___
|
// _____ ____ _________________ ___
|
||||||
@@ -98,7 +98,7 @@ type RegisterForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *RegisterForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *RegisterForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmailDomainAllowed validates that the email address
|
// IsEmailDomainAllowed validates that the email address
|
||||||
@@ -120,7 +120,7 @@ type MustChangePasswordForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *MustChangePasswordForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *MustChangePasswordForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignInForm form for signing in with user/password
|
// SignInForm form for signing in with user/password
|
||||||
@@ -134,7 +134,7 @@ type SignInForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *SignInForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *SignInForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthorizationForm form for authorizing oauth2 clients
|
// AuthorizationForm form for authorizing oauth2 clients
|
||||||
@@ -154,7 +154,7 @@ type AuthorizationForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *AuthorizationForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AuthorizationForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GrantApplicationForm form for authorizing oauth2 clients
|
// GrantApplicationForm form for authorizing oauth2 clients
|
||||||
@@ -170,7 +170,7 @@ type GrantApplicationForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *GrantApplicationForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *GrantApplicationForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccessTokenForm for issuing access tokens from authorization codes or refresh tokens
|
// AccessTokenForm for issuing access tokens from authorization codes or refresh tokens
|
||||||
@@ -189,7 +189,7 @@ type AccessTokenForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *AccessTokenForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AccessTokenForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntrospectTokenForm for introspecting tokens
|
// IntrospectTokenForm for introspecting tokens
|
||||||
@@ -200,7 +200,7 @@ type IntrospectTokenForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *IntrospectTokenForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *IntrospectTokenForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// __________________________________________.___ _______ ________ _________
|
// __________________________________________.___ _______ ________ _________
|
||||||
@@ -225,7 +225,7 @@ type UpdateProfileForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *UpdateProfileForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *UpdateProfileForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateLanguageForm form for updating profile
|
// UpdateLanguageForm form for updating profile
|
||||||
@@ -236,7 +236,7 @@ type UpdateLanguageForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *UpdateLanguageForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *UpdateLanguageForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avatar types
|
// Avatar types
|
||||||
@@ -256,7 +256,7 @@ type AvatarForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *AvatarForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AvatarForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddEmailForm form for adding new email
|
// AddEmailForm form for adding new email
|
||||||
@@ -267,7 +267,7 @@ type AddEmailForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *AddEmailForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AddEmailForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateThemeForm form for updating a users' theme
|
// UpdateThemeForm form for updating a users' theme
|
||||||
@@ -278,7 +278,7 @@ type UpdateThemeForm struct {
|
|||||||
// Validate validates the field
|
// Validate validates the field
|
||||||
func (f *UpdateThemeForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *UpdateThemeForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangePasswordForm form for changing password
|
// ChangePasswordForm form for changing password
|
||||||
@@ -291,7 +291,7 @@ type ChangePasswordForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *ChangePasswordForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *ChangePasswordForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOpenIDForm is for changing openid uri
|
// AddOpenIDForm is for changing openid uri
|
||||||
@@ -302,7 +302,7 @@ type AddOpenIDForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *AddOpenIDForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AddOpenIDForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddKeyForm form for adding SSH/GPG key
|
// AddKeyForm form for adding SSH/GPG key
|
||||||
@@ -319,7 +319,7 @@ type AddKeyForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *AddKeyForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AddKeyForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSecretForm for adding secrets
|
// AddSecretForm for adding secrets
|
||||||
@@ -332,7 +332,7 @@ type AddSecretForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *AddSecretForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *AddSecretForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditVariableForm struct {
|
type EditVariableForm struct {
|
||||||
@@ -343,7 +343,7 @@ type EditVariableForm struct {
|
|||||||
|
|
||||||
func (f *EditVariableForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *EditVariableForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAccessTokenForm form for creating access token
|
// NewAccessTokenForm form for creating access token
|
||||||
@@ -354,7 +354,7 @@ type NewAccessTokenForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *NewAccessTokenForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *NewAccessTokenForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditOAuth2ApplicationForm form for editing oauth2 applications
|
// EditOAuth2ApplicationForm form for editing oauth2 applications
|
||||||
@@ -381,9 +381,9 @@ func (f *EditOAuth2ApplicationForm) Validate(req *http.Request, errs binding.Err
|
|||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
invalidURI := DetectInvalidOAuth2ApplicationRedirectURI(util.SplitTrimSpace(f.RedirectURIs, "\n"))
|
invalidURI := DetectInvalidOAuth2ApplicationRedirectURI(util.SplitTrimSpace(f.RedirectURIs, "\n"))
|
||||||
if invalidURI != "" {
|
if invalidURI != "" {
|
||||||
errs = middleware.ReportValidationError(errs, ctx.Data, "RedirectURIs", binding.ERR_URL, ctx.Locale.TrString("form.url_error", invalidURI))
|
errs = middleware.AddValidationError(errs, "RedirectURIs", "RedirectURIs: "+ctx.Locale.TrString("form.url_error", `"`+invalidURI+`"`))
|
||||||
}
|
}
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TwoFactorAuthForm for logging in with 2FA token.
|
// TwoFactorAuthForm for logging in with 2FA token.
|
||||||
@@ -394,7 +394,7 @@ type TwoFactorAuthForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *TwoFactorAuthForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *TwoFactorAuthForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TwoFactorScratchAuthForm for logging in with 2FA scratch token.
|
// TwoFactorScratchAuthForm for logging in with 2FA scratch token.
|
||||||
@@ -405,7 +405,7 @@ type TwoFactorScratchAuthForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *TwoFactorScratchAuthForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *TwoFactorScratchAuthForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebauthnRegistrationForm for reserving an WebAuthn name
|
// WebauthnRegistrationForm for reserving an WebAuthn name
|
||||||
@@ -416,7 +416,7 @@ type WebauthnRegistrationForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *WebauthnRegistrationForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *WebauthnRegistrationForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PackageSettingForm form for package settings
|
// PackageSettingForm form for package settings
|
||||||
@@ -428,7 +428,7 @@ type PackageSettingForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *PackageSettingForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *PackageSettingForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockUserForm struct {
|
type BlockUserForm struct {
|
||||||
@@ -439,5 +439,5 @@ type BlockUserForm struct {
|
|||||||
|
|
||||||
func (f *BlockUserForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *BlockUserForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type SignInOpenIDForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *SignInOpenIDForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *SignInOpenIDForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignUpOpenIDForm form for signin up with OpenID
|
// SignUpOpenIDForm form for signin up with OpenID
|
||||||
@@ -33,7 +33,7 @@ type SignUpOpenIDForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *SignUpOpenIDForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *SignUpOpenIDForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectOpenIDForm form for connecting an existing account to an OpenID URI
|
// ConnectOpenIDForm form for connecting an existing account to an OpenID URI
|
||||||
@@ -45,5 +45,5 @@ type ConnectOpenIDForm struct {
|
|||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
func (f *ConnectOpenIDForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
func (f *ConnectOpenIDForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||||
ctx := context.GetValidateContext(req)
|
ctx := context.GetValidateContext(req)
|
||||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
return middleware.Validate(ctx, errs, f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,21 +11,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<div class="{{if not .HasError}}tw-hidden{{end}} tw-mb-4" id="add-deploy-key-panel">
|
<div class="tw-hidden tw-mb-4" id="add-deploy-key-panel">
|
||||||
<form class="ui form" action="{{.Link}}" method="post">
|
<form class="ui form form-fetch-action" action="{{.Link}}" method="post">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
{{ctx.Locale.Tr "repo.settings.deploy_key_desc"}}
|
{{ctx.Locale.Tr "repo.settings.deploy_key_desc"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="field {{if .Err_Title}}error{{end}}">
|
<div class="field">
|
||||||
<label for="ssh-key-title">{{ctx.Locale.Tr "repo.settings.title"}}</label>
|
<label for="ssh-key-title">{{ctx.Locale.Tr "repo.settings.title"}}</label>
|
||||||
<input id="ssh-key-title" name="title" value="{{.title}}" autofocus required>
|
<input id="ssh-key-title" name="title" value="{{.title}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
<div class="field {{if .Err_Content}}error{{end}}">
|
<div class="field">
|
||||||
<label for="ssh-key-content">{{ctx.Locale.Tr "repo.settings.deploy_key_content"}}</label>
|
<label for="ssh-key-content">{{ctx.Locale.Tr "repo.settings.deploy_key_content"}}</label>
|
||||||
<textarea id="ssh-key-content" name="content" placeholder="{{ctx.Locale.Tr "settings.key_content_ssh_placeholder"}}" required>{{.content}}</textarea>
|
<textarea id="ssh-key-content" name="content" placeholder="{{ctx.Locale.Tr "settings.key_content_ssh_placeholder"}}" required>{{.content}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui checkbox {{if .Err_IsWritable}}error{{end}}">
|
<div class="ui checkbox">
|
||||||
<input id="ssh-key-is-writable" name="is_writable" type="checkbox" value="1">
|
<input id="ssh-key-is-writable" name="is_writable" type="checkbox" value="1">
|
||||||
<label for="ssh-key-is-writable">
|
<label for="ssh-key-is-writable">
|
||||||
{{ctx.Locale.Tr "repo.settings.is_writable"}}
|
{{ctx.Locale.Tr "repo.settings.is_writable"}}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
|
|||||||
OldRefSubURL: "branch/master",
|
OldRefSubURL: "branch/master",
|
||||||
NewBranch: "",
|
NewBranch: "",
|
||||||
ExpectedStatus: http.StatusSeeOther,
|
ExpectedStatus: http.StatusSeeOther,
|
||||||
FlashMessage: translation.NewLocale("en-US").TrString("form.NewBranchName") + translation.NewLocale("en-US").TrString("form.require_error"),
|
FlashMessage: translation.NewLocale("en-US").TrString("form.require_error", translation.NewLocale("en-US").TrString("form.NewBranchName")),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
OldRefSubURL: "branch/master",
|
OldRefSubURL: "branch/master",
|
||||||
@@ -65,7 +65,7 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
|
|||||||
OldRefSubURL: "branch/master",
|
OldRefSubURL: "branch/master",
|
||||||
NewBranch: strings.Repeat("b", 101),
|
NewBranch: strings.Repeat("b", 101),
|
||||||
ExpectedStatus: http.StatusSeeOther,
|
ExpectedStatus: http.StatusSeeOther,
|
||||||
FlashMessage: translation.NewLocale("en-US").TrString("form.NewBranchName") + translation.NewLocale("en-US").TrString("form.max_size_error", "100"),
|
FlashMessage: translation.NewLocale("en-US").TrString("form.max_size_error", translation.NewLocale("en-US").TrString("form.NewBranchName"), "100"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
OldRefSubURL: "branch/master",
|
OldRefSubURL: "branch/master",
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ func testRenameInvalidUsername(t *testing.T) {
|
|||||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
assert.Contains(t,
|
assert.Contains(t,
|
||||||
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
||||||
translation.NewLocale("en-US").TrString("form.username_error"),
|
translation.NewLocale("en-US").TrString("form.username_error", "Name"),
|
||||||
)
|
)
|
||||||
|
|
||||||
unittest.AssertNotExistsBean(t, &user_model.User{Name: invalidUsername})
|
unittest.AssertNotExistsBean(t, &user_model.User{Name: invalidUsername})
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import {execPseudoSelectorCommands, handleFetchActionSuccessJson} from './common-fetch-action.ts';
|
import {execPseudoSelectorCommands, handleFetchActionErrorFields, handleFetchActionSuccessJson} from './common-fetch-action.ts';
|
||||||
|
import {createElementFromHTML} from '../utils/dom.ts';
|
||||||
|
import {normalizeTestHtml} from '../utils/testhelper.ts';
|
||||||
|
|
||||||
test('execPseudoSelectorCommands', () => {
|
test('execPseudoSelectorCommands', () => {
|
||||||
window.document.body.innerHTML = `
|
window.document.body.innerHTML = `
|
||||||
@@ -57,3 +59,15 @@ test('handleFetchActionSuccessJson', async () => {
|
|||||||
expect(spyReload).toHaveBeenCalledTimes(1);
|
expect(spyReload).toHaveBeenCalledTimes(1);
|
||||||
vi.resetAllMocks();
|
vi.resetAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('handleFetchActionErrorFields', () => {
|
||||||
|
const elForm = createElementFromHTML<HTMLElement>(`<form>
|
||||||
|
<div class="error field"></div>
|
||||||
|
<div class="field"><input name="Foo_Bar[]"></div>
|
||||||
|
</form>`);
|
||||||
|
handleFetchActionErrorFields(elForm, ['foo-BAR', 'other']);
|
||||||
|
expect(normalizeTestHtml(elForm.outerHTML)).toEqual(normalizeTestHtml(`<form>
|
||||||
|
<div class="field"></div>
|
||||||
|
<div class="field error"><input name="Foo_Bar[]"></div>
|
||||||
|
</form>`));
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {GET, request} from '../modules/fetch.ts';
|
import {GET, request} from '../modules/fetch.ts';
|
||||||
import {hideToastsAll, showErrorToast} from '../modules/toast.ts';
|
import {hideToastsAll, showErrorToast} from '../modules/toast.ts';
|
||||||
import {activePageTimerRefresh, addDelegatedEventListener, createElementFromHTML} from '../utils/dom.ts';
|
import {activePageTimerRefresh, addDelegatedEventListener, createElementFromHTML, queryElems} from '../utils/dom.ts';
|
||||||
import {errorMessage, errorName} from '../modules/errors.ts';
|
import {errorMessage, errorName} from '../modules/errors.ts';
|
||||||
import {confirmModal, createConfirmModal} from './comp/ConfirmModal.ts';
|
import {confirmModal, createConfirmModal} from './comp/ConfirmModal.ts';
|
||||||
import {ignoreAreYouSure} from '../vendor/jquery.are-you-sure.ts';
|
import {ignoreAreYouSure} from '../vendor/jquery.are-you-sure.ts';
|
||||||
@@ -92,7 +92,34 @@ async function handleFetchActionSuccess(el: HTMLElement, opt: FetchActionOpts, r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleFetchActionError(resp: Response) {
|
function resetFormErrorFields(elForm: HTMLFormElement) {
|
||||||
|
queryElems(elForm, '.field.error', (el) => el.classList.remove('error'));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handleFetchActionErrorFields(el: HTMLElement, errorFields: string[]) {
|
||||||
|
// The "error field" only works in a form.
|
||||||
|
// And non-form requests do not need such "error field" because the requests are just from a button or a link in such cases.
|
||||||
|
if (el.nodeName !== 'FORM') return;
|
||||||
|
const elForm = el as HTMLFormElement;
|
||||||
|
resetFormErrorFields(elForm);
|
||||||
|
const fieldNameElemMap : Record<string, HTMLElement> = {};
|
||||||
|
const normalizeFieldName = (name: string) => name.replace(/[^A-Za-z0-9]/g, '').toLowerCase();
|
||||||
|
queryElems(elForm, '[name]', (el) => {
|
||||||
|
const name = el.getAttribute('name');
|
||||||
|
if (!name) return;
|
||||||
|
fieldNameElemMap[normalizeFieldName(name)] = el;
|
||||||
|
});
|
||||||
|
for (const errorField of errorFields) {
|
||||||
|
const name = normalizeFieldName(errorField);
|
||||||
|
const elInput = fieldNameElemMap[name];
|
||||||
|
if (!elInput) continue;
|
||||||
|
const elField = elInput.closest('.field');
|
||||||
|
if (!elField) continue;
|
||||||
|
elField.classList.add('error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleFetchActionError(el: HTMLElement, resp: Response) {
|
||||||
const isRespJson = resp.headers.get('content-type')?.includes('application/json');
|
const isRespJson = resp.headers.get('content-type')?.includes('application/json');
|
||||||
const respText = await resp.text();
|
const respText = await resp.text();
|
||||||
const respJson = isRespJson ? JSON.parse(respText) : null;
|
const respJson = isRespJson ? JSON.parse(respText) : null;
|
||||||
@@ -100,6 +127,9 @@ async function handleFetchActionError(resp: Response) {
|
|||||||
// the code was quite messy, sometimes the backend uses "err", sometimes it uses "error", and even "user_error"
|
// the code was quite messy, sometimes the backend uses "err", sometimes it uses "error", and even "user_error"
|
||||||
// but at the moment, as a new approach, we only use "errorMessage" here, backend can use JSONError() to respond.
|
// but at the moment, as a new approach, we only use "errorMessage" here, backend can use JSONError() to respond.
|
||||||
showErrorToast(respJson.errorMessage, {useHtmlBody: respJson.renderFormat === 'html'});
|
showErrorToast(respJson.errorMessage, {useHtmlBody: respJson.renderFormat === 'html'});
|
||||||
|
if (respJson?.errorFields?.length) {
|
||||||
|
handleFetchActionErrorFields(el, respJson?.errorFields);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
showErrorToast(`Error ${resp.status} ${resp.statusText}. Response: ${respText.substring(0, 200)}`);
|
showErrorToast(`Error ${resp.status} ${resp.statusText}. Response: ${respText.substring(0, 200)}`);
|
||||||
}
|
}
|
||||||
@@ -135,7 +165,7 @@ export async function performFetchActionRequest(el: HTMLElement, opt: FetchActio
|
|||||||
headers.set('X-Gitea-Fetch-Action', '1');
|
headers.set('X-Gitea-Fetch-Action', '1');
|
||||||
const resp = await request(url, {method: opt.method, data: opt.data, headers});
|
const resp = await request(url, {method: opt.method, data: opt.data, headers});
|
||||||
if (resp.ok) return resp;
|
if (resp.ok) return resp;
|
||||||
await handleFetchActionError(resp);
|
await handleFetchActionError(el, resp);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (errorName(err) !== 'AbortError') {
|
if (errorName(err) !== 'AbortError') {
|
||||||
console.error(`Fetch action request error:`, err);
|
console.error(`Fetch action request error:`, err);
|
||||||
@@ -194,9 +224,10 @@ function prepareFormFetchActionOpts(formEl: HTMLFormElement, opts: SubmitFormFet
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function submitFormFetchAction(formEl: HTMLFormElement, opts: SubmitFormFetchActionOpts = {}) {
|
export async function submitFormFetchAction(elForm: HTMLFormElement, opts: SubmitFormFetchActionOpts = {}) {
|
||||||
hideToastsAll();
|
hideToastsAll();
|
||||||
await performFetchAction(formEl, prepareFormFetchActionOpts(formEl, opts));
|
resetFormErrorFields(elForm);
|
||||||
|
await performFetchAction(elForm, prepareFormFetchActionOpts(elForm, opts));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function confirmFetchAction(el: HTMLElement) {
|
async function confirmFetchAction(el: HTMLElement) {
|
||||||
|
|||||||
Reference in New Issue
Block a user