This repository has no description
1package state
2
3import (
4 "net/http"
5
6 "github.com/bluesky-social/indigo/atproto/syntax"
7 "tangled.org/core/appview/db"
8 "tangled.org/core/appview/models"
9 "tangled.org/core/appview/oauth"
10 "tangled.org/core/appview/pages"
11 "tangled.org/core/appview/pagination"
12 "tangled.org/core/orm"
13)
14
15func (s *State) Home(w http.ResponseWriter, r *http.Request) {
16 // TODO: set this flag based on the UI
17 filtered := false
18
19 user := s.oauth.GetMultiAccountUser(r)
20
21 timeline, err := db.MakeTimeline(s.db, 50, "", filtered)
22 if err != nil {
23 s.logger.Error("failed to make timeline", "err", err)
24 s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.")
25 return
26 }
27
28 blueskyPosts, err := db.GetBlueskyPosts(s.db, 8)
29 if err != nil {
30 s.logger.Error("failed to get bluesky posts", "err", err)
31 }
32
33 s.pages.Home(w, pages.TimelineParams{
34 LoggedInUser: user,
35 Timeline: timeline,
36 BlueskyPosts: blueskyPosts,
37 ShowNewsletter: s.showNewsletter(user),
38 })
39}
40func (s *State) HomeOrTimeline(w http.ResponseWriter, r *http.Request) {
41 if s.oauth.GetMultiAccountUser(r) != nil {
42 s.Timeline(w, r)
43 return
44 }
45 s.Home(w, r)
46}
47
48func (s *State) Timeline(w http.ResponseWriter, r *http.Request) {
49 user := s.oauth.GetMultiAccountUser(r)
50
51 // TODO: set this flag based on the UI
52 filtered := false
53
54 var userDid string
55 if user != nil {
56 userDid = user.Did
57 }
58 timeline, err := db.MakeTimeline(s.db, 50, userDid, filtered)
59 if err != nil {
60 s.logger.Error("failed to make timeline", "err", err)
61 s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.")
62 }
63
64 repos, err := db.GetTopStarredReposLastWeek(s.db)
65 if err != nil {
66 s.logger.Error("failed to get top starred repos", "err", err)
67 s.pages.Notice(w, "topstarredrepos", "Unable to load.")
68 return
69 }
70
71 gfiLabel, err := db.GetLabelDefinition(s.db, orm.FilterEq("at_uri", s.config.Label.GoodFirstIssue))
72 if err != nil {
73 // non-fatal
74 }
75
76 var notifications []*models.NotificationWithEntity
77 if user != nil {
78 notifications, err = db.GetNotificationsWithEntities(
79 s.db,
80 pagination.Page{Limit: 5, Offset: 0},
81 orm.FilterEq("recipient_did", user.Did),
82 orm.FilterEq("read", 0),
83 )
84 if err != nil {
85 s.logger.Error("failed to get notifications for timeline", "err", err)
86 }
87 }
88
89 var vouchSuggestions []models.VouchSuggestion
90 if user != nil {
91 vouchSuggestions, err = db.GetVouchSuggestions(s.db, user.Did, 3)
92 if err != nil {
93 s.logger.Error("failed to get vouch suggestions", "err", err)
94 }
95 if len(vouchSuggestions) > 0 {
96 suggestionDids := make([]syntax.DID, len(vouchSuggestions))
97 for i, sv := range vouchSuggestions {
98 suggestionDids[i] = syntax.DID(sv.Did)
99 }
100 relationships, err := db.GetVouchRelationshipsBatch(s.db, syntax.DID(user.Did), suggestionDids)
101 if err != nil {
102 s.logger.Error("failed to get vouch relationships for suggestions", "err", err)
103 } else {
104 for i := range vouchSuggestions {
105 vouchSuggestions[i].VouchRelationship = relationships[vouchSuggestions[i].Did]
106 }
107 }
108 }
109 }
110
111 s.pages.Timeline(w, pages.TimelineParams{
112 LoggedInUser: user,
113 Timeline: timeline,
114 Repos: repos,
115 GfiLabel: gfiLabel,
116 VouchSuggestions: vouchSuggestions,
117 Notifications: notifications,
118 ShowNewsletter: s.showNewsletter(user),
119 })
120}
121
122// showNewsletter decides whether the newsletter widget/CTA should render.
123// Anonymous visitors always see it (they can dismiss via localStorage);
124// logged-in users whose newsletter_preferences row exists (either
125// subscribed or dismissed) do not.
126func (s *State) showNewsletter(user *oauth.MultiAccountUser) bool {
127 if user == nil {
128 return true
129 }
130 pref, err := db.GetNewsletterPref(s.db, user.Did)
131 if err != nil {
132 s.logger.Error("failed to read newsletter preference", "did", user.Did, "err", err)
133 return true
134 }
135 return pref == nil
136}