111 lines
3.2 KiB
Go
111 lines
3.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgconn"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
|
|
"wherewoof/frontend/internal/auth"
|
|
"wherewoof/frontend/internal/db"
|
|
)
|
|
|
|
func (a *App) RegisterPage(w http.ResponseWriter, r *http.Request) {
|
|
a.render(w, r, "register", "Create account", nil, "")
|
|
}
|
|
|
|
func (a *App) Register(w http.ResponseWriter, r *http.Request) {
|
|
email := strings.ToLower(strings.TrimSpace(r.FormValue("email")))
|
|
password := r.FormValue("password")
|
|
name := strings.TrimSpace(r.FormValue("name"))
|
|
|
|
if email == "" || password == "" {
|
|
a.render(w, r, "register", "Create account", nil, "Email and password are required.")
|
|
return
|
|
}
|
|
if confirm := strings.ToLower(strings.TrimSpace(r.FormValue("confirm_email"))); confirm != "" && confirm != email {
|
|
a.render(w, r, "register", "Create account", nil, "Emails do not match.")
|
|
return
|
|
}
|
|
if len(password) < 8 {
|
|
a.render(w, r, "register", "Create account", nil, "Password must be at least 8 characters.")
|
|
return
|
|
}
|
|
if len([]byte(password)) > 72 {
|
|
a.render(w, r, "register", "Create account", nil, "Password must be 72 bytes or fewer.")
|
|
return
|
|
}
|
|
|
|
hash, err := auth.HashPassword(password)
|
|
if err != nil {
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
user, err := a.Queries.CreateUser(r.Context(), db.CreateUserParams{
|
|
Email: email,
|
|
PasswordHash: hash,
|
|
Name: pgtype.Text{String: name, Valid: name != ""},
|
|
})
|
|
if err != nil {
|
|
var pgErr *pgconn.PgError
|
|
if errors.As(err, &pgErr) && pgErr.Code == "23505" {
|
|
a.render(w, r, "register", "Create account", nil, "That email is already registered.")
|
|
return
|
|
}
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err := auth.SetUserID(w, r, user.ID); err != nil {
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
next := r.FormValue("next")
|
|
if next == "" || !strings.HasPrefix(next, "/") || strings.HasPrefix(next, "//") {
|
|
next = "/account"
|
|
}
|
|
http.Redirect(w, r, next, http.StatusSeeOther)
|
|
}
|
|
|
|
func (a *App) LoginPage(w http.ResponseWriter, r *http.Request) {
|
|
a.render(w, r, "login", "Log in", nil, "")
|
|
}
|
|
|
|
func (a *App) Login(w http.ResponseWriter, r *http.Request) {
|
|
email := strings.ToLower(strings.TrimSpace(r.FormValue("email")))
|
|
password := r.FormValue("password")
|
|
|
|
user, err := a.Queries.GetUserByEmail(r.Context(), email)
|
|
if err != nil {
|
|
if !errors.Is(err, pgx.ErrNoRows) {
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
a.render(w, r, "login", "Log in", nil, "Invalid email or password.")
|
|
return
|
|
}
|
|
if !auth.CheckPassword(user.PasswordHash, password) {
|
|
a.render(w, r, "login", "Log in", nil, "Invalid email or password.")
|
|
return
|
|
}
|
|
|
|
if err := auth.SetUserID(w, r, user.ID); err != nil {
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
next := r.FormValue("next")
|
|
if next == "" || !strings.HasPrefix(next, "/") || strings.HasPrefix(next, "//") {
|
|
next = "/account"
|
|
}
|
|
http.Redirect(w, r, next, http.StatusSeeOther)
|
|
}
|
|
|
|
func (a *App) Logout(w http.ResponseWriter, r *http.Request) {
|
|
_ = auth.Clear(w, r)
|
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
|
}
|