182 lines
4.6 KiB
Go
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)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|