diff --git a/README.md b/README.md index 6adefbe..77d48f1 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,47 @@ curl -X PUT \ http://localhost:8080/upload ``` +### PUT /update + +Update the metadata for an existing object. The request must be authenticated with a valid write token. The request body must be JSON and include both a `hash` (the object's hash) and a `metadata` object. + +**Request:** +- Method: PUT +- URL: /update +- Headers: + - Authorization: Bearer + - Content-Type: application/json +- Body: +```json +{ + "hash": "", + "metadata": { + "key1": "value1", + "key2": "value2" + } +} +``` + +**Response:** +- 200 OK on success: +```json +{ + "result": "success", + "hash": "" +} +``` +- 400 Bad Request if missing fields or invalid JSON +- 404 Not Found if the object does not exist +- 401/403 if authentication fails + +**Example:** +```sh +curl -X PUT http://localhost:8080/update \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{"hash": "abc123", "metadata": {"foo": "bar"}}' +``` + ### Get a File ``` diff --git a/src/server.cpp b/src/server.cpp index 060b70b..520f77f 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -14,6 +14,7 @@ #include "compress.hpp" #include "string_utils.hpp" // Include the new utility header #include "put_handler.hpp" +#include "update_handler.hpp" // Include the new update handler header #include "utils.hpp" #include "welcome_page.hpp" @@ -106,6 +107,9 @@ Server::Server(const ServerConfig& config) // Initialize the put handler put_handler_ = std::make_unique(*this); + // Initialize the update handler + update_handler_ = std::make_unique(*this); + // Initialize rate limiter auth_rate_limiter_ = std::make_unique( config_.auth_rate_limit, @@ -183,6 +187,11 @@ void Server::setup_routes() { put_handler_->handle_put_object(req, res); }); + // Update object metadata (new endpoint) + server_.Put("/update", [this](const httplib::Request& req, httplib::Response& res) { + update_handler_->handle_update_object(req, res); + }); + // Handle PUT requests to other paths server_.Put("/(.*)", [this](const httplib::Request& req, httplib::Response& res) { res.status = 404; diff --git a/src/server.hpp b/src/server.hpp index b9dc1b2..dcb889d 100644 --- a/src/server.hpp +++ b/src/server.hpp @@ -46,6 +46,7 @@ private: httplib::Server server_; bool running_; std::unique_ptr put_handler_; + std::unique_ptr update_handler_; std::unique_ptr auth_rate_limiter_; }; diff --git a/src/update_handler.cpp b/src/update_handler.cpp new file mode 100644 index 0000000..b02e678 --- /dev/null +++ b/src/update_handler.cpp @@ -0,0 +1,65 @@ +#include "update_handler.hpp" +#include +#include + +namespace simple_object_storage { + +UpdateHandler::UpdateHandler(Server& server) : server_(server) {} + +void UpdateHandler::handle_update_object(const httplib::Request& req, httplib::Response& res) { + std::map params; + // Validate authentication and rate limit (no required query params, just auth) + if (!server_.validate_write_request(req, res, {}, params)) { + return; + } + + // Parse JSON body + nlohmann::json body; + try { + body = nlohmann::json::parse(req.body); + } catch (const nlohmann::json::parse_error& e) { + res.status = 400; + nlohmann::json response = {{"result", "error"}, {"error", "Invalid JSON body"}}; + res.set_content(response.dump(), "application/json"); + return; + } + + // Check for required fields + if (!body.contains("hash") || !body.contains("metadata")) { + res.status = 400; + nlohmann::json response = {{"result", "error"}, {"error", "Missing 'hash' or 'metadata' field in request body"}}; + res.set_content(response.dump(), "application/json"); + return; + } + + std::string hash = body["hash"].get(); + nlohmann::json new_metadata = body["metadata"]; + + // Get the object entry + dbEntry entry; + if (!server_.db_->get(hash, entry)) { + res.status = 404; + nlohmann::json response = {{"result", "error"}, {"error", "Object not found for hash: " + hash}}; + res.set_content(response.dump(), "application/json"); + return; + } + + // Prepare updated entry (keep hash and labeltags, update metadata) + dbEntry updated_entry = entry; + updated_entry.metadata = new_metadata; + // Ensure labeltags and hash are preserved in metadata + updated_entry.metadata["labeltags"] = updated_entry.labeltags; + updated_entry.metadata["hash"] = updated_entry.hash; + + if (!server_.db_->update_or_insert(updated_entry)) { + res.status = 500; + nlohmann::json response = {{"result", "error"}, {"error", "Failed to update metadata for hash: " + hash}}; + res.set_content(response.dump(), "application/json"); + return; + } + + nlohmann::json response = {{"result", "success"}, {"hash", hash}}; + res.set_content(response.dump(), "application/json"); +} + +} // namespace simple_object_storage \ No newline at end of file diff --git a/src/update_handler.hpp b/src/update_handler.hpp new file mode 100644 index 0000000..e6775c8 --- /dev/null +++ b/src/update_handler.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "server.hpp" +#include +#include + +namespace simple_object_storage { + +class UpdateHandler { +public: + explicit UpdateHandler(Server& server); + void handle_update_object(const httplib::Request& req, httplib::Response& res); +private: + Server& server_; +}; + +} // namespace simple_object_storage \ No newline at end of file diff --git a/src/welcome_page.cpp b/src/welcome_page.cpp index 241d1b6..d73aa75 100644 --- a/src/welcome_page.cpp +++ b/src/welcome_page.cpp @@ -184,6 +184,15 @@ std::string welcome_page() { + +
+

PUT /update

+

Update the metadata for an existing object. Requires authentication. Send a JSON body with hash and metadata fields.

+
{
+  "hash": "<object_hash>",
+  "metadata": { "key": "value" }
+}
+