forked from tangled.org/core
this repo has no description
1package state 2 3import ( 4 "net/http" 5 "strings" 6 7 "github.com/go-chi/chi/v5" 8 "github.com/gorilla/sessions" 9 "tangled.org/core/appview/issues" 10 "tangled.org/core/appview/knots" 11 "tangled.org/core/appview/labels" 12 "tangled.org/core/appview/middleware" 13 "tangled.org/core/appview/notifications" 14 oauthhandler "tangled.org/core/appview/oauth/handler" 15 "tangled.org/core/appview/pipelines" 16 "tangled.org/core/appview/pulls" 17 "tangled.org/core/appview/repo" 18 "tangled.org/core/appview/settings" 19 "tangled.org/core/appview/signup" 20 "tangled.org/core/appview/spindles" 21 "tangled.org/core/appview/state/userutil" 22 avstrings "tangled.org/core/appview/strings" 23 "tangled.org/core/log" 24) 25 26func (s *State) Router() http.Handler { 27 router := chi.NewRouter() 28 middleware := middleware.New( 29 s.oauth, 30 s.db, 31 s.enforcer, 32 s.repoResolver, 33 s.idResolver, 34 s.pages, 35 ) 36 37 router.Use(middleware.TryRefreshSession()) 38 router.Get("/favicon.svg", s.Favicon) 39 router.Get("/favicon.ico", s.Favicon) 40 41 userRouter := s.UserRouter(&middleware) 42 standardRouter := s.StandardRouter(&middleware) 43 44 router.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) { 45 pat := chi.URLParam(r, "*") 46 if strings.HasPrefix(pat, "did:") || strings.HasPrefix(pat, "@") { 47 userRouter.ServeHTTP(w, r) 48 } else { 49 // Check if the first path element is a valid handle without '@' or a flattened DID 50 pathParts := strings.SplitN(pat, "/", 2) 51 if len(pathParts) > 0 { 52 if userutil.IsHandleNoAt(pathParts[0]) { 53 // Redirect to the same path but with '@' prefixed to the handle 54 redirectPath := "@" + pat 55 http.Redirect(w, r, "/"+redirectPath, http.StatusFound) 56 return 57 } else if userutil.IsFlattenedDid(pathParts[0]) { 58 // Redirect to the unflattened DID version 59 unflattenedDid := userutil.UnflattenDid(pathParts[0]) 60 var redirectPath string 61 if len(pathParts) > 1 { 62 redirectPath = unflattenedDid + "/" + pathParts[1] 63 } else { 64 redirectPath = unflattenedDid 65 } 66 http.Redirect(w, r, "/"+redirectPath, http.StatusFound) 67 return 68 } 69 } 70 standardRouter.ServeHTTP(w, r) 71 } 72 }) 73 74 return router 75} 76 77func (s *State) UserRouter(mw *middleware.Middleware) http.Handler { 78 r := chi.NewRouter() 79 80 r.With(mw.ResolveIdent()).Route("/{user}", func(r chi.Router) { 81 r.Get("/", s.Profile) 82 r.Get("/feed.atom", s.AtomFeedPage) 83 84 // redirect /@handle/repo.git -> /@handle/repo 85 r.Get("/{repo}.git", func(w http.ResponseWriter, r *http.Request) { 86 nonDotGitPath := strings.TrimSuffix(r.URL.Path, ".git") 87 http.Redirect(w, r, nonDotGitPath, http.StatusMovedPermanently) 88 }) 89 90 r.With(mw.ResolveRepo()).Route("/{repo}", func(r chi.Router) { 91 r.Use(mw.GoImport()) 92 r.Mount("/", s.RepoRouter(mw)) 93 r.Mount("/issues", s.IssuesRouter(mw)) 94 r.Mount("/pulls", s.PullsRouter(mw)) 95 r.Mount("/pipelines", s.PipelinesRouter(mw)) 96 r.Mount("/labels", s.LabelsRouter(mw)) 97 98 // These routes get proxied to the knot 99 r.Get("/info/refs", s.InfoRefs) 100 r.Post("/git-upload-pack", s.UploadPack) 101 r.Post("/git-receive-pack", s.ReceivePack) 102 103 }) 104 }) 105 106 r.NotFound(func(w http.ResponseWriter, r *http.Request) { 107 s.pages.Error404(w) 108 }) 109 110 return r 111} 112 113func (s *State) StandardRouter(mw *middleware.Middleware) http.Handler { 114 r := chi.NewRouter() 115 116 r.Handle("/static/*", s.pages.Static()) 117 118 r.Get("/", s.HomeOrTimeline) 119 r.Get("/timeline", s.Timeline) 120 r.Get("/upgradeBanner", s.UpgradeBanner) 121 122 // special-case handler for serving tangled.org/core 123 r.Get("/core", s.Core()) 124 125 r.Route("/repo", func(r chi.Router) { 126 r.Route("/new", func(r chi.Router) { 127 r.Use(middleware.AuthMiddleware(s.oauth)) 128 r.Get("/", s.NewRepo) 129 r.Post("/", s.NewRepo) 130 }) 131 // r.Post("/import", s.ImportRepo) 132 }) 133 134 r.With(middleware.AuthMiddleware(s.oauth)).Route("/follow", func(r chi.Router) { 135 r.Post("/", s.Follow) 136 r.Delete("/", s.Follow) 137 }) 138 139 r.With(middleware.AuthMiddleware(s.oauth)).Route("/star", func(r chi.Router) { 140 r.Post("/", s.Star) 141 r.Delete("/", s.Star) 142 }) 143 144 r.With(middleware.AuthMiddleware(s.oauth)).Route("/react", func(r chi.Router) { 145 r.Post("/", s.React) 146 r.Delete("/", s.React) 147 }) 148 149 r.Route("/profile", func(r chi.Router) { 150 r.Use(middleware.AuthMiddleware(s.oauth)) 151 r.Get("/edit-bio", s.EditBioFragment) 152 r.Get("/edit-pins", s.EditPinsFragment) 153 r.Post("/bio", s.UpdateProfileBio) 154 r.Post("/pins", s.UpdateProfilePins) 155 }) 156 157 r.Mount("/settings", s.SettingsRouter()) 158 r.Mount("/strings", s.StringsRouter(mw)) 159 r.Mount("/knots", s.KnotsRouter()) 160 r.Mount("/spindles", s.SpindlesRouter()) 161 r.Mount("/notifications", s.NotificationsRouter(mw)) 162 163 r.Mount("/signup", s.SignupRouter()) 164 r.Mount("/", s.OAuthRouter()) 165 166 r.Get("/keys/{user}", s.Keys) 167 r.Get("/terms", s.TermsOfService) 168 r.Get("/privacy", s.PrivacyPolicy) 169 r.Get("/brand", s.Brand) 170 171 r.NotFound(func(w http.ResponseWriter, r *http.Request) { 172 s.pages.Error404(w) 173 }) 174 return r 175} 176 177// Core serves tangled.org/core go-import meta tags, and redirects 178// to the core repository if accessed normally. 179func (s *State) Core() http.HandlerFunc { 180 return func(w http.ResponseWriter, r *http.Request) { 181 if r.URL.Query().Get("go-get") == "1" { 182 w.Header().Set("Content-Type", "text/html") 183 w.Write([]byte(`<meta name="go-import" content="tangled.org/core git https://tangled.org/@tangled.org/core">`)) 184 return 185 } 186 187 http.Redirect(w, r, "/@tangled.org/core", http.StatusFound) 188 } 189} 190 191func (s *State) OAuthRouter() http.Handler { 192 store := sessions.NewCookieStore([]byte(s.config.Core.CookieSecret)) 193 oauth := oauthhandler.New(s.config, s.pages, s.idResolver, s.db, s.sess, store, s.oauth, s.enforcer, s.posthog) 194 return oauth.Router() 195} 196 197func (s *State) SettingsRouter() http.Handler { 198 settings := &settings.Settings{ 199 Db: s.db, 200 OAuth: s.oauth, 201 Pages: s.pages, 202 Config: s.config, 203 } 204 205 return settings.Router() 206} 207 208func (s *State) SpindlesRouter() http.Handler { 209 logger := log.New("spindles") 210 211 spindles := &spindles.Spindles{ 212 Db: s.db, 213 OAuth: s.oauth, 214 Pages: s.pages, 215 Config: s.config, 216 Enforcer: s.enforcer, 217 IdResolver: s.idResolver, 218 Logger: logger, 219 } 220 221 return spindles.Router() 222} 223 224func (s *State) KnotsRouter() http.Handler { 225 logger := log.New("knots") 226 227 knots := &knots.Knots{ 228 Db: s.db, 229 OAuth: s.oauth, 230 Pages: s.pages, 231 Config: s.config, 232 Enforcer: s.enforcer, 233 IdResolver: s.idResolver, 234 Knotstream: s.knotstream, 235 Logger: logger, 236 } 237 238 return knots.Router() 239} 240 241func (s *State) StringsRouter(mw *middleware.Middleware) http.Handler { 242 logger := log.New("strings") 243 244 strs := &avstrings.Strings{ 245 Db: s.db, 246 OAuth: s.oauth, 247 Pages: s.pages, 248 IdResolver: s.idResolver, 249 Notifier: s.notifier, 250 Logger: logger, 251 } 252 253 return strs.Router(mw) 254} 255 256func (s *State) IssuesRouter(mw *middleware.Middleware) http.Handler { 257 issues := issues.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.notifier, s.validator) 258 return issues.Router(mw) 259} 260 261func (s *State) PullsRouter(mw *middleware.Middleware) http.Handler { 262 pulls := pulls.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.notifier) 263 return pulls.Router(mw) 264} 265 266func (s *State) RepoRouter(mw *middleware.Middleware) http.Handler { 267 logger := log.New("repo") 268 repo := repo.New(s.oauth, s.repoResolver, s.pages, s.spindlestream, s.idResolver, s.db, s.config, s.notifier, s.enforcer, logger, s.validator) 269 return repo.Router(mw) 270} 271 272func (s *State) PipelinesRouter(mw *middleware.Middleware) http.Handler { 273 pipes := pipelines.New(s.oauth, s.repoResolver, s.pages, s.spindlestream, s.idResolver, s.db, s.config, s.enforcer) 274 return pipes.Router(mw) 275} 276 277func (s *State) LabelsRouter(mw *middleware.Middleware) http.Handler { 278 ls := labels.New(s.oauth, s.pages, s.db, s.validator, s.enforcer) 279 return ls.Router(mw) 280} 281 282func (s *State) NotificationsRouter(mw *middleware.Middleware) http.Handler { 283 notifs := notifications.New(s.db, s.oauth, s.pages) 284 return notifs.Router(mw) 285} 286 287func (s *State) SignupRouter() http.Handler { 288 logger := log.New("signup") 289 290 sig := signup.New(s.config, s.db, s.posthog, s.idResolver, s.pages, logger) 291 return sig.Router() 292}