forked from tangled.org/core
Monorepo for Tangled — https://tangled.org
1package repo 2 3import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "net/url" 8 "strconv" 9 10 "tangled.org/core/api/tangled" 11 "tangled.org/core/appview/commitverify" 12 "tangled.org/core/appview/db" 13 "tangled.org/core/appview/models" 14 "tangled.org/core/appview/pages" 15 xrpcclient "tangled.org/core/appview/xrpcclient" 16 "tangled.org/core/types" 17 18 indigoxrpc "github.com/bluesky-social/indigo/xrpc" 19 "github.com/go-chi/chi/v5" 20 "github.com/go-git/go-git/v5/plumbing" 21) 22 23func (rp *Repo) Log(w http.ResponseWriter, r *http.Request) { 24 l := rp.logger.With("handler", "RepoLog") 25 26 f, err := rp.repoResolver.Resolve(r) 27 if err != nil { 28 l.Error("failed to fully resolve repo", "err", err) 29 return 30 } 31 32 page := 1 33 if r.URL.Query().Get("page") != "" { 34 page, err = strconv.Atoi(r.URL.Query().Get("page")) 35 if err != nil { 36 page = 1 37 } 38 } 39 40 ref := chi.URLParam(r, "ref") 41 ref, _ = url.PathUnescape(ref) 42 43 scheme := "http" 44 if !rp.config.Core.Dev { 45 scheme = "https" 46 } 47 host := fmt.Sprintf("%s://%s", scheme, f.Knot) 48 xrpcc := &indigoxrpc.Client{ 49 Host: host, 50 } 51 52 limit := int64(60) 53 cursor := "" 54 if page > 1 { 55 // Convert page number to cursor (offset) 56 offset := (page - 1) * int(limit) 57 cursor = strconv.Itoa(offset) 58 } 59 60 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 61 xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, repo) 62 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 63 l.Error("failed to call XRPC repo.log", "err", xrpcerr) 64 rp.pages.Error503(w) 65 return 66 } 67 68 var xrpcResp types.RepoLogResponse 69 if err := json.Unmarshal(xrpcBytes, &xrpcResp); err != nil { 70 l.Error("failed to decode XRPC response", "err", err) 71 rp.pages.Error503(w) 72 return 73 } 74 75 tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 76 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 77 l.Error("failed to call XRPC repo.tags", "err", xrpcerr) 78 rp.pages.Error503(w) 79 return 80 } 81 82 tagMap := make(map[string][]string) 83 if tagBytes != nil { 84 var tagResp types.RepoTagsResponse 85 if err := json.Unmarshal(tagBytes, &tagResp); err == nil { 86 for _, tag := range tagResp.Tags { 87 hash := tag.Hash 88 if tag.Tag != nil { 89 hash = tag.Tag.Target.String() 90 } 91 tagMap[hash] = append(tagMap[hash], tag.Name) 92 } 93 } 94 } 95 96 branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 97 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 98 l.Error("failed to call XRPC repo.branches", "err", xrpcerr) 99 rp.pages.Error503(w) 100 return 101 } 102 103 if branchBytes != nil { 104 var branchResp types.RepoBranchesResponse 105 if err := json.Unmarshal(branchBytes, &branchResp); err == nil { 106 for _, branch := range branchResp.Branches { 107 tagMap[branch.Hash] = append(tagMap[branch.Hash], branch.Name) 108 } 109 } 110 } 111 112 user := rp.oauth.GetUser(r) 113 114 emailToDidMap, err := db.GetEmailToDid(rp.db, uniqueEmails(xrpcResp.Commits), true) 115 if err != nil { 116 l.Error("failed to fetch email to did mapping", "err", err) 117 } 118 119 vc, err := commitverify.GetVerifiedObjectCommits(rp.db, emailToDidMap, xrpcResp.Commits) 120 if err != nil { 121 l.Error("failed to GetVerifiedObjectCommits", "err", err) 122 } 123 124 repoInfo := f.RepoInfo(user) 125 126 var shas []string 127 for _, c := range xrpcResp.Commits { 128 shas = append(shas, c.Hash.String()) 129 } 130 pipelines, err := getPipelineStatuses(rp.db, repoInfo, shas) 131 if err != nil { 132 l.Error("failed to getPipelineStatuses", "err", err) 133 // non-fatal 134 } 135 136 rp.pages.RepoLog(w, pages.RepoLogParams{ 137 LoggedInUser: user, 138 TagMap: tagMap, 139 RepoInfo: repoInfo, 140 RepoLogResponse: xrpcResp, 141 EmailToDid: emailToDidMap, 142 VerifiedCommits: vc, 143 Pipelines: pipelines, 144 }) 145} 146 147func (rp *Repo) Commit(w http.ResponseWriter, r *http.Request) { 148 l := rp.logger.With("handler", "RepoCommit") 149 150 f, err := rp.repoResolver.Resolve(r) 151 if err != nil { 152 l.Error("failed to fully resolve repo", "err", err) 153 return 154 } 155 ref := chi.URLParam(r, "ref") 156 ref, _ = url.PathUnescape(ref) 157 158 var diffOpts types.DiffOpts 159 if d := r.URL.Query().Get("diff"); d == "split" { 160 diffOpts.Split = true 161 } 162 163 if !plumbing.IsHash(ref) { 164 rp.pages.Error404(w) 165 return 166 } 167 168 scheme := "http" 169 if !rp.config.Core.Dev { 170 scheme = "https" 171 } 172 host := fmt.Sprintf("%s://%s", scheme, f.Knot) 173 xrpcc := &indigoxrpc.Client{ 174 Host: host, 175 } 176 177 repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) 178 xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, repo) 179 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 180 l.Error("failed to call XRPC repo.diff", "err", xrpcerr) 181 rp.pages.Error503(w) 182 return 183 } 184 185 var result types.RepoCommitResponse 186 if err := json.Unmarshal(xrpcBytes, &result); err != nil { 187 l.Error("failed to decode XRPC response", "err", err) 188 rp.pages.Error503(w) 189 return 190 } 191 192 emailToDidMap, err := db.GetEmailToDid(rp.db, []string{result.Diff.Commit.Committer.Email, result.Diff.Commit.Author.Email}, true) 193 if err != nil { 194 l.Error("failed to get email to did mapping", "err", err) 195 } 196 197 vc, err := commitverify.GetVerifiedCommits(rp.db, emailToDidMap, []types.NiceDiff{*result.Diff}) 198 if err != nil { 199 l.Error("failed to GetVerifiedCommits", "err", err) 200 } 201 202 user := rp.oauth.GetUser(r) 203 repoInfo := f.RepoInfo(user) 204 pipelines, err := getPipelineStatuses(rp.db, repoInfo, []string{result.Diff.Commit.This}) 205 if err != nil { 206 l.Error("failed to getPipelineStatuses", "err", err) 207 // non-fatal 208 } 209 var pipeline *models.Pipeline 210 if p, ok := pipelines[result.Diff.Commit.This]; ok { 211 pipeline = &p 212 } 213 214 rp.pages.RepoCommit(w, pages.RepoCommitParams{ 215 LoggedInUser: user, 216 RepoInfo: f.RepoInfo(user), 217 RepoCommitResponse: result, 218 EmailToDid: emailToDidMap, 219 VerifiedCommit: vc, 220 Pipeline: pipeline, 221 DiffOpts: diffOpts, 222 }) 223}