Skip to content

Commit

Permalink
Initialize repository
Browse files Browse the repository at this point in the history
  • Loading branch information
abneed committed May 10, 2022
0 parents commit bed9362
Show file tree
Hide file tree
Showing 13 changed files with 348 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode
54 changes: 54 additions & 0 deletions cmd/web/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package main

import (
"fmt"
"log"
"net/http"
"time"

"github.com/abneed/bookings/pkg/config"
"github.com/abneed/bookings/pkg/handlers"
"github.com/abneed/bookings/pkg/render"
"github.com/alexedwards/scs/v2"
)

const portNumber = ":8080"

var app config.AppConfig
var session *scs.SessionManager

// main is the main application function
func main() {
// change this to true when in production
app.InProduction = false

session = scs.New()
session.Lifetime = 24 * time.Hour
session.Cookie.Persist = true
session.Cookie.SameSite = http.SameSiteLaxMode
session.Cookie.Secure = app.InProduction

app.Session = session

tc, err := render.CreateTemplateCache()
if err != nil {
log.Fatal("cannot create template cache")
}

app.TemplateCache = tc
app.UseCache = false

repo := handlers.NewRepo(&app)
handlers.NewHandlers(repo)
render.NewTemplates(&app)

fmt.Println(fmt.Sprintf("Starting application on port %s", portNumber))
// _ = http.ListenAndServe(portNumber, nil)

srv := &http.Server{
Addr: portNumber,
Handler: routes(&app),
}
srv.ListenAndServe()
log.Fatal(err)
}
24 changes: 24 additions & 0 deletions cmd/web/middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"net/http"

"github.com/justinas/nosurf"
)

// NoSurf adds CSRF protection to all POST requests
func NoSurf(next http.Handler) http.Handler {
csrfHandler := nosurf.New(next)
csrfHandler.SetBaseCookie(http.Cookie{
HttpOnly: true,
Path: "/",
Secure: app.InProduction,
SameSite: http.SameSiteLaxMode,
})
return csrfHandler
}

// SessionLoad loads and saves the session on every request
func SessionLoad(next http.Handler) http.Handler {
return session.LoadAndSave(next)
}
22 changes: 22 additions & 0 deletions cmd/web/routes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

import (
"net/http"

"github.com/abneed/bookings/pkg/config"
"github.com/abneed/bookings/pkg/handlers"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
)

func routes(app *config.AppConfig) http.Handler {
mux := chi.NewRouter()

mux.Use(middleware.Recoverer)
mux.Use(NoSurf)
mux.Use(SessionLoad)

mux.Get("/", handlers.Repo.Home)
mux.Get("/about", handlers.Repo.About)
return mux
}
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module github.com/abneed/bookings

go 1.18

require (
github.com/alexedwards/scs/v2 v2.5.0 // indirect
github.com/go-chi/chi v1.5.4 // indirect
github.com/justinas/nosurf v1.1.1 // indirect
)
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
github.com/alexedwards/scs/v2 v2.5.0 h1:zgxOfNFmiJyXG7UPIuw1g2b9LWBeRLh3PjfB9BDmfL4=
github.com/alexedwards/scs/v2 v2.5.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs=
github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg=
github.com/justinas/nosurf v1.1.1 h1:92Aw44hjSK4MxJeMSyDa7jwuI9GR2J/JCQiaKvXXSlk=
github.com/justinas/nosurf v1.1.1/go.mod h1:ALpWdSbuNGy2lZWtyXdjkYv4edL23oSEgfBT1gPJ5BQ=
17 changes: 17 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package config

import (
"html/template"
"log"

"github.com/alexedwards/scs/v2"
)

// AppConfig holds the application config
type AppConfig struct {
UseCache bool
TemplateCache map[string]*template.Template
InfoLog *log.Logger
InProduction bool
Session *scs.SessionManager
}
52 changes: 52 additions & 0 deletions pkg/handlers/handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package handlers

import (
"net/http"

"github.com/abneed/bookings/pkg/config"
"github.com/abneed/bookings/pkg/models"
"github.com/abneed/bookings/pkg/render"
)

// Repo the repository used by the handlers
var Repo *Repository

// Repository is the repository type
type Repository struct {
App *config.AppConfig
}

// NewRepo creates a new repository
func NewRepo(a *config.AppConfig) *Repository {
return &Repository{
App: a,
}
}

