diff --git a/open-x4-sdk b/open-x4-sdk index bd4e6707..c39f253a 160000 --- a/open-x4-sdk +++ b/open-x4-sdk @@ -1 +1 @@ -Subproject commit bd4e6707503ab9c97d13ee0d8f8c69e9ff03cd12 +Subproject commit c39f253a7dabbc193a8d7d310fb8777dca0ab8f1 diff --git a/src/RecentBooksStore.cpp b/src/RecentBooksStore.cpp index 5932de36..cdec3b00 100644 --- a/src/RecentBooksStore.cpp +++ b/src/RecentBooksStore.cpp @@ -104,3 +104,21 @@ bool RecentBooksStore::loadFromFile() { Serial.printf("[%lu] [RBS] Recent books loaded from file (%d entries)\n", millis(), recentBooks.size()); return true; } + +void RecentBooksStore::updatePath(const std::string& oldPath, const std::string& newPath) { + bool changed = false; + for (auto& book : recentBooks) { + if (book.path == oldPath) { + book.path = newPath; + changed = true; + } else if (book.path.find(oldPath + "/") == 0) { + // It's a directory move/rename + book.path = newPath + book.path.substr(oldPath.length()); + changed = true; + } + } + + if (changed) { + saveToFile(); + } +} diff --git a/src/RecentBooksStore.h b/src/RecentBooksStore.h index 7b87f1e0..ba205471 100644 --- a/src/RecentBooksStore.h +++ b/src/RecentBooksStore.h @@ -32,9 +32,18 @@ class RecentBooksStore { int getCount() const { return static_cast(recentBooks.size()); } bool saveToFile() const; - bool loadFromFile(); + + /** + * Update the path of a book in the recent list. + * Useful when moving/renaming files or entire directories. + * If oldPath is a directory, all books within will have their paths updated. + * + * @param oldPath Original absolute path + * @param newPath New absolute path + */ + void updatePath(const std::string& oldPath, const std::string& newPath); }; // Helper macro to access recent books store -#define RECENT_BOOKS RecentBooksStore::getInstance() +#define RECENT_BOOKS RecentBooksStore::getInstance() \ No newline at end of file diff --git a/src/network/CrossPointWebServer.cpp b/src/network/CrossPointWebServer.cpp index a135c9f0..81be0da9 100644 --- a/src/network/CrossPointWebServer.cpp +++ b/src/network/CrossPointWebServer.cpp @@ -11,6 +11,7 @@ #include "html/FilesPageHtml.generated.h" #include "html/HomePageHtml.generated.h" +#include "util/BookCacheManager.h" #include "util/StringUtils.h" namespace { @@ -112,6 +113,10 @@ void CrossPointWebServer::begin() { // Delete file/folder endpoint server->on("/delete", HTTP_POST, [this] { handleDelete(); }); + // Move and Rename endpoints (stubs) + server->on("/move", HTTP_POST, [this] { handleMove(); }); + server->on("/rename", HTTP_POST, [this] { handleRename(); }); + server->onNotFound([this] { handleNotFound(); }); Serial.printf("[%lu] [WEB] [MEM] Free heap after route setup: %d bytes\n", millis(), ESP.getFreeHeap()); @@ -787,6 +792,89 @@ void CrossPointWebServer::handleDelete() const { } } +void CrossPointWebServer::handleMove() const { + if (!server->hasArg("oldPath") || !server->hasArg("newPath")) { + server->send(400, "text/plain", "Missing oldPath or newPath"); + return; + } + + String oldPath = server->arg("oldPath"); + String newPath = server->arg("newPath"); + + if (oldPath.isEmpty() || newPath.isEmpty() || oldPath == "/" || newPath == "/") { + server->send(400, "text/plain", "Invalid paths"); + return; + } + + if (!oldPath.startsWith("/")) oldPath = "/" + oldPath; + if (!newPath.startsWith("/")) newPath = "/" + newPath; + + if (!SdMan.exists(oldPath.c_str())) { + server->send(404, "text/plain", "Source not found"); + return; + } + + if (SdMan.exists(newPath.c_str())) { + server->send(400, "text/plain", "Destination already exists"); + return; + } + + // Migrate cache first (or parts of it if it's a directory) + BookCacheManager::migrateCache(oldPath, newPath); + + if (SdMan.rename(oldPath.c_str(), newPath.c_str())) { + Serial.printf("[%lu] [WEB] Moved %s to %s\n", millis(), oldPath.c_str(), newPath.c_str()); + server->send(200, "text/plain", "Moved successfully"); + } else { + server->send(500, "text/plain", "Move failed"); + } +} + +void CrossPointWebServer::handleRename() const { + if (!server->hasArg("oldPath") || !server->hasArg("newPath")) { + server->send(400, "text/plain", "Missing oldPath or newPath"); + return; + } + + String oldPath = server->arg("oldPath"); + String newPath = server->arg("newPath"); + + if (oldPath.isEmpty() || newPath.isEmpty() || oldPath == "/" || newPath == "/") { + server->send(400, "text/plain", "Invalid paths"); + return; + } + + if (!oldPath.startsWith("/")) oldPath = "/" + oldPath; + if (!newPath.startsWith("/")) newPath = "/" + newPath; + + // Security check: prevent renaming system files + if (oldPath.substring(oldPath.lastIndexOf('/') + 1).startsWith(".") || + newPath.substring(newPath.lastIndexOf('/') + 1).startsWith(".")) { + server->send(403, "text/plain", "Cannot rename system files"); + return; + } + + if (!SdMan.exists(oldPath.c_str())) { + server->send(404, "text/plain", "Source not found"); + return; + } + + if (SdMan.exists(newPath.c_str())) { + server->send(400, "text/plain", "Destination already exists"); + return; + } + + // Migrate cache + BookCacheManager::migrateCache(oldPath, newPath); + + if (SdMan.rename(oldPath.c_str(), newPath.c_str())) { + Serial.printf("[%lu] [WEB] Renamed %s to %s\n", millis(), oldPath.c_str(), newPath.c_str()); + server->send(200, "text/plain", "Renamed successfully"); + } else { + server->send(500, "text/plain", "Rename failed"); + } +} + // WebSocket callback trampoline void CrossPointWebServer::wsEventCallback(uint8_t num, WStype_t type, uint8_t* payload, size_t length) { if (wsInstance) { diff --git a/src/network/CrossPointWebServer.h b/src/network/CrossPointWebServer.h index 36030292..cbd4dfd7 100644 --- a/src/network/CrossPointWebServer.h +++ b/src/network/CrossPointWebServer.h @@ -78,4 +78,6 @@ class CrossPointWebServer { void handleUploadPost() const; void handleCreateFolder() const; void handleDelete() const; + void handleMove() const; + void handleRename() const; }; diff --git a/src/network/html/FilesPage.html b/src/network/html/FilesPage.html index bfdbe3cc..41715a3a 100644 --- a/src/network/html/FilesPage.html +++ b/src/network/html/FilesPage.html @@ -1,5 +1,6 @@ + @@ -7,21 +8,24 @@ + - - -