diff options
author | Runxi Yu <me@runxiyu.org> | 2025-08-18 03:12:41 +0800 |
---|---|---|
committer | Runxi Yu <me@runxiyu.org> | 2025-08-18 03:12:41 +0800 |
commit | f7dde29539536a67687cbeff9662a9617e077150 (patch) | |
tree | d976eb1f64062a65da4e689bd650ad84be737c52 /forged | |
parent | Move sql to inside forged (diff) | |
download | forge-f7dde29539536a67687cbeff9662a9617e077150.tar.gz forge-f7dde29539536a67687cbeff9662a9617e077150.tar.zst forge-f7dde29539536a67687cbeff9662a9617e077150.zip |
Make the index page work
Diffstat (limited to 'forged')
-rw-r--r-- | forged/internal/global/global.go | 8 | ||||
-rw-r--r-- | forged/internal/incoming/hooks/hooks.go | 5 | ||||
-rw-r--r-- | forged/internal/incoming/lmtp/lmtp.go | 5 | ||||
-rw-r--r-- | forged/internal/incoming/ssh/ssh.go | 11 | ||||
-rw-r--r-- | forged/internal/incoming/web/handler.go | 8 | ||||
-rw-r--r-- | forged/internal/incoming/web/handlers/group.go | 7 | ||||
-rw-r--r-- | forged/internal/incoming/web/handlers/index.go | 24 | ||||
-rw-r--r-- | forged/internal/incoming/web/handlers/not_implemented.go | 11 | ||||
-rw-r--r-- | forged/internal/incoming/web/handlers/repo/handler.go | 15 | ||||
-rw-r--r-- | forged/internal/incoming/web/handlers/repo/index.go | 8 | ||||
-rw-r--r-- | forged/internal/incoming/web/router.go | 59 | ||||
-rw-r--r-- | forged/internal/incoming/web/server.go | 8 | ||||
-rw-r--r-- | forged/internal/incoming/web/types/types.go | 10 | ||||
-rw-r--r-- | forged/internal/server/server.go | 21 | ||||
-rw-r--r-- | forged/sql/queries/groups.sql | 3 | ||||
-rw-r--r-- | forged/templates/_footer.tmpl | 2 | ||||
-rw-r--r-- | forged/templates/_header.tmpl | 16 | ||||
-rw-r--r-- | forged/templates/index.tmpl | 8 |
18 files changed, 173 insertions, 56 deletions
diff --git a/forged/internal/global/global.go b/forged/internal/global/global.go new file mode 100644 index 0000000..7d2f03f --- /dev/null +++ b/forged/internal/global/global.go @@ -0,0 +1,8 @@ +package global + +type GlobalData struct { + ForgeTitle string + ForgeVersion string + SSHPubkey string + SSHFingerprint string +} diff --git a/forged/internal/incoming/hooks/hooks.go b/forged/internal/incoming/hooks/hooks.go index d0f57f5..941b03f 100644 --- a/forged/internal/incoming/hooks/hooks.go +++ b/forged/internal/incoming/hooks/hooks.go @@ -10,12 +10,14 @@ import ( "github.com/gliderlabs/ssh" "go.lindenii.runxiyu.org/forge/forged/internal/common/cmap" "go.lindenii.runxiyu.org/forge/forged/internal/common/misc" + "go.lindenii.runxiyu.org/forge/forged/internal/global" ) type Server struct { hookMap cmap.Map[string, hookInfo] socketPath string executablesPath string + globalData *global.GlobalData } type hookInfo struct { session ssh.Session @@ -30,11 +32,12 @@ type hookInfo struct { contribReq string } -func New(config Config) (server *Server) { +func New(config Config, globalData *global.GlobalData) (server *Server) { return &Server{ socketPath: config.Socket, executablesPath: config.Execs, hookMap: cmap.Map[string, hookInfo]{}, + globalData: globalData, } } diff --git a/forged/internal/incoming/lmtp/lmtp.go b/forged/internal/incoming/lmtp/lmtp.go index 61b1caf..d7e5ef4 100644 --- a/forged/internal/incoming/lmtp/lmtp.go +++ b/forged/internal/incoming/lmtp/lmtp.go @@ -8,6 +8,7 @@ import ( "time" "go.lindenii.runxiyu.org/forge/forged/internal/common/misc" + "go.lindenii.runxiyu.org/forge/forged/internal/global" ) type Server struct { @@ -16,15 +17,17 @@ type Server struct { maxSize int64 writeTimeout uint32 readTimeout uint32 + globalData *global.GlobalData } -func New(config Config) (server *Server) { +func New(config Config, globalData *global.GlobalData) (server *Server) { return &Server{ socket: config.Socket, domain: config.Domain, maxSize: config.MaxSize, writeTimeout: config.WriteTimeout, readTimeout: config.ReadTimeout, + globalData: globalData, } } diff --git a/forged/internal/incoming/ssh/ssh.go b/forged/internal/incoming/ssh/ssh.go index 9338eca..dc03501 100644 --- a/forged/internal/incoming/ssh/ssh.go +++ b/forged/internal/incoming/ssh/ssh.go @@ -9,26 +9,27 @@ import ( gliderssh "github.com/gliderlabs/ssh" "go.lindenii.runxiyu.org/forge/forged/internal/common/misc" + "go.lindenii.runxiyu.org/forge/forged/internal/global" gossh "golang.org/x/crypto/ssh" ) type Server struct { gliderServer *gliderssh.Server privkey gossh.Signer - pubkeyString string - pubkeyFP string net string addr string root string shutdownTimeout uint32 + globalData *global.GlobalData } -func New(config Config) (server *Server, err error) { +func New(config Config, globalData *global.GlobalData) (server *Server, err error) { server = &Server{ net: config.Net, addr: config.Addr, root: config.Root, shutdownTimeout: config.ShutdownTimeout, + globalData: globalData, } //exhaustruct:ignore var privkeyBytes []byte @@ -43,8 +44,8 @@ func New(config Config) (server *Server, err error) { return server, fmt.Errorf("parse SSH private key: %w", err) } - server.pubkeyString = misc.BytesToString(gossh.MarshalAuthorizedKey(server.privkey.PublicKey())) - server.pubkeyFP = gossh.FingerprintSHA256(server.privkey.PublicKey()) + server.globalData.SSHPubkey = misc.BytesToString(gossh.MarshalAuthorizedKey(server.privkey.PublicKey())) + server.globalData.SSHFingerprint = gossh.FingerprintSHA256(server.privkey.PublicKey()) server.gliderServer = &gliderssh.Server{ Handler: handle, diff --git a/forged/internal/incoming/web/handler.go b/forged/internal/incoming/web/handler.go index da2a2e0..bc50b33 100644 --- a/forged/internal/incoming/web/handler.go +++ b/forged/internal/incoming/web/handler.go @@ -5,6 +5,8 @@ import ( "net/http" "go.lindenii.runxiyu.org/forge/forged/internal/common/misc" + "go.lindenii.runxiyu.org/forge/forged/internal/database/queries" + "go.lindenii.runxiyu.org/forge/forged/internal/global" handlers "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/handlers" repoHandlers "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/handlers/repo" "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/templates" @@ -14,8 +16,8 @@ type handler struct { r *Router } -func NewHandler(cfg Config) http.Handler { - h := &handler{r: NewRouter().ReverseProxy(cfg.ReverseProxy)} +func NewHandler(cfg Config, globalData *global.GlobalData, queries *queries.Queries) *handler { + h := &handler{r: NewRouter().ReverseProxy(cfg.ReverseProxy).Global(globalData).Queries(queries)} staticFS := http.FileServer(http.Dir(cfg.StaticPath)) h.r.ANYHTTP("-/static/*rest", @@ -36,7 +38,7 @@ func NewHandler(cfg Config) http.Handler { indexHTTP := handlers.NewIndexHTTP(renderer) groupHTTP := handlers.NewGroupHTTP(renderer) repoHTTP := repoHandlers.NewHTTP(renderer) - notImpl := handlers.NewNotImplementedHTTP() + notImpl := handlers.NewNotImplementedHTTP(renderer) // Index h.r.GET("/", indexHTTP.Index) diff --git a/forged/internal/incoming/web/handlers/group.go b/forged/internal/incoming/web/handlers/group.go index 0c631c3..e56a3b5 100644 --- a/forged/internal/incoming/web/handlers/group.go +++ b/forged/internal/incoming/web/handlers/group.go @@ -12,7 +12,11 @@ type GroupHTTP struct { r templates.Renderer } -func NewGroupHTTP(r templates.Renderer) *GroupHTTP { return &GroupHTTP{r: r} } +func NewGroupHTTP(r templates.Renderer) *GroupHTTP { + return &GroupHTTP{ + r: r, + } +} func (h *GroupHTTP) Index(w http.ResponseWriter, r *http.Request, _ wtypes.Vars) { base := wtypes.Base(r) @@ -22,4 +26,3 @@ func (h *GroupHTTP) Index(w http.ResponseWriter, r *http.Request, _ wtypes.Vars) GroupPath: "/" + strings.Join(base.GroupPath, "/") + "/", }) } - diff --git a/forged/internal/incoming/web/handlers/index.go b/forged/internal/incoming/web/handlers/index.go index 259ca4a..22e6201 100644 --- a/forged/internal/incoming/web/handlers/index.go +++ b/forged/internal/incoming/web/handlers/index.go @@ -4,7 +4,9 @@ import ( "log" "net/http" + "go.lindenii.runxiyu.org/forge/forged/internal/database/queries" "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/templates" + "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/types" wtypes "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/types" ) @@ -12,13 +14,25 @@ type IndexHTTP struct { r templates.Renderer } -func NewIndexHTTP(r templates.Renderer) *IndexHTTP { return &IndexHTTP{r: r} } +func NewIndexHTTP(r templates.Renderer) *IndexHTTP { + return &IndexHTTP{ + r: r, + } +} -func (h *IndexHTTP) Index(w http.ResponseWriter, _ *http.Request, _ wtypes.Vars) { - err := h.r.Render(w, "index", struct { - Title string +func (h *IndexHTTP) Index(w http.ResponseWriter, r *http.Request, _ wtypes.Vars) { + groups, err := types.Base(r).Queries.GetRootGroups(r.Context()) + if err != nil { + http.Error(w, "failed to get root groups", http.StatusInternalServerError) + log.Println("failed to get root groups", "error", err) + return + } + err = h.r.Render(w, "index", struct { + BaseData *types.BaseData + Groups []queries.GetRootGroupsRow }{ - Title: "Home", + BaseData: types.Base(r), + Groups: groups, }) if err != nil { log.Println("failed to render index page", "error", err) diff --git a/forged/internal/incoming/web/handlers/not_implemented.go b/forged/internal/incoming/web/handlers/not_implemented.go index 472f73b..6813c88 100644 --- a/forged/internal/incoming/web/handlers/not_implemented.go +++ b/forged/internal/incoming/web/handlers/not_implemented.go @@ -3,12 +3,19 @@ package handlers import ( "net/http" + "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/templates" wtypes "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/types" ) -type NotImplementedHTTP struct{} +type NotImplementedHTTP struct { + r templates.Renderer +} -func NewNotImplementedHTTP() *NotImplementedHTTP { return &NotImplementedHTTP{} } +func NewNotImplementedHTTP(r templates.Renderer) *NotImplementedHTTP { + return &NotImplementedHTTP{ + r: r, + } +} func (h *NotImplementedHTTP) Handle(w http.ResponseWriter, _ *http.Request, _ wtypes.Vars) { http.Error(w, "not implemented", http.StatusNotImplemented) diff --git a/forged/internal/incoming/web/handlers/repo/handler.go b/forged/internal/incoming/web/handlers/repo/handler.go new file mode 100644 index 0000000..2881d7d --- /dev/null +++ b/forged/internal/incoming/web/handlers/repo/handler.go @@ -0,0 +1,15 @@ +package repo + +import ( + "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/templates" +) + +type HTTP struct { + r templates.Renderer +} + +func NewHTTP(r templates.Renderer) *HTTP { + return &HTTP{ + r: r, + } +} diff --git a/forged/internal/incoming/web/handlers/repo/index.go b/forged/internal/incoming/web/handlers/repo/index.go index dd1382f..1a804b2 100644 --- a/forged/internal/incoming/web/handlers/repo/index.go +++ b/forged/internal/incoming/web/handlers/repo/index.go @@ -4,16 +4,9 @@ import ( "net/http" "strings" - "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/templates" wtypes "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/types" ) -type HTTP struct { - r templates.Renderer -} - -func NewHTTP(r templates.Renderer) *HTTP { return &HTTP{r: r} } - func (h *HTTP) Index(w http.ResponseWriter, r *http.Request, v wtypes.Vars) { base := wtypes.Base(r) repo := v["repo"] @@ -25,4 +18,3 @@ func (h *HTTP) Index(w http.ResponseWriter, r *http.Request, v wtypes.Vars) { Repo: repo, }) } - diff --git a/forged/internal/incoming/web/router.go b/forged/internal/incoming/web/router.go index 46eb935..7c2717d 100644 --- a/forged/internal/incoming/web/router.go +++ b/forged/internal/incoming/web/router.go @@ -1,15 +1,18 @@ package web import ( + "fmt" "net/http" "net/url" "sort" "strings" + "go.lindenii.runxiyu.org/forge/forged/internal/database/queries" + "go.lindenii.runxiyu.org/forge/forged/internal/global" wtypes "go.lindenii.runxiyu.org/forge/forged/internal/incoming/web/types" ) -type UserResolver func(*http.Request) (id int, username string, err error) +type UserResolver func(*http.Request) (id string, username string, err error) type ErrorRenderers struct { BadRequest func(http.ResponseWriter, *wtypes.BaseData, string) @@ -57,13 +60,21 @@ type Router struct { routes []route errors ErrorRenderers user UserResolver - global any + global *global.GlobalData reverseProxy bool + queries *queries.Queries } func NewRouter() *Router { return &Router{} } -func (r *Router) Global(v any) *Router { r.global = v; return r } +func (r *Router) Global(g *global.GlobalData) *Router { + r.global = g + return r +} +func (r *Router) Queries(q *queries.Queries) *Router { + r.queries = q + return r +} func (r *Router) ReverseProxy(enabled bool) *Router { r.reverseProxy = enabled; return r } func (r *Router) Errors(e ErrorRenderers) *Router { r.errors = e; return r } func (r *Router) UserResolver(u UserResolver) *Router { r.user = u; return r } @@ -138,6 +149,13 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { Global: r.global, URLSegments: segments, DirMode: dirMode, + Queries: r.queries, + } + + bd.RefType, bd.RefName, err = GetParamRefTypeName(req) + if err != nil { + r.err400(w, bd, "Error parsing ref query parameters: "+err.Error()) + return } if r.user != nil { @@ -379,3 +397,38 @@ func (r *Router) err500(w http.ResponseWriter, b *wtypes.BaseData, msg string) { } http.Error(w, msg, http.StatusInternalServerError) } + +func GetParamRefTypeName(request *http.Request) (retRefType, retRefName string, err error) { + rawQuery := request.URL.RawQuery + queryValues, err := url.ParseQuery(rawQuery) + if err != nil { + return + } + done := false + for _, refType := range []string{"commit", "branch", "tag"} { + refName, ok := queryValues[refType] + if ok { + if done { + err = errDupRefSpec + return + } + done = true + if len(refName) != 1 { + err = errDupRefSpec + return + } + retRefName = refName[0] + retRefType = refType + } + } + if !done { + retRefType = "" + retRefName = "" + err = nil // actually returning empty strings is enough? + } + return +} + +var ( + errDupRefSpec = fmt.Errorf("duplicate ref specifications") +) diff --git a/forged/internal/incoming/web/server.go b/forged/internal/incoming/web/server.go index 6229bf0..f81886f 100644 --- a/forged/internal/incoming/web/server.go +++ b/forged/internal/incoming/web/server.go @@ -9,6 +9,8 @@ import ( "time" "go.lindenii.runxiyu.org/forge/forged/internal/common/misc" + "go.lindenii.runxiyu.org/forge/forged/internal/database/queries" + "go.lindenii.runxiyu.org/forge/forged/internal/global" ) type Server struct { @@ -17,11 +19,12 @@ type Server struct { root string httpServer *http.Server shutdownTimeout uint32 + globalData *global.GlobalData } -func New(config Config) (server *Server) { +func New(config Config, globalData *global.GlobalData, queries *queries.Queries) *Server { httpServer := &http.Server{ - Handler: NewHandler(config), + Handler: NewHandler(config, globalData, queries), ReadTimeout: time.Duration(config.ReadTimeout) * time.Second, WriteTimeout: time.Duration(config.WriteTimeout) * time.Second, IdleTimeout: time.Duration(config.IdleTimeout) * time.Second, @@ -33,6 +36,7 @@ func New(config Config) (server *Server) { root: config.Root, shutdownTimeout: config.ShutdownTimeout, httpServer: httpServer, + globalData: globalData, } } diff --git a/forged/internal/incoming/web/types/types.go b/forged/internal/incoming/web/types/types.go index d47b13a..1301fe9 100644 --- a/forged/internal/incoming/web/types/types.go +++ b/forged/internal/incoming/web/types/types.go @@ -3,18 +3,24 @@ package types import ( "context" "net/http" + + "go.lindenii.runxiyu.org/forge/forged/internal/database/queries" + "go.lindenii.runxiyu.org/forge/forged/internal/global" ) // BaseData is per-request context computed by the router and read by handlers. // Keep it small and stable; page-specific data should live in view models. type BaseData struct { - Global any - UserID int + UserID string Username string URLSegments []string DirMode bool GroupPath []string SeparatorIndex int + RefType string + RefName string + Global *global.GlobalData + Queries *queries.Queries } type ctxKey struct{} diff --git a/forged/internal/server/server.go b/forged/internal/server/server.go index 86332a7..ecd5fe1 100644 --- a/forged/internal/server/server.go +++ b/forged/internal/server/server.go @@ -6,6 +6,8 @@ import ( "go.lindenii.runxiyu.org/forge/forged/internal/config" "go.lindenii.runxiyu.org/forge/forged/internal/database" + "go.lindenii.runxiyu.org/forge/forged/internal/database/queries" + "go.lindenii.runxiyu.org/forge/forged/internal/global" "go.lindenii.runxiyu.org/forge/forged/internal/incoming/hooks" "go.lindenii.runxiyu.org/forge/forged/internal/incoming/lmtp" "go.lindenii.runxiyu.org/forge/forged/internal/incoming/ssh" @@ -22,11 +24,7 @@ type Server struct { webServer *web.Server sshServer *ssh.Server - globalData struct { - SSHPubkey string - SSHFingerprint string - Version string - } + globalData global.GlobalData } func New(configPath string) (server *Server, err error) { @@ -37,10 +35,15 @@ func New(configPath string) (server *Server, err error) { return server, fmt.Errorf("open config: %w", err) } - server.hookServer = hooks.New(server.config.Hooks) - server.lmtpServer = lmtp.New(server.config.LMTP) - server.webServer = web.New(server.config.Web) - server.sshServer, err = ssh.New(server.config.SSH) + queries := queries.New(&server.database) + + server.globalData.ForgeVersion = "unknown" // TODO + server.globalData.ForgeTitle = server.config.General.Title + + server.hookServer = hooks.New(server.config.Hooks, &server.globalData) + server.lmtpServer = lmtp.New(server.config.LMTP, &server.globalData) + server.webServer = web.New(server.config.Web, &server.globalData, queries) + server.sshServer, err = ssh.New(server.config.SSH, &server.globalData) if err != nil { return server, fmt.Errorf("create SSH server: %w", err) } diff --git a/forged/sql/queries/groups.sql b/forged/sql/queries/groups.sql index 07fe5e7..5b48fc4 100644 --- a/forged/sql/queries/groups.sql +++ b/forged/sql/queries/groups.sql @@ -1,3 +1,6 @@ +-- name: GetRootGroups :many +SELECT name, COALESCE(description, '') FROM groups WHERE parent_group IS NULL; + -- name: GetGroupIDDescByPath :one WITH RECURSIVE group_path_cte AS ( SELECT diff --git a/forged/templates/_footer.tmpl b/forged/templates/_footer.tmpl index 22a3958..11e2365 100644 --- a/forged/templates/_footer.tmpl +++ b/forged/templates/_footer.tmpl @@ -4,7 +4,7 @@ */}} {{- define "footer" -}} <a href="https://lindenii.runxiyu.org/forge/">Lindenii Forge</a> -{{ .global.forge_version }} +{{ .BaseData.Global.ForgeVersion }} (<a href="https://forge.lindenii.runxiyu.org/forge/-/repos/server/">upstream</a>, <a href="/-/source/LICENSE">license</a>, <a href="https://webirc.runxiyu.org/kiwiirc/#lindenii">support</a>) diff --git a/forged/templates/_header.tmpl b/forged/templates/_header.tmpl index 340a2ac..39d3491 100644 --- a/forged/templates/_header.tmpl +++ b/forged/templates/_header.tmpl @@ -5,15 +5,15 @@ {{- define "header" -}} <header id="main-header"> <div id="main-header-forge-title"> - <a href="/">{{- .global.forge_title -}}</a> + <a href="/">{{- .BaseData.Global.ForgeTitle -}}</a> </div> <nav id="breadcrumb-nav"> {{- $path := "" -}} - {{- $url_segments := .url_segments -}} - {{- $dir_mode := .dir_mode -}} - {{- $ref_type := .ref_type -}} - {{- $ref := .ref_name -}} - {{- $separator_index := .separator_index -}} + {{- $url_segments := .BaseData.URLSegments -}} + {{- $dir_mode := .BaseData.DirMode -}} + {{- $ref_type := .BaseData.RefType -}} + {{- $ref := .BaseData.RefName -}} + {{- $separator_index := .BaseData.SeparatorIndex -}} {{- if eq $separator_index -1 -}} {{- $separator_index = len $url_segments -}} {{- end -}} @@ -25,8 +25,8 @@ {{- end -}} </nav> <div id="main-header-user"> - {{- if ne .user_id_string "" -}} - <a href="/-/users/{{- .user_id_string -}}">{{- .username -}}</a> + {{- if ne .BaseData.UserID "" -}} + <a href="/-/users/{{- .BaseData.UserID -}}/">{{- .BaseData.Username -}}</a> {{- else -}} <a href="/-/login/">Login</a> {{- end -}} diff --git a/forged/templates/index.tmpl b/forged/templates/index.tmpl index 66bd177..fa9b6a0 100644 --- a/forged/templates/index.tmpl +++ b/forged/templates/index.tmpl @@ -7,7 +7,7 @@ <html lang="en"> <head> {{- template "head_common" . -}} - <title>Index – {{ .global.forge_title -}}</title> + <title>Index – {{ .BaseData.Global.ForgeTitle -}}</title> </head> <body class="index"> {{- template "header" . -}} @@ -24,7 +24,7 @@ </tr> </thead> <tbody> - {{- range .groups -}} + {{- range .Groups -}} <tr> <td> <a href="{{- .Name | path_escape -}}/">{{- .Name -}}</a> @@ -47,11 +47,11 @@ <tbody> <tr> <th scope="row">SSH public key</th> - <td><code class="breakable">{{- .global.server_public_key_string -}}</code></td> + <td><code class="breakable">{{- .BaseData.Global.SSHPubkey -}}</code></td> </tr> <tr> <th scope="row">SSH fingerprint</th> - <td><code class="breakable">{{- .global.server_public_key_fingerprint -}}</code></td> + <td><code class="breakable">{{- .BaseData.Global.SSHFingerprint -}}</code></td> </tr> </tbody> </table> |