Skip to content

Commit

Permalink
Updated Water Contract Type controller to add delete functionality (#866
Browse files Browse the repository at this point in the history
)

Added delete functionality to Water Contract Type controller
  • Loading branch information
zack-rma authored Sep 23, 2024
1 parent adb424e commit 7f3ebaf
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 11 deletions.
2 changes: 2 additions & 0 deletions cwms-data-api/src/main/java/cwms/cda/ApiServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
import cwms.cda.api.watersupply.WaterContractDeleteController;
import cwms.cda.api.watersupply.WaterContractTypeCatalogController;
import cwms.cda.api.watersupply.WaterContractTypeCreateController;
import cwms.cda.api.watersupply.WaterContractTypeDeleteController;
import cwms.cda.api.watersupply.WaterContractUpdateController;
import cwms.cda.api.watersupply.WaterPumpDisassociateController;
import cwms.cda.api.watersupply.WaterUserCatalogController;
Expand Down Expand Up @@ -627,6 +628,7 @@ private void addWaterContractHandlers(String path, RouteRole[] requiredRoles) {
private void addWaterContractTypeHandlers(String path, RouteRole[] requiredRoles) {
post(path, new WaterContractTypeCreateController(metrics), requiredRoles);
get(path, new WaterContractTypeCatalogController(metrics));
delete(path + "/{display-value}", new WaterContractTypeDeleteController(metrics), requiredRoles);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import cwms.cda.data.dto.LookupType;
import cwms.cda.formatters.ContentType;
import cwms.cda.formatters.Formats;
import io.javalin.core.util.Header;
import io.javalin.http.Context;
import io.javalin.http.Handler;
import io.javalin.plugin.openapi.annotations.HttpMethod;
Expand Down Expand Up @@ -86,7 +85,7 @@ public void handle(@NotNull Context ctx) {
ctx.contentType(contentType.toString());
LookupType contractType = Formats.parseContent(contentType, ctx.body(), LookupType.class);
WaterContractDao contractDao = getContractDao(dsl);
contractDao.storeWaterContractTypes(contractType, failIfExists);
contractDao.storeWaterContractType(contractType, failIfExists);
ctx.status(HttpServletResponse.SC_CREATED).json("Contract type successfully stored to CWMS.");
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
*
* MIT License
*
* Copyright (c) 2024 Hydrologic Engineering Center
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE
* SOFTWARE.
*/

package cwms.cda.api.watersupply;

import static cwms.cda.api.Controllers.DELETE;
import static cwms.cda.api.Controllers.OFFICE;
import static cwms.cda.data.dao.JooqDao.getDslContext;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import cwms.cda.data.dao.watersupply.WaterContractDao;
import cwms.cda.data.dto.LookupType;
import cwms.cda.formatters.ContentType;
import cwms.cda.formatters.Formats;
import io.javalin.http.Context;
import io.javalin.http.Handler;
import io.javalin.plugin.openapi.annotations.HttpMethod;
import io.javalin.plugin.openapi.annotations.OpenApi;
import io.javalin.plugin.openapi.annotations.OpenApiParam;
import javax.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;


public final class WaterContractTypeDeleteController extends WaterSupplyControllerBase implements Handler {

private static final String DISPLAY_VALUE = "display-value";

public WaterContractTypeDeleteController(MetricRegistry metrics) {
waterMetrics(metrics);
}

@OpenApi(
pathParams = {
@OpenApiParam(name = OFFICE, required = true, description = "The office associated with "
+ "the contract type to delete"),
@OpenApiParam(name = DISPLAY_VALUE, required = true, description = "The location associated with "
+ "the contract type to delete"),
},
description = "Delete a water contract type",
method = HttpMethod.DELETE,
path = "/projects/{office}/contract-types/{display-value}",
tags = {TAG}
)

@Override
public void handle(@NotNull Context ctx) {
try (Timer.Context ignored = markAndTime(DELETE)) {
DSLContext dsl = getDslContext(ctx);
String office = ctx.pathParam(OFFICE);
String displayValue = ctx.pathParam(DISPLAY_VALUE);
String formatHeader = ctx.req.getContentType();
ContentType contentType = Formats.parseHeader(formatHeader, LookupType.class);
ctx.contentType(contentType.toString());
WaterContractDao dao = new WaterContractDao(dsl);
dao.deleteWaterContractType(office, displayValue);
ctx.status(HttpServletResponse.SC_NO_CONTENT).json("Contract type successfully deleted from CWMS.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import cwms.cda.api.errors.NotFoundException;
import cwms.cda.data.dao.JooqDao;
import cwms.cda.data.dao.LookupTypeDao;
import cwms.cda.data.dao.location.kind.LocationUtil;
import cwms.cda.data.dto.CwmsId;
import cwms.cda.data.dto.LookupType;
Expand Down Expand Up @@ -176,7 +177,17 @@ public void deleteWaterContract(WaterUserContract contract, DeleteMethod deleteA
});
}

public void storeWaterContractTypes(LookupType lookupType,
public void deleteWaterContractType(String office, String displayValue) {
connection(dsl, c -> {
setOffice(c, office);
LookupTypeDao lookupTypeDao = new LookupTypeDao(DSL.using(c));
String category = "AT_WS_CONTRACT_TYPE";
String prefix = "WS_CONTRACT_TYPE";
lookupTypeDao.deleteLookupType(category, prefix, office, displayValue);
});
}

public void storeWaterContractType(LookupType lookupType,
boolean failIfExists) {
connection(dsl, c -> {
setOffice(c, lookupType.getOfficeId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,39 +29,53 @@
import static cwms.cda.data.dao.DaoTest.getDslContext;
import static cwms.cda.security.KeyAccessManager.AUTH_HEADER;
import static io.restassured.RestAssured.given;
import static java.lang.String.format;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;

import cwms.cda.api.errors.NotFoundException;
import cwms.cda.data.dao.LookupTypeDao;
import cwms.cda.data.dto.LookupType;
import cwms.cda.formatters.Formats;
import cwms.cda.formatters.json.JsonV1;
import cwms.cda.helpers.DTOMatch;
import fixtures.CwmsDataApiSetupCallback;
import fixtures.TestAccounts;
import io.restassured.filter.log.LogDetail;
import mil.army.usace.hec.test.database.CwmsDatabaseContainer;
import org.jooq.DSLContext;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import javax.servlet.http.HttpServletResponse;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;


@Tag("integration")
class WaterContractTypeCreateControllerTestIT extends DataApiTestIT {
class WaterContractTypeControllerTestIT extends DataApiTestIT {
private static final String OFFICE_ID = "SWT";
private static final LookupType CONTRACT_TYPE;
public static final Logger LOGGER =
Logger.getLogger(WaterContractTypeControllerTestIT.class.getName());
static {
CONTRACT_TYPE = new LookupType.Builder().withActive(true).withOfficeId(OFFICE_ID)
.withDisplayValue("TEST Contract Type").withTooltip("TEST LOOKUP").build();
}

@AfterEach
void cleanup() throws SQLException {
cleanupType();
}

@Test
void test_create_get_WaterContractType() throws Exception {
// Test Structure
// 1) Create a WaterContractType
// 2) Get the WaterContractType, assert it exists
// 3) Cleanup

TestAccounts.KeyUser user = TestAccounts.KeyUser.SWT_NORMAL;
String json = JsonV1.buildObjectMapper().writeValueAsString(CONTRACT_TYPE);
Expand Down Expand Up @@ -101,18 +115,101 @@ void test_create_get_WaterContractType() throws Exception {
.body("[0].tooltip", equalTo(CONTRACT_TYPE.getTooltip()))
.body("[0].active", equalTo(CONTRACT_TYPE.getActive()))
;
}

// cleanup
cleanupType();
@Test
void test_store_delete_WaterContractType() throws Exception {
// Test Structure
// 1) Create a WaterContractType
// 2) Get the WaterContractType, assert it exists
// 3) Delete the WaterContractType
// 4) Get the WaterContractType, assert it does not exist

TestAccounts.KeyUser user = TestAccounts.KeyUser.SWT_NORMAL;
String json = JsonV1.buildObjectMapper().writeValueAsString(CONTRACT_TYPE);

// create water contract type
given()
.log().ifValidationFails(LogDetail.ALL, true)
.contentType(Formats.JSONV1)
.body(json)
.queryParam("fail-if-exists", false)
.header(AUTH_HEADER, user.toHeaderValue())
.when()
.redirects().follow(true)
.redirects().max(3)
.post("/projects/" + OFFICE_ID + "/contract-types")
.then()
.log().ifValidationFails(LogDetail.ALL, true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_CREATED))
;

// get water contract type and assert that it exists
given()
.log().ifValidationFails(LogDetail.ALL, true)
.contentType(Formats.JSONV1)
.header(AUTH_HEADER, user.toHeaderValue())
.when()
.redirects().follow(true)
.redirects().max(3)
.get("/projects/" + OFFICE_ID + "/contract-types")
.then()
.log().ifValidationFails(LogDetail.ALL, true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_OK))
.body("[0].office-id", equalTo(OFFICE_ID))
.body("[0].display-value", equalTo(CONTRACT_TYPE.getDisplayValue()))
.body("[0].tooltip", equalTo(CONTRACT_TYPE.getTooltip()))
.body("[0].active", equalTo(CONTRACT_TYPE.getActive()))
;

// delete water contract type
given()
.log().ifValidationFails(LogDetail.ALL, true)
.contentType(Formats.JSONV1)
.header(AUTH_HEADER, user.toHeaderValue())
.when()
.redirects().follow(true)
.redirects().max(3)
.delete("/projects/" + OFFICE_ID + "/contract-types/" + CONTRACT_TYPE.getDisplayValue())
.then()
.log().ifValidationFails(LogDetail.ALL, true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_NO_CONTENT))
;

// get water contract type and assert that it does not exist
List<LookupType> results = Arrays.asList(given()
.log().ifValidationFails(LogDetail.ALL, true)
.contentType(Formats.JSONV1)
.header(AUTH_HEADER, user.toHeaderValue())
.when()
.redirects().follow(true)
.redirects().max(3)
.get("/projects/" + OFFICE_ID + "/contract-types")
.then()
.log().ifValidationFails(LogDetail.ALL, true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_OK))
.extract().body().as(LookupType[].class))
;
DTOMatch.assertDoesNotContainDto(results, CONTRACT_TYPE,
(i, s) -> i.getDisplayValue().equalsIgnoreCase(s.getDisplayValue()), "Contract Type not deleted");
}

private void cleanupType() throws SQLException {
CwmsDatabaseContainer<?> databaseLink = CwmsDataApiSetupCallback.getDatabaseLink();
databaseLink.connection(c -> {
DSLContext ctx = getDslContext(c, OFFICE_ID);
LookupTypeDao lookupTypeDao = new LookupTypeDao(ctx);
lookupTypeDao.deleteLookupType("AT_WS_CONTRACT_TYPE", "WS_CONTRACT_TYPE",
CONTRACT_TYPE.getOfficeId(), CONTRACT_TYPE.getDisplayValue());
try {

lookupTypeDao.deleteLookupType("AT_WS_CONTRACT_TYPE", "WS_CONTRACT_TYPE",
CONTRACT_TYPE.getOfficeId(), CONTRACT_TYPE.getDisplayValue());
} catch (NotFoundException e) {
LOGGER.log(Level.CONFIG, format("Cleanup failed to delete lookup type: %s", e.getMessage()));
}
}, CwmsDataApiSetupCallback.getWebUser());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ static void setUp() throws Exception {
projectDao.store(project1, true);
projectDao.store(project2, true);
waterContractDao.storeWaterUser(CONTRACT.getWaterUser(), false);
waterContractDao.storeWaterContractTypes(CONTRACT.getContractType(), false);
waterContractDao.storeWaterContractType(CONTRACT.getContractType(), false);
waterContractDao.storeWaterUser(CONTRACT_NO_PUMP.getWaterUser(), false);
} catch (IOException e) {
throw new RuntimeException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,28 @@ void cleanup() throws SQLException {
}, CwmsDataApiSetupCallback.getWebUser());
}

@Test
void testStoreAndDeleteWaterContractType() throws Exception {
LookupType contractType = new LookupType.Builder()
.withTooltip("Test Tooltip Delete")
.withActive(true)
.withDisplayValue("Test Display Value Delete")
.withOfficeId(OFFICE_ID).build();
CwmsDatabaseContainer<?> db = CwmsDataApiSetupCallback.getDatabaseLink();
db.connection(c -> {
DSLContext ctx = getDslContext(c, OFFICE_ID);
WaterContractDao dao = new WaterContractDao(ctx);
dao.storeWaterContractType(contractType, false);
List<LookupType> retrievedType = dao.getAllWaterContractTypes(OFFICE_ID);
DTOMatch.assertContainsDto(retrievedType, contractType, WaterContractDaoTestIT::typeMatches,
DTOMatch::assertMatch, "Contract Type not stored");
dao.deleteWaterContractType(contractType.getOfficeId(), contractType.getDisplayValue());
retrievedType = dao.getAllWaterContractTypes(OFFICE_ID);
DTOMatch.assertDoesNotContainDto(retrievedType, contractType, WaterContractDaoTestIT::typeMatches,
"Contract Type not deleted");
}, CwmsDataApiSetupCallback.getWebUser());
}

@Test
void testStoreAndRetrieveWaterUserList() throws Exception {
CwmsDatabaseContainer<?> db = CwmsDataApiSetupCallback.getDatabaseLink();
Expand Down Expand Up @@ -243,7 +265,7 @@ void testStoreAndRetrieveWaterContractType() throws Exception {
.withActive(true)
.withDisplayValue("Test Display Value")
.withOfficeId(OFFICE_ID).build();
dao.storeWaterContractTypes(contractType, false);
dao.storeWaterContractType(contractType, false);
List<LookupType> results = dao.getAllWaterContractTypes(OFFICE_ID);
DTOMatch.assertMatch(contractType, results.get(0));
}, CwmsDataApiSetupCallback.getWebUser());
Expand Down Expand Up @@ -356,6 +378,13 @@ void testRemovePumpFromContract() throws Exception {
}, CwmsDataApiSetupCallback.getWebUser());
}

private static boolean typeMatches(LookupType type, LookupType other) {
return type.getTooltip().equals(other.getTooltip()) &&
type.getDisplayValue().equals(other.getDisplayValue()) &&
type.getOfficeId().equals(other.getOfficeId()) &&
type.getActive() == other.getActive();
}

private static WaterUser buildTestWaterUser(String entityName) {
return new WaterUser.Builder().withEntityName(entityName).withProjectId(new CwmsId.Builder()
.withName(testLocation.getName())
Expand Down

0 comments on commit 7f3ebaf

Please sign in to comment.