package main
import (
"bytes"
"html/template"
"net/http"
"strings"
"git.neuromancer.ovh/bastien-mrq/gitfed/internal/i18n"
"git.neuromancer.ovh/bastien-mrq/gitfed/internal/store"
)
var searchTpl = newTpl("search", `
<h1>{{t .Lang "search.title"}}{{if .Query}}: "{{.Query}}"{{end}}</h1>
<form action="/search" method="get" style="max-width:420px;">
<input type="search" name="q" value="{{.Query}}" placeholder="{{t .Lang "nav.search_placeholder"}}" autofocus>
</form>
<table>
<tr><th>{{t .Lang "explore.col_repo"}}</th><th>{{t .Lang "explore.col_owner"}}</th><th>{{t .Lang "explore.col_topics"}}</th></tr>
{{range .Results}}
<tr>
<td><a href="/r/{{.Name}}">{{.Name}}</a>{{if .Description}}<div class="muted" style="font-size:0.82rem;">{{.Description}}</div>{{end}}</td>
<td class="muted">{{.Owner}}</td>
<td>{{range .Topics}}<span class="badge plain">{{.}}</span>{{end}}</td>
</tr>
{{else}}
<tr><td colspan="3" class="muted">{{if .Query}}{{t .Lang "search.no_matches"}}{{else}}{{t .Lang "search.prompt"}}{{end}}</td></tr>
{{end}}
</table>
`)
// searchVisible reports whether repo should be considered for search
// results for the given (possibly anonymous) session: same visibility rule
// as everywhere else — public repos to anyone, private ones only to an
// owner/collaborator.
func (s *server) searchVisible(r *http.Request, repo store.Repo) bool {
return s.canView(r, repo)
}
func (s *server) handleSearch(w http.ResponseWriter, r *http.Request) {
q := strings.TrimSpace(r.URL.Query().Get("q"))
lang := s.lang(r)
var results []store.Repo
if q != "" {
all, err := s.ops.ListRepos()
if err != nil {
s.serverError(w, r, err)
return
}
needle := strings.ToLower(q)
for _, repo := range all {
if !s.searchVisible(r, repo) {
continue
}
if matchesSearch(repo, needle) {
results = append(results, repo)
}
}
}
var buf bytes.Buffer
_ = searchTpl.Execute(&buf, struct {
Query, Lang string
Results []store.Repo
}{q, string(lang), results})
s.render(w, r, i18n.T(lang, "search.title"), "", template.HTML(buf.String()))
}
func matchesSearch(repo store.Repo, lowerNeedle string) bool {
if strings.Contains(strings.ToLower(repo.Name), lowerNeedle) {
return true
}
if strings.Contains(strings.ToLower(repo.Description), lowerNeedle) {
return true
}
for _, t := range repo.Topics {
if strings.Contains(strings.ToLower(t), lowerNeedle) {
return true
}
}
return false
}