diff options
| author | Jacob McDonnell <jacob@jacobmcdonnell.com> | 2026-04-26 09:01:02 -0400 |
|---|---|---|
| committer | Jacob McDonnell <jacob@jacobmcdonnell.com> | 2026-04-26 09:01:02 -0400 |
| commit | b89dc2331a50c63f8b33272a5c4c61ab98abdaa3 (patch) | |
| tree | 5cd72f6ef9ac078b8d3c70bad5f1ae970c0dc7fd /main.go | |
| parent | 711594636704defae873be1a355a292505585afd (diff) | |
feat: Get OSes from Database
The OS drop down now uses HTMX to get the OSes from the database on
load.
Diffstat (limited to 'main.go')
| -rw-r--r-- | main.go | 62 |
1 files changed, 52 insertions, 10 deletions
@@ -6,6 +6,7 @@ import ( "log" "net/http" "os" + "slices" "regexp" "database/sql" _ "modernc.org/sqlite" @@ -22,6 +23,28 @@ type Database struct { DB *sql.DB } +func (d *Database) GetOS(w http.ResponseWriter, r *http.Request) { + rows, err := d.DB.Query("SELECT DISTINCT os FROM manpages;") + if err != nil { + log.Println(err) + ErrorPage(w, 500) + return + } + defer rows.Close() + + for rows.Next() { + var osName string + + if err := rows.Scan(&osName); err != nil { + log.Println(err) + ErrorPage(w, 500) + return + } + + fmt.Fprintf(w, "<option value=\"%s\">%s</option>", osName, osName) + } +} + func (d *Database) Search(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() @@ -36,7 +59,7 @@ func (d *Database) Search(w http.ResponseWriter, r *http.Request) { rows, err := d.DB.Query("SELECT * FROM manpages WHERE name == ? AND section == ? AND os == ?;", name, section, osName) if err != nil { log.Println(err) - ErrorPage(w, http.StatusText(500), 500) + ErrorPage(w, 500) return } defer rows.Close() @@ -47,7 +70,7 @@ func (d *Database) Search(w http.ResponseWriter, r *http.Request) { if err := rows.Scan(&entry.os, &entry.name, &entry.section, &entry.path); err != nil { log.Println(err) - ErrorPage(w, http.StatusText(500), 500) + ErrorPage(w, 500) return } @@ -55,26 +78,32 @@ func (d *Database) Search(w http.ResponseWriter, r *http.Request) { } if len(entries) > 0 { + fmt.Fprintf(w, "<hr>") for _, e := range entries { data, err := os.ReadFile(e.path) if err != nil { log.Println(err) - ErrorPage(w, http.StatusText(500), 500) + ErrorPage(w, 500) return } fmt.Fprintf(w, "%s", data) } + fmt.Fprintf(w, "<hr>") } else { fmt.Fprintf(w, "<center><h1>No results found for %s %s(%s)</h1></center>", osName, name, section) } } -func GetFiles(w http.ResponseWriter, r *http.Request) { +type AllowedFiles struct { + allowedFiles []string +} + +func (a *AllowedFiles) GetFiles(w http.ResponseWriter, r *http.Request) { log.Println("Request for:", r.URL.String()) url := fmt.Sprintf("static%s", r.URL.String()) htmlRegex, err := regexp.Compile("^static/.*\\.html$") if err != nil { - ErrorPage(w, "Internal Server Error", 500) + ErrorPage(w, 500) return } @@ -82,12 +111,17 @@ func GetFiles(w http.ResponseWriter, r *http.Request) { url = "static/index.html" } + if !slices.Contains(a.allowedFiles, url) { + ErrorPage(w, 404) + return + } + if htmlRegex.MatchString(url) { t := template.Must(template.ParseFiles("templates/template.html")) html, err := os.ReadFile(url) if err != nil { - ErrorPage(w, http.StatusText(500), 500) + ErrorPage(w, 500) return } @@ -97,15 +131,15 @@ func GetFiles(w http.ResponseWriter, r *http.Request) { } } -func ErrorPage(w http.ResponseWriter, message string, code int) { - log.Println(code, message) +func ErrorPage(w http.ResponseWriter, code int) { + log.Println(code, http.StatusText(code)) t := template.Must(template.ParseFiles("templates/error.html")) t.Execute(w, struct { Code int Message string }{ Code: code, - Message: message, + Message: http.StatusText(code), }) } @@ -141,9 +175,17 @@ func main() { } dbWrapper := &Database{ DB: db } + allowed := &AllowedFiles { + allowedFiles: []string{ + "static/htmx.min.js", + "static/index.html", + "static/css/main.css", + }, + } http.HandleFunc("/search", dbWrapper.Search) - http.HandleFunc("/", GetFiles) + http.HandleFunc("/os", dbWrapper.GetOS) + http.HandleFunc("/", allowed.GetFiles) log.Fatal(http.ListenAndServe(port, nil)) err = db.Close() |
