Numerous Bug Fixes
Some checks failed
Automated Container Build / build-and-push (push) Failing after 8s

This commit is contained in:
Elijah 2026-05-22 15:50:45 -07:00
parent 02eefdac0e
commit 267d429122
959 changed files with 145571 additions and 221 deletions

View file

@ -1,6 +1,8 @@
package handlers
import (
"archive/zip"
"bufio"
"database/sql"
"fmt"
"io"
@ -89,13 +91,17 @@ func (h *FSHandler) ListDirectory(c *fiber.Ctx) error {
// Enrich with DB metadata (pinned status, etc.)
var isPinned, isTrashed int
var checksum sql.NullString
err = h.DB.QueryRow(
"SELECT is_pinned, is_trashed FROM files WHERE path = ?",
"SELECT is_pinned, is_trashed, checksum FROM files WHERE path = ?",
filepath.ToSlash(entryPath),
).Scan(&isPinned, &isTrashed)
).Scan(&isPinned, &isTrashed, &checksum)
if err == nil {
fi.IsPinned = isPinned == 1
fi.IsTrashed = isTrashed == 1
if checksum.Valid {
fi.Checksum = checksum.String
}
}
// Don't show trashed items in normal listings
@ -139,14 +145,16 @@ func (h *FSHandler) getFileInfo(c *fiber.Ctx, absPath string) error {
}
var isPinned int
var checksum string
var checksum sql.NullString
err = h.DB.QueryRow(
"SELECT is_pinned, checksum FROM files WHERE path = ?",
filepath.ToSlash(relativePath),
).Scan(&isPinned, &checksum)
if err == nil {
fi.IsPinned = isPinned == 1
fi.Checksum = checksum
if checksum.Valid {
fi.Checksum = checksum.String
}
}
return c.JSON(fi)
@ -166,21 +174,32 @@ func (h *FSHandler) CreateFolder(c *fiber.Ctx) error {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "path is required"})
}
// Validate path within jail
fullPath, err := h.resolveSafe(body.Path)
parentDir := filepath.Dir(body.Path)
folderName := filepath.Base(body.Path)
parentFullPath, err := h.resolveSafe(parentDir)
if err != nil {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": err.Error()})
}
uniqueName := GetUniquePath(parentFullPath, folderName)
fullPath := filepath.Join(parentFullPath, uniqueName)
cleanPath := filepath.ToSlash(filepath.Join(parentDir, uniqueName))
// Remove any prefix like "." if cleanPath was "." and it got joined.
// filepath.ToSlash cleans the path.
if cleanPath == "." {
// Just for safety, but base shouldn't be empty
}
if err := os.MkdirAll(fullPath, 0755); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to create folder"})
}
// Record in DB
cleanPath := filepath.ToSlash(body.Path)
h.DB.Exec(
"INSERT OR IGNORE INTO files (path, name, is_dir) VALUES (?, ?, 1)",
cleanPath, filepath.Base(cleanPath),
cleanPath, uniqueName,
)
h.DB.AddAuditLog("folder_created", cleanPath, c.IP())
@ -207,7 +226,10 @@ func (h *FSHandler) Rename(c *fiber.Ctx) error {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": err.Error()})
}
newPath := filepath.Join(filepath.Dir(body.OldPath), body.NewName)
parentDir := filepath.Dir(oldFull)
uniqueName := GetUniquePath(parentDir, body.NewName)
newPath := filepath.Join(filepath.Dir(body.OldPath), uniqueName)
newFull, err := h.resolveSafe(newPath)
if err != nil {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": err.Error()})
@ -216,6 +238,9 @@ func (h *FSHandler) Rename(c *fiber.Ctx) error {
if err := os.Rename(oldFull, newFull); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to rename"})
}
// Update body.NewName to reflect the actual unique name used
body.NewName = uniqueName
// Update DB
h.DB.Exec(
@ -251,8 +276,17 @@ func (h *FSHandler) Move(c *fiber.Ctx) error {
// If destination is a directory, move into it
if info, err := os.Stat(dstFull); err == nil && info.IsDir() {
dstFull = filepath.Join(dstFull, filepath.Base(srcFull))
body.DestPath = filepath.Join(body.DestPath, filepath.Base(body.SourcePath))
uniqueName := GetUniquePath(dstFull, filepath.Base(srcFull))
dstFull = filepath.Join(dstFull, uniqueName)
body.DestPath = filepath.Join(body.DestPath, uniqueName)
} else {
// If destination is not a directory but the file exists (rename), we don't overwrite if they want `(1)`
// Wait, if they intentionally rename to an existing file, should it append (1)?
// Yes, to prevent accidental overwrites.
parentDir := filepath.Dir(dstFull)
uniqueName := GetUniquePath(parentDir, filepath.Base(dstFull))
dstFull = filepath.Join(parentDir, uniqueName)
body.DestPath = filepath.Join(filepath.Dir(body.DestPath), uniqueName)
}
if err := os.Rename(srcFull, dstFull); err != nil {
@ -324,11 +358,16 @@ func (h *FSHandler) Delete(c *fiber.Ctx) error {
// Soft-delete: move to .trash directory
trashPath := filepath.Join(h.Config.TrashDir, relativePath)
if err := os.MkdirAll(filepath.Dir(trashPath), 0755); err != nil {
fmt.Printf("MkdirAll error: %v\n", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to prepare trash"})
}
if err := os.Rename(resolvedPath, trashPath); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to move to trash"})
fmt.Printf("Rename error %s -> %s: %v. Attempting copy & delete fallback...\n", resolvedPath, trashPath, err)
if err := copyFile(resolvedPath, trashPath); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to move to trash"})
}
os.RemoveAll(resolvedPath)
}
// Update DB
@ -438,12 +477,75 @@ func (h *FSHandler) EmptyTrash(c *fiber.Ctx) error {
os.MkdirAll(h.Config.TrashDir, 0755)
h.DB.Exec("DELETE FROM files WHERE is_trashed = 1")
h.DB.AddAuditLog("trash_emptied", "All trashed items permanently deleted", c.IP())
h.DB.AddAuditLog("emptied_trash", "User emptied trash", c.IP())
return c.JSON(fiber.Map{"message": "trash emptied"})
}
// DownloadFolder creates and streams a ZIP archive of a folder.
// GET /api/files/download-folder?path=...
func (h *FSHandler) DownloadFolder(c *fiber.Ctx) error {
folderPath := c.Query("path")
if folderPath == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "path is required"})
}
fullPath, err := h.resolveSafe(folderPath)
if err != nil {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": err.Error()})
}
info, err := os.Stat(fullPath)
if err != nil || !info.IsDir() {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "folder not found"})
}
c.Set("Content-Type", "application/zip")
c.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.zip\"", filepath.Base(fullPath)))
c.Context().SetBodyStreamWriter(func(w *bufio.Writer) {
zipWriter := zip.NewWriter(w)
defer zipWriter.Close()
filepath.Walk(fullPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if path == fullPath {
return nil
}
relPath, err := filepath.Rel(fullPath, path)
if err != nil {
return err
}
if info.IsDir() {
// add directory entry
relPath += "/"
_, err = zipWriter.Create(relPath)
return err
}
// add file entry
zipFile, err := zipWriter.Create(relPath)
if err != nil {
return err
}
fsFile, err := os.Open(path)
if err != nil {
return err
}
defer fsFile.Close()
_, err = io.Copy(zipFile, fsFile)
return err
})
})
return nil
}
// TogglePin pins or unpins a file/folder.
// POST /api/files/pin
func (h *FSHandler) TogglePin(c *fiber.Ctx) error {
@ -585,8 +687,9 @@ func (h *FSHandler) Upload(c *fiber.Ctx) error {
// If destination is a directory, save into it
if info, err := os.Stat(fullDest); err == nil && info.IsDir() {
fullDest = filepath.Join(fullDest, file.Filename)
destPath = filepath.Join(destPath, file.Filename)
uniqueName := GetUniquePath(fullDest, file.Filename)
fullDest = filepath.Join(fullDest, uniqueName)
destPath = filepath.Join(destPath, uniqueName)
}
// Ensure parent directory exists
@ -594,9 +697,6 @@ func (h *FSHandler) Upload(c *fiber.Ctx) error {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to create directory"})
}
// Version existing file if it exists
CreateVersion(h.DB, h.Config, fullDest, filepath.ToSlash(destPath))
// Save the file
if err := c.SaveFile(file, fullDest); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "failed to save file"})