Monorepo for Tangled tangled.org

appview: repo log

authored by anirudh.fi and committed by oppi.li 500665c2 05709520

Changed files
+125 -66
appview
pages
templates
state
knotserver
types
+25 -3
appview/pages/pages.go
··· 127 return p.execute("user/profile", w, params) 128 } 129 130 type RepoIndexParams struct { 131 LoggedInUser *auth.User 132 - Name string 133 - UserDid string 134 - UserHandle string 135 types.RepoIndexResponse 136 } 137 138 func (p *Pages) RepoIndexPage(w io.Writer, params RepoIndexParams) error { 139 return p.execute("repo/index", w, params) 140 }
··· 127 return p.execute("user/profile", w, params) 128 } 129 130 + type RepoInfo struct { 131 + Name string 132 + OwnerDid string 133 + OwnerHandle string 134 + } 135 + 136 + func (r RepoInfo) OwnerWithAt() string { 137 + if r.OwnerHandle != "" { 138 + return fmt.Sprintf("@%s", r.OwnerHandle) 139 + } else { 140 + return r.OwnerDid 141 + } 142 + } 143 + 144 type RepoIndexParams struct { 145 LoggedInUser *auth.User 146 + RepoInfo RepoInfo 147 types.RepoIndexResponse 148 } 149 150 func (p *Pages) RepoIndexPage(w io.Writer, params RepoIndexParams) error { 151 return p.execute("repo/index", w, params) 152 } 153 + 154 + type RepoLogParams struct { 155 + LoggedInUser *auth.User 156 + RepoInfo RepoInfo 157 + types.RepoLogResponse 158 + } 159 + 160 + func (p *Pages) RepoLog(w io.Writer, params RepoLogParams) error { 161 + return p.execute("repo/log", w, params) 162 + }
+4 -10
appview/pages/templates/repo/index.html
··· 1 - {{define "title"}} {{ or .UserHandle .UserDid }} / {{ .Name }} {{end}} 2 3 {{define "content"}} 4 - {{- $id := "" -}} 5 - {{- if .UserHandle -}} 6 - {{- $id = printf "@%s" .UserHandle -}} 7 - {{- else -}} 8 - {{- $id = .UserDid -}} 9 - {{- end -}} 10 11 <h1> 12 - {{ $id }} / {{ .Name }} 13 </h1> 14 <main> 15 <div class="log"> 16 {{ range .Commits }} 17 <div> 18 - <div><a href="/{{ $id }}/{{ $.Name }}/commit/{{ .Hash.String }}" class="commit-hash">{{ slice .Hash.String 0 8 }}</a></div> 19 <pre>{{ .Message }}</pre> 20 </div> 21 <div class="commit-info"> ··· 33 <div class="clone-url"> 34 <strong>clone</strong> 35 <pre> 36 - git clone https://tangled.sh/{{ $id }}/{{ .Name }} 37 </pre> 38 </div> 39 </main>
··· 1 + {{define "title"}} {{ .RepoInfo.OwnerWithAt }} / {{ .RepoInfo.Name }} {{end}} 2 3 {{define "content"}} 4 5 <h1> 6 + {{ .RepoInfo.OwnerWithAt }} / {{ .RepoInfo.Name }} 7 </h1> 8 <main> 9 <div class="log"> 10 {{ range .Commits }} 11 <div> 12 + <div><a href="/{{ $.RepoInfo.OwnerWithAt }}/{{ $.RepoInfo.Name }}/commit/{{ .Hash.String }}" class="commit-hash">{{ slice .Hash.String 0 8 }}</a></div> 13 <pre>{{ .Message }}</pre> 14 </div> 15 <div class="commit-info"> ··· 27 <div class="clone-url"> 28 <strong>clone</strong> 29 <pre> 30 + git clone https://tangled.sh/{{ .RepoInfo.OwnerWithAt }}/{{ .RepoInfo.Name }} 31 </pre> 32 </div> 33 </main>
+9 -10
appview/pages/templates/repo/log.html
··· 1 - <html> 2 - {{ template "layouts/head" . }} 3 4 - {{ template "layouts/repo-header" . }} 5 - <body> 6 - {{ template "layouts/nav" . }} 7 <main> 8 - {{ $repo := .name }} 9 <div class="log"> 10 - {{ range .commits }} 11 <div> 12 - <div><a href="/{{ $repo }}/commit/{{ .Hash.String }}" class="commit-hash">{{ slice .Hash.String 0 8 }}</a></div> 13 <pre>{{ .Message }}</pre> 14 </div> 15 <div class="commit-info"> ··· 19 {{ end }} 20 </div> 21 </main> 22 - </body> 23 - </html>
··· 1 + {{define "title"}} log | {{ .RepoInfo.OwnerWithAt }} / {{ .RepoInfo.Name }} {{end}} 2 3 + {{define "content"}} 4 + 5 + <h1> 6 + log | {{ .RepoInfo.OwnerWithAt }} / {{ .RepoInfo.Name }} 7 + </h1> 8 <main> 9 <div class="log"> 10 + {{ range .Commits }} 11 <div> 12 + <div><a href="/{{ $.RepoInfo.OwnerWithAt }}/{{ $.RepoInfo.Name }}/commit/{{ .Hash.String }}" class="commit-hash">{{ slice .Hash.String 0 8 }}</a></div> 13 <pre>{{ .Message }}</pre> 14 </div> 15 <div class="commit-info"> ··· 19 {{ end }} 20 </div> 21 </main> 22 + {{end}}
+64 -20
appview/state/repo.go
··· 14 ) 15 16 func (s *State) RepoIndex(w http.ResponseWriter, r *http.Request) { 17 - ctx := r.Context() 18 - repoName := chi.URLParam(r, "repo") 19 - 20 - knot, ok := ctx.Value("knot").(string) 21 - if !ok { 22 - log.Println("malformed middleware") 23 - w.WriteHeader(http.StatusInternalServerError) 24 - return 25 - } 26 - 27 - id, ok := ctx.Value("resolvedId").(identity.Identity) 28 - if !ok { 29 - log.Println("malformed middleware") 30 - w.WriteHeader(http.StatusInternalServerError) 31 return 32 } 33 ··· 38 } 39 defer resp.Body.Close() 40 41 - // Read the response body 42 body, err := io.ReadAll(resp.Body) 43 if err != nil { 44 log.Fatalf("Error reading response body: %v", err) ··· 54 55 log.Println(resp.Status, result) 56 57 - user := s.auth.GetUser(r) 58 s.pages.RepoIndexPage(w, pages.RepoIndexParams{ 59 - LoggedInUser: user, 60 - UserDid: id.DID.String(), 61 - UserHandle: id.Handle.String(), 62 - Name: repoName, 63 RepoIndexResponse: result, 64 }) 65 66 return 67 }
··· 14 ) 15 16 func (s *State) RepoIndex(w http.ResponseWriter, r *http.Request) { 17 + repoName, knot, id, err := repoKnotAndId(r) 18 + if err != nil { 19 + log.Println("failed to get repo and knot", err) 20 return 21 } 22 ··· 27 } 28 defer resp.Body.Close() 29 30 body, err := io.ReadAll(resp.Body) 31 if err != nil { 32 log.Fatalf("Error reading response body: %v", err) ··· 42 43 log.Println(resp.Status, result) 44 45 s.pages.RepoIndexPage(w, pages.RepoIndexParams{ 46 + LoggedInUser: s.auth.GetUser(r), 47 + RepoInfo: pages.RepoInfo{ 48 + OwnerDid: id.DID.String(), 49 + OwnerHandle: id.Handle.String(), 50 + Name: repoName, 51 + }, 52 RepoIndexResponse: result, 53 }) 54 55 return 56 } 57 + 58 + func (s *State) RepoLog(w http.ResponseWriter, r *http.Request) { 59 + repoName, knot, id, err := repoKnotAndId(r) 60 + if err != nil { 61 + log.Println("failed to get repo and knot", err) 62 + return 63 + } 64 + 65 + ref := chi.URLParam(r, "ref") 66 + resp, err := http.Get(fmt.Sprintf("http://%s/%s/%s/log/%s", knot, id.DID.String(), repoName, ref)) 67 + if err != nil { 68 + log.Println("failed to reach knotserver", err) 69 + return 70 + } 71 + 72 + body, err := io.ReadAll(resp.Body) 73 + if err != nil { 74 + log.Fatalf("Error reading response body: %v", err) 75 + return 76 + } 77 + 78 + var result types.RepoLogResponse 79 + err = json.Unmarshal(body, &result) 80 + if err != nil { 81 + log.Println("failed to parse json response", err) 82 + return 83 + } 84 + 85 + s.pages.RepoLog(w, pages.RepoLogParams{ 86 + LoggedInUser: s.auth.GetUser(r), 87 + RepoInfo: pages.RepoInfo{ 88 + OwnerDid: id.DID.String(), 89 + OwnerHandle: id.Handle.String(), 90 + Name: repoName, 91 + }, 92 + RepoLogResponse: result, 93 + }) 94 + return 95 + } 96 + 97 + func repoKnotAndId(r *http.Request) (string, string, identity.Identity, error) { 98 + repoName := chi.URLParam(r, "repo") 99 + knot, ok := r.Context().Value("knot").(string) 100 + if !ok { 101 + log.Println("malformed middleware") 102 + return "", "", identity.Identity{}, fmt.Errorf("malformed middleware") 103 + } 104 + id, ok := r.Context().Value("resolvedId").(identity.Identity) 105 + if !ok { 106 + log.Println("malformed middleware") 107 + return "", "", identity.Identity{}, fmt.Errorf("malformed middleware") 108 + } 109 + 110 + return repoName, knot, id, nil 111 + }
-14
appview/state/signer.go
··· 113 114 return s.client.Do(req) 115 } 116 - 117 - func (s *SignedClient) RepoIndex(did, repo string) (*http.Response, error) { 118 - const ( 119 - Method = "GET" 120 - ) 121 - endpoint := fmt.Sprint("/%s/%s", did, repo) 122 - 123 - req, err := s.newRequest(Method, endpoint, nil) 124 - if err != nil { 125 - return nil, err 126 - } 127 - 128 - return s.client.Do(req) 129 - }
··· 113 114 return s.client.Do(req) 115 }
+3
appview/state/state.go
··· 601 r.Get("/", s.ProfilePage) 602 r.With(ResolveRepoKnot(s)).Route("/{repo}", func(r chi.Router) { 603 r.Get("/", s.RepoIndex) 604 // These routes get proxied to the knot 605 r.Get("/info/refs", s.InfoRefs) 606 r.Post("/git-upload-pack", s.UploadPack) 607 }) 608 }) 609
··· 601 r.Get("/", s.ProfilePage) 602 r.With(ResolveRepoKnot(s)).Route("/{repo}", func(r chi.Router) { 603 r.Get("/", s.RepoIndex) 604 + r.Get("/log/{ref}", s.RepoLog) 605 + 606 // These routes get proxied to the knot 607 r.Get("/info/refs", s.InfoRefs) 608 r.Post("/git-upload-pack", s.UploadPack) 609 + 610 }) 611 }) 612
+10 -9
knotserver/routes.go
··· 266 commits = commits[start:end] 267 } 268 269 - data := make(map[string]interface{}) 270 - data["commits"] = commits 271 - data["ref"] = ref 272 - data["desc"] = getDescription(path) 273 - data["log"] = true 274 - data["total"] = total 275 - data["page"] = page 276 - data["per_page"] = pageSize 277 278 - writeJSON(w, data) 279 return 280 } 281
··· 266 commits = commits[start:end] 267 } 268 269 + resp := types.RepoLogResponse{ 270 + Commits: commits, 271 + Ref: ref, 272 + Description: getDescription(path), 273 + Log: true, 274 + Total: total, 275 + Page: page, 276 + PerPage: pageSize, 277 + } 278 279 + writeJSON(w, resp) 280 return 281 } 282
+10
types/repo.go
··· 13 Commits []*object.Commit `json:"commits,omitempty"` 14 Description string `json:"description,omitempty"` 15 }
··· 13 Commits []*object.Commit `json:"commits,omitempty"` 14 Description string `json:"description,omitempty"` 15 } 16 + 17 + type RepoLogResponse struct { 18 + Commits []*object.Commit `json:"commits,omitempty"` 19 + Ref string `json:"ref,omitempty"` 20 + Description string `json:"description,omitempty"` 21 + Log bool `json:"log,omitempty"` 22 + Total int `json:"total,omitempty"` 23 + Page int `json:"page,omitempty"` 24 + PerPage int `json:"per_page,omitempty"` 25 + }