From af82d9d6ecfb2e6b3538708bed4709146f291001 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 7fea71c9..ed3a4bab 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -234,7 +234,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 bba81eadd4320a4c0e9bbe560d3bb5a2d649fb11 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 95c6fb64..03bbc56d 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -306,6 +306,7 @@ type TimelineParams struct { LoggedInUser *oauth.User Timeline []models.TimelineEvent Repos []models.Repo + 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 ed3a4bab..2212a915 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -8,6 +8,7 @@ import ( "log" "log/slog" "net/http" + "strconv" "strings" "time" @@ -228,13 +229,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.") @@ -251,6 +253,7 @@ func (s *State) Timeline(w http.ResponseWriter, r *http.Request) { LoggedInUser: user, Timeline: timeline, Repos: repos, + Filtered: filtered, }) } @@ -293,7 +296,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.") @@ -311,6 +315,7 @@ func (s *State) Home(w http.ResponseWriter, r *http.Request) { LoggedInUser: nil, Timeline: timeline, Repos: repos, + Filtered: filtered, }) } @@ -630,3 +635,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