back interdiff of round #5 and #4

appview: state: dedup profile pages #504

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