shelfy-v2/internal/controllers/folderController.go
2025-07-27 16:26:30 +02:00

182 lines
4.6 KiB
Go

package controllers
import (
"canguidev/shelfy/internal/models"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"time"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type Entry struct {
ID int64 `json:"ID"`
Name, Path string
IsDir bool
ModTime time.Time
Size int64
Children []Entry `json:"Children,omitempty"`
Url string `json:"Url,omitempty"` // <- Ajout ici
}
func listEntries(base, rel string) ([]Entry, error) {
dir := filepath.Join(base, rel)
fis, err := os.ReadDir(dir)
if err != nil {
return nil, err
}
out := make([]Entry, 0, len(fis))
for _, fi := range fis {
info, _ := fi.Info()
out = append(out, Entry{
Name: fi.Name(),
Path: filepath.ToSlash(filepath.Join(rel, fi.Name())),
IsDir: fi.IsDir(),
ModTime: info.ModTime(),
Size: info.Size(),
})
}
return out, nil
}
func StreamHandler(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
base := "upload"
cur := c.Query("path")
// Liste des dossiers du dossier racine
rootEntries, err := listEntries(base, "")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list root entries"})
return
}
var dirs []Entry
for _, e := range rootEntries {
if e.IsDir {
var pathDownload models.PathDownload
// Recherche par PathName (== e.Name)
db.Where("path_name = ?", e.Name).First(&pathDownload)
e.ID = pathDownload.ID // 0 si non trouvé
dirs = append(dirs, e)
}
}
// Liste du chemin courant
entries, err := listEntries(base, cur)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list entries"})
return
}
for i := range entries {
var pathDownload models.PathDownload
db.Where("path_name = ?", entries[i].Name).First(&pathDownload)
entries[i].ID = pathDownload.ID // 0 si non trouvé
}
c.JSON(http.StatusOK, gin.H{
"dirs": dirs,
"entries": entries,
"currentPath": cur,
})
}
}
func DetailHandler() gin.HandlerFunc {
return func(c *gin.Context) {
base := "upload"
rel := c.Query("path")
rel = filepath.Clean("/" + rel)
rel = strings.TrimPrefix(rel, "/") // => chemin relatif à "upload"
absPath := filepath.Join(base, rel)
absPath, err := filepath.Abs(absPath)
if err != nil {
c.JSON(500, gin.H{"error": "Path error"})
return
}
baseAbs, err := filepath.Abs(base)
if err != nil {
c.JSON(500, gin.H{"error": "Base path error"})
return
}
if !strings.HasPrefix(absPath, baseAbs) {
c.JSON(403, gin.H{"error": "Access outside base directory is forbidden"})
return
}
info, err := os.Stat(absPath)
if err != nil {
c.JSON(404, gin.H{"error": "Path not found"})
return
}
type Entry struct {
ID int64 `json:"ID,omitempty"`
Name string `json:"Name"`
Path string `json:"Path"` // <--- Toujours RELATIF à "upload"
IsDir bool `json:"IsDir"`
ModTime time.Time `json:"ModTime"`
Size int64 `json:"Size"`
Children []Entry `json:"Children,omitempty"`
Url string `json:"Url,omitempty"` // <--- Lien d'accès au fichier
}
var buildTree func(absPath, relPath string, fi os.FileInfo) (Entry, error)
buildTree = func(absPath, relPath string, fi os.FileInfo) (Entry, error) {
entry := Entry{
Name: fi.Name(),
Path: relPath, // <-- toujours RELATIF à la racine upload
IsDir: fi.IsDir(),
ModTime: fi.ModTime(),
Size: fi.Size(),
}
if !fi.IsDir() {
entry.Url = "/api/v1/folders/file?path=" + url.QueryEscape(relPath)
}
if fi.IsDir() {
f, err := os.Open(absPath)
if err != nil {
return entry, err
}
defer f.Close()
files, err := f.Readdir(0)
if err != nil {
return entry, err
}
for _, child := range files {
childAbs := filepath.Join(absPath, child.Name())
childRel := filepath.Join(relPath, child.Name())
childEntry, err := buildTree(childAbs, childRel, child)
if err != nil {
continue
}
entry.Children = append(entry.Children, childEntry)
}
}
return entry, nil
}
rootEntry, err := buildTree(absPath, rel, info)
if err != nil {
c.JSON(500, gin.H{"error": "Tree error"})
return
}
c.JSON(200, rootEntry)
}
}