diff --git a/cmd/web.go b/cmd/web.go index 87ad908aa..a56885b85 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -19,6 +19,7 @@ import ( "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/middleware" + "github.com/gogits/gogs/modules/middleware/binding" "github.com/gogits/gogs/routers" "github.com/gogits/gogs/routers/admin" "github.com/gogits/gogs/routers/api/v1" @@ -62,7 +63,7 @@ func runWeb(*cli.Context) { reqSignOut := middleware.Toggle(&middleware.ToggleOptions{SignOutRequire: true}) - bindIgnErr := middleware.BindIgnErr + bindIgnErr := binding.BindIgnErr // Routers. m.Get("/", ignSignIn, routers.Home) @@ -101,7 +102,7 @@ func runWeb(*cli.Context) { r.Post("/settings", bindIgnErr(auth.UpdateProfileForm{}), user.SettingPost) }, reqSignIn) m.Group("/user", func(r martini.Router) { - r.Get("/feeds", middleware.Bind(auth.FeedsForm{}), user.Feeds) + r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds) r.Any("/activate", user.Activate) r.Get("/email2user", user.Email2User) r.Get("/forget_password", user.ForgotPasswd) diff --git a/gogs.go b/gogs.go index 62bbc1794..cb4d43fd8 100644 --- a/gogs.go +++ b/gogs.go @@ -20,7 +20,7 @@ import ( // Test that go1.2 tag above is included in builds. main.go refers to this definition. const go12tag = true -const APP_VER = "0.3.2.0503 Alpha" +const APP_VER = "0.3.2.0505 Alpha" func init() { base.AppVer = APP_VER diff --git a/modules/auth/admin.go b/modules/auth/admin.go index 877af19af..51c1b78cc 100644 --- a/modules/auth/admin.go +++ b/modules/auth/admin.go @@ -12,6 +12,7 @@ import ( "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/middleware/binding" ) type AdminEditUserForm struct { @@ -33,7 +34,7 @@ func (f *AdminEditUserForm) Name(field string) string { return names[field] } -func (f *AdminEditUserForm) Validate(errors *base.BindingErrors, req *http.Request, context martini.Context) { +func (f *AdminEditUserForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { if req.Method == "GET" || errors.Count() == 0 { return } diff --git a/modules/auth/auth.go b/modules/auth/auth.go index 96e3868ff..8f7deaa30 100644 --- a/modules/auth/auth.go +++ b/modules/auth/auth.go @@ -13,6 +13,7 @@ import ( "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/middleware/binding" ) // Web form interface. @@ -37,7 +38,7 @@ func (f *RegisterForm) Name(field string) string { return names[field] } -func (f *RegisterForm) Validate(errors *base.BindingErrors, req *http.Request, context martini.Context) { +func (f *RegisterForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { if req.Method == "GET" || errors.Count() == 0 { return } @@ -70,7 +71,7 @@ func (f *LogInForm) Name(field string) string { return names[field] } -func (f *LogInForm) Validate(errors *base.BindingErrors, req *http.Request, context martini.Context) { +func (f *LogInForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { if req.Method == "GET" || errors.Count() == 0 { return } @@ -98,7 +99,7 @@ func getMinMaxSize(field reflect.StructField) string { return "" } -func validate(errors *base.BindingErrors, data base.TmplData, form Form) { +func validate(errors *binding.BindingErrors, data base.TmplData, form Form) { typ := reflect.TypeOf(form) val := reflect.ValueOf(form) @@ -119,19 +120,19 @@ func validate(errors *base.BindingErrors, data base.TmplData, form Form) { if err, ok := errors.Fields[field.Name]; ok { data["Err_"+field.Name] = true switch err { - case base.BindingRequireError: + case binding.BindingRequireError: data["ErrorMsg"] = form.Name(field.Name) + " cannot be empty" - case base.BindingAlphaDashError: + case binding.BindingAlphaDashError: data["ErrorMsg"] = form.Name(field.Name) + " must be valid alpha or numeric or dash(-_) characters" - case base.BindingAlphaDashDotError: + case binding.BindingAlphaDashDotError: data["ErrorMsg"] = form.Name(field.Name) + " must be valid alpha or numeric or dash(-_) or dot characters" - case base.BindingMinSizeError: + case binding.BindingMinSizeError: data["ErrorMsg"] = form.Name(field.Name) + " must contain at least " + getMinMaxSize(field) + " characters" - case base.BindingMaxSizeError: + case binding.BindingMaxSizeError: data["ErrorMsg"] = form.Name(field.Name) + " must contain at most " + getMinMaxSize(field) + " characters" - case base.BindingEmailError: + case binding.BindingEmailError: data["ErrorMsg"] = form.Name(field.Name) + " is not a valid e-mail address" - case base.BindingUrlError: + case binding.BindingUrlError: data["ErrorMsg"] = form.Name(field.Name) + " is not a valid URL" default: data["ErrorMsg"] = "Unknown error: " + err @@ -196,7 +197,7 @@ func (f *InstallForm) Name(field string) string { return names[field] } -func (f *InstallForm) Validate(errors *base.BindingErrors, req *http.Request, context martini.Context) { +func (f *InstallForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { if req.Method == "GET" || errors.Count() == 0 { return } diff --git a/modules/auth/issue.go b/modules/auth/issue.go index f73ddc744..85be12d2b 100644 --- a/modules/auth/issue.go +++ b/modules/auth/issue.go @@ -12,6 +12,7 @@ import ( "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/middleware/binding" ) type CreateIssueForm struct { @@ -29,7 +30,7 @@ func (f *CreateIssueForm) Name(field string) string { return names[field] } -func (f *CreateIssueForm) Validate(errors *base.BindingErrors, req *http.Request, context martini.Context) { +func (f *CreateIssueForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { if req.Method == "GET" || errors.Count() == 0 { return } diff --git a/modules/auth/release.go b/modules/auth/release.go index a29028e0e..9855c3033 100644 --- a/modules/auth/release.go +++ b/modules/auth/release.go @@ -12,6 +12,7 @@ import ( "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/middleware/binding" ) type NewReleaseForm struct { @@ -30,7 +31,7 @@ func (f *NewReleaseForm) Name(field string) string { return names[field] } -func (f *NewReleaseForm) Validate(errors *base.BindingErrors, req *http.Request, context martini.Context) { +func (f *NewReleaseForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { if req.Method == "GET" || errors.Count() == 0 { return } diff --git a/modules/auth/repo.go b/modules/auth/repo.go index f67fbf671..e61e8202f 100644 --- a/modules/auth/repo.go +++ b/modules/auth/repo.go @@ -12,6 +12,7 @@ import ( "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/middleware/binding" ) type CreateRepoForm struct { @@ -31,7 +32,7 @@ func (f *CreateRepoForm) Name(field string) string { return names[field] } -func (f *CreateRepoForm) Validate(errors *base.BindingErrors, req *http.Request, context martini.Context) { +func (f *CreateRepoForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { if req.Method == "GET" || errors.Count() == 0 { return } @@ -69,7 +70,7 @@ func (f *MigrateRepoForm) Name(field string) string { return names[field] } -func (f *MigrateRepoForm) Validate(errors *base.BindingErrors, req *http.Request, context martini.Context) { +func (f *MigrateRepoForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { if req.Method == "GET" || errors.Count() == 0 { return } diff --git a/modules/auth/setting.go b/modules/auth/setting.go index 7cee00dec..3316d7b9b 100644 --- a/modules/auth/setting.go +++ b/modules/auth/setting.go @@ -13,6 +13,7 @@ import ( "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/middleware/binding" ) type AddSSHKeyForm struct { @@ -28,7 +29,7 @@ func (f *AddSSHKeyForm) Name(field string) string { return names[field] } -func (f *AddSSHKeyForm) Validate(errors *base.BindingErrors, req *http.Request, context martini.Context) { +func (f *AddSSHKeyForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) AssignForm(f, data) diff --git a/modules/auth/user.go b/modules/auth/user.go index 8d60670db..0e591398c 100644 --- a/modules/auth/user.go +++ b/modules/auth/user.go @@ -15,6 +15,7 @@ import ( "github.com/gogits/gogs/models" "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/middleware/binding" ) // SignedInId returns the id of signed in user. @@ -93,7 +94,7 @@ func (f *UpdateProfileForm) Name(field string) string { return names[field] } -func (f *UpdateProfileForm) Validate(errors *base.BindingErrors, req *http.Request, context martini.Context) { +func (f *UpdateProfileForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { if req.Method == "GET" || errors.Count() == 0 { return } @@ -126,7 +127,7 @@ func (f *UpdatePasswdForm) Name(field string) string { return names[field] } -func (f *UpdatePasswdForm) Validate(errors *base.BindingErrors, req *http.Request, context martini.Context) { +func (f *UpdatePasswdForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { if req.Method == "GET" || errors.Count() == 0 { return } diff --git a/modules/base/base.go b/modules/base/base.go index e6befb83f..5536685a4 100644 --- a/modules/base/base.go +++ b/modules/base/base.go @@ -9,51 +9,4 @@ type ( TmplData map[string]interface{} ) -// __________.__ .___.__ -// \______ \__| ____ __| _/|__| ____ ____ -// | | _/ |/ \ / __ | | |/ \ / ___\ -// | | \ | | \/ /_/ | | | | \/ /_/ > -// |______ /__|___| /\____ | |__|___| /\___ / -// \/ \/ \/ \//_____/ - -// Errors represents the contract of the response body when the -// binding step fails before getting to the application. -type BindingErrors struct { - Overall map[string]string `json:"overall"` - Fields map[string]string `json:"fields"` -} - -// Total errors is the sum of errors with the request overall -// and errors on individual fields. -func (err BindingErrors) Count() int { - return len(err.Overall) + len(err.Fields) -} - -func (this *BindingErrors) Combine(other BindingErrors) { - for key, val := range other.Fields { - if _, exists := this.Fields[key]; !exists { - this.Fields[key] = val - } - } - for key, val := range other.Overall { - if _, exists := this.Overall[key]; !exists { - this.Overall[key] = val - } - } -} - -const ( - BindingRequireError string = "Required" - BindingAlphaDashError string = "AlphaDash" - BindingAlphaDashDotError string = "AlphaDashDot" - BindingMinSizeError string = "MinSize" - BindingMaxSizeError string = "MaxSize" - BindingEmailError string = "Email" - BindingUrlError string = "Url" - BindingDeserializationError string = "DeserializationError" - BindingIntegerTypeError string = "IntegerTypeError" - BindingBooleanTypeError string = "BooleanTypeError" - BindingFloatTypeError string = "FloatTypeError" -) - var GoGetMetas = make(map[string]bool) diff --git a/modules/middleware/binding.go b/modules/middleware/binding/binding.go similarity index 81% rename from modules/middleware/binding.go rename to modules/middleware/binding/binding.go index bff34ddde..6de595515 100644 --- a/modules/middleware/binding.go +++ b/modules/middleware/binding/binding.go @@ -3,7 +3,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package middleware +package binding import ( "encoding/json" @@ -17,8 +17,6 @@ import ( "unicode/utf8" "github.com/go-martini/martini" - - "github.com/gogits/gogs/modules/base" ) /* @@ -103,7 +101,7 @@ func Form(formStruct interface{}, ifacePtr ...interface{}) martini.Handler { // Because an empty request body or url can also mean absence of all needed values, // it is not in all cases a bad request, so let's return 422. if parseErr != nil { - errors.Overall[base.BindingDeserializationError] = parseErr.Error() + errors.Overall[BindingDeserializationError] = parseErr.Error() } mapForm(formStruct, req.Form, errors) @@ -123,12 +121,12 @@ func MultipartForm(formStruct interface{}, ifacePtr ...interface{}) martini.Hand // https://code.google.com/p/go/issues/detail?id=6334 multipartReader, err := req.MultipartReader() if err != nil { - errors.Overall[base.BindingDeserializationError] = err.Error() + errors.Overall[BindingDeserializationError] = err.Error() } else { form, parseErr := multipartReader.ReadForm(MaxMemory) if parseErr != nil { - errors.Overall[base.BindingDeserializationError] = parseErr.Error() + errors.Overall[BindingDeserializationError] = parseErr.Error() } req.MultipartForm = form @@ -156,7 +154,7 @@ func Json(jsonStruct interface{}, ifacePtr ...interface{}) martini.Handler { } if err := json.NewDecoder(req.Body).Decode(jsonStruct.Interface()); err != nil && err != io.EOF { - errors.Overall[base.BindingDeserializationError] = err.Error() + errors.Overall[BindingDeserializationError] = err.Error() } validateAndMap(jsonStruct, context, errors, ifacePtr...) @@ -186,7 +184,7 @@ var ( urlPattern = regexp.MustCompile(`(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?`) ) -func validateStruct(errors *base.BindingErrors, obj interface{}) { +func validateStruct(errors *BindingErrors, obj interface{}) { typ := reflect.TypeOf(obj) val := reflect.ValueOf(obj) @@ -220,17 +218,17 @@ func validateStruct(errors *base.BindingErrors, obj interface{}) { switch { case rule == "Required": if reflect.DeepEqual(zero, fieldValue) { - errors.Fields[field.Name] = base.BindingRequireError + errors.Fields[field.Name] = BindingRequireError break } case rule == "AlphaDash": if alphaDashPattern.MatchString(fmt.Sprintf("%v", fieldValue)) { - errors.Fields[field.Name] = base.BindingAlphaDashError + errors.Fields[field.Name] = BindingAlphaDashError break } case rule == "AlphaDashDot": if alphaDashDotPattern.MatchString(fmt.Sprintf("%v", fieldValue)) { - errors.Fields[field.Name] = base.BindingAlphaDashDotError + errors.Fields[field.Name] = BindingAlphaDashDotError break } case strings.HasPrefix(rule, "MinSize("): @@ -240,12 +238,12 @@ func validateStruct(errors *base.BindingErrors, obj interface{}) { break } if str, ok := fieldValue.(string); ok && utf8.RuneCountInString(str) < min { - errors.Fields[field.Name] = base.BindingMinSizeError + errors.Fields[field.Name] = BindingMinSizeError break } v := reflect.ValueOf(fieldValue) if v.Kind() == reflect.Slice && v.Len() < min { - errors.Fields[field.Name] = base.BindingMinSizeError + errors.Fields[field.Name] = BindingMinSizeError break } case strings.HasPrefix(rule, "MaxSize("): @@ -255,22 +253,22 @@ func validateStruct(errors *base.BindingErrors, obj interface{}) { break } if str, ok := fieldValue.(string); ok && utf8.RuneCountInString(str) > max { - errors.Fields[field.Name] = base.BindingMaxSizeError + errors.Fields[field.Name] = BindingMaxSizeError break } v := reflect.ValueOf(fieldValue) if v.Kind() == reflect.Slice && v.Len() > max { - errors.Fields[field.Name] = base.BindingMinSizeError + errors.Fields[field.Name] = BindingMinSizeError break } case rule == "Email": if !emailPattern.MatchString(fmt.Sprintf("%v", fieldValue)) { - errors.Fields[field.Name] = base.BindingEmailError + errors.Fields[field.Name] = BindingEmailError break } case rule == "Url": if !urlPattern.MatchString(fmt.Sprintf("%v", fieldValue)) { - errors.Fields[field.Name] = base.BindingUrlError + errors.Fields[field.Name] = BindingUrlError break } } @@ -278,7 +276,7 @@ func validateStruct(errors *base.BindingErrors, obj interface{}) { } } -func mapForm(formStruct reflect.Value, form map[string][]string, errors *base.BindingErrors) { +func mapForm(formStruct reflect.Value, form map[string][]string, errors *BindingErrors) { typ := formStruct.Elem().Type() for i := 0; i < typ.NumField(); i++ { @@ -319,10 +317,10 @@ func mapForm(formStruct reflect.Value, form map[string][]string, errors *base.Bi // This is a "default" handler, of sorts, and you are // welcome to use your own instead. The Bind middleware // invokes this automatically for convenience. -func ErrorHandler(errs base.BindingErrors, resp http.ResponseWriter) { +func ErrorHandler(errs BindingErrors, resp http.ResponseWriter) { if errs.Count() > 0 { resp.Header().Set("Content-Type", "application/json; charset=utf-8") - if _, ok := errs.Overall[base.BindingDeserializationError]; ok { + if _, ok := errs.Overall[BindingDeserializationError]; ok { resp.WriteHeader(http.StatusBadRequest) } else { resp.WriteHeader(422) @@ -337,7 +335,7 @@ func ErrorHandler(errs base.BindingErrors, resp http.ResponseWriter) { // matching value from the request (via Form middleware) in the // same type, so that not all deserialized values have to be strings. // Supported types are string, int, float, and bool. -func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value, nameInTag string, errors *base.BindingErrors) { +func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value, nameInTag string, errors *BindingErrors) { switch valueKind { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if val == "" { @@ -345,7 +343,7 @@ func setWithProperType(valueKind reflect.Kind, val string, structField reflect.V } intVal, err := strconv.ParseInt(val, 10, 64) if err != nil { - errors.Fields[nameInTag] = base.BindingIntegerTypeError + errors.Fields[nameInTag] = BindingIntegerTypeError } else { structField.SetInt(intVal) } @@ -355,7 +353,7 @@ func setWithProperType(valueKind reflect.Kind, val string, structField reflect.V } uintVal, err := strconv.ParseUint(val, 10, 64) if err != nil { - errors.Fields[nameInTag] = base.BindingIntegerTypeError + errors.Fields[nameInTag] = BindingIntegerTypeError } else { structField.SetUint(uintVal) } @@ -367,7 +365,7 @@ func setWithProperType(valueKind reflect.Kind, val string, structField reflect.V } floatVal, err := strconv.ParseFloat(val, 32) if err != nil { - errors.Fields[nameInTag] = base.BindingFloatTypeError + errors.Fields[nameInTag] = BindingFloatTypeError } else { structField.SetFloat(floatVal) } @@ -377,7 +375,7 @@ func setWithProperType(valueKind reflect.Kind, val string, structField reflect.V } floatVal, err := strconv.ParseFloat(val, 64) if err != nil { - errors.Fields[nameInTag] = base.BindingFloatTypeError + errors.Fields[nameInTag] = BindingFloatTypeError } else { structField.SetFloat(floatVal) } @@ -398,7 +396,7 @@ func ensureNotPointer(obj interface{}) { // Performs validation and combines errors from validation // with errors from deserialization, then maps both the // resulting struct and the errors to the context. -func validateAndMap(obj reflect.Value, context martini.Context, errors *base.BindingErrors, ifacePtr ...interface{}) { +func validateAndMap(obj reflect.Value, context martini.Context, errors *BindingErrors, ifacePtr ...interface{}) { context.Invoke(Validate(obj.Interface())) errors.Combine(getErrors(context)) context.Map(*errors) @@ -408,12 +406,12 @@ func validateAndMap(obj reflect.Value, context martini.Context, errors *base.Bin } } -func newErrors() *base.BindingErrors { - return &base.BindingErrors{make(map[string]string), make(map[string]string)} +func newErrors() *BindingErrors { + return &BindingErrors{make(map[string]string), make(map[string]string)} } -func getErrors(context martini.Context) base.BindingErrors { - return context.Get(reflect.TypeOf(base.BindingErrors{})).Interface().(base.BindingErrors) +func getErrors(context martini.Context) BindingErrors { + return context.Get(reflect.TypeOf(BindingErrors{})).Interface().(BindingErrors) } type ( @@ -421,7 +419,7 @@ type ( // validation before the request even gets to your application. // The Validate method will be executed during the validation phase. Validator interface { - Validate(*base.BindingErrors, *http.Request, martini.Context) + Validate(*BindingErrors, *http.Request, martini.Context) } ) @@ -430,3 +428,43 @@ var ( // Set this to whatever value you prefer; default is 10 MB. MaxMemory = int64(1024 * 1024 * 10) ) + +// Errors represents the contract of the response body when the +// binding step fails before getting to the application. +type BindingErrors struct { + Overall map[string]string `json:"overall"` + Fields map[string]string `json:"fields"` +} + +// Total errors is the sum of errors with the request overall +// and errors on individual fields. +func (err BindingErrors) Count() int { + return len(err.Overall) + len(err.Fields) +} + +func (this *BindingErrors) Combine(other BindingErrors) { + for key, val := range other.Fields { + if _, exists := this.Fields[key]; !exists { + this.Fields[key] = val + } + } + for key, val := range other.Overall { + if _, exists := this.Overall[key]; !exists { + this.Overall[key] = val + } + } +} + +const ( + BindingRequireError string = "Required" + BindingAlphaDashError string = "AlphaDash" + BindingAlphaDashDotError string = "AlphaDashDot" + BindingMinSizeError string = "MinSize" + BindingMaxSizeError string = "MaxSize" + BindingEmailError string = "Email" + BindingUrlError string = "Url" + BindingDeserializationError string = "DeserializationError" + BindingIntegerTypeError string = "IntegerTypeError" + BindingBooleanTypeError string = "BooleanTypeError" + BindingFloatTypeError string = "FloatTypeError" +) diff --git a/modules/middleware/binding_test.go b/modules/middleware/binding/binding_test.go similarity index 99% rename from modules/middleware/binding_test.go rename to modules/middleware/binding/binding_test.go index 2a74e1a6c..c39fbd2a5 100644 --- a/modules/middleware/binding_test.go +++ b/modules/middleware/binding/binding_test.go @@ -3,7 +3,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package middleware +package binding import ( "bytes" diff --git a/rpp.ini b/rpp.ini new file mode 100644 index 000000000..50d1e0c75 --- /dev/null +++ b/rpp.ini @@ -0,0 +1,6 @@ +[host] +LISTEN_ADDR = 127.0.0.1:5000 +REMOTE_ADDR = 127.0.0.1:5000 + +[rules] +IGNORES = .git|.DS_Store|*.tmp|data \ No newline at end of file