taggart

Simple golang tagging filesystem webapp
Log | Files | Refs

commit dd3f7e7ff47fa8ad30cc19115bafc3b738d2bedf
parent 631d58af67757b000f701a2c5478d0c393f66de2
Author: breadcat <breadcat@users.noreply.github.com>
Date:   Sun, 21 Sep 2025 09:40:50 +0100

With renaming, allow deletion too

Diffstat:
Mmain.go | 65++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mtemplates/file.html | 8++++++--
2 files changed, 70 insertions(+), 3 deletions(-)

diff --git a/main.go b/main.go @@ -287,10 +287,16 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, fmt.Sprintf("/file/%d", id), http.StatusSeeOther) } -// Router for file operations, tag deletion, and rename +// Router for file operations, tag deletion, rename, and delete func fileRouter(w http.ResponseWriter, r *http.Request) { parts := strings.Split(r.URL.Path, "/") + // Handle delete: /file/{id}/delete + if len(parts) >= 4 && parts[3] == "delete" { + fileDeleteHandler(w, r, parts) + return + } + // Handle rename: /file/{id}/rename if len(parts) >= 4 && parts[3] == "rename" { fileRenameHandler(w, r, parts) @@ -307,6 +313,63 @@ func fileRouter(w http.ResponseWriter, r *http.Request) { fileHandler(w, r) } +// Handle file deletion +func fileDeleteHandler(w http.ResponseWriter, r *http.Request, parts []string) { + if r.Method != http.MethodPost { + http.Redirect(w, r, "/file/"+parts[2], http.StatusSeeOther) + return + } + + fileID := parts[2] + + // Get current file info + var currentFile File + err := db.QueryRow("SELECT id, filename, path FROM files WHERE id=?", fileID).Scan(&currentFile.ID, &currentFile.Filename, &currentFile.Path) + if err != nil { + http.Error(w, "File not found", http.StatusNotFound) + return + } + + // Start a transaction to ensure data consistency + tx, err := db.Begin() + if err != nil { + http.Error(w, "Failed to start transaction", http.StatusInternalServerError) + return + } + defer tx.Rollback() // Will be ignored if tx.Commit() is called + + // Delete file_tags relationships + _, err = tx.Exec("DELETE FROM file_tags WHERE file_id=?", fileID) + if err != nil { + http.Error(w, "Failed to delete file tags", http.StatusInternalServerError) + return + } + + // Delete file record + _, err = tx.Exec("DELETE FROM files WHERE id=?", fileID) + if err != nil { + http.Error(w, "Failed to delete file record", http.StatusInternalServerError) + return + } + + // Commit the database transaction + err = tx.Commit() + if err != nil { + http.Error(w, "Failed to commit transaction", http.StatusInternalServerError) + return + } + + // Delete the physical file (after successful database deletion) + err = os.Remove(currentFile.Path) + if err != nil { + // Log the error but don't fail the request - database is already clean + log.Printf("Warning: Failed to delete physical file %s: %v", currentFile.Path, err) + } + + // Redirect to home page with success + http.Redirect(w, r, "/?deleted="+currentFile.Filename, http.StatusSeeOther) +} + // Handle file renaming func fileRenameHandler(w http.ResponseWriter, r *http.Request, parts []string) { if r.Method != http.MethodPost { diff --git a/templates/file.html b/templates/file.html @@ -12,13 +12,17 @@ File {{.Data.File.Filename}} <a href="/uploads/{{.Data.File.Filename}}">Download file</a><br> {{end}} -<h3>Rename File</h3> -<form method="post" action="/file/{{.Data.File.ID}}/rename"> +<h3>File Actions</h3> +<form method="post" action="/file/{{.Data.File.ID}}/rename" style="display:inline-block; margin-right: 20px;"> New filename: <input type="text" name="newfilename" value="{{.Data.File.Filename}}" required style="width:300px"><br> <small>Include file extension (e.g., "new-name.jpg")</small><br><br> <button type="submit" onclick="return confirm('Are you sure you want to rename this file?')">Rename File</button> </form> +<form method="post" action="/file/{{.Data.File.ID}}/delete" style="display:inline-block;"> + <button type="submit" onclick="return confirm('Are you sure you want to delete this file? This cannot be undone!')" style="background-color: #dc3545; color: white;">Delete File</button> +</form> + <h3>Tags</h3> <ul> {{range $k, $v := .Data.File.Tags}}