Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MODINV-883 Set instance record as deleted #663

Merged
merged 5 commits into from
Jan 9, 2024
Merged
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 NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## 20.2.0-SNAPSHOT 2023-xx-xx
* Inventory cannot process Holdings with virtual fields ([MODINV-941](https://issues.folio.org/browse/MODINV-941))
* Set instance record as deleted ([MODINV-883](https://issues.folio.org/browse/MODINV-883))

## 20.1.0 2023-10-13
* Update status when user attempts to update shared auth record from member tenant ([MODDATAIMP-926](https://issues.folio.org/browse/MODDATAIMP-926))
Expand Down
39 changes: 28 additions & 11 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"inventory-storage.instances.item.get",
"inventory-storage.bound-with-parts.collection.get"
]
}, {
},
{
"methods": ["GET"],
"pathPattern": "/inventory/items/{id}",
"permissionsRequired": ["inventory.items.item.get"],
Expand Down Expand Up @@ -297,7 +298,8 @@
"inventory-storage.bound-with-parts.collection.get",
"users.item.get"
]
}, {
},
{
"methods": ["PUT"],
"pathPattern": "/inventory/items/{id}",
"permissionsRequired": ["inventory.items.item.put"],
Expand All @@ -313,20 +315,23 @@
"pathPattern": "/inventory/items/{id}",
"permissionsRequired": ["inventory.items.item.delete"],
"modulePermissions": ["inventory-storage.items.item.delete"]
}, {
},
{
"methods": ["DELETE"],
"pathPattern": "/inventory/items",
"permissionsRequired": ["inventory.items.collection.delete"],
"modulePermissions": ["inventory-storage.items.collection.delete"]
}, {
},
{
"methods": ["PUT"],
"pathPattern": "/inventory/holdings/{id}",
"permissionsRequired": ["inventory.holdings.item.put"],
"modulePermissions": [
"inventory-storage.holdings.item.get",
"inventory-storage.holdings.item.put"
]
}, {
},
{
"methods": ["GET"],
"pathPattern": "/inventory/instances",
"permissionsRequired": ["inventory.instances.collection.get"],
Expand All @@ -339,7 +344,8 @@
"inventory-storage.holdings.collection.get",
"inventory-storage.items.collection.get"
]
}, {
},
{
"methods": ["GET"],
"pathPattern": "/inventory/items-by-holdings-id",
"permissionsRequired": ["inventory.items.collection.get"],
Expand All @@ -358,7 +364,8 @@
"inventory-storage.instances.collection.get",
"inventory-storage.instances.item.get"
]
}, {
},
{
"methods": ["GET"],
"pathPattern": "/inventory/instances/{id}",
"permissionsRequired": ["inventory.instances.item.get"],
Expand All @@ -370,7 +377,8 @@
"inventory-storage.holdings.collection.get",
"inventory-storage.items.collection.get"
]
}, {
},
{
"methods": ["POST"],
"pathPattern": "/inventory/instances",
"permissionsRequired": ["inventory.instances.item.post"],
Expand All @@ -386,7 +394,8 @@
"inventory-storage.instance-relationships.item.put",
"inventory-storage.instance-relationships.item.delete"
]
}, {
},
{
"methods": ["PUT"],
"pathPattern": "/inventory/instances/{id}",
"permissionsRequired": ["inventory.instances.item.put"],
Expand All @@ -405,16 +414,24 @@
"inventory-storage.instance-relationships.item.put",
"inventory-storage.instance-relationships.item.delete"
]
}, {
},
{
"methods": ["DELETE"],
"pathPattern": "/inventory/instances/{id}",
"permissionsRequired": ["inventory.instances.item.delete"],
"modulePermissions": ["inventory-storage.instances.item.delete"]
}, {
},
{
"methods": ["DELETE"],
"pathPattern": "/inventory/instances",
"permissionsRequired": ["inventory.instances.collection.delete"],
"modulePermissions": ["inventory-storage.instances.collection.delete"]
},
{
"methods": ["DELETE"],
"pathPattern": "/inventory/instances/{id}/mark-deleted",
"permissionsRequired": [],
"modulePermissions": []
}
]
},
Expand Down
22 changes: 22 additions & 0 deletions ramls/inventory.raml
Original file line number Diff line number Diff line change
Expand Up @@ -368,4 +368,26 @@ resourceTypes:
get:
put:
is: [validate]
/mark-deleted:
delete:
description: Toggle the suppression state of an instance record, affecting either instance and associated MARC record if present.
responses:
204:
description: Instance marked as deleted.
404:
description: "Instance not found"
body:
text/plain:
example: "Instance with such id not found"
422:
description: "Validation error"
body:
application/json:
type: errors
500:
description: "Internal server error"
body:
text/plain:
example: "Internal server error"


