From c84179ea9cde9335ff4267989a78b7b2adae954e Mon Sep 17 00:00:00 2001 From: Mykhaylo Boychuk Date: Mon, 23 Oct 2023 18:07:00 +0200 Subject: [PATCH] [CST-12108] porting of Users Correction Suggestions - new endpoint for correctiontypes with ITs. --- .../AddRelationCorrectionType.java | 148 ++++++++ .../dspace/correctiontype/CorrectionType.java | 31 ++ .../RemoveRelationCorrectionType.java | 148 ++++++++ .../service/CorrectionTypeService.java | 28 ++ .../impl/CorrectionTypeServiceImpl.java | 70 ++++ .../QAOpenaireSimpleMetadataAction.java | 2 +- .../converter/CorrectionTypeConverter.java | 41 +++ .../app/rest/model/CorrectionTypeRest.java | 63 ++++ .../model/hateoas/CorrectionTypeResource.java | 25 ++ .../CorrectionTypeRestRepository.java | 98 +++++ ...nalSourceCorrectionTypeUriListHandler.java | 78 ++++ .../rest/CorrectionTypeRestRepositoryIT.java | 244 +++++++++++++ .../app/rest/QAEventRestRepositoryIT.java | 339 ++++++++++++++++++ dspace/config/spring/api/core-services.xml | 2 + dspace/config/spring/api/correction-types.xml | 39 ++ dspace/config/spring/api/qaevents.xml | 24 +- 16 files changed, 1377 insertions(+), 3 deletions(-) create mode 100644 dspace-api/src/main/java/org/dspace/correctiontype/AddRelationCorrectionType.java create mode 100644 dspace-api/src/main/java/org/dspace/correctiontype/CorrectionType.java create mode 100644 dspace-api/src/main/java/org/dspace/correctiontype/RemoveRelationCorrectionType.java create mode 100644 dspace-api/src/main/java/org/dspace/correctiontype/service/CorrectionTypeService.java create mode 100644 dspace-api/src/main/java/org/dspace/correctiontype/service/impl/CorrectionTypeServiceImpl.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CorrectionTypeConverter.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/model/CorrectionTypeRest.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/CorrectionTypeResource.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CorrectionTypeRestRepository.java create mode 100644 dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/handler/ExternalSourceCorrectionTypeUriListHandler.java create mode 100644 dspace-server-webapp/src/test/java/org/dspace/app/rest/CorrectionTypeRestRepositoryIT.java create mode 100644 dspace/config/spring/api/correction-types.xml diff --git a/dspace-api/src/main/java/org/dspace/correctiontype/AddRelationCorrectionType.java b/dspace-api/src/main/java/org/dspace/correctiontype/AddRelationCorrectionType.java new file mode 100644 index 0000000000..e43ed7d161 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/correctiontype/AddRelationCorrectionType.java @@ -0,0 +1,148 @@ +/** + * 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.correctiontype; + +import java.sql.SQLException; +import java.util.Date; + +import com.google.gson.Gson; +import org.apache.commons.lang3.StringUtils; +import org.dspace.app.nbevent.NBEventActionService; +import org.dspace.app.nbevent.service.NBEventService; +import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.Item; +import org.dspace.content.NBEvent; +import org.dspace.content.service.ItemService; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * implementation class for {@link CorrectionType} + * that will add a new relation metadata to target item if not exist. + * + * @author Mohamed Eskander (mohamed.eskander at 4science.com) + */ +public class AddRelationCorrectionType implements CorrectionType, InitializingBean { + private String id; + private String topic; + private String discoveryConfiguration; + private String creationForm; + private String targetMetadata; + + @Autowired + private ItemService itemService; + + @Autowired + private NBEventService nbEventService; + + @Autowired + private AuthorizeService authorizeService; + + @Autowired + private NBEventActionService nbEventActionService; + + @Override + public void afterPropertiesSet() throws Exception { + setTopic(topic.concat(targetMetadata)); + } + + @Override + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + @Override + public String getDiscoveryConfiguration() { + return discoveryConfiguration; + } + + public void setDiscoveryConfiguration(String discoveryConfiguration) { + this.discoveryConfiguration = discoveryConfiguration; + } + + @Override + public String getCreationForm() { + return creationForm; + } + + public void setCreationForm(String creationForm) { + this.creationForm = creationForm; + } + + public void setTargetMetadata(String targetMetadata) { + this.targetMetadata = targetMetadata; + } + + @Override + public boolean isAllowed(Context context, Item targetItem) throws AuthorizeException, SQLException { + authorizeService.authorizeAction(context, targetItem, Constants.READ); + + if (!targetItem.isArchived() || targetItem.isWithdrawn() || !targetItem.isDiscoverable()) { + return false; + } + + if (StringUtils.equalsAny( + itemService.getEntityType(targetItem), "PersonalArchive", "PersonalPath") + ) { + return false; + } + + return true; + } + + @Override + public boolean isAllowed(Context context, Item targetItem, Item relatedItem) + throws AuthorizeException, SQLException { + if (isAllowed(context, targetItem)) { + if (isMetadataExisted(targetItem, relatedItem.getID().toString())) { + throw new IllegalArgumentException("the provided related item<" + + relatedItem.getID() + "> is already linked"); + } + return true; + } + return false; + } + + @Override + public NBEvent createCorrection(Context context, Item targetItem, Item relatedItem) { + NBEvent nbEvent = new NBEvent("handle:" + targetItem.getHandle(), targetItem.getID().toString(), + targetItem.getName(), this.getTopic(), 1.0, new Gson().toJson(new Object()), new Date()); + nbEvent.setRelated(relatedItem.getID().toString()); + + nbEventService.store(context, nbEvent); + nbEventActionService.accept(context, nbEvent); + return nbEvent; + } + + private boolean isMetadataExisted(Item targetItem, String value) { + return targetItem + .getMetadata() + .stream() + .filter(metadataValue -> + metadataValue.getMetadataField().toString('.').equals(targetMetadata)) + .anyMatch(metadataValue -> + metadataValue.getValue().equals(value) && + metadataValue.getAuthority().equals(value)); + } +} diff --git a/dspace-api/src/main/java/org/dspace/correctiontype/CorrectionType.java b/dspace-api/src/main/java/org/dspace/correctiontype/CorrectionType.java new file mode 100644 index 0000000000..f364a66188 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/correctiontype/CorrectionType.java @@ -0,0 +1,31 @@ +/** + * 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.correctiontype; + +import java.sql.SQLException; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Item; +import org.dspace.content.NBEvent; +import org.dspace.core.Context; + +/** + * interface class that model the CorrectionType. + * + * @author Mohamed Eskander (mohamed.eskander at 4science.com) + */ +public interface CorrectionType { + public String getId(); + public String getTopic(); + public String getDiscoveryConfiguration(); + public String getCreationForm(); + public boolean isAllowed(Context context, Item targetItem) throws AuthorizeException, SQLException; + public boolean isAllowed(Context context, Item targetItem, Item relatedItem) throws AuthorizeException, + SQLException; + public NBEvent createCorrection(Context context, Item targetItem, Item relatedItem); +} diff --git a/dspace-api/src/main/java/org/dspace/correctiontype/RemoveRelationCorrectionType.java b/dspace-api/src/main/java/org/dspace/correctiontype/RemoveRelationCorrectionType.java new file mode 100644 index 0000000000..45df52f124 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/correctiontype/RemoveRelationCorrectionType.java @@ -0,0 +1,148 @@ +/** + * 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.correctiontype; + +import java.sql.SQLException; +import java.util.Date; + +import com.google.gson.Gson; +import org.apache.commons.lang3.StringUtils; +import org.dspace.app.nbevent.NBEventActionService; +import org.dspace.app.nbevent.service.NBEventService; +import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.Item; +import org.dspace.content.NBEvent; +import org.dspace.content.service.ItemService; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * implementation class for {@link CorrectionType} + * that will remove the relation metadata from target item if existed. + * + * @author Mohamed Eskander (mohamed.eskander at 4science.com) + */ +public class RemoveRelationCorrectionType implements CorrectionType, InitializingBean { + private String id; + private String topic; + private String discoveryConfiguration; + private String creationForm; + private String targetMetadata; + + @Autowired + private ItemService itemService; + + @Autowired + private NBEventService nbEventService; + + @Autowired + NBEventActionService nbEventActionService; + + @Autowired + private AuthorizeService authorizeService; + + @Override + public void afterPropertiesSet() throws Exception { + setTopic(topic.concat(targetMetadata)); + } + + @Override + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + @Override + public String getDiscoveryConfiguration() { + return discoveryConfiguration; + } + + public void setDiscoveryConfiguration(String discoveryConfiguration) { + this.discoveryConfiguration = discoveryConfiguration; + } + + @Override + public String getCreationForm() { + return creationForm; + } + + public void setCreationForm(String creationForm) { + this.creationForm = creationForm; + } + + public void setTargetMetadata(String targetMetadata) { + this.targetMetadata = targetMetadata; + } + + @Override + public boolean isAllowed(Context context, Item targetItem) throws SQLException, AuthorizeException { + authorizeService.authorizeAction(context, targetItem, Constants.READ); + + if (!targetItem.isArchived() || targetItem.isWithdrawn() || !targetItem.isDiscoverable()) { + return false; + } + + if (StringUtils.equalsAny( + itemService.getEntityType(targetItem), "PersonalArchive", "PersonalPath") + ) { + return false; + } + return true; + } + + @Override + public boolean isAllowed(Context context, Item targetItem, Item relatedItem) + throws AuthorizeException, SQLException { + if (isAllowed(context, targetItem)) { + if (isMetadataNotExisted(targetItem, relatedItem.getID().toString())) { + throw new IllegalArgumentException("the provided target item<" + + targetItem.getID() + "> has no relation with related item <" + + relatedItem.getID() + ">"); + } + return true; + } + return false; + } + + @Override + public NBEvent createCorrection(Context context, Item targetItem, Item relatedItem) { + NBEvent nbEvent = new NBEvent("handle:" + targetItem.getHandle(), targetItem.getID().toString(), + targetItem.getName(), this.getTopic(), 1.0, new Gson().toJson(new Object()), new Date()); + nbEvent.setRelated(relatedItem.getID().toString()); + + nbEventService.store(context, nbEvent); + nbEventActionService.accept(context, nbEvent); + return nbEvent; + } + + private boolean isMetadataNotExisted(Item targetItem, String value) { + return targetItem + .getMetadata() + .stream() + .filter(metadataValue -> + metadataValue.getMetadataField().toString('.').equals(targetMetadata)) + .noneMatch(metadataValue -> + metadataValue.getValue().equals(value) && + metadataValue.getAuthority().equals(value)); + } +} diff --git a/dspace-api/src/main/java/org/dspace/correctiontype/service/CorrectionTypeService.java b/dspace-api/src/main/java/org/dspace/correctiontype/service/CorrectionTypeService.java new file mode 100644 index 0000000000..fa8d58f64d --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/correctiontype/service/CorrectionTypeService.java @@ -0,0 +1,28 @@ +/** + * 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.correctiontype.service; + +import java.sql.SQLException; +import java.util.List; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Item; +import org.dspace.core.Context; +import org.dspace.correctiontype.CorrectionType; + +/** + * Service interface class for the CorrectionType object. + * + * @author Mohamed Eskander (mohamed.eskander at 4science.com) + */ +public interface CorrectionTypeService { + public CorrectionType findOne(String id); + public List findAll(); + public List findByItem(Context context, Item item) throws AuthorizeException, SQLException; + public CorrectionType findByTopic(String topic); +} diff --git a/dspace-api/src/main/java/org/dspace/correctiontype/service/impl/CorrectionTypeServiceImpl.java b/dspace-api/src/main/java/org/dspace/correctiontype/service/impl/CorrectionTypeServiceImpl.java new file mode 100644 index 0000000000..f6a1a54347 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/correctiontype/service/impl/CorrectionTypeServiceImpl.java @@ -0,0 +1,70 @@ +/** + * 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.correctiontype.service.impl; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.collections4.CollectionUtils; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Item; +import org.dspace.core.Context; +import org.dspace.correctiontype.CorrectionType; +import org.dspace.correctiontype.service.CorrectionTypeService; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Service implementation class for the CorrectionType object. + * + * @author Mohamed Eskander (mohamed.eskander at 4science.com) + */ +public class CorrectionTypeServiceImpl implements CorrectionTypeService { + + @Autowired + private List correctionTypes; + + @Override + public CorrectionType findOne(String id) { + List correctionTypes = findAll(); + return correctionTypes.stream() + .filter(correctionType -> + correctionType.getId().equals(id)) + .findFirst().orElse(null); + } + + @Override + public List findAll() { + + if (CollectionUtils.isNotEmpty(correctionTypes)) { + return correctionTypes; + } + + return List.of(); + } + + @Override + public List findByItem(Context context, Item item) throws AuthorizeException, SQLException { + List correctionTypes = new ArrayList<>(); + for (CorrectionType correctionType : findAll()) { + if (correctionType.isAllowed(context, item)) { + correctionTypes.add(correctionType); + } + } + return correctionTypes; + } + + @Override + public CorrectionType findByTopic(String topic) { + List correctionTypes = findAll(); + return correctionTypes.stream() + .filter(correctionType -> + correctionType.getTopic().equals(topic)) + .findFirst().orElse(null); + } +} diff --git a/dspace-api/src/main/java/org/dspace/qaevent/action/QAOpenaireSimpleMetadataAction.java b/dspace-api/src/main/java/org/dspace/qaevent/action/QAOpenaireSimpleMetadataAction.java index 2509b768ae..36d17e09b3 100644 --- a/dspace-api/src/main/java/org/dspace/qaevent/action/QAOpenaireSimpleMetadataAction.java +++ b/dspace-api/src/main/java/org/dspace/qaevent/action/QAOpenaireSimpleMetadataAction.java @@ -31,7 +31,7 @@ public class QAOpenaireSimpleMetadataAction implements QualityAssuranceAction { private String metadataElement; private String metadataQualifier; @Autowired - private ItemService itemService; + protected ItemService itemService; public void setItemService(ItemService itemService) { this.itemService = itemService; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CorrectionTypeConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CorrectionTypeConverter.java new file mode 100644 index 0000000000..8dcf548a55 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CorrectionTypeConverter.java @@ -0,0 +1,41 @@ +/** + * 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.converter; + +import org.dspace.app.rest.model.CorrectionTypeRest; +import org.dspace.app.rest.projection.Projection; +import org.dspace.correctiontype.CorrectionType; +import org.springframework.stereotype.Component; + +/** + * This class provides the method to convert a CorrectionType to its REST representation, the + * CorrectionTypeRest + * + * @author Mohamed Eskander (mohamed.eskander at 4science.com) + */ +@Component +public class CorrectionTypeConverter + implements DSpaceConverter { + + @Override + public CorrectionTypeRest convert(CorrectionType target, Projection projection) { + CorrectionTypeRest targetRest = new CorrectionTypeRest(); + targetRest.setProjection(projection); + targetRest.setId(target.getId()); + targetRest.setTopic(target.getTopic()); + targetRest.setDiscoveryConfiguration(target.getDiscoveryConfiguration()); + targetRest.setCreationForm(target.getCreationForm()); + return targetRest; + } + + @Override + public Class getModelClass() { + return CorrectionType.class; + } + +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/CorrectionTypeRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/CorrectionTypeRest.java new file mode 100644 index 0000000000..0ed0e724f9 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/CorrectionTypeRest.java @@ -0,0 +1,63 @@ +/** + * 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 org.dspace.app.rest.RestResourceController; + +/** + * The CorrectionType REST Resource + * + * @author Mohamed Eskander (mohamed.eskander at 4science.com) + */ +public class CorrectionTypeRest extends BaseObjectRest { + public static final String NAME = "correctiontype"; + public static final String CATEGORY = RestAddressableModel.CONFIGURATION; + + private String topic; + private String discoveryConfiguration; + private String creationForm; + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public String getDiscoveryConfiguration() { + return discoveryConfiguration; + } + + public void setDiscoveryConfiguration(String discoveryConfiguration) { + this.discoveryConfiguration = discoveryConfiguration; + } + + public String getCreationForm() { + return creationForm; + } + + public void setCreationForm(String creationForm) { + this.creationForm = creationForm; + } + + @Override + public String getCategory() { + return CATEGORY; + } + + @Override + public String getType() { + return NAME; + } + + @Override + public Class getController() { + return RestResourceController.class; + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/CorrectionTypeResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/CorrectionTypeResource.java new file mode 100644 index 0000000000..a91a9912b1 --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/CorrectionTypeResource.java @@ -0,0 +1,25 @@ +/** + * 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.CorrectionTypeRest; +import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource; +import org.dspace.app.rest.utils.Utils; + +/** + * CorrectionType Rest HAL Resource. The HAL Resource wraps the REST Resource + * adding support for the links and embedded resources + * + * @author Mohamed Eskander (mohamed.eskander at 4science.com) + */ +@RelNameDSpaceResource(CorrectionTypeRest.NAME) +public class CorrectionTypeResource extends DSpaceResource { + public CorrectionTypeResource(CorrectionTypeRest target, Utils utils) { + super(target, utils); + } +} diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CorrectionTypeRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CorrectionTypeRestRepository.java new file mode 100644 index 0000000000..e1314fe59f --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CorrectionTypeRestRepository.java @@ -0,0 +1,98 @@ +/** + * 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.sql.SQLException; +import java.util.List; +import java.util.UUID; + +import org.dspace.app.rest.Parameter; +import org.dspace.app.rest.SearchRestMethod; +import org.dspace.app.rest.exception.RESTAuthorizationException; +import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException; +import org.dspace.app.rest.exception.UnprocessableEntityException; +import org.dspace.app.rest.model.CorrectionTypeRest; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Item; +import org.dspace.content.service.ItemService; +import org.dspace.core.Context; +import org.dspace.correctiontype.CorrectionType; +import org.dspace.correctiontype.service.CorrectionTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Component; + +/** + * The CorrectionType REST Repository + * + * @author Mohamed Eskander (mohamed.eskander at 4science.com) + */ +@Component(CorrectionTypeRest.CATEGORY + "." + CorrectionTypeRest.NAME) +public class CorrectionTypeRestRepository extends DSpaceRestRepository { + + @Autowired + private CorrectionTypeService correctionTypeService; + + @Autowired + private ItemService itemService; + + @PreAuthorize("permitAll()") + @Override + public CorrectionTypeRest findOne(Context context, String id) { + throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", ""); + } + + @PreAuthorize("permitAll()") + @Override + public Page findAll(Context context, Pageable pageable) { + List correctionTypes = correctionTypeService.findAll(); + return converter.toRestPage(correctionTypes, pageable, utils.obtainProjection()); + } + + @PreAuthorize("permitAll()") + @SearchRestMethod(name = "findByItem") + public Page findByItem(@Parameter(value = "uuid", required = true) UUID uuid, + Pageable pageable) { + Context context = obtainContext(); + try { + Item item = itemService.find(context, uuid); + if (null == item) { + throw new UnprocessableEntityException("item not found"); + } + + List correctionTypes; + try { + correctionTypes = correctionTypeService.findByItem(context, item); + } catch (AuthorizeException e) { + throw new RESTAuthorizationException(e); + } + + return converter.toRestPage(correctionTypes, pageable, utils.obtainProjection()); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @PreAuthorize("permitAll()") + @SearchRestMethod(name = "findByTopic") + public CorrectionTypeRest findByTopic(@Parameter(value = "topic", required = true) String topic) { + CorrectionType correctionType = correctionTypeService.findByTopic(topic); + if (null == correctionType) { + return null; + } + return converter.toRest(correctionType, utils.obtainProjection()); + } + + @Override + public Class getDomainClass() { + return CorrectionTypeRest.class; + } + +} \ No newline at end of file diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/handler/ExternalSourceCorrectionTypeUriListHandler.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/handler/ExternalSourceCorrectionTypeUriListHandler.java new file mode 100644 index 0000000000..2649a9ac9f --- /dev/null +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/handler/ExternalSourceCorrectionTypeUriListHandler.java @@ -0,0 +1,78 @@ +/** + * 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.handler; + +import java.sql.SQLException; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.servlet.http.HttpServletRequest; + +import org.dspace.app.rest.exception.DSpaceBadRequestException; +import org.dspace.authorize.AuthorizeException; +import org.dspace.core.Context; +import org.dspace.correctiontype.CorrectionType; +import org.dspace.correctiontype.service.CorrectionTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * This class extends the {@link ExternalSourceEntryItemUriListHandler} abstract class and implements it specifically + * for the List<{@link CorrectionType}> objects. + * + * @author Mohamed Eskander (mohamed.eskander at 4science.com) + */ +@Component +public class ExternalSourceCorrectionTypeUriListHandler extends ExternalSourceEntryItemUriListHandler { + + @Autowired + private CorrectionTypeService correctionTypeService; + + @Override + @SuppressWarnings("rawtypes") + public boolean supports(List uriList, String method,Class clazz) { + if (clazz != CorrectionType.class) { + return false; + } + return true; + } + + @Override + public CorrectionType handle(Context context, HttpServletRequest request, List uriList) + throws SQLException, AuthorizeException { + return getObjectFromUriList(context, uriList); + } + + @Override + public boolean validate(Context context, HttpServletRequest request, List uriList) + throws AuthorizeException { + if (uriList.size() > 1) { + return false; + } + return true; + } + + + private CorrectionType getObjectFromUriList(Context context, List uriList) { + CorrectionType correctionType = null; + String url = uriList.get(0); + Pattern pattern = Pattern.compile("\\/api\\/config\\/correctiontypes\\/(.*)"); + Matcher matcher = pattern.matcher(url); + if (!matcher.find()) { + throw new DSpaceBadRequestException("The uri: " + url + " doesn't resolve to an correction type"); + } + String id = matcher.group(1); + try { + correctionType = correctionTypeService.findOne(id); + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + return correctionType; + } + +} \ No newline at end of file diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CorrectionTypeRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CorrectionTypeRestRepositoryIT.java new file mode 100644 index 0000000000..90bcb7a30e --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CorrectionTypeRestRepositoryIT.java @@ -0,0 +1,244 @@ +/** + * 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 com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +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 java.util.UUID; + +import org.dspace.app.rest.repository.CorrectionTypeRestRepository; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.builder.CollectionBuilder; +import org.dspace.builder.CommunityBuilder; +import org.dspace.builder.ItemBuilder; +import org.dspace.content.Collection; +import org.dspace.content.Item; +import org.dspace.content.service.ItemService; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +/** + * Test suite for {@link CorrectionTypeRestRepository} + * + * @author Mohamed Eskander (mohamed.eskander at 4science.com) + * + */ +public class CorrectionTypeRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Autowired + private ItemService itemService; + + @Autowired + private AuthorizeService authorizeService; + + @Test + public void findAllTest() throws Exception { + getClient().perform(get("/api/config/correctiontypes")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", greaterThanOrEqualTo(4))) + .andExpect(jsonPath("$._embedded.correctiontypes", containsInAnyOrder( + allOf( + hasJsonPath("$.id", equalTo("addpersonalpath")), + hasJsonPath("$.topic", equalTo("/DSPACEUSERS/RELATIONADD/dc.relation.personalpath")), + hasJsonPath("$.discoveryConfiguration", equalTo("RELATION.PersonPath.Items")), + hasJsonPath("$.creationForm", equalTo("manageRelation")) + ), + allOf( + hasJsonPath("$.id", equalTo("removepersonalpath")), + hasJsonPath("$.topic", equalTo("/DSPACEUSERS/RELATIONREMOVE/dc.relation.personalpath")), + hasJsonPath("$.discoveryConfiguration", equalTo("RELATION.PersonPath.Items")), + hasJsonPath("$.creationForm", equalTo("manageRelation")) + ), + allOf(hasJsonPath( + "$.id", equalTo("addpersonalarchive")), + hasJsonPath("$.topic", equalTo("/DSPACEUSERS/RELATIONADD/dc.relation.personalarchive")), + hasJsonPath("$.discoveryConfiguration", equalTo("RELATION.PersonArchive.Items")), + hasJsonPath("$.creationForm", equalTo("manageRelation")) + ), + allOf( + hasJsonPath("$.id", equalTo("removepersonalarchive")), + hasJsonPath("$.topic", equalTo("/DSPACEUSERS/RELATIONREMOVE/dc.relation.personalarchive")), + hasJsonPath("$.discoveryConfiguration", equalTo("RELATION.PersonArchive.Items")), + hasJsonPath("$.creationForm", equalTo("manageRelation")) + ) + ))); + } + + @Test + public void findOneTest() throws Exception { + getClient().perform(get("/api/config/correctiontypes/test")) + .andExpect(status().isMethodNotAllowed()); + } + + @Test + public void findByItemWithoutUUIDParameterTest() throws Exception { + getClient().perform(get("/api/config/correctiontypes/search/findByItem/")) + .andExpect(status().isBadRequest()); + } + + @Test + public void findByItemNotFoundTest() throws Exception { + getClient().perform(get("/api/config/correctiontypes/search/findByItem/") + .param("uuid", UUID.randomUUID().toString())) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + public void findByItemUnAuthorizedTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context).build(); + Collection collection = CollectionBuilder.createCollection(context, parentCommunity).build(); + Item privateItem = ItemBuilder.createItem(context, collection).build(); + authorizeService.removeAllPolicies(context, privateItem); + context.restoreAuthSystemState(); + + getClient().perform(get("/api/config/correctiontypes/search/findByItem/") + .param("uuid", privateItem.getID().toString())) + .andExpect(status().isUnauthorized()); + } + + @Test + public void findByNotArchivedItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context).build(); + Collection collection = CollectionBuilder.createCollection(context, parentCommunity).build(); + Item item = ItemBuilder.createItem(context, collection).build(); + item.setArchived(false); + itemService.update(context, item); + context.restoreAuthSystemState(); + + getClient().perform(get("/api/config/correctiontypes/search/findByItem/") + .param("uuid", item.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + } + + @Test + public void findByWithdrawnItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context).build(); + Collection collection = CollectionBuilder.createCollection(context, parentCommunity).build(); + Item item = ItemBuilder.createItem(context, collection).withdrawn().build(); + context.restoreAuthSystemState(); + + getClient(getAuthToken(admin.getEmail(), password)) + .perform(get("/api/config/correctiontypes/search/findByItem/") + .param("uuid", item.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + } + + @Test + public void findByNotDiscoverableItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context).build(); + Collection collection = CollectionBuilder.createCollection(context, parentCommunity).build(); + Item item = ItemBuilder.createItem(context, collection).build(); + item.setDiscoverable(false); + itemService.update(context, item); + context.restoreAuthSystemState(); + + getClient().perform(get("/api/config/correctiontypes/search/findByItem/") + .param("uuid", item.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + } + + @Test + public void findByPersonalArchiveItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context).build(); + Collection collection = CollectionBuilder.createCollection(context, parentCommunity).build(); + Item itemOne = ItemBuilder.createItem(context, collection).withEntityType("PersonalArchive").build(); + Item itemTwo = ItemBuilder.createItem(context, collection).withEntityType("PersonalPath").build(); + context.restoreAuthSystemState(); + + getClient().perform(get("/api/config/correctiontypes/search/findByItem/") + .param("uuid", itemOne.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + + getClient().perform(get("/api/config/correctiontypes/search/findByItem/") + .param("uuid", itemTwo.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + } + + @Test + public void findByItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context).build(); + Collection collection = CollectionBuilder.createCollection(context, parentCommunity).build(); + Item item = ItemBuilder.createItem(context, collection).build(); + context.restoreAuthSystemState(); + + getClient().perform(get("/api/config/correctiontypes/search/findByItem/") + .param("uuid", item.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(4))) + .andExpect(jsonPath("$._embedded.correctiontypes", containsInAnyOrder( + allOf( + hasJsonPath("$.id", equalTo("addpersonalpath")), + hasJsonPath("$.topic", equalTo("/DSPACEUSERS/RELATIONADD/dc.relation.personalpath")), + hasJsonPath("$.discoveryConfiguration", equalTo("RELATION.PersonPath.Items")), + hasJsonPath("$.creationForm", equalTo("manageRelation")) + ), + allOf( + hasJsonPath("$.id", equalTo("removepersonalpath")), + hasJsonPath("$.topic", equalTo("/DSPACEUSERS/RELATIONREMOVE/dc.relation.personalpath")), + hasJsonPath("$.discoveryConfiguration", equalTo("RELATION.PersonPath.Items")), + hasJsonPath("$.creationForm", equalTo("manageRelation")) + ), + allOf(hasJsonPath( + "$.id", equalTo("addpersonalarchive")), + hasJsonPath("$.topic", equalTo("/DSPACEUSERS/RELATIONADD/dc.relation.personalarchive")), + hasJsonPath("$.discoveryConfiguration", equalTo("RELATION.PersonArchive.Items")), + hasJsonPath("$.creationForm", equalTo("manageRelation")) + ), + allOf( + hasJsonPath("$.id", equalTo("removepersonalarchive")), + hasJsonPath("$.topic", equalTo("/DSPACEUSERS/RELATIONREMOVE/dc.relation.personalarchive")), + hasJsonPath("$.discoveryConfiguration", equalTo("RELATION.PersonArchive.Items")), + hasJsonPath("$.creationForm", equalTo("manageRelation")) + ) + ))); + } + + @Test + public void findByTopicWithoutTopicParameterTest() throws Exception { + getClient().perform(get("/api/config/correctiontypes/search/findByTopic/")) + .andExpect(status().isBadRequest()); + } + + @Test + public void findByWrongTopicTest() throws Exception { + getClient().perform(get("/api/config/correctiontypes/search/findByTopic/") + .param("topic", "wrongValue")) + .andExpect(status().isNoContent()); + } + + @Test + public void findByTopicTest() throws Exception { + getClient().perform(get("/api/config/correctiontypes/search/findByTopic/") + .param("topic", "/DSPACEUSERS/RELATIONADD/dc.relation.personalpath")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id", equalTo("addpersonalpath"))) + .andExpect(jsonPath("$.topic", equalTo("/DSPACEUSERS/RELATIONADD/dc.relation.personalpath"))) + .andExpect(jsonPath("$.discoveryConfiguration", equalTo("RELATION.PersonPath.Items"))) + .andExpect(jsonPath("$.creationForm", equalTo("manageRelation"))); + } + +} diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/QAEventRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/QAEventRestRepositoryIT.java index dc021f2904..4794cbd459 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/QAEventRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/QAEventRestRepositoryIT.java @@ -11,8 +11,10 @@ import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasNoJsonPath; import static org.dspace.app.rest.matcher.QAEventMatcher.matchQAEventEntry; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; @@ -26,6 +28,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.util.ArrayList; import java.util.List; +import java.util.UUID; import javax.ws.rs.core.MediaType; import org.dspace.app.rest.matcher.ItemMatcher; @@ -33,6 +36,7 @@ import org.dspace.app.rest.matcher.QAEventMatcher; import org.dspace.app.rest.model.patch.Operation; import org.dspace.app.rest.model.patch.ReplaceOperation; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.authorize.service.AuthorizeService; import org.dspace.builder.CollectionBuilder; import org.dspace.builder.CommunityBuilder; import org.dspace.builder.EntityTypeBuilder; @@ -60,6 +64,9 @@ public class QAEventRestRepositoryIT extends AbstractControllerIntegrationTest { @Autowired private QAEventsDao qaEventsDao; + @Autowired + private AuthorizeService authorizeService; + @Test public void findAllNotImplementedTest() throws Exception { String adminToken = getAuthToken(admin.getEmail(), password); @@ -787,4 +794,336 @@ public class QAEventRestRepositoryIT extends AbstractControllerIntegrationTest { assertThat(processedEvent.getEperson().getID(), is(admin.getID())); } + + @Test + public void createNBEventByCorrectionTypeUnAuthorizedTest() throws Exception { + getClient().perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/addpersonalarchive\n" + + "https://localhost:8080/server/api/core/items/" + UUID.randomUUID() + "\n" + + "https://localhost:8080/server/api/core/items/" + UUID.randomUUID() + )) + .andExpect(status().isUnauthorized()); + } + + @Test + public void createNBEventByCorrectionTypeWithMissingUriTest() throws Exception { + String adminToken = getAuthToken(admin.getEmail(), password); + + getClient(adminToken).perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/addpersonalarchive\n" + + "https://localhost:8080/server/api/core/items/" + UUID.randomUUID() + )) + .andExpect(status().isBadRequest()); + } + + @Test + public void createNBEventByCorrectionTypeWithPersonalArchiveAsTargetItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community").build(); + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1").build(); + + Item personalArchive = ItemBuilder.createItem(context, col1) + .withEntityType("PersonalArchive") + .withTitle("personal archive item").build(); + + context.restoreAuthSystemState(); + + String adminToken = getAuthToken(admin.getEmail(), password); + + getClient(adminToken) + .perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/addpersonalarchive\n" + + "https://localhost:8080/server/api/core/items/" + personalArchive.getID() + "\n" + + "https://localhost:8080/server/api/core/items/" + personalArchive.getID() + )) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + public void createNBEventByCorrectionTypeWithPersonalPathAsTargetItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community").build(); + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1").build(); + + Item personalPath = ItemBuilder.createItem(context, col1) + .withEntityType("PersonalPath") + .withTitle("personal path item").build(); + + context.restoreAuthSystemState(); + + String adminToken = getAuthToken(admin.getEmail(), password); + + getClient(adminToken) + .perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/addpersonalarchive\n" + + "https://localhost:8080/server/api/core/items/" + personalPath.getID() + "\n" + + "https://localhost:8080/server/api/core/items/" + personalPath.getID() + )) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + public void createNBEventByNotFoundCorrectionTypeTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community").build(); + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1").build(); + + Item targetItem = ItemBuilder.createItem(context, col1) + .withEntityType("Publication") + .withTitle("publication item").build(); + + Item relatedItem = ItemBuilder.createItem(context, col1) + .withEntityType("PersonalArchive") + .withTitle("personal archive item").build(); + + context.restoreAuthSystemState(); + + String adminToken = getAuthToken(admin.getEmail(), password); + + getClient(adminToken) + .perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/test\n" + + "https://localhost:8080/server/api/core/items/" + targetItem.getID() + "\n" + + "https://localhost:8080/server/api/core/items/" + relatedItem.getID() + )) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + public void createNBEventByCorrectionTypeButNotFoundTargetItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community").build(); + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1").build(); + + Item personalArchive = ItemBuilder.createItem(context, col1) + .withEntityType("PersonalArchive") + .withTitle("personal archive item").build(); + + context.restoreAuthSystemState(); + + String adminToken = getAuthToken(admin.getEmail(), password); + + getClient(adminToken) + .perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/addpersonalarchive\n" + + "https://localhost:8080/server/api/core/items/" + UUID.randomUUID() + "\n" + + "https://localhost:8080/server/api/core/items/" + personalArchive.getID() + )) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + public void createNBEventByCorrectionTypeButNotFoundRelatedItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community").build(); + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1").build(); + + Item item = ItemBuilder.createItem(context, col1) + .withEntityType("Publication") + .withTitle("publication item").build(); + + context.restoreAuthSystemState(); + + String adminToken = getAuthToken(admin.getEmail(), password); + + getClient(adminToken) + .perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/addpersonalarchive\n" + + "https://localhost:8080/server/api/core/items/" + item.getID() + "\n" + + "https://localhost:8080/server/api/core/items/" + UUID.randomUUID() + )) + .andExpect(status().isUnprocessableEntity()); + } + + @Test + public void createNBEventByCorrectionIsForbiddenTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community").build(); + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1").build(); + Item targetItem = ItemBuilder.createItem(context, col1) + .withEntityType("Publication") + .withTitle("publication item").build(); + + Item relatedItem = ItemBuilder.createItem(context, col1) + .withEntityType("PersonalArchive") + .withTitle("personal archive item").build(); + + authorizeService.removeAllPolicies(context, targetItem); + + context.restoreAuthSystemState(); + + String authToken = getAuthToken(eperson.getEmail(), password); + + //WHEN: create nbEvent and accept it + getClient(authToken) + .perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/addpersonalarchive\n" + + "https://localhost:8080/server/api/core/items/" + targetItem.getID() + "\n" + + "https://localhost:8080/server/api/core/items/" + relatedItem.getID() + )) + .andExpect(status().isForbidden()); + + } + + @Test + public void createNBEventByCorrectionTypeTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community").build(); + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1").build(); + Item targetItem = ItemBuilder.createItem(context, col1) + .withEntityType("Publication") + .withTitle("publication item").build(); + + Item relatedItem = ItemBuilder.createItem(context, col1) + .withEntityType("PersonalArchive") + .withTitle("personal archive item").build(); + + context.restoreAuthSystemState(); + + String adminToken = getAuthToken(admin.getEmail(), password); + + //WHEN: create nbEvent and accept it + getClient(adminToken) + .perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/addpersonalarchive\n" + + "https://localhost:8080/server/api/core/items/" + targetItem.getID() + "\n" + + "https://localhost:8080/server/api/core/items/" + relatedItem.getID() + )) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$", allOf( + hasJsonPath("$.originalId", is("handle:" + targetItem.getHandle())), + hasJsonPath("$.topic", + equalTo("/DSPACEUSERS/RELATIONADD/dc.relation.personalarchive")), + hasJsonPath("$.title", is(targetItem.getName())), + hasJsonPath("$.trust", is("1.000")), + hasJsonPath("$.status", is("PENDING")), + hasJsonPath("$.type", is("nbevent"))))); + + //THEN: nbEvent has been accepted and metadata has been added + getClient(adminToken).perform(get("/api/core/items/" + targetItem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.metadata['dc.relation.personalarchive'].[0].value", + equalTo(relatedItem.getID().toString()))) + .andExpect(jsonPath("$.metadata['dc.relation.personalarchive'].[0].authority", + equalTo(relatedItem.getID().toString()))); + + //THEN: no nbEvents found for the topic + getClient(adminToken).perform(get("/api/integration/nbevents/search/findByTopic") + .param("topic", "/DSPACEUSERS/RELATIONADD/dc.relation.personalarchive")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page.totalElements", is(0))); + } + + @Test + public void createNBEventByCorrectionTypeAlreadyLinkedTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community").build(); + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity) + .withName("Collection 1").build(); + Item targetItem = ItemBuilder.createItem(context, col1) + .withEntityType("Publication") + .withTitle("publication item").build(); + + Item relatedItem = ItemBuilder.createItem(context, col1) + .withEntityType("PersonalArchive") + .withTitle("personal archive item").build(); + + context.restoreAuthSystemState(); + + String adminToken = getAuthToken(admin.getEmail(), password); + + //WHEN: create nbEvent and accept it + getClient(adminToken) + .perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/addpersonalarchive\n" + + "https://localhost:8080/server/api/core/items/" + targetItem.getID() + "\n" + + "https://localhost:8080/server/api/core/items/" + relatedItem.getID() + )) + .andExpect(status().isCreated()); + + //create nbEvent Item already linked before + getClient(adminToken) + .perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/addpersonalarchive\n" + + "https://localhost:8080/server/api/core/items/" + targetItem.getID() + "\n" + + "https://localhost:8080/server/api/core/items/" + relatedItem.getID() + )) + .andExpect(status().isUnprocessableEntity()); + + //create nbEvent to remove relation metadata + getClient(adminToken) + .perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/removepersonalarchive\n" + + "https://localhost:8080/server/api/core/items/" + targetItem.getID() + "\n" + + "https://localhost:8080/server/api/core/items/" + relatedItem.getID() + )) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$", allOf( + hasJsonPath("$.originalId", is("handle:" + targetItem.getHandle())), + hasJsonPath("$.topic", + equalTo("/DSPACEUSERS/RELATIONREMOVE/dc.relation.personalarchive")), + hasJsonPath("$.title", is(targetItem.getName())), + hasJsonPath("$.trust", is("1.000")), + hasJsonPath("$.status", is("PENDING")), + hasJsonPath("$.type", is("nbevent"))))); + + //THEN: nbEvent has been accepted and metadata has been removed + getClient(adminToken).perform(get("/api/core/items/" + targetItem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.metadata['dc.relation.personalarchive']").doesNotExist()) + .andExpect(jsonPath("$.metadata['dc.relation.personalarchive']").doesNotExist()); + + //create nbEvent to remove relation metadata not exist + getClient(adminToken) + .perform(post("/api/integration/nbevents/") + .contentType(org.springframework.http.MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/server/api/config/correctiontypes/removepersonalarchive\n" + + "https://localhost:8080/server/api/core/items/" + targetItem.getID() + "\n" + + "https://localhost:8080/server/api/core/items/" + relatedItem.getID() + )) + .andExpect(status().isUnprocessableEntity()); + + + } + } diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index 3ede01647c..49f464eaf4 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -152,5 +152,7 @@ + + diff --git a/dspace/config/spring/api/correction-types.xml b/dspace/config/spring/api/correction-types.xml new file mode 100644 index 0000000000..157004211b --- /dev/null +++ b/dspace/config/spring/api/correction-types.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/spring/api/qaevents.xml b/dspace/config/spring/api/qaevents.xml index 25bb282672..c58c65ad8a 100644 --- a/dspace/config/spring/api/qaevents.xml +++ b/dspace/config/spring/api/qaevents.xml @@ -25,7 +25,11 @@ - + + + + + @@ -64,5 +68,21 @@ - + + + + + + + + + + + + + + + + +