Monorepo for Tangled tangled.org

appview: allow timeline db queries to be filterable by users follows #626

closed opened by willdot.net targeting master from [deleted fork]: feat/filter-user-timeline

Signed-off-by: Will Andrews did:plc:dadhhalkfcq3gucaq25hjqon

Labels
enhancement
assignee

None yet.

Participants 3
AT URI
at://did:plc:dadhhalkfcq3gucaq25hjqon/sh.tangled.repo.pull/3m24d33byfj22
+474 -16
Diff #2
+38 -10
appview/db/timeline.go
··· 9 9 10 10 // TODO: this gathers heterogenous events from different sources and aggregates 11 11 // them in code; if we did this entirely in sql, we could order and limit and paginate easily 12 - func MakeTimeline(e Execer, limit int, loggedInUserDid string) ([]models.TimelineEvent, error) { 12 + func MakeTimeline(e Execer, limit int, loggedInUserDid string, limitToUsersIsFollowing bool) ([]models.TimelineEvent, error) { 13 13 var events []models.TimelineEvent 14 14 15 - repos, err := getTimelineRepos(e, limit, loggedInUserDid) 15 + var userIsFollowing []string 16 + if limitToUsersIsFollowing { 17 + following, err := GetFollowing(e, loggedInUserDid) 18 + if err != nil { 19 + return nil, err 20 + } 21 + 22 + userIsFollowing = make([]string, 0, len(following)) 23 + for _, follow := range following { 24 + userIsFollowing = append(userIsFollowing, follow.SubjectDid) 25 + } 26 + } 27 + 28 + repos, err := getTimelineRepos(e, limit, loggedInUserDid, userIsFollowing) 16 29 if err != nil { 17 30 return nil, err 18 31 } 19 32 20 - stars, err := getTimelineStars(e, limit, loggedInUserDid) 33 + stars, err := getTimelineStars(e, limit, loggedInUserDid, userIsFollowing) 21 34 if err != nil { 22 35 return nil, err 23 36 } 24 37 25 - follows, err := getTimelineFollows(e, limit, loggedInUserDid) 38 + follows, err := getTimelineFollows(e, limit, loggedInUserDid, userIsFollowing) 26 39 if err != nil { 27 40 return nil, err 28 41 } ··· 70 83 return isStarred, starCount 71 84 } 72 85 73 - func getTimelineRepos(e Execer, limit int, loggedInUserDid string) ([]models.TimelineEvent, error) { 74 - repos, err := GetRepos(e, limit) 86 + func getTimelineRepos(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { 87 + filters := make([]filter, 0) 88 + if userIsFollowing != nil { 89 + filters = append(filters, FilterIn("did", userIsFollowing)) 90 + } 91 + 92 + repos, err := GetRepos(e, limit, filters...) 75 93 if err != nil { 76 94 return nil, err 77 95 } ··· 125 143 return events, nil 126 144 } 127 145 128 - func getTimelineStars(e Execer, limit int, loggedInUserDid string) ([]models.TimelineEvent, error) { 129 - stars, err := GetStars(e, limit) 146 + func getTimelineStars(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { 147 + filters := make([]filter, 0) 148 + if userIsFollowing != nil { 149 + filters = append(filters, FilterIn("starred_by_did", userIsFollowing)) 150 + } 151 + 152 + stars, err := GetStars(e, limit, filters...) 130 153 if err != nil { 131 154 return nil, err 132 155 } ··· 166 189 return events, nil 167 190 } 168 191 169 - func getTimelineFollows(e Execer, limit int, loggedInUserDid string) ([]models.TimelineEvent, error) { 170 - follows, err := GetFollows(e, limit) 192 + func getTimelineFollows(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { 193 + filters := make([]filter, 0) 194 + if userIsFollowing != nil { 195 + filters = append(filters, FilterIn("user_did", userIsFollowing)) 196 + } 197 + 198 + follows, err := GetFollows(e, limit, filters...) 171 199 if err != nil { 172 200 return nil, err 173 201 }
+417 -4
appview/state/state.go
··· 5 5 6 6 7 7 8 + "log" 9 + "log/slog" 10 + "net/http" 11 + "strconv" 12 + "strings" 13 + "time" 8 14 9 15 10 16 ··· 243 249 244 250 245 251 252 + } 246 253 254 + func (s *State) Timeline(w http.ResponseWriter, r *http.Request) { 255 + filtered := getTimelineFilteredQuery(r) 256 + user := s.oauth.GetUser(r) 247 257 258 + var userDid string 259 + if user != nil { 260 + userDid = user.Did 261 + } 262 + timeline, err := db.MakeTimeline(s.db, 50, userDid, filtered) 263 + if err != nil { 264 + log.Println(err) 265 + s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") 248 266 249 267 250 268 ··· 254 272 255 273 256 274 257 - if user != nil { 258 - userDid = user.Did 259 - } 260 - timeline, err := db.MakeTimeline(s.db, 50, userDid) 275 + 276 + 277 + 278 + 279 + 280 + 281 + 282 + Timeline: timeline, 283 + Repos: repos, 284 + GfiLabel: gfiLabel, 285 + Filtered: filtered, 286 + })) 287 + } 288 + 289 + 290 + 291 + 292 + 293 + 294 + 295 + 296 + 297 + 298 + 299 + 300 + 301 + 302 + 303 + 304 + 305 + 306 + 307 + 308 + 309 + 310 + 311 + 312 + 313 + 314 + 315 + 316 + 317 + 318 + 319 + 320 + 321 + 322 + 323 + 324 + 325 + } 326 + 327 + func (s *State) Home(w http.ResponseWriter, r *http.Request) { 328 + filtered := getTimelineFilteredQuery(r) 329 + timeline, err := db.MakeTimeline(s.db, 5, "", filtered) 261 330 if err != nil { 262 331 log.Println(err) 263 332 s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") 333 + 334 + 335 + 336 + 337 + 338 + 339 + 340 + 341 + 342 + 343 + 344 + LoggedInUser: nil, 345 + Timeline: timeline, 346 + Repos: repos, 347 + Filtered: filtered, 348 + }) 349 + } 350 + 351 + 352 + 353 + 354 + 355 + 356 + 357 + 358 + 359 + 360 + 361 + 362 + 363 + 364 + 365 + 366 + 367 + 368 + 369 + 370 + 371 + 372 + 373 + 374 + 375 + 376 + 377 + 378 + 379 + 380 + 381 + 382 + 383 + 384 + 385 + 386 + 387 + 388 + 389 + 390 + 391 + 392 + 393 + 394 + 395 + 396 + 397 + 398 + 399 + 400 + 401 + 402 + 403 + 404 + 405 + 406 + 407 + 408 + 409 + 410 + 411 + 412 + 413 + 414 + 415 + 416 + 417 + 418 + 419 + 420 + 421 + 422 + 423 + 424 + 425 + 426 + 427 + 428 + 429 + 430 + 431 + 432 + 433 + 434 + 435 + 436 + 437 + 438 + 439 + 440 + 441 + 442 + 443 + 444 + 445 + 446 + 447 + 448 + 449 + 450 + 451 + 452 + 453 + 454 + 455 + 456 + 457 + 458 + 459 + 460 + 461 + 462 + 463 + 464 + 465 + 466 + 467 + 468 + 469 + 470 + 471 + 472 + 473 + 474 + 475 + 476 + 477 + 478 + 479 + 480 + 481 + 482 + 483 + 484 + 485 + 486 + 487 + 488 + 489 + 490 + 491 + 492 + 493 + 494 + 495 + 496 + 497 + 498 + 499 + 500 + 501 + 502 + 503 + 504 + 505 + 506 + 507 + 508 + 509 + 510 + 511 + 512 + 513 + 514 + 515 + 516 + 517 + 518 + 519 + 520 + 521 + 522 + 523 + 524 + 525 + 526 + 527 + 528 + 529 + 530 + 531 + 532 + 533 + 534 + 535 + 536 + 537 + 538 + 539 + 540 + 541 + 542 + 543 + 544 + 545 + 546 + 547 + 548 + 549 + 550 + 551 + 552 + 553 + 554 + 555 + 556 + 557 + 558 + 559 + 560 + 561 + 562 + 563 + 564 + 565 + 566 + 567 + 568 + 569 + 570 + 571 + 572 + 573 + 574 + 575 + 576 + 577 + 578 + 579 + 580 + 581 + 582 + 583 + 584 + 585 + 586 + 587 + 588 + 589 + 590 + 591 + 592 + 593 + 594 + 595 + 596 + 597 + 598 + 599 + 600 + 601 + 602 + 603 + 604 + 605 + 606 + 607 + 608 + 609 + 610 + 611 + 612 + 613 + 614 + 615 + 616 + 617 + 618 + 619 + 620 + 621 + 622 + 623 + 624 + 625 + 626 + 627 + 628 + 629 + 630 + 631 + 632 + 633 + 634 + 635 + 636 + 637 + 638 + 639 + 640 + 641 + 642 + 643 + 644 + 645 + 646 + 647 + 648 + 649 + 650 + 651 + 652 + 653 + 654 + 655 + 656 + 657 + 658 + 659 + 660 + 661 + 662 + 663 + 664 + 665 + return nil 666 + } 667 + 668 + func getTimelineFilteredQuery(r *http.Request) bool { 669 + filteredStr := r.URL.Query().Get("filtered") 670 + if filteredStr == "" { 671 + return false 672 + } 673 + 674 + res, _ := strconv.ParseBool(filteredStr) 675 + return res 676 + }
+1
appview/pages/pages.go
··· 307 307 Timeline []models.TimelineEvent 308 308 Repos []models.Repo 309 309 GfiLabel *models.LabelDefinition 310 + Filtered bool 310 311 } 311 312 312 313 func (p *Pages) Timeline(w io.Writer, params TimelineParams) error {
+18 -2
appview/pages/templates/timeline/fragments/timeline.html
··· 1 1 {{ define "timeline/fragments/timeline" }} 2 2 <div class="py-4"> 3 - <div class="px-6 pb-4"> 4 - <p class="text-xl font-bold dark:text-white">Timeline</p> 3 + 4 + <div class="flex gap-2 px-6 pb-4"> 5 + <div> 6 + <p class="text-xl font-bold dark:text-white">Timeline</p> 7 + </div> 8 + {{ if .LoggedInUser }} 9 + <div> 10 + {{ if .Filtered }} 11 + <a href="/timeline" class="hover:underline text-sm"> 12 + Show All 13 + </a> 14 + {{ else }} 15 + <a href="/timeline?filtered=true" class="hover:underline text-sm"> 16 + Show following only 17 + </a> 18 + {{ end }} 19 + </div> 20 + {{ end }} 5 21 </div> 6 22 7 23 <div class="flex flex-col gap-4">

History

5 rounds 4 comments
sign up or login to add to the discussion
6 commits
expand
d76a775d
appview: switch to indigo oauth library
4a1653c5
appview: improve logged-out CTAs
56721612
appview/{db,pages,models}: show tooltips for user handles when hovering on reactions
98084555
appview: allow timeline db queries to be filterable by users follows
e067fac7
appview: allows the user to toggle between a filtered or non filtered timeline
2812b7c6
remove the front end changes
expand 0 comments
closed without merging
5 commits
expand
d76a775d
appview: switch to indigo oauth library
4a1653c5
appview: improve logged-out CTAs
56721612
appview/{db,pages,models}: show tooltips for user handles when hovering on reactions
98084555
appview: allow timeline db queries to be filterable by users follows
e067fac7
appview: allows the user to toggle between a filtered or non filtered timeline
expand 0 comments
2 commits
expand
9366b5f4
appview: allow timeline db queries to be filterable by users follows
2bb3d5d6
appview: allows the user to toggle between a filtered or non filtered timeline
expand 1 comment

following up on discord for this patch, but it works like a charm!

2 commits
expand
af82d9d6
appview: allow timeline db queries to be filterable by users follows
bba81ead
appview: allows the user to toggle between a filtered or non filtered timeline
expand 0 comments
1 commit
expand
af82d9d6
appview: allow timeline db queries to be filterable by users follows
expand 3 comments

This paves the way for allowing users to filter their timeline by just content of users they follow. I'm not great at front end stuff so may need some help getting an actual toggle into the UI.

Note: See this issue as to why the PR has no description

https://tangled.org/@tangled.org/core/issues/241

I'd be happy to assist with the toggle. I'm out on vacation next week, but feel free to reach out on Discord after that :-)

Amazing, thank you! I was planning on giving it a go this weekend and see how I get on but will ping you if I fall into a pit of dispair.