184 lines
4.7 KiB
Go
184 lines
4.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"go-backend/internal/auth"
|
|
"go-backend/internal/database/sqlc"
|
|
"go-backend/internal/services"
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
)
|
|
|
|
// UserService and AuthService are defined here, on the consumer side, so
|
|
// handlers depend only on the methods they actually use and tests can swap
|
|
// in fakes without touching the services package.
|
|
|
|
type UserService interface {
|
|
FindByID(ctx context.Context, id string) (*sqlc.UserAuth, error)
|
|
FindByUsername(ctx context.Context, username string) (*sqlc.UserAuth, error)
|
|
CreateUser(ctx context.Context, userInput sqlc.InsertUserParams) (*sqlc.UserAuth, error)
|
|
PatchUser(ctx context.Context, id string, input services.PatchUserInput) (*sqlc.UserAuth, error)
|
|
}
|
|
|
|
type AuthService interface {
|
|
CreateSession(ctx context.Context, userID string) (*services.SessionWithToken, error)
|
|
ValidateSessionToken(ctx context.Context, token string) (*sqlc.UserSession, bool, error)
|
|
DeleteSession(ctx context.Context, token string) error
|
|
}
|
|
|
|
type Handler struct {
|
|
users UserService
|
|
auth AuthService
|
|
templateCache map[string]*template.Template
|
|
}
|
|
|
|
// PageData wraps every page render so base.tmpl always has a stable place
|
|
// to check whether a user is logged in (.User), regardless of what
|
|
// page-specific data (.Data) the page template itself needs.
|
|
type PageData struct {
|
|
User *sqlc.UserAuth
|
|
Data any
|
|
}
|
|
|
|
func NewHandler(users UserService, auth AuthService, templateCache map[string]*template.Template) *Handler {
|
|
return &Handler{
|
|
users: users,
|
|
auth: auth,
|
|
templateCache: templateCache,
|
|
}
|
|
}
|
|
|
|
// render looks up the pre-parsed template for page (e.g. "index.tmpl") and
|
|
// executes it. It writes an error response itself on failure.
|
|
func (h *Handler) render(w http.ResponseWriter, page string, data PageData) {
|
|
ts, ok := h.templateCache[page]
|
|
if !ok {
|
|
log.Printf("template %s not found in cache", page)
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err := ts.ExecuteTemplate(w, "base", data); err != nil {
|
|
log.Print(err.Error())
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
}
|
|
}
|
|
|
|
func (h *Handler) HomePageHandler(w http.ResponseWriter, r *http.Request) {
|
|
cookie, err := r.Cookie("session")
|
|
|
|
if err != nil {
|
|
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
|
return
|
|
}
|
|
|
|
session, bump, err := h.auth.ValidateSessionToken(r.Context(), cookie.Value)
|
|
|
|
if err != nil {
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if session == nil {
|
|
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
|
return
|
|
}
|
|
|
|
if bump {
|
|
http.SetCookie(w, auth.NewSessionCookie(cookie.Value, false))
|
|
}
|
|
|
|
user, err := h.users.FindByID(r.Context(), session.UserID)
|
|
|
|
if err != nil {
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
h.render(w, "index.tmpl", PageData{User: user, Data: user.Username})
|
|
}
|
|
|
|
func (h *Handler) LoginPageHandler(w http.ResponseWriter, r *http.Request) {
|
|
cookie, _ := r.Cookie("session")
|
|
|
|
if cookie != nil {
|
|
session, bump, err := h.auth.ValidateSessionToken(r.Context(), cookie.Value)
|
|
|
|
if err != nil {
|
|
log.Print(err.Error())
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if bump {
|
|
http.SetCookie(w, auth.NewSessionCookie(cookie.Value, false))
|
|
}
|
|
|
|
if session != nil {
|
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
|
return
|
|
}
|
|
}
|
|
|
|
h.render(w, "login.tmpl", PageData{})
|
|
}
|
|
|
|
func (h *Handler) SignUpPageHandler(w http.ResponseWriter, r *http.Request) {
|
|
cookie, _ := r.Cookie("session")
|
|
|
|
if cookie != nil {
|
|
session, bump, err := h.auth.ValidateSessionToken(r.Context(), cookie.Value)
|
|
|
|
if err != nil {
|
|
log.Print(err.Error())
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if bump {
|
|
http.SetCookie(w, auth.NewSessionCookie(cookie.Value, false))
|
|
}
|
|
|
|
if session != nil {
|
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
|
return
|
|
}
|
|
}
|
|
|
|
h.render(w, "signup.tmpl", PageData{})
|
|
}
|
|
|
|
func (h *Handler) SettingsPageHandler(w http.ResponseWriter, r *http.Request) {
|
|
cookie, err := r.Cookie("session")
|
|
|
|
if err != nil {
|
|
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
|
return
|
|
}
|
|
|
|
session, bump, err := h.auth.ValidateSessionToken(r.Context(), cookie.Value)
|
|
|
|
if err != nil {
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if session == nil {
|
|
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
|
return
|
|
}
|
|
|
|
if bump {
|
|
http.SetCookie(w, auth.NewSessionCookie(cookie.Value, false))
|
|
}
|
|
|
|
user, err := h.users.FindByID(r.Context(), session.UserID)
|
|
|
|
if err != nil {
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
h.render(w, "settings.tmpl", PageData{User: user, Data: user})
|
|
}
|