This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / appview / state / onboarding.go
6.3 kB 230 lines
1package state 2 3import ( 4 "net/http" 5 "strconv" 6 7 "tangled.org/core/appview/db" 8 "tangled.org/core/appview/models" 9 "tangled.org/core/appview/pages" 10) 11 12func onboardingStepURL(step int) string { 13 switch step { 14 case models.OnboardingStepProfile: 15 return "/welcome/profile" 16 case models.OnboardingStepKeys: 17 return "/welcome/keys" 18 case models.OnboardingStepSocial: 19 return "/welcome/social" 20 case models.OnboardingStepRepo: 21 return "/welcome/repo" 22 default: 23 return "/" 24 } 25} 26 27func (s *State) OnboardingResume(w http.ResponseWriter, r *http.Request) { 28 did := s.oauth.GetDid(r) 29 ob, err := db.GetOnboarding(s.db, did) 30 if err != nil { 31 s.logger.Error("failed to get onboarding", "did", did, "err", err) 32 } 33 if ob == nil || ob.Status != models.OnboardingInProgress { 34 http.Redirect(w, r, "/", http.StatusFound) 35 return 36 } 37 http.Redirect(w, r, onboardingStepURL(ob.Step), http.StatusFound) 38} 39 40func (s *State) OnboardingNext(w http.ResponseWriter, r *http.Request) { 41 did := s.oauth.GetDid(r) 42 step, _ := strconv.Atoi(r.FormValue("step")) 43 44 if step >= models.OnboardingStepDone { 45 if err := db.CompleteOnboarding(s.db, did); err != nil { 46 s.logger.Error("failed to complete onboarding", "did", did, "err", err) 47 } 48 s.pages.HxRedirect(w, "/") 49 return 50 } 51 52 if step == models.OnboardingStepRepo { 53 if err := db.CompleteOnboarding(s.db, did); err != nil { 54 s.logger.Error("failed to complete onboarding", "did", did, "err", err) 55 } 56 s.pages.HxRedirect(w, onboardingStepURL(step)) 57 return 58 } 59 60 if err := db.AdvanceOnboardingStep(s.db, did, step); err != nil { 61 s.logger.Error("failed to advance onboarding", "did", did, "err", err) 62 } 63 s.pages.HxRedirect(w, onboardingStepURL(step)) 64} 65 66func (s *State) OnboardingSkip(w http.ResponseWriter, r *http.Request) { 67 did := s.oauth.GetDid(r) 68 if err := db.SkipOnboarding(s.db, did); err != nil { 69 s.logger.Error("failed to skip onboarding", "did", did, "err", err) 70 } 71 s.pages.HxRedirect(w, "/") 72} 73 74func (s *State) OnboardingComplete(w http.ResponseWriter, r *http.Request) { 75 did := s.oauth.GetDid(r) 76 if err := db.CompleteOnboarding(s.db, did); err != nil { 77 s.logger.Error("failed to complete onboarding", "did", did, "err", err) 78 } 79 s.pages.HxRedirect(w, "/") 80} 81 82func (s *State) OnboardingProfile(w http.ResponseWriter, r *http.Request) { 83 user := s.oauth.GetMultiAccountUser(r) 84 85 profile, err := db.GetProfile(s.db, user.Did) 86 if err != nil { 87 s.logger.Error("getting profile data", "did", user.Did, "err", err) 88 } 89 if profile == nil { 90 profile = &models.Profile{Did: user.Did} 91 } 92 93 var alsoKnownAs []string 94 if ident, err := s.idResolver.ResolveIdent(r.Context(), user.Did); err == nil { 95 alsoKnownAs = ident.AlsoKnownAs 96 } 97 98 bp := pages.BaseParamsFromContext(r.Context()) 99 s.pages.Onboarding(w, pages.OnboardingParams{ 100 BaseParams: bp, 101 Step: models.OnboardingStepProfile, 102 EditBio: pages.EditBioParams{ 103 BaseParams: bp, 104 Profile: profile, 105 AlsoKnownAs: alsoKnownAs, 106 Action: "/welcome/profile", 107 }, 108 }) 109} 110 111func (s *State) OnboardingSaveProfile(w http.ResponseWriter, r *http.Request) { 112 did := s.oauth.GetDid(r) 113 114 if err := r.ParseForm(); err != nil { 115 s.pages.Notice(w, "update-profile", "Invalid form.") 116 return 117 } 118 119 profile, err := s.bioFormToProfile(r) 120 if err != nil { 121 s.pages.Notice(w, "update-profile", err.Error()) 122 return 123 } 124 125 if err := s.writeProfile(r, profile); err != nil { 126 s.logger.Error("onboarding: failed to write profile", "did", did, "err", err) 127 s.pages.Notice(w, "update-profile", "Failed to update profile, try again later.") 128 return 129 } 130 131 if err := db.AdvanceOnboardingStep(s.db, did, models.OnboardingStepSocial); err != nil { 132 s.logger.Error("failed to advance onboarding", "did", did, "err", err) 133 } 134 s.pages.HxRedirect(w, "/welcome/social") 135} 136 137func (s *State) OnboardingKeys(w http.ResponseWriter, r *http.Request) { 138 user := s.oauth.GetMultiAccountUser(r) 139 140 pubKeys, err := db.GetPublicKeysForDid(s.db, user.Did) 141 if err != nil { 142 s.logger.Error("getting public keys", "did", user.Did, "err", err) 143 } 144 145 s.pages.Onboarding(w, pages.OnboardingParams{ 146 BaseParams: pages.BaseParamsFromContext(r.Context()), 147 Step: models.OnboardingStepKeys, 148 PubKeys: pubKeys, 149 }) 150} 151 152const onboardingSocialLimit = 4 153 154func (s *State) OnboardingSocial(w http.ResponseWriter, r *http.Request) { 155 user := s.oauth.GetMultiAccountUser(r) 156 bp := pages.BaseParamsFromContext(r.Context()) 157 158 var people []pages.FollowCard 159 mostFollowed, err := db.GetMostFollowed(s.db, onboardingSocialLimit+2) 160 if err != nil { 161 s.logger.Error("failed to get most followed", "err", err) 162 } 163 var dids []string 164 for _, did := range mostFollowed { 165 if did == user.Did { 166 continue 167 } 168 dids = append(dids, did) 169 if len(dids) >= onboardingSocialLimit { 170 break 171 } 172 } 173 if len(dids) > 0 { 174 statuses, _ := db.GetFollowStatuses(s.db, user.Did, dids) 175 counts, _ := db.GetFollowerFollowingCounts(s.db, dids) 176 for _, did := range dids { 177 profile, _ := db.GetProfile(s.db, did) 178 if profile == nil { 179 profile = &models.Profile{Did: did} 180 } 181 people = append(people, pages.FollowCard{ 182 BaseParams: bp, 183 UserDid: did, 184 Profile: profile, 185 FollowStatus: statuses[did], 186 FollowersCount: counts[did].Followers, 187 FollowingCount: counts[did].Following, 188 }) 189 } 190 } 191 192 repos, err := db.GetTopStarredReposLastWeek(s.db) 193 if err != nil { 194 s.logger.Error("failed to get trending repos", "err", err) 195 } 196 trending := make([]models.Repo, 0, onboardingSocialLimit) 197 for _, repo := range repos { 198 if repo.RepoDid == "" { 199 continue 200 } 201 trending = append(trending, repo) 202 if len(trending) >= onboardingSocialLimit { 203 break 204 } 205 } 206 207 starStatuses := map[string]bool{} 208 if len(trending) > 0 { 209 repoDids := make([]string, 0, len(trending)) 210 for _, repo := range trending { 211 repoDids = append(repoDids, repo.RepoDid) 212 } 213 starStatuses, _ = db.GetStarStatuses(s.db, user.Did, repoDids) 214 } 215 216 s.pages.Onboarding(w, pages.OnboardingParams{ 217 BaseParams: bp, 218 Step: models.OnboardingStepSocial, 219 People: people, 220 TrendingRepos: trending, 221 StarStatuses: starStatuses, 222 }) 223} 224 225func (s *State) OnboardingRepo(w http.ResponseWriter, r *http.Request) { 226 s.pages.Onboarding(w, pages.OnboardingParams{ 227 BaseParams: pages.BaseParamsFromContext(r.Context()), 228 Step: models.OnboardingStepRepo, 229 }) 230}