appview: state: dedup profile pages #504

merged
opened by ptr.pet targeting master from [deleted fork]: followers-following-list
Changed files
+369 -381
.jjconflict-base-0
appview
pages
state
.jjconflict-base-1
appview
pages
state
.jjconflict-side-0
appview
pages
state
.jjconflict-side-1
appview
pages
state
.jjconflict-side-2
appview
pages
state
+2 -2
.jjconflict-base-0/appview/pages/pages.go
··· 408 408 return p.execute("repo/fork", w, params) 409 409 } 410 410 411 - type ProfilePageParams struct { 411 + type ProfileHomePageParams struct { 412 412 LoggedInUser *oauth.User 413 413 Repos []db.Repo 414 414 CollaboratingRepos []db.Repo ··· 427 427 Profile *db.Profile 428 428 } 429 429 430 - func (p *Pages) ProfilePage(w io.Writer, params ProfilePageParams) error { 430 + func (p *Pages) ProfileHomePage(w io.Writer, params ProfileHomePageParams) error { 431 431 return p.execute("user/profile", w, params) 432 432 } 433 433
+113 -103
.jjconflict-base-0/appview/state/profile.go
··· 25 25 tabVal := r.URL.Query().Get("tab") 26 26 switch tabVal { 27 27 case "": 28 - s.profilePage(w, r) 28 + s.profileHomePage(w, r) 29 29 case "repos": 30 30 s.reposPage(w, r) 31 31 case "followers": ··· 35 35 } 36 36 } 37 37 38 - func (s *State) profilePage(w http.ResponseWriter, r *http.Request) { 38 + type ProfilePageParams struct { 39 + Id identity.Identity 40 + LoggedInUser *oauth.User 41 + Card pages.ProfileCard 42 + } 43 + 44 + func (s *State) profilePage(w http.ResponseWriter, r *http.Request) *ProfilePageParams { 39 45 didOrHandle := chi.URLParam(r, "user") 40 46 if didOrHandle == "" { 41 - http.Error(w, "Bad request", http.StatusBadRequest) 42 - return 47 + http.Error(w, "bad request", http.StatusBadRequest) 48 + return nil 43 49 } 44 50 45 51 ident, ok := r.Context().Value("resolvedId").(identity.Identity) 46 52 if !ok { 47 - s.pages.Error404(w) 48 - return 53 + log.Printf("malformed middleware") 54 + w.WriteHeader(http.StatusInternalServerError) 55 + return nil 49 56 } 57 + did := ident.DID.String() 50 58 51 - profile, err := db.GetProfile(s.db, ident.DID.String()) 59 + profile, err := db.GetProfile(s.db, did) 52 60 if err != nil { 53 - log.Printf("getting profile data for %s: %s", ident.DID.String(), err) 61 + log.Printf("getting profile data for %s: %s", did, err) 54 62 } 55 63 64 + followStats, err := db.GetFollowerFollowingCount(s.db, did) 65 + if err != nil { 66 + log.Printf("getting follow stats for %s: %s", did, err) 67 + } 68 + 69 + loggedInUser := s.oauth.GetUser(r) 70 + followStatus := db.IsNotFollowing 71 + if loggedInUser != nil { 72 + followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, did) 73 + } 74 + 75 + return &ProfilePageParams{ 76 + Id: ident, 77 + LoggedInUser: loggedInUser, 78 + Card: pages.ProfileCard{ 79 + UserDid: did, 80 + UserHandle: ident.Handle.String(), 81 + Profile: profile, 82 + FollowStatus: followStatus, 83 + FollowersCount: followStats.Followers, 84 + FollowingCount: followStats.Following, 85 + }, 86 + } 87 + } 88 + 89 + func (s *State) profileHomePage(w http.ResponseWriter, r *http.Request) { 90 + pageWithProfile := s.profilePage(w, r) 91 + if pageWithProfile == nil { 92 + return 93 + } 94 + 95 + id := pageWithProfile.Id 56 96 repos, err := db.GetRepos( 57 97 s.db, 58 98 0, 59 - db.FilterEq("did", ident.DID.String()), 99 + db.FilterEq("did", id.DID), 60 100 ) 61 101 if err != nil { 62 - log.Printf("getting repos for %s: %s", ident.DID.String(), err) 102 + log.Printf("getting repos for %s: %s", id.DID, err) 63 103 } 64 104 105 + profile := pageWithProfile.Card.Profile 65 106 // filter out ones that are pinned 66 107 pinnedRepos := []db.Repo{} 67 108 for i, r := range repos { ··· 76 117 } 77 118 } 78 119 79 - collaboratingRepos, err := db.CollaboratingIn(s.db, ident.DID.String()) 120 + collaboratingRepos, err := db.CollaboratingIn(s.db, id.DID.String()) 80 121 if err != nil { 81 - log.Printf("getting collaborating repos for %s: %s", ident.DID.String(), err) 122 + log.Printf("getting collaborating repos for %s: %s", id.DID, err) 82 123 } 83 124 84 125 pinnedCollaboratingRepos := []db.Repo{} ··· 89 130 } 90 131 } 91 132 92 - timeline, err := db.MakeProfileTimeline(s.db, ident.DID.String()) 133 + timeline, err := db.MakeProfileTimeline(s.db, id.DID.String()) 93 134 if err != nil { 94 - log.Printf("failed to create profile timeline for %s: %s", ident.DID.String(), err) 135 + log.Printf("failed to create profile timeline for %s: %s", id.DID, err) 95 136 } 96 137 97 - followers, following, err := db.GetFollowerFollowingCount(s.db, ident.DID.String()) 98 - if err != nil { 99 - log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err) 138 + var didsToResolve []string 139 + for _, r := range collaboratingRepos { 140 + didsToResolve = append(didsToResolve, r.Did) 100 141 } 101 - 102 - loggedInUser := s.oauth.GetUser(r) 103 - followStatus := db.IsNotFollowing 104 - if loggedInUser != nil { 105 - followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String()) 142 + for _, byMonth := range timeline.ByMonth { 143 + for _, pe := range byMonth.PullEvents.Items { 144 + didsToResolve = append(didsToResolve, pe.Repo.Did) 145 + } 146 + for _, ie := range byMonth.IssueEvents.Items { 147 + didsToResolve = append(didsToResolve, ie.Metadata.Repo.Did) 148 + } 149 + for _, re := range byMonth.RepoEvents { 150 + didsToResolve = append(didsToResolve, re.Repo.Did) 151 + if re.Source != nil { 152 + didsToResolve = append(didsToResolve, re.Source.Did) 153 + } 154 + } 106 155 } 107 156 108 157 now := time.Now() 109 158 startOfYear := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC) 110 159 punchcard, err := db.MakePunchcard( 111 160 s.db, 112 - db.FilterEq("did", ident.DID.String()), 161 + db.FilterEq("did", id.DID), 113 162 db.FilterGte("date", startOfYear.Format(time.DateOnly)), 114 163 db.FilterLte("date", now.Format(time.DateOnly)), 115 164 ) 116 165 if err != nil { 117 - log.Println("failed to get punchcard for did", "did", ident.DID.String(), "err", err) 166 + log.Println("failed to get punchcard for did", "did", id.DID, "err", err) 118 167 } 119 168 120 - s.pages.ProfilePage(w, pages.ProfilePageParams{ 121 - LoggedInUser: loggedInUser, 169 + s.pages.ProfileHomePage(w, pages.ProfileHomePageParams{ 170 + LoggedInUser: pageWithProfile.LoggedInUser, 122 171 Repos: pinnedRepos, 123 172 CollaboratingRepos: pinnedCollaboratingRepos, 124 - Card: pages.ProfileCard{ 125 - UserDid: ident.DID.String(), 126 - UserHandle: ident.Handle.String(), 127 - Profile: profile, 128 - FollowStatus: followStatus, 129 - FollowersCount: followers, 130 - FollowingCount: following, 131 - }, 132 - Punchcard: punchcard, 133 - ProfileTimeline: timeline, 173 + Card: pageWithProfile.Card, 174 + Punchcard: punchcard, 175 + ProfileTimeline: timeline, 134 176 }) 135 177 } 136 178 137 179 func (s *State) reposPage(w http.ResponseWriter, r *http.Request) { 138 - ident, ok := r.Context().Value("resolvedId").(identity.Identity) 139 - if !ok { 140 - s.pages.Error404(w) 180 + pageWithProfile := s.profilePage(w, r) 181 + if pageWithProfile == nil { 141 182 return 142 183 } 143 184 144 - profile, err := db.GetProfile(s.db, ident.DID.String()) 145 - if err != nil { 146 - log.Printf("getting profile data for %s: %s", ident.DID.String(), err) 147 - } 148 - 185 + id := pageWithProfile.Id 149 186 repos, err := db.GetRepos( 150 187 s.db, 151 188 0, 152 - db.FilterEq("did", ident.DID.String()), 189 + db.FilterEq("did", id.DID), 153 190 ) 154 191 if err != nil { 155 - log.Printf("getting repos for %s: %s", ident.DID.String(), err) 156 - } 157 - 158 - loggedInUser := s.oauth.GetUser(r) 159 - followStatus := db.IsNotFollowing 160 - if loggedInUser != nil { 161 - followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String()) 162 - } 163 - 164 - followers, following, err := db.GetFollowerFollowingCount(s.db, ident.DID.String()) 165 - if err != nil { 166 - log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err) 192 + log.Printf("getting repos for %s: %s", id.DID, err) 167 193 } 168 194 169 195 s.pages.ReposPage(w, pages.ReposPageParams{ 170 - LoggedInUser: loggedInUser, 196 + LoggedInUser: pageWithProfile.LoggedInUser, 171 197 Repos: repos, 172 - Card: pages.ProfileCard{ 173 - UserDid: ident.DID.String(), 174 - UserHandle: ident.Handle.String(), 175 - Profile: profile, 176 - FollowStatus: followStatus, 177 - FollowersCount: followers, 178 - FollowingCount: following, 179 - }, 198 + Card: pageWithProfile.Card, 180 199 }) 181 200 } 182 201 ··· 187 206 } 188 207 189 208 func (s *State) followPage(w http.ResponseWriter, r *http.Request, fetchFollows func(db.Execer, string) ([]db.Follow, error), extractDid func(db.Follow) string) *FollowsPageParams { 190 - ident, ok := r.Context().Value("resolvedId").(identity.Identity) 191 - if !ok { 192 - s.pages.Error404(w) 209 + pageWithProfile := s.profilePage(w, r) 210 + if pageWithProfile == nil { 193 211 return nil 194 212 } 195 - did := ident.DID.String() 196 213 197 - profile, err := db.GetProfile(s.db, did) 198 - if err != nil { 199 - log.Printf("getting profile data for %s: %s", did, err) 200 - } 214 + id := pageWithProfile.Id 215 + loggedInUser := pageWithProfile.LoggedInUser 201 216 202 - loggedInUser := s.oauth.GetUser(r) 203 - 204 - follows, err := fetchFollows(s.db, did) 217 + follows, err := fetchFollows(s.db, id.DID.String()) 205 218 if err != nil { 206 - log.Printf("getting followers for %s: %s", did, err) 219 + log.Printf("getting followers for %s: %s", id.DID, err) 207 220 } 208 221 209 222 if len(follows) == 0 { 210 - return nil 223 + return &FollowsPageParams{ 224 + LoggedInUser: loggedInUser, 225 + Follows: []pages.FollowCard{}, 226 + Card: pageWithProfile.Card, 227 + } 211 228 } 212 229 213 230 followDids := make([]string, 0, len(follows)) ··· 218 235 profiles, err := db.GetProfiles(s.db, db.FilterIn("did", followDids)) 219 236 if err != nil { 220 237 log.Printf("getting profile for %s: %s", followDids, err) 221 - return nil 238 + } 239 + 240 + followStatsMap, err := db.GetFollowerFollowingCounts(s.db, followDids) 241 + if err != nil { 242 + log.Printf("getting follow counts for %s: %s", followDids, err) 222 243 } 223 244 224 245 var loggedInUserFollowing map[string]struct{} ··· 237 258 238 259 followCards := make([]pages.FollowCard, 0, len(follows)) 239 260 for _, did := range followDids { 240 - followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did) 241 - if err != nil { 242 - log.Printf("getting follow stats for %s: %s", did, err) 261 + followStats, exists := followStatsMap[did] 262 + if !exists { 263 + followStats = db.FollowStats{} 243 264 } 244 265 followStatus := db.IsNotFollowing 245 266 if loggedInUserFollowing != nil { ··· 259 280 followCards = append(followCards, pages.FollowCard{ 260 281 UserDid: did, 261 282 FollowStatus: followStatus, 262 - FollowersCount: followersCount, 263 - FollowingCount: followingCount, 283 + FollowersCount: followStats.Followers, 284 + FollowingCount: followStats.Following, 264 285 Profile: profile, 265 286 }) 266 287 } 267 288 268 - followStatus := db.IsNotFollowing 269 - if loggedInUser != nil { 270 - followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, did) 271 - } 272 - 273 - followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did) 274 - if err != nil { 275 - log.Printf("getting follow stats followers for %s: %s", did, err) 276 - } 277 - 278 289 return &FollowsPageParams{ 279 290 LoggedInUser: loggedInUser, 280 291 Follows: followCards, 281 - Card: pages.ProfileCard{ 282 - UserDid: did, 283 - UserHandle: ident.Handle.String(), 284 - Profile: profile, 285 - FollowStatus: followStatus, 286 - FollowersCount: followersCount, 287 - FollowingCount: followingCount, 288 - }, 292 + Card: pageWithProfile.Card, 289 293 } 290 294 } 291 295 292 296 func (s *State) followersPage(w http.ResponseWriter, r *http.Request) { 293 297 followPage := s.followPage(w, r, db.GetFollowers, func(f db.Follow) string { return f.UserDid }) 298 + if followPage == nil { 299 + return 300 + } 294 301 295 302 s.pages.FollowersPage(w, pages.FollowersPageParams{ 296 303 LoggedInUser: followPage.LoggedInUser, ··· 301 308 302 309 func (s *State) followingPage(w http.ResponseWriter, r *http.Request) { 303 310 followPage := s.followPage(w, r, db.GetFollowing, func(f db.Follow) string { return f.SubjectDid }) 311 + if followPage == nil { 312 + return 313 + } 304 314 305 315 s.pages.FollowingPage(w, pages.FollowingPageParams{ 306 316 LoggedInUser: followPage.LoggedInUser,
+2 -2
.jjconflict-base-1/appview/pages/pages.go
··· 408 408 return p.execute("repo/fork", w, params) 409 409 } 410 410 411 - type ProfilePageParams struct { 411 + type ProfileHomePageParams struct { 412 412 LoggedInUser *oauth.User 413 413 Repos []db.Repo 414 414 CollaboratingRepos []db.Repo ··· 427 427 Profile *db.Profile 428 428 } 429 429 430 - func (p *Pages) ProfilePage(w io.Writer, params ProfilePageParams) error { 430 + func (p *Pages) ProfileHomePage(w io.Writer, params ProfileHomePageParams) error { 431 431 return p.execute("user/profile", w, params) 432 432 } 433 433
.jjconflict-base-0/appview/pages/templates/timeline.html .jjconflict-base-1/appview/pages/templates/timeline.html
+11 -25
.jjconflict-base-1/appview/state/profile.go
··· 61 61 log.Printf("getting profile data for %s: %s", did, err) 62 62 } 63 63 64 - followStats, err := db.GetFollowerFollowingCount(s.db, did) 64 + followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did) 65 65 if err != nil { 66 66 log.Printf("getting follow stats for %s: %s", did, err) 67 67 } ··· 80 80 UserHandle: ident.Handle.String(), 81 81 Profile: profile, 82 82 FollowStatus: followStatus, 83 - FollowersCount: followStats.Followers, 84 - FollowingCount: followStats.Following, 83 + FollowersCount: followersCount, 84 + FollowingCount: followingCount, 85 85 }, 86 86 } 87 87 } ··· 212 212 } 213 213 214 214 id := pageWithProfile.Id 215 - loggedInUser := pageWithProfile.LoggedInUser 216 215 217 216 follows, err := fetchFollows(s.db, id.DID.String()) 218 217 if err != nil { ··· 220 219 } 221 220 222 221 if len(follows) == 0 { 223 - return &FollowsPageParams{ 224 - LoggedInUser: loggedInUser, 225 - Follows: []pages.FollowCard{}, 226 - Card: pageWithProfile.Card, 227 - } 222 + return nil 228 223 } 229 224 230 225 followDids := make([]string, 0, len(follows)) ··· 235 230 profiles, err := db.GetProfiles(s.db, db.FilterIn("did", followDids)) 236 231 if err != nil { 237 232 log.Printf("getting profile for %s: %s", followDids, err) 233 + return nil 238 234 } 239 235 240 - followStatsMap, err := db.GetFollowerFollowingCounts(s.db, followDids) 241 - if err != nil { 242 - log.Printf("getting follow counts for %s: %s", followDids, err) 243 - } 244 - 236 + loggedInUser := pageWithProfile.LoggedInUser 245 237 var loggedInUserFollowing map[string]struct{} 246 238 if loggedInUser != nil { 247 239 following, err := db.GetFollowing(s.db, loggedInUser.Did) ··· 258 250 259 251 followCards := make([]pages.FollowCard, 0, len(follows)) 260 252 for _, did := range followDids { 261 - followStats, exists := followStatsMap[did] 262 - if !exists { 263 - followStats = db.FollowStats{} 253 + followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did) 254 + if err != nil { 255 + log.Printf("getting follow stats for %s: %s", did, err) 264 256 } 265 257 followStatus := db.IsNotFollowing 266 258 if loggedInUserFollowing != nil { ··· 280 272 followCards = append(followCards, pages.FollowCard{ 281 273 UserDid: did, 282 274 FollowStatus: followStatus, 283 - FollowersCount: followStats.Followers, 284 - FollowingCount: followStats.Following, 275 + FollowersCount: followersCount, 276 + FollowingCount: followingCount, 285 277 Profile: profile, 286 278 }) 287 279 } ··· 295 287 296 288 func (s *State) followersPage(w http.ResponseWriter, r *http.Request) { 297 289 followPage := s.followPage(w, r, db.GetFollowers, func(f db.Follow) string { return f.UserDid }) 298 - if followPage == nil { 299 - return 300 - } 301 290 302 291 s.pages.FollowersPage(w, pages.FollowersPageParams{ 303 292 LoggedInUser: followPage.LoggedInUser, ··· 308 297 309 298 func (s *State) followingPage(w http.ResponseWriter, r *http.Request) { 310 299 followPage := s.followPage(w, r, db.GetFollowing, func(f db.Follow) string { return f.SubjectDid }) 311 - if followPage == nil { 312 - return 313 - } 314 300 315 301 s.pages.FollowingPage(w, pages.FollowingPageParams{ 316 302 LoggedInUser: followPage.LoggedInUser,
+2 -2
.jjconflict-side-0/appview/pages/pages.go
··· 408 408 return p.execute("repo/fork", w, params) 409 409 } 410 410 411 - type ProfilePageParams struct { 411 + type ProfileHomePageParams struct { 412 412 LoggedInUser *oauth.User 413 413 Repos []db.Repo 414 414 CollaboratingRepos []db.Repo ··· 427 427 Profile *db.Profile 428 428 } 429 429 430 - func (p *Pages) ProfilePage(w io.Writer, params ProfilePageParams) error { 430 + func (p *Pages) ProfileHomePage(w io.Writer, params ProfileHomePageParams) error { 431 431 return p.execute("user/profile", w, params) 432 432 } 433 433
+92 -96
.jjconflict-side-0/appview/state/profile.go
··· 25 25 tabVal := r.URL.Query().Get("tab") 26 26 switch tabVal { 27 27 case "": 28 - s.profilePage(w, r) 28 + s.profileHomePage(w, r) 29 29 case "repos": 30 30 s.reposPage(w, r) 31 31 case "followers": ··· 35 35 } 36 36 } 37 37 38 - func (s *State) profilePage(w http.ResponseWriter, r *http.Request) { 38 + type ProfilePageParams struct { 39 + Id identity.Identity 40 + LoggedInUser *oauth.User 41 + Card pages.ProfileCard 42 + } 43 + 44 + func (s *State) profilePage(w http.ResponseWriter, r *http.Request) *ProfilePageParams { 39 45 didOrHandle := chi.URLParam(r, "user") 40 46 if didOrHandle == "" { 41 - http.Error(w, "Bad request", http.StatusBadRequest) 42 - return 47 + http.Error(w, "bad request", http.StatusBadRequest) 48 + return nil 43 49 } 44 50 45 51 ident, ok := r.Context().Value("resolvedId").(identity.Identity) 46 52 if !ok { 47 - s.pages.Error404(w) 48 - return 53 + log.Printf("malformed middleware") 54 + w.WriteHeader(http.StatusInternalServerError) 55 + return nil 56 + } 57 + did := ident.DID.String() 58 + 59 + profile, err := db.GetProfile(s.db, did) 60 + if err != nil { 61 + log.Printf("getting profile data for %s: %s", did, err) 49 62 } 50 63 51 - profile, err := db.GetProfile(s.db, ident.DID.String()) 64 + followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did) 52 65 if err != nil { 53 - log.Printf("getting profile data for %s: %s", ident.DID.String(), err) 66 + log.Printf("getting follow stats for %s: %s", did, err) 54 67 } 55 68 69 + loggedInUser := s.oauth.GetUser(r) 70 + followStatus := db.IsNotFollowing 71 + if loggedInUser != nil { 72 + followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, did) 73 + } 74 + 75 + return &ProfilePageParams{ 76 + Id: ident, 77 + LoggedInUser: loggedInUser, 78 + Card: pages.ProfileCard{ 79 + UserDid: did, 80 + UserHandle: ident.Handle.String(), 81 + Profile: profile, 82 + FollowStatus: followStatus, 83 + FollowersCount: followersCount, 84 + FollowingCount: followingCount, 85 + }, 86 + } 87 + } 88 + 89 + func (s *State) profileHomePage(w http.ResponseWriter, r *http.Request) { 90 + pageWithProfile := s.profilePage(w, r) 91 + if pageWithProfile == nil { 92 + return 93 + } 94 + 95 + id := pageWithProfile.Id 56 96 repos, err := db.GetRepos( 57 97 s.db, 58 98 0, 59 - db.FilterEq("did", ident.DID.String()), 99 + db.FilterEq("did", id.DID), 60 100 ) 61 101 if err != nil { 62 - log.Printf("getting repos for %s: %s", ident.DID.String(), err) 102 + log.Printf("getting repos for %s: %s", id.DID, err) 63 103 } 64 104 105 + profile := pageWithProfile.Card.Profile 65 106 // filter out ones that are pinned 66 107 pinnedRepos := []db.Repo{} 67 108 for i, r := range repos { ··· 76 117 } 77 118 } 78 119 79 - collaboratingRepos, err := db.CollaboratingIn(s.db, ident.DID.String()) 120 + collaboratingRepos, err := db.CollaboratingIn(s.db, id.DID.String()) 80 121 if err != nil { 81 - log.Printf("getting collaborating repos for %s: %s", ident.DID.String(), err) 122 + log.Printf("getting collaborating repos for %s: %s", id.DID, err) 82 123 } 83 124 84 125 pinnedCollaboratingRepos := []db.Repo{} ··· 89 130 } 90 131 } 91 132 92 - timeline, err := db.MakeProfileTimeline(s.db, ident.DID.String()) 133 + timeline, err := db.MakeProfileTimeline(s.db, id.DID.String()) 93 134 if err != nil { 94 - log.Printf("failed to create profile timeline for %s: %s", ident.DID.String(), err) 135 + log.Printf("failed to create profile timeline for %s: %s", id.DID, err) 95 136 } 96 137 97 - followers, following, err := db.GetFollowerFollowingCount(s.db, ident.DID.String()) 98 - if err != nil { 99 - log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err) 138 + var didsToResolve []string 139 + for _, r := range collaboratingRepos { 140 + didsToResolve = append(didsToResolve, r.Did) 100 141 } 101 - 102 - loggedInUser := s.oauth.GetUser(r) 103 - followStatus := db.IsNotFollowing 104 - if loggedInUser != nil { 105 - followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String()) 142 + for _, byMonth := range timeline.ByMonth { 143 + for _, pe := range byMonth.PullEvents.Items { 144 + didsToResolve = append(didsToResolve, pe.Repo.Did) 145 + } 146 + for _, ie := range byMonth.IssueEvents.Items { 147 + didsToResolve = append(didsToResolve, ie.Metadata.Repo.Did) 148 + } 149 + for _, re := range byMonth.RepoEvents { 150 + didsToResolve = append(didsToResolve, re.Repo.Did) 151 + if re.Source != nil { 152 + didsToResolve = append(didsToResolve, re.Source.Did) 153 + } 154 + } 106 155 } 107 156 108 157 now := time.Now() 109 158 startOfYear := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC) 110 159 punchcard, err := db.MakePunchcard( 111 160 s.db, 112 - db.FilterEq("did", ident.DID.String()), 161 + db.FilterEq("did", id.DID), 113 162 db.FilterGte("date", startOfYear.Format(time.DateOnly)), 114 163 db.FilterLte("date", now.Format(time.DateOnly)), 115 164 ) 116 165 if err != nil { 117 - log.Println("failed to get punchcard for did", "did", ident.DID.String(), "err", err) 166 + log.Println("failed to get punchcard for did", "did", id.DID, "err", err) 118 167 } 119 168 120 - s.pages.ProfilePage(w, pages.ProfilePageParams{ 121 - LoggedInUser: loggedInUser, 169 + s.pages.ProfileHomePage(w, pages.ProfileHomePageParams{ 170 + LoggedInUser: pageWithProfile.LoggedInUser, 122 171 Repos: pinnedRepos, 123 172 CollaboratingRepos: pinnedCollaboratingRepos, 124 - Card: pages.ProfileCard{ 125 - UserDid: ident.DID.String(), 126 - UserHandle: ident.Handle.String(), 127 - Profile: profile, 128 - FollowStatus: followStatus, 129 - FollowersCount: followers, 130 - FollowingCount: following, 131 - }, 132 - Punchcard: punchcard, 133 - ProfileTimeline: timeline, 173 + Card: pageWithProfile.Card, 174 + Punchcard: punchcard, 175 + ProfileTimeline: timeline, 134 176 }) 135 177 } 136 178 137 179 func (s *State) reposPage(w http.ResponseWriter, r *http.Request) { 138 - ident, ok := r.Context().Value("resolvedId").(identity.Identity) 139 - if !ok { 140 - s.pages.Error404(w) 180 + pageWithProfile := s.profilePage(w, r) 181 + if pageWithProfile == nil { 141 182 return 142 183 } 143 184 144 - profile, err := db.GetProfile(s.db, ident.DID.String()) 145 - if err != nil { 146 - log.Printf("getting profile data for %s: %s", ident.DID.String(), err) 147 - } 148 - 185 + id := pageWithProfile.Id 149 186 repos, err := db.GetRepos( 150 187 s.db, 151 188 0, 152 - db.FilterEq("did", ident.DID.String()), 189 + db.FilterEq("did", id.DID), 153 190 ) 154 191 if err != nil { 155 - log.Printf("getting repos for %s: %s", ident.DID.String(), err) 156 - } 157 - 158 - loggedInUser := s.oauth.GetUser(r) 159 - followStatus := db.IsNotFollowing 160 - if loggedInUser != nil { 161 - followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String()) 162 - } 163 - 164 - followers, following, err := db.GetFollowerFollowingCount(s.db, ident.DID.String()) 165 - if err != nil { 166 - log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err) 192 + log.Printf("getting repos for %s: %s", id.DID, err) 167 193 } 168 194 169 195 s.pages.ReposPage(w, pages.ReposPageParams{ 170 - LoggedInUser: loggedInUser, 196 + LoggedInUser: pageWithProfile.LoggedInUser, 171 197 Repos: repos, 172 - Card: pages.ProfileCard{ 173 - UserDid: ident.DID.String(), 174 - UserHandle: ident.Handle.String(), 175 - Profile: profile, 176 - FollowStatus: followStatus, 177 - FollowersCount: followers, 178 - FollowingCount: following, 179 - }, 198 + Card: pageWithProfile.Card, 180 199 }) 181 200 } 182 201 ··· 187 206 } 188 207 189 208 func (s *State) followPage(w http.ResponseWriter, r *http.Request, fetchFollows func(db.Execer, string) ([]db.Follow, error), extractDid func(db.Follow) string) *FollowsPageParams { 190 - ident, ok := r.Context().Value("resolvedId").(identity.Identity) 191 - if !ok { 192 - s.pages.Error404(w) 209 + pageWithProfile := s.profilePage(w, r) 210 + if pageWithProfile == nil { 193 211 return nil 194 212 } 195 - did := ident.DID.String() 196 213 197 - profile, err := db.GetProfile(s.db, did) 198 - if err != nil { 199 - log.Printf("getting profile data for %s: %s", did, err) 200 - } 214 + id := pageWithProfile.Id 201 215 202 - loggedInUser := s.oauth.GetUser(r) 203 - 204 - follows, err := fetchFollows(s.db, did) 216 + follows, err := fetchFollows(s.db, id.DID.String()) 205 217 if err != nil { 206 - log.Printf("getting followers for %s: %s", did, err) 218 + log.Printf("getting followers for %s: %s", id.DID, err) 207 219 } 208 220 209 221 if len(follows) == 0 { ··· 221 233 return nil 222 234 } 223 235 236 + loggedInUser := pageWithProfile.LoggedInUser 224 237 var loggedInUserFollowing map[string]struct{} 225 238 if loggedInUser != nil { 226 239 following, err := db.GetFollowing(s.db, loggedInUser.Did) ··· 265 278 }) 266 279 } 267 280 268 - followStatus := db.IsNotFollowing 269 - if loggedInUser != nil { 270 - followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, did) 271 - } 272 - 273 - followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did) 274 - if err != nil { 275 - log.Printf("getting follow stats followers for %s: %s", did, err) 276 - } 277 - 278 281 return &FollowsPageParams{ 279 282 LoggedInUser: loggedInUser, 280 283 Follows: followCards, 281 - Card: pages.ProfileCard{ 282 - UserDid: did, 283 - UserHandle: ident.Handle.String(), 284 - Profile: profile, 285 - FollowStatus: followStatus, 286 - FollowersCount: followersCount, 287 - FollowingCount: followingCount, 288 - }, 284 + Card: pageWithProfile.Card, 289 285 } 290 286 } 291 287
+2 -2
.jjconflict-side-1/appview/pages/pages.go
··· 408 408 return p.execute("repo/fork", w, params) 409 409 } 410 410 411 - type ProfilePageParams struct { 411 + type ProfileHomePageParams struct { 412 412 LoggedInUser *oauth.User 413 413 Repos []db.Repo 414 414 CollaboratingRepos []db.Repo ··· 427 427 Profile *db.Profile 428 428 } 429 429 430 - func (p *Pages) ProfilePage(w io.Writer, params ProfilePageParams) error { 430 + func (p *Pages) ProfileHomePage(w io.Writer, params ProfileHomePageParams) error { 431 431 return p.execute("user/profile", w, params) 432 432 } 433 433
+125 -110
.jjconflict-side-1/appview/state/profile.go
··· 25 25 tabVal := r.URL.Query().Get("tab") 26 26 switch tabVal { 27 27 case "": 28 - s.profilePage(w, r) 28 + s.profileHomePage(w, r) 29 29 case "repos": 30 30 s.reposPage(w, r) 31 31 case "followers": ··· 35 35 } 36 36 } 37 37 38 - func (s *State) profilePage(w http.ResponseWriter, r *http.Request) { 38 + type ProfilePageParams struct { 39 + Id identity.Identity 40 + LoggedInUser *oauth.User 41 + Card pages.ProfileCard 42 + } 43 + 44 + func (s *State) profilePage(w http.ResponseWriter, r *http.Request) *ProfilePageParams { 39 45 didOrHandle := chi.URLParam(r, "user") 40 46 if didOrHandle == "" { 41 - http.Error(w, "Bad request", http.StatusBadRequest) 42 - return 47 + http.Error(w, "bad request", http.StatusBadRequest) 48 + return nil 43 49 } 44 50 45 51 ident, ok := r.Context().Value("resolvedId").(identity.Identity) 46 52 if !ok { 47 - s.pages.Error404(w) 48 - return 53 + log.Printf("malformed middleware") 54 + w.WriteHeader(http.StatusInternalServerError) 55 + return nil 56 + } 57 + did := ident.DID.String() 58 + 59 + profile, err := db.GetProfile(s.db, did) 60 + if err != nil { 61 + log.Printf("getting profile data for %s: %s", did, err) 49 62 } 50 63 51 - profile, err := db.GetProfile(s.db, ident.DID.String()) 64 + followStats, err := db.GetFollowerFollowingCount(s.db, did) 52 65 if err != nil { 53 - log.Printf("getting profile data for %s: %s", ident.DID.String(), err) 66 + log.Printf("getting follow stats for %s: %s", did, err) 67 + } 68 + 69 + loggedInUser := s.oauth.GetUser(r) 70 + followStatus := db.IsNotFollowing 71 + if loggedInUser != nil { 72 + followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, did) 54 73 } 55 74 75 + return &ProfilePageParams{ 76 + Id: ident, 77 + LoggedInUser: loggedInUser, 78 + Card: pages.ProfileCard{ 79 + UserDid: did, 80 + UserHandle: ident.Handle.String(), 81 + Profile: profile, 82 + FollowStatus: followStatus, 83 + FollowersCount: followStats.Followers, 84 + FollowingCount: followStats.Following, 85 + }, 86 + } 87 + } 88 + 89 + func (s *State) profileHomePage(w http.ResponseWriter, r *http.Request) { 90 + pageWithProfile := s.profilePage(w, r) 91 + if pageWithProfile == nil { 92 + return 93 + } 94 + 95 + id := pageWithProfile.Id 56 96 repos, err := db.GetRepos( 57 97 s.db, 58 98 0, 59 - db.FilterEq("did", ident.DID.String()), 99 + db.FilterEq("did", id.DID), 60 100 ) 61 101 if err != nil { 62 - log.Printf("getting repos for %s: %s", ident.DID.String(), err) 102 + log.Printf("getting repos for %s: %s", id.DID, err) 63 103 } 64 104 105 + profile := pageWithProfile.Card.Profile 65 106 // filter out ones that are pinned 66 107 pinnedRepos := []db.Repo{} 67 108 for i, r := range repos { ··· 76 117 } 77 118 } 78 119 79 - collaboratingRepos, err := db.CollaboratingIn(s.db, ident.DID.String()) 120 + collaboratingRepos, err := db.CollaboratingIn(s.db, id.DID.String()) 80 121 if err != nil { 81 - log.Printf("getting collaborating repos for %s: %s", ident.DID.String(), err) 122 + log.Printf("getting collaborating repos for %s: %s", id.DID, err) 82 123 } 83 124 84 125 pinnedCollaboratingRepos := []db.Repo{} ··· 89 130 } 90 131 } 91 132 92 - timeline, err := db.MakeProfileTimeline(s.db, ident.DID.String()) 133 + timeline, err := db.MakeProfileTimeline(s.db, id.DID.String()) 93 134 if err != nil { 94 - log.Printf("failed to create profile timeline for %s: %s", ident.DID.String(), err) 135 + log.Printf("failed to create profile timeline for %s: %s", id.DID, err) 95 136 } 96 137 97 - followers, following, err := db.GetFollowerFollowingCount(s.db, ident.DID.String()) 98 - if err != nil { 99 - log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err) 138 + var didsToResolve []string 139 + for _, r := range collaboratingRepos { 140 + didsToResolve = append(didsToResolve, r.Did) 100 141 } 101 - 102 - loggedInUser := s.oauth.GetUser(r) 103 - followStatus := db.IsNotFollowing 104 - if loggedInUser != nil { 105 - followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String()) 142 + for _, byMonth := range timeline.ByMonth { 143 + for _, pe := range byMonth.PullEvents.Items { 144 + didsToResolve = append(didsToResolve, pe.Repo.Did) 145 + } 146 + for _, ie := range byMonth.IssueEvents.Items { 147 + didsToResolve = append(didsToResolve, ie.Metadata.Repo.Did) 148 + } 149 + for _, re := range byMonth.RepoEvents { 150 + didsToResolve = append(didsToResolve, re.Repo.Did) 151 + if re.Source != nil { 152 + didsToResolve = append(didsToResolve, re.Source.Did) 153 + } 154 + } 106 155 } 107 156 108 157 now := time.Now() 109 158 startOfYear := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC) 110 159 punchcard, err := db.MakePunchcard( 111 160 s.db, 112 - db.FilterEq("did", ident.DID.String()), 161 + db.FilterEq("did", id.DID), 113 162 db.FilterGte("date", startOfYear.Format(time.DateOnly)), 114 163 db.FilterLte("date", now.Format(time.DateOnly)), 115 164 ) 116 165 if err != nil { 117 - log.Println("failed to get punchcard for did", "did", ident.DID.String(), "err", err) 166 + log.Println("failed to get punchcard for did", "did", id.DID, "err", err) 118 167 } 119 168 120 - s.pages.ProfilePage(w, pages.ProfilePageParams{ 121 - LoggedInUser: loggedInUser, 169 + s.pages.ProfileHomePage(w, pages.ProfileHomePageParams{ 170 + LoggedInUser: pageWithProfile.LoggedInUser, 122 171 Repos: pinnedRepos, 123 172 CollaboratingRepos: pinnedCollaboratingRepos, 124 - Card: pages.ProfileCard{ 125 - UserDid: ident.DID.String(), 126 - UserHandle: ident.Handle.String(), 127 - Profile: profile, 128 - FollowStatus: followStatus, 129 - FollowersCount: followers, 130 - FollowingCount: following, 131 - }, 132 - Punchcard: punchcard, 133 - ProfileTimeline: timeline, 173 + Card: pageWithProfile.Card, 174 + Punchcard: punchcard, 175 + ProfileTimeline: timeline, 134 176 }) 135 177 } 136 178 137 179 func (s *State) reposPage(w http.ResponseWriter, r *http.Request) { 138 - ident, ok := r.Context().Value("resolvedId").(identity.Identity) 139 - if !ok { 140 - s.pages.Error404(w) 180 + pageWithProfile := s.profilePage(w, r) 181 + if pageWithProfile == nil { 141 182 return 142 183 } 143 184 144 - profile, err := db.GetProfile(s.db, ident.DID.String()) 145 - if err != nil { 146 - log.Printf("getting profile data for %s: %s", ident.DID.String(), err) 147 - } 148 - 185 + id := pageWithProfile.Id 149 186 repos, err := db.GetRepos( 150 187 s.db, 151 188 0, 152 - db.FilterEq("did", ident.DID.String()), 189 + db.FilterEq("did", id.DID), 153 190 ) 154 191 if err != nil { 155 - log.Printf("getting repos for %s: %s", ident.DID.String(), err) 156 - } 157 - 158 - loggedInUser := s.oauth.GetUser(r) 159 - followStatus := db.IsNotFollowing 160 - if loggedInUser != nil { 161 - followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String()) 162 - } 163 - 164 - followers, following, err := db.GetFollowerFollowingCount(s.db, ident.DID.String()) 165 - if err != nil { 166 - log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err) 192 + log.Printf("getting repos for %s: %s", id.DID, err) 167 193 } 168 194 169 195 s.pages.ReposPage(w, pages.ReposPageParams{ 170 - LoggedInUser: loggedInUser, 196 + LoggedInUser: pageWithProfile.LoggedInUser, 171 197 Repos: repos, 172 - Card: pages.ProfileCard{ 173 - UserDid: ident.DID.String(), 174 - UserHandle: ident.Handle.String(), 175 - Profile: profile, 176 - FollowStatus: followStatus, 177 - FollowersCount: followers, 178 - FollowingCount: following, 179 - }, 198 + Card: pageWithProfile.Card, 180 199 }) 181 200 } 182 201 ··· 186 205 Card pages.ProfileCard 187 206 } 188 207 189 - func (s *State) followPage(w http.ResponseWriter, r *http.Request, fetchFollows func(db.Execer, string) ([]db.Follow, error), extractDid func(db.Follow) string) *FollowsPageParams { 190 - ident, ok := r.Context().Value("resolvedId").(identity.Identity) 191 - if !ok { 192 - s.pages.Error404(w) 193 - return nil 194 - } 195 - did := ident.DID.String() 196 - 197 - profile, err := db.GetProfile(s.db, did) 198 - if err != nil { 199 - log.Printf("getting profile data for %s: %s", did, err) 208 + func (s *State) followPage(w http.ResponseWriter, r *http.Request, fetchFollows func(db.Execer, string) ([]db.Follow, error), extractDid func(db.Follow) string) (FollowsPageParams, error) { 209 + pageWithProfile := s.profilePage(w, r) 210 + if pageWithProfile == nil { 211 + return FollowsPageParams{}, nil 200 212 } 201 213 202 - loggedInUser := s.oauth.GetUser(r) 214 + id := pageWithProfile.Id 215 + loggedInUser := pageWithProfile.LoggedInUser 203 216 204 - follows, err := fetchFollows(s.db, did) 217 + follows, err := fetchFollows(s.db, id.DID.String()) 205 218 if err != nil { 206 - log.Printf("getting followers for %s: %s", did, err) 219 + log.Printf("getting followers for %s: %s", id.DID, err) 220 + return FollowsPageParams{}, err 207 221 } 208 222 209 223 if len(follows) == 0 { 210 - return nil 224 + return FollowsPageParams{ 225 + LoggedInUser: loggedInUser, 226 + Follows: []pages.FollowCard{}, 227 + Card: pageWithProfile.Card, 228 + }, nil 211 229 } 212 230 213 231 followDids := make([]string, 0, len(follows)) ··· 218 236 profiles, err := db.GetProfiles(s.db, db.FilterIn("did", followDids)) 219 237 if err != nil { 220 238 log.Printf("getting profile for %s: %s", followDids, err) 221 - return nil 239 + return FollowsPageParams{}, err 240 + } 241 + 242 + followStatsMap, err := db.GetFollowerFollowingCounts(s.db, followDids) 243 + if err != nil { 244 + log.Printf("getting follow counts for %s: %s", followDids, err) 245 + return FollowsPageParams{}, err 222 246 } 223 247 224 248 var loggedInUserFollowing map[string]struct{} 225 249 if loggedInUser != nil { 226 250 following, err := db.GetFollowing(s.db, loggedInUser.Did) 227 251 if err != nil { 228 - return nil 252 + return FollowsPageParams{}, err 229 253 } 230 254 if len(following) > 0 { 231 255 loggedInUserFollowing = make(map[string]struct{}, len(following)) ··· 237 261 238 262 followCards := make([]pages.FollowCard, 0, len(follows)) 239 263 for _, did := range followDids { 240 - followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did) 241 - if err != nil { 242 - log.Printf("getting follow stats for %s: %s", did, err) 264 + followStats, exists := followStatsMap[did] 265 + if !exists { 266 + followStats = db.FollowStats{} 243 267 } 244 268 followStatus := db.IsNotFollowing 245 269 if loggedInUserFollowing != nil { ··· 259 283 followCards = append(followCards, pages.FollowCard{ 260 284 UserDid: did, 261 285 FollowStatus: followStatus, 262 - FollowersCount: followersCount, 263 - FollowingCount: followingCount, 286 + FollowersCount: followStats.Followers, 287 + FollowingCount: followStats.Following, 264 288 Profile: profile, 265 289 }) 266 290 } 267 291 268 - followStatus := db.IsNotFollowing 269 - if loggedInUser != nil { 270 - followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, did) 271 - } 272 - 273 - followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did) 274 - if err != nil { 275 - log.Printf("getting follow stats followers for %s: %s", did, err) 276 - } 277 - 278 - return &FollowsPageParams{ 292 + return FollowsPageParams{ 279 293 LoggedInUser: loggedInUser, 280 294 Follows: followCards, 281 - Card: pages.ProfileCard{ 282 - UserDid: did, 283 - UserHandle: ident.Handle.String(), 284 - Profile: profile, 285 - FollowStatus: followStatus, 286 - FollowersCount: followersCount, 287 - FollowingCount: followingCount, 288 - }, 289 - } 295 + Card: pageWithProfile.Card, 296 + }, nil 290 297 } 291 298 292 299 func (s *State) followersPage(w http.ResponseWriter, r *http.Request) { 293 - followPage := s.followPage(w, r, db.GetFollowers, func(f db.Follow) string { return f.UserDid }) 300 + followPage, err := s.followPage(w, r, db.GetFollowers, func(f db.Follow) string { return f.UserDid }) 301 + if err != nil { 302 + s.pages.Notice(w, "all-followers", "Failed to load followers") 303 + return 304 + } 294 305 295 306 s.pages.FollowersPage(w, pages.FollowersPageParams{ 296 307 LoggedInUser: followPage.LoggedInUser, ··· 300 311 } 301 312 302 313 func (s *State) followingPage(w http.ResponseWriter, r *http.Request) { 303 - followPage := s.followPage(w, r, db.GetFollowing, func(f db.Follow) string { return f.SubjectDid }) 314 + followPage, err := s.followPage(w, r, db.GetFollowing, func(f db.Follow) string { return f.SubjectDid }) 315 + if err != nil { 316 + s.pages.Notice(w, "all-following", "Failed to load following") 317 + return 318 + } 304 319 305 320 s.pages.FollowingPage(w, pages.FollowingPageParams{ 306 321 LoggedInUser: followPage.LoggedInUser,
+2 -2
.jjconflict-side-2/appview/pages/pages.go
··· 408 408 return p.execute("repo/fork", w, params) 409 409 } 410 410 411 - type ProfilePageParams struct { 411 + type ProfileHomePageParams struct { 412 412 LoggedInUser *oauth.User 413 413 Repos []db.Repo 414 414 CollaboratingRepos []db.Repo ··· 427 427 Profile *db.Profile 428 428 } 429 429 430 - func (p *Pages) ProfilePage(w io.Writer, params ProfilePageParams) error { 430 + func (p *Pages) ProfileHomePage(w io.Writer, params ProfileHomePageParams) error { 431 431 return p.execute("user/profile", w, params) 432 432 } 433 433
.jjconflict-side-1/appview/pages/templates/timeline.html .jjconflict-side-2/appview/pages/templates/timeline.html
+18 -37
.jjconflict-side-2/appview/state/profile.go
··· 61 61 log.Printf("getting profile data for %s: %s", did, err) 62 62 } 63 63 64 - followStats, err := db.GetFollowerFollowingCount(s.db, did) 64 + followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did) 65 65 if err != nil { 66 66 log.Printf("getting follow stats for %s: %s", did, err) 67 67 } ··· 80 80 UserHandle: ident.Handle.String(), 81 81 Profile: profile, 82 82 FollowStatus: followStatus, 83 - FollowersCount: followStats.Followers, 84 - FollowingCount: followStats.Following, 83 + FollowersCount: followersCount, 84 + FollowingCount: followingCount, 85 85 }, 86 86 } 87 87 } ··· 205 205 Card pages.ProfileCard 206 206 } 207 207 208 - func (s *State) followPage(w http.ResponseWriter, r *http.Request, fetchFollows func(db.Execer, string) ([]db.Follow, error), extractDid func(db.Follow) string) (FollowsPageParams, error) { 208 + func (s *State) followPage(w http.ResponseWriter, r *http.Request, fetchFollows func(db.Execer, string) ([]db.Follow, error), extractDid func(db.Follow) string) *FollowsPageParams { 209 209 pageWithProfile := s.profilePage(w, r) 210 210 if pageWithProfile == nil { 211 - return FollowsPageParams{}, nil 211 + return nil 212 212 } 213 213 214 214 id := pageWithProfile.Id 215 - loggedInUser := pageWithProfile.LoggedInUser 216 215 217 216 follows, err := fetchFollows(s.db, id.DID.String()) 218 217 if err != nil { 219 218 log.Printf("getting followers for %s: %s", id.DID, err) 220 - return FollowsPageParams{}, err 221 219 } 222 220 223 221 if len(follows) == 0 { 224 - return FollowsPageParams{ 225 - LoggedInUser: loggedInUser, 226 - Follows: []pages.FollowCard{}, 227 - Card: pageWithProfile.Card, 228 - }, nil 222 + return nil 229 223 } 230 224 231 225 followDids := make([]string, 0, len(follows)) ··· 236 230 profiles, err := db.GetProfiles(s.db, db.FilterIn("did", followDids)) 237 231 if err != nil { 238 232 log.Printf("getting profile for %s: %s", followDids, err) 239 - return FollowsPageParams{}, err 240 - } 241 - 242 - followStatsMap, err := db.GetFollowerFollowingCounts(s.db, followDids) 243 - if err != nil { 244 - log.Printf("getting follow counts for %s: %s", followDids, err) 245 - return FollowsPageParams{}, err 233 + return nil 246 234 } 247 235 236 + loggedInUser := pageWithProfile.LoggedInUser 248 237 var loggedInUserFollowing map[string]struct{} 249 238 if loggedInUser != nil { 250 239 following, err := db.GetFollowing(s.db, loggedInUser.Did) 251 240 if err != nil { 252 - return FollowsPageParams{}, err 241 + return nil 253 242 } 254 243 if len(following) > 0 { 255 244 loggedInUserFollowing = make(map[string]struct{}, len(following)) ··· 261 250 262 251 followCards := make([]pages.FollowCard, 0, len(follows)) 263 252 for _, did := range followDids { 264 - followStats, exists := followStatsMap[did] 265 - if !exists { 266 - followStats = db.FollowStats{} 253 + followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did) 254 + if err != nil { 255 + log.Printf("getting follow stats for %s: %s", did, err) 267 256 } 268 257 followStatus := db.IsNotFollowing 269 258 if loggedInUserFollowing != nil { ··· 283 272 followCards = append(followCards, pages.FollowCard{ 284 273 UserDid: did, 285 274 FollowStatus: followStatus, 286 - FollowersCount: followStats.Followers, 287 - FollowingCount: followStats.Following, 275 + FollowersCount: followersCount, 276 + FollowingCount: followingCount, 288 277 Profile: profile, 289 278 }) 290 279 } 291 280 292 - return FollowsPageParams{ 281 + return &FollowsPageParams{ 293 282 LoggedInUser: loggedInUser, 294 283 Follows: followCards, 295 284 Card: pageWithProfile.Card, 296 - }, nil 285 + } 297 286 } 298 287 299 288 func (s *State) followersPage(w http.ResponseWriter, r *http.Request) { 300 - followPage, err := s.followPage(w, r, db.GetFollowers, func(f db.Follow) string { return f.UserDid }) 301 - if err != nil { 302 - s.pages.Notice(w, "all-followers", "Failed to load followers") 303 - return 304 - } 289 + followPage := s.followPage(w, r, db.GetFollowers, func(f db.Follow) string { return f.UserDid }) 305 290 306 291 s.pages.FollowersPage(w, pages.FollowersPageParams{ 307 292 LoggedInUser: followPage.LoggedInUser, ··· 311 296 } 312 297 313 298 func (s *State) followingPage(w http.ResponseWriter, r *http.Request) { 314 - followPage, err := s.followPage(w, r, db.GetFollowing, func(f db.Follow) string { return f.SubjectDid }) 315 - if err != nil { 316 - s.pages.Notice(w, "all-following", "Failed to load following") 317 - return 318 - } 299 + followPage := s.followPage(w, r, db.GetFollowing, func(f db.Follow) string { return f.SubjectDid }) 319 300 320 301 s.pages.FollowingPage(w, pages.FollowingPageParams{ 321 302 LoggedInUser: followPage.LoggedInUser,