From 727427589e8e7ef182601fc8253bf9185e277365 Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Wed, 4 Dec 2024 11:42:49 -0300 Subject: [PATCH 01/13] feat(blog,gitea): gitea api to blog reroute mock --- handlers/pages/routes.go | 6 ++++++ libs/blog/blog.go | 45 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 libs/blog/blog.go diff --git a/handlers/pages/routes.go b/handlers/pages/routes.go index ea33418..c83897e 100644 --- a/handlers/pages/routes.go +++ b/handlers/pages/routes.go @@ -2,7 +2,9 @@ package pages import ( "log/slog" + "net/http" + "forge.capytal.company/capytal/www/libs/blog" "forge.capytal.company/capytalcode/project-comicverse/lib/router" "forge.capytal.company/capytalcode/project-comicverse/lib/router/rerrors" ) @@ -15,5 +17,9 @@ func Routes(log *slog.Logger) router.Router { r.Handle("/", &IndexPage{}) r.Handle("/about", &AboutPage{}) + b := blog.NewGiteaBlog("dot013", "blog", "https://forge.capytal.company/api/v1") + + r.Handle("/blog/{path...}", http.StripPrefix("/blog/", b)) + return r } diff --git a/libs/blog/blog.go b/libs/blog/blog.go new file mode 100644 index 0000000..a7c82f5 --- /dev/null +++ b/libs/blog/blog.go @@ -0,0 +1,45 @@ +package blog + +import ( + "fmt" + "io" + "log" + "net/http" + "path" + "forge.capytal.company/capytalcode/project-comicverse/lib/router/rerrors" +) + +func NewGiteaBlog(owner, repo, endpoint string) *GiteaBlog { + return &GiteaBlog{ + owner: owner, + repo: repo, + endpoint: endpoint, + } +} + +func (b *GiteaBlog) ServeHTTP(w http.ResponseWriter, r *http.Request) { + p := path.Clean(r.URL.Path) + p = fmt.Sprintf("%s/repos/%s/%s/contents/%s", b.endpoint, b.owner, b.repo, p) + + log.Printf("PATH %s", p) + + res, err := http.Get(p) + if err != nil { + rerrors.InternalError(err).ServeHTTP(w, r) + return + } + + body, err := io.ReadAll(res.Body) + if err != nil { + rerrors.InternalError(err).ServeHTTP(w, r) + return + } else if res.StatusCode != http.StatusOK { + rerrors.InternalError(fmt.Errorf("Non-OK: %s", string(body))).ServeHTTP(w, r) + return + } + + if _, err := w.Write(body); err != nil { + rerrors.InternalError(err).ServeHTTP(w, r) + return + } +} From 178c32087e296db2c3bf43de29b5a98718d5df06 Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Wed, 18 Dec 2024 09:48:25 -0300 Subject: [PATCH 02/13] feat(deps): update dependencies --- go.mod | 4 ++-- go.sum | 4 ++++ handlers/pages/routes.go | 2 +- main.go | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index be8efa2..0845342 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,6 @@ go 1.22.7 toolchain go1.22.8 -require forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241024232831-478dd0216e72 +require forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241213195940-67230ba75d8a -require github.com/a-h/templ v0.2.778 +require github.com/a-h/templ v0.2.793 diff --git a/go.sum b/go.sum index a8574f7..83a265b 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,10 @@ forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241024232831-478dd0216e72 h1:HpAsKmgSWME9bfpvicXlZF/+ZZW92w6DXoscsqNB1j8= forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241024232831-478dd0216e72/go.mod h1:COqB9i9nyQrQUz/ZqMvN98V7rh0t7vdXmBV36G8Q+7Q= +forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241213195940-67230ba75d8a h1:PDmA2uCzFdn+CdS3C+Pg1YGhJERgMjwgCjUEUaIDZTM= +forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241213195940-67230ba75d8a/go.mod h1:COqB9i9nyQrQUz/ZqMvN98V7rh0t7vdXmBV36G8Q+7Q= github.com/a-h/templ v0.2.778 h1:VzhOuvWECrwOec4790lcLlZpP4Iptt5Q4K9aFxQmtaM= github.com/a-h/templ v0.2.778/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= +github.com/a-h/templ v0.2.793 h1:Io+/ocnfGWYO4VHdR0zBbf39PQlnzVCVVD+wEEs6/qY= +github.com/a-h/templ v0.2.793/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/handlers/pages/routes.go b/handlers/pages/routes.go index c83897e..d91d872 100644 --- a/handlers/pages/routes.go +++ b/handlers/pages/routes.go @@ -12,7 +12,7 @@ import ( func Routes(log *slog.Logger) router.Router { r := router.NewRouter() - r.Use(rerrors.NewErrorMiddleware(ErrorPage{}.Component, log).Wrap) + r.Use(rerrors.NewErrorMiddleware(ErrorPage{}.Component, log)) r.Handle("/", &IndexPage{}) r.Handle("/about", &AboutPage{}) diff --git a/main.go b/main.go index b9fbb41..4b1fadd 100644 --- a/main.go +++ b/main.go @@ -42,7 +42,7 @@ func main() { logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) - router.Use(middleware.NewLoggerMiddleware(logger).Wrap) + router.Use(middleware.NewLoggerMiddleware(logger)) if dev { configs.DEVELOPMENT = true From dddaad65fd52b85096e4000cf3a5755577840539 Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Wed, 18 Dec 2024 09:51:00 -0300 Subject: [PATCH 03/13] feat: prototyping of blog system with forgejo --- handlers/pages/blog.go | 96 ++++++++++++++++++++++++++++++++++++++++ handlers/pages/routes.go | 5 +-- 2 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 handlers/pages/blog.go diff --git a/handlers/pages/blog.go b/handlers/pages/blog.go new file mode 100644 index 0000000..cc472e7 --- /dev/null +++ b/handlers/pages/blog.go @@ -0,0 +1,96 @@ +package pages + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "path" + + "forge.capytal.company/capytalcode/project-comicverse/lib/router" + "forge.capytal.company/capytalcode/project-comicverse/lib/router/rerrors" +) + +type Blog struct { + repo string + owner string + endpoint string +} + +func NewBlog(repo, owner, endpoint string) *Blog { + u, err := url.Parse(endpoint) + if err != nil { + panic(fmt.Sprintf("Blog Forgejo endpoint is not a valid URL: %v", err)) + } + return &Blog{repo: repo, owner: owner, endpoint: u.String()} +} + +func (p *Blog) Routes() router.Router { + r := router.NewRouter() + + r.HandleFunc("/", p.listPosts) + + return r +} + +func (p *Blog) listPosts(w http.ResponseWriter, r *http.Request) { + _, body, rerr := p.get(fmt.Sprintf("/repos/%s/%s/contents/daily-blogs", p.owner, p.repo)) + if rerr != nil { + rerr.ServeHTTP(w, r) + return + } + + var list []forgejoFile + + err := json.Unmarshal(body, &list) + if err != nil { + rerrors.InternalError(errors.New("failed to parse list of entries"), err).ServeHTTP(w, r) + return + } + + w.WriteHeader(http.StatusOK) + _, err = w.Write([]byte(fmt.Sprintf("%v", list))) + if err != nil { + rerrors.InternalError(err).ServeHTTP(w, r) + } +} + +func (p *Blog) get(endpoint string) (http.Header, []byte, *rerrors.RouteError) { + u, _ := url.Parse(p.endpoint) + u.Path = path.Join(u.Path, endpoint) + + r, err := http.Get(u.String()) + if err != nil { + e := rerrors.InternalError( + fmt.Errorf("failed to make request to endpoint %s", u.String()), + err, + ) + return nil, nil, &e + } + + body, err := io.ReadAll(r.Body) + if err != nil { + e := rerrors.InternalError( + fmt.Errorf("failed to read response body of request to endpoint %s", u.String()), + err, + ) + return nil, nil, &e + } else if r.StatusCode != http.StatusOK { + e := rerrors.InternalError( + fmt.Errorf("request to endpoint %s returned non-200 code %q.\n%s", u.String(), r.Status, string(body)), + ) + return nil, nil, &e + } + + return r.Header, body, nil +} + +type forgejoFile struct { + Name string `json:"name"` + Path string `json:"path"` + Sha string `json:"sha"` + LastCommitSha string `json:"last_commit_sha"` + Type string `json:"type"` +} diff --git a/handlers/pages/routes.go b/handlers/pages/routes.go index d91d872..850abc4 100644 --- a/handlers/pages/routes.go +++ b/handlers/pages/routes.go @@ -17,9 +17,8 @@ func Routes(log *slog.Logger) router.Router { r.Handle("/", &IndexPage{}) r.Handle("/about", &AboutPage{}) - b := blog.NewGiteaBlog("dot013", "blog", "https://forge.capytal.company/api/v1") - - r.Handle("/blog/{path...}", http.StripPrefix("/blog/", b)) + b := NewBlog("dot013", "blog", "https://forge.capytal.company/api/v1") + r.Handle("/blog/", b.Routes()) return r } From b0bac675d9a06d0ad28aaf98bf02ccc457e6dd71 Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Wed, 18 Dec 2024 09:54:08 -0300 Subject: [PATCH 04/13] fix(blog,prototype): order of paramenters in blog constructor --- handlers/pages/blog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/pages/blog.go b/handlers/pages/blog.go index cc472e7..93ea983 100644 --- a/handlers/pages/blog.go +++ b/handlers/pages/blog.go @@ -19,7 +19,7 @@ type Blog struct { endpoint string } -func NewBlog(repo, owner, endpoint string) *Blog { +func NewBlog(owner, repo, endpoint string) *Blog { u, err := url.Parse(endpoint) if err != nil { panic(fmt.Sprintf("Blog Forgejo endpoint is not a valid URL: %v", err)) From c808ea111ed21ec931eb51ff164987672fed3771 Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Wed, 18 Dec 2024 09:54:25 -0300 Subject: [PATCH 05/13] fix(blog,prototype): remove unused imports from router --- handlers/pages/routes.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/handlers/pages/routes.go b/handlers/pages/routes.go index 850abc4..556916c 100644 --- a/handlers/pages/routes.go +++ b/handlers/pages/routes.go @@ -2,9 +2,7 @@ package pages import ( "log/slog" - "net/http" - "forge.capytal.company/capytal/www/libs/blog" "forge.capytal.company/capytalcode/project-comicverse/lib/router" "forge.capytal.company/capytalcode/project-comicverse/lib/router/rerrors" ) From 5b19d4493daaea0423d105f888afa6b1f783f180 Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Wed, 18 Dec 2024 15:45:39 -0300 Subject: [PATCH 06/13] feat: use local close of loreddev/x instead of lib in project-comicverse --- .gitmodules | 3 +++ go.mod | 6 +++--- go.sum | 6 ------ handlers/pages/about.templ | 2 +- handlers/pages/error.templ | 4 ++-- handlers/pages/index.templ | 2 +- handlers/pages/routes.go | 4 ++-- libs/blog/blog.go | 3 ++- main.go | 5 +++-- x | 1 + 10 files changed, 18 insertions(+), 18 deletions(-) create mode 100644 .gitmodules create mode 160000 x diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ef78831 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "x"] + path = x + url = https://forge.capytal.company/loreddev/x diff --git a/go.mod b/go.mod index 0845342..eab5b74 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,9 @@ module forge.capytal.company/capytal/www -go 1.22.7 +go 1.23.3 -toolchain go1.22.8 +require forge.capytal.company/loreddev/x v0.0.0 -require forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241213195940-67230ba75d8a +replace forge.capytal.company/loreddev/x => ./x require github.com/a-h/templ v0.2.793 diff --git a/go.sum b/go.sum index 83a265b..dab7b07 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,3 @@ -forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241024232831-478dd0216e72 h1:HpAsKmgSWME9bfpvicXlZF/+ZZW92w6DXoscsqNB1j8= -forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241024232831-478dd0216e72/go.mod h1:COqB9i9nyQrQUz/ZqMvN98V7rh0t7vdXmBV36G8Q+7Q= -forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241213195940-67230ba75d8a h1:PDmA2uCzFdn+CdS3C+Pg1YGhJERgMjwgCjUEUaIDZTM= -forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241213195940-67230ba75d8a/go.mod h1:COqB9i9nyQrQUz/ZqMvN98V7rh0t7vdXmBV36G8Q+7Q= -github.com/a-h/templ v0.2.778 h1:VzhOuvWECrwOec4790lcLlZpP4Iptt5Q4K9aFxQmtaM= -github.com/a-h/templ v0.2.778/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= github.com/a-h/templ v0.2.793 h1:Io+/ocnfGWYO4VHdR0zBbf39PQlnzVCVVD+wEEs6/qY= github.com/a-h/templ v0.2.793/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/handlers/pages/about.templ b/handlers/pages/about.templ index 62be68e..67484a6 100644 --- a/handlers/pages/about.templ +++ b/handlers/pages/about.templ @@ -5,7 +5,7 @@ import ( "forge.capytal.company/capytal/www/templates/layouts" - "forge.capytal.company/capytalcode/project-comicverse/lib/router/rerrors" + "forge.capytal.company/loreddev/x/groute/router/rerrors" ) type AboutPage struct{} diff --git a/handlers/pages/error.templ b/handlers/pages/error.templ index f183ffc..0206962 100644 --- a/handlers/pages/error.templ +++ b/handlers/pages/error.templ @@ -4,9 +4,9 @@ package pages import ( "fmt" - "forge.capytal.company/capytalcode/project-comicverse/lib/router/rerrors" - "forge.capytal.company/capytal/www/templates/layouts" + + "forge.capytal.company/loreddev/x/groute/router/rerrors" ) type ErrorPage struct{} diff --git a/handlers/pages/index.templ b/handlers/pages/index.templ index bb7e5c3..25a076d 100644 --- a/handlers/pages/index.templ +++ b/handlers/pages/index.templ @@ -6,7 +6,7 @@ import ( "forge.capytal.company/capytal/www/assets" "forge.capytal.company/capytal/www/templates/layouts" - "forge.capytal.company/capytalcode/project-comicverse/lib/router/rerrors" + "forge.capytal.company/loreddev/x/groute/router/rerrors" ) type IndexPage struct{} diff --git a/handlers/pages/routes.go b/handlers/pages/routes.go index 556916c..6f688d1 100644 --- a/handlers/pages/routes.go +++ b/handlers/pages/routes.go @@ -3,8 +3,8 @@ package pages import ( "log/slog" - "forge.capytal.company/capytalcode/project-comicverse/lib/router" - "forge.capytal.company/capytalcode/project-comicverse/lib/router/rerrors" + "forge.capytal.company/loreddev/x/groute/router" + "forge.capytal.company/loreddev/x/groute/router/rerrors" ) func Routes(log *slog.Logger) router.Router { diff --git a/libs/blog/blog.go b/libs/blog/blog.go index a7c82f5..e4c9a14 100644 --- a/libs/blog/blog.go +++ b/libs/blog/blog.go @@ -6,7 +6,8 @@ import ( "log" "net/http" "path" - "forge.capytal.company/capytalcode/project-comicverse/lib/router/rerrors" + + "forge.capytal.company/loreddev/x/groute/router/rerrors" ) func NewGiteaBlog(owner, repo, endpoint string) *GiteaBlog { diff --git a/main.go b/main.go index 4b1fadd..ee20d4b 100644 --- a/main.go +++ b/main.go @@ -14,8 +14,9 @@ import ( "forge.capytal.company/capytal/www/configs" "forge.capytal.company/capytal/www/handlers/pages" - "forge.capytal.company/capytalcode/project-comicverse/lib/middleware" - "forge.capytal.company/capytalcode/project-comicverse/lib/router" + + "forge.capytal.company/loreddev/x/groute/middleware" + "forge.capytal.company/loreddev/x/groute/router" ) var ( diff --git a/x b/x new file mode 160000 index 0000000..c0854de --- /dev/null +++ b/x @@ -0,0 +1 @@ +Subproject commit c0854dea2c1e35b051a73e998e099dc4319f36a5 From 23062bd02aadcb7b3b2d1a0f603fd8725952038c Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Wed, 18 Dec 2024 15:45:55 -0300 Subject: [PATCH 07/13] chore: update flakes --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index fb2a0f8..aaad62e 100644 --- a/flake.lock +++ b/flake.lock @@ -78,11 +78,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1730200266, - "narHash": "sha256-l253w0XMT8nWHGXuXqyiIC/bMvh1VRszGXgdpQlfhvU=", + "lastModified": 1734424634, + "narHash": "sha256-cHar1vqHOOyC7f1+tVycPoWTfKIaqkoe1Q6TnKzuti4=", "owner": "nixos", "repo": "nixpkgs", - "rev": "807e9154dcb16384b1b765ebe9cd2bba2ac287fd", + "rev": "d3c42f187194c26d9f0309a8ecc469d6c878ce33", "type": "github" }, "original": { From 8559f57473794760757edf5851be71fdb0dea7e9 Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Wed, 18 Dec 2024 15:51:51 -0300 Subject: [PATCH 08/13] chore: fix commited file --- handlers/pages/{blog.go => blog.templ} | 42 +++++++++++++++++++++----- handlers/pages/routes.go | 3 +- 2 files changed, 36 insertions(+), 9 deletions(-) rename handlers/pages/{blog.go => blog.templ} (68%) diff --git a/handlers/pages/blog.go b/handlers/pages/blog.templ similarity index 68% rename from handlers/pages/blog.go rename to handlers/pages/blog.templ index 93ea983..693b851 100644 --- a/handlers/pages/blog.go +++ b/handlers/pages/blog.templ @@ -4,13 +4,13 @@ import ( "encoding/json" "errors" "fmt" - "io" "net/http" "net/url" "path" - "forge.capytal.company/capytalcode/project-comicverse/lib/router" - "forge.capytal.company/capytalcode/project-comicverse/lib/router/rerrors" + "forge.capytal.company/capytal/www/templates/layouts" + + "forge.capytal.company/loreddev/x/groute/router/rerrors" ) type Blog struct { @@ -27,10 +27,17 @@ func NewBlog(owner, repo, endpoint string) *Blog { return &Blog{repo: repo, owner: owner, endpoint: u.String()} } -func (p *Blog) Routes() router.Router { - r := router.NewRouter() +func (p *Blog) Routes() http.Handler { + r := http.NewServeMux() - r.HandleFunc("/", p.listPosts) + r.HandleFunc("/{entry...}", func(w http.ResponseWriter, r *http.Request) { + pv := r.PathValue("entry") + if pv == "" { + p.listPosts(w, r) + } else { + p.blogEntry(w, r) + } + }) return r } @@ -50,13 +57,32 @@ func (p *Blog) listPosts(w http.ResponseWriter, r *http.Request) { return } - w.WriteHeader(http.StatusOK) - _, err = w.Write([]byte(fmt.Sprintf("%v", list))) + err = p.blogEntryList(list).Render(r.Context(), w) if err != nil { rerrors.InternalError(err).ServeHTTP(w, r) } } +templ (p *Blog) blogEntryList(entries []forgejoFile) { + @layouts.Page() { +
    + for _, e := range entries { +
  • { e.Name }
  • + } +
+ } +} + +func (p *Blog) blogEntry(w http.ResponseWriter, r *http.Request) { + _, body, rerr := p.get(fmt.Sprintf("/repos/%s/%s/raw/%s", p.owner, p.repo, r.PathValue("entry"))) + if rerr != nil { + rerr.ServeHTTP(w, r) + return + } + + w.Write(body) +} + func (p *Blog) get(endpoint string) (http.Header, []byte, *rerrors.RouteError) { u, _ := url.Parse(p.endpoint) u.Path = path.Join(u.Path, endpoint) diff --git a/handlers/pages/routes.go b/handlers/pages/routes.go index 6f688d1..5cd6f5e 100644 --- a/handlers/pages/routes.go +++ b/handlers/pages/routes.go @@ -2,6 +2,7 @@ package pages import ( "log/slog" + "net/http" "forge.capytal.company/loreddev/x/groute/router" "forge.capytal.company/loreddev/x/groute/router/rerrors" @@ -16,7 +17,7 @@ func Routes(log *slog.Logger) router.Router { r.Handle("/about", &AboutPage{}) b := NewBlog("dot013", "blog", "https://forge.capytal.company/api/v1") - r.Handle("/blog/", b.Routes()) + r.Handle("/blog", http.StripPrefix("/blog/", b.Routes())) return r } From 6cc20b29c435a2a63fbe411b68ae3998495ca8ee Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Wed, 18 Dec 2024 16:04:20 -0300 Subject: [PATCH 09/13] chore(deps): update submodule --- x | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x b/x index c0854de..d00fd5d 160000 --- a/x +++ b/x @@ -1 +1 @@ -Subproject commit c0854dea2c1e35b051a73e998e099dc4319f36a5 +Subproject commit d00fd5dbbee9ee4c2e2312beea5960fde7147689 From 5ea562dd31b9ba2d125d702a5011f83e6572a072 Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Wed, 18 Dec 2024 16:05:48 -0300 Subject: [PATCH 10/13] feat(blog): blog based on forgejo proof-of-concept --- handlers/pages/blog.templ | 5 +++-- handlers/pages/routes.go | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/handlers/pages/blog.templ b/handlers/pages/blog.templ index 693b851..a8dc088 100644 --- a/handlers/pages/blog.templ +++ b/handlers/pages/blog.templ @@ -11,6 +11,7 @@ import ( "forge.capytal.company/capytal/www/templates/layouts" "forge.capytal.company/loreddev/x/groute/router/rerrors" + "forge.capytal.company/loreddev/x/groute/router" ) type Blog struct { @@ -27,8 +28,8 @@ func NewBlog(owner, repo, endpoint string) *Blog { return &Blog{repo: repo, owner: owner, endpoint: u.String()} } -func (p *Blog) Routes() http.Handler { - r := http.NewServeMux() +func (p *Blog) Routes() router.Router { + r := router.NewRouter() r.HandleFunc("/{entry...}", func(w http.ResponseWriter, r *http.Request) { pv := r.PathValue("entry") diff --git a/handlers/pages/routes.go b/handlers/pages/routes.go index 5cd6f5e..6f688d1 100644 --- a/handlers/pages/routes.go +++ b/handlers/pages/routes.go @@ -2,7 +2,6 @@ package pages import ( "log/slog" - "net/http" "forge.capytal.company/loreddev/x/groute/router" "forge.capytal.company/loreddev/x/groute/router/rerrors" @@ -17,7 +16,7 @@ func Routes(log *slog.Logger) router.Router { r.Handle("/about", &AboutPage{}) b := NewBlog("dot013", "blog", "https://forge.capytal.company/api/v1") - r.Handle("/blog", http.StripPrefix("/blog/", b.Routes())) + r.Handle("/blog/", b.Routes()) return r } From 8c1d4af93dc6acb836f88aaea486044867297b9c Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Wed, 18 Dec 2024 16:35:29 -0300 Subject: [PATCH 11/13] feat(blog): markdown renderer proof-of-concept --- go.mod | 8 +++++++- go.sum | 8 ++++++++ handlers/pages/blog.templ | 27 +++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index eab5b74..71f4655 100644 --- a/go.mod +++ b/go.mod @@ -6,4 +6,10 @@ require forge.capytal.company/loreddev/x v0.0.0 replace forge.capytal.company/loreddev/x => ./x -require github.com/a-h/templ v0.2.793 +require ( + github.com/a-h/templ v0.2.793 + github.com/yuin/goldmark v1.7.8 + github.com/yuin/goldmark-meta v1.1.0 +) + +require gopkg.in/yaml.v2 v2.3.0 // indirect diff --git a/go.sum b/go.sum index dab7b07..48d0b02 100644 --- a/go.sum +++ b/go.sum @@ -2,3 +2,11 @@ github.com/a-h/templ v0.2.793 h1:Io+/ocnfGWYO4VHdR0zBbf39PQlnzVCVVD+wEEs6/qY= github.com/a-h/templ v0.2.793/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= +github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= +github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/handlers/pages/blog.templ b/handlers/pages/blog.templ index a8dc088..9c9251f 100644 --- a/handlers/pages/blog.templ +++ b/handlers/pages/blog.templ @@ -12,12 +12,18 @@ import ( "forge.capytal.company/loreddev/x/groute/router/rerrors" "forge.capytal.company/loreddev/x/groute/router" + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/extension" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark-meta" ) type Blog struct { repo string owner string endpoint string + + md goldmark.Markdown } func NewBlog(owner, repo, endpoint string) *Blog { @@ -25,7 +31,13 @@ func NewBlog(owner, repo, endpoint string) *Blog { if err != nil { panic(fmt.Sprintf("Blog Forgejo endpoint is not a valid URL: %v", err)) } - return &Blog{repo: repo, owner: owner, endpoint: u.String()} + + md := goldmark.New( + goldmark.WithExtensions(extension.GFM, meta.Meta), + goldmark.WithParserOptions(parser.WithAutoHeadingID()), + ) + + return &Blog{repo: repo, owner: owner, endpoint: u.String(), md: md} } func (p *Blog) Routes() router.Router { @@ -81,7 +93,18 @@ func (p *Blog) blogEntry(w http.ResponseWriter, r *http.Request) { return } - w.Write(body) + var buf bytes.Buffer + err := p.md.Convert(body, &buf) + if err != nil { + rerrors.InternalError(errors.New("failed to render markdown"), err).ServeHTTP(w, r) + return + } + + _, err = buf.WriteTo(w) + if err != nil { + rerrors.InternalError(errors.New("failed to write response"), err).ServeHTTP(w, r) + return + } } func (p *Blog) get(endpoint string) (http.Header, []byte, *rerrors.RouteError) { From f05e71515c8b10d6bbd424fdc46227e0450dbbb1 Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Fri, 3 Jan 2025 10:26:04 -0300 Subject: [PATCH 12/13] chore(deps): update templ --- flake.lock | 93 ++++++++++++++++-------------------------------------- flake.nix | 3 +- go.mod | 2 +- go.sum | 2 ++ makefile | 9 +++--- 5 files changed, 37 insertions(+), 72 deletions(-) diff --git a/flake.lock b/flake.lock index aaad62e..cf7090a 100644 --- a/flake.lock +++ b/flake.lock @@ -1,24 +1,6 @@ { "nodes": { "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1694529238, - "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_2": { "locked": { "lastModified": 1667395993, "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", @@ -54,28 +36,6 @@ "type": "github" } }, - "gomod2nix": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": [ - "templ", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1722589758, - "narHash": "sha256-sbbA8b6Q2vB/t/r1znHawoXLysCyD4L/6n6/RykiSnA=", - "owner": "nix-community", - "repo": "gomod2nix", - "rev": "4e08ca09253ef996bd4c03afa383b23e35fe28a1", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "gomod2nix", - "type": "github" - } - }, "nixpkgs": { "locked": { "lastModified": 1734424634, @@ -92,18 +52,34 @@ "type": "github" } }, - "nixpkgs_2": { + "nixpkgs-unstable": { "locked": { - "lastModified": 1724322575, - "narHash": "sha256-kRYwAdYsaICNb2WYcWtBFG6caSuT0v/vTAyR8ap0IR0=", + "lastModified": 1735471104, + "narHash": "sha256-0q9NGQySwDQc7RhAV2ukfnu7Gxa5/ybJ2ANT8DQrQrs=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2a02822b466ffb9f1c02d07c5dd6b96d08b56c6b", + "rev": "88195a94f390381c6afcdaa933c2f6ff93959cb4", "type": "github" }, "original": { "owner": "NixOS", - "ref": "release-24.05", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1735669367, + "narHash": "sha256-tfYRbFhMOnYaM4ippqqid3BaLOXoFNdImrfBfCp4zn0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "edf04b75c13c2ac0e54df5ec5c543e300f76f1c9", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.11", "repo": "nixpkgs", "type": "github" } @@ -114,46 +90,31 @@ "templ": "templ" } }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, "templ": { "inputs": { "gitignore": "gitignore", - "gomod2nix": "gomod2nix", "nixpkgs": "nixpkgs_2", + "nixpkgs-unstable": "nixpkgs-unstable", "xc": "xc" }, "locked": { - "lastModified": 1725786353, - "narHash": "sha256-lU8aVTw73HX0lNGPyD8Xnvtnr2VFTXv/S6xCVn6Lg74=", + "lastModified": 1735817715, + "narHash": "sha256-kTP/DLnou3KETZRtvHdeiMmRW6xldgZBAn9O9p9s/MA=", "owner": "a-h", "repo": "templ", - "rev": "e2511cd57e5ecd28ce6e3d944c87f1e31e20b596", + "rev": "e54517eb7d8a7d9ef67d43177709a0ca26235e43", "type": "github" }, "original": { "owner": "a-h", - "ref": "v0.2.778", + "ref": "v0.3.819", "repo": "templ", "type": "github" } }, "xc": { "inputs": { - "flake-utils": "flake-utils_2", + "flake-utils": "flake-utils", "nixpkgs": [ "templ", "nixpkgs" diff --git a/flake.nix b/flake.nix index b29c326..f8629d4 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,7 @@ description = "My development environment"; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - templ.url = "github:a-h/templ?ref=v0.2.778"; + templ.url = "github:a-h/templ?ref=v0.3.819"; }; outputs = { self, @@ -50,6 +50,7 @@ gotools delve (templ system) + gopls # Sqlite tools sqlite diff --git a/go.mod b/go.mod index 71f4655..bbc31a6 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require forge.capytal.company/loreddev/x v0.0.0 replace forge.capytal.company/loreddev/x => ./x require ( - github.com/a-h/templ v0.2.793 + github.com/a-h/templ v0.3.819 github.com/yuin/goldmark v1.7.8 github.com/yuin/goldmark-meta v1.1.0 ) diff --git a/go.sum b/go.sum index 48d0b02..3965a29 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/a-h/templ v0.2.793 h1:Io+/ocnfGWYO4VHdR0zBbf39PQlnzVCVVD+wEEs6/qY= github.com/a-h/templ v0.2.793/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= +github.com/a-h/templ v0.3.819 h1:KDJ5jTFN15FyJnmSmo2gNirIqt7hfvBD2VXVDTySckM= +github.com/a-h/templ v0.3.819/go.mod h1:iDJKJktpttVKdWoTkRNNLcllRI+BlpopJc+8au3gOUo= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= diff --git a/makefile b/makefile index 243caa5..7a9153b 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,5 @@ PORT?=8080 +TEMPL_VERSION=v0.3.819 lint: build/templ go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.1 run @@ -10,13 +11,13 @@ lint/fix: build/templ fmt: build/templ go fmt ./. - go run github.com/a-h/templ/cmd/templ@v0.2.707 fmt . + go run github.com/a-h/templ/cmd/templ@$(TEMPL_VERSION) fmt . go run mvdan.cc/gofumpt@v0.7.0 -l -w . go run github.com/segmentio/golines@v0.12.2 -w . go run golang.org/x/tools/cmd/goimports@v0.26.0 -w -l . dev/templ: - go run github.com/a-h/templ/cmd/templ@v0.2.707 generate --watch \ + go run github.com/a-h/templ/cmd/templ@$(TEMPL_VERSION) generate --watch \ --proxy=http://localhost:$(PORT) \ --proxybind="0.0.0.0" \ --open-browser=false @@ -33,7 +34,7 @@ dev/server: dev/sync_assets: go run github.com/air-verse/air@v1.52.2 \ - --build.cmd "go run github.com/a-h/templ/cmd/templ@v0.2.707 generate --notify-proxy" \ + --build.cmd "go run github.com/a-h/templ/cmd/templ@$(TEMPL_VERSION) generate --notify-proxy" \ --build.bin "true" \ --build.delay "100" \ --build.exclude_dir "" \ @@ -48,7 +49,7 @@ dev: make -j4 dev/templ dev/server dev/sync_assets dev/assets/css build/templ: - go run github.com/a-h/templ/cmd/templ@v0.2.707 generate + go run github.com/a-h/templ/cmd/templ@$(TEMPL_VERSION) generate build/app: go build -o ./.dist/app . From 588f9f48be9d688f16fb49e7be33dc3e8e4bf802 Mon Sep 17 00:00:00 2001 From: "Gustavo L de Mello (Guz)" Date: Fri, 3 Jan 2025 10:26:20 -0300 Subject: [PATCH 13/13] feat(blog): wrap output html in page template --- handlers/pages/blog.templ | 51 ++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/handlers/pages/blog.templ b/handlers/pages/blog.templ index 9c9251f..fda6ae5 100644 --- a/handlers/pages/blog.templ +++ b/handlers/pages/blog.templ @@ -1,6 +1,8 @@ package pages import ( + "bytes" + "io" "encoding/json" "errors" "fmt" @@ -18,15 +20,29 @@ import ( "github.com/yuin/goldmark-meta" ) +type EntryTemplate func(html []byte) templ.Component + type Blog struct { repo string owner string endpoint string - md goldmark.Markdown + md goldmark.Markdown + entryTemplate EntryTemplate } -func NewBlog(owner, repo, endpoint string) *Blog { +type BlogOptions struct { + EntryTemplate EntryTemplate +} + +func NewBlog(owner, repo, endpoint string, opts ...BlogOptions) *Blog { + /* + opt := BlogOptions{} + if len(opts) > 0 { + opt = opts[0] + } + */ + u, err := url.Parse(endpoint) if err != nil { panic(fmt.Sprintf("Blog Forgejo endpoint is not a valid URL: %v", err)) @@ -37,7 +53,14 @@ func NewBlog(owner, repo, endpoint string) *Blog { goldmark.WithParserOptions(parser.WithAutoHeadingID()), ) - return &Blog{repo: repo, owner: owner, endpoint: u.String(), md: md} + return &Blog{ + repo: repo, + owner: owner, + endpoint: u.String(), + md: md, + // entryTemplate: opt.EntryTemplate, + entryTemplate: template, + } } func (p *Blog) Routes() router.Router { @@ -93,14 +116,20 @@ func (p *Blog) blogEntry(w http.ResponseWriter, r *http.Request) { return } - var buf bytes.Buffer - err := p.md.Convert(body, &buf) + buf := bytes.NewBuffer([]byte("")) + err := p.md.Convert(body, buf) if err != nil { rerrors.InternalError(errors.New("failed to render markdown"), err).ServeHTTP(w, r) return } - _, err = buf.WriteTo(w) + html, err := io.ReadAll(buf) + if err != nil { + rerrors.InternalError(errors.New("failed to read markdown html")).ServeHTTP(w, r) + return + } + + err = p.entryTemplate(html).Render(r.Context(), w) if err != nil { rerrors.InternalError(errors.New("failed to write response"), err).ServeHTTP(w, r) return @@ -144,3 +173,13 @@ type forgejoFile struct { LastCommitSha string `json:"last_commit_sha"` Type string `json:"type"` } + +templ template(html []byte) { + @layouts.Page() { +
+
+ @templ.Raw(string(html)) +
+
+ } +}