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

refactor: use cookie-based login

feat: add login page
This commit is contained in:
Ferdinand Mütsch
2020-05-24 13:41:19 +02:00
parent d3ab54f6dc
commit 9697bb5fd5
19 changed files with 449 additions and 219 deletions

43
routes/common.go Normal file
View File

@ -0,0 +1,43 @@
package routes
import (
"fmt"
"github.com/muety/wakapi/utils"
"html/template"
"io/ioutil"
"path"
)
func init() {
loadTemplates()
}
var templates map[string]*template.Template
func loadTemplates() {
tplPath := "views"
tpls := template.New("").Funcs(template.FuncMap{
"json": utils.Json,
"date": utils.FormatDateHuman,
})
templates = make(map[string]*template.Template)
files, err := ioutil.ReadDir(tplPath)
if err != nil {
panic(err)
}
for _, file := range files {
tplName := file.Name()
if file.IsDir() || path.Ext(tplName) != ".html" {
continue
}
tpl, err := tpls.New(tplName).ParseFiles(fmt.Sprintf("%s/%s", tplPath, tplName))
if err != nil {
panic(err)
}
templates[tplName] = tpl
}
}

View File

@ -7,12 +7,16 @@ import (
)
type HealthHandler struct {
Db *gorm.DB
db *gorm.DB
}
func NewHealthHandler(db *gorm.DB) *HealthHandler {
return &HealthHandler{db: db}
}
func (h *HealthHandler) ApiGet(w http.ResponseWriter, r *http.Request) {
var dbStatus int
if err := h.Db.DB().Ping(); err == nil {
if err := h.db.DB().Ping(); err == nil {
dbStatus = 1
}

View File

@ -12,15 +12,18 @@ import (
)
type HeartbeatHandler struct {
HeartbeatSrvc *services.HeartbeatService
config *models.Config
heartbeatSrvc *services.HeartbeatService
}
func NewHeartbeatHandler(config *models.Config, heartbearService *services.HeartbeatService) *HeartbeatHandler {
return &HeartbeatHandler{
config: config,
heartbeatSrvc: heartbearService,
}
}
func (h *HeartbeatHandler) ApiPost(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
var heartbeats []*models.Heartbeat
user := r.Context().Value(models.UserKey).(*models.User)
opSys, editor, _ := utils.ParseUserAgent(r.Header.Get("User-Agent"))
@ -37,7 +40,7 @@ func (h *HeartbeatHandler) ApiPost(w http.ResponseWriter, r *http.Request) {
hb.Editor = editor
hb.User = user
hb.UserID = user.ID
hb.Augment(h.HeartbeatSrvc.Config.CustomLanguages)
hb.Augment(h.config.CustomLanguages)
if !hb.Valid() {
w.WriteHeader(http.StatusBadRequest)
@ -46,7 +49,7 @@ func (h *HeartbeatHandler) ApiPost(w http.ResponseWriter, r *http.Request) {
}
}
if err := h.HeartbeatSrvc.InsertBatch(heartbeats); err != nil {
if err := h.heartbeatSrvc.InsertBatch(heartbeats); err != nil {
w.WriteHeader(http.StatusInternalServerError)
os.Stderr.WriteString(err.Error())
return

104
routes/index.go Normal file
View File

@ -0,0 +1,104 @@
package routes
import (
"github.com/gorilla/schema"
"github.com/muety/wakapi/models"
"github.com/muety/wakapi/services"
"github.com/muety/wakapi/utils"
"net/http"
)
type IndexHandler struct {
config *models.Config
userSrvc *services.UserService
}
var loginDecoder = schema.NewDecoder()
func NewIndexHandler(config *models.Config, userService *services.UserService) *IndexHandler {
return &IndexHandler{
config: config,
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 != "" {
http.Redirect(w, r, "/summary", http.StatusFound)
return
}
if err := r.URL.Query().Get("error"); err != "" {
if err == "unauthorized" {
respondError(w, err, http.StatusUnauthorized)
} else {
respondError(w, err, http.StatusInternalServerError)
}
return
}
templates["index.tpl.html"].Execute(w, nil)
}
func (h *IndexHandler) Login(w http.ResponseWriter, r *http.Request) {
if h.config.IsDev() {
loadTemplates()
}
var login models.Login
if err := r.ParseForm(); err != nil {
respondError(w, "missing parameters", http.StatusBadRequest)
return
}
if err := loginDecoder.Decode(&login, r.PostForm); err != nil {
respondError(w, "missing parameters", http.StatusBadRequest)
return
}
user, err := h.userSrvc.GetUserById(login.Username)
if err != nil {
respondError(w, "resource not found", http.StatusNotFound)
return
}
if !utils.CheckPassword(user, login.Password) {
respondError(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)
return
}
cookie := &http.Cookie{
Name: models.AuthCookieKey,
Value: encoded,
Path: "/",
Secure: true,
HttpOnly: true,
}
http.SetCookie(w, cookie)
http.Redirect(w, r, "/summary", http.StatusFound)
}
func (h *IndexHandler) Logout(w http.ResponseWriter, r *http.Request) {
if h.config.IsDev() {
loadTemplates()
}
utils.ClearCookie(w, models.AuthCookieKey)
http.Redirect(w, r, "/", http.StatusFound)
}
func respondError(w http.ResponseWriter, error string, status int) {
w.WriteHeader(status)
templates["index.tpl.html"].Execute(w, struct {
Error string
}{Error: error})
}

View File

@ -2,11 +2,7 @@ package routes
import (
"errors"
"fmt"
"html/template"
"io/ioutil"
"net/http"
"path"
"time"
"github.com/muety/wakapi/models"
@ -24,55 +20,19 @@ const (
)
type SummaryHandler struct {
SummarySrvc *services.SummaryService
Initialized bool
templates map[string]*template.Template
cummarySrvc *services.SummaryService
config *models.Config
}
func (m *SummaryHandler) Init() {
m.loadTemplates()
m.Initialized = true
}
func (m *SummaryHandler) loadTemplates() {
tplPath := "views"
templates := template.New("").Funcs(template.FuncMap{
"json": utils.Json,
"date": utils.FormatDateHuman,
})
m.templates = make(map[string]*template.Template)
files, err := ioutil.ReadDir(tplPath)
if err != nil {
panic(err)
}
for _, file := range files {
tplName := file.Name()
if file.IsDir() || path.Ext(tplName) != ".html" {
continue
}
tpl, err := templates.New(tplName).ParseFiles(fmt.Sprintf("%s/%s", tplPath, tplName))
if err != nil {
panic(err)
}
m.templates[tplName] = tpl
func NewSummaryHandler(config *models.Config, summaryService *services.SummaryService) *SummaryHandler {
return &SummaryHandler{
cummarySrvc: summaryService,
config: config,
}
}
func (h *SummaryHandler) ApiGet(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
if !h.Initialized {
h.Init()
}
summary, err, status := loadUserSummary(r, h.SummarySrvc)
summary, err, status := loadUserSummary(r, h.cummarySrvc)
if err != nil {
w.WriteHeader(status)
w.Write([]byte(err.Error()))
@ -83,17 +43,8 @@ func (h *SummaryHandler) ApiGet(w http.ResponseWriter, r *http.Request) {
}
func (h *SummaryHandler) Index(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
if !h.Initialized {
h.Init()
}
if h.SummarySrvc.Config.IsDev() {
h.loadTemplates()
if h.config.IsDev() {
loadTemplates()
}
q := r.URL.Query()
@ -102,7 +53,7 @@ func (h *SummaryHandler) Index(w http.ResponseWriter, r *http.Request) {
r.URL.RawQuery = q.Encode()
}
summary, err, status := loadUserSummary(r, h.SummarySrvc)
summary, err, status := loadUserSummary(r, h.cummarySrvc)
if err != nil {
w.WriteHeader(status)
w.Write([]byte(err.Error()))
@ -111,10 +62,10 @@ func (h *SummaryHandler) Index(w http.ResponseWriter, r *http.Request) {
vm := models.SummaryViewModel{
Summary: summary,
LanguageColors: utils.FilterLanguageColors(h.SummarySrvc.Config.LanguageColors, summary),
LanguageColors: utils.FilterLanguageColors(h.config.LanguageColors, summary),
}
h.templates["index.tpl.html"].Execute(w, vm)
templates["summary.tpl.html"].Execute(w, vm)
}
func loadUserSummary(r *http.Request, summaryService *services.SummaryService) (*models.Summary, error, int) {