forked from
tangled.org/core
fork
Configure Feed
Select the types of activity you want to include in your feed.
this repo has no description
fork
Configure Feed
Select the types of activity you want to include in your feed.
1package state
2
3import (
4 "net/http"
5 "strings"
6
7 "github.com/go-chi/chi/v5"
8 "tangled.sh/tangled.sh/core/appview/middleware"
9 "tangled.sh/tangled.sh/core/appview/settings"
10 "tangled.sh/tangled.sh/core/appview/state/userutil"
11)
12
13func (s *State) Router() http.Handler {
14 router := chi.NewRouter()
15
16 router.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) {
17 pat := chi.URLParam(r, "*")
18 if strings.HasPrefix(pat, "did:") || strings.HasPrefix(pat, "@") {
19 s.UserRouter().ServeHTTP(w, r)
20 } else {
21 // Check if the first path element is a valid handle without '@' or a flattened DID
22 pathParts := strings.SplitN(pat, "/", 2)
23 if len(pathParts) > 0 {
24 if userutil.IsHandleNoAt(pathParts[0]) {
25 // Redirect to the same path but with '@' prefixed to the handle
26 redirectPath := "@" + pat
27 http.Redirect(w, r, "/"+redirectPath, http.StatusFound)
28 return
29 } else if userutil.IsFlattenedDid(pathParts[0]) {
30 // Redirect to the unflattened DID version
31 unflattenedDid := userutil.UnflattenDid(pathParts[0])
32 var redirectPath string
33 if len(pathParts) > 1 {
34 redirectPath = unflattenedDid + "/" + pathParts[1]
35 } else {
36 redirectPath = unflattenedDid
37 }
38 http.Redirect(w, r, "/"+redirectPath, http.StatusFound)
39 return
40 }
41 }
42 s.StandardRouter().ServeHTTP(w, r)
43 }
44 })
45
46 return router
47}
48
49func (s *State) UserRouter() http.Handler {
50 r := chi.NewRouter()
51
52 // strip @ from user
53 r.Use(StripLeadingAt)
54
55 r.With(ResolveIdent(s)).Route("/{user}", func(r chi.Router) {
56 r.Get("/", s.ProfilePage)
57 r.With(ResolveRepo(s)).Route("/{repo}", func(r chi.Router) {
58 r.Get("/", s.RepoIndex)
59 r.Get("/commits/{ref}", s.RepoLog)
60 r.Route("/tree/{ref}", func(r chi.Router) {
61 r.Get("/", s.RepoIndex)
62 r.Get("/*", s.RepoTree)
63 })
64 r.Get("/commit/{ref}", s.RepoCommit)
65 r.Get("/branches", s.RepoBranches)
66 r.Get("/tags", s.RepoTags)
67 r.Get("/blob/{ref}/*", s.RepoBlob)
68 r.Get("/blob/{ref}/raw/*", s.RepoBlobRaw)
69
70 r.Route("/issues", func(r chi.Router) {
71 r.Get("/", s.RepoIssues)
72 r.Get("/{issue}", s.RepoSingleIssue)
73
74 r.Group(func(r chi.Router) {
75 r.Use(middleware.AuthMiddleware(s.auth))
76 r.Get("/new", s.NewIssue)
77 r.Post("/new", s.NewIssue)
78 r.Post("/{issue}/comment", s.NewIssueComment)
79 r.Route("/{issue}/comment/{comment_id}/", func(r chi.Router) {
80 r.Get("/", s.IssueComment)
81 r.Delete("/", s.DeleteIssueComment)
82 r.Get("/edit", s.EditIssueComment)
83 r.Post("/edit", s.EditIssueComment)
84 })
85 r.Post("/{issue}/close", s.CloseIssue)
86 r.Post("/{issue}/reopen", s.ReopenIssue)
87 })
88 })
89
90 r.Route("/fork", func(r chi.Router) {
91 r.Use(middleware.AuthMiddleware(s.auth))
92 r.Get("/", s.ForkRepo)
93 r.Post("/", s.ForkRepo)
94 })
95
96 r.Route("/pulls", func(r chi.Router) {
97 r.Get("/", s.RepoPulls)
98 r.With(middleware.AuthMiddleware(s.auth)).Route("/new", func(r chi.Router) {
99 r.Get("/", s.NewPull)
100 r.Get("/patch-upload", s.PatchUploadFragment)
101 r.Post("/validate-patch", s.ValidatePatch)
102 r.Get("/compare-branches", s.CompareBranchesFragment)
103 r.Get("/compare-forks", s.CompareForksFragment)
104 r.Get("/fork-branches", s.CompareForksBranchesFragment)
105 r.Post("/", s.NewPull)
106 })
107
108 r.Route("/{pull}", func(r chi.Router) {
109 r.Use(ResolvePull(s))
110 r.Get("/", s.RepoSinglePull)
111
112 r.Route("/round/{round}", func(r chi.Router) {
113 r.Get("/", s.RepoPullPatch)
114 r.Get("/interdiff", s.RepoPullInterdiff)
115 r.Get("/actions", s.PullActions)
116 r.With(middleware.AuthMiddleware(s.auth)).Route("/comment", func(r chi.Router) {
117 r.Get("/", s.PullComment)
118 r.Post("/", s.PullComment)
119 })
120 })
121
122 r.Route("/round/{round}.patch", func(r chi.Router) {
123 r.Get("/", s.RepoPullPatchRaw)
124 })
125
126 r.Group(func(r chi.Router) {
127 r.Use(middleware.AuthMiddleware(s.auth))
128 r.Route("/resubmit", func(r chi.Router) {
129 r.Get("/", s.ResubmitPull)
130 r.Post("/", s.ResubmitPull)
131 })
132 r.Post("/close", s.ClosePull)
133 r.Post("/reopen", s.ReopenPull)
134 // collaborators only
135 r.Group(func(r chi.Router) {
136 r.Use(RepoPermissionMiddleware(s, "repo:push"))
137 r.Post("/merge", s.MergePull)
138 // maybe lock, etc.
139 })
140 })
141 })
142 })
143
144 // These routes get proxied to the knot
145 r.Get("/info/refs", s.InfoRefs)
146 r.Post("/git-upload-pack", s.UploadPack)
147
148 // settings routes, needs auth
149 r.Group(func(r chi.Router) {
150 r.Use(middleware.AuthMiddleware(s.auth))
151 // repo description can only be edited by owner
152 r.With(RepoPermissionMiddleware(s, "repo:owner")).Route("/description", func(r chi.Router) {
153 r.Put("/", s.RepoDescription)
154 r.Get("/", s.RepoDescription)
155 r.Get("/edit", s.RepoDescriptionEdit)
156 })
157 r.With(RepoPermissionMiddleware(s, "repo:settings")).Route("/settings", func(r chi.Router) {
158 r.Get("/", s.RepoSettings)
159 r.With(RepoPermissionMiddleware(s, "repo:invite")).Put("/collaborator", s.AddCollaborator)
160 r.With(RepoPermissionMiddleware(s, "repo:delete")).Delete("/delete", s.DeleteRepo)
161 r.Put("/branches/default", s.SetDefaultBranch)
162 })
163 })
164 })
165 })
166
167 r.NotFound(func(w http.ResponseWriter, r *http.Request) {
168 s.pages.Error404(w)
169 })
170
171 return r
172}
173
174func (s *State) StandardRouter() http.Handler {
175 r := chi.NewRouter()
176
177 r.Handle("/static/*", s.pages.Static())
178
179 r.Get("/", s.Timeline)
180
181 r.With(middleware.AuthMiddleware(s.auth)).Post("/logout", s.Logout)
182
183 r.Route("/login", func(r chi.Router) {
184 r.Get("/", s.Login)
185 r.Post("/", s.Login)
186 })
187
188 r.Route("/knots", func(r chi.Router) {
189 r.Use(middleware.AuthMiddleware(s.auth))
190 r.Get("/", s.Knots)
191 r.Post("/key", s.RegistrationKey)
192
193 r.Route("/{domain}", func(r chi.Router) {
194 r.Post("/init", s.InitKnotServer)
195 r.Get("/", s.KnotServerInfo)
196 r.Route("/member", func(r chi.Router) {
197 r.Use(KnotOwner(s))
198 r.Get("/", s.ListMembers)
199 r.Put("/", s.AddMember)
200 r.Delete("/", s.RemoveMember)
201 })
202 })
203 })
204
205 r.Route("/repo", func(r chi.Router) {
206 r.Route("/new", func(r chi.Router) {
207 r.Use(middleware.AuthMiddleware(s.auth))
208 r.Get("/", s.NewRepo)
209 r.Post("/", s.NewRepo)
210 })
211 // r.Post("/import", s.ImportRepo)
212 })
213
214 r.With(middleware.AuthMiddleware(s.auth)).Route("/follow", func(r chi.Router) {
215 r.Post("/", s.Follow)
216 r.Delete("/", s.Follow)
217 })
218
219 r.With(middleware.AuthMiddleware(s.auth)).Route("/star", func(r chi.Router) {
220 r.Post("/", s.Star)
221 r.Delete("/", s.Star)
222 })
223
224 r.Mount("/settings", s.SettingsRouter())
225
226 r.Get("/keys/{user}", s.Keys)
227
228 r.NotFound(func(w http.ResponseWriter, r *http.Request) {
229 s.pages.Error404(w)
230 })
231 return r
232}
233
234func (s *State) SettingsRouter() http.Handler {
235 settings := &settings.Settings{
236 Db: s.db,
237 Auth: s.auth,
238 Pages: s.pages,
239 Config: s.config,
240 }
241
242 return settings.Router()
243}