diff --git a/src/main/java/org/qortal/api/resource/ArbitraryResource.java b/src/main/java/org/qortal/api/resource/ArbitraryResource.java index 68a759db..2bfd8452 100644 --- a/src/main/java/org/qortal/api/resource/ArbitraryResource.java +++ b/src/main/java/org/qortal/api/resource/ArbitraryResource.java @@ -349,12 +349,11 @@ public class ArbitraryResource { ) public String post(@PathParam("service") String serviceString, @PathParam("name") String name, - @QueryParam("identifier") String identifier, String path) { Security.checkApiCallAllowed(request); // TODO: automatic PUT/PATCH - return this.upload(Method.PUT, Service.valueOf(serviceString), name, identifier, path); + return this.upload(Method.PUT, Service.valueOf(serviceString), name, null, path); } @PUT @@ -385,11 +384,10 @@ public class ArbitraryResource { ) public String put(@PathParam("service") String serviceString, @PathParam("name") String name, - @QueryParam("identifier") String identifier, String path) { Security.checkApiCallAllowed(request); - return this.upload(Method.PUT, Service.valueOf(serviceString), name, identifier, path); + return this.upload(Method.PUT, Service.valueOf(serviceString), name, null, path); } @PATCH @@ -421,10 +419,117 @@ public class ArbitraryResource { ) public String patch(@PathParam("service") String serviceString, @PathParam("name") String name, - @QueryParam("identifier") String identifier, String path) { Security.checkApiCallAllowed(request); + return this.upload(Method.PATCH, Service.valueOf(serviceString), name, null, path); + } + + + @POST + @Path("/{service}/{name}/{identifier}") + @Operation( + summary = "Build raw, unsigned, ARBITRARY transaction, based on a user-supplied path", + description = "A POST transaction automatically selects a PUT or PATCH method based on the data supplied", + requestBody = @RequestBody( + required = true, + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string", example = "/Users/user/Documents/MyDirectoryOrFile" + ) + ) + ), + responses = { + @ApiResponse( + description = "raw, unsigned, ARBITRARY transaction encoded in Base58", + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string" + ) + ) + ) + } + ) + public String post(@PathParam("service") String serviceString, + @PathParam("name") String name, + @PathParam("identifier") String identifier, + String path) { + Security.checkApiCallAllowed(request); + + // TODO: automatic PUT/PATCH + return this.upload(Method.PUT, Service.valueOf(serviceString), name, identifier, path); + } + + @PUT + @Path("/{service}/{name}/{identifier}") + @Operation( + summary = "Build raw, unsigned, ARBITRARY transaction, based on a user-supplied path, using the PUT method", + description = "A PUT transaction replaces the data held for this name and service in its entirety.", + requestBody = @RequestBody( + required = true, + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string", example = "/Users/user/Documents/MyDirectoryOrFile" + ) + ) + ), + responses = { + @ApiResponse( + description = "raw, unsigned, ARBITRARY transaction encoded in Base58", + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string" + ) + ) + ) + } + ) + public String put(@PathParam("service") String serviceString, + @PathParam("name") String name, + @PathParam("identifier") String identifier, + String path) { + Security.checkApiCallAllowed(request); + + return this.upload(Method.PUT, Service.valueOf(serviceString), name, identifier, path); + } + + @PATCH + @Path("/{service}/{name}/{identifier}") + @Operation( + summary = "Build raw, unsigned, ARBITRARY transaction, based on a user-supplied path, using the PATCH method", + description = "A PATCH transaction calculates the delta between the current state on the on-chain state, " + + "and then publishes only the differences.", + requestBody = @RequestBody( + required = true, + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string", example = "/Users/user/Documents/MyDirectoryOrFile" + ) + ) + ), + responses = { + @ApiResponse( + description = "raw, unsigned, ARBITRARY transaction encoded in Base58", + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string" + ) + ) + ) + } + ) + public String patch(@PathParam("service") String serviceString, + @PathParam("name") String name, + @PathParam("identifier") String identifier, + String path) { + Security.checkApiCallAllowed(request); + return this.upload(Method.PATCH, Service.valueOf(serviceString), name, identifier, path); } diff --git a/tools/qdata b/tools/qdata index 8b562324..b4a439aa 100755 --- a/tools/qdata +++ b/tools/qdata @@ -8,10 +8,16 @@ if [ -z "$*" ]; then echo "Usage:" echo echo "Host/update data:" - echo "qdata [PUT/PATCH] [service] [name] [dirpath]" + echo "qdata [PUT/PATCH] [service] [name] [dirpath] " echo echo "Fetch data:" - echo "qdata GET [service] [name] [filepath] " + echo "qdata GET [service] [name] " + echo + echo "Notes:" + echo "- When requesting a resource, please supply the relative path to a file within the data structure," + echo " or 'default' to indicate a file with no identifier." + echo "- The same applies when specifying the relative path to a file within the data structure; use 'default'" + echo " to indicate a single file resource." echo exit fi @@ -33,6 +39,7 @@ fi if [[ "${method}" == "PUT" || "${method}" == "PATCH" ]]; then directory=$4 + identifier=$5 if [ -z "${directory}" ]; then echo "Error: missing directory"; exit @@ -42,7 +49,7 @@ if [[ "${method}" == "PUT" || "${method}" == "PATCH" ]]; then fi echo "Creating transaction - this can take a while..." - tx_data=$(curl --silent --insecure -X ${method} "http://${host}:${port}/arbitrary/${service}/${name}" -d "${directory}") + tx_data=$(curl --silent --insecure -X ${method} "http://${host}:${port}/arbitrary/${service}/${name}/${identifier}" -d "${directory}") if [[ "${tx_data}" == *"error"* || "${tx_data}" == *"ERROR"* ]]; then echo "${tx_data}"; exit fi @@ -63,18 +70,29 @@ if [[ "${method}" == "PUT" || "${method}" == "PATCH" ]]; then fi elif [[ "${method}" == "GET" ]]; then - filepath=$4 - rebuild=$5 - - if [ -z "${filepath}" ]; then - echo "Error: missing filepath. Please supply the relative path to a file within the data structure."; exit - fi + identifier=$4 + filepath=$5 + rebuild=$6 if [ -z "${rebuild}" ]; then rebuild="false" fi - response=$(curl --silent --insecure -X GET "http://${host}:${port}/arbitrary/${service}/${name}?rebuild=${rebuild}&filepath=${filepath}") + # Handle default + if [[ "${identifier}" == "default" ]]; then + identifier="" + fi + if [[ "${filepath}" == "default" ]]; then + filepath="" + fi + + # We use a different API depending on whether or not an identifier is supplied + if [ -n "${identifier}" ]; then + response=$(curl --silent --insecure -X GET "http://${host}:${port}/arbitrary/${service}/${name}/${identifier}?rebuild=${rebuild}&filepath=${filepath}") + else + response=$(curl --silent --insecure -X GET "http://${host}:${port}/arbitrary/${service}/${name}?rebuild=${rebuild}&filepath=${filepath}") + fi + if [ -z "${response}" ]; then echo "Empty response from ${host}:${port}" fi