From 09893af60911ca959e703c50b4a29a7c118a9368 Mon Sep 17 00:00:00 2001 From: zack-rma Date: Tue, 7 Jul 2026 13:54:05 -0700 Subject: [PATCH] Initial update to ratings endpoint to support passing retrieved data into create endpoint --- .../cwms/cda/data/dao/JsonRatingUtils.java | 60 ++++++++- .../java/cwms/cda/data/dao/RatingSetDao.java | 8 +- .../cwms/cda/data/rating/remove_office.xsl | 12 ++ .../api/rating/RatingsControllerTestIT.java | 39 ++++++ .../cwms/cda/data/dto/rating/rating_post.json | 126 ++++++++++++++++++ 5 files changed, 240 insertions(+), 5 deletions(-) create mode 100644 cwms-data-api/src/test/resources/cwms/cda/data/dto/rating/rating_post.json diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/JsonRatingUtils.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/JsonRatingUtils.java index 8996891c01..6532264cc9 100644 --- a/cwms-data-api/src/main/java/cwms/cda/data/dao/JsonRatingUtils.java +++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/JsonRatingUtils.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import hec.data.RatingException; import hec.data.cwmsRating.RatingSet; @@ -54,15 +56,67 @@ public static String jsonToXml(String json) throws IOException, TransformerExcep ObjectMapper om = new ObjectMapper(); JsonNode jsonNode = om.readTree(json); - + ObjectWriter writer; XmlMapper mapper = new XmlMapper(); - ObjectWriter writer = mapper.writer() - .withRootName("ratings"); + JsonNode ratings = jsonNode.findPath("ratings"); + writer = mapper.writer() + .withRootName("ratings"); + if (!ratings.isEmpty()) { + jsonNode = transformJsonStructure(ratings); + } String xml = writer.writeValueAsString(jsonNode); return cleanupXml(xml); } + private static JsonNode transformJsonStructure(JsonNode ratingInput) { + String ratingSpecs = "rating-specs"; + String simpleRating = "simple-rating"; + String ratingTemplates = "rating-templates"; + String ratings = "ratings"; + String name = "name"; + String parametersString = "parameters-string"; + ObjectMapper mapper = new ObjectMapper(); + ObjectNode transformed = mapper.createObjectNode(); + + if (ratingInput.has(ratingSpecs)) { + JsonNode ratingSpec = ratingInput.get(ratingSpecs).get(0); + ObjectNode temp = mapper.createObjectNode(); + ratingSpec.forEachEntry(temp::set); + if (temp.has("name")) { + temp.set("rating-spec-id", temp.get("name")); + temp.remove("name"); + } + temp.set("active", JsonNodeFactory.instance.booleanNode(true)); + transformed.set("rating-spec", temp); + } + if (ratingInput.has(ratingTemplates)) { + JsonNode ratingTemplate = ratingInput.get(ratingTemplates).get(0); + ObjectNode temp = mapper.createObjectNode(); + ratingTemplate.forEachEntry(temp::set); + if (temp.has(parametersString)) { + temp.set("parameters-id", temp.get(parametersString)); + temp.remove(parametersString); + } + if (temp.has(name)) { + temp.set("template-id", temp.get(name)); + temp.remove(name); + } + transformed.set("rating-template", temp); + } + if (ratingInput.has(ratings) && ratingInput.get(ratings).get(0).has(simpleRating)) { + JsonNode rating = ratingInput.get(ratings).get(0).get(simpleRating); + ObjectNode temp = mapper.createObjectNode(); + rating.forEachEntry(temp::set); + if (temp.has(name)) { + temp.set("rating-spec-id", temp.get(name)); + temp.remove(name); + } + transformed.set(simpleRating, temp); + } + return transformed; + } + private static String cleanupXml(String xml) throws TransformerException { // Doing this in steps b/c I'm not good enough at xslt to make it happen at once. diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/RatingSetDao.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/RatingSetDao.java index 48309a6220..2580c44d28 100644 --- a/cwms-data-api/src/main/java/cwms/cda/data/dao/RatingSetDao.java +++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/RatingSetDao.java @@ -28,7 +28,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import cwms.cda.data.dto.VerticalDatumInfo; -import cwms.cda.data.dto.rating.RatingSpec; import hec.data.RatingException; import hec.data.cwmsRating.RatingSet; import java.io.IOException; @@ -36,7 +35,6 @@ import java.sql.Timestamp; import java.time.Instant; import java.util.List; - import mil.army.usace.hec.cwms.rating.io.jdbc.ConnectionProvider; import mil.army.usace.hec.cwms.rating.io.jdbc.RatingJdbcFactory; import org.jetbrains.annotations.Nullable; @@ -66,6 +64,12 @@ private static String extractOfficeId(String ratingSet) throws JsonProcessingExc if (!values.isEmpty()) { //Getting the last instance since the order is template, spec, rating office = values.get(values.size() - 1).textValue(); + } else { + values = node.findValues("office"); + if (!values.isEmpty()) { + //Getting the last instance since the order is template, spec, rating + office = values.get(values.size() - 1).textValue(); + } } return office; } diff --git a/cwms-data-api/src/main/resources/cwms/cda/data/rating/remove_office.xsl b/cwms-data-api/src/main/resources/cwms/cda/data/rating/remove_office.xsl index 0b900f70e8..230921319c 100644 --- a/cwms-data-api/src/main/resources/cwms/cda/data/rating/remove_office.xsl +++ b/cwms-data-api/src/main/resources/cwms/cda/data/rating/remove_office.xsl @@ -18,9 +18,21 @@ + + + + + + + + + + + + diff --git a/cwms-data-api/src/test/java/cwms/cda/api/rating/RatingsControllerTestIT.java b/cwms-data-api/src/test/java/cwms/cda/api/rating/RatingsControllerTestIT.java index e97f4dd7d5..61d605b38d 100644 --- a/cwms-data-api/src/test/java/cwms/cda/api/rating/RatingsControllerTestIT.java +++ b/cwms-data-api/src/test/java/cwms/cda/api/rating/RatingsControllerTestIT.java @@ -546,5 +546,44 @@ void test_1206_rating_create_xml() throws IOException { .statusCode(is(HttpServletResponse.SC_CREATED)); } + @Test + void test_1758_rating_post() throws IOException { + TestAccounts.KeyUser user = TestAccounts.KeyUser.SPK_NORMAL; + String ratingId = "FSMI.Stage;Flow.EXSA.PRODUCTION"; + ratingId = ratingId.replaceAll("FSMI", EXISTING_LOC); + String body = readResourceFile("cwms/cda/data/dto/rating/rating_post.json"); + body = body.replaceAll("FSMI", EXISTING_LOC); + // Create the set + given() + .log().ifValidationFails(LogDetail.ALL,true) + .contentType(Formats.JSONV2) + .accept(Formats.JSONV2) + .body(body) + .header("Authorization", user.toHeaderValue()) + .queryParam(OFFICE, SPK) + .when() + .redirects().follow(true) + .redirects().max(3) + .post("/ratings") + .then() + .log().ifValidationFails(LogDetail.ALL,true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_CREATED)); + + given() + .log().ifValidationFails(LogDetail.ALL,true) + .accept(Formats.JSONV2) + .queryParam(OFFICE, SPK) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("/ratings/" + ratingId) + .then() + .log().ifValidationFails(LogDetail.ALL,true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .contentType(is(Formats.JSONV2)) + .body("office-id", is(SPK)); + } } diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/rating/rating_post.json b/cwms-data-api/src/test/resources/cwms/cda/data/dto/rating/rating_post.json new file mode 100644 index 0000000000..cd08eb04f0 --- /dev/null +++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/rating/rating_post.json @@ -0,0 +1,126 @@ +{ + "ratings": { + "query-info": { + "time-of-query": "2026-06-01T16:52:08Z", + "process-query": "PT3.394S", + "format-output": "PT3.050S", + "requested-format": "JSON", + "requested-office-id": "SPK", + "requested-start-time": "2026-05-31T16:52:08Z", + "requested-end-time": "2026-06-01T16:52:08Z", + "requested-items": [ + { + "name": "FSMI.Stage;Flow.EXSA.PRODUCTION", + "unit": "NATIVE", + "datum": "NATIVE" + } + ], + "templates-retrieved": 1, + "total-specifications-retrieved": 1, + "unique-specifications-retrieved": 1, + "total-ratings-retrieved": 1, + "unique-ratings-retrieved": 1 + }, + "rating-templates": [ + { + "office": "SPK", + "name": "Stage;Flow.EXSA", + "parameters-string": "Stage;Flow", + "version": "EXSA", + "ind-parameters": [ + { + "name": "Stage", + "value-lookup-in-range": "LINEAR", + "value-lookup-below-range": "NEAREST", + "value-lookup-above-range": "NEAREST" + } + ], + "dep-parameter": "Flow", + "description": null + } + ], + "rating-specs": [ + { + "office": "SPK", + "name": "FSMI.Stage;Flow.EXSA.PRODUCTION", + "location": "FSMI", + "version": "PRODUCTION", + "source-agency": null, + "time-lookup-in-range": "PREVIOUS", + "time-lookup-before-first": "NEAREST", + "time-lookup-after-last": "PREVIOUS", + "rounding": { + "ind-parameters": [ + "2223456784" + ], + "dep-parameter": "2223456784" + }, + "description": "FSMI Expanded, Shift-Adjusted PRODUCTION Stream Rating" + } + ], + "ratings": [ + { + "simple-rating": { + "office": "SPK", + "name": "FSMI.Stage;Flow.EXSA.PRODUCTION", + "ind-parameters": [ + "Stage (ft)" + ], + "dep-parameter": "Flow (cfs)", + "effective-date": "2007-07-11T20:38:00Z", + "description": null, + "values": [ + [ + 17, + 114000 + ], + [ + 18.75, + 140000 + ], + [ + 20.47, + 165558 + ], + [ + 30, + 313800 + ], + [ + 30.4, + 320500 + ], + [ + 30.84, + 328800 + ], + [ + 31, + 332200 + ], + [ + 31.29, + 339300 + ], + [ + 31.4, + 342500 + ], + [ + 31.62, + 349500 + ], + [ + 32.26, + 372000 + ], + [ + 36, + 520000 + ] + ] + } + } + ] + } +} \ No newline at end of file