// NewHandlers sets the repository for the handlers
func NewHandlers(r *Repository) {
Repo = r
}

// Home is the home page handler
func (m *Repository) Home(w http.ResponseWriter, r *http.Request) {
remoteIP := r.RemoteAddr
m.App.Session.Put(r.Context(), "remote_ip", remoteIP)

render.RenderTemplate(w, "home.page.html", &models.TemplateData{})
}

// About is the about page handler
func (m *Repository) About(w http.ResponseWriter, r *http.Request) {
// perform some logic
stringMap := make(map[string]string)
stringMap["test"] = "Hello, again."

remoteIP := m.App.Session.GetString(r.Context(), "remote_ip")
stringMap["remote_ip"] = remoteIP

// send the data to the template
render.RenderTemplate(w, "about.page.html", &models.TemplateData{
StringMap: stringMap,
})
}
13 changes: 13 additions & 0 deletions pkg/models/templatedata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package models

// TemplateData holds data sent from handlers to templates
type TemplateData struct {
StringMap map[string]string
IntMap map[string]int
FloatMap map[string]float32
Data map[string]interface{}
CSRFToken string
Flash string
Warning string
Error string
}
88 changes: 88 additions & 0 deletions pkg/render/render.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package render

import (
"bytes"
"fmt"
"html/template"
"log"
"net/http"
"path/filepath"

"github.com/abneed/bookings/pkg/config"
"github.com/abneed/bookings/pkg/models"
)

var functions = template.FuncMap{}

var app *config.AppConfig

// NewTemplates sets the config for the template package
func NewTemplates(a *config.AppConfig) {
app = a
}

func AddDefaultData(td *models.TemplateData) *models.TemplateData {
return td
}

// RenderTemplate renders templates using html/template
func RenderTemplate(w http.ResponseWriter, tmpl string, td *models.TemplateData) {
var tc map[string]*template.Template

if app.UseCache {
// get the template cache from the app config
tc = app.TemplateCache
} else {
tc, _ = CreateTemplateCache()
}

t, ok := tc[tmpl]
if !ok {
log.Fatal("Could not get template from template cache")
}

buf := new(bytes.Buffer)

td = AddDefaultData(td)

_ = t.Execute(buf, td)
_, err := buf.WriteTo(w)
if err != nil {
fmt.Println("Error writing template to browser", err)
}
}

// CreateTemplateCache creates a template cache as a map
func CreateTemplateCache() (map[string]*template.Template, error) {

myCache := map[string]*template.Template{}

pages, err := filepath.Glob("./templates/*.page.html")
if err != nil {
return myCache, err
}

for _, page := range pages {
name := filepath.Base(page)
ts, err := template.New(name).Funcs(functions).ParseFiles(page)
if err != nil {
return myCache, err
}

matches, err := filepath.Glob("./templates/*layout.html")
if err != nil {
return myCache, err
}

if len(matches) > 0 {
ts, err = ts.ParseGlob("./templates/*.layout.html")
if err != nil {
return myCache, err
}
}

myCache[name] = ts
}

return myCache, nil
}
22 changes: 22 additions & 0 deletions templates/about.page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{template "base" .}}

{{define "content"}}
<div class="container">
<div class="row">
<div class="col">
<h1>This is the about page</h1>
<p>This is a paragraph of text</p>
<p>This is a paragraph of text</p>

<p>This came from the template: {{index .StringMap "test"}}</p>
<p>
{{if ne (index .StringMap "remote_ip") ""}}
Your remote IP address is {{index .StringMap "remote_ip"}}
{{else}}
I don't know your ip address yet. Visit the <a href="/">Home page</a> so I can set it.
{{end}}
</p>
</div>
</div>
</div>
{{end}}
28 changes: 28 additions & 0 deletions templates/base.layout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{{define "base"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">

{{block "css" .}}

{{end}}
</head>
<body>

{{block "content" .}}

{{end}}

{{block "js" .}}

{{end}}

</body>
</html>
{{end}}
12 changes: 12 additions & 0 deletions templates/home.page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{{template "base" .}}

{{define "content"}}
<div class="container">
<div class="row">
<div class="col">
<h1>This is the home page</h1>
<p>This is some text</p>
</div>
</div>
</div>
{{end}}

0 comments on commit bed9362

Please sign in to comment.