143 lines
3.4 KiB
Go
143 lines
3.4 KiB
Go
package routes
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"database/sql"
|
|
"html/template"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"git.soup.land/soup/shelves/internal/auth"
|
|
"git.soup.land/soup/shelves/internal/errorsx"
|
|
"git.soup.land/soup/shelves/internal/forms"
|
|
"git.soup.land/soup/shelves/internal/httpx"
|
|
"git.soup.land/soup/shelves/internal/templates/components"
|
|
)
|
|
|
|
func settingsRenderView(f settingsForm, e settingsFormErrors) template.HTML {
|
|
body := components.Form{
|
|
Action: "/settings",
|
|
Fields: []components.Field{
|
|
components.Field{
|
|
Label: "Display name",
|
|
Name: "displayName",
|
|
Placeholder: "Jane Doe",
|
|
Value: f.displayName,
|
|
Error: errorsx.String(e.displayName),
|
|
},
|
|
components.Field{
|
|
Label: "Password",
|
|
Type: "password",
|
|
Placeholder: "Password",
|
|
Name: "password",
|
|
Error: errorsx.String(e.password),
|
|
},
|
|
components.Field{
|
|
Label: "Confirm password",
|
|
Placeholder: "Confirm Password",
|
|
Type: "password",
|
|
Name: "passwordConfirmation",
|
|
},
|
|
},
|
|
}.HTML()
|
|
|
|
return components.Page{Title: "Set up", Body: body}.HTML()
|
|
}
|
|
|
|
func queryGetOwnerSettings(db *sql.DB) (settingsForm, error) {
|
|
form := settingsForm{}
|
|
err := db.QueryRow(`select display_name from owner_settings`).Scan(&form.displayName)
|
|
if err == sql.ErrNoRows {
|
|
err = nil
|
|
}
|
|
|
|
return form, err
|
|
}
|
|
|
|
func SettingsGet(w http.ResponseWriter, r *http.Request) {
|
|
ctx := httpx.GetCtx(r)
|
|
if !ctx.SessionInfo.IsAdmin && !ctx.NeedsOwnerSetup {
|
|
httpx.LoginRedirect(w, *r.URL)
|
|
return
|
|
}
|
|
|
|
form, err := queryGetOwnerSettings(ctx.DB)
|
|
if err != nil {
|
|
httpx.InternalServerError(w, err)
|
|
return
|
|
}
|
|
|
|
html(w, settingsRenderView(form, settingsFormErrors{}))
|
|
}
|
|
|
|
type settingsForm struct {
|
|
password string
|
|
displayName string
|
|
}
|
|
|
|
type settingsFormErrors struct {
|
|
password error
|
|
displayName error
|
|
}
|
|
|
|
func parseForm(f *settingsForm, e *settingsFormErrors, vs url.Values, v *forms.Validator) {
|
|
f.password = vs.Get("password")
|
|
passwordConfirmation := vs.Get("passwordConfirmation")
|
|
f.displayName = vs.Get("displayName")
|
|
|
|
e.password = v.MinLength(f.password, 1)
|
|
if e.password == nil && f.password != passwordConfirmation {
|
|
e.password = v.Fail("Passwords did not match")
|
|
}
|
|
|
|
e.displayName = v.MinLength(f.displayName, 1)
|
|
}
|
|
|
|
func queryUpdateOwnerSettings(db *sql.DB, display_name string, password_salt []byte, password_hash []byte) error {
|
|
_, err := db.Exec(`
|
|
insert or replace into owner_settings (display_name, password_salt, password_hash)
|
|
values (?, ?, ?)
|
|
`, display_name, password_salt, password_hash)
|
|
return err
|
|
}
|
|
|
|
func updateOwnerSettings(db *sql.DB, f settingsForm) error {
|
|
salt := make([]byte, 32)
|
|
_, err := rand.Read(salt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
hash := auth.HashPassword([]byte(f.password), salt)
|
|
|
|
return queryUpdateOwnerSettings(db, f.displayName, salt, hash)
|
|
}
|
|
|
|
func SettingsPost(w http.ResponseWriter, r *http.Request) {
|
|
ctx := httpx.GetCtx(r)
|
|
|
|
if !ctx.SessionInfo.IsAdmin && !ctx.NeedsOwnerSetup {
|
|
httpx.Unauthorized(w)
|
|
return
|
|
}
|
|
|
|
form := settingsForm{}
|
|
errs := settingsFormErrors{}
|
|
failed := forms.ParseFormData(r, func(vs url.Values, v *forms.Validator) {
|
|
parseForm(&form, &errs, vs, v)
|
|
})
|
|
|
|
if failed {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
html(w, settingsRenderView(form, errs))
|
|
return
|
|
}
|
|
|
|
err := updateOwnerSettings(ctx.DB, form)
|
|
if err != nil {
|
|
httpx.InternalServerError(w, err)
|
|
} else {
|
|
httpx.SeeOther(w, "/")
|
|
}
|
|
}
|