this repo has no description
1package web 2 3import ( 4 "log/slog" 5 "net/http" 6 7 "github.com/go-chi/chi/v5" 8 "tangled.org/core/appview/config" 9 "tangled.org/core/appview/db" 10 "tangled.org/core/appview/indexer" 11 "tangled.org/core/appview/mentions" 12 "tangled.org/core/appview/notify" 13 "tangled.org/core/appview/oauth" 14 "tangled.org/core/appview/pages" 15 isvc "tangled.org/core/appview/service/issue" 16 rsvc "tangled.org/core/appview/service/repo" 17 "tangled.org/core/appview/state" 18 "tangled.org/core/appview/validator" 19 "tangled.org/core/appview/web/handler" 20 "tangled.org/core/appview/web/middleware" 21 "tangled.org/core/idresolver" 22 "tangled.org/core/rbac" 23) 24 25// RouterFromState creates a web router from `state.State`. This exist to 26// bridge between legacy web routers under `State` and new architecture 27func RouterFromState(s *state.State) http.Handler { 28 config, db, enforcer, idResolver, refResolver, indexer, logger, notifier, oauth, pages, validator := s.Expose() 29 30 return Router( 31 logger, 32 config, 33 db, 34 enforcer, 35 idResolver, 36 refResolver, 37 indexer, 38 notifier, 39 oauth, 40 pages, 41 validator, 42 s, 43 ) 44} 45 46func Router( 47 // NOTE: put base dependencies (db, idResolver, oauth etc) 48 logger *slog.Logger, 49 config *config.Config, 50 db *db.DB, 51 enforcer *rbac.Enforcer, 52 idResolver *idresolver.Resolver, 53 mentionsResolver *mentions.Resolver, 54 indexer *indexer.Indexer, 55 notifier notify.Notifier, 56 oauth *oauth.OAuth, 57 pages *pages.Pages, 58 validator *validator.Validator, 59 // to use legacy web handlers. will be removed later 60 s *state.State, 61) http.Handler { 62 repo := rsvc.NewService( 63 logger, 64 config, 65 db, 66 enforcer, 67 ) 68 issue := isvc.NewService( 69 logger, 70 config, 71 db, 72 enforcer, 73 notifier, 74 idResolver, 75 mentionsResolver, 76 indexer.Issues, 77 validator, 78 ) 79 80 i := s.ExposeIssue() 81 82 r := chi.NewRouter() 83 84 mw := s.Middleware() 85 auth := middleware.AuthMiddleware() 86 87 r.Use(middleware.WithLogger(logger)) 88 r.Use(middleware.WithSession(oauth)) 89 90 r.Use(middleware.Normalize()) 91 92 r.Get("/pwa-manifest.json", s.WebAppManifest) 93 r.Get("/robots.txt", s.RobotsTxt) 94 95 r.Handle("/static/*", pages.Static()) 96 97 r.Get("/", s.HomeOrTimeline) 98 r.Get("/timeline", s.Timeline) 99 r.Get("/upgradeBanner", s.UpgradeBanner) 100 101 r.Get("/terms", s.TermsOfService) 102 r.Get("/privacy", s.PrivacyPolicy) 103 r.Get("/brand", s.Brand) 104 // special-case handler for serving tangled.org/core 105 r.Get("/core", s.Core()) 106 107 r.Get("/login", s.Login) 108 r.Post("/login", s.Login) 109 r.Post("/logout", s.Logout) 110 111 r.Get("/goodfirstissues", s.GoodFirstIssues) 112 113 r.With(auth).Get("/repo/new", s.NewRepo) 114 r.With(auth).Post("/repo/new", s.NewRepo) 115 116 r.With(auth).Post("/follow", s.Follow) 117 r.With(auth).Delete("/follow", s.Follow) 118 119 r.With(auth).Post("/star", s.Star) 120 r.With(auth).Delete("/star", s.Star) 121 122 r.With(auth).Post("/react", s.React) 123 r.With(auth).Delete("/react", s.React) 124 125 r.With(auth).Get("/profile/edit-bio", s.EditBioFragment) 126 r.With(auth).Get("/profile/edit-pins", s.EditPinsFragment) 127 r.With(auth).Post("/profile/bio", s.UpdateProfileBio) 128 r.With(auth).Post("/profile/pins", s.UpdateProfilePins) 129 130 r.Mount("/settings", s.SettingsRouter()) 131 r.Mount("/strings", s.StringsRouter(mw)) 132 r.Mount("/settings/knots", s.KnotsRouter()) 133 r.Mount("/settings/spindles", s.SpindlesRouter()) 134 r.Mount("/notifications", s.NotificationsRouter(mw)) 135 136 r.Mount("/signup", s.SignupRouter()) 137 r.Get("/oauth/client-metadata.json", handler.OauthClientMetadata(oauth)) 138 r.Get("/oauth/jwks.json", handler.OauthJwks(oauth)) 139 r.Get("/oauth/callback", oauth.Callback) 140 141 // special-case handler. should replace with xrpc later 142 r.Get("/keys/{user}", s.Keys) 143 144 r.HandleFunc("/@*", func(w http.ResponseWriter, r *http.Request) { 145 http.Redirect(w, r, "/"+chi.URLParam(r, "*"), http.StatusFound) 146 }) 147 148 r.Route("/{user}", func(r chi.Router) { 149 r.Use(middleware.EnsureDidOrHandle(pages)) 150 r.Use(middleware.ResolveIdent(idResolver, pages)) 151 152 r.Get("/", s.Profile) 153 r.Get("/feed.atom", s.AtomFeedPage) 154 155 r.Route("/{repo}", func(r chi.Router) { 156 r.Use(middleware.ResolveRepo(db, pages)) 157 158 r.Mount("/", s.RepoRouter(mw)) 159 160 // /{user}/{repo}/issues/* 161 r.With(middleware.Paginate).Get("/issues", handler.RepoIssues(issue, repo, pages, db)) 162 r.With(auth).Get("/issues/new", handler.NewIssue(repo, pages)) 163 r.With(auth).Post("/issues/new", handler.NewIssuePost(issue, pages)) 164 r.Route("/issues/{issue}", func(r chi.Router) { 165 r.Use(middleware.ResolveIssue(db, pages)) 166 167 r.Get("/", handler.Issue(issue, repo, pages, db)) 168 r.Get("/opengraph", i.IssueOpenGraphSummary) 169 170 r.With(auth).Delete("/", handler.IssueDelete(issue, pages)) 171 172 r.With(auth).Get("/edit", handler.IssueEdit(issue, repo, pages)) 173 r.With(auth).Post("/edit", handler.IssueEditPost(issue, pages)) 174 175 r.With(auth).Post("/close", handler.CloseIssue(issue, pages)) 176 r.With(auth).Post("/reopen", handler.ReopenIssue(issue, pages)) 177 178 r.With(auth).Post("/comment", i.NewIssueComment) 179 r.With(auth).Route("/comment/{commentId}/", func(r chi.Router) { 180 r.Get("/", i.IssueComment) 181 r.Delete("/", i.DeleteIssueComment) 182 r.Get("/edit", i.EditIssueComment) 183 r.Post("/edit", i.EditIssueComment) 184 r.Get("/reply", i.ReplyIssueComment) 185 r.Get("/replyPlaceholder", i.ReplyIssueCommentPlaceholder) 186 }) 187 }) 188 189 r.Mount("/pulls", s.PullsRouter(mw)) 190 r.Mount("/pipelines", s.PipelinesRouter()) 191 r.Mount("/labels", s.LabelsRouter()) 192 193 // These routes get proxied to the knot 194 r.Get("/info/refs", s.InfoRefs) 195 r.Post("/git-upload-pack", s.UploadPack) 196 r.Post("/git-receive-pack", s.ReceivePack) 197 }) 198 }) 199 200 r.NotFound(func(w http.ResponseWriter, r *http.Request) { 201 pages.Error404(w) 202 }) 203 204 return r 205}