2020-05-24 14:41:19 +03:00
|
|
|
package routes
|
|
|
|
|
|
|
|
import (
|
2020-05-24 17:34:32 +03:00
|
|
|
"fmt"
|
2020-05-24 14:41:19 +03:00
|
|
|
"github.com/gorilla/schema"
|
|
|
|
"github.com/muety/wakapi/models"
|
|
|
|
"github.com/muety/wakapi/services"
|
|
|
|
"github.com/muety/wakapi/utils"
|
|
|
|
"net/http"
|
2020-05-24 17:34:32 +03:00
|
|
|
"net/url"
|
2020-05-24 14:41:19 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type IndexHandler struct {
|
|
|
|
config *models.Config
|
|
|
|
userSrvc *services.UserService
|
|
|
|
}
|
|
|
|
|
|
|
|
var loginDecoder = schema.NewDecoder()
|
2020-05-24 17:34:32 +03:00
|
|
|
var signupDecoder = schema.NewDecoder()
|
2020-05-24 14:41:19 +03:00
|
|
|
|
2020-05-24 18:32:26 +03:00
|
|
|
func NewIndexHandler(userService *services.UserService) *IndexHandler {
|
2020-05-24 14:41:19 +03:00
|
|
|
return &IndexHandler{
|
2020-05-24 18:32:26 +03:00
|
|
|
config: models.GetConfig(),
|
2020-05-24 14:41:19 +03:00
|
|
|
userSrvc: userService,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *IndexHandler) Index(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if h.config.IsDev() {
|
|
|
|
loadTemplates()
|
|
|
|
}
|
|
|
|
|
|
|
|
if cookie, err := r.Cookie(models.AuthCookieKey); err == nil && cookie.Value != "" {
|
2020-05-24 18:08:44 +03:00
|
|
|
http.Redirect(w, r, fmt.Sprintf("%s/summary", h.config.BasePath), http.StatusFound)
|
2020-05-24 14:41:19 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-05-24 17:34:32 +03:00
|
|
|
if handleAlerts(w, r, "") {
|
2020-05-24 14:41:19 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-05-24 17:34:32 +03:00
|
|
|
// 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
|
|
|
|
}
|
2020-05-24 14:41:19 +03:00
|
|
|
templates["index.tpl.html"].Execute(w, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *IndexHandler) Login(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if h.config.IsDev() {
|
|
|
|
loadTemplates()
|
|
|
|
}
|
|
|
|
|
2020-05-24 17:34:32 +03:00
|
|
|
if cookie, err := r.Cookie(models.AuthCookieKey); err == nil && cookie.Value != "" {
|
2020-05-24 18:08:44 +03:00
|
|
|
http.Redirect(w, r, fmt.Sprintf("%s/summary", h.config.BasePath), http.StatusFound)
|
2020-05-24 17:34:32 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-05-24 14:41:19 +03:00
|
|
|
var login models.Login
|
|
|
|
if err := r.ParseForm(); err != nil {
|
2020-05-24 17:34:32 +03:00
|
|
|
respondAlert(w, "missing parameters", "", "", http.StatusBadRequest)
|
2020-05-24 14:41:19 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if err := loginDecoder.Decode(&login, r.PostForm); err != nil {
|
2020-05-24 17:34:32 +03:00
|
|
|
respondAlert(w, "missing parameters", "", "", http.StatusBadRequest)
|
2020-05-24 14:41:19 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
user, err := h.userSrvc.GetUserById(login.Username)
|
|
|
|
if err != nil {
|
2020-05-24 17:34:32 +03:00
|
|
|
respondAlert(w, "resource not found", "", "", http.StatusNotFound)
|
2020-05-24 14:41:19 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if !utils.CheckPassword(user, login.Password) {
|
2020-05-24 17:34:32 +03:00
|
|
|
respondAlert(w, "invalid credentials", "", "", http.StatusUnauthorized)
|
2020-05-24 14:41:19 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
encoded, err := h.config.SecureCookie.Encode(models.AuthCookieKey, login)
|
|
|
|
if err != nil {
|
2020-05-24 17:34:32 +03:00
|
|
|
respondAlert(w, "internal server error", "", "", http.StatusInternalServerError)
|
2020-05-24 14:41:19 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
cookie := &http.Cookie{
|
|
|
|
Name: models.AuthCookieKey,
|
|
|
|
Value: encoded,
|
|
|
|
Path: "/",
|
|
|
|
Secure: true,
|
|
|
|
HttpOnly: true,
|
|
|
|
}
|
|
|
|
http.SetCookie(w, cookie)
|
2020-05-24 18:08:44 +03:00
|
|
|
http.Redirect(w, r, fmt.Sprintf("%s/summary", h.config.BasePath), http.StatusFound)
|
2020-05-24 14:41:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (h *IndexHandler) Logout(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if h.config.IsDev() {
|
|
|
|
loadTemplates()
|
|
|
|
}
|
|
|
|
|
|
|
|
utils.ClearCookie(w, models.AuthCookieKey)
|
2020-05-24 18:08:44 +03:00
|
|
|
http.Redirect(w, r, fmt.Sprintf("%s/", h.config.BasePath), http.StatusFound)
|
2020-05-24 14:41:19 +03:00
|
|
|
}
|
|
|
|
|
2020-05-24 17:34:32 +03:00
|
|
|
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 != "" {
|
2020-05-24 18:08:44 +03:00
|
|
|
http.Redirect(w, r, fmt.Sprintf("%s/summary", h.config.BasePath), http.StatusFound)
|
2020-05-24 17:34:32 +03:00
|
|
|
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 != "" {
|
2020-05-24 18:08:44 +03:00
|
|
|
http.Redirect(w, r, fmt.Sprintf("%s/summary", h.config.BasePath), http.StatusFound)
|
2020-05-24 17:34:32 +03:00
|
|
|
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 != "" {
|
2020-05-24 18:08:44 +03:00
|
|
|
http.Redirect(w, r, fmt.Sprintf("%s/summary", h.config.BasePath), http.StatusFound)
|
2020-05-24 17:34:32 +03:00
|
|
|
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")
|
2020-05-24 18:08:44 +03:00
|
|
|
http.Redirect(w, r, fmt.Sprintf("%s/?success=%s", h.config.BasePath, msg), http.StatusFound)
|
2020-05-24 17:34:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func respondAlert(w http.ResponseWriter, error, success, tplName string, status int) {
|
2020-05-24 14:41:19 +03:00
|
|
|
w.WriteHeader(status)
|
2020-05-24 17:34:32 +03:00
|
|
|
if tplName == "" {
|
|
|
|
tplName = "index.tpl.html"
|
|
|
|
}
|
|
|
|
templates[tplName].Execute(w, struct {
|
|
|
|
Error string
|
|
|
|
Success string
|
2020-05-24 14:41:19 +03:00
|
|
|
}{Error: error})
|
|
|
|
}
|
2020-05-24 17:34:32 +03:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|