tagliatelle

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

include-files.go (4415B)


      1 package main
      2 
      3 import (
      4     "fmt"
      5     "log"
      6     "net/http"
      7     "os"
      8     "path/filepath"
      9     "strings"
     10 )
     11 
     12 func fileRouter(w http.ResponseWriter, r *http.Request) {
     13 	parts := strings.Split(r.URL.Path, "/")
     14 
     15 	if len(parts) >= 4 && parts[3] == "delete" {
     16 		fileDeleteHandler(w, r, parts)
     17 		return
     18 	}
     19 
     20 	if len(parts) >= 4 && parts[3] == "rename" {
     21 		fileRenameHandler(w, r, parts)
     22 		return
     23 	}
     24 
     25 	if len(parts) >= 7 && parts[3] == "tag" {
     26 		tagActionHandler(w, r, parts)
     27 		return
     28 	}
     29 
     30 	fileHandler(w, r)
     31 }
     32 
     33 func fileDeleteHandler(w http.ResponseWriter, r *http.Request, parts []string) {
     34 	if r.Method != http.MethodPost {
     35 		http.Redirect(w, r, "/file/"+parts[2], http.StatusSeeOther)
     36 		return
     37 	}
     38 
     39 	fileID := parts[2]
     40 
     41 	var currentFile File
     42 	err := db.QueryRow("SELECT id, filename, path FROM files WHERE id=?", fileID).Scan(&currentFile.ID, &currentFile.Filename, &currentFile.Path)
     43 	if err != nil {
     44 		renderError(w, "File not found", http.StatusNotFound)
     45 		return
     46 	}
     47 
     48 	tx, err := db.Begin()
     49 	if err != nil {
     50 		renderError(w, "Failed to start transaction", http.StatusInternalServerError)
     51 		return
     52 	}
     53 	defer tx.Rollback()
     54 
     55 	if _, err = tx.Exec("DELETE FROM file_tags WHERE file_id=?", fileID); err != nil {
     56 		renderError(w, "Failed to delete file tags", http.StatusInternalServerError)
     57 		return
     58 	}
     59 
     60 	if _, err = tx.Exec("DELETE FROM files WHERE id=?", fileID); err != nil {
     61 		renderError(w, "Failed to delete file record", http.StatusInternalServerError)
     62 		return
     63 	}
     64 
     65 	if err = tx.Commit(); err != nil {
     66 		renderError(w, "Failed to commit transaction", http.StatusInternalServerError)
     67 		return
     68 	}
     69 
     70 	if err = os.Remove(currentFile.Path); err != nil {
     71 		log.Printf("Warning: Failed to delete physical file %s: %v", currentFile.Path, err)
     72 	}
     73 
     74 	// Delete thumbnail if it exists
     75 	thumbPath := filepath.Join(config.UploadDir, "thumbnails", currentFile.Filename+".jpg")
     76 	if _, err := os.Stat(thumbPath); err == nil {
     77 		if err := os.Remove(thumbPath); err != nil {
     78 			log.Printf("Warning: Failed to delete thumbnail %s: %v", thumbPath, err)
     79 		}
     80 	}
     81 
     82 	http.Redirect(w, r, "/?deleted="+currentFile.Filename, http.StatusSeeOther)
     83 }
     84 
     85 func fileRenameHandler(w http.ResponseWriter, r *http.Request, parts []string) {
     86 	if r.Method != http.MethodPost {
     87 		http.Redirect(w, r, "/file/"+parts[2], http.StatusSeeOther)
     88 		return
     89 	}
     90 
     91 	fileID := parts[2]
     92 	newFilename := sanitizeFilename(strings.TrimSpace(r.FormValue("newfilename")))
     93 
     94 	if newFilename == "" {
     95 		renderError(w, "New filename cannot be empty", http.StatusBadRequest)
     96 		return
     97 	}
     98 
     99 	var currentFilename, currentPath string
    100 	err := db.QueryRow("SELECT filename, path FROM files WHERE id=?", fileID).Scan(&currentFilename, &currentPath)
    101 	if err != nil {
    102 		renderError(w, "File not found", http.StatusNotFound)
    103 		return
    104 	}
    105 
    106 	if currentFilename == newFilename {
    107 		http.Redirect(w, r, "/file/"+fileID, http.StatusSeeOther)
    108 		return
    109 	}
    110 
    111 	newPath := filepath.Join(config.UploadDir, newFilename)
    112 	if _, err := os.Stat(newPath); !os.IsNotExist(err) {
    113 		renderError(w, "A file with that name already exists", http.StatusConflict)
    114 		return
    115 	}
    116 
    117 	if err := os.Rename(currentPath, newPath); err != nil {
    118 		renderError(w, "Failed to rename physical file: "+err.Error(), http.StatusInternalServerError)
    119 		return
    120 	}
    121 
    122 	thumbOld := filepath.Join(config.UploadDir, "thumbnails", currentFilename+".jpg")
    123 	thumbNew := filepath.Join(config.UploadDir, "thumbnails", newFilename+".jpg")
    124 
    125 	if _, err := os.Stat(thumbOld); err == nil {
    126 		if err := os.Rename(thumbOld, thumbNew); err != nil {
    127 			os.Rename(newPath, currentPath)
    128 			renderError(w, "Failed to rename thumbnail: "+err.Error(), http.StatusInternalServerError)
    129 			return
    130 		}
    131 	}
    132 
    133 	_, err = db.Exec("UPDATE files SET filename=?, path=? WHERE id=?", newFilename, newPath, fileID)
    134 	if err != nil {
    135 		os.Rename(newPath, currentPath)
    136 		if _, err := os.Stat(thumbNew); err == nil {
    137 			os.Rename(thumbNew, thumbOld)
    138 		}
    139 		renderError(w, "Failed to update database", http.StatusInternalServerError)
    140 		return
    141 	}
    142 
    143 	http.Redirect(w, r, "/file/"+fileID, http.StatusSeeOther)
    144 }
    145 
    146 func checkFileConflictStrict(filename string) (string, string, error) {
    147 	finalPath := filepath.Join(config.UploadDir, filename)
    148 	if _, err := os.Stat(finalPath); err == nil {
    149 		return "", "", fmt.Errorf("a file with that name already exists")
    150 	} else if !os.IsNotExist(err) {
    151 		return "", "", fmt.Errorf("failed to check for existing file: %v", err)
    152 	}
    153 	return filename, finalPath, nil
    154 }