From 20a12c6299bfad76df98f02d1e16da34d3416287 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Tue, 29 Oct 2024 16:36:40 +0100 Subject: [PATCH 1/5] Implement banner images in a more standard way --- cmd/backend/images.go | 18 ---------------- cmd/frontend/articles.go | 33 ++++++++++------------------ cmd/frontend/images.go | 36 +++++++++++++++++++------------ cmd/main.go | 1 + web/templates/editor.html | 13 +++++------ web/templates/review-article.html | 2 +- 6 files changed, 40 insertions(+), 63 deletions(-) diff --git a/cmd/backend/images.go b/cmd/backend/images.go index 88c0609..6a2619c 100644 --- a/cmd/backend/images.go +++ b/cmd/backend/images.go @@ -1,7 +1,6 @@ package backend import ( - "encoding/base64" "fmt" "image" "io" @@ -43,20 +42,3 @@ func SaveImage(src io.Reader, maxHeight, maxWidth int, path string) (string, err return filename, nil } - -func ServeBase64Image(c *Config, filename string) (string, error) { - file := c.PicsDir + "/" + filename - - img, err := os.Open(file) - if err != nil { - return "", fmt.Errorf("error opening file %v: %v", file, err) - } - defer img.Close() - - imgBytes, err := io.ReadAll(img) - if err != nil { - return "", fmt.Errorf("error turning %v into bytes: %v", file, err) - } - - return base64.StdEncoding.EncodeToString(imgBytes), nil -} diff --git a/cmd/frontend/articles.go b/cmd/frontend/articles.go index 864bfd6..9b73385 100644 --- a/cmd/frontend/articles.go +++ b/cmd/frontend/articles.go @@ -80,7 +80,7 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { article := &b.Article{ Title: r.PostFormValue("article-title"), - BannerLink: r.PostFormValue("article-banner-url"), + BannerLink: c.Domain + "/image/serve/" + r.PostFormValue("article-banner-url"), Summary: r.PostFormValue("article-summary"), Published: false, Rejected: false, @@ -181,6 +181,12 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return } + bannerLink := c.Domain + "/image/serve/" + r.PostFormValue("article-banner-url") + if len(bannerLink) == 0 { + http.Error(w, "Bitte ein Titelbild einfügen.", http.StatusBadRequest) + return + } + summary := r.PostFormValue("article-summary") if len(summary) == 0 { http.Error(w, "Bitte die Beschreibung eingeben.", http.StatusBadRequest) @@ -202,6 +208,7 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { if err = db.UpdateAttributes( &b.Attribute{Table: "articles", ID: id, AttName: "title", Value: title}, + &b.Attribute{Table: "articles", ID: id, AttName: "banner_link", Value: bannerLink}, &b.Attribute{Table: "articles", ID: id, AttName: "summary", Value: summary}, &b.Attribute{Table: "articles", ID: id, AttName: "rejected", Value: false}, &b.Attribute{Table: "articles", ID: id, AttName: "is_in_issue", Value: r.PostFormValue("issue") == "on"}, @@ -347,13 +354,7 @@ func ReviewRejectedArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.Handler } imgURL := strings.Split(data.Article.BannerLink, "/") - imgFileName := imgURL[len(imgURL)-1] - data.BannerImage, err = b.ServeBase64Image(c, imgFileName) - if err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + data.BannerImage = imgURL[len(imgURL)-1] articleAbsName := fmt.Sprint(c.ArticleDir, "/", data.Article.ID, ".md") content, err := os.ReadFile(articleAbsName) @@ -624,13 +625,7 @@ func ReviewArticle(c *b.Config, db *b.DB, s *b.CookieStore, action, title, butto } imgURL := strings.Split(article.BannerLink, "/") - imgFileName := imgURL[len(imgURL)-1] - data.BannerImage, err = b.ServeBase64Image(c, imgFileName) - if err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + data.BannerImage = imgURL[len(imgURL)-1] data.Article.Summary, err = b.ConvertToPlain(article.Summary) if err != nil { @@ -807,13 +802,7 @@ func EditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { } imgURL := strings.Split(data.Article.BannerLink, "/") - imgFileName := imgURL[len(imgURL)-1] - data.BannerImage, err = b.ServeBase64Image(c, imgFileName) - if err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + data.BannerImage = imgURL[len(imgURL)-1] content, err := os.ReadFile(fmt.Sprint(c.ArticleDir, "/", data.Article.ID, ".md")) if err != nil { diff --git a/cmd/frontend/images.go b/cmd/frontend/images.go index 921c768..a6424b8 100644 --- a/cmd/frontend/images.go +++ b/cmd/frontend/images.go @@ -5,6 +5,7 @@ import ( "html/template" "log" "net/http" + "path/filepath" b "streifling.com/jason/cpolis/cmd/backend" ) @@ -69,20 +70,8 @@ func UploadBanner(c *b.Config, s *b.CookieStore, fileKey, htmlFile, htmlTemplate return } - base64Img, err := b.ServeBase64Image(c, filename) - if err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - data := new(struct { - BannerImage string - URL string - }) - - data.BannerImage = base64Img - data.URL = c.Domain + "/image/serve/" + filename + data := new(struct{ BannerImage string }) + data.BannerImage = filename tmpl, err := template.ParseFiles(c.WebDir + "/templates/" + htmlFile) if err = template.Must(tmpl, err).ExecuteTemplate(w, htmlTemplate, data); err != nil { @@ -92,3 +81,22 @@ func UploadBanner(c *b.Config, s *b.CookieStore, fileKey, htmlFile, htmlTemplate } } } + +func ServeImage(c *b.Config, s *b.CookieStore) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if _, err := getSession(w, r, c, s); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + absFilepath, err := filepath.Abs(c.PicsDir) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + http.ServeFile(w, r, absFilepath+"/"+r.PathValue("img")) + } +} diff --git a/cmd/main.go b/cmd/main.go index 9950445..4f9f697 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -68,6 +68,7 @@ func main() { mux.HandleFunc("GET /article/write", f.WriteArticle(config, db, store)) mux.HandleFunc("GET /atom/serve", c.ServeAtomFeed(config)) mux.HandleFunc("GET /hub", f.ShowHub(config, db, store)) + mux.HandleFunc("GET /image/{img}", f.ServeImage(config, store)) mux.HandleFunc("GET /image/serve/{pic}", c.ServeImage(config)) mux.HandleFunc("GET /issue/this", f.ShowCurrentIssue(config, db, store)) mux.HandleFunc("GET /logout", f.Logout(config, store)) diff --git a/web/templates/editor.html b/web/templates/editor.html index 5d27fa0..5ee79c3 100644 --- a/web/templates/editor.html +++ b/web/templates/editor.html @@ -3,10 +3,7 @@
-
- Banner Image - -
+ {{template "article-banner-template" .}}
@@ -17,7 +14,7 @@
+ hx-post="/article/upload-banner" hx-swap="outerHTML" hx-target="#article-banner-container" />
@@ -92,8 +89,8 @@ {{end}} {{define "article-banner-template"}} -
- Banner Image - +
+ Banner Image +
{{end}} diff --git a/web/templates/review-article.html b/web/templates/review-article.html index ee57a5a..c04b65b 100644 --- a/web/templates/review-article.html +++ b/web/templates/review-article.html @@ -3,7 +3,7 @@
- Banner Image + Banner Image
Titel From 083718711d50525d3ad04592efa4594bcfd9d67b Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Tue, 29 Oct 2024 16:37:41 +0100 Subject: [PATCH 2/5] Use empty alt tag for banner image --- web/templates/editor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/templates/editor.html b/web/templates/editor.html index 5ee79c3..7860dba 100644 --- a/web/templates/editor.html +++ b/web/templates/editor.html @@ -90,7 +90,7 @@ {{define "article-banner-template"}}
- Banner Image +
{{end}} From e95871ee7008ed7b1f147ef11378b5ce1a917310 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Tue, 29 Oct 2024 16:43:42 +0100 Subject: [PATCH 3/5] Fix bug that allowed empty banner images --- cmd/frontend/articles.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd/frontend/articles.go b/cmd/frontend/articles.go index 9b73385..806c7ae 100644 --- a/cmd/frontend/articles.go +++ b/cmd/frontend/articles.go @@ -80,7 +80,7 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { article := &b.Article{ Title: r.PostFormValue("article-title"), - BannerLink: c.Domain + "/image/serve/" + r.PostFormValue("article-banner-url"), + BannerLink: r.PostFormValue("article-banner-url"), Summary: r.PostFormValue("article-summary"), Published: false, Rejected: false, @@ -93,10 +93,13 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { http.Error(w, "Bitte den Titel eingeben.", http.StatusBadRequest) return } + if len(article.BannerLink) == 0 { http.Error(w, "Bitte ein Titelbild einfügen.", http.StatusBadRequest) return } + article.BannerLink = c.Domain + "/image/serve/" + article.BannerLink + if len(article.Summary) == 0 { http.Error(w, "Bitte die Beschreibung eingeben.", http.StatusBadRequest) return @@ -181,11 +184,12 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return } - bannerLink := c.Domain + "/image/serve/" + r.PostFormValue("article-banner-url") + bannerLink := r.PostFormValue("article-banner-url") if len(bannerLink) == 0 { http.Error(w, "Bitte ein Titelbild einfügen.", http.StatusBadRequest) return } + bannerLink = c.Domain + "/image/serve/" + bannerLink summary := r.PostFormValue("article-summary") if len(summary) == 0 { From 0dd2101a08569a2ca2f7ff274e5f472c59fd649b Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Tue, 29 Oct 2024 17:00:51 +0100 Subject: [PATCH 4/5] Cleanup --- cmd/backend/atom.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/backend/atom.go b/cmd/backend/atom.go index c3953f6..f969f32 100644 --- a/cmd/backend/atom.go +++ b/cmd/backend/atom.go @@ -8,8 +8,6 @@ import ( "git.streifling.com/jason/atom" ) -type Feed struct{ *atom.Feed } - func GenerateAtomFeed(c *Config, db *DB) (*string, error) { feed := atom.NewFeed(c.Title) feed.ID = atom.NewID("urn:feed:1") From 1fbc0ddcf6662864fa57d60d3c805abfd0d69d8c Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Wed, 30 Oct 2024 02:12:53 +0100 Subject: [PATCH 5/5] Make banner link and summary optional --- cmd/backend/atom.go | 30 +++++++++++++++++------------- cmd/frontend/articles.go | 23 +++-------------------- cmd/frontend/issues.go | 4 ---- 3 files changed, 20 insertions(+), 37 deletions(-) diff --git a/cmd/backend/atom.go b/cmd/backend/atom.go index f969f32..8ce4fe0 100644 --- a/cmd/backend/atom.go +++ b/cmd/backend/atom.go @@ -30,12 +30,25 @@ func GenerateAtomFeed(c *Config, db *DB) (*string, error) { } entry := atom.NewEntry(articleTitle) entry.ID = atom.NewID(fmt.Sprint("urn:entry:", article.ID)) - entry.Content = atom.NewContent(atom.OutOfLine, "text/hmtl", article.ContentLink) entry.Published = atom.NewDate(article.Created) - linkID := entry.AddLink(atom.NewLink(article.BannerLink)) - entry.Links[linkID].Rel = "enclosure" - entry.Links[linkID].Type = "image/webp" + if article.AutoGenerated { + entry.Content = atom.NewContent(atom.InlineText, "text", "") + } else { + entry.Content = atom.NewContent(atom.OutOfLine, "text/hmtl", article.ContentLink) + + articleSummary, err := ConvertToPlain(article.Summary) + if err != nil { + return nil, fmt.Errorf("error converting description to plain text for Atom feed: %v", err) + } + entry.Summary = atom.NewText("text", articleSummary) + } + + if len(article.BannerLink) > 0 { + linkID := entry.AddLink(atom.NewLink(article.BannerLink)) + entry.Links[linkID].Rel = "enclosure" + entry.Links[linkID].Type = "image/webp" + } user, err := db.GetUser(c, article.AuthorID) if err != nil { @@ -43,15 +56,6 @@ func GenerateAtomFeed(c *Config, db *DB) (*string, error) { } entry.AddAuthor(atom.NewPerson(user.FirstName + " " + user.LastName)) - articleSummary, err := ConvertToPlain(article.Summary) - if err != nil { - return nil, fmt.Errorf("error converting description to plain text for Atom feed: %v", err) - } - if article.AutoGenerated { - articleSummary = "auto generated" - } - entry.Summary = atom.NewText("text", articleSummary) - tags, err := db.GetArticleTags(article.ID) if err != nil { return nil, fmt.Errorf("error getting tags for articles for Atom feed: %v", err) diff --git a/cmd/frontend/articles.go b/cmd/frontend/articles.go index 806c7ae..816480d 100644 --- a/cmd/frontend/articles.go +++ b/cmd/frontend/articles.go @@ -80,7 +80,7 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { article := &b.Article{ Title: r.PostFormValue("article-title"), - BannerLink: r.PostFormValue("article-banner-url"), + BannerLink: c.Domain + "/image/serve/" + r.PostFormValue("article-banner-url"), Summary: r.PostFormValue("article-summary"), Published: false, Rejected: false, @@ -94,17 +94,6 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { return } - if len(article.BannerLink) == 0 { - http.Error(w, "Bitte ein Titelbild einfügen.", http.StatusBadRequest) - return - } - article.BannerLink = c.Domain + "/image/serve/" + article.BannerLink - - if len(article.Summary) == 0 { - http.Error(w, "Bitte die Beschreibung eingeben.", http.StatusBadRequest) - return - } - article.ID, err = db.AddArticle(article) if err != nil { log.Println(err) @@ -185,17 +174,11 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { } bannerLink := r.PostFormValue("article-banner-url") - if len(bannerLink) == 0 { - http.Error(w, "Bitte ein Titelbild einfügen.", http.StatusBadRequest) - return + if len(bannerLink) != 0 { + bannerLink = c.Domain + "/image/serve/" + bannerLink } - bannerLink = c.Domain + "/image/serve/" + bannerLink summary := r.PostFormValue("article-summary") - if len(summary) == 0 { - http.Error(w, "Bitte die Beschreibung eingeben.", http.StatusBadRequest) - return - } content := r.PostFormValue("article-content") if len(content) == 0 { diff --git a/cmd/frontend/issues.go b/cmd/frontend/issues.go index 4aefb63..d290681 100644 --- a/cmd/frontend/issues.go +++ b/cmd/frontend/issues.go @@ -41,10 +41,6 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun http.Error(w, "Bitte den Titel eingeben.", http.StatusBadRequest) return } - if len(article.BannerLink) == 0 { - http.Error(w, "Bitte ein Titelbild einfügen.", http.StatusBadRequest) - return - } article.ID, err = db.AddArticle(article) if err != nil {