Monorepo for Tangled tangled.org

appview: implement follower and following pages for users #484

merged opened by ptr.pet targeting master from [deleted fork]: followers-following-list
Labels

None yet.

assignee

None yet.

Participants 2
AT URI
at://did:plc:dfl62fgb7wtjj3fcbb72naae/sh.tangled.repo.pull/3lwawsuk3de22
+62 -113
Interdiff #6 #7
appview/db/profile.go

This file has not been changed.

appview/db/timeline.go

This file has not been changed.

appview/pages/funcmap.go

This file has not been changed.

+5 -7
appview/pages/pages.go
··· 435 435 } 436 436 437 437 type FollowCard struct { 438 - UserDid string 439 - UserHandle string 440 - UserDisplayName string 441 - FollowStatus db.FollowStatus 442 - FollowersCount int 443 - FollowingCount int 444 - Profile *db.Profile 438 + UserDid string 439 + FollowStatus db.FollowStatus 440 + FollowersCount int 441 + FollowingCount int 442 + Profile *db.Profile 445 443 } 446 444 447 445 type FollowersPageParams struct {
appview/pages/templates/timeline.html

This file has not been changed.

appview/pages/templates/user/followers.html

This file has not been changed.

appview/pages/templates/user/following.html

This file has not been changed.

appview/pages/templates/user/fragments/follow.html

This file has not been changed.

+2 -2
appview/pages/templates/user/fragments/followCard.html
··· 1 1 {{ define "user/fragments/followCard" }} 2 - {{ $userIdent := didOrHandle .UserDid .UserHandle }} 2 + {{ $userIdent := resolve .UserDid }} 3 3 <div class="flex flex-col divide-y divide-gray-200 dark:divide-gray-700 border border-gray-200 dark:border-gray-700 rounded-sm"> 4 4 <div class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800 flex items-center gap-4"> 5 5 <div class="flex-shrink-0 max-h-full w-24 h-24"> ··· 8 8 9 9 <div class="flex-1 min-h-0 justify-around flex flex-col"> 10 10 <a href="/{{ $userIdent }}"> 11 - <span class="font-bold dark:text-white overflow-hidden text-ellipsis whitespace-nowrap max-w-full">{{ .UserDisplayName | truncateAt30 }}</span> 11 + <span class="font-bold dark:text-white overflow-hidden text-ellipsis whitespace-nowrap max-w-full">{{ $userIdent | truncateAt30 }}</span> 12 12 </a> 13 13 <p class="text-sm pb-2 md:pb-2">{{.Profile.Description}}</p> 14 14 <div class="text-sm flex items-center gap-2 my-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full">
appview/pages/templates/user/fragments/profileCard.html

This file has not been changed.

+55 -104
appview/state/profile.go
··· 195 195 }) 196 196 } 197 197 198 - func (s *State) makeFollowCards(ctx context.Context, loggedInUser *oauth.User, follows []db.Follow, extractDid func(db.Follow) string) ([]pages.FollowCard, error) { 198 + type FollowsPageParams struct { 199 + LoggedInUser *oauth.User 200 + Follows []pages.FollowCard 201 + Card pages.ProfileCard 202 + } 203 + 204 + func (s *State) followPage(w http.ResponseWriter, r *http.Request, fetchFollows func(db.Execer, string) ([]db.Follow, error), extractDid func(db.Follow) string) *FollowsPageParams { 205 + ident, ok := r.Context().Value("resolvedId").(identity.Identity) 206 + if !ok { 207 + s.pages.Error404(w) 208 + return nil 209 + } 210 + did := ident.DID.String() 211 + 212 + profile, err := db.GetProfile(s.db, did) 213 + if err != nil { 214 + log.Printf("getting profile data for %s: %s", did, err) 215 + } 216 + 217 + loggedInUser := s.oauth.GetUser(r) 218 + 219 + follows, err := fetchFollows(s.db, did) 220 + if err != nil { 221 + log.Printf("getting followers for %s: %s", did, err) 222 + } 223 + 199 224 if len(follows) == 0 { 200 - return nil, nil 225 + return nil 201 226 } 202 227 203 228 followDids := make([]string, 0, len(follows)) ··· 207 232 208 233 profiles, err := db.GetProfiles(s.db, db.FilterIn("did", followDids)) 209 234 if err != nil { 210 - return nil, err 235 + log.Printf("getting profile for %s: %s", followDids, err) 236 + return nil 211 237 } 212 238 213 239 var loggedInUserFollowing map[string]struct{} 214 240 if loggedInUser != nil { 215 241 following, err := db.GetFollowing(s.db, loggedInUser.Did) 216 242 if err != nil { 217 - return nil, err 243 + return nil 218 244 } 219 245 if len(following) > 0 { 220 246 loggedInUserFollowing = make(map[string]struct{}, len(following)) ··· 226 252 227 253 followCards := make([]pages.FollowCard, 0, len(follows)) 228 254 for _, did := range followDids { 229 - var handle string 230 - var displayName string 231 - if ident, err := s.idResolver.ResolveIdent(ctx, did); err != nil { 232 - log.Printf("can't resolve handle for %s: %s", did, err) 233 - displayName = did 234 - } else if ident.Handle.IsInvalidHandle() { 235 - displayName = fmt.Sprintf("handle.invalid (%s)", did) 236 - } else { 237 - displayName = ident.Handle.String() 238 - handle = ident.Handle.String() 239 - } 240 255 followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did) 241 256 if err != nil { 242 257 log.Printf("getting follow stats for %s: %s", did, err) ··· 257 272 profile.Did = did 258 273 } 259 274 followCards = append(followCards, pages.FollowCard{ 260 - UserDid: did, 261 - UserHandle: handle, 262 - UserDisplayName: displayName, 263 - FollowStatus: followStatus, 264 - FollowersCount: followersCount, 265 - FollowingCount: followingCount, 266 - Profile: profile, 275 + UserDid: did, 276 + FollowStatus: followStatus, 277 + FollowersCount: followersCount, 278 + FollowingCount: followingCount, 279 + Profile: profile, 267 280 }) 268 281 } 269 - return followCards, nil 270 - } 271 - 272 - func (s *State) followersPage(w http.ResponseWriter, r *http.Request) { 273 - ident, ok := r.Context().Value("resolvedId").(identity.Identity) 274 - if !ok { 275 - s.pages.Error404(w) 276 - return 277 - } 278 - 279 - profile, err := db.GetProfile(s.db, ident.DID.String()) 280 - if err != nil { 281 - log.Printf("getting profile data followers for %s: %s", ident.DID.String(), err) 282 - } 283 - 284 - loggedInUser := s.oauth.GetUser(r) 285 - 286 - followers, err := db.GetFollowers(s.db, ident.DID.String()) 287 - if err != nil { 288 - log.Printf("getting followers followers for %s: %s", ident.DID.String(), err) 289 - } 290 - followerCards, err := s.makeFollowCards( 291 - r.Context(), 292 - loggedInUser, 293 - followers, 294 - func(f db.Follow) string { return f.UserDid }, 295 - ) 296 - if err != nil { 297 - log.Printf("getting follow followers cards for %s: %s", ident.DID.String(), err) 298 - } 299 282 300 283 followStatus := db.IsNotFollowing 301 284 if loggedInUser != nil { 302 - followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String()) 285 + followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, did) 303 286 } 304 287 305 - followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, ident.DID.String()) 288 + followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, did) 306 289 if err != nil { 307 - log.Printf("getting follow stats followers for %s: %s", ident.DID.String(), err) 290 + log.Printf("getting follow stats followers for %s: %s", did, err) 308 291 } 309 292 310 - s.pages.FollowersPage(w, pages.FollowersPageParams{ 293 + return &FollowsPageParams{ 311 294 LoggedInUser: loggedInUser, 312 - Followers: followerCards, 295 + Follows: followCards, 313 296 Card: pages.ProfileCard{ 314 - UserDid: ident.DID.String(), 297 + UserDid: did, 315 298 UserHandle: ident.Handle.String(), 316 299 Profile: profile, 317 300 FollowStatus: followStatus, 318 301 FollowersCount: followersCount, 319 302 FollowingCount: followingCount, 320 303 }, 321 - }) 322 - } 323 - 324 - func (s *State) followingPage(w http.ResponseWriter, r *http.Request) { 325 - ident, ok := r.Context().Value("resolvedId").(identity.Identity) 326 - if !ok { 327 - s.pages.Error404(w) 328 - return 329 304 } 305 + } 330 306 331 - profile, err := db.GetProfile(s.db, ident.DID.String()) 332 - if err != nil { 333 - log.Printf("getting profile data following for %s: %s", ident.DID.String(), err) 334 - } 335 - 336 - loggedInUser := s.oauth.GetUser(r) 337 - 338 - following, err := db.GetFollowing(s.db, ident.DID.String()) 339 - if err != nil { 340 - log.Printf("getting following following for %s: %s", ident.DID.String(), err) 341 - } 342 - followingCards, err := s.makeFollowCards( 343 - r.Context(), 344 - loggedInUser, 345 - following, 346 - func(f db.Follow) string { return f.SubjectDid }, 347 - ) 348 - if err != nil { 349 - log.Printf("getting follow following cards for %s: %s", ident.DID.String(), err) 350 - } 307 + func (s *State) followersPage(w http.ResponseWriter, r *http.Request) { 308 + followPage := s.followPage(w, r, db.GetFollowers, func(f db.Follow) string { return f.UserDid }) 351 309 352 - followStatus := db.IsNotFollowing 353 - if loggedInUser != nil { 354 - followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String()) 355 - } 310 + s.pages.FollowersPage(w, pages.FollowersPageParams{ 311 + LoggedInUser: followPage.LoggedInUser, 312 + Followers: followPage.Follows, 313 + Card: followPage.Card, 314 + }) 315 + } 356 316 357 - followersCount, followingCount, err := db.GetFollowerFollowingCount(s.db, ident.DID.String()) 358 - if err != nil { 359 - log.Printf("getting follow stats following for %s: %s", ident.DID.String(), err) 360 - } 317 + func (s *State) followingPage(w http.ResponseWriter, r *http.Request) { 318 + followPage := s.followPage(w, r, db.GetFollowing, func(f db.Follow) string { return f.SubjectDid }) 361 319 362 320 s.pages.FollowingPage(w, pages.FollowingPageParams{ 363 - LoggedInUser: loggedInUser, 364 - Following: followingCards, 365 - Card: pages.ProfileCard{ 366 - UserDid: ident.DID.String(), 367 - UserHandle: ident.Handle.String(), 368 - Profile: profile, 369 - FollowStatus: followStatus, 370 - FollowersCount: followersCount, 371 - FollowingCount: followingCount, 372 - }, 321 + LoggedInUser: followPage.LoggedInUser, 322 + Following: followPage.Follows, 323 + Card: followPage.Card, 373 324 }) 374 325 } 375 326
appview/state/router.go

