diff --git a/internal/controllers/folderController.go b/internal/controllers/folderController.go index 00bc15f..5d6e1bc 100644 --- a/internal/controllers/folderController.go +++ b/internal/controllers/folderController.go @@ -49,37 +49,99 @@ func listEntries(base, rel string) ([]Entry, error) { func StreamHandler(db *gorm.DB) gin.HandlerFunc { return func(c *gin.Context) { base := "upload" - cur := c.Query("path") - // Liste des dossiers du dossier racine + // --- Sanitize du chemin courant --- + raw := c.Query("path") + cur := filepath.Clean("/" + strings.TrimSpace(raw)) // force un chemin absolu “virtuel” + if cur == "/" { + cur = "" // racine logique sous "upload" + } + // Interdit les traversées ou chemins absolus réels + if strings.Contains(cur, "..") || strings.HasPrefix(raw, "/") { + c.JSON(http.StatusBadRequest, gin.H{"error": "Chemin invalide"}) + return + } + + // --- Liste des dossiers du dossier racine (upload/*) --- rootEntries, err := listEntries(base, "") if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list root entries"}) return } + // On ne garde que les dossiers et on prépare la liste des noms pour une recherche en BDD var dirs []Entry + var rootNames []string 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) + rootNames = append(rootNames, e.Name) } } - // Liste du chemin courant + // Batch: récupère les IDs pour tous les noms racine (Path = nom simple) + // (tu peux remplacer "path = ?" par "path_name = ?" si tu préfères) + var rows []models.PathDownload + if len(rootNames) > 0 { + if err := db.Where("path IN ?", rootNames).Find(&rows).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "DB lookup failed"}) + return + } + } + + // Map nom -> ID (int64) + idByName := make(map[string]int64, len(rows)) + for _, r := range rows { + idByName[r.Path] = r.ID // Path = "Film"/"Série"/... + } + + // Affecte l'ID seulement pour les dossiers racine + for i := range dirs { + if id, ok := idByName[dirs[i].Name]; ok { + dirs[i].ID = id + } else { + dirs[i].ID = 0 // non trouvé en BDD + } + } + + // --- Liste du chemin courant (upload/) --- 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é + // IMPORTANT : + // La BDD ne contient que les dossiers racine. + // Donc on ne tente de mettre un ID aux entries QUE si on est à la racine. + if cur == "" && len(entries) > 0 { + var names []string + for _, e := range entries { + if e.IsDir { + names = append(names, e.Name) + } + } + var rows2 []models.PathDownload + if len(names) > 0 { + if err := db.Where("path IN ?", names).Find(&rows2).Error; err == nil { + tmp := make(map[string]int64, len(rows2)) + for _, r := range rows2 { + tmp[r.Path] = r.ID + } + for i := range entries { + if entries[i].IsDir { + if id, ok := tmp[entries[i].Name]; ok { + entries[i].ID = id + } + } + } + } + } + } else { + // On laisse ID = 0 pour le contenu interne des catégories (non suivi en BDD) + for i := range entries { + entries[i].ID = 0 + } } c.JSON(http.StatusOK, gin.H{