Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cwms-data-api/src/main/java/cwms/cda/api/Controllers.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ public final class Controllers {

public static final String GROUP_ID = "group-id";
public static final String REPLACE_ASSIGNED_LOCS = "replace-assigned-locs";
public static final String REPLACE_METADATA = "replace-metadata";
public static final String REPLACE_ASSIGNED_TS = "replace-assigned-ts";
public static final String TS_IDS = "ts-ids";
public static final String IGNORE_MISSING = "ignore-missing";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ private Timer.Context markAndTime(String subject) {
+ "owning office of the category the location group belongs to "
+ "whose data is to be included in the response."),
@OpenApiParam(name = LOCATION_OFFICE_ID, description = "Specifies the "
+ "owning office of the location assigned to the location group whose data is to be included in the response."),
+ "owning office of the location assigned to the location group whose data is "
+ "to be included in the response."),
},
responses = {
@OpenApiResponse(status = STATUS_200,
Expand Down Expand Up @@ -313,6 +314,8 @@ public void create(@NotNull Context ctx) {
@OpenApiParam(name = REPLACE_ASSIGNED_LOCS, type = Boolean.class, description = "Specifies whether to "
+ "unassign all existing locations before assigning new locations specified in the content body "
+ "Default: false"),
@OpenApiParam(name = REPLACE_METADATA, type = Boolean.class, description = "Specifies whether to "
+ "replace group metadata with that specified in the content body. Default: false"),
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the "
+ "office of the user making the request. This is the office that the location, group, and category "
+ "belong to. If the group and/or category belong to the CWMS office, "
Expand All @@ -335,14 +338,18 @@ public void update(@NotNull Context ctx, @NotNull String groupId) {
LocationGroup deserialize = Formats.parseContent(contentType, body, LocationGroup.class);
boolean replaceAssignedLocs = ctx.queryParamAsClass(REPLACE_ASSIGNED_LOCS,
Boolean.class).getOrDefault(false);
boolean ignoreMissing = ctx.queryParamAsClass(IGNORE_MISSING, Boolean.class).getOrDefault(false);
boolean replaceMetadata = ctx.queryParamAsClass(REPLACE_METADATA, Boolean.class).getOrDefault(false);
LocationGroupDao locationGroupDao = new LocationGroupDao(dsl);
if (!office.equalsIgnoreCase(CWMS_OFFICE) && !groupId.equals(deserialize.getId())) {
locationGroupDao.renameLocationGroup(groupId, deserialize);
}
if (replaceAssignedLocs) {
locationGroupDao.unassignAllLocs(deserialize, office);
}
if (replaceMetadata) {
locationGroupDao.replaceWithMetadata(deserialize, replaceAssignedLocs);
}
boolean ignoreMissing = ctx.queryParamAsClass(IGNORE_MISSING, Boolean.class).getOrDefault(false);
List<CwmsId> missingLocations = locationGroupDao.assignLocs(deserialize, office, ignoreMissing);
if (missingLocations.isEmpty()) {
ctx.status(HttpServletResponse.SC_OK);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import static org.jooq.impl.DSL.count;
import static org.jooq.impl.DSL.noCondition;

import cwms.cda.api.errors.NotFoundException;
import cwms.cda.data.dto.AssignedLocation;
import cwms.cda.data.dto.CwmsId;
import cwms.cda.data.dto.LocationCategory;
Expand Down Expand Up @@ -94,7 +95,19 @@ public LocationGroupDao(DSLContext dsl) {
* @return An optional location group.
*/
public Optional<LocationGroup> getLocationGroup(@NotNull String officeId, @NotNull String categoryId,
@NotNull String groupId) {
@NotNull String groupId) {
return getLocationGroup(dsl, officeId, categoryId, groupId);
}

/**
* Get a location group by office, category, and group id.
* @param officeId The office id to use for the query.
* @param categoryId The category id to use for the query.
* @param groupId The group id to use for the query.
* @return An optional location group.
*/
public Optional<LocationGroup> getLocationGroup(@NotNull DSLContext context, @NotNull String officeId,
@NotNull String categoryId, @NotNull String groupId) {
officeId = officeId.toUpperCase();

Condition joinCondition;
Expand All @@ -109,7 +122,7 @@ public Optional<LocationGroup> getLocationGroup(@NotNull String officeId, @NotNu
.and(catGroupView.GRP_DB_OFFICE_ID.in(CWMS, officeId))
.and(catGroupView.CAT_DB_OFFICE_ID.in(CWMS, officeId));

LocationGroup locGroup = buildQuery(whereCondition, joinCondition)
LocationGroup locGroup = buildQuery(whereCondition, joinCondition, context)
.fetchSize(DEFAULT_FETCH_SIZE)
.fetchOne(mapToLocationGroup);

Expand Down Expand Up @@ -509,6 +522,40 @@ public List<CwmsId> create(LocationGroup group, boolean allowPartialAssignment)
});
}

/**
* Replace a stored location group with a new group, storing the new group's metadata
* @param group The new group to replace the old one with
* @param replaceAssignedLocs If true, replace the assigned locations with the new group's assigned locations
*/
public void replaceWithMetadata(LocationGroup group, boolean replaceAssignedLocs) {
String office = group.getOfficeId();
String categoryId = group.getLocationCategory().getId();
String groupId = group.getId();
connection(dsl, conn -> {
DSLContext dslContext = getDslContext(conn, office);
dslContext.transaction((Configuration trx) -> {
DSLContext transactionContext = trx.dsl();
Optional<LocationGroup> oldGroup = getLocationGroup(transactionContext, office, categoryId, groupId);
if (oldGroup.isPresent()) {
Configuration config = transactionContext.configuration();
CWMS_LOC_PACKAGE.call_UNASSIGN_LOC_GROUP(config,
categoryId, groupId, null, "T", office);
CWMS_LOC_PACKAGE.call_DELETE_LOC_GROUP__2(config, categoryId,
groupId, "F", office);
LocationGroup newGroup = new LocationGroup(group, oldGroup.get().getAssignedLocations());
CWMS_LOC_PACKAGE.call_CREATE_LOC_GROUP2(config, categoryId,
newGroup.getId(), newGroup.getDescription(), newGroup.getOfficeId(),
newGroup.getSharedLocAliasId(), newGroup.getSharedRefLocationId());
if (!replaceAssignedLocs) {
assignLocs(trx, newGroup, office);
}
} else {
throw new NotFoundException("Location Group " + categoryId + "/" + groupId + " not found");
}
});
});
}

@NotNull
private static LOC_ALIAS_TYPE3 convertToLocAliasType(AssignedLocation a) {
BigDecimal attribute = toBigDecimal(a.getAttribute());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,105 @@ void test_rename_group(String format) throws Exception {
.statusCode(is(HttpServletResponse.SC_NO_CONTENT));
}

@ParameterizedTest
@ValueSource(strings = {Formats.JSON, Formats.DEFAULT})
void test_update_group_metadata(String format) throws Exception {
// validate that we can update the group aliasID, description, and loc ref
String officeId = user.getOperatingOffice();
String locationId = "LocGroupMetaTest";
createLocation(locationId, true, officeId);
AssignedLocation assignLoc = new AssignedLocation(locationId, officeId, "AliasId", 1, locationId);
LocationCategory cat = new LocationCategory(officeId, "test_metadata_group", "IntegrationTesting");
LocationGroup group = new LocationGroup(new LocationGroup(cat, officeId, "test_rename_group", null,
null, null, null), Collections.singletonList(assignLoc));
groupsToCleanup.add(group);
categoriesToCleanup.add(cat);
ContentType contentType = Formats.parseHeader(Formats.JSON, LocationCategory.class);
String categoryXml = Formats.format(contentType, cat);
String groupXml = Formats.format(contentType, group);
//Create Category
given()
.log().ifValidationFails(LogDetail.ALL,true)
.accept(format)
.contentType(Formats.JSON)
.body(categoryXml)
.header("Authorization", user.toHeaderValue())
.when()
.redirects().follow(true)
.redirects().max(3)
.post("/location/category/")
.then()
.log().ifValidationFails(LogDetail.ALL,true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_CREATED));
//Create Group
given()
.log().ifValidationFails(LogDetail.ALL,true)
.accept(format)
.contentType(Formats.JSON)
.body(groupXml)
.header("Authorization", user.toHeaderValue())
.when()
.redirects().follow(true)
.redirects().max(3)
.post("/location/group")
.then()
.log().ifValidationFails(LogDetail.ALL,true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_CREATED));
String sharedLocAliasId = "sharedLocAliasId";
LocationGroup newGroup = new LocationGroup(cat, officeId, "test_metadata_group_new", "IntegrationTesting",
sharedLocAliasId, locationId, 123);
groupsToCleanup.add(newGroup);
String newGroupXml = Formats.format(contentType, newGroup);
//Rename Group, including metadata
given()
.log().ifValidationFails(LogDetail.ALL,true)
.accept(format)
.contentType(Formats.JSON)
.body(newGroupXml)
.header("Authorization", user.toHeaderValue())
.header(CATEGORY_ID, group.getLocationCategory().getId())
.queryParam(REPLACE_METADATA, true)
.queryParam(OFFICE, group.getOfficeId())
.when()
.redirects().follow(true)
.redirects().max(3)
.patch("/location/group/"+ group.getId())
.then()
.log().ifValidationFails(LogDetail.ALL,true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_OK));
//Read
given()
.log().ifValidationFails(LogDetail.ALL,true)
.accept(format)
.contentType(Formats.JSON)
.queryParam(OFFICE, officeId)
.queryParam(CATEGORY_ID, group.getLocationCategory().getId())
.queryParam(CATEGORY_OFFICE_ID, officeId)
.queryParam(GROUP_OFFICE_ID, officeId)
.when()
.redirects().follow(true)
.redirects().max(3)
.get("/location/group/" + newGroup.getId())
.then()
.log().ifValidationFails(LogDetail.ALL,true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_OK))
.body("office-id", equalTo(newGroup.getOfficeId()))
.body("id", equalTo(newGroup.getId()))
.body("description", equalTo(newGroup.getDescription()))
.body("location-category.office-id", equalTo(officeId))
.body("location-category.id", equalTo(group.getLocationCategory().getId()))
.body("location-category.description", equalTo(group.getLocationCategory().getDescription()))
.body("shared-loc-alias-id", equalTo(sharedLocAliasId))
.body("shared-ref-location-id", equalTo(locationId))
.body("assigned-locations[0].location-id", equalTo(locationId))
.body("assigned-locations[0].alias-id", equalTo("AliasId"))
.body("assigned-locations[0].ref-location-id", equalTo(locationId));
}

@ParameterizedTest
@ValueSource(strings = {Formats.JSON, Formats.DEFAULT})
void test_add_assigned_locs(String format) throws Exception {
Expand Down
Loading