From 59222160af061b86bc4122f616dc7b65d9a6bb6f Mon Sep 17 00:00:00 2001 From: Elias Kohout Date: Thu, 2 Jan 2025 15:05:20 +0100 Subject: [PATCH] move routes in seperate files; better error handling for enpoint functions --- cmd/frontend/main.go | 88 ++------------------------ internal/routes/Index.go | 42 ++++++++++++ internal/routes/UpSearch.go | 68 ++++++++++++++++++++ internal/viewmodel/ArticleViewModel.go | 4 +- templates/layout.html | 4 +- 5 files changed, 118 insertions(+), 88 deletions(-) create mode 100644 internal/routes/Index.go create mode 100644 internal/routes/UpSearch.go diff --git a/cmd/frontend/main.go b/cmd/frontend/main.go index d2f65af..3514d33 100644 --- a/cmd/frontend/main.go +++ b/cmd/frontend/main.go @@ -1,99 +1,19 @@ package main import ( - "crowsnest/internal/data" - "crowsnest/internal/model" - "crowsnest/internal/viewmodel" - "html/template" + "crowsnest/internal/routes" "net/http" - "regexp" - "strings" ) -type articleDateOrder struct {} -func (ord articleDateOrder) Weight(a *model.Article) int { - return int(a.PublishDate.Unix()) -} - -type articleTermFrequency struct { - terms []string -} -func (ord articleTermFrequency) Weight(a *model.Article) int { - score := 0 - for _, term := range ord.terms { - score += strings.Count(a.Content, term) - } - return score -} - - -func index(w http.ResponseWriter, req *http.Request) { - // retrieve from repo - fds, err := data.NewFileDatastore("./persistence/spiegel100.json") - if err != nil { panic(err) } - repo, err := data.NewDefaultRepository[*model.Article](fds, "article") - if err != nil { panic(err) } - articles, err := repo.GetByCriteria(articleDateOrder{}) - if err != nil { panic(err) } - - // convert to viewmodel - articleVMs := make([]*viewmodel.ArticleViewModel, 0, len(articles)) - for _, a := range articles { - articleVMs = append(articleVMs, viewmodel.NewArticleViewModel(a)) - } - - // render template - t := template.Must(template.ParseFiles("templates/article.html", "templates/layout.html")) - err = t.ExecuteTemplate(w, "base", articleVMs[:10]) - if err != nil { panic(err) } -} - -func search(w http.ResponseWriter, req *http.Request) { - // parse the form data - err := req.ParseForm() - if err != nil { - http.Error(w, "Unable to parse form", http.StatusBadRequest) - return - } - - // collect search terms - p := regexp.MustCompile("\\s+") - searchTerms := make([]string, 0) - for _, elem := range p.Split(req.FormValue("search"), -1) { - elem = strings.TrimSpace(elem) - if elem == "" { continue } - searchTerms = append(searchTerms, elem) - } - - // retrieve from repo - fds, _ := data.NewFileDatastore("./persistence/spiegel100.json") - repo, _ := data.NewDefaultRepository[*model.Article](fds, "article") - var articles []*model.Article - if len(searchTerms) != 0 { - articles, _ = repo.GetByCriteria(articleTermFrequency{ terms: searchTerms }) - } else { - articles, _ = repo.GetAll() - } - - // convert to viewmodel - articleVMs := make([]*viewmodel.ArticleViewModel, 0, len(articles)) - for _, a := range articles { - articleVMs = append(articleVMs, viewmodel.NewArticleViewModel(a)) - } - - t := template.Must(template.ParseFiles("templates/article.html", "templates/layout.html")) - err = t.ExecuteTemplate(w, "base", articleVMs) - if err != nil { panic(err) } -} func main() { // routes - http.HandleFunc("/", index) - http.HandleFunc("/search", search) + http.HandleFunc("GET /", routes.Index) + http.HandleFunc("POST /up/search", routes.UpSearch) // serve files from the "static" directory fs := http.FileServer(http.Dir("./static")) - http.Handle("/static", http.StripPrefix("/", fs)) + http.Handle("GET /static/", http.StripPrefix("/", fs)) // start server http.ListenAndServe(":8080", nil) diff --git a/internal/routes/Index.go b/internal/routes/Index.go new file mode 100644 index 0000000..7b005dc --- /dev/null +++ b/internal/routes/Index.go @@ -0,0 +1,42 @@ +package routes + +import ( + "crowsnest/internal/data" + "crowsnest/internal/model" + "crowsnest/internal/viewmodel" + "html/template" + "net/http" +) + +// sort criteria +type articleDateOrder struct {} +func (ord articleDateOrder) Weight(a *model.Article) int { + return int(a.PublishDate.Unix()) +} + +// List the latest articles using the base template. +func Index(w http.ResponseWriter, req *http.Request) { + // retrieve from repo + fds, err := data.NewFileDatastore("./persistence/spiegel100.json") + if err != nil { http.Error(w, "Failed to load datastore", http.StatusInternalServerError); return; } + repo, err := data.NewDefaultRepository[*model.Article](fds, "article") + if err != nil { http.Error(w, "Failed to create repository", http.StatusInternalServerError); return; } + articles, err := repo.GetByCriteria(articleDateOrder{}) + if err != nil { http.Error(w, "Failed to get articles", http.StatusInternalServerError); return; } + + // truncate + if len(articles) > 10 { + articles = articles[:10] + } + + // convert to viewmodel + articleVMs := make([]*viewmodel.ArticleViewModel, 0, len(articles)) + for _, a := range articles { + articleVMs = append(articleVMs, viewmodel.NewArticleViewModel(a)) + } + + // render template + t := template.Must(template.ParseFiles("templates/article.html", "templates/layout.html")) + err = t.ExecuteTemplate(w, "base", articleVMs) + if err != nil { http.Error(w, "Failed to render template", http.StatusInternalServerError); return; } +} diff --git a/internal/routes/UpSearch.go b/internal/routes/UpSearch.go new file mode 100644 index 0000000..0105216 --- /dev/null +++ b/internal/routes/UpSearch.go @@ -0,0 +1,68 @@ +package routes + +import ( + "crowsnest/internal/data" + "crowsnest/internal/model" + "crowsnest/internal/viewmodel" + "html/template" + "net/http" + "regexp" + "strings" +) + +// sort criteria +type articleTermFrequency struct { + terms []string +} + +func (ord articleTermFrequency) Weight(a *model.Article) int { + score := 0 + for _, term := range ord.terms { + score += strings.Count(a.Content, term) + } + return score +} + +// Enpoint that returns a list of articles given search terms in the post +// request of a search form. Uses the content template. +func UpSearch(w http.ResponseWriter, req *http.Request) { + // parse the form data + err := req.ParseForm() + if err != nil { http.Error(w, "Unable to parse form", http.StatusBadRequest); return; } + + // collect search terms + p := regexp.MustCompile("\\s+") + searchTerms := make([]string, 0) + for _, elem := range p.Split(req.FormValue("search"), -1) { + elem = strings.TrimSpace(elem) + if elem == "" { continue } + searchTerms = append(searchTerms, elem) + } + + // retrieve from repo + fds, _ := data.NewFileDatastore("./persistence/spiegel100.json") + if err != nil { http.Error(w, "Failed to read datastore", http.StatusInternalServerError); return; } + + repo, _ := data.NewDefaultRepository[*model.Article](fds, "article") + if err != nil { http.Error(w, "Failed to create repository", http.StatusInternalServerError); return; } + + var articles []*model.Article + if len(searchTerms) != 0 { + articles, err = repo.GetByCriteria(articleTermFrequency{ terms: searchTerms }) + } else { + Index(w, req) + return + } + if err != nil { http.Error(w, "Failed to get articles from repo", http.StatusInternalServerError); return; } + + // convert to viewmodel + articleVMs := make([]*viewmodel.ArticleViewModel, 0, len(articles)) + for _, a := range articles { + articleVMs = append(articleVMs, viewmodel.NewArticleViewModel(a)) + } + + // render template + t := template.Must(template.ParseFiles("templates/article.html")) + err = t.ExecuteTemplate(w, "content", articleVMs) + if err != nil { http.Error(w, "Failed to render template", http.StatusInternalServerError); return; } +} diff --git a/internal/viewmodel/ArticleViewModel.go b/internal/viewmodel/ArticleViewModel.go index 0753380..eceaa12 100644 --- a/internal/viewmodel/ArticleViewModel.go +++ b/internal/viewmodel/ArticleViewModel.go @@ -13,8 +13,8 @@ type ArticleViewModel struct { func NewArticleViewModel(a *model.Article) *ArticleViewModel { summary := a.Content - if len(a.Content) > 200 { - summary = summary[:200] + if len(a.Content) > 300 { + summary = summary[:300] } return &ArticleViewModel{ diff --git a/templates/layout.html b/templates/layout.html index 4642a41..30cde0d 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -8,8 +8,8 @@