Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Add one Admin page with status, accounts, and the audit log

43e681d8a5d94567aa9530d32b2c89223c1a17f9 · Keenan Nemetz · 5d ago · parent af018ce8

Add one Admin page with status, accounts, and the audit log

Instance administration was split between the Status and Accounts pages,
and the audit log had no browser view at all. The new /admin page gathers
the status tabs, the account roster, and a read-only audit viewer into one
place with a tab for each, and /status, /runners, and /users redirect to
the tab they named so old links keep working.

The audit reader walks the file backwards a chunk at a time, returns the
newest records first, and shows one extra record to know whether an older
page exists. It skips a line it cannot parse rather than failing the page
and refuses a symlink or a non-regular file, as startup already does.

Refs #198 (01M6MK0NNZ2XR1D5TQKNWYT4HN).

server/routes.go +10−5

@@ -38,8 +38,8 @@ func (s *Server) assetRoutes(mux *http.ServeMux) {
38 38 }
39 39
40 40 // globalRoutes are the destinations that are not scoped to a repository:
41 // the repository list, the instance feed, the admin status page, and the probes
42 // a reverse proxy or a monitor calls.
41 // the repository list, the instance feed, the redirects to the Admin page, and the
42 // probes a reverse proxy or a monitor calls.
43 43 func (s *Server) globalRoutes(mux *http.ServeMux) {
44 44 w := s.Web
45 45 mux.HandleFunc("GET /{$}", w.IndexPage)
@@ -53,15 +53,17 @@ func (s *Server) globalRoutes(mux *http.ServeMux) {
53 53 mux.HandleFunc("GET /u/{$}", w.PeoplePage)
54 54 mux.HandleFunc("GET /u/{name}", w.ProfilePage)
55 55 mux.HandleFunc("GET /search/palette", w.SearchPalette)
56 mux.HandleFunc("GET /status", w.StatusPage)
56 // The status tabs moved onto the Admin page; old links redirect to the tab they
57 // named so a bookmark lands where it used to.
58 mux.HandleFunc("GET /status", w.StatusRedirect)
57 59 mux.HandleFunc("GET /healthz", func(rw http.ResponseWriter, r *http.Request) {
58 60 rw.Header().Set("Content-Type", "text/plain")
59 61 fmt.Fprint(rw, "ok\n")
60 62 })
61 // Runner presence moved to the status page's Runners tab; the old URL is
63 // Runner presence moved to the Admin page's Runners tab; the old URL is
62 64 // linked from notes and scripts, so it redirects rather than 404s.
63 65 mux.HandleFunc("GET /runners", func(rw http.ResponseWriter, r *http.Request) {
64 http.Redirect(rw, r, "/status?tab=runners", http.StatusMovedPermanently)
66 http.Redirect(rw, r, "/admin?tab=runners", http.StatusMovedPermanently)
65 67 })
66 68 }
67 69
@@ -95,8 +97,11 @@ func (s *Server) authRoutes(mux *http.ServeMux) {
95 97 // admin role itself; hiding a link is presentation, never authorization.
96 98 func (s *Server) adminRoutes(mux *http.ServeMux) {
97 99 w := s.Web
100 mux.HandleFunc("GET /admin", w.AdminPage)
98 101 mux.HandleFunc("GET /repos/new", w.AdminNewRepoPage)
99 102 mux.HandleFunc("POST /repos", w.CreateAdminRepo)
103 // The roster is the Accounts tab now; /users stays as the URL the account
104 // detail pages are still below.
100 105 mux.HandleFunc("GET /users", w.AdminUsersPage)
101 106 mux.HandleFunc("POST /users", w.CreateAdminUser)
102 107 mux.HandleFunc("POST /users/bots", w.CreateAdminBot)