From fbca771479aeac7e87528031958575fed47ad4a6 Mon Sep 17 00:00:00 2001 From: Elias Kohout Date: Thu, 2 Jan 2025 16:21:02 +0100 Subject: [PATCH] restructuring --- {internal/routes => cmd/frontend}/Index.go | 9 +++-- {internal/routes => cmd/frontend}/UpSearch.go | 11 +++--- cmd/frontend/main.go | 19 +++++----- cmd/frontend/routes.go | 19 ++++++++++ internal/model/{Article.go => article.go} | 35 +++++++++++++++---- internal/viewmodel/ArticleViewModel.go | 27 -------------- 6 files changed, 66 insertions(+), 54 deletions(-) rename {internal/routes => cmd/frontend}/Index.go (83%) rename {internal/routes => cmd/frontend}/UpSearch.go (87%) create mode 100644 cmd/frontend/routes.go rename internal/model/{Article.go => article.go} (50%) delete mode 100644 internal/viewmodel/ArticleViewModel.go diff --git a/internal/routes/Index.go b/cmd/frontend/Index.go similarity index 83% rename from internal/routes/Index.go rename to cmd/frontend/Index.go index f1531e2..f34ba18 100644 --- a/internal/routes/Index.go +++ b/cmd/frontend/Index.go @@ -1,9 +1,8 @@ -package routes +package main import ( "crowsnest/internal/data" "crowsnest/internal/model" - "crowsnest/internal/viewmodel" "html/template" "net/http" ) @@ -15,7 +14,7 @@ func (ord articleDateOrder) Weight(a *model.Article) int { } // List the latest articles using the base template. -func Index(w http.ResponseWriter, req *http.Request) { +func (app *App) 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; } @@ -30,9 +29,9 @@ func Index(w http.ResponseWriter, req *http.Request) { } // convert to viewmodel - articleVMs := make([]*viewmodel.ArticleViewModel, 0, len(articles)) + articleVMs := make([]*model.ArticleViewModel, 0, len(articles)) for _, a := range articles { - articleVMs = append(articleVMs, viewmodel.NewArticleViewModel(a)) + articleVMs = append(articleVMs, a.ViewModel()) } // render template diff --git a/internal/routes/UpSearch.go b/cmd/frontend/UpSearch.go similarity index 87% rename from internal/routes/UpSearch.go rename to cmd/frontend/UpSearch.go index 5713dfb..6d2d080 100644 --- a/internal/routes/UpSearch.go +++ b/cmd/frontend/UpSearch.go @@ -1,9 +1,8 @@ -package routes +package main import ( "crowsnest/internal/data" "crowsnest/internal/model" - "crowsnest/internal/viewmodel" "html/template" "net/http" "regexp" @@ -25,7 +24,7 @@ func (ord articleTermFrequency) Weight(a *model.Article) int { // 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) { +func (app *App) 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; } @@ -50,15 +49,15 @@ func UpSearch(w http.ResponseWriter, req *http.Request) { if len(searchTerms) != 0 { articles, err = repo.GetByCriteria(articleTermFrequency{ terms: searchTerms }) } else { - Index(w, req) + app.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)) + articleVMs := make([]*model.ArticleViewModel, 0, len(articles)) for _, a := range articles { - articleVMs = append(articleVMs, viewmodel.NewArticleViewModel(a)) + articleVMs = append(articleVMs, a.ViewModel()) } // render template diff --git a/cmd/frontend/main.go b/cmd/frontend/main.go index 239182d..789d33d 100644 --- a/cmd/frontend/main.go +++ b/cmd/frontend/main.go @@ -1,20 +1,21 @@ package main import ( - "crowsnest/internal/routes" + "log" "net/http" ) +type App struct {} + func main() { - // routes - http.HandleFunc("GET /", routes.Index) - http.HandleFunc("POST /up/search", routes.UpSearch) + app := &App{} - // serve files from the "static" directory - fs := http.FileServer(http.Dir("assets/static")) - http.Handle("GET /static/", http.StripPrefix("/", fs)) + server := http.Server{ + Addr: ":8080", + Handler: app.routes(), + } - // start server - http.ListenAndServe(":8080", nil) + server.ListenAndServe() + log.Println("server started, listening on :8080") } diff --git a/cmd/frontend/routes.go b/cmd/frontend/routes.go new file mode 100644 index 0000000..cadaf49 --- /dev/null +++ b/cmd/frontend/routes.go @@ -0,0 +1,19 @@ +package main + +import ( + "net/http" +) + +func (app *App) routes() http.Handler { + mux := http.NewServeMux() + + // dynamic routes + mux.HandleFunc("GET /", app.Index) + mux.HandleFunc("POST /up/search", app.UpSearch) + + // serve files from the "static" directory + fs := http.FileServer(http.Dir("assets/static")) + mux.Handle("GET /static/", http.StripPrefix("/", fs)) + + return mux +} diff --git a/internal/model/Article.go b/internal/model/article.go similarity index 50% rename from internal/model/Article.go rename to internal/model/article.go index 2ea722a..fcb8dde 100644 --- a/internal/model/Article.go +++ b/internal/model/article.go @@ -6,6 +6,7 @@ import ( "encoding/hex" ) + // TODO docstring type Article struct { SourceUrl string @@ -16,18 +17,38 @@ type Article struct { Author string } +// TODO docstring +type ArticleViewModel struct { + Title string + Author string + PublishDate string + SourceUrl string + Summary string +} -// Generates a hash based on the source url of the article. Can be used to -// identify the article. -func (article *Article) Hash() string { - hash := sha256.Sum256([]byte(article.SourceUrl)) - return hex.EncodeToString(hash[:]) + +// TODO docstring +func (a *Article) ViewModel() *ArticleViewModel { + summary := a.Content + if len(a.Content) > 300 { + summary = summary[:300] + } + + return &ArticleViewModel{ + Title: a.Title, + Author: a.Author, + PublishDate: a.PublishDate.Local().Format("02.01.2006 03:04"), + SourceUrl: a.SourceUrl, + Summary: summary, + } } // --- implement IIdentifiable interface --- -// Using the Identifier attribute as the Id. +// Generates a hash based on the source url of the article. Can be used to +// identify the article. func (article *Article) Id() string { - return article.Hash() + hash := sha256.Sum256([]byte(article.SourceUrl)) + return hex.EncodeToString(hash[:]) } diff --git a/internal/viewmodel/ArticleViewModel.go b/internal/viewmodel/ArticleViewModel.go deleted file mode 100644 index eceaa12..0000000 --- a/internal/viewmodel/ArticleViewModel.go +++ /dev/null @@ -1,27 +0,0 @@ -package viewmodel - -import "crowsnest/internal/model" - - -type ArticleViewModel struct { - Title string - Author string - PublishDate string - SourceUrl string - Summary string -} - -func NewArticleViewModel(a *model.Article) *ArticleViewModel { - summary := a.Content - if len(a.Content) > 300 { - summary = summary[:300] - } - - return &ArticleViewModel{ - Title: a.Title, - Author: a.Author, - PublishDate: a.PublishDate.Local().Format("02.01.2006 03:04"), - SourceUrl: a.SourceUrl, - Summary: summary, - } -}