package files import ( "encoding/json" "errors" _ "image/gif" _ "image/jpeg" _ "image/png" "net/http" "github.com/google/uuid" "aether/internal/auth" "aether/pkg/response" ) // Favoriten der Seitenleiste: anlegen, entfernen, sortieren, auf- und // zuklappen. Der Zustand liegt serverseitig, damit er auf jedem Gerät gleich ist. // GET /api/v1/favorites func (h *Handler) ListFavorites(w http.ResponseWriter, r *http.Request) { user := auth.UserFromContext(r.Context()) favs, err := h.store.ListFavorites(r.Context(), user.ID) if err != nil { response.Error(w, http.StatusInternalServerError, "database error") return } if favs == nil { favs = []*Favorite{} } response.JSON(w, http.StatusOK, favs) } // POST /api/v1/favorites func (h *Handler) AddFavorite(w http.ResponseWriter, r *http.Request) { user := auth.UserFromContext(r.Context()) var body struct { FolderID string `json:"folder_id"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil || body.FolderID == "" { response.Error(w, http.StatusBadRequest, "folder_id required") return } folderID, err := uuid.Parse(body.FolderID) if err != nil { response.Error(w, http.StatusBadRequest, "invalid folder_id") return } // Lesezugriff genügt: Ein Favorit ist ein Lesezeichen, keine Änderung. // Die frühere Besitzprüfung schloss Gruppenordner und geteilte Ordner aus – // sie gehören dem Anfragenden nicht, sind aber genau die, die man sich // merken will. if _, ok := h.resolveFolder(w, r, &folderID, false); !ok { return } fav, err := h.store.AddFavorite(r.Context(), user.ID, folderID) if err != nil { response.Error(w, http.StatusInternalServerError, "database error") return } response.JSON(w, http.StatusCreated, fav) } // DELETE /api/v1/favorites/{folderId} func (h *Handler) RemoveFavorite(w http.ResponseWriter, r *http.Request) { user := auth.UserFromContext(r.Context()) folderID, err := parseID(r, "folderId") if err != nil { response.Error(w, http.StatusBadRequest, "invalid folder id") return } if err := h.store.RemoveFavorite(r.Context(), user.ID, folderID); errors.Is(err, ErrNotFound) { response.Error(w, http.StatusNotFound, "favorite not found") return } else if err != nil { response.Error(w, http.StatusInternalServerError, "database error") return } response.NoContent(w) } // PATCH /api/v1/favorites/{folderId}/expand func (h *Handler) SetFavoriteExpanded(w http.ResponseWriter, r *http.Request) { user := auth.UserFromContext(r.Context()) folderID, err := parseID(r, "folderId") if err != nil { response.Error(w, http.StatusBadRequest, "invalid folder id") return } var body struct { Expanded bool `json:"expanded"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { response.Error(w, http.StatusBadRequest, "invalid body") return } if err := h.store.SetFavoriteExpanded(r.Context(), user.ID, folderID, body.Expanded); errors.Is(err, ErrNotFound) { response.Error(w, http.StatusNotFound, "favorite not found") return } else if err != nil { response.Error(w, http.StatusInternalServerError, "database error") return } response.NoContent(w) } // PATCH /api/v1/favorites/reorder func (h *Handler) ReorderFavorites(w http.ResponseWriter, r *http.Request) { user := auth.UserFromContext(r.Context()) var body struct { FolderIDs []string `json:"folder_ids"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { response.Error(w, http.StatusBadRequest, "invalid body") return } ids := make([]uuid.UUID, 0, len(body.FolderIDs)) for _, s := range body.FolderIDs { id, err := uuid.Parse(s) if err != nil { response.Error(w, http.StatusBadRequest, "invalid folder_id: "+s) return } ids = append(ids, id) } if err := h.store.ReorderFavorites(r.Context(), user.ID, ids); err != nil { response.Error(w, http.StatusInternalServerError, "database error") return } response.NoContent(w) }