29 changes: 29 additions & 0 deletions src/main/java/org/folio/inventory/resources/Instances.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public void register(Router router) {
router.get(INSTANCES_PATH + "/:id").handler(this::getById);
router.put(INSTANCES_PATH + "/:id").handler(this::update);
router.delete(INSTANCES_PATH + "/:id").handler(this::deleteById);
router.delete(INSTANCES_PATH + "/:id" + "/mark-deleted").handler(this::softDelete);
}

private void getAll(RoutingContext routingContext) {
Expand Down Expand Up @@ -302,6 +303,34 @@ private void deleteById(RoutingContext routingContext) {
FailureResponseConsumer.serverError(routingContext.response()));
}

private void softDelete(RoutingContext routingContext) {
WebContext webContext = new WebContext(routingContext);
InstanceCollection instanceCollection = storage.getInstanceCollection(webContext);
instanceCollection.findById(routingContext.request().getParam("id"),
it -> {
Instance instance = it.getResult();
if (instance != null) {
updateVisibility(instance, routingContext, instanceCollection);
if (isInstanceControlledByRecord(instance)) {
updateSuppressFromDiscoveryFlag(webContext, instance); //todo: will be replaced by soft delete by instance
}
} else {
ClientErrorResponse.notFound(routingContext.response());
}
}, FailureResponseConsumer.serverError(routingContext.response()));
}

private void updateVisibility(Instance instance, RoutingContext routingContext, InstanceCollection instanceCollection) {
instance.setDiscoverySuppress(true);
instance.setStaffSuppress(true);
instanceCollection.update(instance, v -> {
log.info("staffSuppress and discoverySuppress properties are set to true for instance {}",
instance.getId());
noContent(routingContext.response());
},
FailureResponseConsumer.serverError(routingContext.response()));
}

private void getById(RoutingContext routingContext) {
WebContext context = new WebContext(routingContext);

Expand Down
26 changes: 26 additions & 0 deletions src/test/java/api/InstancesApiExamples.java
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,32 @@ public void canDeleteAnInstance()
assertThat(getAllResponse.getJson().getInteger("totalRecords"), is(2));
}

@Test
@SneakyThrows
public void canSoftDeleteInstance() {
JsonObject instanceToDelete = createInstance(marcInstanceWithDefaultBlockedFields(UUID.randomUUID()));

URL softDeleteUrl = new URL(String.format("%s/%s/%s",
ApiRoot.instances(), instanceToDelete.getString("id"), "mark-deleted" ));

URL getByIdUrl = new URL(String.format("%s/%s",
ApiRoot.instances(), instanceToDelete.getString("id")));

final var deleteCompleted = okapiClient.delete(softDeleteUrl);

Response deleteResponse = deleteCompleted.toCompletableFuture().get(5, SECONDS);

assertThat(deleteResponse.getStatusCode(), is(204));
assertThat(deleteResponse.hasBody(), is(false));

final var getCompleted = okapiClient.get(getByIdUrl);

Response getResponse = getCompleted.toCompletableFuture().get(5, SECONDS);

assertTrue(getResponse.getJson().getBoolean("staffSuppress"));
assertTrue(getResponse.getJson().getBoolean("discoverySuppress"));
}

@Test
public void canGetAllInstances()
throws InterruptedException,
Expand Down