tagliatelle

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

include-search.go (2104B)


      1 package main
      2 
      3 import (
      4     "database/sql"
      5     "fmt"
      6     "net/http"
      7     "net/url"
      8     "strings"
      9 )
     10 
     11 func searchHandler(w http.ResponseWriter, r *http.Request) {
     12 	query := strings.TrimSpace(r.URL.Query().Get("q"))
     13 
     14 	var files []File
     15 	var searchTitle string
     16 
     17 	if query != "" {
     18 		sqlPattern := "%" + strings.ReplaceAll(strings.ReplaceAll(strings.ToLower(query), "*", "%"), "?", "_") + "%"
     19 
     20 		rows, err := db.Query(`
     21 			SELECT f.id, f.filename, f.path, COALESCE(f.description, '') AS description,
     22 			       c.name AS category, t.value AS tag
     23 			FROM files f
     24 			LEFT JOIN file_tags ft ON ft.file_id = f.id
     25 			LEFT JOIN tags t ON t.id = ft.tag_id
     26 			LEFT JOIN categories c ON c.id = t.category_id
     27 			WHERE LOWER(f.filename) LIKE ? OR LOWER(f.description) LIKE ? OR LOWER(t.value) LIKE ?
     28 			ORDER BY f.filename
     29 		`, sqlPattern, sqlPattern, sqlPattern)
     30 		if err != nil {
     31 			renderError(w, "Search failed: "+err.Error(), http.StatusInternalServerError)
     32 			return
     33 		}
     34 		defer rows.Close()
     35 
     36 		fileMap := make(map[int]*File)
     37 		for rows.Next() {
     38 			var id int
     39 			var filename, path, description, category, tag sql.NullString
     40 
     41 			if err := rows.Scan(&id, &filename, &path, &description, &category, &tag); err != nil {
     42 				renderError(w, "Failed to read search results: "+err.Error(), http.StatusInternalServerError)
     43 				return
     44 			}
     45 
     46 			f, exists := fileMap[id]
     47 			if !exists {
     48 				f = &File{
     49 					ID:              id,
     50 					Filename:        filename.String,
     51 					Path:            path.String,
     52 					EscapedFilename: url.PathEscape(filename.String),
     53 					Description:     description.String,
     54 					Tags:            make(map[string][]string),
     55 				}
     56 				fileMap[id] = f
     57 			}
     58 
     59 			if category.Valid && tag.Valid && tag.String != "" {
     60 				f.Tags[category.String] = append(f.Tags[category.String], tag.String)
     61 			}
     62 		}
     63 
     64 		for _, f := range fileMap {
     65 			files = append(files, *f)
     66 		}
     67 
     68 		searchTitle = fmt.Sprintf("Search Results for: %s", query)
     69 	} else {
     70 		searchTitle = "Search Files"
     71 	}
     72 
     73 	pageData := buildPageData(searchTitle, files)
     74 	pageData.Query = query
     75 	pageData.Files = files
     76 	renderTemplate(w, "search.html", pageData)
     77 }