Compare commits

...

7 Commits

10 changed files with 261 additions and 49 deletions

41
cmd/bcrypt/bcrypt.go Normal file
View File

@@ -0,0 +1,41 @@
package main
import (
"fmt"
"os"
"golang.org/x/crypto/bcrypt"
)
func main() {
switch os.Args[1] {
case "hash":
hash(os.Args[2])
case "compare":
compare(os.Args[2], os.Args[3])
default:
fmt.Printf("Invalid command: %v\n", os.Args[1])
}
}
func hash(password string) {
fmt.Printf("Hash the password %q\n", password)
hashedBytes, err := bcrypt.GenerateFromPassword(
[]byte(password), bcrypt.DefaultCost)
if err != nil {
fmt.Printf("error hashing: %v\n", err)
return
}
hash := string(hashedBytes)
fmt.Println(hash)
}
func compare(password, hash string) {
fmt.Printf("Compare the password %q with the hash %q\n", password, hash)
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
if err != nil {
fmt.Printf("Password is invalid: %v\n", password)
return
}
fmt.Println("Password is correct!")
}

144
cmd/exp/exp.go Normal file
View File

@@ -0,0 +1,144 @@
package main
import (
"database/sql"
"fmt"
_ "github.com/jackc/pgx/v4/stdlib"
)
func AddUser(db *sql.DB, name string, email string) (error, int) {
row := db.QueryRow(`
INSERT INTO users(name, email)
VALUES($1, $2)
RETURNING id;
`, name, email)
var id int
err := row.Scan(&id)
return err, id
}
func QueryUser(db *sql.DB, id int) (error, string, string) {
row := db.QueryRow(`
SELECT name, email
FROM users
WHERE id=$1;`, id)
var name, email string
err := row.Scan(&name, &email)
return err, name, email
}
type Order struct {
ID int
UID int
Amount int
Desc string
}
func AddOrder(db *sql.DB, uid int, amount int, desc string) (error, int) {
row := db.QueryRow(`
insert into orders(user_id, amount, description)
values($1, $2, $3)
returning id;
`, uid, amount, desc)
var id int
err := row.Scan(&id)
return err, id
}
func QueryOrders(db *sql.DB, uid int) ([]Order, error) {
var orders []Order
rows, err := db.Query(`
select id, amount, description from orders where user_id=$1
`, uid)
if err != nil {
return orders, err
}
defer rows.Close()
for rows.Next() {
var order Order
order.UID = uid
err := rows.Scan(&order.ID, &order.Amount, &order.Desc)
if err != nil {
return orders, err
}
orders = append(orders, order)
}
err = rows.Err()
return orders, err
}
func main() {
db, err := sql.Open("pgx", "host=localhost port=5432 user=baloo dbname=lenslocked sslmode=disable")
if err != nil {
panic(err)
}
defer db.Close()
err = db.Ping()
if err != nil {
panic(err)
}
fmt.Println("Connected!")
_, err = db.Exec(`
create table if not exists users (
id serial primary key,
name text,
email text not null
);
create table if not exists orders (
id serial primary key,
user_id int not null,
amount int,
description text
);`)
if err != nil {
panic(err)
}
fmt.Println("Tables created")
var name string
var email string
// Create User
/*
name = "Jon Rob Baker"
email = "demo@user.com"
err, id := AddUser(db, name, email)
if err != nil {
panic(err)
}
fmt.Println("User ", id, " created")
*/
// Query User
err, name, email = QueryUser(db, 5)
if err == sql.ErrNoRows {
fmt.Println("Error, no rows!")
}
if err != nil {
panic(err)
}
fmt.Printf("User information: name=%s, email=%s\n", name, email)
uid := 5
// Create fake orders
/*
for i := 1; i <= 5; i++ {
amount := i * 100
desc := fmt.Sprintf("Fake order #%d", i)
err, _ := AddOrder(db, uid, amount, desc)
if err != nil {
panic(err)
}
}
fmt.Println("Created fake orders")
*/
// Query Orders
orders, err := QueryOrders(db, uid)
if err != nil {
panic(err)
}
fmt.Println("Orders: ", orders)
}

26
cmd/tplfn/tplfn.go Normal file
View File

@@ -0,0 +1,26 @@
package main
import (
"fmt"
"html/template"
"os"
)
func main() {
tplstr := "hello {{myFunc}}\n"
fmap := template.FuncMap{}
fmap["myFunc"] = func() (string, error) {
return "world", fmt.Errorf("hi")
}
tpl, err := template.New("demo").Funcs(fmap).Parse(tplstr)
if err != nil {
panic(fmt.Errorf("Error creating template: %v", err))
}
err = tpl.Execute(os.Stdout, nil)
if err != nil {
panic(err)
}
}

View File

