taggart

Simple golang tagging filesystem webapp
Log | Files | Refs

commit ac88cbf20af11adaae2b495e042602e489c886b5
parent 25125d4ebb21d5063afc4a6fb4b6bd0a1e6ad331
Author: breadcat <breadcat@users.noreply.github.com>
Date:   Fri, 19 Sep 2025 18:34:20 +0100

Add untagged files handler

Diffstat:
Mmain.go | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mtemplates/list.html | 25++++++++++++++++++++++---
Atemplates/untagged.html | 29+++++++++++++++++++++++++++++
3 files changed, 114 insertions(+), 7 deletions(-)

diff --git a/main.go b/main.go @@ -83,6 +83,8 @@ func main() { http.HandleFunc("/file/", fileRouter) http.HandleFunc("/tags", tagsHandler) http.HandleFunc("/tag/", tagFilterHandler) + http.HandleFunc("/untagged", untaggedFilesHandler) + http.Handle("/uploads/", http.StripPrefix("/uploads/", http.FileServer(http.Dir("uploads")))) http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) @@ -91,19 +93,71 @@ func main() { http.ListenAndServe(":8080", nil) } -// List all files +// List all files, plus untagged files func listFilesHandler(w http.ResponseWriter, r *http.Request) { - rows, _ := db.Query("SELECT id, filename, path FROM files ORDER BY id DESC") + // Tagged files + rows, _ := db.Query(` + SELECT DISTINCT f.id, f.filename, f.path + FROM files f + JOIN file_tags ft ON ft.file_id = f.id + ORDER BY f.id DESC + `) + defer rows.Close() + var tagged []File + for rows.Next() { + var f File + rows.Scan(&f.ID, &f.Filename, &f.Path) + tagged = append(tagged, f) + } + + // Untagged files + untaggedRows, _ := db.Query(` + SELECT f.id, f.filename, f.path + FROM files f + LEFT JOIN file_tags ft ON ft.file_id = f.id + WHERE ft.file_id IS NULL + ORDER BY f.id DESC + `) + defer untaggedRows.Close() + var untagged []File + for untaggedRows.Next() { + var f File + untaggedRows.Scan(&f.ID, &f.Filename, &f.Path) + untagged = append(untagged, f) + } + + tmpl.ExecuteTemplate(w, "list.html", struct { + Tagged []File + Untagged []File + }{tagged, untagged}) +} + + +// Show untagged files at /untagged +func untaggedFilesHandler(w http.ResponseWriter, r *http.Request) { + rows, _ := db.Query(` + SELECT f.id, f.filename, f.path + FROM files f + WHERE NOT EXISTS ( + SELECT 1 + FROM file_tags ft + WHERE ft.file_id = f.id + ) + ORDER BY f.id DESC + `) defer rows.Close() + var files []File for rows.Next() { var f File rows.Scan(&f.ID, &f.Filename, &f.Path) files = append(files, f) } - tmpl.ExecuteTemplate(w, "list.html", files) + + tmpl.ExecuteTemplate(w, "untagged.html", files) } + // Upload a file func uploadHandler(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet { @@ -284,5 +338,10 @@ func tagFilterHandler(w http.ResponseWriter, r *http.Request) { files = append(files, f) } - tmpl.ExecuteTemplate(w, "list.html", files) + // Wrap in the same struct expected by list.html + tmpl.ExecuteTemplate(w, "list.html", struct { + Tagged []File + Untagged []File + }{files, nil}) } + diff --git a/templates/list.html b/templates/list.html @@ -7,10 +7,11 @@ </head> <body> <h1>Files</h1> -<p><a href="/upload">Upload new file</a> | <a href="/tags">Browse tags</a></p> +<p><a href="/upload">Upload new file</a> | <a href="/tags">Browse tags</a> | <a href="/untagged">Untagged files</a></p> +<h2>Tagged Files</h2> <ul> -{{range .}} +{{range .Tagged}} <li> <a href="/file/{{.ID}}">{{.Filename}}</a><br> {{if hasAnySuffix .Filename ".jpg" ".jpeg" ".png" ".gif" ".webp"}} @@ -22,7 +23,25 @@ {{end}} </li> {{else}} - <li>No files uploaded yet.</li> + <li>No tagged files yet.</li> +{{end}} +</ul> + +<h2>Untagged Files</h2> +<ul> +{{range .Untagged}} + <li> + <a href="/file/{{.ID}}">{{.Filename}}</a><br> + {{if hasAnySuffix .Filename ".jpg" ".jpeg" ".png" ".gif" ".webp"}} + <img src="/uploads/{{.Filename}}" style="max-width:150px"> + {{else if hasAnySuffix .Filename ".mp4" ".webm" ".mov"}} + <video width="150" controls> + <source src="/uploads/{{.Filename}}"> + </video> + {{end}} + </li> +{{else}} + <li>No untagged files.</li> {{end}} </ul> </body> diff --git a/templates/untagged.html b/templates/untagged.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>Untagged Files</title> + <link rel="stylesheet" type="text/css" href="/static/style.css"> +</head> +<body> +<h1>Untagged Files</h1> +<p><a href="/">Back to all files</a> | <a href="/upload">Upload new file</a></p> + +<ul> +{{range .}} + <li> + <a href="/file/{{.ID}}">{{.Filename}}</a><br> + {{if hasAnySuffix .Filename ".jpg" ".jpeg" ".png" ".gif" ".webp"}} + <img src="/uploads/{{.Filename}}" style="max-width:150px"> + {{else if hasAnySuffix .Filename ".mp4" ".webm" ".mov"}} + <video width="150" controls> + <source src="/uploads/{{.Filename}}"> + </video> + {{end}} + </li> +{{else}} + <li>No untagged files.</li> +{{end}} +</ul> +</body> +</html>