plan/chapter_3_tasks
Raw Download raw file
  1package main
  2
  3import (
  4	"html/template"
  5	"log"
  6	"net/http"
  7	"regexp"
  8)
  9
 10// PageData holds common data passed to templates
 11type PageData struct {
 12	Title       string
 13	ServiceName string
 14	Content     interface{}
 15}
 16
 17// application holds the application-wide dependencies and configuration
 18// This demonstrates a custom handler type that can hold state and dependencies
 19type application struct {
 20	logger      *log.Logger
 21	serviceName string
 22}
 23
 24// TemplateHandler represents handlers that render templates
 25// This is a custom handler type that implements http.Handler interface
 26type TemplateHandler struct {
 27	app          *application
 28	templateName string
 29	pageName     string
 30	title        string
 31}
 32
 33// ServeHTTP makes TemplateHandler satisfy the http.Handler interface
 34func (th *TemplateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 35	w.Header().Add("Server", th.app.serviceName)
 36
 37	// Parse templates with inheritance
 38	ts, err := template.ParseFiles(
 39		"./ui/html/layouts/base.tmpl",
 40		"./ui/html/pages/"+th.templateName,
 41	)
 42	if err != nil {
 43		th.app.logger.Println(err.Error())
 44		http.Error(w, "Internal Server Error", 500)
 45		return
 46	}
 47
 48	// Prepare template data
 49	data := PageData{
 50		Title:       th.title,
 51		ServiceName: th.app.serviceName,
 52		Content:     nil,
 53	}
 54
 55	// Execute template
 56	err = ts.ExecuteTemplate(w, "base", data)
 57	if err != nil {
 58		th.app.logger.Println(err.Error())
 59		http.Error(w, "Internal Server Error", 500)
 60	}
 61}
 62
 63// home displays the buylater.email landing page
 64// This demonstrates using http.HandlerFunc to convert a regular function
 65// into something that satisfies the http.Handler interface
 66func (app *application) home(w http.ResponseWriter, r *http.Request) {
 67	w.Header().Add("Server", app.serviceName)
 68
 69	// Parse templates with inheritance
 70	ts, err := template.ParseFiles(
 71		"./ui/html/layouts/base.tmpl",
 72		"./ui/html/pages/home.tmpl",
 73	)
 74	if err != nil {
 75		app.logger.Println(err.Error())
 76		http.Error(w, "Internal Server Error", 500)
 77		return
 78	}
 79
 80	// Prepare template data
 81	data := PageData{
 82		Title:       "Home",
 83		ServiceName: app.serviceName,
 84		Content:     nil,
 85	}
 86
 87	// Execute template
 88	err = ts.ExecuteTemplate(w, "base", data)
 89	if err != nil {
 90		app.logger.Println(err.Error())
 91		http.Error(w, "Internal Server Error", 500)
 92	}
 93}
 94
 95// submitForm displays the email submission form for scheduling purchase reminders
 96// This will be handled by the TemplateHandler type to demonstrate custom handler types
 97
 98// processSubmit handles the form submission and schedules the email reminder
 99// This demonstrates a method handler with business logic
100func (app *application) processSubmit(w http.ResponseWriter, r *http.Request) {
101	w.Header().Add("Server", app.serviceName)
102
103	// Parse templates with inheritance
104	ts, err := template.ParseFiles(
105		"./ui/html/layouts/base.tmpl",
106		"./ui/html/pages/complete.tmpl",
107	)
108	if err != nil {
109		app.logger.Println(err.Error())
110		http.Error(w, "Internal Server Error", 500)
111		return
112	}
113
114	// Prepare template data
115	data := PageData{
116		Title:       "Submission Complete",
117		ServiceName: app.serviceName,
118		Content:     nil,
119	}
120
121	// Execute template
122	err = ts.ExecuteTemplate(w, "base", data)
123	if err != nil {
124		app.logger.Println(err.Error())
125		http.Error(w, "Internal Server Error", 500)
126	}
127}
128
129// confirmWithToken handles magic link confirmation with token validation
130// This demonstrates a stateless handler function that can be converted with http.HandlerFunc
131func confirmWithToken(w http.ResponseWriter, r *http.Request) {
132	token := r.PathValue("token")
133
134	if !isValidToken(token) {
135		w.Header().Add("Server", "buylater.email")
136		http.NotFound(w, r)
137		return
138	}
139
140	w.Header().Add("Server", "buylater.email")
141	w.WriteHeader(http.StatusOK)
142	w.Write([]byte("Email Confirmed! Your purchase reminder has been activated via magic link."))
143}
144
145// isValidToken validates that the token is alphanumeric and at least 32 characters
146func isValidToken(token string) bool {
147	if len(token) < 32 {
148		return false
149	}
150
151	// Check if token contains only alphanumeric characters
152	matched, _ := regexp.MatchString("^[a-zA-Z0-9]+$", token)
153	return matched
154}
155
156// about displays information about the buylater.email service
157// This will be handled by the TemplateHandler type to demonstrate reusable custom handlers