From 9366b5f4e580002424cad397a5be372d83d845c7 Mon Sep 17 00:00:00 2001 From: Will Andrews Date: Wed, 1 Oct 2025 06:34:35 +0100 Subject: [PATCH] appview: allow timeline db queries to be filterable by users follows Signed-off-by: Will Andrews --- appview/db/timeline.go | 48 +++++++++++++++++++++++++++++++++--------- appview/state/state.go | 2 +- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/appview/db/timeline.go b/appview/db/timeline.go index c74b1e4e..46439c77 100644 --- a/appview/db/timeline.go +++ b/appview/db/timeline.go @@ -9,20 +9,33 @@ import ( // TODO: this gathers heterogenous events from different sources and aggregates // them in code; if we did this entirely in sql, we could order and limit and paginate easily -func MakeTimeline(e Execer, limit int, loggedInUserDid string) ([]models.TimelineEvent, error) { +func MakeTimeline(e Execer, limit int, loggedInUserDid string, limitToUsersIsFollowing bool) ([]models.TimelineEvent, error) { var events []models.TimelineEvent - repos, err := getTimelineRepos(e, limit, loggedInUserDid) + var userIsFollowing []string + if limitToUsersIsFollowing { + following, err := GetFollowing(e, loggedInUserDid) + if err != nil { + return nil, err + } + + userIsFollowing = make([]string, 0, len(following)) + for _, follow := range following { + userIsFollowing = append(userIsFollowing, follow.SubjectDid) + } + } + + repos, err := getTimelineRepos(e, limit, loggedInUserDid, userIsFollowing) if err != nil { return nil, err } - stars, err := getTimelineStars(e, limit, loggedInUserDid) + stars, err := getTimelineStars(e, limit, loggedInUserDid, userIsFollowing) if err != nil { return nil, err } - follows, err := getTimelineFollows(e, limit, loggedInUserDid) + follows, err := getTimelineFollows(e, limit, loggedInUserDid, userIsFollowing) if err != nil { return nil, err } @@ -70,8 +83,13 @@ func getRepoStarInfo(repo *models.Repo, starStatuses map[string]bool) (bool, int return isStarred, starCount } -func getTimelineRepos(e Execer, limit int, loggedInUserDid string) ([]models.TimelineEvent, error) { - repos, err := GetRepos(e, limit) +func getTimelineRepos(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { + filters := make([]filter, 0) + if userIsFollowing != nil { + filters = append(filters, FilterIn("did", userIsFollowing)) + } + + repos, err := GetRepos(e, limit, filters...) if err != nil { return nil, err } @@ -125,8 +143,13 @@ func getTimelineRepos(e Execer, limit int, loggedInUserDid string) ([]models.Tim return events, nil } -func getTimelineStars(e Execer, limit int, loggedInUserDid string) ([]models.TimelineEvent, error) { - stars, err := GetStars(e, limit) +func getTimelineStars(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { + filters := make([]filter, 0) + if userIsFollowing != nil { + filters = append(filters, FilterIn("starred_by_did", userIsFollowing)) + } + + stars, err := GetStars(e, limit, filters...) if err != nil { return nil, err } @@ -166,8 +189,13 @@ func getTimelineStars(e Execer, limit int, loggedInUserDid string) ([]models.Tim return events, nil } -func getTimelineFollows(e Execer, limit int, loggedInUserDid string) ([]models.TimelineEvent, error) { - follows, err := GetFollows(e, limit) +func getTimelineFollows(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { + filters := make([]filter, 0) + if userIsFollowing != nil { + filters = append(filters, FilterIn("user_did", userIsFollowing)) + } + + follows, err := GetFollows(e, limit, filters...) if err != nil { return nil, err } diff --git a/appview/state/state.go b/appview/state/state.go index 0a23b9ca..8cdd6cf1 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -257,7 +257,7 @@ func (s *State) Timeline(w http.ResponseWriter, r *http.Request) { if user != nil { userDid = user.Did } - timeline, err := db.MakeTimeline(s.db, 50, userDid) + timeline, err := db.MakeTimeline(s.db, 50, userDid, false) if err != nil { log.Println(err) s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") -- 2.43.0 From 2bb3d5d6cd3508ad0765f74e22d36066a6c6abbe Mon Sep 17 00:00:00 2001 From: Will Andrews Date: Sun, 5 Oct 2025 20:48:20 +0100 Subject: [PATCH] appview: allows the user to toggle between a filtered or non filtered timeline Signed-off-by: Will Andrews --- appview/pages/pages.go | 1 + .../timeline/fragments/timeline.html | 20 +++++++++++++++++-- appview/state/state.go | 19 ++++++++++++++++-- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/appview/pages/pages.go b/appview/pages/pages.go index c0d4a036..6302c8a6 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -307,6 +307,7 @@ type TimelineParams struct { Timeline []models.TimelineEvent Repos []models.Repo GfiLabel *models.LabelDefinition + Filtered bool } func (p *Pages) Timeline(w io.Writer, params TimelineParams) error { diff --git a/appview/pages/templates/timeline/fragments/timeline.html b/appview/pages/templates/timeline/fragments/timeline.html index 081e112a..ea0bbd7c 100644 --- a/appview/pages/templates/timeline/fragments/timeline.html +++ b/appview/pages/templates/timeline/fragments/timeline.html @@ -1,7 +1,23 @@ {{ define "timeline/fragments/timeline" }}
-
-

Timeline

+ +
+
+

Timeline

+
+ {{ if .LoggedInUser }} +
+ {{ if .Filtered }} + + Show All + + {{ else }} + + Show following only + + {{ end }} +
+ {{ end }}
diff --git a/appview/state/state.go b/appview/state/state.go index 8cdd6cf1..ea81b2c3 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -8,6 +8,7 @@ import ( "log" "log/slog" "net/http" + "strconv" "strings" "time" @@ -251,13 +252,14 @@ func (s *State) HomeOrTimeline(w http.ResponseWriter, r *http.Request) { } func (s *State) Timeline(w http.ResponseWriter, r *http.Request) { + filtered := getTimelineFilteredQuery(r) user := s.oauth.GetUser(r) var userDid string if user != nil { userDid = user.Did } - timeline, err := db.MakeTimeline(s.db, 50, userDid, false) + timeline, err := db.MakeTimeline(s.db, 50, userDid, filtered) if err != nil { log.Println(err) s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") @@ -280,6 +282,7 @@ func (s *State) Timeline(w http.ResponseWriter, r *http.Request) { Timeline: timeline, Repos: repos, GfiLabel: gfiLabel, + Filtered: filtered, })) } @@ -322,7 +325,8 @@ func (s *State) UpgradeBanner(w http.ResponseWriter, r *http.Request) { } func (s *State) Home(w http.ResponseWriter, r *http.Request) { - timeline, err := db.MakeTimeline(s.db, 5, "") + filtered := getTimelineFilteredQuery(r) + timeline, err := db.MakeTimeline(s.db, 5, "", filtered) if err != nil { log.Println(err) s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") @@ -340,6 +344,7 @@ func (s *State) Home(w http.ResponseWriter, r *http.Request) { LoggedInUser: nil, Timeline: timeline, Repos: repos, + Filtered: filtered, }) } @@ -659,3 +664,13 @@ func BackfillDefaultDefs(e db.Execer, r *idresolver.Resolver) error { return nil } + +func getTimelineFilteredQuery(r *http.Request) bool { + filteredStr := r.URL.Query().Get("filtered") + if filteredStr == "" { + return false + } + + res, _ := strconv.ParseBool(filteredStr) + return res +} -- 2.43.0