This file has not been changed.

appview/strings/strings.go

This file has not been changed.

History

14 rounds 6 comments
sign up or login to add to the discussion
1 commit
expand
cb75b373
appview: implement follower and following pages for users
expand 0 comments
pull request successfully merged
1 commit
expand
98413d89
appview: implement follower and following pages for users
expand 0 comments
1 commit
expand
118fb342
appview: implement follower and following pages for users
expand 0 comments
1 commit
expand
7a5c931a
appview: implement follower and following pages for users
expand 0 comments
1 commit
expand
773aa964
appview: implement follower and following pages for users
expand 1 comment
  • fixed timeline linking to wrong user (forgot to use subjectHandle instead of userHandle)
  • use ?tab= for followers / following like repo page does
  • fix repos opengraph url from /repos to ?tab=repos
1 commit
expand
ece60a35
appview: implement follower and following pages for users
expand 1 comment
  • added following / follower page links to timeline and follow cards
  • also added followers and following to profile tab switch case
1 commit
expand
a8bcde9d
appview: implement follower and following pages for users
expand 1 comment

using resolve in html instead of resolving handles in go code, and dedupped followers/followingPage into followPage

1 commit
expand
a285cd0f
appview: implement follower and following pages for users
expand 0 comments
1 commit
expand
3c2d8223
appview: implement follower and following pages for users
expand 1 comment

fixed some issues now that i got my dev setup working again

1 commit
expand
90b0a392
appview: implement follower and following pages for users
expand 1 comment

comments from #1 should be addressed now

on top of that changed GetProfiles to return a map instead of array, which seemed easier to do since it internally uses a map anyway and both places it's used in need it as a map

1 commit
expand
0dfc15e9
appview: implement follower and following pages for users
expand 0 comments
1 commit
expand
9643a898
appview: implement follower and following pages for users
expand 0 comments
1 commit
expand
cf9a2ce8
appview: implement follower and following pages for users
expand 1 comment

the pages themselves look pretty good for a start!

  • i'd like to add follower-following count to each item (to make these identical to the profile cards in the timeline)
  • this GetProfile call results in an N+1 query. we have a helper called GetProfiles to help with this, you can get profiles of multiple DIDs in one DB call. db/timeline.go has an example of the same.

overall, i'm loving this stack!

ptr.pet submitted #0
1 commit
expand
cbdbaf6d
appview: implement follower and following pages for users
expand 0 comments