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