306 lines
7.7 KiB
Go
306 lines
7.7 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"time"
|
|
)
|
|
|
|
// Favorite représente un élément favori (note ou dossier)
|
|
type Favorite struct {
|
|
Path string `json:"path"`
|
|
IsDir bool `json:"is_dir"`
|
|
Title string `json:"title"`
|
|
AddedAt time.Time `json:"added_at"`
|
|
Order int `json:"order"`
|
|
}
|
|
|
|
// FavoritesData contient la liste des favoris
|
|
type FavoritesData struct {
|
|
Items []Favorite `json:"items"`
|
|
}
|
|
|
|
// getFavoritesFilePath retourne le chemin du fichier de favoris
|
|
func (h *Handler) getFavoritesFilePath() string {
|
|
return filepath.Join(h.notesDir, ".favorites.json")
|
|
}
|
|
|
|
// loadFavorites charge les favoris depuis le fichier JSON
|
|
func (h *Handler) loadFavorites() (*FavoritesData, error) {
|
|
path := h.getFavoritesFilePath()
|
|
|
|
// Si le fichier n'existe pas, retourner une liste vide
|
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
|
return &FavoritesData{Items: []Favorite{}}, nil
|
|
}
|
|
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var favorites FavoritesData
|
|
if err := json.Unmarshal(data, &favorites); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Trier par ordre
|
|
sort.Slice(favorites.Items, func(i, j int) bool {
|
|
return favorites.Items[i].Order < favorites.Items[j].Order
|
|
})
|
|
|
|
return &favorites, nil
|
|
}
|
|
|
|
// saveFavorites sauvegarde les favoris dans le fichier JSON
|
|
func (h *Handler) saveFavorites(favorites *FavoritesData) error {
|
|
path := h.getFavoritesFilePath()
|
|
|
|
data, err := json.MarshalIndent(favorites, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.WriteFile(path, data, 0644)
|
|
}
|
|
|
|
// handleFavorites route les requêtes /api/favorites/*
|
|
func (h *Handler) handleFavorites(w http.ResponseWriter, r *http.Request) {
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
h.handleGetFavorites(w, r)
|
|
case http.MethodPost:
|
|
h.handleAddFavorite(w, r)
|
|
case http.MethodDelete:
|
|
h.handleRemoveFavorite(w, r)
|
|
case http.MethodPut:
|
|
h.handleReorderFavorites(w, r)
|
|
default:
|
|
http.Error(w, "Méthode non autorisée", http.StatusMethodNotAllowed)
|
|
}
|
|
}
|
|
|
|
// handleGetFavorites retourne la liste des favoris (HTML)
|
|
func (h *Handler) handleGetFavorites(w http.ResponseWriter, r *http.Request) {
|
|
favorites, err := h.loadFavorites()
|
|
if err != nil {
|
|
h.logger.Printf("Erreur chargement favoris: %v", err)
|
|
// En cas d'erreur, retourner une liste vide plutôt qu'une erreur 500
|
|
favorites = &FavoritesData{Items: []Favorite{}}
|
|
}
|
|
|
|
// Enrichir avec les informations des fichiers
|
|
enrichedFavorites := []map[string]interface{}{}
|
|
|
|
for _, fav := range favorites.Items {
|
|
absPath := filepath.Join(h.notesDir, fav.Path)
|
|
|
|
// Vérifier si le fichier/dossier existe toujours
|
|
if _, err := os.Stat(absPath); os.IsNotExist(err) {
|
|
continue // Skip les favoris qui n'existent plus
|
|
}
|
|
|
|
item := map[string]interface{}{
|
|
"Path": fav.Path,
|
|
"IsDir": fav.IsDir,
|
|
"Title": fav.Title,
|
|
"Icon": getIcon(fav.IsDir, fav.Path),
|
|
}
|
|
|
|
enrichedFavorites = append(enrichedFavorites, item)
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
"Favorites": enrichedFavorites,
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
if err := h.templates.ExecuteTemplate(w, "favorites.html", data); err != nil {
|
|
h.logger.Printf("Erreur template favoris: %v", err)
|
|
http.Error(w, "Erreur de rendu", http.StatusInternalServerError)
|
|
}
|
|
}
|
|
|
|
// handleAddFavorite ajoute un élément aux favoris
|
|
func (h *Handler) handleAddFavorite(w http.ResponseWriter, r *http.Request) {
|
|
if err := r.ParseForm(); err != nil {
|
|
h.logger.Printf("Erreur ParseForm: %v", err)
|
|
http.Error(w, "Formulaire invalide", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
path := r.FormValue("path")
|
|
isDir := r.FormValue("is_dir") == "true"
|
|
title := r.FormValue("title")
|
|
|
|
h.logger.Printf("handleAddFavorite: path='%s', is_dir='%s', title='%s'", path, r.FormValue("is_dir"), title)
|
|
|
|
if path == "" {
|
|
h.logger.Printf("Erreur: chemin vide")
|
|
http.Error(w, "Chemin requis", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Valider que le fichier/dossier existe
|
|
absPath := filepath.Join(h.notesDir, path)
|
|
if _, err := os.Stat(absPath); os.IsNotExist(err) {
|
|
http.Error(w, "Fichier/dossier introuvable", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
// Si pas de titre, utiliser le nom du fichier
|
|
if title == "" {
|
|
title = filepath.Base(path)
|
|
if !isDir && filepath.Ext(title) == ".md" {
|
|
title = title[:len(title)-3]
|
|
}
|
|
}
|
|
|
|
favorites, err := h.loadFavorites()
|
|
if err != nil {
|
|
h.logger.Printf("Erreur chargement favoris: %v", err)
|
|
http.Error(w, "Erreur de chargement", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Vérifier si déjà en favoris
|
|
for _, fav := range favorites.Items {
|
|
if fav.Path == path {
|
|
http.Error(w, "Déjà en favoris", http.StatusConflict)
|
|
return
|
|
}
|
|
}
|
|
|
|
// Ajouter le nouveau favori
|
|
newFavorite := Favorite{
|
|
Path: path,
|
|
IsDir: isDir,
|
|
Title: title,
|
|
AddedAt: time.Now(),
|
|
Order: len(favorites.Items),
|
|
}
|
|
|
|
favorites.Items = append(favorites.Items, newFavorite)
|
|
|
|
if err := h.saveFavorites(favorites); err != nil {
|
|
h.logger.Printf("Erreur sauvegarde favoris: %v", err)
|
|
http.Error(w, "Erreur de sauvegarde", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Retourner la liste mise à jour
|
|
h.handleGetFavorites(w, r)
|
|
}
|
|
|
|
// handleRemoveFavorite retire un élément des favoris
|
|
func (h *Handler) handleRemoveFavorite(w http.ResponseWriter, r *http.Request) {
|
|
if err := r.ParseForm(); err != nil {
|
|
// Pour DELETE, il faut lire le body manuellement
|
|
body, _ := io.ReadAll(r.Body)
|
|
r.Body.Close()
|
|
values, _ := url.ParseQuery(string(body))
|
|
r.Form = values
|
|
}
|
|
|
|
path := r.FormValue("path")
|
|
|
|
if path == "" {
|
|
http.Error(w, "Chemin requis", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
favorites, err := h.loadFavorites()
|
|
if err != nil {
|
|
h.logger.Printf("Erreur chargement favoris: %v", err)
|
|
http.Error(w, "Erreur de chargement", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Retirer le favori
|
|
newItems := []Favorite{}
|
|
found := false
|
|
for _, fav := range favorites.Items {
|
|
if fav.Path != path {
|
|
newItems = append(newItems, fav)
|
|
} else {
|
|
found = true
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
http.Error(w, "Favori introuvable", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
// Réorganiser les ordres
|
|
for i := range newItems {
|
|
newItems[i].Order = i
|
|
}
|
|
|
|
favorites.Items = newItems
|
|
|
|
if err := h.saveFavorites(favorites); err != nil {
|
|
h.logger.Printf("Erreur sauvegarde favoris: %v", err)
|
|
http.Error(w, "Erreur de sauvegarde", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Retourner la liste mise à jour
|
|
h.handleGetFavorites(w, r)
|
|
}
|
|
|
|
// handleReorderFavorites réorganise l'ordre des favoris
|
|
func (h *Handler) handleReorderFavorites(w http.ResponseWriter, r *http.Request) {
|
|
var order []string
|
|
if err := json.NewDecoder(r.Body).Decode(&order); err != nil {
|
|
http.Error(w, "JSON invalide", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
favorites, err := h.loadFavorites()
|
|
if err != nil {
|
|
h.logger.Printf("Erreur chargement favoris: %v", err)
|
|
http.Error(w, "Erreur de chargement", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Créer un map pour retrouver les favoris rapidement
|
|
favMap := make(map[string]*Favorite)
|
|
for i := range favorites.Items {
|
|
favMap[favorites.Items[i].Path] = &favorites.Items[i]
|
|
}
|
|
|
|
// Réorganiser selon le nouvel ordre
|
|
newItems := []Favorite{}
|
|
for i, path := range order {
|
|
if fav, ok := favMap[path]; ok {
|
|
fav.Order = i
|
|
newItems = append(newItems, *fav)
|
|
}
|
|
}
|
|
|
|
favorites.Items = newItems
|
|
|
|
if err := h.saveFavorites(favorites); err != nil {
|
|
h.logger.Printf("Erreur sauvegarde favoris: %v", err)
|
|
http.Error(w, "Erreur de sauvegarde", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte("OK"))
|
|
}
|
|
|
|
// getIcon retourne l'icône appropriée pour un fichier/dossier
|
|
func getIcon(isDir bool, path string) string {
|
|
if isDir {
|
|
return "📁"
|
|
}
|
|
return "📄"
|
|
}
|