v0.1.14 26223e3

router.go RawHistoryFolder

1package httpserve
2
3import (
4	"github.com/bnema/gordon/internal/httpserve/handlers"
5	"github.com/bnema/gordon/internal/httpserve/middleware"
6	"github.com/bnema/gordon/internal/server"
7	_ "github.com/joho/godotenv/autoload"
8	"github.com/labstack/echo/v4"
9	echomid "github.com/labstack/echo/v4/middleware"
10)
11
12// RegisterRoutes registers all routes and middlewares
13func RegisterRoutes(e *echo.Echo, a *server.App) *echo.Echo {
14	// e.Use(echomid.Logger()) too verbose
15	e.Use(echomid.Recover())
16	// Initiate the session middleware
17	e.Use(middleware.InitSessionMiddleware(a))
18
19	// Language detection
20	e.Use(middleware.LanguageDetection)
21
22	AdminPath := a.Config.Admin.Path
23	bindLoginRoute(e, a, AdminPath)
24	bindAPIEndpoints(e, a)
25
26	// SetCommonDataMiddleware will pass data to the renderer
27	e.Use(middleware.SetCommonDataMiddleware(a))
28
29	// Error handler middleware
30	e.Use(middleware.ErrorHandler)
31
32	// Use middlewares
33	e.Use(middleware.SecureRoutes(a))
34
35	// Color scheme detection for dark/light mode
36	e.Use(middleware.ColorSchemeDetection)
37
38	bindAdminRoute(e, a, AdminPath)
39	bindStaticRoute(e, a, "/*")
40	bindHTMXEndpoints(e, a)
41
42	// Protect the root path with a 403
43	e.GET("/", func(c echo.Context) error {
44		return c.String(403, "403 Forbidden")
45	})
46
47	return e
48}
49
50// bindAPIEndpoints expose /api endpoints and speaks only JSON
51func bindAPIEndpoints(e *echo.Echo, a *server.App) {
52	apiGroup := e.Group("/api")
53
54	// Device flow endpoints (without RequireToken middleware)
55	apiGroup.POST("/device/code", func(c echo.Context) error {
56		return handlers.DeviceCodeRequest(c, a)
57	})
58	apiGroup.POST("/device/token", func(c echo.Context) error {
59		return handlers.DeviceTokenRequest(c, a)
60	})
61
62	// Other API endpoints that require a token
63	protectedApiGroup := apiGroup.Group("", middleware.RequireToken(a))
64	protectedApiGroup.GET("/ping", func(c echo.Context) error {
65		return handlers.GetInfos(c, a)
66	})
67	protectedApiGroup.POST("/deploy", func(c echo.Context) error {
68		return handlers.PostDeploy(c, a)
69	})
70	protectedApiGroup.POST("/push", func(c echo.Context) error {
71		return handlers.PostPush(c, a)
72	})
73	protectedApiGroup.POST("/stop", func(c echo.Context) error {
74		return handlers.PostContainerStop(c, a)
75	})
76	protectedApiGroup.POST("/remove", func(c echo.Context) error {
77		return handlers.PostContainerRemove(c, a)
78	})
79}
80
81// bindStaticRoute bind static path
82func bindStaticRoute(e *echo.Echo, a *server.App, path string) {
83	e.GET(path, func(c echo.Context) error {
84		return handlers.StaticRoute(c, a)
85	}, echomid.Gzip())
86}
87
88// bindLoginRoute binds all login routes
89func bindLoginRoute(e *echo.Echo, a *server.App, adminPath string) {
90	e.GET(adminPath+"/login", func(c echo.Context) error {
91		return handlers.RenderLoginPage(c, a)
92	})
93	e.GET(adminPath+"/login/oauth/github", func(c echo.Context) error {
94		return handlers.StartOAuthGithub(c, a)
95	})
96	e.GET(adminPath+"/login/oauth/callback", func(c echo.Context) error {
97		return handlers.OAuthCallback(c, a)
98	})
99	e.GET(adminPath+"/logout", func(c echo.Context) error {
100		return handlers.Logout(c, a)
101	})
102}
103
104// bindAdminRoute binds all admin routes
105func bindAdminRoute(e *echo.Echo, a *server.App, adminPath string) {
106	adminGroup := e.Group(adminPath)
107	// Since login is behind the admin path, we cannot use group middleware
108	adminGroup.GET("", func(c echo.Context) error {
109		return c.Redirect(302, adminPath+"/manager")
110	}, middleware.RequireLogin(a))
111
112	adminGroup.GET("/manager", func(c echo.Context) error {
113		return handlers.AdminManagerRoute(c, a)
114	}, middleware.RequireLogin(a))
115	adminGroup.GET("/cc/:ID", func(c echo.Context) error {
116		return handlers.CreateContainerFullGET(c, a)
117	}, middleware.RequireLogin(a))
118}
119
120// bindHTMXEndpoints binds all HTMX endpoints
121func bindHTMXEndpoints(e *echo.Echo, a *server.App) {
122	// Create a  group for /htmx endpoints
123	htmxGroup := e.Group("/htmx")
124
125	// Apply middleware to the group, so all endpoints are protected
126	htmxGroup.Use(middleware.RequireLogin(a))
127
128	// List all images component
129	htmxGroup.GET("/image-manager", func(c echo.Context) error {
130		return handlers.ImageManagerComponent(c, a)
131	})
132	// Delete an image
133	htmxGroup.DELETE("/image-manager/delete/:ID", func(c echo.Context) error {
134		return handlers.ImageManagerDelete(c, a)
135	})
136
137	// List all containers
138	htmxGroup.GET("/container-manager", func(c echo.Context) error {
139		return handlers.ContainerManagerComponent(c, a)
140	})
141	// Stop a container
142	htmxGroup.POST("/container-manager/stop/:ID", func(c echo.Context) error {
143		return handlers.ContainerManagerStop(c, a)
144	})
145	// Delete a container
146	htmxGroup.DELETE("/container-manager/delete/:ID", func(c echo.Context) error {
147		return handlers.ContainerManagerDelete(c, a)
148	})
149	// Start a container
150	htmxGroup.POST("/container-manager/start/:ID", func(c echo.Context) error {
151		return handlers.ContainerManagerStart(c, a)
152	})
153	// Edit a container view
154	htmxGroup.GET("/container-manager/edit/:ID", func(c echo.Context) error {
155		return handlers.ContainerManagerEditGET(c, a)
156	})
157	// Edit a container action
158	htmxGroup.POST("/container-manager/edit/:ID", func(c echo.Context) error {
159		return handlers.ContainerManagerEditPOST(c, a)
160	})
161
162	// Display upload-image component
163	htmxGroup.GET("/upload-image", func(c echo.Context) error {
164		return handlers.UploadImageGETHandler(c, a)
165	})
166	// Upload image
167	htmxGroup.POST("/upload-image", func(c echo.Context) error {
168		return handlers.UploadImagePOSTHandler(c, a)
169	})
170	// Display create-container component
171	htmxGroup.GET("/create-container/:ID", func(c echo.Context) error {
172		return handlers.CreateContainerGET(c, a)
173	})
174	// Create container
175	htmxGroup.POST("/create-container/:ID", func(c echo.Context) error {
176		return handlers.CreateContainerPOST(c, a)
177	})
178}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close