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 (s *State) fullyResolvedRepo(r *http.Request) (*FullyResolvedRepo, error) {
21 repoName := chi.URLParam(r, "repo")
22 ref := chi.URLParam(r, "ref")
23
24 knot, ok := r.Context().Value("knot").(string)
25 if !ok {
26 log.Println("malformed middleware")
27 return nil, fmt.Errorf("malformed middleware")
28 }
29 id, ok := r.Context().Value("resolvedId").(identity.Identity)
30 if !ok {
31 log.Println("malformed middleware")
32 return nil, fmt.Errorf("malformed middleware")
33 }
34
35 repoAt, ok := r.Context().Value("repoAt").(string)
36 if !ok {
37 log.Println("malformed middleware")
38 return nil, fmt.Errorf("malformed middleware")
39 }
40
41 if ref == "" {
42 us, err := NewUnsignedClient(knot, s.config.Dev)
43 if err != nil {
44 return nil, fmt.Errorf("failed to setup new signed client: %w", err)
45 }
46
47 def, err := us.DefaultBranch(id.DID.String(), repoName)
48 if err != nil {
49 return nil, fmt.Errorf("failed to get default branch: %w", err)
50 }
51
52 ref = def.Branch
53 }
54
55 parsedRepoAt, err := syntax.ParseATURI(repoAt)
56 if err != nil {
57 log.Println("malformed repo at-uri")
58 return nil, fmt.Errorf("malformed middleware: %w", err)
59 }
60
61 // pass through values from the middleware
62 description, ok := r.Context().Value("repoDescription").(string)
63 addedAt, ok := r.Context().Value("repoAddedAt").(string)
64
65 return &FullyResolvedRepo{
66 Knot: knot,
67 OwnerId: id,
68 RepoName: repoName,
69 RepoAt: parsedRepoAt,
70 Description: description,
71 AddedAt: addedAt,
72 Ref: ref,
73 }, nil
74}
75
76func RolesInRepo(s *State, u *auth.User, f *FullyResolvedRepo) pages.RolesInRepo {
77 if u != nil {
78 r := s.enforcer.GetPermissionsInRepo(u.Did, f.Knot, f.OwnerSlashRepo())
79 return pages.RolesInRepo{r}
80 } else {
81 return pages.RolesInRepo{}
82 }
83}
84
85func uniqueEmails(commits []*object.Commit) []string {
86 emails := make(map[string]struct{})
87 for _, commit := range commits {
88 if commit.Author.Email != "" {
89 emails[commit.Author.Email] = struct{}{}
90 }
91 if commit.Committer.Email != "" {
92 emails[commit.Committer.Email] = struct{}{}
93 }
94 }
95 var uniqueEmails []string
96 for email := range emails {
97 uniqueEmails = append(uniqueEmails, email)
98 }
99 return uniqueEmails
100}
101
102func EmailToDidOrHandle(s *State, emails []string) map[string]string {
103 emailToDid, err := db.GetEmailToDid(s.db, emails, true) // only get verified emails for mapping
104 if err != nil {
105 log.Printf("error fetching dids for emails: %v", err)
106 return nil
107 }
108
109 var dids []string
110 for _, v := range emailToDid {
111 dids = append(dids, v)
112 }
113 resolvedIdents := s.resolver.ResolveIdents(context.Background(), dids)
114
115 didHandleMap := make(map[string]string)
116 for _, identity := range resolvedIdents {
117 if !identity.Handle.IsInvalidHandle() {
118 didHandleMap[identity.DID.String()] = fmt.Sprintf("@%s", identity.Handle.String())
119 } else {
120 didHandleMap[identity.DID.String()] = identity.DID.String()
121 }
122 }
123
124 // Create map of email to didOrHandle for commit display
125 emailToDidOrHandle := make(map[string]string)
126 for email, did := range emailToDid {
127 if didOrHandle, ok := didHandleMap[did]; ok {
128 emailToDidOrHandle[email] = didOrHandle
129 }
130 }
131
132 return emailToDidOrHandle
133}
134
135func randomString(n int) string {
136 const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
137 result := make([]byte, n)
138
139 for i := 0; i < n; i++ {
140 n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
141 result[i] = letters[n.Int64()]
142 }
143
144 return string(result)
145}