Added auth
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"pool-stats/constants"
|
||||
"pool-stats/database"
|
||||
@@ -10,6 +9,8 @@ import (
|
||||
)
|
||||
|
||||
type DailyStatsPageData struct {
|
||||
PageDataBase
|
||||
|
||||
DailyStats []models.DailyStats
|
||||
|
||||
Start string
|
||||
@@ -25,16 +26,10 @@ type DailyStatsPageData struct {
|
||||
}
|
||||
|
||||
func (ws *WebServer) DailyStatsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
tmpl, err := template.Must(ws.templates.Clone()).ParseFiles("templates/daily_stats.html")
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to parse template", http.StatusInternalServerError)
|
||||
println("Error parsing template:", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
startParam := r.URL.Query().Get("start")
|
||||
endParam := r.URL.Query().Get("end")
|
||||
var startTime, endTime time.Time
|
||||
var err error
|
||||
|
||||
if startParam == "" || endParam == "" {
|
||||
endTime = time.Now().Truncate(24 * time.Hour)
|
||||
@@ -91,9 +86,6 @@ func (ws *WebServer) DailyStatsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
PrevPageStart: prevPageStart.Format(time.DateOnly),
|
||||
PrevPageEnd: prevPageEnd.Format(time.DateOnly),
|
||||
}
|
||||
if err := tmpl.ExecuteTemplate(w, "daily_stats.html", data); err != nil {
|
||||
http.Error(w, "Failed to render template", http.StatusInternalServerError)
|
||||
println("Error rendering template:", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ws.renderTemplate(w, r, "templates/daily_stats.html", &data)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
|
||||
"pool-stats/database"
|
||||
@@ -9,17 +8,12 @@ import (
|
||||
)
|
||||
|
||||
type IndexPageData struct {
|
||||
PageDataBase
|
||||
|
||||
Stats []models.TimeWindowHighShare
|
||||
}
|
||||
|
||||
func (ws *WebServer) IndexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
tmpl, err := template.Must(ws.templates.Clone()).ParseFiles("templates/index.html")
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to parse template", 500)
|
||||
println("Error parsing template:", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
tws := database.GetTimeWindowHighShares(ws.db)
|
||||
if tws == nil {
|
||||
http.Error(w, "Failed to load time window high shares", 500)
|
||||
@@ -30,9 +24,5 @@ func (ws *WebServer) IndexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
Stats: tws,
|
||||
}
|
||||
|
||||
if err := tmpl.ExecuteTemplate(w, "index.html", indexData); err != nil {
|
||||
http.Error(w, "Failed to render template", 500)
|
||||
println("Error rendering template:", err.Error())
|
||||
return
|
||||
}
|
||||
ws.renderTemplate(w, r, "templates/index.html", &indexData)
|
||||
}
|
||||
|
||||
42
web/loginHandler.go
Normal file
42
web/loginHandler.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type LoginPageData struct {
|
||||
PageDataBase
|
||||
|
||||
ErrorMessage string
|
||||
}
|
||||
|
||||
func (ws *WebServer) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
loginData := LoginPageData{}
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
loginData.ErrorMessage = "Failed to parse form data"
|
||||
} else {
|
||||
password := r.FormValue("password")
|
||||
if password != ws.adminPassword || ws.adminPassword == "" {
|
||||
loginData.ErrorMessage = "Invalid password"
|
||||
} else {
|
||||
sessionID := generateSessionID()
|
||||
if sessionID == "" {
|
||||
loginData.ErrorMessage = "Failed to generate session ID"
|
||||
}
|
||||
|
||||
ws.sessions[sessionID] = "admin"
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "session_id",
|
||||
Value: sessionID,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
})
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ws.renderTemplate(w, r, "templates/login.html", &loginData)
|
||||
}
|
||||
25
web/logoutHandler.go
Normal file
25
web/logoutHandler.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (ws *WebServer) LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
cookie, err := r.Cookie("session_id")
|
||||
if err != nil {
|
||||
http.Error(w, "No session found", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
delete(ws.sessions, cookie.Value)
|
||||
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "session_id",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
Expires: <-time.After(time.Second * 1),
|
||||
})
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
18
web/models.go
Normal file
18
web/models.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package web
|
||||
|
||||
type PageDataBase struct {
|
||||
UserName string
|
||||
}
|
||||
|
||||
func (pageData PageDataBase) GetUserName() string {
|
||||
return pageData.UserName
|
||||
}
|
||||
|
||||
func (pageData *PageDataBase) SetUserName(userName string) {
|
||||
pageData.UserName = userName
|
||||
}
|
||||
|
||||
type IPageDataBase interface {
|
||||
GetUserName() string
|
||||
SetUserName(userName string)
|
||||
}
|
||||
@@ -3,20 +3,24 @@ package web
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"pool-stats/helpers"
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/gofrs/uuid/v5"
|
||||
"github.com/ostafen/clover/v2"
|
||||
)
|
||||
|
||||
type WebServer struct {
|
||||
db *clover.DB
|
||||
port int
|
||||
templates *template.Template
|
||||
db *clover.DB
|
||||
port int
|
||||
templates *template.Template
|
||||
sessions map[string]string
|
||||
adminPassword string
|
||||
}
|
||||
|
||||
func NewWebServer(db *clover.DB, port int) *WebServer {
|
||||
func NewWebServer(db *clover.DB, port int, adminPassword string) *WebServer {
|
||||
templates := template.New("base").Funcs(template.FuncMap{
|
||||
"add": func(a, b int) int { return a + b },
|
||||
"sub": func(a, b int) int { return a - b },
|
||||
@@ -30,14 +34,18 @@ func NewWebServer(db *clover.DB, port int) *WebServer {
|
||||
))
|
||||
|
||||
return &WebServer{
|
||||
db: db,
|
||||
port: port,
|
||||
templates: templates,
|
||||
db: db,
|
||||
port: port,
|
||||
templates: templates,
|
||||
sessions: make(map[string]string),
|
||||
adminPassword: adminPassword,
|
||||
}
|
||||
}
|
||||
|
||||
func (ws *WebServer) Start() error {
|
||||
http.HandleFunc("/", ws.IndexHandler)
|
||||
http.HandleFunc("/login", ws.LoginHandler)
|
||||
http.HandleFunc("/logout", ws.LogoutHandler)
|
||||
http.HandleFunc("/shares", ws.SharesHandler)
|
||||
http.HandleFunc("/top-shares", ws.TopSharesHandler)
|
||||
http.HandleFunc("/daily-stats", ws.DailyStatsHandler)
|
||||
@@ -46,3 +54,48 @@ func (ws *WebServer) Start() error {
|
||||
println("Listening on", address)
|
||||
return http.ListenAndServe(address, nil)
|
||||
}
|
||||
|
||||
func generateSessionID() string {
|
||||
uuid, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
fmt.Println("Error generating session ID:", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return uuid.String()
|
||||
}
|
||||
|
||||
func (ws *WebServer) getUser(r *http.Request) string {
|
||||
cookie, err := r.Cookie("session_id")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if user, ok := ws.sessions[cookie.Value]; ok {
|
||||
return user
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ws *WebServer) renderTemplate(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
templateFile string,
|
||||
data IPageDataBase) {
|
||||
|
||||
data.SetUserName(ws.getUser(r))
|
||||
|
||||
tmpl, err := template.Must(ws.templates.Clone()).ParseFiles(templateFile)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to parse template", 500)
|
||||
println("Error parsing template:", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
templateName := filepath.Base(templateFile)
|
||||
|
||||
if err := tmpl.ExecuteTemplate(w, templateName, data); err != nil {
|
||||
http.Error(w, "Failed to render template", 500)
|
||||
println("Error rendering template:", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"pool-stats/database"
|
||||
"pool-stats/models"
|
||||
@@ -9,19 +8,14 @@ import (
|
||||
)
|
||||
|
||||
type SharePageData struct {
|
||||
PageDataBase
|
||||
|
||||
Shares []models.ShareLog
|
||||
Page int
|
||||
HasMore bool
|
||||
}
|
||||
|
||||
func (ws *WebServer) SharesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
tmpl, err := template.Must(ws.templates.Clone()).ParseFiles("templates/shares.html")
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to parse template", 500)
|
||||
println("Error parsing template:", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
entriesPerPage := 10
|
||||
page := r.URL.Query().Get("page")
|
||||
if page == "" {
|
||||
@@ -46,8 +40,6 @@ func (ws *WebServer) SharesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
Page: offset/entriesPerPage + 1,
|
||||
HasMore: len(shareLogs) == entriesPerPage,
|
||||
}
|
||||
if err := tmpl.ExecuteTemplate(w, "shares.html", data); err != nil {
|
||||
http.Error(w, "Failed to render template", 500)
|
||||
return
|
||||
}
|
||||
|
||||
ws.renderTemplate(w, r, "templates/shares.html", &data)
|
||||
}
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"pool-stats/database"
|
||||
"pool-stats/models"
|
||||
)
|
||||
|
||||
type TopSharesPageData struct {
|
||||
PageDataBase
|
||||
|
||||
Shares []models.ShareLog
|
||||
}
|
||||
|
||||
func (ws *WebServer) TopSharesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
tmpl, err := template.Must(ws.templates.Clone()).ParseFiles("templates/top_shares.html")
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to parse template", 500)
|
||||
println("Error parsing template:", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
topShares := database.ListTopShares(ws.db)
|
||||
if topShares == nil {
|
||||
http.Error(w, "Failed to load top shares", 500)
|
||||
@@ -28,8 +22,6 @@ func (ws *WebServer) TopSharesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
data := TopSharesPageData{
|
||||
Shares: topShares,
|
||||
}
|
||||
if err := tmpl.ExecuteTemplate(w, "top_shares.html", data); err != nil {
|
||||
http.Error(w, "Failed to render template", 500)
|
||||
return
|
||||
}
|
||||
|
||||
ws.renderTemplate(w, r, "templates/top_shares.html", &data)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user