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