forked from tangled.org/core
this repo has no description
1package state 2 3import ( 4 "context" 5 "crypto/rand" 6 "fmt" 7 "log" 8 "math/big" 9 "net/http" 10 "net/url" 11 "path" 12 "strings" 13 14 "github.com/bluesky-social/indigo/atproto/identity" 15 "github.com/bluesky-social/indigo/atproto/syntax" 16 "github.com/go-chi/chi/v5" 17 "github.com/go-git/go-git/v5/plumbing/object" 18 "tangled.sh/tangled.sh/core/appview/db" 19 "tangled.sh/tangled.sh/core/appview/knotclient" 20 "tangled.sh/tangled.sh/core/appview/oauth" 21 "tangled.sh/tangled.sh/core/appview/pages/repoinfo" 22) 23 24func (s *State) fullyResolvedRepo(r *http.Request) (*FullyResolvedRepo, error) { 25 repoName := chi.URLParam(r, "repo") 26 knot, ok := r.Context().Value("knot").(string) 27 if !ok { 28 log.Println("malformed middleware") 29 return nil, fmt.Errorf("malformed middleware") 30 } 31 id, ok := r.Context().Value("resolvedId").(identity.Identity) 32 if !ok { 33 log.Println("malformed middleware") 34 return nil, fmt.Errorf("malformed middleware") 35 } 36 37 repoAt, ok := r.Context().Value("repoAt").(string) 38 if !ok { 39 log.Println("malformed middleware") 40 return nil, fmt.Errorf("malformed middleware") 41 } 42 43 parsedRepoAt, err := syntax.ParseATURI(repoAt) 44 if err != nil { 45 log.Println("malformed repo at-uri") 46 return nil, fmt.Errorf("malformed middleware") 47 } 48 49 ref := chi.URLParam(r, "ref") 50 51 if ref == "" { 52 us, err := knotclient.NewUnsignedClient(knot, s.config.Core.Dev) 53 if err != nil { 54 return nil, err 55 } 56 57 defaultBranch, err := us.DefaultBranch(id.DID.String(), repoName) 58 if err != nil { 59 return nil, err 60 } 61 62 ref = defaultBranch.Branch 63 } 64 65 currentDir := path.Dir(extractPathAfterRef(r.URL.EscapedPath(), ref)) 66 67 // pass through values from the middleware 68 description, ok := r.Context().Value("repoDescription").(string) 69 addedAt, ok := r.Context().Value("repoAddedAt").(string) 70 71 return &FullyResolvedRepo{ 72 Knot: knot, 73 OwnerId: id, 74 RepoName: repoName, 75 RepoAt: parsedRepoAt, 76 Description: description, 77 CreatedAt: addedAt, 78 Ref: ref, 79 CurrentDir: currentDir, 80 }, nil 81} 82 83func RolesInRepo(s *State, u *oauth.User, f *FullyResolvedRepo) repoinfo.RolesInRepo { 84 if u != nil { 85 r := s.enforcer.GetPermissionsInRepo(u.Did, f.Knot, f.DidSlashRepo()) 86 return repoinfo.RolesInRepo{r} 87 } else { 88 return repoinfo.RolesInRepo{} 89 } 90} 91 92// extractPathAfterRef gets the actual repository path 93// after the ref. for example: 94// 95// /@icyphox.sh/foorepo/blob/main/abc/xyz/ => abc/xyz/ 96func extractPathAfterRef(fullPath, ref string) string { 97 fullPath = strings.TrimPrefix(fullPath, "/") 98 99 ref = url.PathEscape(ref) 100 101 prefixes := []string{ 102 fmt.Sprintf("blob/%s/", ref), 103 fmt.Sprintf("tree/%s/", ref), 104 fmt.Sprintf("raw/%s/", ref), 105 } 106 107 for _, prefix := range prefixes { 108 idx := strings.Index(fullPath, prefix) 109 if idx != -1 { 110 return fullPath[idx+len(prefix):] 111 } 112 } 113 114 return "" 115} 116 117func uniqueEmails(commits []*object.Commit) []string { 118 emails := make(map[string]struct{}) 119 for _, commit := range commits { 120 if commit.Author.Email != "" { 121 emails[commit.Author.Email] = struct{}{} 122 } 123 if commit.Committer.Email != "" { 124 emails[commit.Committer.Email] = struct{}{} 125 } 126 } 127 var uniqueEmails []string 128 for email := range emails { 129 uniqueEmails = append(uniqueEmails, email) 130 } 131 return uniqueEmails 132} 133 134func balanceIndexItems(commitCount, branchCount, tagCount, fileCount int) (commitsTrunc int, branchesTrunc int, tagsTrunc int) { 135 if commitCount == 0 && tagCount == 0 && branchCount == 0 { 136 return 137 } 138 139 // typically 1 item on right side = 2 files in height 140 availableSpace := fileCount / 2 141 142 // clamp tagcount 143 if tagCount > 0 { 144 tagsTrunc = 1 145 availableSpace -= 1 // an extra subtracted for headers etc. 146 } 147 148 // clamp branchcount 149 if branchCount > 0 { 150 branchesTrunc = min(max(branchCount, 1), 2) 151 availableSpace -= branchesTrunc // an extra subtracted for headers etc. 152 } 153 154 // show 155 if commitCount > 0 { 156 commitsTrunc = max(availableSpace, 3) 157 } 158 159 return 160} 161 162func EmailToDidOrHandle(s *State, emails []string) map[string]string { 163 emailToDid, err := db.GetEmailToDid(s.db, emails, true) // only get verified emails for mapping 164 if err != nil { 165 log.Printf("error fetching dids for emails: %v", err) 166 return nil 167 } 168 169 var dids []string 170 for _, v := range emailToDid { 171 dids = append(dids, v) 172 } 173 resolvedIdents := s.resolver.ResolveIdents(context.Background(), dids) 174 175 didHandleMap := make(map[string]string) 176 for _, identity := range resolvedIdents { 177 if !identity.Handle.IsInvalidHandle() { 178 didHandleMap[identity.DID.String()] = fmt.Sprintf("@%s", identity.Handle.String()) 179 } else { 180 didHandleMap[identity.DID.String()] = identity.DID.String() 181 } 182 } 183 184 // Create map of email to didOrHandle for commit display 185 emailToDidOrHandle := make(map[string]string) 186 for email, did := range emailToDid { 187 if didOrHandle, ok := didHandleMap[did]; ok { 188 emailToDidOrHandle[email] = didOrHandle 189 } 190 } 191 192 return emailToDidOrHandle 193} 194 195func randomString(n int) string { 196 const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 197 result := make([]byte, n) 198 199 for i := 0; i < n; i++ { 200 n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) 201 result[i] = letters[n.Int64()] 202 } 203 204 return string(result) 205}