mirror of
https://github.com/acaloiaro/garbagespeak.com
synced 2026-07-21 18:29:08 +00:00
User creation validation
This commit is contained in:
parent
afc096d1d1
commit
e768c99db0
9 changed files with 198 additions and 47 deletions
|
|
@ -6,21 +6,50 @@ title: Create Account
|
|||
<div class="auth-wrapper">
|
||||
<div class="auth-form">
|
||||
<form hx-post="{{ .Site.Params.apiBaseUrl }}/users/create">
|
||||
<label for="username">Username</label>
|
||||
<input id="username" type="text" name="username" placeholder="desired username"/>
|
||||
<div hx-target="this" hx-swap="innerHTML">
|
||||
<label for="username">Username</label>
|
||||
<input id="username"
|
||||
type="text"
|
||||
name="username"
|
||||
placeholder="desired username"
|
||||
hx-post="{{ .Site.Params.apiBaseUrl }}/users/new_user_validation"
|
||||
hx-indicator="#username-ind">
|
||||
<img id="username-ind" src="/img/bars.svg" class="htmx-indicator"/>
|
||||
|
||||
<label for="email">Email (we do not spam or sell information)</label>
|
||||
<input id="email" type="email" name="email" placeholder="thot_ldr@email.com">
|
||||
<label for="email">Email (we do not spam or sell information)</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="thot_ldr@email.com"
|
||||
hx-post="{{ .Site.Params.apiBaseUrl }}/users/new_user_validation"
|
||||
hx-indicator="#email-ind">
|
||||
<img id="email-ind" src="/img/bars.svg" class="htmx-indicator"/>
|
||||
|
||||
<label for="password">Password</label>
|
||||
<input id="password type="password" name="password" placeholder="desired password">
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
id="password
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="desired password"
|
||||
hx-post="{{ .Site.Params.apiBaseUrl }}/users/new_user_validation"
|
||||
hx-indicator="#password-ind">
|
||||
<img id="password-ind" src="/img/bars.svg" class="htmx-indicator"/>
|
||||
|
||||
<label for="password_confirmation">Password Confirmation</label>
|
||||
<input id="password_confirmation" type="text" name="password_confirmation" placeholder="desired password again">
|
||||
<br>
|
||||
<br>
|
||||
<button class="btn btn-success">Create Account</button>
|
||||
<label for="password_confirmation">Password Confirmation</label>
|
||||
<input
|
||||
id="password_confirmation"
|
||||
type="text"
|
||||
name="password_confirmation"
|
||||
placeholder="desired password again"
|
||||
hx-post="{{ .Site.Params.apiBaseUrl }}/users/new_user_validation"
|
||||
hx-indicator="#password-conf-ind">
|
||||
<img id="password-conf-ind" src="/img/bars.svg" class="htmx-indicator"/>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<button disabled>Create Account</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,17 +5,17 @@ title: Log in
|
|||
<div class="auth-wrapper">
|
||||
<div class="auth-form">
|
||||
<form hx-post="{{ .Site.Params.apiBaseUrl }}/users/login">
|
||||
<div hx-target="this" hx-swap="outerHTML">
|
||||
<div hx-target="this" hx-swap="innerHTML">
|
||||
<label for="username">Username</label>
|
||||
<input id="username" type="text" name="username" placeholder="desired username" hx-post="{{ .Site.Params.apiBaseUrl }}/users/login">
|
||||
<img id="ind" src="/img/bars.svg" class="htmx-indicator"/>
|
||||
<label for="password">Password</label>
|
||||
<input id="password" type="password" name="password" placeholder="desired password">
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<button class="btn btn-success">Log In</button>
|
||||
</div>
|
||||
|
||||
<label for="password">Password</label>
|
||||
<input id="password" type="password" name="password" placeholder="desired password">
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<button class="btn btn-success">Log In</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
8
go.mod
8
go.mod
|
|
@ -2,13 +2,13 @@ module github.com/acaloiaro/garbage_speak
|
|||
|
||||
go 1.20
|
||||
|
||||
replace github.com/acaloiaro/neoq v0.17.0 => /home/adriano/git/neoq
|
||||
|
||||
require (
|
||||
github.com/acaloiaro/neoq v0.17.0
|
||||
github.com/acaloiaro/neoq v0.18.0
|
||||
github.com/alexedwards/scs/pgxstore v0.0.0-20230327161757-10d4299e3b24
|
||||
github.com/alexedwards/scs/v2 v2.5.1
|
||||
github.com/georgysavva/scany/v2 v2.0.0
|
||||
github.com/go-chi/chi/v5 v5.0.10
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/gofrs/uuid v4.4.0+incompatible
|
||||
github.com/golang-migrate/migrate/v4 v4.16.2
|
||||
github.com/jackc/pgx-gofrs-uuid v0.0.0-20230224015001-1d428863c2e2
|
||||
|
|
@ -17,8 +17,6 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/go-chi/chi/v5 v5.0.10 // indirect
|
||||
github.com/go-chi/cors v1.2.1 // indirect
|
||||
github.com/gofrs/uuid/v5 v5.0.0 // indirect
|
||||
github.com/guregu/null v4.0.0+incompatible // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -1,6 +1,8 @@
|
|||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/acaloiaro/neoq v0.18.0 h1:WKTDNEL/sH5hlwd/7Kgbqb4kKdvNVdzNNjfKRtt3v5k=
|
||||
github.com/acaloiaro/neoq v0.18.0/go.mod h1:uLI2JfC2V9p+H5lx5s0SUsjxIYLm8JDhi6VkyURMvLM=
|
||||
github.com/alexedwards/scs/pgxstore v0.0.0-20230327161757-10d4299e3b24 h1:l8+ZTNz/s7fbpTz/oeUmXCL39Rn49SRaXnj2/LZzCos=
|
||||
github.com/alexedwards/scs/pgxstore v0.0.0-20230327161757-10d4299e3b24/go.mod h1:KTB1slYgIU/BBa4MWA5IdET31OsbPQBM7dqDw5klIt4=
|
||||
github.com/alexedwards/scs/v2 v2.5.1 h1:EhAz3Kb3OSQzD8T+Ub23fKsiuvE0GzbF5Lgn0uTwM3Y=
|
||||
|
|
|
|||
|
|
@ -1,24 +1,5 @@
|
|||
<style>
|
||||
.auth-wrapper{
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.auth-wrapper .sign-form{
|
||||
max-width: 350px;
|
||||
width: 100%;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.auth-wrapper h1{margin-bottom: 20px;}
|
||||
</style>
|
||||
|
||||
<div class="auth-wrapper">
|
||||
<div class="sign-form">
|
||||
<h1>Sign In</h1>
|
||||
|
||||
<form action="/users/login" method="POST" hx-target=".auth-wrapper">
|
||||
<input type="text" name="username">
|
||||
<input type="text" name="password">
|
||||
|
|
|
|||
60
partials/users/new_user_validation.html
Normal file
60
partials/users/new_user_validation.html
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<label for="username">Username</label>
|
||||
<input
|
||||
id="username"
|
||||
type="text"
|
||||
name="username"
|
||||
placeholder="desired username"
|
||||
value="{{ .Username }}"
|
||||
hx-post="{{ .ApiBaseUrl }}/users/new_user_validation"
|
||||
hx-indicator="#username-ind">
|
||||
<img id="username-ind" src="/img/bars.svg" class="htmx-indicator"/>
|
||||
{{ with .UsernameError }}
|
||||
<div class="error-message">{{ . }}</div>
|
||||
{{ end }}
|
||||
|
||||
<label for="email">Email (we do not spam or sell information)</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="your email address"
|
||||
value="{{ .Email }}"
|
||||
hx-post="{{ .ApiBaseUrl }}/users/new_user_validation"
|
||||
hx-indicator="#email-ind">
|
||||
<img id="email-ind" src="/img/bars.svg" class="htmx-indicator"/>
|
||||
{{ with .EmailError }}
|
||||
<div class="error-message">{{ . }}</div>
|
||||
{{ end }}
|
||||
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="desired password"
|
||||
value="{{ .Password }}"
|
||||
hx-post="{{ .ApiBaseUrl }}/users/new_user_validation"
|
||||
hx-indicator="#password-ind">
|
||||
<img id="password-ind" src="/img/bars.svg" class="htmx-indicator"/>
|
||||
{{ with .PasswordError }}
|
||||
<div class="error-message">{{ . }}</div>
|
||||
{{ end }}
|
||||
|
||||
<label for="password_confirmation">Password Confirmation</label>
|
||||
<input
|
||||
id="password_confirmation"
|
||||
type="password"
|
||||
name="password_confirmation"
|
||||
placeholder="desired password"
|
||||
value="{{ .PasswordConfirmation }}"
|
||||
hx-post="{{ .ApiBaseUrl }}/users/new_user_validation"
|
||||
hx-indicator="#password-conf-ind">
|
||||
<img id="password-conf-ind" src="/img/bars.svg" class="htmx-indicator"/>
|
||||
{{ with .PasswordConfirmationError }}
|
||||
<div class="error-message">{{ . }}</div>
|
||||
{{ end }}
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<button {{ if gt .ErrorCount 0 }}disabled=true{{end}}>Create Account</button>
|
||||
|
||||
67
server.go
67
server.go
|
|
@ -162,6 +162,7 @@ func main() {
|
|||
r.Get("/garbage_bin", garbageBin)
|
||||
r.Get("/nav/user_items", navUserItems)
|
||||
r.Route("/users", func(r chi.Router) {
|
||||
r.Post("/new_user_validation", newUserValidationHandler)
|
||||
r.Get("/create", newAccountHandler)
|
||||
r.Post("/login", loginHandler)
|
||||
r.Post("/create", createAccount)
|
||||
|
|
@ -175,8 +176,72 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
// loginHandler renders the login page
|
||||
// newUserValidationHandler checks whether a username is available during account creation
|
||||
func newUserValidationHandler(w http.ResponseWriter, r *http.Request) {
|
||||
tmplVars := map[string]any{"ApiBaseUrl": apiURL()}
|
||||
tmpl := template.Must(template.ParseFiles("partials/users/new_user_validation.html"))
|
||||
errCnt := 0
|
||||
|
||||
if err := r.ParseForm(); err != nil {
|
||||
ise(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
username := r.PostForm.Get("username")
|
||||
email := r.PostForm.Get("email")
|
||||
password := r.PostForm.Get("password")
|
||||
passwordConfirmation := r.PostForm.Get("password_confirmation")
|
||||
|
||||
tmplVars["Username"] = username
|
||||
tmplVars["Email"] = email
|
||||
tmplVars["Password"] = password
|
||||
tmplVars["PasswordConfirmation"] = passwordConfirmation
|
||||
|
||||
log.Println("vars", tmplVars)
|
||||
|
||||
if len(username) == 0 {
|
||||
tmplVars["UsernameError"] = "Please choose a username"
|
||||
errCnt += 1
|
||||
} else if len(username) > 0 {
|
||||
var userID string
|
||||
db.QueryRow(r.Context(), "SELECT id FROM users WHERE username = $1", username).Scan(&userID)
|
||||
if userID != "" {
|
||||
tmplVars["UsernameError"] = fmt.Sprintf("Username '%s' is unavailable. Choose a different username.", username)
|
||||
errCnt += 1
|
||||
}
|
||||
}
|
||||
|
||||
if (len(email) > 0 && len(email) < 4) || (len(email) >= 4 && !strings.Contains(email, "@")) {
|
||||
tmplVars["EmailError"] = "Please enter a valid email address."
|
||||
errCnt += 1
|
||||
}
|
||||
|
||||
if len(password) > 0 && len(password) < 8 {
|
||||
tmplVars["PasswordError"] = "Please choose a password greater than 8 characters"
|
||||
errCnt += 1
|
||||
}
|
||||
|
||||
if len(password) > 0 && len(passwordConfirmation) > 0 && password != passwordConfirmation {
|
||||
tmplVars["PasswordConfirmationError"] = "Passwords do not match"
|
||||
errCnt += 1
|
||||
}
|
||||
|
||||
tmplVars["ErrorCount"] = errCnt
|
||||
|
||||
var buff = bytes.NewBufferString("")
|
||||
err := tmpl.Execute(buff, tmplVars)
|
||||
if err != nil {
|
||||
ise(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("respones", buff.String())
|
||||
w.Header().Add("Content-Type", "text/html")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(buff.Bytes())
|
||||
}
|
||||
|
||||
// loginHandler renders the login page
|
||||
func loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
ise(err, w)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ input {
|
|||
}
|
||||
}
|
||||
|
||||
.auth-wrapper{
|
||||
.auth-wrapper {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -50,9 +50,7 @@ input {
|
|||
}
|
||||
|
||||
.auth-wrapper .auth-form {
|
||||
max-width: 450px;
|
||||
width: 100%;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.auth-wrapper h1{margin-bottom: 20px;}
|
||||
|
|
@ -62,3 +60,17 @@ label {
|
|||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.htmx-indicator {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button:disabled,
|
||||
button[disabled]{
|
||||
border: 1px solid #999999;
|
||||
background-color: #cccccc;
|
||||
color: #666666;
|
||||
}
|
||||
|
|
|
|||
4
themes/terminal/layouts/shortcodes/include.html
Normal file
4
themes/terminal/layouts/shortcodes/include.html
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{{ $file := .Get 0 }}
|
||||
{{ $file | readFile | safeHTML }}
|
||||
|
||||
|
||||
Loading…
Reference in a new issue