Author | Jakob Wakeling <[email protected]> |
Date | 2023-07-18 12:40:45 |
Commit | 8abd3436c0a348d9a084e4a83a16e028ca2e8199 |
Parent | e08e053ce424bcb899dfb39b0028011762819ce9 |
Implement repository refs page
Diffstat
M | main.go | | | 14 | ++++++++++---- |
M | res/admin_user_index.html | | | 1 | + |
A | res/error.html | | | 11 | +++++++++++ |
M | res/repo_create.html | | | 3 | ++- |
M | res/repo_index.html | | | 1 | + |
M | res/repo_log.html | | | 21 | ++++++++++++++++++++- |
A | res/repo_refs.html | | | 62 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | res/repo_tree.html | | | 44 | ++++++++++++++++++++++++++++++++++++++++++++ |
M | res/res.go | | | 9 | +++++++++ |
M | res/style.css | | | 6 | ++++-- |
M | res/user_create.html | | | 1 | + |
M | res/user_login.html | | | 3 | ++- |
M | src/admin.go | | | 22 | +++++++++++----------- |
M | src/git.go | | | 18 | +++++++++--------- |
A | src/http.go | | | 21 | +++++++++++++++++++++ |
M | src/repo.go | | | 119 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------- |
M | src/user.go | | | 15 | +++++---------- |
17 files changed, 310 insertions, 61 deletions
diff --git a/main.go b/main.go index 2977ff6..0ef7922 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ package main import ( "log" "net/http" + "strings" "time" "github.com/Jamozed/Goit/res" @@ -37,17 +38,18 @@ func main() { h.Path("/admin/user/create").Methods("GET", "POST").HandlerFunc(g.HandleAdminUserCreate) // h.Path("/admin/user/edit").Methods("GET", "POST").HandlerFunc() - h.Path("/{repo}/").Methods(http.MethodGet).HandlerFunc(g.HandleRepoLog) + h.Path("/{repo:.+(?:\\.git)$}").Methods(http.MethodGet).HandlerFunc(redirectDotGit) + h.Path("/{repo}").Methods(http.MethodGet).HandlerFunc(g.HandleRepoLog) h.Path("/{repo}/log").Methods(http.MethodGet).HandlerFunc(g.HandleRepoLog) - // h.Path("/{repo}/tree").Methods(http.MethodGet).HandlerFunc(g.HandleRepoTree) - // h.Path("/{repo}/refs").Methods(http.MethodGet).HandlerFunc(g.HandleRepoRefs) + h.Path("/{repo}/tree").Methods(http.MethodGet).HandlerFunc(g.HandleRepoTree) + h.Path("/{repo}/refs").Methods(http.MethodGet).HandlerFunc(g.HandleRepoRefs) h.Path("/{repo}/info/refs").Methods(http.MethodGet).HandlerFunc(goit.HandleInfoRefs) h.Path("/{repo}/git-upload-pack").Methods(http.MethodPost).HandlerFunc(goit.HandleUploadPack) h.Path("/{repo}/git-receive-pack").Methods(http.MethodPost).HandlerFunc(goit.HandleReceivePack) h.Path("/static/style.css").Methods(http.MethodGet).HandlerFunc(handleStyle) - h.PathPrefix("/").HandlerFunc(http.NotFound) + h.PathPrefix("/").HandlerFunc(goit.HttpNotFound) /* Create a ticker to periodically cleanup expired sessions */ tick := time.NewTicker(1 * time.Hour) @@ -75,3 +77,7 @@ func handleStyle(w http.ResponseWriter, r *http.Request) { log.Println("[handleStyle]", 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/admin_user_index.html b/res/admin_user_index.html index ed84ecd..08bc819 100644 --- a/res/admin_user_index.html +++ b/res/admin_user_index.html @@ -4,6 +4,7 @@ <title>Users</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> <body> <table> diff --git a/res/error.html b/res/error.html new file mode 100644 index 0000000..1a00cdc --- /dev/null +++ b/res/error.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<head> + <meta charset="UTF-8"> + <title>{{.Status}}</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> +<body> + <b>{{.Status}}</b> +</body> diff --git a/res/repo_create.html b/res/repo_create.html index dd04bad..7fd3740 100644 --- a/res/repo_create.html +++ b/res/repo_create.html @@ -3,7 +3,8 @@ <meta charset="UTF-8"> <title>Create Repository</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <link rel="stylesheet" href="/static/style.css"> + <link rel="stylesheet" type="text/css" href="/static/style.css"> + <link rel="icon" type="image/png" href="/static/favicon.png"> </head> <body> <form action="/repo/create" method="post"> diff --git a/res/repo_index.html b/res/repo_index.html index 450097b..2662bd3 100644 --- a/res/repo_index.html +++ b/res/repo_index.html @@ -4,6 +4,7 @@ <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> <body> <table> diff --git a/res/repo_log.html b/res/repo_log.html index 4dbd5b1..113d825 100644 --- a/res/repo_log.html +++ b/res/repo_log.html @@ -1,11 +1,30 @@ <!DOCTYPE html> <head> <meta charset="UTF-8"> - <title>Repositories</title> + <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> <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> diff --git a/res/repo_refs.html b/res/repo_refs.html new file mode 100644 index 0000000..19fc5d3 --- /dev/null +++ b/res/repo_refs.html @@ -0,0 +1,62 @@ +<!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> +<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> + <h2>Branches</h2> + <table> + <thead> + <tr> + <td><b>Name</b></td> + <td><b>Hash</b></td> + </tr> + </thead> + <tbody> + {{range .Branches}} + <tr> + <td>{{.Name}}</a></td> + <td>{{.Hash}}</td> + </tr> + {{end}} + </tbody> + </table> + <h2>Tags</h2> + <table> + <thead> + <tr> + <td><b>Name</b></td> + <td><b>Hash</b></td> + </tr> + </thead> + <tbody> + {{range .Tags}} + <tr> + <td>{{.Name}}</a></td> + <td>{{.Hash}}</td> + </tr> + {{end}} + </tbody> + </table> +</body> diff --git a/res/repo_tree.html b/res/repo_tree.html new file mode 100644 index 0000000..ca65c95 --- /dev/null +++ b/res/repo_tree.html @@ -0,0 +1,44 @@ +<!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> +<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> +</body> diff --git a/res/res.go b/res/res.go index 3acb4e9..cb3647b 100644 --- a/res/res.go +++ b/res/res.go @@ -14,11 +14,20 @@ var RepoCreate string //go:embed repo_log.html var RepoLog string +//go:embed repo_tree.html +var RepoTree string + +//go:embed repo_refs.html +var RepoRefs string + //go:embed user_create.html 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/res/style.css b/res/style.css index 2f78065..28108ed 100644 --- a/res/style.css +++ b/res/style.css @@ -1,8 +1,10 @@ html { background-color: #111111; color: #888888; height: 100%; } -body { font-family: monospace; margin: 0; width: 100%; } +body { font-family: monospace; margin: 1em; } + a { color: #FF7E00; text-decoration: none; } a:hover { text-decoration: underline; } +h1 { font-size: 1em; margin: 0; } +hr { border: 0; height: 1em; margin: 0; } -table { margin: 1em; } table td { padding: 0 0.4em; } table tr:hover td { background-color: #222222; } diff --git a/res/user_create.html b/res/user_create.html index b04c0c3..c4cfbd7 100644 --- a/res/user_create.html +++ b/res/user_create.html @@ -4,6 +4,7 @@ <title>Create User</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> <body> <h1>Create User</h1> diff --git a/res/user_login.html b/res/user_login.html index 1ade9a1..0da5c64 100644 --- a/res/user_login.html +++ b/res/user_login.html @@ -3,7 +3,8 @@ <meta charset="UTF-8"> <title>Login</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <link rel="stylesheet" href="/static/style.css"> + <link rel="stylesheet" type="text/css" href="/static/style.css"> + <link rel="icon" type="image/png" href="/static/favicon.png"> </head> <body> <h1>Login</h1> diff --git a/src/admin.go b/src/admin.go index 6f5a75e..cb8f762 100644 --- a/src/admin.go +++ b/src/admin.go @@ -24,20 +24,20 @@ func init() { func (g *Goit) HandleAdminUserIndex(w http.ResponseWriter, r *http.Request) { if ok, uid := AuthHttp(r); !ok { - http.NotFound(w, r) + HttpError(w, http.StatusNotFound) return } else if user, err := g.GetUser(uid); err != nil { log.Println("[Admin:User:Create:Auth]", err.Error()) - http.NotFound(w, r) + HttpError(w, http.StatusNotFound) return } else if !user.IsAdmin { - http.NotFound(w, r) + HttpError(w, http.StatusNotFound) return } if rows, err := g.db.Query("SELECT id, name, name_full, is_admin FROM users"); err != nil { log.Println("[Admin:User:Index:SELECT]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) } else { defer rows.Close() @@ -56,7 +56,7 @@ func (g *Goit) HandleAdminUserIndex(w http.ResponseWriter, r *http.Request) { if err := rows.Err(); err != nil { log.Println("[Admin:User:Index:SELECT:Err]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) } else { adminUserIndex.Execute(w, struct{ Users []row }{users}) } @@ -65,14 +65,14 @@ func (g *Goit) HandleAdminUserIndex(w http.ResponseWriter, r *http.Request) { func (g *Goit) HandleAdminUserCreate(w http.ResponseWriter, r *http.Request) { if ok, uid := AuthHttp(r); !ok { - http.NotFound(w, r) + HttpError(w, http.StatusNotFound) return } else if user, err := g.GetUser(uid); err != nil { log.Println("[Admin:User:Create:Auth]", err.Error()) - http.NotFound(w, r) + HttpError(w, http.StatusNotFound) return } else if !user.IsAdmin { - http.NotFound(w, r) + HttpError(w, http.StatusNotFound) return } @@ -90,20 +90,20 @@ func (g *Goit) HandleAdminUserCreate(w http.ResponseWriter, r *http.Request) { data.Msg = "Username \"" + username + "\" is reserved" } else if exists, err := g.UserExists(username); err != nil { log.Println("[Admin:User:Create:Exists]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) return } else if exists { data.Msg = "Username \"" + username + "\" is taken" } else if salt, err := Salt(); err != nil { log.Println("[Admin:User:Create:Salt]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) return } else if _, err := g.db.Exec( "INSERT INTO users (name, name_full, pass, pass_algo, salt, is_admin) VALUES (?, ?, ?, ?, ?, ?)", username, fullname, Hash(password, salt), "argon2", salt, admin, ); err != nil { log.Println("[Admin:User:Create:INSERT]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) return } else { data.Msg = "User \"" + username + "\" created successfully" diff --git a/src/git.go b/src/git.go index a5c6373..cd7dcbf 100644 --- a/src/git.go +++ b/src/git.go @@ -40,7 +40,7 @@ func HandleInfoRefs(w http.ResponseWriter, r *http.Request) { refs, _, err := c.Run(nil, nil) if err != nil { log.Println("[Git]", err.Error()) - http.Error(w, "500 Internal Server Error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) return } @@ -83,28 +83,28 @@ func httpBase(w http.ResponseWriter, r *http.Request, service string) *Repo { case "git-receive-pack": isPull = false default: - http.Error(w, "404 Not Found", http.StatusNotFound) + HttpError(w, http.StatusNotFound) return nil } if r.Header.Get("Git-Protocol") != "version=2" { - http.Error(w, "403 Forbidden", http.StatusForbidden) + HttpError(w, http.StatusForbidden) return nil } repo, err := GetRepoByName(db, reponame) if err != nil { - http.Error(w, "500 Internal Server Error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) return nil } else if repo == nil { - http.Error(w, "404 Not Found", http.StatusNotFound) + HttpError(w, http.StatusNotFound) return nil } /* Require authentication other than for public pull */ if repo.IsPrivate || !isPull { /* TODO authentcate */ - http.Error(w, "401 Unauthorized", http.StatusUnauthorized) + HttpError(w, http.StatusUnauthorized) return nil } @@ -120,7 +120,7 @@ func serviceRPC(w http.ResponseWriter, r *http.Request, service string, repo *Re if r.Header.Get("Content-Type") != "application/x-"+service+"-request" { log.Println("[GitRPC]", "Content-Type mismatch") - http.Error(w, "401 Unauthorized", http.StatusUnauthorized) + HttpError(w, http.StatusUnauthorized) return } @@ -128,7 +128,7 @@ func serviceRPC(w http.ResponseWriter, r *http.Request, service string, repo *Re if r.Header.Get("Content-Encoding") == "gzip" { if b, err := gzip.NewReader(r.Body); err != nil { log.Println("[GitRPC]", err.Error()) - http.Error(w, "500 Internal Server Error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) return } else { body = b @@ -145,7 +145,7 @@ func serviceRPC(w http.ResponseWriter, r *http.Request, service string, repo *Re if _, _, err := c.Run(body, w); err != nil { log.Println("[GitRPC]", err.Error()) - http.Error(w, "500 Internal Server Error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) return } } diff --git a/src/http.go b/src/http.go new file mode 100644 index 0000000..d2e2162 --- /dev/null +++ b/src/http.go @@ -0,0 +1,21 @@ +package goit + +import ( + "fmt" + "html/template" + "net/http" + + "github.com/Jamozed/Goit/res" +) + +var htmlError *template.Template = template.Must(template.New("error").Parse(res.Error)) + +func HttpError(w http.ResponseWriter, code int) { + w.WriteHeader(code) + s := fmt.Sprint(code) + " " + http.StatusText(code) + htmlError.Execute(w, struct{ Status string }{s}) +} + +func HttpNotFound(w http.ResponseWriter, r *http.Request) { + HttpError(w, http.StatusNotFound) +} diff --git a/src/repo.go b/src/repo.go index bfbf8ce..01a6fca 100644 --- a/src/repo.go +++ b/src/repo.go @@ -15,6 +15,7 @@ import ( "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" "github.com/gorilla/mux" ) @@ -30,23 +31,19 @@ type Repo struct { } var ( - repoIndex *template.Template - repoCreate *template.Template - repoLog *template.Template + 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 init() { - repoIndex = template.Must(template.New("repo_index").Parse(res.RepoIndex)) - repoCreate = template.Must(template.New("repo_create").Parse(res.RepoCreate)) - repoLog = template.Must(template.New("repo_log").Parse(res.RepoLog)) -} - func (g *Goit) HandleIndex(w http.ResponseWriter, r *http.Request) { authOk, uid := AuthHttp(r) if rows, err := g.db.Query("SELECT id, owner_id, name, description, is_private FROM repos"); err != nil { log.Println("[Index:SELECT]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) } else { defer rows.Close() @@ -70,7 +67,7 @@ func (g *Goit) HandleIndex(w http.ResponseWriter, r *http.Request) { if err := rows.Err(); err != nil { log.Println("[Index:SELECT:Err]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) } else { repoIndex.Execute(w, struct{ Repos []row }{repos}) } @@ -79,14 +76,14 @@ func (g *Goit) HandleIndex(w http.ResponseWriter, r *http.Request) { func (g *Goit) HandleRepoCreate(w http.ResponseWriter, r *http.Request) { if ok, uid := AuthHttp(r); !ok { - http.Error(w, "401 unauthorized", http.StatusUnauthorized) + HttpError(w, http.StatusUnauthorized) } else if r.Method == http.MethodPost { name := r.FormValue("reponame") private := r.FormValue("visibility") == "private" if taken, err := RepoExists(g.db, name); err != nil { log.Println("[RepoCreate:RepoExists]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) } else if taken { repoCreate.Execute(w, struct{ Msg string }{"Reponame is taken"}) } else if SliceContains[string](reserved, name) { @@ -99,7 +96,7 @@ func (g *Goit) HandleRepoCreate(w http.ResponseWriter, r *http.Request) { uid, name, strings.ToLower(name), "", "master", private, ); err != nil { log.Println("[RepoCreate:INSERT]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) } else { http.Redirect(w, r, "/"+name+"/", http.StatusFound) } @@ -112,27 +109,105 @@ func (g *Goit) HandleRepoCreate(w http.ResponseWriter, r *http.Request) { func (g *Goit) HandleRepoLog(w http.ResponseWriter, r *http.Request) { reponame := mux.Vars(r)["repo"] + repo, err := GetRepoByName(db, reponame) + if err != nil { + HttpError(w, http.StatusInternalServerError) + return + } else if repo == nil { + HttpError(w, http.StatusNotFound) + return + } + type row struct{ Date, Message, Author string } commits := []row{} if gr, err := git.PlainOpen("./" + reponame + ".git"); err != nil { - log.Println("[Repo:Open]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + log.Println("[Repo:Log]", err.Error()) + HttpError(w, http.StatusInternalServerError) + return } else if ref, err := gr.Head(); err != nil { - log.Println("[Repo:Head]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + log.Println("[Repo:Log]", err.Error()) + HttpError(w, http.StatusInternalServerError) + return } else if iter, err := gr.Log(&git.LogOptions{From: ref.Hash()}); err != nil { log.Println("[Repo:Log]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) + return } else if err := iter.ForEach(func(c *object.Commit) error { - commits = append(commits, row{c.Author.When.UTC().Format(time.RFC3339), c.Message, c.Author.Name}) + commits = append(commits, row{c.Author.When.UTC().Format(time.DateTime), strings.SplitN(c.Message, "\n", 2)[0], c.Author.Name}) return nil }); err != nil { log.Println("[Repo:Log]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) + return } - repoLog.Execute(w, struct{ Commits []row }{commits}) + 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 { + log.Println("[Repo:Log]", err.Error()) + } +} + +func (g *Goit) HandleRepoTree(w http.ResponseWriter, r *http.Request) { + HttpError(w, http.StatusNoContent) +} + +func (g *Goit) HandleRepoRefs(w http.ResponseWriter, r *http.Request) { + reponame := mux.Vars(r)["repo"] + + repo, err := GetRepoByName(db, reponame) + if err != nil { + HttpError(w, http.StatusInternalServerError) + return + } else if repo == nil { + HttpError(w, http.StatusNotFound) + return + } + + type bra struct{ Name, Hash string } + type tag struct{ Name, Hash string } + bras := []bra{} + tags := []tag{} + + if gr, err := git.PlainOpen("./" + reponame + ".git"); err != nil { + log.Println("[Repo:Refs]", err.Error()) + HttpError(w, http.StatusInternalServerError) + return + } else if iter, err := gr.Branches(); err != nil { + log.Println("[Repo:Refs]", err.Error()) + HttpError(w, http.StatusInternalServerError) + return + } else if err := iter.ForEach(func(b *plumbing.Reference) error { + bras = append(bras, bra{b.Name().Short(), b.Hash().String()}) + return nil + }); err != nil { + log.Println("[Repo:Refs]", err.Error()) + HttpError(w, http.StatusInternalServerError) + return + } else if iter, err := gr.Tags(); err != nil { + log.Println("[Repo:Refs]", err.Error()) + HttpError(w, http.StatusInternalServerError) + return + } else if err := iter.ForEach(func(b *plumbing.Reference) error { + tags = append(tags, tag{b.Name().Short(), b.Hash().String()}) + return nil + }); err != nil { + log.Println("[Repo:Refs]", err.Error()) + HttpError(w, http.StatusInternalServerError) + 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 { + log.Println("[Repo:Refs]", err.Error()) + } } func GetRepoByName(db *sql.DB, name string) (*Repo, error) { diff --git a/src/user.go b/src/user.go index 53e7653..9b2617c 100644 --- a/src/user.go +++ b/src/user.go @@ -31,15 +31,10 @@ type User struct { var ( reserved []string = []string{"admin", "repo", "static", "user"} - userLogin *template.Template - userCreate *template.Template + userLogin *template.Template = template.Must(template.New("user_login").Parse(res.UserLogin)) + userCreate *template.Template = template.Must(template.New("user_create").Parse(res.UserCreate)) ) -func init() { - userLogin = template.Must(template.New("user_login").Parse(res.UserLogin)) - userCreate = template.Must(template.New("user_create").Parse(res.UserCreate)) -} - func (g *Goit) HandleUserLogin(w http.ResponseWriter, r *http.Request) { if ok, _ := AuthHttp(r); ok { http.Redirect(w, r, "/", http.StatusFound) @@ -57,7 +52,7 @@ func (g *Goit) HandleUserLogin(w http.ResponseWriter, r *http.Request) { data.Msg = "Username cannot be empty" } else if exists, err := g.UserExists(username); err != nil { log.Println("[User:Login:Exists]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) return } else if !exists { data.Msg = "Invalid credentials" @@ -65,7 +60,7 @@ func (g *Goit) HandleUserLogin(w http.ResponseWriter, r *http.Request) { "SELECT id, name, pass, pass_algo, salt FROM users WHERE name = ?", username, ).Scan(&u.Id, &u.Name, &u.Pass, &u.PassAlgo, &u.Salt); err != nil { log.Println("[User:Login:SELECT]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) return } else if !bytes.Equal(Hash(password, u.Salt), u.Pass) { data.Msg = "Invalid credentials" @@ -73,7 +68,7 @@ func (g *Goit) HandleUserLogin(w http.ResponseWriter, r *http.Request) { expiry := time.Now().Add(15 * time.Minute) if s, err := NewSession(u.Id, expiry); err != nil { log.Println("[User:Login:Session]", err.Error()) - http.Error(w, "500 internal server error", http.StatusInternalServerError) + HttpError(w, http.StatusInternalServerError) return } else { http.SetCookie(w, &http.Cookie{Name: "session", Value: s, Path: "/", Expires: expiry})