@@ -4,23 +4,21 @@ import (
"git.kealoha.me/lks/lenslocked/templates" "git.kealoha.me/lks/lenslocked/templates"
"git.kealoha.me/lks/lenslocked/views" "git.kealoha.me/lks/lenslocked/views"
"net/http" "net/http"
"strings"
) )
type Template interface { type Template interface {
Execute(w http.ResponseWriter, data interface{}) Execute(w http.ResponseWriter, r *http.Request, data interface{})
} }
func StaticController(templatePath ...string) http.HandlerFunc { func StaticController(templatePath ...string) http.HandlerFunc {
tpl := views.Must(views.FromFS(templates.FS, templatePath...)) tpl := views.Must(views.FromFS(templates.FS, templatePath...))
var testWriter strings.Builder err := tpl.TestTemplate(nil)
err := tpl.ExecuteWriter(&testWriter, nil)
if err != nil { if err != nil {
panic(err) panic(err)
} }
return func(w http.ResponseWriter, r *http.Request) { tpl.Execute(w, nil) } return func(w http.ResponseWriter, r *http.Request) { tpl.Execute(w, r, nil) }
} }
func FAQ(templatePath ...string) http.HandlerFunc { func FAQ(templatePath ...string) http.HandlerFunc {
@@ -40,13 +38,12 @@ func FAQ(templatePath ...string) http.HandlerFunc {
tpl := views.Must(views.FromFS(templates.FS, templatePath...)) tpl := views.Must(views.FromFS(templates.FS, templatePath...))
var testWriter strings.Builder err := tpl.TestTemplate(nil)
err := tpl.ExecuteWriter(&testWriter, nil)
if err != nil { if err != nil {
panic(err) panic(err)
} }
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
tpl.Execute(w, questions) tpl.Execute(w, r, questions)
} }
} }

View File

