mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 18:14:26 +00:00
Merged in coar-notify-7_CST-12115 (pull request #1251)
[CST-12115] added support to decide if a correction suggestion should be automatically processed Approved-by: Andrea Bollini
This commit is contained in:
@@ -7,11 +7,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.dspace.app.ldn.action;
|
package org.dspace.app.ldn.action;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.dspace.app.ldn.NotifyServiceEntity;
|
||||||
import org.dspace.app.ldn.model.Notification;
|
import org.dspace.app.ldn.model.Notification;
|
||||||
|
import org.dspace.app.ldn.service.LDNMessageService;
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.content.QAEvent;
|
import org.dspace.content.QAEvent;
|
||||||
import org.dspace.content.service.ItemService;
|
import org.dspace.content.service.ItemService;
|
||||||
@@ -33,14 +37,16 @@ public class LDNCorrectionAction implements LDNAction {
|
|||||||
protected ItemService itemService;
|
protected ItemService itemService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private QAEventService qaEventService;
|
private QAEventService qaEventService;
|
||||||
|
@Autowired
|
||||||
|
private LDNMessageService ldnMessageService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionStatus execute(Notification notification, Item item) throws Exception {
|
public ActionStatus execute(Notification notification, Item item) throws Exception {
|
||||||
ActionStatus result = ActionStatus.ABORT;
|
ActionStatus result;
|
||||||
Context context = ContextUtil.obtainCurrentRequestContext();
|
Context context = ContextUtil.obtainCurrentRequestContext();
|
||||||
QAEvent qaEvent = new QAEvent(QAEvent.COAR_NOTIFY,
|
QAEvent qaEvent = new QAEvent(QAEvent.COAR_NOTIFY,
|
||||||
notification.getObject().getId(), item.getID().toString(), item.getName(),
|
notification.getObject().getId(), item.getID().toString(), item.getName(),
|
||||||
this.getQaEventTopic(), 0d,
|
this.getQaEventTopic(), getScore(context, notification).doubleValue(),
|
||||||
"{\"abstracts[0]\": \"" + notification.getObject().getIetfCiteAs() + "\"}"
|
"{\"abstracts[0]\": \"" + notification.getObject().getIetfCiteAs() + "\"}"
|
||||||
, new Date());
|
, new Date());
|
||||||
qaEventService.store(context, qaEvent);
|
qaEventService.store(context, qaEvent);
|
||||||
@@ -49,6 +55,21 @@ public class LDNCorrectionAction implements LDNAction {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BigDecimal getScore(Context context, Notification notification) throws SQLException {
|
||||||
|
|
||||||
|
if (notification.getOrigin() == null) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
NotifyServiceEntity service = ldnMessageService.findNotifyService(context, notification.getOrigin());
|
||||||
|
|
||||||
|
if (service == null) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return service.getScore();
|
||||||
|
}
|
||||||
|
|
||||||
public String getQaEventTopic() {
|
public String getQaEventTopic() {
|
||||||
return qaEventTopic;
|
return qaEventTopic;
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,9 @@ import java.sql.SQLException;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.dspace.app.ldn.LDNMessageEntity;
|
import org.dspace.app.ldn.LDNMessageEntity;
|
||||||
|
import org.dspace.app.ldn.NotifyServiceEntity;
|
||||||
import org.dspace.app.ldn.model.Notification;
|
import org.dspace.app.ldn.model.Notification;
|
||||||
|
import org.dspace.app.ldn.model.Service;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,4 +96,14 @@ public interface LDNMessageService {
|
|||||||
* @param context The DSpace context
|
* @param context The DSpace context
|
||||||
*/
|
*/
|
||||||
public int extractAndProcessMessageFromQueue(Context context) throws SQLException;
|
public int extractAndProcessMessageFromQueue(Context context) throws SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find the related notify service entity
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
* @param service the service
|
||||||
|
* @return the NotifyServiceEntity
|
||||||
|
* @throws SQLException if something goes wrong
|
||||||
|
*/
|
||||||
|
public NotifyServiceEntity findNotifyService(Context context, Service service) throws SQLException;
|
||||||
}
|
}
|
||||||
|
@@ -148,7 +148,7 @@ public class LDNMessageServiceImpl implements LDNMessageService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private NotifyServiceEntity findNotifyService(Context context, Service service) throws SQLException {
|
public NotifyServiceEntity findNotifyService(Context context, Service service) throws SQLException {
|
||||||
return notifyServiceDao.findByLdnUrl(context, service.getInbox());
|
return notifyServiceDao.findByLdnUrl(context, service.getInbox());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -197,6 +197,7 @@ public class QAEvent {
|
|||||||
public Class<? extends QAMessageDTO> getMessageDtoClass() {
|
public Class<? extends QAMessageDTO> getMessageDtoClass() {
|
||||||
switch (getSource()) {
|
switch (getSource()) {
|
||||||
case OPENAIRE_SOURCE:
|
case OPENAIRE_SOURCE:
|
||||||
|
case COAR_NOTIFY:
|
||||||
return OpenaireMessageDTO.class;
|
return OpenaireMessageDTO.class;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown event's source: " + getSource());
|
throw new IllegalArgumentException("Unknown event's source: " + getSource());
|
||||||
|
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* 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.qaevent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration of possible actions to perform over a {@link org.dspace.content.QAEvent}
|
||||||
|
*
|
||||||
|
* @author Mohamed Eskander (mohamed.eskander at 4science.com)
|
||||||
|
*/
|
||||||
|
public enum AutomaticProcessingAction {
|
||||||
|
REJECT, ACCEPT, IGNORE
|
||||||
|
}
|
@@ -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.qaevent;
|
||||||
|
|
||||||
|
import org.dspace.content.QAEvent;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface allows the implemnetation of Automation Processing rules
|
||||||
|
* defining which {@link AutomaticProcessingAction} should be eventually
|
||||||
|
* performed on a specific {@link QAEvent}
|
||||||
|
*
|
||||||
|
* @author Mohamed Eskander (mohamed.eskander at 4science.com)
|
||||||
|
*/
|
||||||
|
public interface QAEventAutomaticProcessingEvaluation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate a {@link QAEvent} to decide which, if any, {@link AutomaticProcessingAction} should be performed
|
||||||
|
*
|
||||||
|
* @param context the DSpace context
|
||||||
|
* @param qaEvent the quality assurance event
|
||||||
|
* @return an action of {@link AutomaticProcessingAction} or null if no automatic action should be performed
|
||||||
|
*/
|
||||||
|
AutomaticProcessingAction evaluateAutomaticProcessing(Context context, QAEvent qaEvent);
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,151 @@
|
|||||||
|
/**
|
||||||
|
* 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.qaevent;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.content.QAEvent;
|
||||||
|
import org.dspace.content.logic.LogicalStatement;
|
||||||
|
import org.dspace.content.service.ItemService;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configurable implementation of {@link QAEventAutomaticProcessingEvaluation} allowing to define thresholds for
|
||||||
|
* automatic acceptance, rejection or ignore of {@link QAEvent} matching a specific, optional, item filter
|
||||||
|
* {@link LogicalStatement}. If the item filter is not defined only the score threshold will be used.
|
||||||
|
*
|
||||||
|
* @author Mohamed Eskander (mohamed.eskander at 4science.com)
|
||||||
|
*/
|
||||||
|
public class QAScoreAutomaticProcessingEvaluation implements QAEventAutomaticProcessingEvaluation {
|
||||||
|
/**
|
||||||
|
* The minimum score of QAEvent to be considered for automatic approval (trust must be greater or equals to that)
|
||||||
|
*/
|
||||||
|
private double scoreToApprove;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The threshold under which QAEvent are considered for automatic ignore (trust must be less or equals to that)
|
||||||
|
*/
|
||||||
|
private double scoreToIgnore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The threshold under which QAEvent are considered for automatic rejection (trust must be less or equals to that)
|
||||||
|
*/
|
||||||
|
private double scoreToReject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The optional logical statement that must pass for item target of a QAEvent to be considered for automatic
|
||||||
|
* approval
|
||||||
|
*/
|
||||||
|
private LogicalStatement itemFilterToApprove;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The optional logical statement that must pass for item target of a QAEvent to be considered for automatic
|
||||||
|
* ignore
|
||||||
|
*/
|
||||||
|
private LogicalStatement itemFilterToIgnore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The optional logical statement that must pass for item target of a QAEvent to be considered for automatic
|
||||||
|
* rejection
|
||||||
|
*/
|
||||||
|
private LogicalStatement itemFilterToReject;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ItemService itemService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AutomaticProcessingAction evaluateAutomaticProcessing(Context context, QAEvent qaEvent) {
|
||||||
|
Item item = findItem(context, qaEvent.getTarget());
|
||||||
|
|
||||||
|
if (shouldReject(context, qaEvent.getTrust(), item)) {
|
||||||
|
return AutomaticProcessingAction.REJECT;
|
||||||
|
} else if (shouldIgnore(context, qaEvent.getTrust(), item)) {
|
||||||
|
return AutomaticProcessingAction.IGNORE;
|
||||||
|
} else if (shouldApprove(context, qaEvent.getTrust(), item)) {
|
||||||
|
return AutomaticProcessingAction.ACCEPT;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Item findItem(Context context, String uuid) {
|
||||||
|
try {
|
||||||
|
return itemService.find(context, UUID.fromString(uuid));
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldReject(Context context, double trust, Item item) {
|
||||||
|
return trust <= scoreToReject &&
|
||||||
|
(itemFilterToReject == null || itemFilterToReject.getResult(context, item));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldIgnore(Context context, double trust, Item item) {
|
||||||
|
return trust <= scoreToIgnore &&
|
||||||
|
(itemFilterToIgnore == null || itemFilterToIgnore.getResult(context, item));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldApprove(Context context, double trust, Item item) {
|
||||||
|
return trust >= scoreToApprove &&
|
||||||
|
(itemFilterToApprove == null || itemFilterToApprove.getResult(context, item));
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getScoreToApprove() {
|
||||||
|
return scoreToApprove;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScoreToApprove(double scoreToApprove) {
|
||||||
|
this.scoreToApprove = scoreToApprove;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getScoreToIgnore() {
|
||||||
|
return scoreToIgnore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScoreToIgnore(double scoreToIgnore) {
|
||||||
|
this.scoreToIgnore = scoreToIgnore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getScoreToReject() {
|
||||||
|
return scoreToReject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScoreToReject(double scoreToReject) {
|
||||||
|
this.scoreToReject = scoreToReject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogicalStatement getItemFilterToApprove() {
|
||||||
|
return itemFilterToApprove;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItemFilterToApprove(LogicalStatement itemFilterToApprove) {
|
||||||
|
this.itemFilterToApprove = itemFilterToApprove;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogicalStatement getItemFilterToIgnore() {
|
||||||
|
return itemFilterToIgnore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItemFilterToIgnore(LogicalStatement itemFilterToIgnore) {
|
||||||
|
this.itemFilterToIgnore = itemFilterToIgnore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogicalStatement getItemFilterToReject() {
|
||||||
|
return itemFilterToReject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItemFilterToReject(LogicalStatement itemFilterToReject) {
|
||||||
|
this.itemFilterToReject = itemFilterToReject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -16,6 +16,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -41,14 +42,18 @@ import org.dspace.content.QAEvent;
|
|||||||
import org.dspace.content.service.ItemService;
|
import org.dspace.content.service.ItemService;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.handle.service.HandleService;
|
import org.dspace.handle.service.HandleService;
|
||||||
|
import org.dspace.qaevent.AutomaticProcessingAction;
|
||||||
|
import org.dspace.qaevent.QAEventAutomaticProcessingEvaluation;
|
||||||
import org.dspace.qaevent.QASource;
|
import org.dspace.qaevent.QASource;
|
||||||
import org.dspace.qaevent.QATopic;
|
import org.dspace.qaevent.QATopic;
|
||||||
import org.dspace.qaevent.dao.QAEventsDao;
|
import org.dspace.qaevent.dao.QAEventsDao;
|
||||||
import org.dspace.qaevent.dao.impl.QAEventsDaoImpl;
|
import org.dspace.qaevent.dao.impl.QAEventsDaoImpl;
|
||||||
|
import org.dspace.qaevent.service.QAEventActionService;
|
||||||
import org.dspace.qaevent.service.QAEventService;
|
import org.dspace.qaevent.service.QAEventService;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of {@link QAEventService} that use Solr to store events. When
|
* Implementation of {@link QAEventService} that use Solr to store events. When
|
||||||
@@ -73,6 +78,13 @@ public class QAEventServiceImpl implements QAEventService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private QAEventsDaoImpl qaEventsDao;
|
private QAEventsDaoImpl qaEventsDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("qaAutomaticProcessingMap")
|
||||||
|
private Map<String, QAEventAutomaticProcessingEvaluation> qaAutomaticProcessingMap;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private QAEventActionService qaEventActionService;
|
||||||
|
|
||||||
private ObjectMapper jsonMapper;
|
private ObjectMapper jsonMapper;
|
||||||
|
|
||||||
public QAEventServiceImpl() {
|
public QAEventServiceImpl() {
|
||||||
@@ -321,12 +333,43 @@ public class QAEventServiceImpl implements QAEventService {
|
|||||||
updateRequest.process(getSolr());
|
updateRequest.process(getSolr());
|
||||||
|
|
||||||
getSolr().commit();
|
getSolr().commit();
|
||||||
|
|
||||||
|
performAutomaticProcessingIfNeeded(context, dto);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void performAutomaticProcessingIfNeeded(Context context, QAEvent qaEvent) {
|
||||||
|
QAEventAutomaticProcessingEvaluation evaluation = qaAutomaticProcessingMap.get(qaEvent.getSource());
|
||||||
|
|
||||||
|
if (evaluation == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AutomaticProcessingAction action = evaluation.evaluateAutomaticProcessing(context, qaEvent);
|
||||||
|
|
||||||
|
if (action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case REJECT:
|
||||||
|
qaEventActionService.reject(context, qaEvent);
|
||||||
|
break;
|
||||||
|
case IGNORE:
|
||||||
|
qaEventActionService.discard(context, qaEvent);
|
||||||
|
break;
|
||||||
|
case ACCEPT:
|
||||||
|
qaEventActionService.accept(context, qaEvent);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown automatic action requested " + action);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QAEvent findEventByEventId(String eventId) {
|
public QAEvent findEventByEventId(String eventId) {
|
||||||
SolrQuery param = new SolrQuery(EVENT_ID + ":" + eventId);
|
SolrQuery param = new SolrQuery(EVENT_ID + ":" + eventId);
|
||||||
|
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:context="http://www.springframework.org/schema/context"
|
||||||
|
xmlns:util="http://www.springframework.org/schema/util"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||||
|
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||||
|
http://www.springframework.org/schema/context
|
||||||
|
http://www.springframework.org/schema/context/spring-context-2.5.xsd
|
||||||
|
http://www.springframework.org/schema/util
|
||||||
|
http://www.springframework.org/schema/util/spring-util.xsd">
|
||||||
|
|
||||||
|
<context:annotation-config /> <!-- allows us to use spring annotations in beans -->
|
||||||
|
|
||||||
|
<!-- this file contains extra beans related to the qaevent feature configured only for test purpose -->
|
||||||
|
<util:map id="qaAutomaticProcessingMap">
|
||||||
|
<entry key="coar-notify" value-ref="qaScoreEvaluation"/>
|
||||||
|
</util:map>
|
||||||
|
|
||||||
|
<bean id="qaScoreEvaluation" class="org.dspace.qaevent.QAScoreAutomaticProcessingEvaluation">
|
||||||
|
<property name="scoreToReject" value="0.3" />
|
||||||
|
<property name="scoreToIgnore" value="0.5" />
|
||||||
|
<property name="scoreToApprove" value="0.8" />
|
||||||
|
<property name="itemFilterToReject" ref="simple-demo_filter" />
|
||||||
|
<property name="itemFilterToIgnore" ref="simple-demo_filter" />
|
||||||
|
<property name="itemFilterToApprove" ref="simple-demo_filter" />
|
||||||
|
</bean>
|
||||||
|
</beans>
|
@@ -10,6 +10,7 @@ package org.dspace.app.rest;
|
|||||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasNoJsonPath;
|
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasNoJsonPath;
|
||||||
import static org.dspace.app.rest.matcher.QAEventMatcher.matchQAEventEntry;
|
import static org.dspace.app.rest.matcher.QAEventMatcher.matchQAEventEntry;
|
||||||
|
import static org.dspace.content.QAEvent.COAR_NOTIFY;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
@@ -831,4 +832,140 @@ public class QAEventRestRepositoryIT extends AbstractControllerIntegrationTest {
|
|||||||
assertThat(processedEvent.getEperson().getID(), is(admin.getID()));
|
assertThat(processedEvent.getEperson().getID(), is(admin.getID()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createQAEventsAndAcceptAutomaticallyByScoreAndFilterTest() 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).withTitle("demo").build();
|
||||||
|
|
||||||
|
QAEvent event =
|
||||||
|
QAEventBuilder.createTarget(context, item)
|
||||||
|
.withSource(COAR_NOTIFY)
|
||||||
|
.withTrust(0.8)
|
||||||
|
.withTopic("ENRICH/MORE/REVIEW")
|
||||||
|
.withMessage("{\"abstracts[0]\": \"https://doi.org/10.3214/987654\"}")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
String authToken = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
getClient(authToken).perform(get("/api/core/items/" + item.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.metadata['datacite.relation.isReviewedBy'][0].value",
|
||||||
|
is("https://doi.org/10.3214/987654")));
|
||||||
|
|
||||||
|
getClient(authToken).perform(get("/api/integration/qualityassuranceevents/" + event.getEventId()))
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createQAEventsAndIgnoreAutomaticallyByScoreAndFilterTest() 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).withTitle("demo").build();
|
||||||
|
|
||||||
|
QAEvent event =
|
||||||
|
QAEventBuilder.createTarget(context, item)
|
||||||
|
.withSource(COAR_NOTIFY)
|
||||||
|
.withTrust(0.4)
|
||||||
|
.withTopic("ENRICH/MORE/REVIEW")
|
||||||
|
.withMessage("{\"abstracts[0]\": \"https://doi.org/10.3214/987654\"}")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
String authToken = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
getClient(authToken).perform(get("/api/core/items/" + item.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.metadata['datacite.relation.isReviewedBy']").doesNotExist());
|
||||||
|
|
||||||
|
getClient(authToken).perform(get("/api/integration/qualityassuranceevents/" + event.getEventId()))
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createQAEventsAndRejectAutomaticallyByScoreAndFilterTest() 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).withTitle("demo").build();
|
||||||
|
|
||||||
|
QAEvent event =
|
||||||
|
QAEventBuilder.createTarget(context, item)
|
||||||
|
.withSource(COAR_NOTIFY)
|
||||||
|
.withTrust(0.3)
|
||||||
|
.withTopic("ENRICH/MORE/REVIEW")
|
||||||
|
.withMessage("{\"abstracts[0]\": \"https://doi.org/10.3214/987654\"}")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
String authToken = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
getClient(authToken).perform(get("/api/core/items/" + item.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.metadata['datacite.relation.isReviewedBy']").doesNotExist());
|
||||||
|
|
||||||
|
getClient(authToken).perform(get("/api/integration/qualityassuranceevents/" + event.getEventId()))
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createQAEventsAndDoNothingScoreNotInRangTest() 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).withTitle("demo").build();
|
||||||
|
|
||||||
|
QAEvent event =
|
||||||
|
QAEventBuilder.createTarget(context, item)
|
||||||
|
.withSource(COAR_NOTIFY)
|
||||||
|
.withTrust(0.7)
|
||||||
|
.withTopic("ENRICH/MORE/REVIEW")
|
||||||
|
.withMessage("{\"abstracts[0]\": \"https://doi.org/10.3214/987654\"}")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
String authToken = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
getClient(authToken).perform(get("/api/core/items/" + item.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.metadata['datacite.relation.isReviewedBy']").doesNotExist());
|
||||||
|
|
||||||
|
getClient(authToken).perform(get("/api/integration/qualityassuranceevents/" + event.getEventId())
|
||||||
|
.param("projection", "full"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", QAEventMatcher.matchQAEventFullEntry(event)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createQAEventsAndDoNothingFilterNotCompatibleWithItemTest() 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).withTitle("item title").build();
|
||||||
|
|
||||||
|
QAEvent event =
|
||||||
|
QAEventBuilder.createTarget(context, item)
|
||||||
|
.withSource(COAR_NOTIFY)
|
||||||
|
.withTrust(0.8)
|
||||||
|
.withTopic("ENRICH/MORE/REVIEW")
|
||||||
|
.withMessage("{\"abstracts[0]\": \"https://doi.org/10.3214/987654\"}")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
String authToken = getAuthToken(admin.getEmail(), password);
|
||||||
|
|
||||||
|
getClient(authToken).perform(get("/api/core/items/" + item.getID()))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.metadata['datacite.relation.isReviewedBy']").doesNotExist());
|
||||||
|
|
||||||
|
getClient(authToken).perform(get("/api/integration/qualityassuranceevents/" + event.getEventId())
|
||||||
|
.param("projection", "full"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$", QAEventMatcher.matchQAEventFullEntry(event)));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -928,6 +928,7 @@ registry.metadata.load = schema-publicationVolume-types.xml
|
|||||||
registry.metadata.load = openaire4-types.xml
|
registry.metadata.load = openaire4-types.xml
|
||||||
registry.metadata.load = dspace-types.xml
|
registry.metadata.load = dspace-types.xml
|
||||||
registry.metadata.load = iiif-types.xml
|
registry.metadata.load = iiif-types.xml
|
||||||
|
registry.metadata.load = datacite-types.xml
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------#
|
#---------------------------------------------------------------#
|
||||||
|
@@ -2,10 +2,13 @@
|
|||||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xmlns:context="http://www.springframework.org/schema/context"
|
xmlns:context="http://www.springframework.org/schema/context"
|
||||||
|
xmlns:util="http://www.springframework.org/schema/util"
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||||
http://www.springframework.org/schema/context
|
http://www.springframework.org/schema/context
|
||||||
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
|
http://www.springframework.org/schema/context/spring-context-2.5.xsd
|
||||||
|
http://www.springframework.org/schema/util
|
||||||
|
http://www.springframework.org/schema/util/spring-util.xsd">
|
||||||
|
|
||||||
<context:annotation-config /> <!-- allows us to use spring annotations in beans -->
|
<context:annotation-config /> <!-- allows us to use spring annotations in beans -->
|
||||||
|
|
||||||
@@ -72,5 +75,25 @@
|
|||||||
</map>
|
</map>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
To configure rules to automatic process specific qaevent you must provide a qaAutomaticProcessingMap
|
||||||
|
where the keys are the qaevent source provider name and the value is a reference to a
|
||||||
|
AutomaticProcessingEvaluation implementation. Below you can find an example of configuration defining
|
||||||
|
some thresholds rules for the coar-notify generated QAEvent to be approved, rejected and ignored
|
||||||
|
-->
|
||||||
|
<!--
|
||||||
|
<util:map id="qaAutomaticProcessingMap">
|
||||||
|
<entry key="coar-notify" value-ref="qaScoreEvaluation"/>
|
||||||
|
</util:map>
|
||||||
|
|
||||||
|
<bean id="qaScoreEvaluation" class="org.dspace.qaevent.QAScoreAutomaticProcessingEvaluation">
|
||||||
|
<property name="scoreToReject" value="0.3" />
|
||||||
|
<property name="scoreToIgnore" value="0.5" />
|
||||||
|
<property name="scoreToApprove" value="0.8" />
|
||||||
|
<property name="itemFilterToReject" ref="simple-demo_filter" />
|
||||||
|
<property name="itemFilterToIgnore" ref="simple-demo_filter" />
|
||||||
|
<property name="itemFilterToApprove" ref="simple-demo_filter" />
|
||||||
|
</bean>
|
||||||
|
-->
|
||||||
</beans>
|
</beans>
|
||||||
|
Reference in New Issue
Block a user