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