welcome: username error handling (#75)
* username error handling welcome ui
* added short username check with separate error handling function
* nothing happaned here
* added username error handling, form saves info
* pull75 fixes
* pull75 fixes ui
* CSS change
* separate css for errors, added logic for several type of errors
* rename extractErrorMessage
* validation changes
* added validations in api
* changed rendering template, recives errors in JSON format
* rolled back schema and makefile in kratos
* changes in HTML
* combined kratos and manual validations
* fixed rendering and handling JSON error response
* rollback unused index.html
* minor fixes
* refactored the repeated logic of Errors into a separate function
* rollback
* refactor: group errors and form data together
* rollback picocss version
* use picocss 2.0.6
---------
Co-authored-by: Giorgi Lekveishvili <lekva@gl-mbp-m1-max.local>
diff --git a/core/installer/welcome/welcome.go b/core/installer/welcome/welcome.go
index 60adf6b..4d30784 100644
--- a/core/installer/welcome/welcome.go
+++ b/core/installer/welcome/welcome.go
@@ -5,6 +5,7 @@
"embed"
"encoding/json"
"fmt"
+ "html/template"
"io"
"log"
"net/http"
@@ -51,11 +52,14 @@
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", s.port), nil))
}
-func (s *Server) createAdminAccountForm(w http.ResponseWriter, _ *http.Request) {
- if _, err := w.Write(indexHtml); err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
+func (s *Server) createAdminAccountForm(w http.ResponseWriter, r *http.Request) {
+ renderRegistrationForm(w, formData{})
+}
+
+type formData struct {
+ UsernameErrors []string
+ PasswordErrors []string
+ Data createAccountReq
}
type createAccountReq struct {
@@ -69,6 +73,15 @@
Password string `json:"password,omitempty"`
}
+type ValidationError struct {
+ Field string `json:"field"`
+ Message string `json:"message"`
+}
+
+type ErrorResponse struct {
+ Errors []ValidationError `json:"errors"`
+}
+
func getFormValue(v url.Values, name string) (string, error) {
items, ok := v[name]
if !ok || len(items) != 1 {
@@ -102,6 +115,18 @@
return req, nil
}
+func renderRegistrationForm(w http.ResponseWriter, data formData) {
+ tmpl, err := template.New("create-account").Parse(string(indexHtml))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ if err := tmpl.Execute(w, data); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
func (s *Server) createAdminAccount(w http.ResponseWriter, r *http.Request) {
req, err := extractReq(r)
if err != nil {
@@ -126,11 +151,26 @@
http.Error(w, respStr, http.StatusInternalServerError)
return
}
- // TODO(gio): better handle status code and error message
if resp.StatusCode != http.StatusOK {
- var e bytes.Buffer
- io.Copy(&e, resp.Body)
- http.Error(w, e.String(), http.StatusInternalServerError)
+ var errResponse ErrorResponse
+ if err := json.NewDecoder(resp.Body).Decode(&errResponse); err != nil {
+ http.Error(w, "Error Decoding JSON", http.StatusInternalServerError)
+ return
+ }
+ var usernameErrors, passwordErrors []string
+ for _, err := range errResponse.Errors {
+ if err.Field == "username" {
+ usernameErrors = append(usernameErrors, err.Message)
+ }
+ if err.Field == "password" {
+ passwordErrors = append(passwordErrors, err.Message)
+ }
+ }
+ renderRegistrationForm(w, formData{
+ usernameErrors,
+ passwordErrors,
+ req,
+ })
return
}
}