1
0
mirror of https://github.com/muety/wakapi.git synced 2023-08-10 21:12:56 +03:00

feat: user signup

This commit is contained in:
Ferdinand Mütsch
2020-05-24 16:34:32 +02:00
parent a317dc6942
commit abfaa9d768
10 changed files with 280 additions and 58 deletions

View File

@ -1,11 +1,13 @@
package routes
import (
"fmt"
"github.com/gorilla/schema"
"github.com/muety/wakapi/models"
"github.com/muety/wakapi/services"
"github.com/muety/wakapi/utils"
"net/http"
"net/url"
)
type IndexHandler struct {
@ -14,6 +16,7 @@ type IndexHandler struct {
}
var loginDecoder = schema.NewDecoder()
var signupDecoder = schema.NewDecoder()
func NewIndexHandler(config *models.Config, userService *services.UserService) *IndexHandler {
return &IndexHandler{
@ -32,15 +35,18 @@ func (h *IndexHandler) Index(w http.ResponseWriter, r *http.Request) {
return
}
if err := r.URL.Query().Get("error"); err != "" {
if err == "unauthorized" {
respondError(w, err, http.StatusUnauthorized)
} else {
respondError(w, err, http.StatusInternalServerError)
}
if handleAlerts(w, r, "") {
return
}
// TODO: make this more generic and reusable
if success := r.URL.Query().Get("success"); success != "" {
templates["index.tpl.html"].Execute(w, struct {
Success string
Error string
}{Success: success})
return
}
templates["index.tpl.html"].Execute(w, nil)
}
@ -49,30 +55,35 @@ func (h *IndexHandler) Login(w http.ResponseWriter, r *http.Request) {
loadTemplates()
}
if cookie, err := r.Cookie(models.AuthCookieKey); err == nil && cookie.Value != "" {
http.Redirect(w, r, "/summary", http.StatusFound)
return
}
var login models.Login
if err := r.ParseForm(); err != nil {
respondError(w, "missing parameters", http.StatusBadRequest)
respondAlert(w, "missing parameters", "", "", http.StatusBadRequest)
return
}
if err := loginDecoder.Decode(&login, r.PostForm); err != nil {
respondError(w, "missing parameters", http.StatusBadRequest)
respondAlert(w, "missing parameters", "", "", http.StatusBadRequest)
return
}
user, err := h.userSrvc.GetUserById(login.Username)
if err != nil {
respondError(w, "resource not found", http.StatusNotFound)
respondAlert(w, "resource not found", "", "", http.StatusNotFound)
return
}
if !utils.CheckPassword(user, login.Password) {
respondError(w, "invalid credentials", http.StatusUnauthorized)
respondAlert(w, "invalid credentials", "", "", http.StatusUnauthorized)
return
}
encoded, err := h.config.SecureCookie.Encode(models.AuthCookieKey, login)
if err != nil {
respondError(w, "internal server error", http.StatusInternalServerError)
respondAlert(w, "internal server error", "", "", http.StatusInternalServerError)
return
}
@ -96,9 +107,108 @@ func (h *IndexHandler) Logout(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/", http.StatusFound)
}
func respondError(w http.ResponseWriter, error string, status int) {
func (h *IndexHandler) Signup(w http.ResponseWriter, r *http.Request) {
if h.config.IsDev() {
loadTemplates()
}
if cookie, err := r.Cookie(models.AuthCookieKey); err == nil && cookie.Value != "" {
http.Redirect(w, r, "/summary", http.StatusFound)
return
}
switch r.Method {
case http.MethodPost:
h.handlePostSignup(w, r)
return
default:
h.handleGetSignup(w, r)
return
}
}
func (h *IndexHandler) handleGetSignup(w http.ResponseWriter, r *http.Request) {
if h.config.IsDev() {
loadTemplates()
}
if cookie, err := r.Cookie(models.AuthCookieKey); err == nil && cookie.Value != "" {
http.Redirect(w, r, "/summary", http.StatusFound)
return
}
if handleAlerts(w, r, "signup.tpl.html") {
return
}
templates["signup.tpl.html"].Execute(w, nil)
}
func (h *IndexHandler) handlePostSignup(w http.ResponseWriter, r *http.Request) {
if h.config.IsDev() {
loadTemplates()
}
if cookie, err := r.Cookie(models.AuthCookieKey); err == nil && cookie.Value != "" {
http.Redirect(w, r, "/summary", http.StatusFound)
return
}
var signup models.Signup
if err := r.ParseForm(); err != nil {
respondAlert(w, "missing parameters", "", "signup.tpl.html", http.StatusBadRequest)
return
}
if err := signupDecoder.Decode(&signup, r.PostForm); err != nil {
respondAlert(w, "missing parameters", "", "signup.tpl.html", http.StatusBadRequest)
return
}
if signup.Password != signup.PasswordRepeat {
respondAlert(w, "passwords do not match", "", "signup.tpl.html", http.StatusBadRequest)
return
}
_, created, err := h.userSrvc.CreateOrGet(&signup)
if err != nil {
respondAlert(w, "failed to create new user", "", "signup.tpl.html", http.StatusInternalServerError)
return
}
if !created {
respondAlert(w, "user already existing", "", "signup.tpl.html", http.StatusConflict)
return
}
msg := url.QueryEscape("account created successfully")
http.Redirect(w, r, fmt.Sprintf("/?success=%s", msg), http.StatusFound)
}
func respondAlert(w http.ResponseWriter, error, success, tplName string, status int) {
w.WriteHeader(status)
templates["index.tpl.html"].Execute(w, struct {
Error string
if tplName == "" {
tplName = "index.tpl.html"
}
templates[tplName].Execute(w, struct {
Error string
Success string
}{Error: error})
}
// TODO: do better
func handleAlerts(w http.ResponseWriter, r *http.Request, tplName string) bool {
if err := r.URL.Query().Get("error"); err != "" {
if err == "unauthorized" {
respondAlert(w, err, "", tplName, http.StatusUnauthorized)
} else {
respondAlert(w, err, "", tplName, http.StatusInternalServerError)
}
return true
}
if success := r.URL.Query().Get("success"); success != "" {
respondAlert(w, "", success, tplName, http.StatusOK)
return true
}
return false
}

View File

@ -6,6 +6,7 @@ import (
"html/template"
"io/ioutil"
"path"
"strings"
)
func init() {
@ -17,8 +18,10 @@ var templates map[string]*template.Template
func loadTemplates() {
tplPath := "views"
tpls := template.New("").Funcs(template.FuncMap{
"json": utils.Json,
"date": utils.FormatDateHuman,
"json": utils.Json,
"date": utils.FormatDateHuman,
"title": strings.Title,
"capitalize": utils.Capitalize,
})
templates = make(map[string]*template.Template)