CST-12236 rename and expose ldn inbox url

This commit is contained in:
frabacche
2023-10-26 16:17:50 +02:00
15 changed files with 446 additions and 91 deletions

View File

@@ -54,6 +54,11 @@ public class LDNMessageEntity implements ReloadableEntity<String> {
*/
public static final Integer QUEUE_STATUS_FAILED = 4;
/**
* Message must not be processed
*/
public static final Integer QUEUE_STATUS_UNTRUSTED = 5;
@Id
private String id;

View File

@@ -7,10 +7,7 @@
*/
package org.dspace.app.ldn.action;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -51,7 +48,7 @@ public class LDNCorrectionAction implements LDNAction {
return result;
}
public String getQaEventTopic() {
return qaEventTopic;
}

View File

@@ -40,7 +40,7 @@ public class LDNMessageDaoImpl extends AbstractHibernateDAO<LDNMessageEntity> im
public List<LDNMessageEntity> findOldestMessageToProcess(Context context, int max_attempts) throws SQLException {
// looking for oldest failed-processed message
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, LDNMessageEntity.class);
CriteriaQuery<LDNMessageEntity> criteriaQuery = getCriteriaQuery(criteriaBuilder, LDNMessageEntity.class);
Root<LDNMessageEntity> root = criteriaQuery.from(LDNMessageEntity.class);
criteriaQuery.select(root);
List<Predicate> andPredicates = new ArrayList<>(3);
@@ -65,7 +65,7 @@ public class LDNMessageDaoImpl extends AbstractHibernateDAO<LDNMessageEntity> im
public List<LDNMessageEntity> findProcessingTimedoutMessages(Context context, int max_attempts)
throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, LDNMessageEntity.class);
CriteriaQuery<LDNMessageEntity> criteriaQuery = getCriteriaQuery(criteriaBuilder, LDNMessageEntity.class);
Root<LDNMessageEntity> root = criteriaQuery.from(LDNMessageEntity.class);
criteriaQuery.select(root);
List<Predicate> andPredicates = new ArrayList<>(3);

View File

