Merge branch 'main' into DURACOM-127

This commit is contained in:
Francesco Pio Scognamiglio
2023-05-24 15:43:14 +02:00
committed by GitHub
7 changed files with 218 additions and 7 deletions

View File

@@ -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.importer.external.crossref;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.importer.external.metadatamapping.contributor.JsonPathMetadataProcessor;
import org.joda.time.LocalDate;
/**
* This class is used for CrossRef's Live-Import to extract
* issued attribute.
* Beans are configured in the crossref-integration.xml file.
*
* @author Francesco Pio Scognamiglio (francescopio.scognamiglio at 4science.com)
*/
public class CrossRefDateMetadataProcessor implements JsonPathMetadataProcessor {
private final static Logger log = LogManager.getLogger();
private String pathToArray;
@Override
public Collection<String> processMetadata(String json) {
JsonNode rootNode = convertStringJsonToJsonNode(json);
Iterator<JsonNode> dates = rootNode.at(pathToArray).iterator();
Collection<String> values = new ArrayList<>();
while (dates.hasNext()) {
JsonNode date = dates.next();
LocalDate issuedDate = null;
SimpleDateFormat issuedDateFormat = null;
if (date.has(0) && date.has(1) && date.has(2)) {
issuedDate = new LocalDate(
date.get(0).numberValue().intValue(),
date.get(1).numberValue().intValue(),
date.get(2).numberValue().intValue());
issuedDateFormat = new SimpleDateFormat("yyyy-MM-dd");
} else if (date.has(0) && date.has(1)) {
issuedDate = new LocalDate().withYear(date.get(0).numberValue().intValue())
.withMonthOfYear(date.get(1).numberValue().intValue());
issuedDateFormat = new SimpleDateFormat("yyyy-MM");
} else if (date.has(0)) {
issuedDate = new LocalDate().withYear(date.get(0).numberValue().intValue());
issuedDateFormat = new SimpleDateFormat("yyyy");
}
values.add(issuedDateFormat.format(issuedDate.toDate()));
}
return values;
}
private JsonNode convertStringJsonToJsonNode(String json) {
ObjectMapper mapper = new ObjectMapper();
JsonNode body = null;
try {
body = mapper.readTree(json);
} catch (JsonProcessingException e) {
log.error("Unable to process json response.", e);
}
return body;
}
public void setPathToArray(String pathToArray) {
this.pathToArray = pathToArray;
}
}

View File

@@ -120,7 +120,7 @@ public class ItemTemplateRestController {
* @throws SQLException
* @throws AuthorizeException
*/
@PreAuthorize("hasPermission(#uuid, 'ITEM', 'WRITE')")
@PreAuthorize("hasPermission(#uuid, 'ITEMTEMPLATE', 'WRITE')")
@RequestMapping(method = RequestMethod.PATCH)
public ResponseEntity<RepresentationModel<?>> patch(HttpServletRequest request, @PathVariable UUID uuid,
@RequestBody(required = true) JsonNode jsonNode)
@@ -153,7 +153,7 @@ public class ItemTemplateRestController {
* @throws AuthorizeException
* @throws IOException
*/
@PreAuthorize("hasPermission(#uuid, 'ITEM', 'DELETE')")
@PreAuthorize("hasPermission(#uuid, 'ITEMTEMPLATE', 'DELETE')")
@RequestMapping(method = RequestMethod.DELETE)
public ResponseEntity<RepresentationModel<?>> deleteTemplateItem(HttpServletRequest request,
@PathVariable UUID uuid)

View File

@@ -0,0 +1,83 @@
/**
* 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.security;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.model.TemplateItemRest;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Collection;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.services.RequestService;
import org.dspace.services.model.Request;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
/**
* {@link RestObjectPermissionEvaluatorPlugin} class that evaluate WRITE and DELETE permission over a TemplateItem
*
* @author Bui Thai Hai (thaihai.bui@dlcorp.com.vn)
*/
@Component
public class TemplateItemRestPermissionEvaluatorPlugin extends RestObjectPermissionEvaluatorPlugin {
private static final Logger log = LoggerFactory.getLogger(TemplateItemRestPermissionEvaluatorPlugin.class);
@Autowired
private RequestService requestService;
@Autowired
ItemService its;
@Autowired
private AuthorizeService authorizeService;
@Override
public boolean hasDSpacePermission(Authentication authentication, Serializable targetId, String targetType,
DSpaceRestPermission permission) {
DSpaceRestPermission restPermission = DSpaceRestPermission.convert(permission);
if (!DSpaceRestPermission.WRITE.equals(restPermission) &&
!DSpaceRestPermission.DELETE.equals(restPermission)) {
return false;
}
if (!StringUtils.equalsIgnoreCase(targetType, TemplateItemRest.NAME)) {
return false;
}
Request request = requestService.getCurrentRequest();
Context context = ContextUtil.obtainContext(request.getHttpServletRequest());
EPerson ePerson = context.getCurrentUser();
if (ePerson == null) {
return false;
}
// Allow collection's admin to edit/delete the template
UUID dsoId = UUID.fromString(targetId.toString());
requestService.getCurrentRequest().getHttpServletRequest().getRequestURL();
try {
Collection coll = its.find(context, dsoId).getTemplateItemOf();
if (authorizeService.isAdmin(context, coll)) {
return true;
}
} catch (SQLException e) {
log.error(e.getMessage(), e);
}
return false;
}
}

View File

@@ -146,7 +146,7 @@ public class CrossRefImportMetadataSourceServiceIT extends AbstractLiveImportInt
+ " Medical College of Prevention of Iodine Deficiency Diseases");
MetadatumDTO author = createMetadatumDTO("dc", "contributor", "author", "L.V. Senyuk");
MetadatumDTO type = createMetadatumDTO("dc", "type", null, "journal-article");
MetadatumDTO date = createMetadatumDTO("dc", "date", "issued", "2016");
MetadatumDTO date = createMetadatumDTO("dc", "date", "issued", "2016-05-19");
MetadatumDTO ispartof = createMetadatumDTO("dc", "relation", "ispartof",
"Ukraïnsʹkij žurnal medicini, bìologìï ta sportu");
MetadatumDTO doi = createMetadatumDTO("dc", "identifier", "doi", "10.26693/jmbs01.02.184");
@@ -172,7 +172,7 @@ public class CrossRefImportMetadataSourceServiceIT extends AbstractLiveImportInt
"Ischemic Heart Disease and Role of Nurse of Cardiology Department");
MetadatumDTO author2 = createMetadatumDTO("dc", "contributor", "author", "K. І. Kozak");
MetadatumDTO type2 = createMetadatumDTO("dc", "type", null, "journal-article");
MetadatumDTO date2 = createMetadatumDTO("dc", "date", "issued", "2016");
MetadatumDTO date2 = createMetadatumDTO("dc", "date", "issued", "2016-05-19");
MetadatumDTO ispartof2 = createMetadatumDTO("dc", "relation", "ispartof",
"Ukraïnsʹkij žurnal medicini, bìologìï ta sportu");
MetadatumDTO doi2 = createMetadatumDTO("dc", "identifier", "doi", "10.26693/jmbs01.02.105");

