[TLC-380] Refactor browses endpoint for browse link usage

This commit is contained in:
Kim Shepherd
2023-01-25 15:36:48 +13:00
parent 135385816a
commit d85de89261
4 changed files with 117 additions and 192 deletions

View File

@@ -7,12 +7,18 @@
*/
package org.dspace.app.rest.repository;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.model.BrowseIndexRest;
import org.dspace.browse.BrowseException;
import org.dspace.browse.BrowseIndex;
import org.dspace.browse.CrossLinks;
import org.dspace.core.Context;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -53,6 +59,65 @@ public class BrowseIndexRestRepository extends DSpaceRestRepository<BrowseIndexR
}
}
/**
* Find a browse index by a specific field
* @param field
* @return
* @throws SQLException
*/
@SearchRestMethod(name = "byField")
public BrowseIndexRest findByField(@Parameter(value = "field", required = true) String field)
throws SQLException {
BrowseIndexRest bi = null;
BrowseIndex bix = null;
try {
CrossLinks cl = new CrossLinks();
if (cl.hasLink(field)) {
// Get the index name for this
String browseIndexName = cl.getLinkType(field);
bix = BrowseIndex.getBrowseIndex(browseIndexName);
}
} catch (BrowseException e) {
throw new RuntimeException(e.getMessage(), e);
}
if (bix != null) {
bi = converter.toRest(bix, utils.obtainProjection());
}
return bi;
}
/**
* Get paginated list of all browse index definitions for configured browse links
*
* @param context
* the dspace context
* @param pageable
* object embedding the requested pagination info
* @return
*/
@SearchRestMethod(name = "allLinked")
public Page<BrowseIndexRest> findAllLinked(Context context, Pageable pageable) {
try {
CrossLinks cl = new CrossLinks();
List<BrowseIndex> linkedIndexes = new ArrayList<>();
Map<String, String> links = cl.getLinks();
for (String field : links.keySet()) {
if (cl.hasLink(field)) {
String indexName = cl.getLinkType(field);
if (indexName != null) {
BrowseIndex bix = BrowseIndex.getBrowseIndex(indexName);
if (bix != null) {
linkedIndexes.add(bix);
}
}
}
}
return converter.toRestPage(linkedIndexes, pageable, linkedIndexes.size(), utils.obtainProjection());
} catch (BrowseException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
@Override
public Class<BrowseIndexRest> getDomainClass() {
return BrowseIndexRest.class;

View File

@@ -1,101 +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.repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.dspace.app.rest.model.BrowseIndexRest;
import org.dspace.browse.BrowseException;
import org.dspace.browse.BrowseIndex;
import org.dspace.browse.CrossLinks;
import org.dspace.core.Context;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
/**
* This is the repository responsible for listing link behaviour for various browse definitions and fields.
* Note "link" here refers to rendering an HTML link from a displayed metadata value to a browse page
* not a HAL _link
*
* @author Kim Shepherd
*/
@Component(BrowseIndexRest.CATEGORY + ".browselink")
public class BrowseLinkRestRepository extends DSpaceRestRepository<BrowseIndexRest, String> {
/**
* Return a browse definition for a given metadata field name if it is configured
* as a browse link, or null (404)
*
* @param context
* the dspace context
* @param metadataField
* the rest object id
* @return
*/
@Override
@PreAuthorize("permitAll()")
public BrowseIndexRest findOne(Context context, String metadataField) {
BrowseIndexRest bi = null;
BrowseIndex bix = null;
try {
CrossLinks cl = new CrossLinks();
if (cl.hasLink(metadataField)) {
// Get the index name for this
String browseIndexName = cl.getLinkType(metadataField);
bix = BrowseIndex.getBrowseIndex(browseIndexName);
}
} catch (BrowseException e) {
throw new RuntimeException(e.getMessage(), e);
}
if (bix != null) {
bi = converter.toRest(bix, utils.obtainProjection());
}
return bi;
}
/**
* Get paginated list of all browse index definitions for configured browse links
*
* @param context
* the dspace context
* @param pageable
* object embedding the requested pagination info
* @return
*/
@Override
public Page<BrowseIndexRest> findAll(Context context, Pageable pageable) {
try {
CrossLinks cl = new CrossLinks();
List<BrowseIndex> linkedIndexes = new ArrayList<>();
Map<String, String> links = cl.getLinks();
for (String field : links.keySet()) {
if (cl.hasLink(field)) {
String indexName = cl.getLinkType(field);
if (indexName != null) {
BrowseIndex bix = BrowseIndex.getBrowseIndex(indexName);
if (bix != null) {
linkedIndexes.add(bix);
}
}
}
}
return converter.toRestPage(linkedIndexes, pageable, linkedIndexes.size(), utils.obtainProjection());
} catch (BrowseException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
@Override
public Class<BrowseIndexRest> getDomainClass() {
return BrowseIndexRest.class;
}
}

View File

@@ -1,90 +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.containsInAnyOrder;
import static org.hamcrest.Matchers.hasSize;
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.content;
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.matcher.BrowseIndexMatcher;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.content.authority.service.MetadataAuthorityService;
import org.dspace.services.ConfigurationService;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Integration test to test the /api/discover/browselinks endpoint
*
* @author Kim Shepherd
*/
public class BrowseLinkRestRepositoryIT extends AbstractControllerIntegrationTest {
@Autowired
ConfigurationService configurationService;
@Autowired
MetadataAuthorityService metadataAuthorityService;
/**
* Expect a single author browse definition
* @throws Exception
*/
@Test
public void findOne() throws Exception {
//When we call the root endpoint
getClient().perform(get("/api/discover/browselinks/dc.contributor.author"))
//The status has to be 200 OK
.andExpect(status().isOk())
//We expect the content type to be "application/hal+json;charset=UTF-8"
.andExpect(content().contentType(contentType))
//The array of browse index should have a size 1
.andExpect(jsonPath("$.id", is("author")))
//Check that all (and only) the default browse indexes are present
.andExpect(jsonPath("$.metadataBrowse", is(true)))
;
}
/**
* Expect a list of browse definitions that are also configured for link rendering
* @throws Exception
*/
@Test
public void findAll() throws Exception {
//When we call the root endpoint
getClient().perform(get("/api/discover/browselinks"))
//The status has to be 200 OK
.andExpect(status().isOk())
//We expect the content type to be "application/hal+json;charset=UTF-8"
.andExpect(content().contentType(contentType))
// Expect TWO results, author and browse (see dspace-api test data local.cfg_
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(2)))
.andExpect(jsonPath("$.page.totalPages", is(1)))
.andExpect(jsonPath("$.page.number", is(0)))
//The array of browse index should have a size 2
.andExpect(jsonPath("$._embedded.browses", hasSize(2)))
//Check that all (and only) the default browse indexes are present
.andExpect(jsonPath("$._embedded.browses", containsInAnyOrder(
BrowseIndexMatcher.contributorBrowseIndex("asc"),
BrowseIndexMatcher.subjectBrowseIndex("asc")
)))
;
}
}

View File

@@ -980,7 +980,7 @@ public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTe
/**
* This test was introduced to reproduce the bug DS-4269 Pagination links must be consistent also when there is not
* explicit pagination parameters in the request (i.e. defaults apply)
*
*
* @throws Exception
*/
public void browsePaginationWithoutExplicitParams() throws Exception {
@@ -2125,4 +2125,55 @@ public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTe
.andExpect(jsonPath("$._embedded.items[0]._embedded.owningCollection._embedded.adminGroup",
nullValue()));
}
/**
* Expect a single author browse definition
* @throws Exception
*/
@Test
public void findOneLinked() throws Exception {
//When we call the root endpoint
getClient().perform(get("/api/discover/browses/search/byField?field=dc.contributor.author"))
//The status has to be 200 OK
.andExpect(status().isOk())
//We expect the content type to be "application/hal+json;charset=UTF-8"
.andExpect(content().contentType(contentType))
//The array of browse index should have a size 1
.andExpect(jsonPath("$.id", is("author")))
//Check that all (and only) the default browse indexes are present
.andExpect(jsonPath("$.metadataBrowse", is(true)))
;
}
/**
* Expect a list of browse definitions that are also configured for link rendering
* @throws Exception
*/
@Test
public void findAllLinked() throws Exception {
//When we call the root endpoint
getClient().perform(get("/api/discover/browses/search/allLinked"))
//The status has to be 200 OK
.andExpect(status().isOk())
//We expect the content type to be "application/hal+json;charset=UTF-8"
.andExpect(content().contentType(contentType))
// Expect TWO results, author and browse (see dspace-api test data local.cfg_
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(2)))
.andExpect(jsonPath("$.page.totalPages", is(1)))
.andExpect(jsonPath("$.page.number", is(0)))
//The array of browse index should have a size 2
.andExpect(jsonPath("$._embedded.browses", hasSize(2)))
//Check that all (and only) the default browse indexes are present
.andExpect(jsonPath("$._embedded.browses", containsInAnyOrder(
BrowseIndexMatcher.contributorBrowseIndex("asc"),
BrowseIndexMatcher.subjectBrowseIndex("asc")
)))
;
}
}