@@ -90,7 +90,8 @@ public class LDNMessageServiceImpl implements LDNMessageService {
message = mapper.writeValueAsString(notification);
ldnMessage.setMessage(message);
} catch (JsonProcessingException e) {
log.error("Notification json can't be correctly processed and stored inside the LDN Message Entity");
log.error("Notification json can't be correctly processed " +
"and stored inside the LDN Message Entity" + ldnMessage);
log.error(e);
}
ldnMessage.setType(StringUtils.joinWith(",", notification.getType()));
@@ -105,6 +106,11 @@ public class LDNMessageServiceImpl implements LDNMessageService {
ldnMessage.setActivityStreamType(notificationTypeArrayList.get(0));
ldnMessage.setCoarNotifyType(notificationTypeArrayList.get(1));
ldnMessage.setQueueStatus(LDNMessageEntity.QUEUE_STATUS_QUEUED);
//CST-12126 if source is untrusted, set the queue_status of the
//ldnMsgEntity to UNTRUSTED
if (ldnMessage.getOrigin() == null) {
ldnMessage.setQueueStatus(LDNMessageEntity.QUEUE_STATUS_UNTRUSTED);
}
ldnMessage.setQueueTimeout(new Date());
update(context, ldnMessage);
@@ -113,6 +119,12 @@ public class LDNMessageServiceImpl implements LDNMessageService {
@Override
public void update(Context context, LDNMessageEntity ldnMessage) throws SQLException {
//CST-12126 then LDNMessageService.update() when the origin is set != null,
//move the queue_status from UNTRUSTED to QUEUED
if (ldnMessage.getOrigin() != null &&
LDNMessageEntity.QUEUE_STATUS_UNTRUSTED.compareTo(ldnMessage.getQueueStatus()) == 0) {
ldnMessage.setQueueStatus(LDNMessageEntity.QUEUE_STATUS_QUEUED);
}
ldnMessageDao.save(context, ldnMessage);
}

View File

@@ -58,25 +58,14 @@ public interface QAEventService {
public long countTopicsBySource(String source);
/**
* Find all the events by topic.
* Find all the events by topic sorted by trust descending.
*
* @param topic the topic to search for
* @param offset the offset to apply
* @param pageSize the page size
* @param orderField the field to order for
* @param ascending true if the order should be ascending, false otherwise
* @return the events
*/
public List<QAEvent> findEventsByTopicAndPage(String topic, long offset, int pageSize,
String orderField, boolean ascending);
/**
* Find all the events by topic.
*
* @param topic the topic to search for
* @return the events
*/
public List<QAEvent> findEventsByTopic(String topic);
public List<QAEvent> findEventsByTopicAndPage(String topic, long offset, int pageSize);
/**
* Find all the events by topic.
@@ -156,4 +145,44 @@ public interface QAEventService {
*/
public boolean isRelatedItemSupported(QAEvent qaevent);
/**
* Find a list of QA events according to the pagination parameters for the specified topic and target sorted by
* trust descending
*
* @param topic the topic to search for
* @param offset the offset to apply
* @param pageSize the page size
* @param target the uuid of the QA event's target
* @return the events
*/
public List<QAEvent> findEventsByTopicAndPageAndTarget(String topic, long offset, int pageSize, UUID target);
/**
* Count the QA events related to the specified topic and target
* @param topic the topic to search for
* @param target the uuid of the QA event's target
* @return the count result
*/
public long countEventsByTopicAndTarget(String topic, UUID target);
/**
* Find all the event's topics related to the given source for a specific item
*
* @param source the source to search for
* @param target the item referring to
* @param offset the offset to apply
* @param pageSize the page size
* @return the topics list
*/
public List<QATopic> findAllTopicsBySourceAndTarget(String source, UUID target, long offset, int pageSize);
/**
* Count all the event's topics related to the given source referring to a specific item
*
* @param target the item uuid
* @param source the source to search for
* @return the count result
*/
public long countTopicsBySourceAndTarget(String source, UUID target);
}

View File

@@ -140,6 +140,27 @@ public class QAEventServiceImpl implements QAEventService {
return response.getFacetField(TOPIC).getValueCount();
}
@Override
public long countTopicsBySourceAndTarget(String source, UUID target) {
SolrQuery solrQuery = new SolrQuery();
solrQuery.setRows(0);
solrQuery.setQuery("*:*");
solrQuery.setFacet(true);
solrQuery.setFacetMinCount(1);
solrQuery.addFacetField(TOPIC);
solrQuery.addFilterQuery("source:" + source);
if (target != null) {
solrQuery.addFilterQuery(RESOURCE_UUID + ":" + target.toString());
}
QueryResponse response;
try {
response = getSolr().query(solrQuery);
} catch (SolrServerException | IOException e) {
throw new RuntimeException(e);
}
return response.getFacetField(TOPIC).getValueCount();
}
@Override
public void deleteEventByEventId(String id) {
try {
@@ -234,6 +255,49 @@ public class QAEventServiceImpl implements QAEventService {
return topics;
}
@Override
public List<QATopic> findAllTopicsBySourceAndTarget(String source, UUID target, long offset, int count) {
if (source != null && isNotSupportedSource(source)) {
return null;
}
SolrQuery solrQuery = new SolrQuery();
solrQuery.setRows(0);
solrQuery.setQuery("*:*");
solrQuery.setFacet(true);
solrQuery.setFacetMinCount(1);
solrQuery.setFacetLimit((int) (offset + count));
solrQuery.addFacetField(TOPIC);
if (source != null) {
solrQuery.addFilterQuery(SOURCE + ":" + source);
}
if (target != null) {
solrQuery.addFilterQuery(RESOURCE_UUID + ":" + target.toString());
}
QueryResponse response;
List<QATopic> topics = new ArrayList<>();
try {
response = getSolr().query(solrQuery);
FacetField facetField = response.getFacetField(TOPIC);
topics = new ArrayList<>();
int idx = 0;
for (Count c : facetField.getValues()) {
if (idx < offset) {
idx++;
continue;
}
QATopic topic = new QATopic();
topic.setKey(c.getName());
topic.setTotalEvents(c.getCount());
topic.setLastEvent(new Date());
topics.add(topic);
idx++;
}
} catch (SolrServerException | IOException e) {
throw new RuntimeException(e);
}
return topics;
}
@Override
public void store(Context context, QAEvent dto) {
@@ -283,15 +347,14 @@ public class QAEventServiceImpl implements QAEventService {
}
@Override
public List<QAEvent> findEventsByTopicAndPage(String topic, long offset,
int pageSize, String orderField, boolean ascending) {
public List<QAEvent> findEventsByTopicAndPage(String topic, long offset, int pageSize) {
SolrQuery solrQuery = new SolrQuery();
solrQuery.setStart(((Long) offset).intValue());
if (pageSize != -1) {
solrQuery.setRows(pageSize);
}
solrQuery.setSort(orderField, ascending ? ORDER.asc : ORDER.desc);
solrQuery.setSort(TRUST, ORDER.desc);
solrQuery.setQuery(TOPIC + ":" + topic.replaceAll("!", "/"));
QueryResponse response;
@@ -314,8 +377,33 @@ public class QAEventServiceImpl implements QAEventService {
}
@Override
public List<QAEvent> findEventsByTopic(String topic) {
return findEventsByTopicAndPage(topic, 0, -1, TRUST, false);
public List<QAEvent> findEventsByTopicAndPageAndTarget(String topic, long offset, int pageSize, UUID target) {
SolrQuery solrQuery = new SolrQuery();
solrQuery.setStart(((Long) offset).intValue());
solrQuery.setRows(pageSize);
solrQuery.setSort(TRUST, ORDER.desc);
solrQuery.setQuery("*:*");
solrQuery.addFilterQuery(TOPIC + ":" + topic.replaceAll("!", "/"));
solrQuery.addFilterQuery(RESOURCE_UUID + ":" + target.toString());
QueryResponse response;
try {
response = getSolr().query(solrQuery);
if (response != null) {
SolrDocumentList list = response.getResults();
List<QAEvent> responseItem = new ArrayList<>();
for (SolrDocument doc : list) {
QAEvent item = getQAEventFromSOLR(doc);
responseItem.add(item);
}
return responseItem;
}
} catch (SolrServerException | IOException e) {
throw new RuntimeException(e);
}
return List.of();
}
@Override
@@ -332,6 +420,22 @@ public class QAEventServiceImpl implements QAEventService {
}
}
@Override
public long countEventsByTopicAndTarget(String topic, UUID target) {
SolrQuery solrQuery = new SolrQuery();
solrQuery.setRows(0);
solrQuery.setQuery("*:*");
solrQuery.addFilterQuery(TOPIC + ":" + topic.replace("!", "/"));
solrQuery.addFilterQuery(RESOURCE_UUID + ":" + target.toString());
QueryResponse response = null;
try {
response = getSolr().query(solrQuery);
return response.getResults().getNumFound();
} catch (SolrServerException | IOException e) {
throw new RuntimeException(e);
}
}
@Override
public QASource findSource(String sourceName) {
@@ -457,7 +561,8 @@ public class QAEventServiceImpl implements QAEventService {
}
private String[] getSupportedSources() {
return configurationService.getArrayProperty("qaevent.sources", new String[] { QAEvent.OPENAIRE_SOURCE, QAEvent.COAR_NOTIFY });
return configurationService.getArrayProperty("qaevent.sources", new String[]
{ QAEvent.OPENAIRE_SOURCE, QAEvent.COAR_NOTIFY });
}
}

View File

@@ -9,13 +9,12 @@ package org.dspace.qaevent.script;
import static java.util.List.of;
import static org.dspace.content.QAEvent.OPENAIRE_SOURCE;
import static org.dspace.content.QAEvent.COAR_NOTIFY;
import static org.dspace.matcher.QAEventMatcher.pendingOpenaireEventWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
@@ -33,7 +32,9 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.List;
import eu.dnetlib.broker.BrokerClient;
import org.apache.commons.io.IOUtils;
import org.dspace.AbstractIntegrationTestWithDatabase;
import org.dspace.app.launcher.ScriptLauncher;
@@ -43,8 +44,10 @@ import org.dspace.builder.CommunityBuilder;
import org.dspace.builder.ItemBuilder;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.content.QAEvent;
import org.dspace.matcher.QASourceMatcher;
import org.dspace.matcher.QATopicMatcher;
import org.dspace.qaevent.QATopic;
import org.dspace.qaevent.service.BrokerClientFactory;
import org.dspace.qaevent.service.QAEventService;
import org.dspace.qaevent.service.impl.BrokerClientFactoryImpl;
@@ -53,7 +56,6 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import eu.dnetlib.broker.BrokerClient;
/**
* Integration tests for {@link OpenaireEventsImport}.
@@ -157,14 +159,16 @@ public class OpenaireEventsImportIT extends AbstractIntegrationTestWithDatabase
"Trying to read the QA events from the provided file",
"Found 5 events in the given file"));
assertThat(qaEventService.findAllSources(0, 20), containsInAnyOrder(QASourceMatcher.with(OPENAIRE_SOURCE, 5L), QASourceMatcher.with(COAR_NOTIFY, 0L)));
assertThat(qaEventService.findAllSources(0, 20),
hasItem(QASourceMatcher.with(OPENAIRE_SOURCE, 5L))
);
assertThat(qaEventService.findAllTopics(0, 20), containsInAnyOrder(
QATopicMatcher.with("ENRICH/MORE/PROJECT", 1L),
QATopicMatcher.with("ENRICH/MORE/PID", 1L),
QATopicMatcher.with("ENRICH/MISSING/PID", 1L),
QATopicMatcher.with("ENRICH/MISSING/PROJECT", 1L),
QATopicMatcher.with("ENRICH/MISSING/ABSTRACT", 1L)));
List<QATopic> topicList = qaEventService.findAllTopics(0, 20);
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MORE/PROJECT", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MORE/PID", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MISSING/PID", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MISSING/PROJECT", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MISSING/ABSTRACT", 1L)));
String projectMessage = "{\"projects[0].acronym\":\"PAThs\",\"projects[0].code\":\"687567\","
+ "\"projects[0].funder\":\"EC\",\"projects[0].fundingProgram\":\"H2020\","
@@ -172,14 +176,14 @@ public class OpenaireEventsImportIT extends AbstractIntegrationTestWithDatabase
+ "\"projects[0].openaireId\":\"40|corda__h2020::6e32f5eb912688f2424c68b851483ea4\","
+ "\"projects[0].title\":\"Tracking Papyrus and Parchment Paths\"}";
assertThat(qaEventService.findEventsByTopic("ENRICH/MORE/PROJECT"), contains(
assertThat(qaEventService.findEventsByTopicAndPage("ENRICH/MORE/PROJECT", 0, 20), contains(
pendingOpenaireEventWith("oai:www.openstarts.units.it:123456789/99998", firstItem,
"Egypt, crossroad of translations and literary interweavings", projectMessage,
"ENRICH/MORE/PROJECT", 1.00d)));
String abstractMessage = "{\"abstracts[0]\":\"Missing Abstract\"}";
assertThat(qaEventService.findEventsByTopic("ENRICH/MISSING/ABSTRACT"), contains(
assertThat(qaEventService.findEventsByTopicAndPage("ENRICH/MISSING/ABSTRACT", 0, 20), contains(
pendingOpenaireEventWith("oai:www.openstarts.units.it:123456789/99999", secondItem, "Test Publication",
abstractMessage, "ENRICH/MISSING/ABSTRACT", 1.00d)));
@@ -213,17 +217,16 @@ public class OpenaireEventsImportIT extends AbstractIntegrationTestWithDatabase
"Trying to read the QA events from the provided file",
"Found 5 events in the given file"));
assertThat(qaEventService.findAllSources(0, 20), containsInAnyOrder(QASourceMatcher.with(OPENAIRE_SOURCE, 3L), QASourceMatcher.with(COAR_NOTIFY, 0L)));
assertThat(qaEventService.findAllSources(0, 20), hasItem(QASourceMatcher.with(OPENAIRE_SOURCE, 3L)));
assertThat(qaEventService.findAllTopics(0, 20), containsInAnyOrder(
QATopicMatcher.with("ENRICH/MISSING/ABSTRACT", 1L),
QATopicMatcher.with("ENRICH/MISSING/PROJECT", 1L),
QATopicMatcher.with("ENRICH/MORE/PID", 1L)
));
List<QATopic> topicList = qaEventService.findAllTopics(0, 20);
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MISSING/ABSTRACT", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MISSING/PROJECT", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MORE/PID", 1L)));
String abstractMessage = "{\"abstracts[0]\":\"Missing Abstract\"}";
assertThat(qaEventService.findEventsByTopic("ENRICH/MISSING/ABSTRACT"), contains(
assertThat(qaEventService.findEventsByTopicAndPage("ENRICH/MISSING/ABSTRACT", 0, 20), contains(
pendingOpenaireEventWith("oai:www.openstarts.units.it:123456789/99999", item, "Test Publication",
abstractMessage, "ENRICH/MISSING/ABSTRACT", 1.00d)));
@@ -253,13 +256,13 @@ public class OpenaireEventsImportIT extends AbstractIntegrationTestWithDatabase
"Trying to read the QA events from the provided file",
"Found 2 events in the given file"));
assertThat(qaEventService.findAllSources(0, 20), containsInAnyOrder(QASourceMatcher.with(OPENAIRE_SOURCE, 1L), QASourceMatcher.with(COAR_NOTIFY, 0L)));
assertThat(qaEventService.findAllSources(0, 20), hasItem(QASourceMatcher.with(OPENAIRE_SOURCE, 1L)));
assertThat(qaEventService.findAllTopics(0, 20), contains(QATopicMatcher.with("ENRICH/MISSING/ABSTRACT", 1L)));
String abstractMessage = "{\"abstracts[0]\":\"Missing Abstract\"}";
assertThat(qaEventService.findEventsByTopic("ENRICH/MISSING/ABSTRACT"), contains(
assertThat(qaEventService.findEventsByTopicAndPage("ENRICH/MISSING/ABSTRACT", 0, 20), contains(
pendingOpenaireEventWith("oai:www.openstarts.units.it:123456789/999991", secondItem, "Test Publication 2",
abstractMessage, "ENRICH/MISSING/ABSTRACT", 1.00d)));
@@ -280,7 +283,7 @@ public class OpenaireEventsImportIT extends AbstractIntegrationTestWithDatabase
assertThat(handler.getWarningMessages(),empty());
assertThat(handler.getInfoMessages(), contains("Trying to read the QA events from the provided file"));
assertThat(qaEventService.findAllSources(0, 20), containsInAnyOrder(QASourceMatcher.with(OPENAIRE_SOURCE, 0L), QASourceMatcher.with(COAR_NOTIFY, 0L)));
assertThat(qaEventService.findAllSources(0, 20), hasItem(QASourceMatcher.with(OPENAIRE_SOURCE, 0L)));
assertThat(qaEventService.findAllTopics(0, 20), empty());
@@ -327,14 +330,14 @@ public class OpenaireEventsImportIT extends AbstractIntegrationTestWithDatabase
"Found 0 events from the subscription sub2",
"Found 2 events from the subscription sub3"));
assertThat(qaEventService.findAllSources(0, 20), containsInAnyOrder(QASourceMatcher.with(OPENAIRE_SOURCE, 6L), QASourceMatcher.with(COAR_NOTIFY, 0L)));
assertThat(qaEventService.findAllSources(0, 20), hasItem(QASourceMatcher.with(OPENAIRE_SOURCE, 6L)));
assertThat(qaEventService.findAllTopics(0, 20), containsInAnyOrder(
QATopicMatcher.with("ENRICH/MORE/PROJECT", 1L),
QATopicMatcher.with("ENRICH/MORE/PID", 1L),
QATopicMatcher.with("ENRICH/MISSING/PID", 1L),
QATopicMatcher.with("ENRICH/MISSING/PROJECT", 1L),
QATopicMatcher.with("ENRICH/MISSING/ABSTRACT", 2L)));
List<QATopic> topicList = qaEventService.findAllTopics(0, 20);
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MORE/PROJECT", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MORE/PID", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MISSING/PID", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MISSING/PROJECT", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MISSING/ABSTRACT", 2L)));
String projectMessage = "{\"projects[0].acronym\":\"PAThs\",\"projects[0].code\":\"687567\","
+ "\"projects[0].funder\":\"EC\",\"projects[0].fundingProgram\":\"H2020\","
@@ -342,16 +345,18 @@ public class OpenaireEventsImportIT extends AbstractIntegrationTestWithDatabase
+ "\"projects[0].openaireId\":\"40|corda__h2020::6e32f5eb912688f2424c68b851483ea4\","
+ "\"projects[0].title\":\"Tracking Papyrus and Parchment Paths\"}";
assertThat(qaEventService.findEventsByTopic("ENRICH/MORE/PROJECT"), contains(
assertThat(qaEventService.findEventsByTopicAndPage("ENRICH/MORE/PROJECT", 0, 20), contains(
pendingOpenaireEventWith("oai:www.openstarts.units.it:123456789/99998", firstItem,
"Egypt, crossroad of translations and literary interweavings", projectMessage,
"ENRICH/MORE/PROJECT", 1.00d)));
String abstractMessage = "{\"abstracts[0]\":\"Missing Abstract\"}";
assertThat(qaEventService.findEventsByTopic("ENRICH/MISSING/ABSTRACT"), containsInAnyOrder(
List<QAEvent> eventList = qaEventService.findEventsByTopicAndPage("ENRICH/MISSING/ABSTRACT", 0, 20);
assertThat(eventList, hasItem(
pendingOpenaireEventWith("oai:www.openstarts.units.it:123456789/99999", secondItem, "Test Publication",
abstractMessage, "ENRICH/MISSING/ABSTRACT", 1.00d),
abstractMessage, "ENRICH/MISSING/ABSTRACT", 1.00d)));
assertThat(eventList, hasItem(
pendingOpenaireEventWith("oai:www.openstarts.units.it:123456789/999991", thirdItem, "Test Publication 2",
abstractMessage, "ENRICH/MISSING/ABSTRACT", 1.00d)));
@@ -381,7 +386,7 @@ public class OpenaireEventsImportIT extends AbstractIntegrationTestWithDatabase
assertThat(handler.getWarningMessages(), empty());
assertThat(handler.getInfoMessages(), contains("Trying to read the QA events from the OPENAIRE broker"));
assertThat(qaEventService.findAllSources(0, 20), containsInAnyOrder(QASourceMatcher.with(OPENAIRE_SOURCE, 0L), QASourceMatcher.with(COAR_NOTIFY, 0L)));
assertThat(qaEventService.findAllSources(0, 20), hasItem(QASourceMatcher.with(OPENAIRE_SOURCE, 0L)));
assertThat(qaEventService.findAllTopics(0, 20), empty());
@@ -432,17 +437,17 @@ public class OpenaireEventsImportIT extends AbstractIntegrationTestWithDatabase
"Found 0 events from the subscription sub2",
"Found 2 events from the subscription sub3"));
assertThat(qaEventService.findAllSources(0, 20), containsInAnyOrder(QASourceMatcher.with(OPENAIRE_SOURCE, 6L), QASourceMatcher.with(COAR_NOTIFY, 0L)));
assertThat(qaEventService.findAllSources(0, 20), hasItem(QASourceMatcher.with(OPENAIRE_SOURCE, 6L)));
assertThat(qaEventService.findAllTopics(0, 20), containsInAnyOrder(
QATopicMatcher.with("ENRICH/MORE/PROJECT", 1L),
QATopicMatcher.with("ENRICH/MISSING/PID", 1L),
QATopicMatcher.with("ENRICH/MORE/PID", 1L),
QATopicMatcher.with("ENRICH/MISSING/PROJECT", 1L),
QATopicMatcher.with("ENRICH/MISSING/ABSTRACT", 2L)));
List<QATopic> topicList = qaEventService.findAllTopics(0, 20);
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MORE/PROJECT", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MISSING/PID", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MORE/PID", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MISSING/PROJECT", 1L)));
assertThat(topicList, hasItem(QATopicMatcher.with("ENRICH/MISSING/ABSTRACT", 2L)));
assertThat(qaEventService.findEventsByTopic("ENRICH/MORE/PROJECT"), hasSize(1));
assertThat(qaEventService.findEventsByTopic("ENRICH/MISSING/ABSTRACT"), hasSize(2));
assertThat(qaEventService.findEventsByTopicAndPage("ENRICH/MORE/PROJECT", 0, 20), hasSize(1));
assertThat(qaEventService.findEventsByTopicAndPage("ENRICH/MISSING/ABSTRACT", 0, 20), hasSize(2));
verify(mockBrokerClient).listSubscriptions(openaireURL, "user@test.com");
verify(mockBrokerClient).downloadEvents(eq(openaireURL), eq("sub1"), any());
@@ -459,7 +464,7 @@ public class OpenaireEventsImportIT extends AbstractIntegrationTestWithDatabase
context.turnOffAuthorisationSystem();
Item firstItem = createItem("Test item", "123456789/99998");
Item secondItem = createItem("Test item 2", "123456789/99999");
context.restoreAuthSystemState();
TestDSpaceRunnableHandler handler = new TestDSpaceRunnableHandler();
@@ -470,7 +475,7 @@ public class OpenaireEventsImportIT extends AbstractIntegrationTestWithDatabase
assertThat(qaEventService.findAllTopics(0, 20), contains(
QATopicMatcher.with("ENRICH/MORE/REVIEW", 1L)));
assertThat(qaEventService.findAllSources(0, 20), containsInAnyOrder(QASourceMatcher.with(OPENAIRE_SOURCE, 1L), QASourceMatcher.with(COAR_NOTIFY, 0L)));
assertThat(qaEventService.findAllSources(0, 20), hasItem(QASourceMatcher.with(OPENAIRE_SOURCE, 1L)));
verifyNoInteractions(mockBrokerClient);
}

View File

@@ -55,20 +55,23 @@ public class LDNInboxController {
public ResponseEntity<Object> inbox(@RequestBody Notification notification) throws Exception {
Context context = ContextUtil.obtainCurrentRequestContext();
validate(notification);
log.info("stored notification {} {}", notification.getId(), notification.getType());
context.commit();
LDNMessageEntity ldnMsgEntity = ldnMessageService.create(context, notification);
LDNProcessor processor = router.route(ldnMsgEntity);
if (processor == null) {
log.error(String.format("No processor found for type %s", notification.getType()));
/*
* return ResponseEntity.badRequest()
.body(String.format("No processor found for type %s", notification.getType()));
*/
log.info("stored ldn message {}", ldnMsgEntity);
context.commit();
if (ldnMsgEntity.getQueueStatus() != LDNMessageEntity.QUEUE_STATUS_UNTRUSTED) {
LDNProcessor processor = router.route(ldnMsgEntity);
if (processor == null) {
log.error(String.format("No processor found for type %s", notification.getType()));
return ResponseEntity.badRequest()
.body(String.format("No processor found for type %s", notification.getType()));
} else {
processor.process(notification);
}
} else {
processor.process(notification);
log.warn("LDNMessage " + ldnMsgEntity + " has been received by an untrusted source");
}
return ResponseEntity.accepted()
.body(String.format("Successfully stored notification %s %s",

View File

@@ -28,6 +28,7 @@ public class CoarNotifyLdnEnabled implements AuthorizationFeature {
@Autowired
private ConfigurationService configurationService;
@Override
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException, SearchServiceException {
return configurationService.getBooleanProperty("coar-notify.enabled", true);
@@ -35,6 +36,7 @@ public class CoarNotifyLdnEnabled implements AuthorizationFeature {
@Override
public String[] getSupportedTypes() {
return new String[]{SiteRest.CATEGORY + "." + SiteRest.NAME};
return new String[]{ SiteRest.CATEGORY + "." + SiteRest.NAME };
}
}

View File

@@ -9,6 +9,7 @@ package org.dspace.app.rest.repository;
import java.sql.SQLException;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.Parameter;
@@ -29,7 +30,6 @@ import org.dspace.util.UUIDUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
@@ -75,16 +75,19 @@ public class QAEventRestRepository extends DSpaceRestRepository<QAEventRest, Str
@SearchRestMethod(name = "findByTopic")
@PreAuthorize("hasAuthority('ADMIN')")
public Page<QAEventRest> findByTopic(Context context, @Parameter(value = "topic", required = true) String topic,
@Parameter(value = "target", required = false) UUID target,
Pageable pageable) {
List<QAEvent> qaEvents = null;
long count = 0L;
boolean ascending = false;
if (pageable.getSort() != null && pageable.getSort().getOrderFor(ORDER_FIELD) != null) {
ascending = pageable.getSort().getOrderFor(ORDER_FIELD).getDirection() == Direction.ASC;
if (target == null) {
qaEvents = qaEventService.findEventsByTopicAndPage(topic,
pageable.getOffset(), pageable.getPageSize());
count = qaEventService.countEventsByTopic(topic);
} else {
qaEvents = qaEventService.findEventsByTopicAndPageAndTarget(topic,
pageable.getOffset(), pageable.getPageSize(), target);
count = qaEventService.countEventsByTopicAndTarget(topic, target);
}
qaEvents = qaEventService.findEventsByTopicAndPage(topic,
pageable.getOffset(), pageable.getPageSize(), ORDER_FIELD, ascending);
count = qaEventService.countEventsByTopic(topic);
if (qaEvents == null) {
return null;
}

View File

@@ -8,7 +8,10 @@
package org.dspace.app.rest.repository;
import java.util.List;
import java.util.UUID;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.model.QATopicRest;
@@ -33,6 +36,8 @@ public class QATopicRestRepository extends DSpaceRestRepository<QATopicRest, Str
@Autowired
private QAEventService qaEventService;
private static final Logger log = LogManager.getLogger();
@Override
@PreAuthorize("hasAuthority('ADMIN')")
public QATopicRest findOne(Context context, String id) {
@@ -67,6 +72,21 @@ public class QATopicRestRepository extends DSpaceRestRepository<QATopicRest, Str
return converter.toRestPage(topics, pageable, count, utils.obtainProjection());
}
@SearchRestMethod(name = "byTarget")
@PreAuthorize("hasAuthority('ADMIN')")
public Page<QATopicRest> findByTarget(Context context,
@Parameter(value = "target", required = true) UUID target,
@Parameter(value = "source", required = false) String source,
Pageable pageable) {
List<QATopic> topics = qaEventService
.findAllTopicsBySourceAndTarget(source, target, pageable.getOffset(), pageable.getPageSize());
long count = qaEventService.countTopicsBySourceAndTarget(source, target);
if (topics == null) {
return null;
}
return converter.toRestPage(topics, pageable, count, utils.obtainProjection());
}
@Override
public Class<QATopicRest> getDomainClass() {
return QATopicRest.class;

View File

@@ -56,7 +56,8 @@ public class NotifyServiceInboundPatternsAddOperation extends PatchOperation<Not
NotifyServiceInboundPattern persistInboundPattern = inboundPatternService.findByServiceAndPattern(
context, notifyServiceEntity, patchInboundPattern.getPattern());
if (persistInboundPattern != null) {
if (persistInboundPattern != null && persistInboundPattern.getConstraint().equals(patchInboundPattern
.getConstraint())) {
throw new DSpaceBadRequestException("the provided InboundPattern is already existed");
}

View File

@@ -49,7 +49,8 @@ public final class NotifyServicePatchUtils {
try {
if (operation.getValue() != null) {
if (operation.getValue() instanceof JsonValueEvaluator) {
inboundPattern = objectMapper.readValue(((JsonValueEvaluator) operation.getValue()).getValueNode().toString(),
inboundPattern = objectMapper.readValue(
((JsonValueEvaluator) operation.getValue()).getValueNode().toString(),
NotifyServiceInboundPattern.class);
}
}
@@ -75,7 +76,8 @@ public final class NotifyServicePatchUtils {
try {
if (operation.getValue() != null) {
if (operation.getValue() instanceof JsonValueEvaluator) {
outboundPattern = objectMapper.readValue(((JsonValueEvaluator) operation.getValue()).getValueNode().toString(),
outboundPattern = objectMapper.readValue(
((JsonValueEvaluator) operation.getValue()).getValueNode().toString(),
NotifyServiceOutboundPattern.class);
}
}

View File

@@ -26,6 +26,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;
@@ -153,6 +154,49 @@ public class QAEventRestRepositoryIT extends AbstractControllerIntegrationTest {
.andExpect(status().isForbidden());
}
@Test
public void findByTopicAndTargetTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context).withName("Parent Community").build();
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build();
String uuid = UUID.randomUUID().toString();
Item item = ItemBuilder.createItem(context, col1).withTitle("Tracking Papyrus and Parchment Paths")
.build();
QAEventBuilder qBuilder = QAEventBuilder.createTarget(context, item)
.withTopic("ENRICH/MISSING/PID")
.withMessage("{\"pids[0].type\":\"doi\",\"pids[0].value\":\"10.2307/2144300\"}");
QAEvent event1 = qBuilder.build();
context.restoreAuthSystemState();
String authToken = getAuthToken(admin.getEmail(), password);
getClient(authToken)
.perform(
get("/api/integration/qualityassuranceevents/search/findByTopic")
.param("topic", "ENRICH!MISSING!PID")
.param("target", uuid))
.andExpect(status().isOk()).andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(0)));
uuid = item.getID().toString();
// check for an existing item but a different topic
getClient(authToken)
.perform(
get("/api/integration/qualityassuranceevents/search/findByTopic")
.param("topic", "not-existing")
.param("target", uuid))
.andExpect(status().isOk()).andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(0)));
// check for an existing item and topic
getClient(authToken)
.perform(
get("/api/integration/qualityassuranceevents/search/findByTopic")
.param("topic", "ENRICH!MISSING!PID")
.param("target", uuid))
.andExpect(status().isOk()).andExpect(jsonPath("$._embedded.qualityassuranceevents", Matchers.hasSize(1)))
.andExpect(jsonPath("$._embedded.qualityassuranceevents",
Matchers.contains(QAEventMatcher.matchQAEventEntry(event1))))
.andExpect(jsonPath("$.page.size", is(20))).andExpect(jsonPath("$.page.totalElements", is(1)));
}
@Test
public void findByTopicTest() throws Exception {
context.turnOffAuthorisationSystem();

View File

@@ -13,13 +13,17 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
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.matcher.QATopicMatcher;
import org.dspace.app.rest.repository.QATopicRestRepository;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.builder.CollectionBuilder;
import org.dspace.builder.CommunityBuilder;
import org.dspace.builder.ItemBuilder;
import org.dspace.builder.QAEventBuilder;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.services.ConfigurationService;
import org.hamcrest.Matchers;
import org.junit.Test;
@@ -274,4 +278,127 @@ public class QATopicRestRepositoryIT extends AbstractControllerIntegrationTest {
.andExpect(status().isForbidden());
}
@Test
public void findByTargetTest() throws Exception {
context.turnOffAuthorisationSystem();
configurationService.setProperty("qaevent.sources",
new String[] { "openaire", "test-source", "test-source-2" });
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build();
Item item1 = ItemBuilder.createItem(context, col1).withTitle("Science and Freedom").build();
Item item2 = ItemBuilder.createItem(context, col1).withTitle("Science and Freedom 2").build();
QAEventBuilder.createTarget(context, item1)
.withSource("openaire")
.withTopic("ENRICH/MISSING/PID")
.withMessage("{\"pids[0].type\":\"doi\",\"pids[0].value\":\"10.2307/2144300\"}").build();
QAEventBuilder.createTarget(context, item1)
.withSource("openaire")
.withTopic("ENRICH/MISSING/ABSTRACT")
.withMessage(
"{\"abstracts[0]\": \"Descrizione delle caratteristiche...\"}")
.build();
QAEventBuilder.createTarget(context, item1)
.withTopic("TEST/TOPIC")
.withSource("test-source")
.build();
QAEventBuilder.createTarget(context, item1)
.withTopic("TEST/TOPIC/2")
.withSource("test-source")
.build();
QAEventBuilder.createTarget(context, item2)
.withTopic("ENRICH/MISSING/PID")
.withMessage("{\"pids[0].type\":\"doi\",\"pids[0].value\":\"10.2307/2144301\"}").build();
QAEventBuilder.createTarget(context, item2)
.withTopic("ENRICH/MISSING/PID")
.withMessage("{\"pids[0].type\":\"pmid\",\"pids[0].value\":\"2144301\"}").build();
context.restoreAuthSystemState();
String authToken = getAuthToken(admin.getEmail(), password);
getClient(authToken).perform(get("/api/integration/qualityassurancetopics/search/byTarget")
.param("target", item1.getID().toString()))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.qualityassurancetopics",
Matchers.containsInAnyOrder(QATopicMatcher.matchQATopicEntry("ENRICH/MISSING/PID", 1),
QATopicMatcher.matchQATopicEntry("ENRICH/MISSING/ABSTRACT", 1),
QATopicMatcher.matchQATopicEntry("TEST/TOPIC", 1),
QATopicMatcher.matchQATopicEntry("TEST/TOPIC/2", 1))))
.andExpect(jsonPath("$.page.size", is(20))).andExpect(jsonPath("$.page.totalElements", is(4)));
getClient(authToken).perform(get("/api/integration/qualityassurancetopics/search/byTarget")
.param("target", item1.getID().toString())
.param("source", "openaire"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.qualityassurancetopics",
Matchers.containsInAnyOrder(QATopicMatcher.matchQATopicEntry("ENRICH/MISSING/PID", 1),
QATopicMatcher.matchQATopicEntry("ENRICH/MISSING/ABSTRACT", 1))))
.andExpect(jsonPath("$.page.size", is(20))).andExpect(jsonPath("$.page.totalElements", is(2)));
getClient(authToken).perform(get("/api/integration/qualityassurancetopics/search/byTarget")
.param("target", item2.getID().toString()))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.qualityassurancetopics",
Matchers.containsInAnyOrder(QATopicMatcher.matchQATopicEntry("ENRICH/MISSING/PID", 2))))
.andExpect(jsonPath("$.page.size", is(20))).andExpect(jsonPath("$.page.totalElements", is(1)));
getClient(authToken).perform(get("/api/integration/qualityassurancetopics/search/byTarget")
.param("target", UUID.randomUUID().toString()))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.qualityassurancetopics").doesNotExist())
.andExpect(jsonPath("$.page.size", is(20))).andExpect(jsonPath("$.page.totalElements", is(0)));
}
@Test
public void findByTargetUnauthorizedTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build();
Item item1 = ItemBuilder.createItem(context, col1).withTitle("Science and Freedom").build();
QAEventBuilder.createTarget(context, item1)
.withTopic("ENRICH/MISSING/PID").build();
context.restoreAuthSystemState();
getClient().perform(get("/api/integration/qualityassurancetopics/search/byTarget")
.param("target", item1.getID().toString()))
.andExpect(status().isUnauthorized());
}
@Test
public void findByTargetForbiddenTest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build();
Item item1 = ItemBuilder.createItem(context, col1).withTitle("Science and Freedom").build();
QAEventBuilder.createTarget(context, item1)
.withTopic("ENRICH/MISSING/PID").build();
context.restoreAuthSystemState();
String authToken = getAuthToken(eperson.getEmail(), password);
getClient(authToken).perform(get("/api/integration/qualityassurancetopics/search/byTarget")
.param("target", item1.getID().toString()))
.andExpect(status().isForbidden());
}
@Test
public void findByTargetBadRequest() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build();
Item item1 = ItemBuilder.createItem(context, col1).withTitle("Science and Freedom").build();
QAEventBuilder.createTarget(context, item1)
.withSource("test-source")
.withTopic("ENRICH/MISSING/PID").build();
context.restoreAuthSystemState();
String authToken = getAuthToken(eperson.getEmail(), password);
getClient(authToken).perform(get("/api/integration/qualityassurancetopics/search/byTarget")
.param("source", "test-source"))
.andExpect(status().isBadRequest());
}
}