View File

@@ -33,6 +33,7 @@ import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.authorize.service.ResourcePolicyService;
import org.dspace.builder.CollectionBuilder;
import org.dspace.builder.CommunityBuilder;
import org.dspace.builder.ResourcePolicyBuilder;
import org.dspace.content.Collection;
import org.dspace.core.Constants;
import org.hamcrest.Matchers;
@@ -243,6 +244,35 @@ public class ItemTemplateRestControllerIT extends AbstractControllerIntegrationT
)))));
}
/* Similar to patchTemplateItem(), except it is for collection admin, not repository admin
Test case was simplified, since it does not do anything else.
*/
@Test
public void patchTemplateItemAsCollectionAdmin() throws Exception {
setupTestTemplate();
String itemId = installTestTemplate();
ResourcePolicyBuilder.createResourcePolicy(context).withUser(eperson)
.withAction(Constants.ADMIN)
.withDspaceObject(childCollection).build();
String collAdminToken = getAuthToken(eperson.getEmail(), password);
getClient(collAdminToken).perform(patch(getTemplateItemUrlTemplate(itemId))
.content(patchBody)
.contentType(contentType))
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.type", is("itemtemplate"))
)));
getClient(collAdminToken).perform(get(getCollectionTemplateItemUrlTemplate(childCollection.getID().toString())))
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.allOf(
hasJsonPath("$.type", is("itemtemplate"))
)));
}
@Test
public void patchIllegalInArchiveTemplateItem() throws Exception {
setupTestTemplate();
@@ -337,6 +367,22 @@ public class ItemTemplateRestControllerIT extends AbstractControllerIntegrationT
.andExpect(status().isNoContent());
}
/*Similar to deleteTemplateItem(), except it is for collection admin, not repository admin
*/
@Test
public void deleteTemplateItemAsCollectionAdmin() throws Exception {
setupTestTemplate();
String itemId = installTestTemplate();
ResourcePolicyBuilder.createResourcePolicy(context).withUser(eperson)
.withAction(Constants.ADMIN)
.withDspaceObject(childCollection).build();
String collAdminToken = getAuthToken(eperson.getEmail(), password);
getClient(collAdminToken).perform(delete(getTemplateItemUrlTemplate(itemId)))
.andExpect(status().isNoContent());
}
@Test
public void deleteTemplateItemNoRights() throws Exception {
setupTestTemplate();

View File

@@ -69,8 +69,11 @@
<bean id="crossrefYearContrib" class="org.dspace.importer.external.metadatamapping.contributor.SimpleJsonPathMetadataContributor">
<property name="field" ref="crossref.year"/>
<property name="query" value="/issued/date-parts/0/0"/>
<property name="metadataProcessor" ref="crossrefDateMetadataProcessor"></property>
</bean>
<bean name="crossrefDateMetadataProcessor" class="org.dspace.importer.external.crossref.CrossRefDateMetadataProcessor">
<property name="pathToArray" value="/issued/date-parts"></property>
</bean>
<bean id="crossref.year" class="org.dspace.importer.external.metadatamapping.MetadataFieldConfig">
<constructor-arg value="dc.date.issued"/>
</bean>

View File

@@ -20,7 +20,7 @@
<!--=== GENERAL / DSPACE-API DEPENDENCIES ===-->
<java.version>11</java.version>
<spring.version>5.3.27</spring.version>
<spring-boot.version>2.7.11</spring-boot.version>
<spring-boot.version>2.7.12</spring-boot.version>
<spring-security.version>5.7.8</spring-security.version> <!-- sync with version used by spring-boot-->
<hibernate.version>5.6.15.Final</hibernate.version>
<hibernate-validator.version>6.2.5.Final</hibernate-validator.version>
@@ -42,7 +42,7 @@
<pdfbox-version>2.0.28</pdfbox-version>
<rome.version>1.19.0</rome.version>
<slf4j.version>1.7.36</slf4j.version>
<tika.version>2.3.0</tika.version>
<tika.version>2.5.0</tika.version>
<!-- Sync with whatever version Tika uses -->
<bouncycastle.version>1.70</bouncycastle.version>