package handlers
import (
"database/sql"
"html/template"
"mealprep/auth"
"mealprep/database"
"net/http"
"strings"
"time"
)
// LoginPageHandler shows the login page
func LoginPageHandler(w http.ResponseWriter, r *http.Request) {
tmpl := `
Login - Meal Prep Planner
🍽️ Meal Prep Planner
Login
{{if .Error}}
{{.Error}}
{{end}}
Don't have an account? Register here
`
data := struct {
Error string
}{
Error: r.URL.Query().Get("error"),
}
t := template.Must(template.New("login").Parse(tmpl))
t.Execute(w, data)
}
// RegisterPageHandler shows the registration page
func RegisterPageHandler(w http.ResponseWriter, r *http.Request) {
tmpl := `
Register - Meal Prep Planner
🍽️ Meal Prep Planner
Create Account
{{if .Error}}
{{.Error}}
{{end}}
Already have an account? Login here
`
data := struct {
Error string
}{
Error: r.URL.Query().Get("error"),
}
t := template.Must(template.New("register").Parse(tmpl))
t.Execute(w, data)
}
// LoginHandler processes login requests
func LoginHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Redirect(w, r, "/login", http.StatusSeeOther)
return
}
if err := r.ParseForm(); err != nil {
http.Redirect(w, r, "/login?error=Invalid+request", http.StatusSeeOther)
return
}
email := strings.TrimSpace(strings.ToLower(r.FormValue("email")))
password := r.FormValue("password")
// Validate input
if email == "" || password == "" {
http.Redirect(w, r, "/login?error=Email+and+password+required", http.StatusSeeOther)
return
}
if !auth.ValidateEmail(email) {
http.Redirect(w, r, "/login?error=Invalid+email+format", http.StatusSeeOther)
return
}
// Get user from database
user, err := database.GetUserByEmail(email)
if err != nil {
if err == sql.ErrNoRows {
http.Redirect(w, r, "/login?error=Invalid+credentials", http.StatusSeeOther)
return
}
http.Redirect(w, r, "/login?error=Server+error", http.StatusSeeOther)
return
}
// Check password
if !auth.CheckPassword(password, user.PasswordHash) {
http.Redirect(w, r, "/login?error=Invalid+credentials", http.StatusSeeOther)
return
}
// Create session
token, err := auth.GenerateSessionToken()
if err != nil {
http.Redirect(w, r, "/login?error=Failed+to+create+session", http.StatusSeeOther)
return
}
expiresAt := auth.GetSessionExpiry()
if err := database.CreateSession(token, user.ID, expiresAt); err != nil {
http.Redirect(w, r, "/login?error=Failed+to+create+session", http.StatusSeeOther)
return
}
// Set secure cookie
http.SetCookie(w, &http.Cookie{
Name: "session_token",
Value: token,
Expires: expiresAt,
HttpOnly: true,
Secure: false, // Set to true in production with HTTPS
SameSite: http.SameSiteStrictMode,
Path: "/",
})
// Redirect to home
http.Redirect(w, r, "/", http.StatusSeeOther)
}
// RegisterHandler processes registration requests
func RegisterHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Redirect(w, r, "/register", http.StatusSeeOther)
return
}
if err := r.ParseForm(); err != nil {
http.Redirect(w, r, "/register?error=Invalid+request", http.StatusSeeOther)
return
}
email := strings.TrimSpace(strings.ToLower(r.FormValue("email")))
password := r.FormValue("password")
passwordConfirm := r.FormValue("password_confirm")
// Validate input
if email == "" || password == "" || passwordConfirm == "" {
http.Redirect(w, r, "/register?error=All+fields+required", http.StatusSeeOther)
return
}
if !auth.ValidateEmail(email) {
http.Redirect(w, r, "/register?error=Invalid+email+format", http.StatusSeeOther)
return
}
if password != passwordConfirm {
http.Redirect(w, r, "/register?error=Passwords+do+not+match", http.StatusSeeOther)
return
}
if len(password) < 8 {
http.Redirect(w, r, "/register?error=Password+must+be+at+least+8+characters", http.StatusSeeOther)
return
}
// Check if user exists
existingUser, _ := database.GetUserByEmail(email)
if existingUser != nil {
http.Redirect(w, r, "/register?error=Email+already+registered", http.StatusSeeOther)
return
}
// Hash password
passwordHash, err := auth.HashPassword(password)
if err != nil {
http.Redirect(w, r, "/register?error=Failed+to+create+account", http.StatusSeeOther)
return
}
// Create user
userID, err := database.CreateUser(email, passwordHash)
if err != nil {
http.Redirect(w, r, "/register?error=Failed+to+create+account", http.StatusSeeOther)
return
}
// Create session
token, err := auth.GenerateSessionToken()
if err != nil {
http.Redirect(w, r, "/login", http.StatusSeeOther)
return
}
expiresAt := auth.GetSessionExpiry()
if err := database.CreateSession(token, int(userID), expiresAt); err != nil {
http.Redirect(w, r, "/login", http.StatusSeeOther)
return
}
// Set secure cookie
http.SetCookie(w, &http.Cookie{
Name: "session_token",
Value: token,
Expires: expiresAt,
HttpOnly: true,
Secure: false, // Set to true in production with HTTPS
SameSite: http.SameSiteStrictMode,
Path: "/",
})
// Redirect to home
http.Redirect(w, r, "/", http.StatusSeeOther)
}
// LogoutHandler processes logout requests
func LogoutHandler(w http.ResponseWriter, r *http.Request) {
// Get session cookie
cookie, err := r.Cookie("session_token")
if err == nil {
// Delete session from database
database.DeleteSession(cookie.Value)
}
// Clear cookie
http.SetCookie(w, &http.Cookie{
Name: "session_token",
Value: "",
Expires: time.Unix(0, 0),
HttpOnly: true,
Secure: false,
SameSite: http.SameSiteStrictMode,
Path: "/",
MaxAge: -1,
})
http.Redirect(w, r, "/login", http.StatusSeeOther)
}