Author | Jakob Wakeling <[email protected]> |
Date | 2023-07-19 10:07:36 |
Commit | 17c34f47738b5ccbed6a6f6906e167c673e962b4 |
Parent | 1828e5fb2957c068734703ded8c0b6144b9bba3d |
Make use of nested Go HTML templates
Diffstat
M | main.go | | | 14 | +++++++++++++- |
A | res/base/head.html.tmpl | | | 7 | +++++++ |
A | res/base/repo_header.html.tmpl | | | 29 | +++++++++++++++++++++++++++++ |
R | res/error.html -> res/error.html.tmpl | | | 0 | |
M | res/repo_index.html | | | 54 | +++++++++++++++++++++++++----------------------------- |
M | res/repo_log.html | | | 38 | ++------------------------------------ |
M | res/repo_refs.html | | | 29 | ++++------------------------- |
M | res/repo_tree.html | | | 61 | ++++++++++++++++++++----------------------------------------- |
M | res/res.go | | | 12 | +++++++++--- |
M | src/goit.go | | | 13 | +++++++++++-- |
M | src/http.go | | | 18 | ++++++++++++++++-- |
M | src/repo.go | | | 53 | +++++++++++++++++++++++++---------------------------- |
12 files changed, 161 insertions, 167 deletions
diff --git a/main.go b/main.go index 63f947d..0f97b7b 100644 --- a/main.go +++ b/main.go @@ -45,6 +45,7 @@ func main() { h.Path("/{repo}/git-receive-pack").Methods(http.MethodPost).HandlerFunc(goit.HandleReceivePack) h.Path("/static/style.css").Methods(http.MethodGet).HandlerFunc(handleStyle) + h.Path("/static/favicon.png").Methods(http.MethodGet).HandlerFunc(handleFavicon) h.PathPrefix("/").HandlerFunc(goit.HttpNotFound) @@ -70,12 +71,23 @@ func logHttp(handler http.Handler) http.Handler { } func handleStyle(w http.ResponseWriter, r *http.Request) { - w.Header().Add("Content-Type", "text/css") + w.Header().Set("Content-Type", "text/css") if _, err := w.Write([]byte(res.Style)); err != nil { log.Println("[Style]", err.Error()) } } +func handleFavicon(w http.ResponseWriter, r *http.Request) { + if goit.Favicon == nil { + goit.HttpError(w, http.StatusNotFound) + } else { + w.Header().Set("Content-Type", "image/png") + if _, err := w.Write(goit.Favicon); err != nil { + log.Println("[Favicon]", err.Error()) + } + } +} + func redirectDotGit(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, strings.TrimSuffix(r.URL.Path, ".git"), http.StatusMovedPermanently) } diff --git a/res/base/head.html.tmpl b/res/base/head.html.tmpl new file mode 100644 index 0000000..5f5135a --- /dev/null +++ b/res/base/head.html.tmpl @@ -0,0 +1,7 @@ +{{define "base/head"}} +<meta charset="UTF-8"> +<title>{{.Title}}</title> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<link rel="stylesheet" type="text/css" href="/static/style.css"> +<link rel="icon" type="image/png" href="/static/favicon.png"> +{{end}} diff --git a/res/base/repo_header.html.tmpl b/res/base/repo_header.html.tmpl new file mode 100644 index 0000000..b25b18e --- /dev/null +++ b/res/base/repo_header.html.tmpl @@ -0,0 +1,29 @@ +<table> + <tr> + <td rowspan="2"><a href="/"> + <img style="max-height: 24px;" src="/static/favicon.png"> + </a></td> + <td><h1>{{.Name}}</h1></td> + </tr> + <tr> + <td>{{.Description}}</td> + </tr> + <tr> + <td></td> + <td>git clone <a href="{{.Url}}">{{.Url}}</a></td> + </tr> + <tr> + <td></td> + <td> + <a href="/{{.Name}}/log">Log</a> + | <a href="/{{.Name}}/tree">Tree</a> + | <a href="/{{.Name}}/refs">Refs</a> + {{if .HasReadme}} + | <a href="">README</a> + {{end}} + {{if .HasLicence}} + | <a href="">LICENCE</a> + {{end}} + </td> + </tr> +</table> diff --git a/res/error.html b/res/error.html.tmpl similarity index 100% rename from res/error.html rename to res/error.html.tmpl diff --git a/res/repo_index.html b/res/repo_index.html index 2662bd3..49e67a2 100644 --- a/res/repo_index.html +++ b/res/repo_index.html @@ -1,32 +1,28 @@ <!DOCTYPE html> -<head> - <meta charset="UTF-8"> - <title>Repositories</title> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <link rel="stylesheet" type="text/css" href="/static/style.css"> - <link rel="icon" type="image/png" href="/static/favicon.png"> -</head> +<head>{{template "base/head" .}}</head> <body> - <table> - <thead> - <tr> - <td><b>Name</b></td> - <td><b>Description</b></td> - <td><b>Owner</b></td> - <td><b>Visibility</b></td> - <td><b>Last Commit</b></td> - </tr> - </thead> - <tbody> - {{range .Repos}} - <tr> - <td><a href="/{{.Name}}/">{{.Name}}</a></td> - <td>{{.Description}}</td> - <td>{{.Owner}}</td> - <td>{{.Visibility}}</td> - <td>{{.LastCommit}}</td> - </tr> - {{end}} - </tbody> - </table> + <main> + <table> + <thead> + <tr> + <td><b>Name</b></td> + <td><b>Description</b></td> + <td><b>Owner</b></td> + <td><b>Visibility</b></td> + <td><b>Last Commit</b></td> + </tr> + </thead> + <tbody> + {{range .Repos}} + <tr> + <td><a href="/{{.Name}}/">{{.Name}}</a></td> + <td>{{.Description}}</td> + <td>{{.Owner}}</td> + <td>{{.Visibility}}</td> + <td>{{.LastCommit}}</td> + </tr> + {{end}} + </tbody> + </table> + </main> </body> diff --git a/res/repo_log.html b/res/repo_log.html index 999aa88..4c1aeac 100644 --- a/res/repo_log.html +++ b/res/repo_log.html @@ -1,41 +1,7 @@ <!DOCTYPE html> -<head> - <meta charset="UTF-8"> - <title>Log</title> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <link rel="stylesheet" type="text/css" href="/static/style.css"> - <link rel="icon" type="image/png" href="/static/favicon.png"> -</head> +<head>{{template "base/head" .}}</head> <body> - <header> - <table> - <tr> - <td rowspan="2"><a href="/"><img style="max-height: 22px;" src=""></a></td> - <td><h1>{{.Name}}</h1></td> - </tr> - <tr> - <td>{{.Description}}</td> - </tr> - <tr> - <td></td> - <td>git clone <a href="{{.Url}}">{{.Url}}</a></td> - </tr> - <tr> - <td></td> - <td> - <a href="/{{.Name}}/log">Log</a> - | <a href="/{{.Name}}/tree">Tree</a> - | <a href="/{{.Name}}/refs">Refs</a> - {{if .HasReadme}} - | <a href="">README</a> - {{end}} - {{if .HasLicence}} - | <a href="">LICENCE</a> - {{end}} - </td> - </tr> - </table> - </header><hr> + <header>{{template "base/repo_header" .}}</header><hr> <main> {{if .Commits}} <table> diff --git a/res/repo_refs.html b/res/repo_refs.html index 9fc5f00..b250660 100644 --- a/res/repo_refs.html +++ b/res/repo_refs.html @@ -1,30 +1,8 @@ <!DOCTYPE html> -<head> - <meta charset="UTF-8"> - <title>Refs</title> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <link rel="stylesheet" type="text/css" href="/static/style.css"> - <link rel="icon" type="image/png" href="/static/favicon.png"> -</head> +<head>{{template "base/head" .}}</head> <body> - <table> - <tr><td><h1>{{.Name}}</h1></td></tr> - <tr><td><span>{{.Description}}</span></td></tr> - <tr><td>git clone <a href="{{.Url}}">{{.Url}}</a></td></tr> - <tr> - <td> - <a href="/{{.Name}}/log">Log</a> - | <a href="/{{.Name}}/tree">Tree</a> - | <a href="/{{.Name}}/refs">Refs</a> - {{if .HasReadme}} - | <a href="">README</a> - {{end}} - {{if .HasLicence}} - | <a href="">LICENCE</a> - {{end}} - </td> - </tr> - </table><hr> + <header>{{template "base/repo_header" .}}</header><hr> + <main> {{if .Branches}} <h2>Branches</h2> <table> @@ -63,4 +41,5 @@ </tbody> </table> {{end}} + </main> </body> diff --git a/res/repo_tree.html b/res/repo_tree.html index ca65c95..4ca17bc 100644 --- a/res/repo_tree.html +++ b/res/repo_tree.html @@ -1,44 +1,23 @@ <!DOCTYPE html> -<head> - <meta charset="UTF-8"> - <title>Tree</title> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <link rel="stylesheet" type="text/css" href="/static/style.css"> - <link rel="icon" type="image/png" href="/static/favicon.png"> -</head> +<head>{{template "base/head" .}}</head> <body> - <table> - <tr><td><h1>{{.Name}}</h1></td></tr> - <tr><td><span>{{.Description}}</span></td></tr> - <tr><td>git clone <a href="{{.Url}}">{{.Url}}</a></td></tr> - <tr> - <td> - <a href="/{{.Name}}/log">Log</a> - | <a href="/{{.Name}}/tree">Tree</a> - | <a href="/{{.Name}}/refs">Refs</a> - {{if .HasReadme}} - | <a href="">README</a> - {{end}} - {{if .HasLicence}} - | <a href="">LICENCE</a> - {{end}} - </td> - </tr> - </table><hr> - <table> - <thead> - <tr> - <td><b>Name</b></td> - <td><b>Size</b></td> - </tr> - </thead> - <tbody> - {{range .Files}} - <tr> - <td>{{.Name}}</a></td> - <td>{{.Size}}</td> - </tr> - {{end}} - </tbody> - </table> + <header>{{template "base/repo_header" .}}</header><hr> + <main> + <table> + <thead> + <tr> + <td><b>Name</b></td> + <td><b>Size</b></td> + </tr> + </thead> + <tbody> + {{range .Files}} + <tr> + <td>{{.Name}}</a></td> + <td>{{.Size}}</td> + </tr> + {{end}} + </tbody> + </table> + </main> </body> diff --git a/res/res.go b/res/res.go index cb3647b..0f1cd3a 100644 --- a/res/res.go +++ b/res/res.go @@ -2,6 +2,15 @@ package res import _ "embed" +//go:embed error.html.tmpl +var Error string + +//go:embed base/head.html.tmpl +var BaseHead string + +//go:embed base/repo_header.html.tmpl +var RepoHeader string + //go:embed repo_index.html var RepoIndex string @@ -26,8 +35,5 @@ var UserCreate string //go:embed admin_user_index.html var AdminUserIndex string -//go:embed error.html -var Error string - //go:embed style.css var Style string diff --git a/src/goit.go b/src/goit.go index 7553fc4..22634d0 100644 --- a/src/goit.go +++ b/src/goit.go @@ -31,6 +31,7 @@ var config = Config{ } var db *sql.DB +var Favicon []byte /* Initialise Goit. */ func InitGoit(conf string) (err error) { @@ -44,6 +45,14 @@ func InitGoit(conf string) (err error) { } } + if dat, err := os.ReadFile(path.Join(config.DataPath, "favicon.png")); err != nil { + if !errors.Is(err, os.ErrNotExist) { + return fmt.Errorf("[Config] %w", err) + } + } else { + Favicon = dat + } + if db, err = sql.Open("sqlite3", path.Join(config.DataPath, "goit.db")); err != nil { return fmt.Errorf("[Database] %w", err) } @@ -96,6 +105,6 @@ func InitGoit(conf string) (err error) { return nil } -func GetRepoPath(username, reponame string) string { - return path.Join(config.DataPath, "repos", username, reponame+".git") +func GetRepoPath(name string) string { + return path.Join(config.DataPath, "repos", name+".git") } diff --git a/src/http.go b/src/http.go index d2e2162..37cb9df 100644 --- a/src/http.go +++ b/src/http.go @@ -8,12 +8,26 @@ import ( "github.com/Jamozed/Goit/res" ) -var htmlError *template.Template = template.Must(template.New("error").Parse(res.Error)) +var tmpl = template.Must(template.New("error").Parse(res.Error)) + +func init() { + tmpl.Option("missingkey=zero") + + template.Must(tmpl.New("base/head").Parse(res.BaseHead)) + template.Must(tmpl.New("base/repo_header").Parse(res.RepoHeader)) + + template.Must(tmpl.New("repo_index").Parse(res.RepoIndex)) + template.Must(tmpl.New("repo_create").Parse(res.RepoCreate)) + + template.Must(tmpl.New("repo_log").Parse(res.RepoLog)) + template.Must(tmpl.New("repo_tree").Parse(res.RepoTree)) + template.Must(tmpl.New("repo_refs").Parse(res.RepoRefs)) +} func HttpError(w http.ResponseWriter, code int) { w.WriteHeader(code) s := fmt.Sprint(code) + " " + http.StatusText(code) - htmlError.Execute(w, struct{ Status string }{s}) + tmpl.ExecuteTemplate(w, "error", struct{ Status string }{s}) } func HttpNotFound(w http.ResponseWriter, r *http.Request) { diff --git a/src/repo.go b/src/repo.go index 400e9d2..4220c8b 100644 --- a/src/repo.go +++ b/src/repo.go @@ -7,13 +7,11 @@ package goit import ( "database/sql" "errors" - "html/template" "log" "net/http" "strings" "time" - "github.com/Jamozed/Goit/res" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" @@ -30,14 +28,6 @@ type Repo struct { IsPrivate bool } -var ( - repoIndex *template.Template = template.Must(template.New("repo_index").Parse(res.RepoIndex)) - repoCreate *template.Template = template.Must(template.New("repo_create").Parse(res.RepoCreate)) - repoLog *template.Template = template.Must(template.New("repo_log").Parse(res.RepoLog)) - repoTree *template.Template = template.Must(template.New("repo_tree").Parse(res.RepoTree)) - repoRefs *template.Template = template.Must(template.New("repo_refs").Parse(res.RepoRefs)) -) - func HandleIndex(w http.ResponseWriter, r *http.Request) { authOk, uid := AuthHttp(r) @@ -68,8 +58,11 @@ func HandleIndex(w http.ResponseWriter, r *http.Request) { if err := rows.Err(); err != nil { log.Println("[Index:SELECT:Err]", err.Error()) HttpError(w, http.StatusInternalServerError) - } else { - repoIndex.Execute(w, struct{ Repos []row }{repos}) + } else if err := tmpl.ExecuteTemplate(w, "repo_index", struct { + Title string + Repos []row + }{"Repositories", repos}); err != nil { + log.Println("[Repo:Index]", err.Error()) } } } @@ -85,9 +78,9 @@ func HandleRepoCreate(w http.ResponseWriter, r *http.Request) { log.Println("[RepoCreate:RepoExists]", err.Error()) HttpError(w, http.StatusInternalServerError) } else if taken { - repoCreate.Execute(w, struct{ Msg string }{"Reponame is taken"}) + tmpl.ExecuteTemplate(w, "repo_create", struct{ Msg string }{"Reponame is taken"}) } else if SliceContains[string](reserved, name) { - repoCreate.Execute(w, struct{ Msg string }{"Reponame is reserved"}) + tmpl.ExecuteTemplate(w, "repo_create", struct{ Msg string }{"Reponame is reserved"}) } else { if _, err := db.Exec( `INSERT INTO repos ( @@ -102,7 +95,7 @@ func HandleRepoCreate(w http.ResponseWriter, r *http.Request) { } } } else /* GET */ { - repoCreate.Execute(w, nil) + tmpl.ExecuteTemplate(w, "repo_create", nil) } } @@ -121,7 +114,7 @@ func HandleRepoLog(w http.ResponseWriter, r *http.Request) { type row struct{ Date, Message, Author string } commits := []row{} - if gr, err := git.PlainOpen("./" + reponame + ".git"); err != nil { + if gr, err := git.PlainOpen(GetRepoPath(reponame)); err != nil { log.Println("[Repo:Log]", err.Error()) HttpError(w, http.StatusInternalServerError) return @@ -144,11 +137,13 @@ func HandleRepoLog(w http.ResponseWriter, r *http.Request) { return } - if err := repoLog.Execute(w, struct { - Name, Description, Url string - HasReadme, HasLicence bool - Commits []row - }{reponame, repo.Description, r.URL.Host + "/" + repo.Name + ".git", false, false, commits}); err != nil { + if err := tmpl.ExecuteTemplate(w, "repo_log", struct { + Title, Name, Description, Url string + HasReadme, HasLicence bool + Commits []row + }{ + "Log", reponame, repo.Description, r.URL.Host + "/" + repo.Name + ".git", false, false, commits, + }); err != nil { log.Println("[Repo:Log]", err.Error()) } } @@ -174,7 +169,7 @@ func HandleRepoRefs(w http.ResponseWriter, r *http.Request) { bras := []bra{} tags := []tag{} - if gr, err := git.PlainOpen("./" + reponame + ".git"); err != nil { + if gr, err := git.PlainOpen(GetRepoPath(reponame)); err != nil { log.Println("[Repo:Refs]", err.Error()) HttpError(w, http.StatusInternalServerError) return @@ -202,12 +197,14 @@ func HandleRepoRefs(w http.ResponseWriter, r *http.Request) { return } - if err := repoRefs.Execute(w, struct { - Name, Description, Url string - HasReadme, HasLicence bool - Branches []bra - Tags []tag - }{reponame, repo.Description, r.URL.Host + "/" + repo.Name + ".git", false, false, bras, tags}); err != nil { + if err := tmpl.ExecuteTemplate(w, "repo_refs", struct { + Title, Name, Description, Url string + HasReadme, HasLicence bool + Branches []bra + Tags []tag + }{ + "Refs", reponame, repo.Description, r.URL.Host + "/" + repo.Name + ".git", false, false, bras, tags, + }); err != nil { log.Println("[Repo:Refs]", err.Error()) } }