Skip to content

Commit

Permalink
Merge pull request #2762 from atmire/w2p-70471_request-configuration-…
Browse files Browse the repository at this point in the history
…properties-in-rest

Configuration property retrieval Rest endpoint
  • Loading branch information
tdonohue committed Jun 10, 2020
2 parents e03a3f4 + a7aeb10 commit 81b1e57
Show file tree
Hide file tree
Showing 7 changed files with 239 additions and 0 deletions.
12 changes: 12 additions & 0 deletions dspace-api/src/test/data/dspaceFolder/config/local.cfg
Expand Up @@ -108,3 +108,15 @@ plugin.sequence.java.util.Collection = \
java.util.LinkedList, \
java.util.Stack, \
java.util.TreeSet

###########################################
# PROPERTIES USED TO TEST CONFIGURATION #
# PROPERTY EXPOSURE VIA REST #
###########################################
rest.properties.exposed = configuration.exposed.single.value
rest.properties.exposed = configuration.exposed.array.value
rest.properties.exposed = configuration.not.existing

configuration.not.exposed = secret_value
configuration.exposed.single.value = public_value
configuration.exposed.array.value = public_value_1, public_value_2
@@ -0,0 +1,62 @@
/**
* 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.model;

import java.util.List;

import com.fasterxml.jackson.annotation.JsonIgnore;
import org.dspace.app.rest.RestResourceController;

/**
* This class acts as the REST representation of a DSpace configuration property.
* This class acts as a data holder for the PropertyResource
*/
public class PropertyRest extends BaseObjectRest<String> {
public static final String NAME = "property";
public static final String CATEGORY = RestAddressableModel.CONFIGURATION;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public List<String> getValues() {
return values;
}

public void setValues(List<String> values) {
this.values = values;
}

public String name;
public List<String> values;

@Override
@JsonIgnore
public String getId() {
return this.name;
}

@Override
public String getCategory() {
return CATEGORY;
}

@Override
public Class getController() {
return RestResourceController.class;
}

@Override
public String getType() {
return NAME;
}
}
@@ -0,0 +1,21 @@
/**
* 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.model.hateoas;

import org.dspace.app.rest.model.PropertyRest;
import org.dspace.app.rest.utils.Utils;

/**
* The purpose of this class is to wrap the information of the PropertyRest into a HAL resource
*/
public class PropertyResource extends DSpaceResource<PropertyRest> {

public PropertyResource(PropertyRest data, Utils utils) {
super(data, utils);
}
}
@@ -0,0 +1,79 @@
/**
* 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.Arrays;
import java.util.List;

import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.model.PropertyRest;
import org.dspace.core.Context;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;

/**
* This is the repository responsible of exposing configuration properties
*/
@Component(PropertyRest.CATEGORY + "." + PropertyRest.NAME)
public class ConfigurationRestRepository extends DSpaceRestRepository<PropertyRest, String> {

private ConfigurationService configurationService;
private List<String> exposedProperties;

@Autowired
public ConfigurationRestRepository(ConfigurationService configurationService) {
this.configurationService = configurationService;
this.exposedProperties = Arrays.asList(configurationService.getArrayProperty("rest.properties.exposed"));
}

/**
* Gets the value of a configuration property if it is exposed via REST
*
* Example:
* <pre>
* {@code
* curl http://<dspace.server.url>/api/config/properties/google.analytics.key
* -XGET \
* -H 'Authorization: Bearer eyJhbGciOiJI...'
* }
* </pre>
*
* @param property
* @return
*/
@Override
@PreAuthorize("permitAll()")
public PropertyRest findOne(Context context, String property) {
if (!exposedProperties.contains(property) || !configurationService.hasProperty(property)) {
throw new ResourceNotFoundException("No such configuration property: " + property);
}

String[] propertyValues = configurationService.getArrayProperty(property);

PropertyRest propertyRest = new PropertyRest();
propertyRest.setName(property);
propertyRest.setValues(Arrays.asList(propertyValues));

return propertyRest;
}

@Override
public Page<PropertyRest> findAll(Context context, Pageable pageable) {
throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed", "");
}

@Override
public Class<PropertyRest> getDomainClass() {
return PropertyRest.class;
}
}
Expand Up @@ -53,6 +53,7 @@
import org.dspace.app.rest.model.LinkRest;
import org.dspace.app.rest.model.LinksRest;
import org.dspace.app.rest.model.ProcessRest;
import org.dspace.app.rest.model.PropertyRest;
import org.dspace.app.rest.model.ResourcePolicyRest;
import org.dspace.app.rest.model.RestAddressableModel;
import org.dspace.app.rest.model.RestModel;
Expand Down Expand Up @@ -264,6 +265,9 @@ public static String makeSingular(String modelPlural) {
if (StringUtils.equals(modelPlural, "versionhistories")) {
return VersionHistoryRest.NAME;
}
if (StringUtils.equals(modelPlural, "properties")) {
return PropertyRest.NAME;
}
return modelPlural.replaceAll("s$", "");
}

Expand Down
@@ -0,0 +1,55 @@
/**
* 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.test.AbstractControllerIntegrationTest;
import org.junit.Test;

/**
* Integration Tests against the /api/config/properties/[property] endpoint
*/
public class ConfigurationRestRepositoryIT extends AbstractControllerIntegrationTest {
@Test
public void getSingleValue() throws Exception {
getClient().perform(get("/api/config/properties/configuration.exposed.single.value"))
.andExpect(jsonPath("$.values[0]", is("public_value")))
.andExpect(jsonPath("$.type", is("property")))
.andExpect(jsonPath("$.name", is("configuration.exposed.single.value")))
.andExpect(jsonPath("$._links.self.href", is("http://localhost/api/config/properties/configuration.exposed.single.value")));
}

@Test
public void getArrayValue() throws Exception {
getClient().perform(get("/api/config/properties/configuration.exposed.array.value"))
.andExpect(jsonPath("$.values[0]", is("public_value_1")))
.andExpect(jsonPath("$.values[1]", is("public_value_2")));
}

@Test
public void getNonExistingValue() throws Exception {
getClient().perform(get("/api/config/properties/configuration.not.existing"))
.andExpect(status().isNotFound());
}

@Test
public void getNonExposedValue() throws Exception {
getClient().perform(get("/api/config/properties/configuration.not.exposed"))
.andExpect(status().isNotFound());
}

@Test
public void getAll() throws Exception {
getClient().perform(get("/api/config/properties/"))
.andExpect(status().isMethodNotAllowed());
}
}
6 changes: 6 additions & 0 deletions dspace/config/modules/rest.cfg
Expand Up @@ -161,3 +161,9 @@ rest.report-regex-non-ascii = ^.*[^\\p{ASCII}].*$

# The maximum number of results to return for 1 request
rest.search.max.results = 100

# Define which configuration properties are exposed through the http://<dspace.server.url>/api/config/properties/
# rest endpoint. If a rest request is made for a property which exists, but isn't listed here, the server will
# respond that the property wasn't found. This property can be defined multiple times to allow access to multiple
# configuration properties.
rest.properties.exposed = google.analytics.key

0 comments on commit 81b1e57

Please sign in to comment.