M client.go => client.go +4 -6
@@ 46,13 46,12 @@ func manageClient(w http.ResponseWriter, req *http.Request) {
if req.Method != http.MethodPost {
data := struct {
+ TemplateBaseData
Client *Client
}{
Client: client,
}
- if err := tpl.ExecuteTemplate(w, "manage-client.html", &data); err != nil {
- panic(err)
- }
+ tpl.MustExecuteTemplate(w, "manage-client.html", &data)
return
}
@@ 107,15 106,14 @@ func manageClient(w http.ResponseWriter, req *http.Request) {
}
data := struct {
+ TemplateBaseData
ClientID string
ClientSecret string
}{
ClientID: client.ClientID,
ClientSecret: clientSecret,
}
- if err := tpl.ExecuteTemplate(w, "client-secret.html", &data); err != nil {
- panic(err)
- }
+ tpl.MustExecuteTemplate(w, "client-secret.html", &data)
}
func validateAllowedRedirectURIs(rawRedirectURIs string) error {
M config.go => config.go +3 -2
@@ 7,8 7,9 @@ import (
)
type Config struct {
- Listen string `scfg:"listen"`
- Database string `scfg:"database"`
+ Listen string `scfg:"listen"`
+ Database string `scfg:"database"`
+ ServerName string `scfg:"server-name"`
}
func loadConfig(filename string) (*Config, error) {
M config.in => config.in +1 -0
@@ 1,2 1,3 @@
listen localhost:8080
database /var/lib/sinwon/main.db
+server-name sinwon
M main.go => main.go +10 -2
@@ 4,7 4,6 @@ import (
"context"
"embed"
"flag"
- "html/template"
"log"
"net"
"net/http"
@@ 46,7 45,16 @@ func main() {
log.Fatalf("Failed to open DB: %v", err)
}
- tpl := template.Must(template.ParseFS(templateFS, "template/*.html"))
+ tplBaseData := &TemplateBaseData{
+ ServerName: cfg.ServerName,
+ }
+ if tplBaseData.ServerName == "" {
+ tplBaseData.ServerName = "sinwon"
+ }
+ tpl, err := loadTemplate(templateFS, "template/*.html", tplBaseData)
+ if err != nil {
+ log.Fatalf("Failed to load template: %v", err)
+ }
mux := chi.NewRouter()
mux.Handle("/static/*", http.FileServer(http.FS(staticFS)))
M middleware.go => middleware.go +41 -3
@@ 4,6 4,8 @@ import (
"context"
"fmt"
"html/template"
+ "io"
+ "io/fs"
"mime"
"net/http"
)
@@ 25,8 27,8 @@ func dbFromContext(ctx context.Context) *DB {
return ctx.Value(contextKeyDB).(*DB)
}
-func templateFromContext(ctx context.Context) *template.Template {
- return ctx.Value(contextKeyTemplate).(*template.Template)
+func templateFromContext(ctx context.Context) *Template {
+ return ctx.Value(contextKeyTemplate).(*Template)
}
func loginTokenFromContext(ctx context.Context) *AccessToken {
@@ 37,7 39,7 @@ func loginTokenFromContext(ctx context.Context) *AccessToken {
return v.(*AccessToken)
}
-func newBaseContext(db *DB, tpl *template.Template) context.Context {
+func newBaseContext(db *DB, tpl *Template) context.Context {
ctx := context.Background()
ctx = context.WithValue(ctx, contextKeyDB, db)
ctx = context.WithValue(ctx, contextKeyTemplate, tpl)
@@ 109,3 111,39 @@ func loginTokenMiddleware(next http.Handler) http.Handler {
next.ServeHTTP(w, req)
})
}
+
+type TemplateBaseData struct {
+ ServerName string
+}
+
+func (data *TemplateBaseData) Base() *TemplateBaseData {
+ return data
+}
+
+type TemplateData interface {
+ Base() *TemplateBaseData
+}
+
+type Template struct {
+ tpl *template.Template
+ baseData *TemplateBaseData
+}
+
+func loadTemplate(fs fs.FS, pattern string, baseData *TemplateBaseData) (*Template, error) {
+ tpl, err := template.ParseFS(fs, pattern)
+ if err != nil {
+ return nil, err
+ }
+ return &Template{tpl: tpl, baseData: baseData}, nil
+}
+
+func (tpl *Template) MustExecuteTemplate(w io.Writer, filename string, data TemplateData) {
+ if data == nil {
+ data = tpl.baseData
+ } else {
+ *data.Base() = *tpl.baseData
+ }
+ if err := tpl.tpl.ExecuteTemplate(w, filename, data); err != nil {
+ panic(err)
+ }
+}
M oauth2.go => oauth2.go +2 -3
@@ 148,13 148,12 @@ func authorize(w http.ResponseWriter, req *http.Request) {
}
if _, ok := req.PostForm["authorize"]; !ok {
data := struct {
+ TemplateBaseData
Client *Client
}{
Client: client,
}
- if err := tpl.ExecuteTemplate(w, "authorize.html", data); err != nil {
- panic(err)
- }
+ tpl.MustExecuteTemplate(w, "authorize.html", &data)
return
}
M template/authorize.html => template/authorize.html +2 -2
@@ 1,8 1,8 @@
-{{ template "head.html" }}
+{{ template "head.html" .Base }}
<main>
-<h1>sinwon</h1>
+<h1>{{ .ServerName }}</h1>
<p>
Authorize
M template/client-secret.html => template/client-secret.html +2 -2
@@ 1,8 1,8 @@
-{{ template "head.html" }}
+{{ template "head.html" .Base }}
<main>
-<h1>sinwon</h1>
+<h1>{{ .ServerName }}</h1>
<p>
<strong>Client ID</strong>: <code>{{ .ClientID }}</code><br>
M template/head.html => template/head.html +1 -1
@@ 2,7 2,7 @@
<html lang="en">
<head>
<meta charset="utf-8"/>
- <title>sinwon</title>
+ <title>{{ .ServerName }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="stylesheet" href="/static/style.css"/>
</head>
M template/index.html => template/index.html +2 -2
@@ 1,8 1,8 @@
-{{ template "head.html" }}
+{{ template "head.html" .Base }}
<main>
-<h1>sinwon</h1>
+<h1>{{ .ServerName }}</h1>
<p>Welcome, {{ .Me.Username }}!</p>
M template/login.html => template/login.html +2 -2
@@ 1,8 1,8 @@
-{{ template "head.html" }}
+{{ template "head.html" .Base }}
<main>
-<h1>sinwon</h1>
+<h1>{{ .ServerName }}</h1>
<form method="post" action="">
Username: <input type="text" name="username" autocomplete="username"><br>
M template/manage-client.html => template/manage-client.html +2 -2
@@ 1,8 1,8 @@
-{{ template "head.html" }}
+{{ template "head.html" .Base }}
<main>
-<h1>sinwon</h1>
+<h1>{{ .ServerName }}</h1>
<form method="post" action="">
{{ if .Client.ClientID }}
M template/manage-user.html => template/manage-user.html +2 -2
@@ 1,8 1,8 @@
-{{ template "head.html" }}
+{{ template "head.html" .Base }}
<main>
-<h1>sinwon</h1>
+<h1>{{ .ServerName }}</h1>
<form method="post" action="">
Username: <input type="text" name="username" value="{{ .User.Username }}" required><br>
M user.go => user.go +6 -12
@@ 49,6 49,7 @@ func index(w http.ResponseWriter, req *http.Request) {
}
data := struct {
+ TemplateBaseData
Me *User
AuthorizedClients []AuthorizedClient
Clients []Client
@@ 59,9 60,7 @@ func index(w http.ResponseWriter, req *http.Request) {
Clients: clients,
Users: users,
}
- if err := tpl.ExecuteTemplate(w, "index.html", &data); err != nil {
- panic(err)
- }
+ tpl.MustExecuteTemplate(w, "index.html", &data)
}
func login(w http.ResponseWriter, req *http.Request) {
@@ 89,9 88,7 @@ func login(w http.ResponseWriter, req *http.Request) {
username := req.PostFormValue("username")
password := req.PostFormValue("password")
if username == "" {
- if err := tpl.ExecuteTemplate(w, "login.html", nil); err != nil {
- panic(err)
- }
+ tpl.MustExecuteTemplate(w, "login.html", nil)
return
}
@@ 106,9 103,7 @@ func login(w http.ResponseWriter, req *http.Request) {
if err != nil {
log.Printf("login failed for user %q: %v", username, err)
// TODO: show error message
- if err := tpl.ExecuteTemplate(w, "login.html", nil); err != nil {
- panic(err)
- }
+ tpl.MustExecuteTemplate(w, "login.html", nil)
return
}
@@ 186,15 181,14 @@ func manageUser(w http.ResponseWriter, req *http.Request) {
admin := req.PostFormValue("admin") == "on"
if username == "" {
data := struct {
+ TemplateBaseData
User *User
Me *User
}{
User: user,
Me: me,
}
- if err := tpl.ExecuteTemplate(w, "manage-user.html", &data); err != nil {
- panic(err)
- }
+ tpl.MustExecuteTemplate(w, "manage-user.html", &data)
return
}