tagliatelle

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

include-files.go (4967B)


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