From 56cccf13e921db5f80733485caa1951c040f7d05 Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Thu, 28 Aug 2025 09:46:42 +0100 Subject: [PATCH] appview/pages: add strings tab to profile Change-Id: txmszmkrslykpsuvluypvpvnmrqwkmms Signed-off-by: oppiliappan --- .../templates/layouts/fragments/topbar.html | 2 +- appview/pages/templates/user/strings.html | 45 +++++++++++++ appview/state/profile.go | 67 ++++++++++++++++--- appview/strings/strings.go | 60 +---------------- 4 files changed, 104 insertions(+), 70 deletions(-) create mode 100644 appview/pages/templates/user/strings.html diff --git a/appview/pages/templates/layouts/fragments/topbar.html b/appview/pages/templates/layouts/fragments/topbar.html index 20da4098..d581fbae 100644 --- a/appview/pages/templates/layouts/fragments/topbar.html +++ b/appview/pages/templates/layouts/fragments/topbar.html @@ -61,7 +61,7 @@ > profile repositories - strings + strings knots spindles settings diff --git a/appview/pages/templates/user/strings.html b/appview/pages/templates/user/strings.html new file mode 100644 index 00000000..6501485b --- /dev/null +++ b/appview/pages/templates/user/strings.html @@ -0,0 +1,45 @@ +{{ define "title" }}{{ or .Card.UserHandle .Card.UserDid }} · strings {{ end }} + +{{ define "profileContent" }} +
+ {{ block "allStrings" . }}{{ end }} +
+{{ end }} + +{{ define "allStrings" }} +
+ {{ range .Strings }} +
+ {{ template "singleString" (list $ .) }} +
+ {{ else }} +

This user does not have any strings yet.

