From 1b99eaa016e449a0104bd328dfae2e35aab5b8e0 Mon Sep 17 00:00:00 2001 From: Niko Abeler Date: Sat, 13 Aug 2022 15:32:26 +0200 Subject: [PATCH] WIP RSS renderer. #3 --- cmd/owl-web/handler.go | 20 +++++++ cmd/owl-web/main.go | 2 + .../{repo_base.html => repo/base.html} | 0 embed/initial/repo/config.yml | 1 + repository.go | 35 ++++++++++- rss.go | 60 +++++++++++++++++++ rss_test.go | 49 +++++++++++++++ 7 files changed, 164 insertions(+), 3 deletions(-) rename embed/initial/{repo_base.html => repo/base.html} (100%) create mode 100644 embed/initial/repo/config.yml create mode 100644 rss.go create mode 100644 rss_test.go diff --git a/cmd/owl-web/handler.go b/cmd/owl-web/handler.go index a446401..58e5566 100644 --- a/cmd/owl-web/handler.go +++ b/cmd/owl-web/handler.go @@ -56,6 +56,26 @@ func userIndexHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Requ } } +func userRSSHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Request, httprouter.Params) { + return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + user, err := getUserFromRepo(repo, ps) + if err != nil { + println("Error getting user: ", err.Error()) + notFoundHandler(repo)(w, r) + return + } + html, err := owl.RenderRSSFeed(user) + if err != nil { + println("Error rendering index page: ", err.Error()) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte("Internal server error")) + return + } + println("Rendering index page for user", user.Name()) + w.Write([]byte(html)) + } +} + func postHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Request, httprouter.Params) { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { postId := ps.ByName("post") diff --git a/cmd/owl-web/main.go b/cmd/owl-web/main.go index aee9828..a14970c 100644 --- a/cmd/owl-web/main.go +++ b/cmd/owl-web/main.go @@ -14,6 +14,7 @@ func Router(repo *owl.Repository) http.Handler { router.ServeFiles("/static/*filepath", http.Dir(repo.StaticDir())) router.GET("/", repoIndexHandler(repo)) router.GET("/user/:user/", userIndexHandler(repo)) + router.GET("/user/:user/index.xml", userRSSHandler(repo)) router.GET("/user/:user/posts/:post/", postHandler(repo)) router.GET("/user/:user/posts/:post/media/*filepath", postMediaHandler(repo)) router.NotFound = http.HandlerFunc(notFoundHandler(repo)) @@ -24,6 +25,7 @@ func SingleUserRouter(repo *owl.Repository) http.Handler { router := httprouter.New() router.ServeFiles("/static/*filepath", http.Dir(repo.StaticDir())) router.GET("/", userIndexHandler(repo)) + router.GET("/index.xml", userRSSHandler(repo)) router.GET("/posts/:post/", postHandler(repo)) router.GET("/posts/:post/media/*filepath", postMediaHandler(repo)) return router diff --git a/embed/initial/repo_base.html b/embed/initial/repo/base.html similarity index 100% rename from embed/initial/repo_base.html rename to embed/initial/repo/base.html diff --git a/embed/initial/repo/config.yml b/embed/initial/repo/config.yml new file mode 100644 index 0000000..78122e0 --- /dev/null +++ b/embed/initial/repo/config.yml @@ -0,0 +1 @@ +domain: "http://localhost:8080" \ No newline at end of file diff --git a/repository.go b/repository.go index e4fae33..529af30 100644 --- a/repository.go +++ b/repository.go @@ -25,6 +25,10 @@ type Repository struct { active_user string } +type RepoConfig struct { + Domain string `yaml:"domain"` +} + func CreateRepository(name string) (Repository, error) { newRepo := Repository{name: name} // check if repository already exists @@ -46,9 +50,15 @@ func CreateRepository(name string) (Repository, error) { os.WriteFile(newRepo.StaticDir()+"/"+file.Name(), src_data, 0644) } - // copy repo_base.html to base.html - src_data, _ := static_files.ReadFile("embed/initial/repo_base.html") - os.WriteFile(newRepo.Dir()+"/base.html", src_data, 0644) + // copy repo/ to newRepo.Dir() + init_files, _ := static_files.ReadDir("embed/initial/repo") + for _, file := range init_files { + if file.IsDir() { + continue + } + src_data, _ := static_files.ReadFile("embed/initial/repo/" + file.Name()) + os.WriteFile(newRepo.Dir()+"/"+file.Name(), src_data, 0644) + } return newRepo, nil } @@ -103,6 +113,11 @@ func (repo Repository) UserUrlPath(user User) string { return "/user/" + user.name + "/" } +func (repo Repository) FullUserUrl(user User) string { + config, _ := repo.Config() + return config.Domain + repo.UserUrlPath(user) +} + func (repo Repository) Template() (string, error) { // load base.html path := path.Join(repo.Dir(), "base.html") @@ -179,3 +194,17 @@ func (repo Repository) PostAliases() (map[string]*Post, error) { } return aliases, nil } + +func (repo Repository) Config() (RepoConfig, error) { + config_path := path.Join(repo.Dir(), "config.yml") + config_data, err := ioutil.ReadFile(config_path) + if err != nil { + return RepoConfig{}, err + } + var meta RepoConfig + err = yaml.Unmarshal(config_data, &meta) + if err != nil { + return RepoConfig{}, err + } + return meta, nil +} diff --git a/rss.go b/rss.go new file mode 100644 index 0000000..948dbf5 --- /dev/null +++ b/rss.go @@ -0,0 +1,60 @@ +package owl + +import ( + "bytes" + "encoding/xml" +) + +type RSS struct { + XMLName xml.Name `xml:"rss"` + Version string `xml:"version,attr"` + Channel RSSChannel `xml:"channel"` +} + +type RSSChannel struct { + Title string `xml:"title"` + Link string `xml:"link"` + Description string `xml:"description"` + Items []RSSItem `xml:"item"` +} + +type RSSItem struct { + Title string `xml:"title"` + Link string `xml:"link"` + Description string `xml:"description"` + PubDate string `xml:"pubDate"` +} + +func RenderRSSFeed(user User) (string, error) { + + config, _ := user.Config() + + rss := RSS{ + Version: "2.0", + Channel: RSSChannel{ + Title: config.Title, + Link: user.repo.FullUserUrl(user), + Description: config.SubTitle, + Items: make([]RSSItem, 0), + }, + } + + // posts, _ := user.Posts() + // for _, post := range posts { + // rss.Channel.Items = append(rss.Channel.Items, RSSItem{ + // Title: post.Title(), + // Link: post.Link(), + // Description: post.Description(), + // PubDate: post.PubDate(), + // }) + // } + + buf := new(bytes.Buffer) + err := xml.NewEncoder(buf).Encode(rss) + if err != nil { + return "", err + } + + return xml.Header + buf.String(), nil + +} diff --git a/rss_test.go b/rss_test.go new file mode 100644 index 0000000..b273288 --- /dev/null +++ b/rss_test.go @@ -0,0 +1,49 @@ +package owl_test + +import ( + "h4kor/owl-blogs" + "strings" + "testing" +) + +func TestRenderRSSFeedMeta(t *testing.T) { + user := getTestUser() + user.SetConfig(owl.UserConfig{ + Title: "Test Title", + SubTitle: "Test SubTitle", + }) + res, err := owl.RenderRSSFeed(user) + if err != nil { + t.Error("Error rendering RSS feed: " + err.Error()) + return + } + if !strings.Contains(res, "") { + t.Error("xml version not rendered. Got: " + res) + } + if !strings.Contains(res, "") { + t.Error("rss version not rendered. Got: " + res) + } + +} + +func TestRenderRSSFeedUserData(t *testing.T) { + user := getTestUser() + user.SetConfig(owl.UserConfig{ + Title: "Test Title", + SubTitle: "Test SubTitle", + }) + res, err := owl.RenderRSSFeed(user) + if err != nil { + t.Error("Error rendering RSS feed: " + err.Error()) + return + } + if !strings.Contains(res, "Test Title") { + t.Error("Title not rendered. Got: " + res) + } + if !strings.Contains(res, "Test SubTitle") { + t.Error("SubTitle not rendered. Got: " + res) + } + if !strings.Contains(res, "http://localhost:8080/user/") { + t.Error("SubTitle not rendered. Got: " + res) + } +}