Commit 8c10b8e1 authored by Maxym Borodenko's avatar Maxym Borodenko

API v1 delete accession

parent 5f289395
......@@ -26,7 +26,6 @@ import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.genesys2.server.api.ApiBaseController;
import org.genesys2.server.api.PleaseRetryException;
import org.genesys2.server.api.model.AccessionHeaderJson;
import org.genesys2.server.exception.InvalidApiUsageException;
import org.genesys2.server.exception.NotFoundElement;
import org.genesys2.server.model.impl.FaoInstitute;
......@@ -115,7 +114,7 @@ public class AccessionUploadController {
} catch (DataAccessException | TransactionException | PersistenceException e) {
List<AccessionOpResponse> res = upsert1By1(institute, updates);
LOG.info("Processed {} accessions for {} 1by1 after {} tries in {}ms because of {}", updates.size(), instCode, tryCount + 1, stopWatch.getTime(), e.getMessage());
LOG.info("Processed {} accessions for {} 1by1 after {} tries in {}ms because of {}", updates.size(), instCode, tryCount + 1, stopWatch.getTime(), e.getMessage());
return res;
} catch (PleaseRetryException e) {
......@@ -180,7 +179,7 @@ public class AccessionUploadController {
@PreAuthorize("isAuthenticated()")
@RequestMapping(value = "/{instCode}/delete", method = { RequestMethod.POST }, consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public @ResponseBody List<AccessionOpResponse> deleteAccessions(@PathVariable("instCode") String instCode, @RequestBody List<AccessionHeaderJson> batch) throws RESTApiException {
public @ResponseBody List<AccessionOpResponse> deleteAccessions(@PathVariable("instCode") String instCode, @RequestBody ArrayNode batch) throws RESTApiException {
// User's permission to WRITE to this WIEWS institute are checked in
// BatchRESTService.
final FaoInstitute institute = instituteService.getInstitute(instCode);
......@@ -211,26 +210,24 @@ public class AccessionUploadController {
* @param batch the batch
* @return the list
*/
private List<AccessionOpResponse> deleteAccessions1by1(FaoInstitute institute, List<AccessionHeaderJson> batch) {
private List<AccessionOpResponse> deleteAccessions1by1(FaoInstitute institute, ArrayNode batch) {
LOG.info("Attempting delete 1 by 1");
final List<AccessionHeaderJson> batchOfOne = new ArrayList<AccessionHeaderJson>();
List<AccessionOpResponse> response = new ArrayList<AccessionOpResponse>();
for (AccessionHeaderJson acceJ : batch) {
final ArrayNode single = new ObjectMapper().createArrayNode();
final List<AccessionOpResponse> response = new ArrayList<AccessionOpResponse>();
for (JsonNode accn : batch) {
try {
batchOfOne.clear();
batchOfOne.add(acceJ);
AccessionOpResponse accessionResponse = uploader.deleteAccessions(institute, batchOfOne).get(0);
single.removeAll();
single.add(accn);
AccessionOpResponse accessionResponse = uploader.deleteAccessions(institute, single).get(0);
response.add(accessionResponse);
} catch (Throwable e) {
if (LOG.isInfoEnabled()) {
LOG.info("Error deleting {}: {}", acceJ.instCode, e.getMessage());
LOG.info("Error deleting {}: {}", accn.get("instituteCode"), e.getMessage());
}
AccessionOpResponse accessionResponse = new AccessionOpResponse(acceJ.instCode, acceJ.acceNumb, acceJ.genus);
AccessionOpResponse accessionResponse = new AccessionOpResponse(accn.get("instituteCode").asText(), accn.get("accessionNumber").asText(), accn.get("taxonomy").get("genus").asText());
accessionResponse.setError(getDetailedErrorMessage(e));
response.add(accessionResponse);
}
......
......@@ -31,6 +31,7 @@ import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
......@@ -172,7 +173,7 @@ public class AccessionUploader implements InitializingBean {
}
}
LOG.debug("Processsed incoming JSON for {} accessions in {}ms", updates.size(), stopWatch.getTime());
LOG.debug("Processed incoming JSON for {} accessions in {}ms", updates.size(), stopWatch.getTime());
List<Accession> existingAccessions = accessionRepository.find(! institute.hasUniqueAcceNumbs(), accessions);
LOG.debug("Have {} accessions for update and {} exist in {}ms", accessions.size(), existingAccessions.size(), stopWatch.getTime());
......@@ -675,39 +676,85 @@ public class AccessionUploader implements InitializingBean {
@Transactional(timeout = 250, isolation = Isolation.READ_UNCOMMITTED, rollbackFor = Throwable.class)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#institute, 'WRITE')")
public List<AccessionOpResponse> deleteAccessions(FaoInstitute institute, List<AccessionHeaderJson> identifiers) {
// Security check
for (int i = 0; i < identifiers.size(); i++) {
AccessionHeaderJson accession = identifiers.get(i);
if (!institute.getCode().equals(accession.instCode)) {
throw new InvalidApiUsageException("Accession does not belong to institute " + institute.getCode());
}
final ObjectMapper mapper = new ObjectMapper();
final ArrayNode arrayNode = mapper.createArrayNode();
for (AccessionHeaderJson accnJ: identifiers) {
ObjectNode rootNode = mapper.createObjectNode();
rootNode.put("instituteCode", accnJ.getHoldingInstitute());
rootNode.put("accessionNumber", accnJ.getAccessionNumber());
rootNode.put("doi", accnJ.getDoi());
ObjectNode taxonNode = mapper.createObjectNode();
taxonNode.put("genus", accnJ.getGenus());
rootNode.set("taxonomy", taxonNode);
arrayNode.add(rootNode);
}
return deleteAccessions(institute, arrayNode);
}
@Transactional(timeout = 250, isolation = Isolation.READ_UNCOMMITTED, rollbackFor = Throwable.class)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#institute, 'WRITE')")
public List<AccessionOpResponse> deleteAccessions(FaoInstitute institute, ArrayNode identifiers) {
assert (identifiers.isArray());
StopWatch stopWatch = StopWatch.createStarted();
ObjectReader reader = objectMapper.readerFor(Accession.class);
final List<Accession> toBeDeleted = new ArrayList<>(identifiers.size());
final List<AccessionOpResponse> responses = new ArrayList<>(identifiers.size());
// Require matching genus for deletion
List<Accession> existingAccessions = accessionRepository.find(true, identifiers);
List<Accession> toRemove = new ArrayList<>(identifiers.size());
List<AccessionHistoric> deleted = new ArrayList<>();
final List<Accession> toRemove = new ArrayList<>(identifiers.size());
final List<AccessionHistoric> deleted = new ArrayList<>();
for (JsonNode accn : identifiers) {
LOG.trace("Received: {}", accn);
try {
Accession accession = reader.readValue(accn);
if (accession.getInstituteCode() == null || (accession.getDoi() == null && accession.getAccessionNumber() == null)) {
throw new InvalidApiUsageException("instituteCode, accessionNumber OR doi missing in " + accn);
}
// Security check
if (!accession.getInstituteCode().equals(institute.getCode())) {
throw new InvalidApiUsageException("Accession does not belong to institute " + institute.getCode());
}
toBeDeleted.add(accession);
} catch (IOException e) {
LOG.error("Could not parse input: {}", e.getMessage(), e);
toBeDeleted.add(null); // need to match get(index) with responses and updates
AccessionOpResponse response = new AccessionOpResponse(accn.get("instituteCode").asText(), accn.get("accessionNumber").asText(), accn.get("taxonomy").get("genus").asText());
response.setResult(new UpsertResult(UpsertResult.Type.ERROR)).setError(e.getMessage());
responses.add(response);
}
}
LOG.debug("Processed incoming JSON for {} accessions in {}ms", identifiers.size(), stopWatch.getTime());
for (int i = 0; i < identifiers.size(); i++) {
final AccessionHeaderJson deletion = identifiers.get(i);
LOG.trace("Deleting: {}", deletion);
List<Accession> existingAccessions = accessionRepository.find(! institute.hasUniqueAcceNumbs(), toBeDeleted);
LOG.debug("Have {} accessions for update and {} exist in {}ms", toBeDeleted.size(), existingAccessions.size(), stopWatch.getTime());
for (Accession deletion: toBeDeleted) {
AccessionOpResponse response;
responses.add(response = new AccessionOpResponse(deletion.getHoldingInstitute(), deletion.getAccessionNumber(), deletion.getGenus()));
responses.add(response = new AccessionOpResponse(deletion.getHoldingInstitute(), deletion.getAccessionNumber(), deletion.getTaxonomy().getGenus()));
Accession accession = existingAccessions.stream()
.filter(existing -> (
existing.getInstituteCode().equals(deletion.getHoldingInstitute()) &&
existing.getAccessionNumber().equals(deletion.getAccessionNumber()) &&
existing.getTaxonomy().getGenus().equals(deletion.getGenus())
existing.getInstituteCode().equals(deletion.getHoldingInstitute()) &&
existing.getAccessionNumber().equals(deletion.getAccessionNumber()) &&
existing.getTaxonomy().getGenus().equals(deletion.getGenus())
)).findFirst().orElse(null);
if (accession == null) {
response.setResult(new UpsertResult(UpsertResult.Type.NOOP));
response.setError("Record not found");
} else {
try {
if (deletion.doi != null || accession.getDoi() != null) {
if (accession.getDoi() != null) {
throw new InvalidApiUsageException("Accessions with doi cannot be deleted");
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment