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