From d6d00f6dc9d8720b33cfaa5262039ed97575822b Mon Sep 17 00:00:00 2001 From: Travis Shears Date: Sat, 18 Oct 2025 21:17:34 +0200 Subject: [PATCH] add page for single micro-blog posts ", p.ID, p.Source, p.ID)) posted: %s ", p.Timestamp.Format("2006-01-02 15:04"))) ") ", post.Title)) ", ") --- ") ") ") ", post.Title)) ") ") --- internal/microblog/microblog.go | 70 +++++++++++++++++++++------------ internal/pocketbase/pb.go | 30 ++++++++++++++ tasks.txt | 1 + 3 files changed, 76 insertions(+), 25 deletions(-) diff --git a/internal/microblog/microblog.go b/internal/microblog/microblog.go index b8e442e..1e41276 100644 --- a/internal/microblog/microblog.go +++ b/internal/microblog/microblog.go @@ -162,6 +162,30 @@ func transformMastodonPost(p pbPost) post { } } +// GetRecentPosts returns the most recent posts +func (mb *MicroBlog) GetPost(id string) (post, error) { + res, err := mb.pbClient.GetRecord("micro_blog_posts", id) + if err != nil { + return post{}, fmt.Errorf("failed to fetch post from pocketbase: %w", err) + } + + var remotePost pbPost + if err := json.Unmarshal(*res, &remotePost); err != nil { + return post{}, fmt.Errorf("failed to decode response: %w", err) + } + slog.Info("post from pocketbase", "remotePost", remotePost) + switch remotePost.Source { + case SourceMastodon: + return transformMastodonPost(remotePost), nil + case SourceNostr: + return transformNostrPost(remotePost), nil + case SourceBlueSky: + return transformBlueSkyPost(remotePost), nil + } + return post{}, + fmt.Errorf("Don't know how to transform a post with that source") +} + // GetRecentPosts returns the most recent posts func (mb *MicroBlog) GetRecentPosts(limit int, page int) ([]post, error) { res, err := mb.pbClient.GetList("micro_blog_posts", page, limit, "-posted") @@ -173,7 +197,7 @@ func (mb *MicroBlog) GetRecentPosts(limit int, page int) ([]post, error) { if err := json.Unmarshal(res.Items, &rawPosts); err != nil { return nil, fmt.Errorf("failed to decode response: %w", err) } - slog.Info("Posts from pocketbase", "rawPosts", rawPosts) + slog.Info("Posts from pocketbase", "count", len(rawPosts)) var filteredPosts []post for _, p := range rawPosts { @@ -221,16 +245,16 @@ func (mb *MicroBlog) HandleBlogRequest(w gemini.ResponseWriter, req *gemini.Requ return } mb.serveIndex(w, req, num) - // case strings.HasPrefix(path, "/microblog/post/"): - // postID := strings.TrimPrefix(path, "/microblog/post/") - // mb.servePost(w, req, postID) + case strings.HasPrefix(path, "/microblog/post/"): + postID := strings.TrimPrefix(path, "/microblog/post/") + mb.servePost(w, req, postID) default: w.WriteStatusMsg(gemini.StatusNotFound, "Page not found") } } func drawPost(builder *strings.Builder, p post) { - builder.WriteString(fmt.Sprintf("=> / 🖋️ %s post: %s \n", p.Source, p.ID)) + builder.WriteString(fmt.Sprintf("=> /microblog/post/%s 🖋️ %s post: %s \n", p.ID, p.Source, p.ID)) builder.WriteString(formatContent(p.Content)) builder.WriteString(fmt.Sprintf("\nposted: %s\n", p.Timestamp.Format("2006-01-02 15:04"))) builder.WriteString("\n\n") @@ -274,26 +298,22 @@ func (mb *MicroBlog) serveIndex(w gemini.ResponseWriter, req *gemini.Request, pa w.WriteBody([]byte(content.String())) } -// servePost serves a single blog post -// func (mb *MicroBlog) servePost(w gemini.ResponseWriter, req *gemini.Request, postID string) { -// post, found := mb.GetPost(postID) -// if !found { -// w.WriteStatusMsg(gemini.StatusNotFound, "Post not found") -// return -// } +// // servePost serves a single blog post +func (mb *MicroBlog) servePost(w gemini.ResponseWriter, req *gemini.Request, postID string) { + post, err := mb.GetPost(postID) + if err != nil { + slog.Error("Problem getting post", "error", err) + w.WriteStatusMsg(gemini.StatusNotFound, "Problem getting post") + return + } -// w.WriteStatusMsg(gemini.StatusSuccess, "text/gemini") + w.WriteStatusMsg(gemini.StatusSuccess, "text/gemini") -// var content strings.Builder -// content.WriteString(fmt.Sprintf("# %s\n\n", post.Title)) -// content.WriteString(fmt.Sprintf("By %s on %s\n\n", -// post.Author, -// post.Timestamp.Format("2006-01-02 15:04"))) -// content.WriteString("---\n\n") -// content.WriteString(post.Content) -// content.WriteString("\n\n---\n\n") -// content.WriteString("=> /blog Back to blog\n") -// content.WriteString("=> / Back to home\n") + var content strings.Builder + // content.WriteString(fmt.Sprintf("# %s\n\n", post.Title)) + drawPost(&content, post) + content.WriteString("=> /microblog Back to posts\n") + content.WriteString("=> / Back to home\n") -// w.WriteBody([]byte(content.String())) -// } + w.WriteBody([]byte(content.String())) +} diff --git a/internal/pocketbase/pb.go b/internal/pocketbase/pb.go index 2967112..7f583da 100644 --- a/internal/pocketbase/pb.go +++ b/internal/pocketbase/pb.go @@ -195,3 +195,33 @@ func (c *PocketBaseClient) GetList( } return &res, nil } + +func (c *PocketBaseClient) GetRecord( + collection string, + id string, +) (*[]byte, error) { + slog.Info( + "Getting single record from pocketbase", + "recordId", id) + apiURL := fmt.Sprintf("%s/api/collections/%s/records/%s", c.host, collection, id) + resp, err := c.makeAuthenticatedRequest("GET", apiURL, nil) + if err != nil { + return nil, fmt.Errorf("failed to make request: %w", err) + } + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body)) + } + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response body: %w", err) + } + defer resp.Body.Close() + + var res pbRes + if err := json.Unmarshal(body, &res); err != nil { + return nil, fmt.Errorf("failed to decode response: %w", err) + } + return &body, nil + +} diff --git a/tasks.txt b/tasks.txt index a392848..2357f59 100644 --- a/tasks.txt +++ b/tasks.txt @@ -1,4 +1,5 @@ -----------DONE LINE----------- +DONE task: make page for single micro blog posts DONE task: rework the micro-blog to be more like station DONE task: add mastodon and bluysky to microblog DONE task: implement dir codeview pages