forked from tangled.org/core
Monorepo for Tangled — https://tangled.org
1package state 2 3import ( 4 "crypto/hmac" 5 "crypto/sha256" 6 "encoding/hex" 7 "fmt" 8 "log" 9 "net/http" 10 11 "github.com/bluesky-social/indigo/atproto/identity" 12 "github.com/go-chi/chi/v5" 13 "tangled.sh/tangled.sh/core/appview/db" 14 "tangled.sh/tangled.sh/core/appview/pages" 15) 16 17func (s *State) ProfilePage(w http.ResponseWriter, r *http.Request) { 18 didOrHandle := chi.URLParam(r, "user") 19 if didOrHandle == "" { 20 http.Error(w, "Bad request", http.StatusBadRequest) 21 return 22 } 23 24 ident, ok := r.Context().Value("resolvedId").(identity.Identity) 25 if !ok { 26 s.pages.Error404(w) 27 return 28 } 29 30 repos, err := db.GetAllReposByDid(s.db, ident.DID.String()) 31 if err != nil { 32 log.Printf("getting repos for %s: %s", ident.DID.String(), err) 33 } 34 35 collaboratingRepos, err := db.CollaboratingIn(s.db, ident.DID.String()) 36 if err != nil { 37 log.Printf("getting collaborating repos for %s: %s", ident.DID.String(), err) 38 } 39 40 timeline, err := db.MakeProfileTimeline(s.db, ident.DID.String()) 41 if err != nil { 42 log.Printf("failed to create profile timeline for %s: %s", ident.DID.String(), err) 43 } 44 45 var didsToResolve []string 46 for _, r := range collaboratingRepos { 47 didsToResolve = append(didsToResolve, r.Did) 48 } 49 for _, byMonth := range timeline.ByMonth { 50 for _, pe := range byMonth.PullEvents.Items { 51 didsToResolve = append(didsToResolve, pe.Repo.Did) 52 } 53 for _, ie := range byMonth.IssueEvents.Items { 54 didsToResolve = append(didsToResolve, ie.Metadata.Repo.Did) 55 } 56 for _, re := range byMonth.RepoEvents { 57 didsToResolve = append(didsToResolve, re.Repo.Did) 58 if re.Source != nil { 59 didsToResolve = append(didsToResolve, re.Source.Did) 60 } 61 } 62 } 63 64 resolvedIds := s.resolver.ResolveIdents(r.Context(), didsToResolve) 65 didHandleMap := make(map[string]string) 66 for _, identity := range resolvedIds { 67 if !identity.Handle.IsInvalidHandle() { 68 didHandleMap[identity.DID.String()] = fmt.Sprintf("@%s", identity.Handle.String()) 69 } else { 70 didHandleMap[identity.DID.String()] = identity.DID.String() 71 } 72 } 73 74 followers, following, err := db.GetFollowerFollowing(s.db, ident.DID.String()) 75 if err != nil { 76 log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err) 77 } 78 79 loggedInUser := s.auth.GetUser(r) 80 followStatus := db.IsNotFollowing 81 if loggedInUser != nil { 82 followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String()) 83 } 84 85 profileAvatarUri := s.GetAvatarUri(ident.Handle.String()) 86 s.pages.ProfilePage(w, pages.ProfilePageParams{ 87 LoggedInUser: loggedInUser, 88 UserDid: ident.DID.String(), 89 UserHandle: ident.Handle.String(), 90 Repos: repos, 91 CollaboratingRepos: collaboratingRepos, 92 ProfileStats: pages.ProfileStats{ 93 Followers: followers, 94 Following: following, 95 }, 96 FollowStatus: db.FollowStatus(followStatus), 97 DidHandleMap: didHandleMap, 98 AvatarUri: profileAvatarUri, 99 ProfileTimeline: timeline, 100 }) 101} 102 103func (s *State) GetAvatarUri(handle string) string { 104 secret := s.config.AvatarSharedSecret 105 h := hmac.New(sha256.New, []byte(secret)) 106 h.Write([]byte(handle)) 107 signature := hex.EncodeToString(h.Sum(nil)) 108 return fmt.Sprintf("%s/%s/%s", s.config.AvatarHost, signature, handle) 109}