@@ -2,14 +2,11 @@ package controllers
import ( import (
"fmt" "fmt"
"html/template"
"net/http" "net/http"
"strings"
"git.kealoha.me/lks/lenslocked/models" "git.kealoha.me/lks/lenslocked/models"
"git.kealoha.me/lks/lenslocked/templates" "git.kealoha.me/lks/lenslocked/templates"
"git.kealoha.me/lks/lenslocked/views" "git.kealoha.me/lks/lenslocked/views"
"github.com/gorilla/csrf"
) )
type Users struct { type Users struct {
@@ -22,12 +19,10 @@ type Users struct {
func (u Users) GetSignup(w http.ResponseWriter, r *http.Request) { func (u Users) GetSignup(w http.ResponseWriter, r *http.Request) {
var data struct { var data struct {
Email string Email string
CSRFField template.HTML
} }
data.Email = r.FormValue("email") data.Email = r.FormValue("email")
data.CSRFField = csrf.TemplateField(r) u.Templates.Signup.Execute(w, r, data)
u.Templates.Signup.Execute(w, data)
} }
func (u Users) PostSignup(w http.ResponseWriter, r *http.Request) { func (u Users) PostSignup(w http.ResponseWriter, r *http.Request) {
@@ -44,12 +39,10 @@ func (u Users) PostSignup(w http.ResponseWriter, r *http.Request) {
func (u Users) GetSignin(w http.ResponseWriter, r *http.Request) { func (u Users) GetSignin(w http.ResponseWriter, r *http.Request) {
var data struct { var data struct {
Email string Email string
CSRFField template.HTML
} }
data.Email = r.FormValue("email") data.Email = r.FormValue("email")
data.CSRFField = csrf.TemplateField(r) u.Templates.Signin.Execute(w, r, data)
u.Templates.Signin.Execute(w, data)
} }
func (u Users) PostSignin(w http.ResponseWriter, r *http.Request) { func (u Users) PostSignin(w http.ResponseWriter, r *http.Request) {
var data struct { var data struct {
@@ -67,9 +60,10 @@ func (u Users) PostSignin(w http.ResponseWriter, r *http.Request) {
// Bad cookie // Bad cookie
cookie := http.Cookie{ cookie := http.Cookie{
Name: "bad", Name: "bad",
Value: user.Email, Value: user.Email,
Path: "/", Path: "/",
HttpOnly: true,
} }
http.SetCookie(w, &cookie) http.SetCookie(w, &cookie)
@@ -97,12 +91,11 @@ func Default(user_service *models.UserService, templatePath ...string) Users {
signup_tpl := views.Must(views.FromFS(templates.FS, "signup.gohtml", "tailwind.gohtml")) signup_tpl := views.Must(views.FromFS(templates.FS, "signup.gohtml", "tailwind.gohtml"))
signin_tpl := views.Must(views.FromFS(templates.FS, "signin.gohtml", "tailwind.gohtml")) signin_tpl := views.Must(views.FromFS(templates.FS, "signin.gohtml", "tailwind.gohtml"))
var testWriter strings.Builder err := signup_tpl.TestTemplate(nil)
err := signup_tpl.ExecuteWriter(&testWriter, nil)
if err != nil { if err != nil {
panic(err) panic(err)
} }
err = signin_tpl.ExecuteWriter(&testWriter, nil) err = signin_tpl.TestTemplate(nil)
if err != nil { if err != nil {
panic(err) panic(err)
} }

5
go.mod
View File

@@ -6,11 +6,10 @@ require (
github.com/go-chi/chi/v5 v5.1.0 github.com/go-chi/chi/v5 v5.1.0
github.com/jackc/pgx/v4 v4.18.3 github.com/jackc/pgx/v4 v4.18.3
golang.org/x/crypto v0.26.0 golang.org/x/crypto v0.26.0
google.golang.org/grpc v1.65.0
) )
require ( require (
github.com/gorilla/csrf v1.7.2 // indirect github.com/gorilla/csrf v1.7.2
github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/securecookie v1.1.2 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.14.3 // indirect github.com/jackc/pgconn v1.14.3 // indirect
@@ -19,7 +18,5 @@ require (
github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgtype v1.14.0 // indirect github.com/jackc/pgtype v1.14.0 // indirect
golang.org/x/sys v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect golang.org/x/text v0.17.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
) )

14
go.sum
View File

@@ -16,8 +16,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI= github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI=
github.com/gorilla/csrf v1.7.2/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk= github.com/gorilla/csrf v1.7.2/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk=
@@ -142,8 +142,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -157,8 +155,6 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -181,12 +177,6 @@ golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=

View File

@@ -9,7 +9,7 @@
Welcome back! Welcome back!
</h1> </h1>
<form action="/signin" method="post"> <form action="/signin" method="post">
{{.CSRFField}} {{csrfField}}
<div class="py-2"> <div class="py-2">
<label for="email" class="text-sm font-semibold text-gray-800"> <label for="email" class="text-sm font-semibold text-gray-800">
Email Address Email Address

View File

@@ -10,7 +10,7 @@
Sign Up! Sign Up!
</h1> </h1>
<form action="/signup" method="post"> <form action="/signup" method="post">
{{.CSRFField}} {{csrfField}}
<div> <div>
<label for="signupEmail" class="text-sm font-semibold text-gray-800">Email Address</label> <label for="signupEmail" class="text-sm font-semibold text-gray-800">Email Address</label>
<input name="email" id="signupEmail" type="email" placeholder="Email address" required autocomplete="email" <input name="email" id="signupEmail" type="email" placeholder="Email address" required autocomplete="email"

View File

@@ -3,28 +3,46 @@ package views
import ( import (
"fmt" "fmt"
"html/template" "html/template"
"io"
"io/fs" "io/fs"
"log" "log"
"net/http" "net/http"
"os" "os"
"strings"
"github.com/gorilla/csrf"
) )
type Template struct { type Template struct {
htmlTpl *template.Template htmlTpl *template.Template
} }
func (t Template) Execute(w http.ResponseWriter, data interface{}) { func (t Template) Execute(w http.ResponseWriter, r *http.Request, data interface{}) {
tpl, err := t.htmlTpl.Clone()
if err != nil {
log.Printf("Template Clone Error: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
tpl = tpl.Funcs(template.FuncMap{
"csrfField": func() template.HTML { return csrf.TemplateField(r) },
})
w.Header().Set("Content-Type", "text/html; charset=utf8") w.Header().Set("Content-Type", "text/html; charset=utf8")
err := t.htmlTpl.Execute(w, data) err = tpl.Execute(w, data)
if err != nil { if err != nil {
log.Printf("Error executing template: %v", err) log.Printf("Error executing template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError) http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return return
} }
} }
func (t Template) ExecuteWriter(w io.Writer, data interface{}) error { func (t Template) TestTemplate(data interface{}) error {
return t.htmlTpl.Execute(w, data) var testWriter strings.Builder
tpl, err := t.htmlTpl.Clone()
if err != nil {
return err
}
return tpl.Execute(&testWriter, data)
} }
func FromFile(pattern ...string) (Template, error) { func FromFile(pattern ...string) (Template, error) {
@@ -32,7 +50,13 @@ func FromFile(pattern ...string) (Template, error) {
return FromFS(fs, pattern...) return FromFS(fs, pattern...)
} }
func FromFS(fs fs.FS, pattern ...string) (Template, error) { func FromFS(fs fs.FS, pattern ...string) (Template, error) {
tpl, err := template.ParseFS(fs, pattern...) tpl := template.New(pattern[0])
tpl = tpl.Funcs(template.FuncMap{
"csrfField": func() template.HTML {
return `<div class="hidden">STUB: PLACEHOLDER</div>`
},
})
tpl, err := tpl.ParseFS(fs, pattern...)
if err != nil { if err != nil {
return Template{}, fmt.Errorf("Error parsing template: %v", err) return Template{}, fmt.Errorf("Error parsing template: %v", err)
} }