71752: /metadatafield/<exactMdString> replace with byfieldName?exactName endpoint + tests

This commit is contained in:
Marie Verdonck
2020-08-12 12:51:42 +02:00
parent 9dae6a9579
commit 75ebc887cc
4 changed files with 101 additions and 164 deletions

View File

@@ -1,68 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.model.MetadataFieldRest;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.content.MetadataField;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* This controller will handle all the incoming calls on the /api/core/metadatafields/name/<:metadata-field-full-name>
* endpoint where the metadata-field-full-name parameter can be filled in to match a specific metadata field by name
* There's always at most one metadata field per name.
* <p>
* It responds with:
* <p>
* The single metadata field if there's a match
* 404 if the metadata field doesn't exist
*
* @author Maria Verdonck (Atmire) on 17/07/2020
*/
@RestController
@RequestMapping("/api/" + MetadataFieldRest.CATEGORY + "/" + MetadataFieldRest.NAME_PLURAL)
public class MetadataFieldNameRestController {
@Autowired
private ConverterService converter;
@Autowired
private MetadataFieldService metadataFieldService;
@Autowired
private Utils utils;
@GetMapping("/name/{metadata-field-full-name}")
public MetadataFieldRest get(HttpServletRequest request, HttpServletResponse response,
@PathVariable("metadata-field-full-name") String mdFieldName) {
Context context = ContextUtil.obtainContext(request);
try {
MetadataField metadataField = metadataFieldService.findByString(context, mdFieldName, '.');
if (metadataField == null) {
throw new ResourceNotFoundException("There was no metadata field found with name: " + mdFieldName);
}
return converter.toRest(metadataField, utils.obtainProjection());
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}

View File

@@ -120,6 +120,9 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
* @param qualifierName an exact match of the field's qualifier (e.g. "author", "alternative")
* @param query part of the fully qualified field, should start with the start of the schema, element or
* qualifier (e.g. "dc.ti", "contributor", "auth", "contributor.ot")
* @param exactName exactName, The exact fully qualified field, should use the syntax schema.element
* .qualifier or schema.element if no qualifier exists (e.g. "dc.title", "dc.contributor
* .author"). It will only return one value if there's an exact match
* @param pageable the pagination options
* @return List of {@link MetadataFieldRest} objects representing all {@link MetadataField} objects that match
* the given params
@@ -129,22 +132,32 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
@Parameter(value = "element", required = false) String elementName,
@Parameter(value = "qualifier", required = false) String qualifierName,
@Parameter(value = "query", required = false) String query,
@Parameter(value = "exactName", required = false) String exactName,
Pageable pageable) throws SQLException {
Context context = obtainContext();
DiscoverQuery discoverQuery = this.createDiscoverQuery(context, schemaName, elementName, qualifierName, query);
List<MetadataField> matchingMetadataFields = new ArrayList<>();
try {
DiscoverResult searchResult = searchService.search(context, null, discoverQuery);
for (IndexableObject object : searchResult.getIndexableObjects()) {
if (object instanceof IndexableMetadataField) {
matchingMetadataFields.add(((IndexableMetadataField) object).getIndexedObject());
if (StringUtils.isBlank(exactName)) {
// Find matches in Solr Search core
DiscoverQuery discoverQuery = this.createDiscoverQuery(context, schemaName, elementName, qualifierName, query);
try {
DiscoverResult searchResult = searchService.search(context, null, discoverQuery);
for (IndexableObject object : searchResult.getIndexableObjects()) {
if (object instanceof IndexableMetadataField) {
matchingMetadataFields.add(((IndexableMetadataField) object).getIndexedObject());
}
}
} catch (SearchServiceException e) {
log.error("Error while searching with Discovery", e);
throw new IllegalArgumentException("Error while searching with Discovery: " + e.getMessage());
}
} else {
// Find at most one match with exactName query param in DB
MetadataField exactMatchingMdField = metadataFieldService.findByString(context, exactName, '.');
if (exactMatchingMdField != null) {
matchingMetadataFields.add(exactMatchingMdField);
}
} catch (SearchServiceException e) {
log.error("Error while searching with Discovery", e);
throw new IllegalArgumentException("Error while searching with Discovery: " + e.getMessage());
}
return converter.toRestPage(matchingMetadataFields, pageable, utils.obtainProjection());
@@ -202,15 +215,15 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
@Override
@PreAuthorize("hasAuthority('ADMIN')")
protected MetadataFieldRest createAndReturn(Context context)
throws AuthorizeException, SQLException {
throws AuthorizeException, SQLException {
// parse request body
MetadataFieldRest metadataFieldRest;
try {
metadataFieldRest = new ObjectMapper().readValue(
getRequestService().getCurrentRequest().getHttpServletRequest().getInputStream(),
MetadataFieldRest.class
);
getRequestService().getCurrentRequest().getHttpServletRequest().getInputStream(),
MetadataFieldRest.class
);
} catch (IOException excIO) {
throw new DSpaceBadRequestException("error parsing request body", excIO);
}
@@ -234,14 +247,14 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
MetadataField metadataField;
try {
metadataField = metadataFieldService.create(context, schema,
metadataFieldRest.getElement(), metadataFieldRest.getQualifier(), metadataFieldRest.getScopeNote());
metadataFieldRest.getElement(), metadataFieldRest.getQualifier(), metadataFieldRest.getScopeNote());
metadataFieldService.update(context, metadataField);
} catch (NonUniqueMetadataException e) {
throw new UnprocessableEntityException(
"metadata field "
+ schema.getName() + "." + metadataFieldRest.getElement()
+ (metadataFieldRest.getQualifier() != null ? "." + metadataFieldRest.getQualifier() : "")
+ " already exists"
"metadata field "
+ schema.getName() + "." + metadataFieldRest.getElement()
+ (metadataFieldRest.getQualifier() != null ? "." + metadataFieldRest.getQualifier() : "")
+ " already exists"
);
} catch (IOException e) {
throw new RuntimeException(e);
@@ -271,7 +284,7 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
@Override
@PreAuthorize("hasAuthority('ADMIN')")
protected MetadataFieldRest put(Context context, HttpServletRequest request, String apiCategory, String model,
Integer id, JsonNode jsonNode) throws SQLException, AuthorizeException {
Integer id, JsonNode jsonNode) throws SQLException, AuthorizeException {
MetadataFieldRest metadataFieldRest = new Gson().fromJson(jsonNode.toString(), MetadataFieldRest.class);
@@ -297,9 +310,11 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
context.commit();
} catch (NonUniqueMetadataException e) {
throw new UnprocessableEntityException("metadata field "
+ metadataField.getMetadataSchema().getName() + "." + metadataFieldRest.getElement()
+ (metadataFieldRest.getQualifier() != null ? "." + metadataFieldRest.getQualifier() : "")
+ " already exists");
+ metadataField.getMetadataSchema().getName() + "." +
metadataFieldRest.getElement()
+ (metadataFieldRest.getQualifier() != null ?
"." + metadataFieldRest.getQualifier() : "")
+ " already exists");
} catch (IOException e) {
throw new RuntimeException(e);
}

View File

@@ -1,74 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.dspace.app.rest.builder.MetadataFieldBuilder;
import org.dspace.app.rest.builder.MetadataSchemaBuilder;
import org.dspace.app.rest.test.AbstractEntityIntegrationTest;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.junit.Test;
/**
* Integration tests for the {@link org.dspace.app.rest.MetadataFieldNameRestController} controlled endpoints
*
* @author Maria Verdonck (Atmire) on 17/07/2020
*/
public class MetadataFieldNameRestControllerIT extends AbstractEntityIntegrationTest {
private static final String GETBYNAME_METADATAFIELDS_ENDPOINT =
MetadatafieldRestRepositoryIT.METADATAFIELDS_ENDPOINT + "name/";
@Test
public void testGetMetadataFieldByName_ExistingName() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", "AQualifier", "AScopeNote").build();
context.restoreAuthSystemState();
getClient().perform(get(GETBYNAME_METADATAFIELDS_ENDPOINT + metadataField.toString('.')))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id", is(metadataField.getID())))
.andExpect(jsonPath("$.element", is(metadataField.getElement())));
}
@Test
public void testGetMetadataFieldByName_ExistingName_NoQualifier() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", null, "AScopeNote").build();
context.restoreAuthSystemState();
getClient().perform(get(GETBYNAME_METADATAFIELDS_ENDPOINT + metadataField.toString('.')))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id", is(metadataField.getID())))
.andExpect(jsonPath("$.element", is(metadataField.getElement())))
.andExpect(jsonPath("$.qualifier", is(metadataField.getQualifier())));
}
@Test
public void testGetMetadataFieldByName_NonExistentName() throws Exception {
String nonExistentName = "nonExistentName";
getClient().perform(get(GETBYNAME_METADATAFIELDS_ENDPOINT + nonExistentName))
.andExpect(status().isNotFound());
}
}

View File

@@ -447,6 +447,70 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
.andExpect(jsonPath("$.page.totalElements", is(2)));
}
@Test
public void findByFieldName_query_exactName() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataSchema schema2 = MetadataSchemaBuilder.createMetadataSchema(context, "test",
"http://www.dspace.org/ns/aschema2").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", null, "AScopeNote").build();
MetadataField metadataField2 = MetadataFieldBuilder
.createMetadataField(context, schema2, "AnElement2", null, "AScopeNote2").build();
MetadataField metadataField3 = MetadataFieldBuilder
.createMetadataField(context, schema, "test", null, "AScopeNote2").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("exactName", metadataField.toString('.')))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField3))
)))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField2))
)))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(1)));
}
@Test
public void findByFieldName_query_exactName_NoResult() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataSchema schema2 = MetadataSchemaBuilder.createMetadataSchema(context, "test",
"http://www.dspace.org/ns/aschema2").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", null, "AScopeNote").build();
MetadataField metadataField2 = MetadataFieldBuilder
.createMetadataField(context, schema2, "AnElement2", null, "AScopeNote2").build();
MetadataField metadataField3 = MetadataFieldBuilder
.createMetadataField(context, schema, "test", null, "AScopeNote2").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("exactName", "not.valid.mdstring"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.page.totalElements", is(0)));
}
@Test
public void findByFieldName_invalidQuery() throws Exception {
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)