+ {{ end }} +
+{{ end }} + +{{ define "singleString" }} + {{ $root := index . 0 }} + {{ $s := index . 1 }} +
+ + {{ with $s.Description }} +
+ {{ . }} +
+ {{ end }} + + {{ $stat := $s.Stats }} +
+ {{ $stat.LineCount }} line{{if ne $stat.LineCount 1}}s{{end}} + + {{ with $s.Edited }} + edited {{ template "repo/fragments/shortTimeAgo" . }} + {{ else }} + {{ template "repo/fragments/shortTimeAgo" $s.Created }} + {{ end }} +
+
+{{ end }} diff --git a/appview/state/profile.go b/appview/state/profile.go index 857f1bf6..71173c2c 100644 --- a/appview/state/profile.go +++ b/appview/state/profile.go @@ -24,8 +24,6 @@ import ( func (s *State) Profile(w http.ResponseWriter, r *http.Request) { tabVal := r.URL.Query().Get("tab") switch tabVal { - case "", "overview": - s.profileOverview(w, r) case "repos": s.reposPage(w, r) case "followers": @@ -34,6 +32,10 @@ func (s *State) Profile(w http.ResponseWriter, r *http.Request) { s.followingPage(w, r) case "starred": s.starredPage(w, r) + case "strings": + s.stringsPage(w, r) + default: + s.profileOverview(w, r) } } @@ -54,6 +56,21 @@ func (s *State) profile(r *http.Request) (*pages.ProfileCard, error) { return nil, fmt.Errorf("failed to get profile: %w", err) } + repoCount, err := db.CountRepos(s.db, db.FilterEq("did", did)) + if err != nil { + return nil, fmt.Errorf("failed to get repo count: %w", err) + } + + stringCount, err := db.CountStrings(s.db, db.FilterEq("did", did)) + if err != nil { + return nil, fmt.Errorf("failed to get string count: %w", err) + } + + starredCount, err := db.CountStars(s.db, db.FilterEq("starred_by_did", did)) + if err != nil { + return nil, fmt.Errorf("failed to get starred repo count: %w", err) + } + followStats, err := db.GetFollowerFollowingCount(s.db, did) if err != nil { return nil, fmt.Errorf("failed to get follower stats: %w", err) @@ -78,13 +95,18 @@ func (s *State) profile(r *http.Request) (*pages.ProfileCard, error) { } return &pages.ProfileCard{ - UserDid: did, - UserHandle: ident.Handle.String(), - Profile: profile, - FollowStatus: followStatus, - FollowersCount: followStats.Followers, - FollowingCount: followStats.Following, - Punchcard: punchcard, + UserDid: did, + UserHandle: ident.Handle.String(), + Profile: profile, + FollowStatus: followStatus, + Stats: pages.ProfileStats{ + RepoCount: repoCount, + StringCount: stringCount, + StarredCount: starredCount, + FollowersCount: followStats.Followers, + FollowingCount: followStats.Following, + }, + Punchcard: punchcard, }, nil } @@ -218,6 +240,31 @@ func (s *State) starredPage(w http.ResponseWriter, r *http.Request) { }) } +func (s *State) stringsPage(w http.ResponseWriter, r *http.Request) { + l := s.logger.With("handler", "stringsPage") + + profile, err := s.profile(r) + if err != nil { + l.Error("failed to build profile card", "err", err) + s.pages.Error500(w) + return + } + l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle) + + strings, err := db.GetStrings(s.db, 0, db.FilterEq("did", profile.UserDid)) + if err != nil { + l.Error("failed to get strings", "err", err) + s.pages.Error500(w) + return + } + + err = s.pages.ProfileStrings(w, pages.ProfileStringsParams{ + LoggedInUser: s.oauth.GetUser(r), + Strings: strings, + Card: profile, + }) +} + type FollowsPageParams struct { Follows []pages.FollowCard Card *pages.ProfileCard @@ -283,7 +330,7 @@ func (s *State) followPage( followStatus := db.IsNotFollowing if _, exists := loggedInUserFollowing[did]; exists { followStatus = db.IsFollowing - } else if loggedInUser.Did == did { + } else if loggedInUser != nil && loggedInUser.Did == did { followStatus = db.IsSelf } diff --git a/appview/strings/strings.go b/appview/strings/strings.go index 4af0b363..cb9328ab 100644 --- a/appview/strings/strings.go +++ b/appview/strings/strings.go @@ -5,7 +5,6 @@ import ( "log/slog" "net/http" "path" - "slices" "strconv" "time" @@ -161,64 +160,7 @@ func (s *Strings) contents(w http.ResponseWriter, r *http.Request) { } func (s *Strings) dashboard(w http.ResponseWriter, r *http.Request) { - l := s.Logger.With("handler", "dashboard") - - id, ok := r.Context().Value("resolvedId").(identity.Identity) - if !ok { - l.Error("malformed middleware") - w.WriteHeader(http.StatusInternalServerError) - return - } - l = l.With("did", id.DID, "handle", id.Handle) - - all, err := db.GetStrings( - s.Db, - 0, - db.FilterEq("did", id.DID), - ) - if err != nil { - l.Error("failed to fetch strings", "err", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - slices.SortFunc(all, func(a, b db.String) int { - if a.Created.After(b.Created) { - return -1 - } else { - return 1 - } - }) - - profile, err := db.GetProfile(s.Db, id.DID.String()) - if err != nil { - l.Error("failed to fetch user profile", "err", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - loggedInUser := s.OAuth.GetUser(r) - followStatus := db.IsNotFollowing - if loggedInUser != nil { - followStatus = db.GetFollowStatus(s.Db, loggedInUser.Did, id.DID.String()) - } - - followStats, err := db.GetFollowerFollowingCount(s.Db, id.DID.String()) - if err != nil { - l.Error("failed to get follow stats", "err", err) - } - - s.Pages.StringsDashboard(w, pages.StringsDashboardParams{ - LoggedInUser: s.OAuth.GetUser(r), - Card: pages.ProfileCard{ - UserDid: id.DID.String(), - UserHandle: id.Handle.String(), - Profile: profile, - FollowStatus: followStatus, - FollowersCount: followStats.Followers, - FollowingCount: followStats.Following, - }, - Strings: all, - }) + http.Redirect(w, r, fmt.Sprintf("/%s?tab=strings", chi.URLParam(r, "user")), http.StatusFound) } func (s *Strings) edit(w http.ResponseWriter, r *http.Request) { -- 2.43.0