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("web/templates/article.html")) err = t.ExecuteTemplate(w, "content", articleVMs) if err != nil { http.Error(w, "Failed to render template", http.StatusInternalServerError); return; } }