···
"github.com/gorilla/feeds"
"tangled.sh/tangled.sh/core/api/tangled"
"tangled.sh/tangled.sh/core/appview/db"
20
-
"tangled.sh/tangled.sh/core/appview/oauth"
20
+
// "tangled.sh/tangled.sh/core/appview/oauth"
"tangled.sh/tangled.sh/core/appview/pages"
func (s *State) Profile(w http.ResponseWriter, r *http.Request) {
tabVal := r.URL.Query().Get("tab")
28
-
s.profileHomePage(w, r)
27
+
case "", "overview":
28
+
s.profileOverview(w, r)
38
-
type ProfilePageParams struct {
39
-
Id identity.Identity
40
-
LoggedInUser *oauth.User
41
-
Card pages.ProfileCard
44
-
func (s *State) profilePage(w http.ResponseWriter, r *http.Request) *ProfilePageParams {
40
+
func (s *State) profile(r *http.Request) (*pages.ProfileCard, error) {
didOrHandle := chi.URLParam(r, "user")
47
-
http.Error(w, "bad request", http.StatusBadRequest)
43
+
return nil, fmt.Errorf("empty DID or handle")
ident, ok := r.Context().Value("resolvedId").(identity.Identity)
53
-
log.Printf("malformed middleware")
54
-
w.WriteHeader(http.StatusInternalServerError)
48
+
return nil, fmt.Errorf("failed to resolve ID")
did := ident.DID.String()
profile, err := db.GetProfile(s.db, did)
61
-
log.Printf("getting profile data for %s: %s", did, err)
54
+
return nil, fmt.Errorf("failed to get profile: %w", err)
followStats, err := db.GetFollowerFollowingCount(s.db, did)
68
-
log.Printf("getting follow stats for %s: %s", did, err)
59
+
return nil, fmt.Errorf("failed to get follower stats: %w", err)
loggedInUser := s.oauth.GetUser(r)
···
followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, did)
77
-
return &ProfilePageParams{
79
-
LoggedInUser: loggedInUser,
80
-
Card: pages.ProfileCard{
82
-
UserHandle: ident.Handle.String(),
84
-
FollowStatus: followStatus,
85
-
FollowersCount: followStats.Followers,
86
-
FollowingCount: followStats.Following,
69
+
startOfYear := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC)
70
+
punchcard, err := db.MakePunchcard(
72
+
db.FilterEq("did", did),
73
+
db.FilterGte("date", startOfYear.Format(time.DateOnly)),
74
+
db.FilterLte("date", now.Format(time.DateOnly)),
77
+
return nil, fmt.Errorf("failed to get punchcard for %s: %w", did, err)
80
+
return &pages.ProfileCard{
82
+
UserHandle: ident.Handle.String(),
84
+
FollowStatus: followStatus,
85
+
FollowersCount: followStats.Followers,
86
+
FollowingCount: followStats.Following,
87
+
Punchcard: punchcard,
91
-
func (s *State) profileHomePage(w http.ResponseWriter, r *http.Request) {
92
-
pageWithProfile := s.profilePage(w, r)
93
-
if pageWithProfile == nil {
91
+
func (s *State) profileOverview(w http.ResponseWriter, r *http.Request) {
92
+
l := s.logger.With("handler", "profileHomePage")
94
+
profile, err := s.profile(r)
96
+
l.Error("failed to build profile card", "err", err)
100
+
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
97
-
id := pageWithProfile.Id
repos, err := db.GetRepos(
101
-
db.FilterEq("did", id.DID),
105
+
db.FilterEq("did", profile.UserDid),
104
-
log.Printf("getting repos for %s: %s", id.DID, err)
108
+
l.Error("failed to fetch repos", "err", err)
107
-
profile := pageWithProfile.Card.Profile
// filter out ones that are pinned
pinnedRepos := []db.Repo{}
for i, r := range repos {
// if this is a pinned repo, add it
112
-
if slices.Contains(profile.PinnedRepos[:], r.RepoAt()) {
115
+
if slices.Contains(profile.Profile.PinnedRepos[:], r.RepoAt()) {
pinnedRepos = append(pinnedRepos, r)
// if there are no saved pins, add the first 4 repos
117
-
if profile.IsPinnedReposEmpty() && i < 4 {
120
+
if profile.Profile.IsPinnedReposEmpty() && i < 4 {
pinnedRepos = append(pinnedRepos, r)
122
-
collaboratingRepos, err := db.CollaboratingIn(s.db, id.DID.String())
125
+
collaboratingRepos, err := db.CollaboratingIn(s.db, profile.UserDid)
124
-
log.Printf("getting collaborating repos for %s: %s", id.DID, err)
127
+
l.Error("failed to fetch collaborating repos", "err", err)
pinnedCollaboratingRepos := []db.Repo{}
for _, r := range collaboratingRepos {
// if this is a pinned repo, add it
130
-
if slices.Contains(profile.PinnedRepos[:], r.RepoAt()) {
133
+
if slices.Contains(profile.Profile.PinnedRepos[:], r.RepoAt()) {
pinnedCollaboratingRepos = append(pinnedCollaboratingRepos, r)
135
-
timeline, err := db.MakeProfileTimeline(s.db, id.DID.String())
138
+
timeline, err := db.MakeProfileTimeline(s.db, profile.UserDid)
137
-
log.Printf("failed to create profile timeline for %s: %s", id.DID, err)
140
+
l.Error("failed to create timeline", "err", err)
140
-
var didsToResolve []string
141
-
for _, r := range collaboratingRepos {
142
-
didsToResolve = append(didsToResolve, r.Did)
144
-
for _, byMonth := range timeline.ByMonth {
145
-
for _, pe := range byMonth.PullEvents.Items {
146
-
didsToResolve = append(didsToResolve, pe.Repo.Did)
148
-
for _, ie := range byMonth.IssueEvents.Items {
149
-
didsToResolve = append(didsToResolve, ie.Metadata.Repo.Did)
151
-
for _, re := range byMonth.RepoEvents {
152
-
didsToResolve = append(didsToResolve, re.Repo.Did)
153
-
if re.Source != nil {
154
-
didsToResolve = append(didsToResolve, re.Source.Did)
143
+
s.pages.ProfileOverview(w, pages.ProfileOverviewParams{
144
+
LoggedInUser: s.oauth.GetUser(r),
146
+
Repos: pinnedRepos,
147
+
CollaboratingRepos: pinnedCollaboratingRepos,
148
+
ProfileTimeline: timeline,
152
+
func (s *State) reposPage(w http.ResponseWriter, r *http.Request) {
153
+
l := s.logger.With("handler", "reposPage")
155
+
profile, err := s.profile(r)
157
+
l.Error("failed to build profile card", "err", err)
158
+
s.pages.Error500(w)
161
+
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
160
-
startOfYear := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC)
161
-
punchcard, err := db.MakePunchcard(
163
+
repos, err := db.GetRepos(
163
-
db.FilterEq("did", id.DID),
164
-
db.FilterGte("date", startOfYear.Format(time.DateOnly)),
165
-
db.FilterLte("date", now.Format(time.DateOnly)),
166
+
db.FilterEq("did", profile.UserDid),
168
-
log.Println("failed to get punchcard for did", "did", id.DID, "err", err)
169
+
l.Error("failed to get repos", "err", err)
170
+
s.pages.Error500(w)
171
-
s.pages.ProfileHomePage(w, pages.ProfileHomePageParams{
172
-
LoggedInUser: pageWithProfile.LoggedInUser,
173
-
Repos: pinnedRepos,
174
-
CollaboratingRepos: pinnedCollaboratingRepos,
175
-
Card: pageWithProfile.Card,
176
-
Punchcard: punchcard,
177
-
ProfileTimeline: timeline,
174
+
err = s.pages.ProfileRepos(w, pages.ProfileReposParams{
175
+
LoggedInUser: s.oauth.GetUser(r),
181
-
func (s *State) reposPage(w http.ResponseWriter, r *http.Request) {
182
-
pageWithProfile := s.profilePage(w, r)
183
-
if pageWithProfile == nil {
181
+
func (s *State) starredPage(w http.ResponseWriter, r *http.Request) {
182
+
l := s.logger.With("handler", "starredPage")
184
+
profile, err := s.profile(r)
186
+
l.Error("failed to build profile card", "err", err)
187
+
s.pages.Error500(w)
190
+
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
192
+
stars, err := db.GetStars(s.db, 0, db.FilterEq("starred_by_did", profile.UserDid))
194
+
l.Error("failed to get stars", "err", err)
195
+
s.pages.Error500(w)
198
+
var repoAts []string
199
+
for _, s := range stars {
200
+
repoAts = append(repoAts, string(s.RepoAt))
187
-
id := pageWithProfile.Id
repos, err := db.GetRepos(
191
-
db.FilterEq("did", id.DID),
206
+
db.FilterIn("at_uri", repoAts),
194
-
log.Printf("getting repos for %s: %s", id.DID, err)
209
+
l.Error("failed to get repos", "err", err)
210
+
s.pages.Error500(w)
197
-
s.pages.ReposPage(w, pages.ReposPageParams{
198
-
LoggedInUser: pageWithProfile.LoggedInUser,
214
+
err = s.pages.ProfileStarred(w, pages.ProfileStarredParams{
215
+
LoggedInUser: s.oauth.GetUser(r),
200
-
Card: pageWithProfile.Card,
type FollowsPageParams struct {
205
-
LoggedInUser *oauth.User
206
-
Follows []pages.FollowCard
207
-
Card pages.ProfileCard
222
+
Follows []pages.FollowCard
223
+
Card *pages.ProfileCard
210
-
func (s *State) followPage(w http.ResponseWriter, r *http.Request, fetchFollows func(db.Execer, string) ([]db.Follow, error), extractDid func(db.Follow) string) (FollowsPageParams, error) {
211
-
pageWithProfile := s.profilePage(w, r)
212
-
if pageWithProfile == nil {
213
-
return FollowsPageParams{}, nil
226
+
func (s *State) followPage(
228
+
fetchFollows func(db.Execer, string) ([]db.Follow, error),
229
+
extractDid func(db.Follow) string,
230
+
) (*FollowsPageParams, error) {
231
+
l := s.logger.With("handler", "reposPage")
233
+
profile, err := s.profile(r)
237
+
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
216
-
id := pageWithProfile.Id
217
-
loggedInUser := pageWithProfile.LoggedInUser
239
+
loggedInUser := s.oauth.GetUser(r)
219
-
follows, err := fetchFollows(s.db, id.DID.String())
241
+
follows, err := fetchFollows(s.db, profile.UserDid)
221
-
log.Printf("getting followers for %s: %s", id.DID, err)
222
-
return FollowsPageParams{}, err
243
+
l.Error("failed to fetch follows", "err", err)
226
-
return FollowsPageParams{
227
-
LoggedInUser: loggedInUser,
228
-
Follows: []pages.FollowCard{},
229
-
Card: pageWithProfile.Card,
followDids := make([]string, 0, len(follows))
···
profiles, err := db.GetProfiles(s.db, db.FilterIn("did", followDids))
240
-
log.Printf("getting profile for %s: %s", followDids, err)
241
-
return FollowsPageParams{}, err
258
+
l.Error("failed to get profiles", "followDids", followDids, "err", err)
followStatsMap, err := db.GetFollowerFollowingCounts(s.db, followDids)
···
log.Printf("getting follow counts for %s: %s", followDids, err)
249
-
var loggedInUserFollowing map[string]struct{}
267
+
loggedInUserFollowing := make(map[string]struct{})
following, err := db.GetFollowing(s.db, loggedInUser.Did)
253
-
return FollowsPageParams{}, err
271
+
l.Error("failed to get follow list", "err", err, "loggedInUser", loggedInUser.Did)
255
-
if len(following) > 0 {
256
-
loggedInUserFollowing = make(map[string]struct{}, len(following))
257
-
for _, follow := range following {
258
-
loggedInUserFollowing[follow.SubjectDid] = struct{}{}
274
+
loggedInUserFollowing = make(map[string]struct{}, len(following))
275
+
for _, follow := range following {
276
+
loggedInUserFollowing[follow.SubjectDid] = struct{}{}
263
-
followCards := make([]pages.FollowCard, 0, len(follows))
264
-
for _, did := range followDids {
265
-
followStats, exists := followStatsMap[did]
267
-
followStats = db.FollowStats{}
280
+
followCards := make([]pages.FollowCard, len(follows))
281
+
for i, did := range followDids {
282
+
followStats := followStatsMap[did]
followStatus := db.IsNotFollowing
270
-
if loggedInUserFollowing != nil {
271
-
if _, exists := loggedInUserFollowing[did]; exists {
272
-
followStatus = db.IsFollowing
273
-
} else if loggedInUser.Did == did {
274
-
followStatus = db.IsSelf
284
+
if _, exists := loggedInUserFollowing[did]; exists {
285
+
followStatus = db.IsFollowing
286
+
} else if loggedInUser.Did == did {
287
+
followStatus = db.IsSelf
if p, exists := profiles[did]; exists {
···
284
-
followCards = append(followCards, pages.FollowCard{
297
+
followCards[i] = pages.FollowCard{
FollowStatus: followStatus,
FollowersCount: followStats.Followers,
FollowingCount: followStats.Following,
293
-
return FollowsPageParams{
294
-
LoggedInUser: loggedInUser,
295
-
Follows: followCards,
296
-
Card: pageWithProfile.Card,
306
+
return &FollowsPageParams{
307
+
Follows: followCards,
func (s *State) followersPage(w http.ResponseWriter, r *http.Request) {
301
-
followPage, err := s.followPage(w, r, db.GetFollowers, func(f db.Follow) string { return f.UserDid })
313
+
followPage, err := s.followPage(r, db.GetFollowers, func(f db.Follow) string { return f.UserDid })
s.pages.Notice(w, "all-followers", "Failed to load followers")
307
-
s.pages.FollowersPage(w, pages.FollowersPageParams{
308
-
LoggedInUser: followPage.LoggedInUser,
319
+
s.pages.ProfileFollowers(w, pages.ProfileFollowersParams{
320
+
LoggedInUser: s.oauth.GetUser(r),
Followers: followPage.Follows,
func (s *State) followingPage(w http.ResponseWriter, r *http.Request) {
315
-
followPage, err := s.followPage(w, r, db.GetFollowing, func(f db.Follow) string { return f.SubjectDid })
327
+
followPage, err := s.followPage(r, db.GetFollowing, func(f db.Follow) string { return f.SubjectDid })
s.pages.Notice(w, "all-following", "Failed to load following")
321
-
s.pages.FollowingPage(w, pages.FollowingPageParams{
322
-
LoggedInUser: followPage.LoggedInUser,
333
+
s.pages.ProfileFollowing(w, pages.ProfileFollowingParams{
334
+
LoggedInUser: s.oauth.GetUser(r),
Following: followPage.Follows,