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