add search by site:<domain> functionality

pull/5/head
cblgh 2021-10-20 18:55:37 +02:00 zatwierdzone przez Alexander Cobleigh
rodzic bd03b61420
commit e28cdccb7c
3 zmienionych plików z 40 dodań i 6 usunięć

Wyświetl plik

@ -95,6 +95,11 @@ func SearchWordsByScore(db *sql.DB, words []string) []types.PageData {
return searchWords(db, words, true) return searchWords(db, words, true)
} }
func SearchWordsBySite(db *sql.DB, words []string, domain string) []types.PageData {
// search words by site is same as search words by score, but adds a domain condition
return searchWords(db, words, true, domain)
}
func SearchWordsByCount(db *sql.DB, words []string) []types.PageData { func SearchWordsByCount(db *sql.DB, words []string) []types.PageData {
return searchWords(db, words, false) return searchWords(db, words, false)
} }
@ -190,7 +195,7 @@ func countQuery(db *sql.DB, table string) int {
return count return count
} }
func searchWords(db *sql.DB, words []string, searchByScore bool) []types.PageData { func searchWords(db *sql.DB, words []string, searchByScore bool, domain ...string) []types.PageData {
var wordlist []string var wordlist []string
var args []interface{} var args []interface{}
for _, word := range words { for _, word := range words {
@ -198,6 +203,16 @@ func searchWords(db *sql.DB, words []string, searchByScore bool) []types.PageDat
args = append(args, strings.ToLower(word)) args = append(args, strings.ToLower(word))
} }
// the domains conditional defaults to just 'true' i.e. no domain condition
domains := []string{"1"}
if len(domain) > 0 && domain[0] != "" {
domains = make([]string, 0) // we've got at least one domain! clear domains default
for _, d := range domain {
domains = append(domains, "domain = ?")
args = append(args, d)
}
}
orderType := "SUM(score)" orderType := "SUM(score)"
if !searchByScore { if !searchByScore {
orderType = "COUNT(*)" orderType = "COUNT(*)"
@ -206,12 +221,13 @@ func searchWords(db *sql.DB, words []string, searchByScore bool) []types.PageDat
query := fmt.Sprintf(` query := fmt.Sprintf(`
SELECT p.url, p.about, p.title SELECT p.url, p.about, p.title
FROM inv_index inv INNER JOIN pages p ON inv.url = p.url FROM inv_index inv INNER JOIN pages p ON inv.url = p.url
WHERE %s WHERE (%s)
AND (%s)
GROUP BY inv.url GROUP BY inv.url
ORDER BY %s ORDER BY %s
DESC DESC
LIMIT 15 LIMIT 15
`, strings.Join(wordlist, " OR "), orderType) `, strings.Join(wordlist, " OR "), strings.Join(domains, " OR "), orderType)
stmt, err := db.Prepare(query) stmt, err := db.Prepare(query)
util.Check(err) util.Check(err)

Wyświetl plik

@ -1,11 +1,14 @@
{{ template "head" . }} {{ template "head" . }}
{{ template "nav" . }} {{ template "nav" . }}
<main id="results" class="flow2"> <main id="results" class="flow2">
<h1>{{ .Data.Title }}</h1> <h1>{{ .Data.Title }} {{ if ne .Data.Site "" }} for {{ .Data.Site }} {{ end }}</h1>
<form method="GET" class="search"> <form method="GET" class="search">
<label for="search">Search {{ .SiteName }}</label> <label for="search">Search {{ .SiteName }} </label>
<span class="search__input"> <span class="search__input">
<input type="search" minlength="1" required name="q" placeholder="Search" value="{{ .Data.Query }}" class="search-box" id="search"> <input type="search" minlength="1" required name="q" placeholder="Search" value="{{ .Data.Query }}" class="search-box" id="search">
{{ if ne .Data.Site "" }}
<input type="hidden" value="{{ .Data.Site }}" name="site">
{{ end }}
<button type="submit" class="search__button" aria-label="Search" title="Search"> <button type="submit" class="search__button" aria-label="Search" title="Search">
<svg viewBox="0 0 420 300" xmlns="http://www.w3.org/2000/svg" baseProfile="full" style="background:var(--secondary)" width="42" height="30" fill="none"><path d="M90 135q60-60 120-60 0 0 0 0 60 0 120 60m-120 60a60 60 0 01-60-60 60 60 0 0160-60 60 60 0 0160 60 60 60 0 01-60 60m45-15h0l30 30m-75-15h0v45m-45-60h0l-30 30" stroke-width="81" stroke-linecap="square" stroke-linejoin="round" stroke="var(--primary)"/></svg> <svg viewBox="0 0 420 300" xmlns="http://www.w3.org/2000/svg" baseProfile="full" style="background:var(--secondary)" width="42" height="30" fill="none"><path d="M90 135q60-60 120-60 0 0 0 0 60 0 120 60m-120 60a60 60 0 01-60-60 60 60 0 0160-60 60 60 0 0160 60 60 60 0 01-60 60m45-15h0l30 30m-75-15h0v45m-45-60h0l-30 30" stroke-width="81" stroke-linecap="square" stroke-linejoin="round" stroke="var(--primary)"/></svg>
</button> </button>

Wyświetl plik

@ -27,6 +27,7 @@ type TemplateView struct {
type SearchData struct { type SearchData struct {
Query string Query string
Title string Title string
Site string
Pages []types.PageData Pages []types.PageData
IsInternal bool IsInternal bool
} }
@ -60,11 +61,19 @@ func (h RequestHandler) searchRoute(res http.ResponseWriter, req *http.Request)
var query string var query string
view := &TemplateView{} view := &TemplateView{}
var domain string
if req.Method == http.MethodGet { if req.Method == http.MethodGet {
params := req.URL.Query() params := req.URL.Query()
if words, exists := params["q"]; exists && words[0] != "" { if words, exists := params["q"]; exists && words[0] != "" {
query = words[0] query = words[0]
} }
if parts, exists := params["site"]; exists && parts[0] != "" {
// make sure we only have the domain, and no protocol prefix
domain = strings.TrimPrefix(parts[0], "https://")
domain = strings.TrimPrefix(domain, "http://")
domain = strings.TrimSuffix(domain, "/")
}
} }
if len(query) == 0 { if len(query) == 0 {
@ -73,7 +82,12 @@ func (h RequestHandler) searchRoute(res http.ResponseWriter, req *http.Request)
return return
} }
pages := database.SearchWordsByScore(h.db, util.Inflect(strings.Fields(query))) var pages []types.PageData
if domain != "" {
pages = database.SearchWordsBySite(h.db, util.Inflect(strings.Fields(query)), domain)
} else {
pages = database.SearchWordsByScore(h.db, util.Inflect(strings.Fields(query)))
}
if useURLTitles { if useURLTitles {
for i, pageData := range pages { for i, pageData := range pages {
@ -87,6 +101,7 @@ func (h RequestHandler) searchRoute(res http.ResponseWriter, req *http.Request)
view.Data = SearchData{ view.Data = SearchData{
Title: "Results", Title: "Results",
Query: query, Query: query,
Site: domain,
Pages: pages, Pages: pages,
IsInternal: true, IsInternal: true,
} }