From 4df226809421a46e51010ba8560ecff3799cf922 Mon Sep 17 00:00:00 2001 From: akuma06 Date: Sun, 7 May 2017 19:59:38 +0200 Subject: [PATCH] Added Form Validation Display of error messages --- db/gorm.go | 20 +------- router/templateVariables.go | 1 + router/userHandler.go | 57 +++++++++++++-------- service/user/cookieHelper.go | 2 +- service/user/form/formValidator.go | 58 +++++++++++----------- templates/user/register.html | 20 +++++++- util/modelHelper/modelHelper.go | 79 +++++++++++++++++++++++++++++- 7 files changed, 167 insertions(+), 70 deletions(-) diff --git a/db/gorm.go b/db/gorm.go index cb38b775..bbef9270 100644 --- a/db/gorm.go +++ b/db/gorm.go @@ -31,28 +31,12 @@ func GormInit(conf *config.Config) (*gorm.DB, error) { if config.Environment == "DEVELOPMENT" { db.LogMode(true) // db.DropTable(&model.User{}, "UserFollower") - db.AutoMigrate(&model.Torrents{}) - // db.AutoMigrate(&model.User{}, &model.Role{}, &model.Connection{}, &model.Language{}, &model.Article{}, &model.Location{}, &model.Comment{}, &model.File{}) + db.AutoMigrate(&model.Torrents{}, &model.User{}, &model.Role{}, &model.Connection{}, &model.Language{}) + // db.AutoMigrate(&model.Article{}, &model.Location{}, &model.Comment{}, &model.File{}) // db.Model(&model.User{}).AddIndex("idx_user_token", "token") } log.CheckError(err) - // relation := gorm.Relationship{} - // relation.Kind = "many2many" - // relation.ForeignFieldNames = []string{"id"} //(M1 pkey) - // relation.ForeignDBNames = []string{"user_id"} //(M1 fkey in m1m2join) - // relation.AssociationForeignFieldNames = []string{"id"} //(M2 pkey) - // // relation.AssociationForeignStructFieldNames = []string{"id", "ID"} //(m2 pkey name in m2 struct?) - // relation.AssociationForeignDBNames = []string{"follower_id"} //(m2 fkey in m1m2join) - // m1Type := reflect.TypeOf(model.User{}) - // m2Type := reflect.TypeOf(model.User{}) - // handler := gorm.JoinTableHandler{} - // // ORDER BELOW MATTERS - // // Install handler - // db.SetJoinTableHandler(&model.User{}, "Likings", &handler) - // // Configure handler to use the relation that we've defined - // handler.Setup(&relation, "users_followers", m1Type, m2Type) - return db, err } diff --git a/router/templateVariables.go b/router/templateVariables.go index 44be10e5..84a00deb 100644 --- a/router/templateVariables.go +++ b/router/templateVariables.go @@ -38,6 +38,7 @@ type ViewTemplateVariables struct { type UserRegisterTemplateVariables struct { RegistrationForm userForms.RegistrationForm + FormErrors map[string][]string Search SearchForm Navigation Navigation URL *url.URL // For parsing Url in templates diff --git a/router/userHandler.go b/router/userHandler.go index 61f3df95..bd4411f8 100644 --- a/router/userHandler.go +++ b/router/userHandler.go @@ -7,6 +7,7 @@ import ( "github.com/ewhal/nyaa/service/user" "github.com/ewhal/nyaa/service/user/form" "github.com/ewhal/nyaa/util/languages" + "github.com/ewhal/nyaa/util/log" "github.com/ewhal/nyaa/util/modelHelper" "github.com/gorilla/mux" ) @@ -20,7 +21,7 @@ func UserRegisterFormHandler(w http.ResponseWriter, r *http.Request) { modelHelper.BindValueForm(&b, r) b.CaptchaID = captcha.GetID() languages.SetTranslation("en-us", viewRegisterTemplate) - htv := UserRegisterTemplateVariables{b, NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)} + htv := UserRegisterTemplateVariables{b, form.NewErrors(), NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)} err := viewRegisterTemplate.ExecuteTemplate(w, "index.html", htv) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -52,29 +53,43 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) { // Post Registration controller, we do some check on the form here, the rest on user service func UserRegisterPostHandler(w http.ResponseWriter, r *http.Request) { // Check same Password + b := form.RegistrationForm{} + err := form.NewErrors() if !captcha.Authenticate(captcha.Extract(r)) { - // TODO: Prettier passing of mistyoed captcha errors - http.Error(w, captcha.ErrInvalidCaptcha.Error(), 403) - return + err["errors"] = append(err["errors"], "Wrong captcha!") } - if (r.PostFormValue("password") == r.PostFormValue("password_confirm")) && (r.PostFormValue("password") != "") { - if (form.EmailValidation(r.PostFormValue("email"))) && (form.ValidateUsername(r.PostFormValue("username"))) { - _, err := userService.CreateUser(w, r) - if err == nil { - b := form.RegistrationForm{} - htv := UserRegisterTemplateVariables{b, NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)} - err = viewRegisterSuccessTemplate.ExecuteTemplate(w, "index.html", htv) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } - } else { - UserRegisterFormHandler(w, r) - } - } else { - UserRegisterFormHandler(w, r) + if (len(err) == 0) { + _, err = form.EmailValidation(r.PostFormValue("email"), err) + _, err = form.ValidateUsername(r.PostFormValue("username"), err) + log.Info("test lets see 3") + if (len(err) == 0) { + modelHelper.BindValueForm(&b, r) + err = modelHelper.ValidateForm(&b, err) + log.Info("test lets see 1") + if (len(err) == 0) { + _, errorUser := userService.CreateUser(w, r) + err["errors"] = append(err["errors"], errorUser.Error()) + log.Info("test lets see 2") + if (len(err) == 0) { + b := form.RegistrationForm{} + htv := UserRegisterTemplateVariables{b, err, NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)} + errorTmpl := viewRegisterSuccessTemplate.ExecuteTemplate(w, "index.html", htv) + if errorTmpl != nil { + http.Error(w, errorTmpl.Error(), http.StatusInternalServerError) + } + } + } + } + } + if (len(err) > 0) { + log.Info("test lets see 4") + b.CaptchaID = captcha.GetID() + languages.SetTranslation("en-us", viewRegisterTemplate) + htv := UserRegisterTemplateVariables{b, err, NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)} + errorTmpl := viewRegisterTemplate.ExecuteTemplate(w, "index.html", htv) + if errorTmpl != nil { + http.Error(w, errorTmpl.Error(), http.StatusInternalServerError) } - } else { - UserRegisterFormHandler(w, r) } } diff --git a/service/user/cookieHelper.go b/service/user/cookieHelper.go index 9ec85646..0974fc83 100644 --- a/service/user/cookieHelper.go +++ b/service/user/cookieHelper.go @@ -89,7 +89,7 @@ func SetCookieHandler(w http.ResponseWriter, email string, pass string) (int, er if email != "" && pass != "" { log.Debugf("User email : %s , password : %s", email, pass) var user model.User - isValidEmail := formStruct.EmailValidation(email) + isValidEmail, _ := formStruct.EmailValidation(email, formStruct.NewErrors()) if isValidEmail { log.Debug("User entered valid email.") if db.ORM.Where("email = ?", email).First(&user).RecordNotFound() { diff --git a/service/user/form/formValidator.go b/service/user/form/formValidator.go index 17ff512d..13430cfd 100644 --- a/service/user/form/formValidator.go +++ b/service/user/form/formValidator.go @@ -9,42 +9,44 @@ import ( const EMAIL_REGEX = `(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})` const USERNAME_REGEX = `(\W)` -func EmailValidation(email string) bool { - exp, err := regexp.Compile(EMAIL_REGEX) - if regexpCompiled := log.CheckError(err); regexpCompiled { +func EmailValidation(email string, err map[string][]string) (bool, map[string][]string) { + exp, errorRegex := regexp.Compile(EMAIL_REGEX) + if regexpCompiled := log.CheckError(errorRegex); regexpCompiled { if exp.MatchString(email) { - return true - } - } - return false -} -func ValidateUsername(username string) bool { - exp, err := regexp.Compile(USERNAME_REGEX) - - if username == "" { - return false - - } - if (len(username) < 3) || (len(username) > 15) { - return false - - } - if regexpCompiled := log.CheckError(err); regexpCompiled { - if exp.MatchString(username) { - return false + err["email"] = append(err["email"], "Email Address is not valid") + return true, err } } else { - return false + return false, err } - return true + return false, err +} +func ValidateUsername(username string, err map[string][]string) (bool, map[string][]string) { + exp, errorRegex := regexp.Compile(USERNAME_REGEX) + if regexpCompiled := log.CheckError(errorRegex); regexpCompiled { + if exp.MatchString(username) { + err["username"] = append(err["username"], "Username contains illegal characters") + return false, err + } + } else { + return false, err + } + return true, err +} + +func NewErrors() map[string][]string { + err := make(map[string][]string) + return err } // RegistrationForm is used when creating a user. type RegistrationForm struct { - Username string `form:"registrationUsername"` - Email string `form:"registrationEmail"` - Password string `form:"registrationPassword"` - CaptchaID string `form:"captchaID" inmodel:"false"` + Username string `form:"username" needed:"true" min_len:"3" max_len:"20"` + Email string `form:"email" needed:"true"` + Password string `form:"password" needed:"true" min_len:"6" max_len:"25"` + Confirm_Password string `form:"password_confirmation" omit:"true" needed:"true"` + CaptchaID string `form:"captchaID" omit:"true" needed:"true"` + T_and_C bool `form:"t_and_c" omit:"true" needed:"true" equal:"true" hum_name:"Terms and Conditions"` } // RegistrationForm is used when creating a user authentication. diff --git a/templates/user/register.html b/templates/user/register.html index 94870df7..e0005708 100644 --- a/templates/user/register.html +++ b/templates/user/register.html @@ -8,21 +8,36 @@

{{T "signup_box_title" }}


+ {{ range (index $.FormErrors "errors")}} +
{{ . }}
+ {{end}}
+ {{ range (index $.FormErrors "username")}} +

{{ . }}

+ {{end}}
+ {{ range (index $.FormErrors "email")}} +

{{ . }}

+ {{end}}
-
+ {{ range (index $.FormErrors "password")}} +

{{ . }}

+ {{end}} +
+ {{ range (index $.FormErrors "password_confirmation")}} +

{{ . }}

+ {{end}}
@@ -31,6 +46,9 @@ + {{ range (index $.FormErrors "t_and_c")}} +

{{ . }}

+ {{end}}
diff --git a/util/modelHelper/modelHelper.go b/util/modelHelper/modelHelper.go index 776c89cc..72a98522 100644 --- a/util/modelHelper/modelHelper.go +++ b/util/modelHelper/modelHelper.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/ewhal/nyaa/util/log" "strconv" + "fmt" ) func IsZeroOfUnderlyingType(x interface{}) bool { @@ -18,7 +19,7 @@ func AssignValue(model interface{}, form interface{}) { typeOfTForm := formElem.Type() for i := 0; i < formElem.NumField(); i++ { tag := typeOfTForm.Field(i).Tag - if tag.Get("omit") != "false" { + if tag.Get("omit") != "true" { modelField := modelIndirect.FieldByName(typeOfTForm.Field(i).Name) if modelField.IsValid() { formField := formElem.Field(i) @@ -46,6 +47,82 @@ func BindValueForm(form interface{}, r *http.Request) { case "float" : nbr, _ := strconv.Atoi(r.PostFormValue(tag.Get("form"))) formElem.Field(i).SetFloat(float64(nbr)) + case "bool" : + nbr, _ := strconv.ParseBool(r.PostFormValue(tag.Get("form"))) + formElem.Field(i).SetBool(nbr) } } } + + + +func ValidateForm(form interface{}, errorForm map[string][]string) (map[string][]string) { + formElem := reflect.ValueOf(form).Elem() + for i := 0; i < formElem.NumField(); i++ { + typeField := formElem.Type().Field(i) + tag := typeField.Tag + inputName := typeField.Name + if (tag.Get("hum_name") != "") { // For more human input name than gibberish + inputName = tag.Get("hum_name") + } + if tag.Get("len_min") != "" { // Check minimum length + lenMin, _ := strconv.Atoi(tag.Get("len_min")) + if formElem.Field(i).Len() < lenMin { + errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Minimal length of %s required for the input: %s", lenMin, inputName)) + } + } + if tag.Get("len_max") != "" { // Check minimum length + lenMax, _ := strconv.Atoi(tag.Get("len_max")) + if formElem.Field(i).Len() > lenMax { + errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Maximal length of %s required for the input: %s", lenMax, inputName)) + } + } + if tag.Get("equalInput") != "" { + otherInput := formElem.FieldByName(tag.Get("equalForm")) + if formElem.Field(i).Interface() != otherInput.Interface() { + errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName)) + } + } + switch typeField.Type.Name() { + case "string" : + if tag.Get("equal") != "" && formElem.Field(i).String() != tag.Get("equal") { + errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName)) + } + if tag.Get("needed") != "" && formElem.Field(i).String() == "" { + errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName)) + } + case "int" : + if tag.Get("equal") != "" { // Check minimum length + equal, _ := strconv.Atoi(tag.Get("equal")) + if formElem.Field(i).Int() > int64(equal) { + errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName)) + } + if tag.Get("needed") != "" && formElem.Field(i).Int() == 0 { + errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName)) + } + } + case "float" : + if tag.Get("equal") != "" { // Check minimum length + equal, _ := strconv.Atoi(tag.Get("equal")) + if formElem.Field(i).Float() != float64(equal) { + errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName)) + } + if tag.Get("needed") != "" && formElem.Field(i).Float() == 0 { + errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName)) + } + } + case "bool" : + if tag.Get("equal") != "" { // Check minimum length + equal, _ := strconv.ParseBool(tag.Get("equal")) + if formElem.Field(i).Bool() != equal { + errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName)) + } + } + } + } + + if (len(errorForm) == 0) { // If no error, return nil + return nil + } + return errorForm +} \ No newline at end of file