From 1c408db907c5798a44c211862c4e6faa18ba0e32 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Fri, 12 Nov 2021 17:42:21 +0000 Subject: [PATCH] Rework of arbitrary APIs and qdata to support identifiers qdata has reached the stage of needing parameterized arguments, but this is low priority now that we have data functionality within the UI itself. --- .../api/resource/ArbitraryResource.java | 115 +++++++++++++++++- tools/qdata | 38 ++++-- 2 files changed, 138 insertions(+), 15 deletions(-) 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