Add account settings page to change passwords

This commit is contained in:
Noah 2017-12-23 19:15:50 -08:00
parent 00925bb267
commit 419ae157cc
5 changed files with 192 additions and 3 deletions

View File

@ -82,8 +82,7 @@ func New(documentRoot, userRoot string) *Blog {
// Initialize the router. // Initialize the router.
r := mux.NewRouter() r := mux.NewRouter()
r.HandleFunc("/initial-setup", blog.SetupHandler) r.HandleFunc("/initial-setup", blog.SetupHandler)
r.HandleFunc("/login", blog.LoginHandler) blog.AuthRoutes(r)
r.HandleFunc("/logout", blog.LogoutHandler)
blog.AdminRoutes(r) blog.AdminRoutes(r)
blog.ContactRoutes(r) blog.ContactRoutes(r)
blog.BlogRoutes(r) blog.BlogRoutes(r)

View File

@ -4,10 +4,18 @@ import (
"errors" "errors"
"net/http" "net/http"
"github.com/gorilla/mux"
"github.com/kirsle/blog/core/forms" "github.com/kirsle/blog/core/forms"
"github.com/kirsle/blog/core/models/users" "github.com/kirsle/blog/core/models/users"
) )
// AuthRoutes attaches the auth routes to the app.
func (b *Blog) AuthRoutes(r *mux.Router) {
r.HandleFunc("/login", b.LoginHandler)
r.HandleFunc("/logout", b.LogoutHandler)
r.HandleFunc("/account", b.AccountHandler)
}
// Login logs the browser in as the given user. // Login logs the browser in as the given user.
func (b *Blog) Login(w http.ResponseWriter, r *http.Request, u *users.User) error { func (b *Blog) Login(w http.ResponseWriter, r *http.Request, u *users.User) error {
session, err := b.store.Get(r, "session") // TODO session name session, err := b.store.Get(r, "session") // TODO session name
@ -75,3 +83,84 @@ func (b *Blog) LogoutHandler(w http.ResponseWriter, r *http.Request) {
session.Save(r, w) session.Save(r, w)
b.Redirect(w, "/") b.Redirect(w, "/")
} }
// AccountHandler shows the account settings page.
func (b *Blog) AccountHandler(w http.ResponseWriter, r *http.Request) {
if !b.LoggedIn(r) {
b.FlashAndRedirect(w, r, "/login?next=/account", "You must be logged in to do that!")
return
}
currentUser, err := b.CurrentUser(r)
if err != nil {
b.FlashAndRedirect(w, r, "/login?next=/account", "You must be logged in to do that!!")
return
}
// Load an editable copy of the user.
user, err := users.Load(currentUser.ID)
if err != nil {
b.FlashAndRedirect(w, r, "/login?next=/account", "User ID %d not loadable?", currentUser.ID)
return
}
v := NewVars()
form := &forms.Account{
Username: user.Username,
Email: user.Email,
Name: user.Name,
}
v.Form = form
if r.Method == http.MethodPost {
form.Username = users.Normalize(r.FormValue("username"))
form.Email = r.FormValue("email")
form.Name = r.FormValue("name")
form.OldPassword = r.FormValue("oldpassword")
form.NewPassword = r.FormValue("newpassword")
form.NewPassword2 = r.FormValue("newpassword2")
if err = form.Validate(); err != nil {
b.Flash(w, r, err.Error())
} else {
var ok = true
// Validate the username is available.
if form.Username != user.Username {
if _, err = users.LoadUsername(form.Username); err == nil {
b.Flash(w, r, "That username already exists.")
ok = false
}
}
// Changing their password?
if len(form.OldPassword) > 0 {
// Validate their old password.
if _, err = users.CheckAuth(form.Username, form.OldPassword); err != nil {
b.Flash(w, r, "Your old password is incorrect.")
ok = false
} else {
err = user.SetPassword(form.NewPassword)
if err != nil {
b.Flash(w, r, "Change password error: %s", err)
ok = false
}
}
}
// Still good?
if ok {
user.Username = form.Username
user.Name = form.Name
user.Email = form.Email
err = user.Save()
if err != nil {
b.Flash(w, r, "Error saving user: %s", err)
} else {
b.FlashAndRedirect(w, r, "/account", "Settings saved!")
return
}
}
}
}
b.RenderTemplate(w, r, "account", v)
}

View File

@ -19,3 +19,29 @@ func (f Login) Validate() error {
} }
return nil return nil
} }
// Account is for updating account settings.
type Account struct {
Username string
OldPassword string
NewPassword string
NewPassword2 string
Email string
Name string
}
// Validate the account form.
func (f Account) Validate() error {
if len(f.Username) == 0 {
return errors.New("username is required")
}
if len(f.OldPassword) > 0 && len(f.NewPassword) > 0 {
if f.NewPassword != f.NewPassword2 {
return errors.New("your passwords don't match")
}
}
if len(f.Name) == 0 {
f.Name = f.Username
}
return nil
}

View File

@ -101,7 +101,7 @@
<h4 class="cart-title">Control Center</h4> <h4 class="cart-title">Control Center</h4>
<p> <p>
Logged in as: {{ .CurrentUser.Username }} Logged in as: <a href="/account">{{ .CurrentUser.Username }}</a>
</p> </p>
<ul class="list-unstyled"> <ul class="list-unstyled">

75
root/account.gohtml Normal file
View File

@ -0,0 +1,75 @@
{{ define "title" }}Account Settings{{ end }}
{{ define "content" }}
<h1>Account Settings</h1>
<form action="/account" method="POST">
<input type="hidden" name="_csrf" value="{{ .CSRF }}">
<h3>The Basics</h3>
<div class="form-group">
<label for="username">Username</label>
<small class="text-muted">You log in using this name.</small>
<input type="text"
class="form-control"
name="username"
id="username"
value="{{ .Form.Username }}"
placeholder="soandso">
</div>
<div class="form-group">
<label for="name">Name</label>
<input type="text"
class="form-control"
name="name"
id="name"
value="{{ .Form.Name }}"
placeholder="{{ or .Form.Username "Anonymous" }}">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text"
class="form-control"
name="email"
id="email"
value="{{ .Form.Email }}"
placeholder="name@domain.com">
</div>
<h3>Change Password</h3>
<div class="form-group">
<label for="oldpassword">Current Password</label>
<input type="password"
class="form-control"
name="oldpassword"
id="oldpassword"
placeholder="Current Password">
</div>
<div class="form-group">
<label for="newpassword">New Password</label>
<input type="password"
class="form-control"
name="newpassword"
id="newpassword"
placeholder="New Password">
</div>
<div class="form-group">
<label for="newpassword2">Confirm</label>
<input type="password"
class="form-control"
name="newpassword2"
id="newpassword2"
placeholder="Confirm">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Save Settings</button>
<a href="/" class="btn btn-secondary">Cancel</a>
</div>
</form>
{{ end }}