diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDatasetDisplay.java b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDatasetDisplay.java index 941d4a33d31..75e18ec49e1 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDatasetDisplay.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDatasetDisplay.java @@ -278,9 +278,14 @@ public String composeFilterQuery(String startDate, String endDate, boolean relat } //Creates query for usage raport generator - public String composeQueryWithInverseRelation(DSpaceObject dSpaceObject, List default_queries ) { + public String composeQueryWithInverseRelation(DSpaceObject dSpaceObject, List default_queries, int type) { StringBuilder query = new StringBuilder(); - query.append("{!join from=search.resourceid to=id fromIndex="); + if (type == Constants.BITSTREAM) { + query.append("{!join from=search.resourceid to=owningItem fromIndex="); + } else { + query.append("{!join from=search.resourceid to=id fromIndex="); + } + query.append(configurationService.getProperty("solr.multicorePrefix")); query.append("search} "); boolean isFirstDefaultQuery = true; diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/AbstractTopSolrStatsFieldGenerator.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/AbstractTopSolrStatsFieldGenerator.java index 9d04803c71e..6d8242ca9fb 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/AbstractTopSolrStatsFieldGenerator.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/AbstractTopSolrStatsFieldGenerator.java @@ -66,8 +66,8 @@ Dataset getTypeStatsDataset(Context context, DSpaceObject dso, String typeAxisSt } else { hasValidRelation = true; - query = statisticsDatasetDisplay - .composeQueryWithInverseRelation(dso, discoveryConfiguration.getDefaultFilterQueries()); + query = statisticsDatasetDisplay.composeQueryWithInverseRelation( + dso, discoveryConfiguration.getDefaultFilterQueries(), getDsoType(dso)); } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TopCategoriesGenerator.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TopCategoriesGenerator.java index 58532e46bf0..39d8a1730c0 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TopCategoriesGenerator.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TopCategoriesGenerator.java @@ -93,7 +93,8 @@ private int getCategoryCount(DSpaceObject dso, DiscoveryConfiguration discoveryC private String composeCategoryQuery(DSpaceObject dso, DiscoveryConfiguration configuration, String categoryQuery) { List defaultFilterQueries = configuration.getDefaultFilterQueries(); - String query = new StatisticsDatasetDisplay().composeQueryWithInverseRelation(dso, defaultFilterQueries); + String query = new StatisticsDatasetDisplay().composeQueryWithInverseRelation(dso, + defaultFilterQueries, dso.getType()); if (categoryQuery.equals(OTHER_CATEGORY)) { return query + " AND " + getAllCategoryQueriesReverted(); diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TopItemsGenerator.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TopItemsGenerator.java index d0805c68de3..1e67b0cac66 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TopItemsGenerator.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TopItemsGenerator.java @@ -81,9 +81,8 @@ public UsageReportRest createUsageReport(Context context, DSpaceObject root, Str } else { hasValidRelation = true; - query = statisticsDatasetDisplay - .composeQueryWithInverseRelation(root, - discoveryConfiguration.getDefaultFilterQueries()); + query = statisticsDatasetDisplay.composeQueryWithInverseRelation(root, + discoveryConfiguration.getDefaultFilterQueries(), getDsoType()); } } if (!hasValidRelation) { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TotalDownloadsAndVisitsGenerator.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TotalDownloadsAndVisitsGenerator.java index 2a1d95e0c29..620333ce61b 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TotalDownloadsAndVisitsGenerator.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TotalDownloadsAndVisitsGenerator.java @@ -59,9 +59,8 @@ public UsageReportRest createUsageReport(Context context, DSpaceObject dso, Stri } else { hasValidRelation = true; - query = statisticsDatasetDisplay. - composeQueryWithInverseRelation( - dso, discoveryConfiguration.getDefaultFilterQueries()); + query = statisticsDatasetDisplay.composeQueryWithInverseRelation(dso, + discoveryConfiguration.getDefaultFilterQueries(), dso.getType()); } } if (!hasValidRelation) { diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TotalVisitGenerator.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TotalVisitGenerator.java index 98ee393b5cd..e419ac660fd 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TotalVisitGenerator.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TotalVisitGenerator.java @@ -118,7 +118,7 @@ Dataset getDSOStatsDataset(Context context, DSpaceObject dso, int dsoType, Strin } else { hasValidRelation = true; query = statisticsDatasetDisplay.composeQueryWithInverseRelation( - dso, discoveryConfiguration.getDefaultFilterQueries()); + dso, discoveryConfiguration.getDefaultFilterQueries(), dso.getType()); type_of_dso = dso.getType(); } } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TotalVisitPerPeriodGenerator.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TotalVisitPerPeriodGenerator.java index 5f7f53898ab..465f1022372 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TotalVisitPerPeriodGenerator.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/statistics/TotalVisitPerPeriodGenerator.java @@ -97,7 +97,8 @@ public UsageReportRest createUsageReport(Context context, DSpaceObject dso, Stri statisticsDatasetDisplay .composeQueryWithInverseRelation( dso, - discoveryConfiguration.getDefaultFilterQueries() + discoveryConfiguration.getDefaultFilterQueries(), + getDsoType(dso) ) ); } diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/UsageReportUtils.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/UsageReportUtils.java index 90f7ec25254..47dbcef1749 100644 --- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/UsageReportUtils.java +++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/UsageReportUtils.java @@ -101,6 +101,12 @@ public class UsageReportUtils { public static final String TOP_DOWNLOAD_COUNTRIES_REPORT_ID = "TopDownloadsCountries"; public static final String TOP_DOWNLOAD_CITIES_REPORT_ID = "TopDownloadsCities"; public static final String TOTAL_DOWNLOAD_PER_MONTH_REPORT_ID = "TotalDownloadsPerMonth"; + public static final String TOP_ITEMS_CITIES_REPORT_ID = "TopItemsCities"; + public static final String TOP_ITEMS_CONTINENTS_REPORT_ID = "TopItemsContinents"; + public static final String TOP_ITEMS_COUNTRIES_REPORT_ID = "TopItemsCountries"; + public static final String TOP_ITEMS_CATEGORIES_REPORT_ID = "TopItemsCategories"; + public static final String TOTAL_ITEMS_VISITS_REPORT_ID = "TotalItemsVisits"; + public static final String TOTAL_ITEMS_VISITS_PER_MONTH_REPORT_ID = "TotalItemsVisitsPerMonth"; /** * Get list of usage reports that are applicable to the DSO (of given UUID) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java index 0f7996a765f..68dee1555f7 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java @@ -25,24 +25,27 @@ import static org.dspace.app.rest.utils.UsageReportUtils.TOP_DOWNLOAD_CITIES_REPORT_ID; import static org.dspace.app.rest.utils.UsageReportUtils.TOP_DOWNLOAD_CONTINENTS_REPORT_ID; import static org.dspace.app.rest.utils.UsageReportUtils.TOP_DOWNLOAD_COUNTRIES_REPORT_ID; +import static org.dspace.app.rest.utils.UsageReportUtils.TOP_ITEMS_CATEGORIES_REPORT_ID; +import static org.dspace.app.rest.utils.UsageReportUtils.TOP_ITEMS_CITIES_REPORT_ID; +import static org.dspace.app.rest.utils.UsageReportUtils.TOP_ITEMS_CONTINENTS_REPORT_ID; +import static org.dspace.app.rest.utils.UsageReportUtils.TOP_ITEMS_COUNTRIES_REPORT_ID; import static org.dspace.app.rest.utils.UsageReportUtils.TOP_ITEMS_REPORT_ID; import static org.dspace.app.rest.utils.UsageReportUtils.TOP_ITEMS_REPORT_RELATION_ORGUNIT_RP_RESEARCHOUTPUTS; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_DOWNLOADS_REPORT_ID; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_DOWNLOADS_REPORT_ID_RELATION_ORGUNIT_RP_RESEARCHOUTPUTS; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_DOWNLOAD_PER_MONTH_REPORT_ID; -//import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_DOWNLOADS_REPORT_ID_RELATION_PERSON_RESEARCHOUTPUTS; +import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_ITEMS_VISITS_PER_MONTH_REPORT_ID; +import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_ITEMS_VISITS_REPORT_ID; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_VISITS_PER_MONTH_REPORT_ID; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_VISITS_PER_MONTH_REPORT_ID_RELATION_ORGUNIT_RP_RESEARCHOUTPUTS; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_VISITS_PER_MONTH_REPORT_ID_RELATION_PERSON_PROJECTS; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_VISITS_PER_MONTH_REPORT_ID_RELATION_PERSON_RESEARCHOUTPUTS; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_VISITS_REPORT_ID; -//import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_VISITS_REPORT_ID_RELATION_ORGUNIT_PROJECTS; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_VISITS_REPORT_ID_RELATION_ORGUNIT_RP_RESEARCHOUTPUTS; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_VISITS_REPORT_ID_RELATION_PERSON_PROJECTS; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_VISITS_REPORT_ID_RELATION_PERSON_RESEARCHOUTPUTS; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_VISITS_TOTAL_DOWNLOADS; import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_VISITS_TOTAL_DOWNLOADS_RELATION_ORGUNIT_RP_RESEARCHOUTPUTS; -//import static org.dspace.app.rest.utils.UsageReportUtils.TOTAL_VISITS_TOTAL_DOWNLOADS_RELATION_PERSON_RESEARCHOUTPUTS; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.not; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -921,10 +924,10 @@ public void TotalDownloadsReport_Item_NotVisited() throws Exception { } @Test - public void TotalDownloadsReport_NotSupportedDSO_Collection() throws Exception { + public void TotalDownloadsReport_SupportedDSO_Collection() throws Exception { getClient(adminToken) .perform(get("/api/statistics/usagereports/" + collectionVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID)) - .andExpect(status().isNotFound()); + .andExpect(status().isOk()); } /** @@ -1575,7 +1578,8 @@ public void usageReportsSearch_Community_Visited() throws Exception { // And request the community usage reports getClient(adminToken) - .perform(get("/api/statistics/usagereports/search/object?uri=http://localhost:8080/server/api/core" + + .perform(get("/api/statistics/usagereports/search/object?category=community-mainReports" + + "&uri=http://localhost:8080/server/api/core" + "/communities/" + communityVisited.getID())) // ** THEN ** .andExpect(status().isOk()) @@ -1616,7 +1620,8 @@ public void usageReportsSearch_Collection_NotVisited() throws Exception { // Collection is not visited // And request the collection's usage reports getClient(adminToken) - .perform(get("/api/statistics/usagereports/search/object?uri=http://localhost:8080/server/api/core" + + .perform(get("/api/statistics/usagereports/search/object?category=collection-mainReports" + + "&uri=http://localhost:8080/server/api/core" + "/collections/" + collectionNotVisited.getID())) // ** THEN ** .andExpect(status().isOk()) @@ -2035,7 +2040,8 @@ public void usageReportsSearch_Community_VisitedAtTime() throws Exception { String endDate = dateFormat.format(cal.getTime()); // And request the community usage reports getClient(adminToken) - .perform(get("/api/statistics/usagereports/search/object?uri=http://localhost:8080/server/api/core" + + .perform(get("/api/statistics/usagereports/search/object?category=community-mainReports" + + "&uri=http://localhost:8080/server/api/core" + "/communities/" + communityVisited.getID() + "&startDate=2019-06-01&endDate=" + endDate)) // ** THEN ** .andExpect(status().isOk()) @@ -2435,6 +2441,515 @@ public void usageReportsSearch_OrgUnitWithPublicationVisited() throws Exception ))); } + @Test + public void usageReportsSearch_Collection_ItemReports() throws Exception { + context.turnOffAuthorisationSystem(); + + Item item = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("My item") + .withType("Controlled Vocabulary for Resource Type Genres::image") + .build(); + Item item2 = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("My item 2") + .withType("Controlled Vocabulary for Resource Type Genres::thesis") + .build(); + Item item3 = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("My item 3") + .withType("Controlled Vocabulary for Resource Type Genres::thesis::bachelor thesis") + .build(); + Item item4 = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("My item 4") + .withType("Controlled Vocabulary for Resource Type Genres::text::periodical::" + + "journal::contribution to journal::journal article") + .build(); + context.restoreAuthSystemState(); + + ObjectMapper mapper = new ObjectMapper(); + + ViewEventRest viewEventRest = new ViewEventRest(); + viewEventRest.setTargetType("item"); + viewEventRest.setTargetId(item.getID()); + + getClient().perform(post("/api/statistics/viewevents") + .content(mapper.writeValueAsBytes(viewEventRest)) + .contentType(contentType)) + .andExpect(status().isCreated()); + + ViewEventRest viewEventRest2 = new ViewEventRest(); + viewEventRest2.setTargetType("item"); + viewEventRest2.setTargetId(item2.getID()); + + getClient().perform(post("/api/statistics/viewevents") + .content(mapper.writeValueAsBytes(viewEventRest2)) + .contentType(contentType)) + .andExpect(status().isCreated()); + + getClient().perform(post("/api/statistics/viewevents") + .content(mapper.writeValueAsBytes(viewEventRest2)) + .contentType(contentType)) + .andExpect(status().isCreated()); + + ViewEventRest viewEventRest3 = new ViewEventRest(); + viewEventRest3.setTargetType("item"); + viewEventRest3.setTargetId(item3.getID()); + + getClient().perform(post("/api/statistics/viewevents") + .content(mapper.writeValueAsBytes(viewEventRest3)) + .contentType(contentType)) + .andExpect(status().isCreated()); + + ViewEventRest viewEventRest4 = new ViewEventRest(); + viewEventRest4.setTargetType("item"); + viewEventRest4.setTargetId(item4.getID()); + + getClient().perform(post("/api/statistics/viewevents") + .content(mapper.writeValueAsBytes(viewEventRest4)) + .contentType(contentType)) + .andExpect(status().isCreated()); + + UsageReportPointDsoTotalVisitsRest expectedPoint1 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint1.addValue("views", 1); + expectedPoint1.setType("item"); + expectedPoint1.setLabel("My item"); + expectedPoint1.setId(item.getID().toString()); + + UsageReportPointDsoTotalVisitsRest expectedPoint2 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint2.addValue("views", 2); + expectedPoint2.setType("item"); + expectedPoint2.setLabel("My item 2"); + expectedPoint2.setId(item2.getID().toString()); + + UsageReportPointDsoTotalVisitsRest expectedPoint3 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint3.addValue("views", 1); + expectedPoint3.setType("item"); + expectedPoint3.setLabel("My item 3"); + expectedPoint3.setId(item3.getID().toString()); + + UsageReportPointDsoTotalVisitsRest expectedPoint4 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint4.addValue("views", 1); + expectedPoint4.setType("item"); + expectedPoint4.setLabel("My item 4"); + expectedPoint4.setId(item4.getID().toString()); + + List points = List.of(expectedPoint1, expectedPoint2, expectedPoint3, expectedPoint4); + + UsageReportPointCityRest pointCity = new UsageReportPointCityRest(); + pointCity.addValue("views", 5); + pointCity.setId("New York"); + + UsageReportPointContinentRest pointContinent = new UsageReportPointContinentRest(); + pointContinent.addValue("views", 5); + pointContinent.setId("North America"); + + UsageReportPointCountryRest pointCountry = new UsageReportPointCountryRest(); + pointCountry.addValue("views", 5); + pointCountry.setIdAndLabel(Locale.US.getCountry(), Locale.US.getDisplayCountry(context.getCurrentLocale())); + + UsageReportPointCategoryRest articleCategory = new UsageReportPointCategoryRest(); + articleCategory.addValue("views", 1); + articleCategory.setId("article"); + + UsageReportPointCategoryRest thesisCategory = new UsageReportPointCategoryRest(); + thesisCategory.addValue("views", 3); + thesisCategory.setId("thesis"); + + UsageReportPointCategoryRest otherCategory = new UsageReportPointCategoryRest(); + otherCategory.addValue("views", 1); + otherCategory.setId("other"); + + UsageReportPointCategoryRest bookCategory = new UsageReportPointCategoryRest(); + bookCategory.addValue("views", 0); + bookCategory.setId("book"); + + UsageReportPointCategoryRest bookChapterCategory = new UsageReportPointCategoryRest(); + bookChapterCategory.addValue("views", 0); + bookChapterCategory.setId("bookChapter"); + + UsageReportPointCategoryRest datasetCategory = new UsageReportPointCategoryRest(); + datasetCategory.addValue("views", 0); + datasetCategory.setId("dataset"); + + List categories = List.of(articleCategory, thesisCategory, otherCategory, bookCategory, + bookChapterCategory, datasetCategory); + + // And request the collections global usage report (show top most popular items) + getClient(adminToken) + .perform(get("/api/statistics/usagereports/search/object") + .param("category", "collection-itemReports") + .param("uri", "http://localhost:8080/server/api/core/collections/" + collectionNotVisited.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.usagereports", not(empty()))) + .andExpect(jsonPath("$._embedded.usagereports", Matchers.containsInAnyOrder( + matchUsageReport(collectionNotVisited.getID() + "_" + TOTAL_ITEMS_VISITS_REPORT_ID, + TOP_ITEMS_REPORT_ID, points), + matchUsageReport(collectionNotVisited.getID() + "_" + TOP_ITEMS_CITIES_REPORT_ID, + TOP_CITIES_REPORT_ID, List.of(pointCity)), + matchUsageReport(collectionNotVisited.getID() + "_" + TOTAL_ITEMS_VISITS_PER_MONTH_REPORT_ID, + TOTAL_VISITS_PER_MONTH_REPORT_ID, getLastMonthVisitPoints(5)), + matchUsageReport(collectionNotVisited.getID() + "_" + TOP_ITEMS_CONTINENTS_REPORT_ID, + TOP_CONTINENTS_REPORT_ID, List.of(pointContinent)), + matchUsageReport(collectionNotVisited.getID() + "_" + TOP_ITEMS_CATEGORIES_REPORT_ID, + TOP_CATEGORIES_REPORT_ID, categories), + matchUsageReport(collectionNotVisited.getID() + "_" + TOP_ITEMS_COUNTRIES_REPORT_ID, + TOP_COUNTRIES_REPORT_ID, List.of(pointCountry))))); + } + + @Test + public void usageReportsSearch_Collection_DownloadReports() throws Exception { + + context.turnOffAuthorisationSystem(); + + Item item1 = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("Item 1") + .build(); + + Item item2 = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("Item 2") + .build(); + + Item item3 = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("Item 3") + .build(); + + Bitstream bitstream1 = createBitstream(item1, "Bitstream 1"); + Bitstream bitstream2 = createBitstream(item1, "Bitstream 2"); + Bitstream bitstream3 = createBitstream(item2, "Bitstream 3"); + Bitstream bitstream4 = createBitstream(item3, "Bitstream 4"); + + getClient().perform(get("/api/core/bitstreams/" + bitstream1.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream1.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream2.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream3.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream3.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream3.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream4.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream4.getID() + "/content")) + .andExpect(status().isOk()); + + context.restoreAuthSystemState(); + + UsageReportPointDsoTotalVisitsRest expectedPoint1 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint1.addValue("views", 3); + expectedPoint1.setType("item"); + expectedPoint1.setLabel("Item 1"); + expectedPoint1.setId(item1.getID().toString()); + + UsageReportPointDsoTotalVisitsRest expectedPoint2 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint2.addValue("views", 3); + expectedPoint2.setType("item"); + expectedPoint2.setLabel("Item 2"); + expectedPoint2.setId(item2.getID().toString()); + + UsageReportPointDsoTotalVisitsRest expectedPoint3 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint3.addValue("views", 2); + expectedPoint3.setType("item"); + expectedPoint3.setLabel("Item 3"); + expectedPoint3.setId(item3.getID().toString()); + + List points = List.of(expectedPoint1, expectedPoint2, expectedPoint3); + + UsageReportPointCityRest pointCity = new UsageReportPointCityRest(); + pointCity.addValue("views", 8); + pointCity.setId("New York"); + + UsageReportPointContinentRest pointContinent = new UsageReportPointContinentRest(); + pointContinent.addValue("views", 8); + pointContinent.setId("North America"); + + UsageReportPointCountryRest pointCountry = new UsageReportPointCountryRest(); + pointCountry.addValue("views", 8); + pointCountry.setIdAndLabel(Locale.US.getCountry(), Locale.US.getDisplayCountry(context.getCurrentLocale())); + + getClient(adminToken) + .perform(get("/api/statistics/usagereports/search/object") + .param("category", "collection-downloadReports") + .param("uri", "http://localhost:8080/server/api/core/collections/" + collectionNotVisited.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.usagereports", not(empty()))) + .andExpect(jsonPath("$._embedded.usagereports", Matchers.containsInAnyOrder( + matchUsageReport(collectionNotVisited.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID, + TOP_ITEMS_REPORT_ID, points), + matchUsageReport(collectionNotVisited.getID() + "_" + TOP_DOWNLOAD_CITIES_REPORT_ID, + TOP_CITIES_REPORT_ID, List.of(pointCity)), + matchUsageReport(collectionNotVisited.getID() + "_" + TOTAL_DOWNLOAD_PER_MONTH_REPORT_ID, + TOTAL_VISITS_PER_MONTH_REPORT_ID, getLastMonthVisitPoints(8)), + matchUsageReport(collectionNotVisited.getID() + "_" + TOP_DOWNLOAD_CONTINENTS_REPORT_ID, + TOP_CONTINENTS_REPORT_ID, List.of(pointContinent)), + matchUsageReport(collectionNotVisited.getID() + "_" + TOP_DOWNLOAD_COUNTRIES_REPORT_ID, + TOP_COUNTRIES_REPORT_ID, List.of(pointCountry))))); + } + + @Test + public void usageReportsSearch_Community_ItemReports() throws Exception { + context.turnOffAuthorisationSystem(); + + Community community = CommunityBuilder.createCommunity(context).build(); + collectionNotVisited = CollectionBuilder.createCollection(context, community).build(); + + Item item = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("My item") + .withType("Controlled Vocabulary for Resource Type Genres::image") + .build(); + Item item2 = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("My item 2") + .withType("Controlled Vocabulary for Resource Type Genres::thesis") + .build(); + Item item3 = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("My item 3") + .withType("Controlled Vocabulary for Resource Type Genres::thesis::bachelor thesis") + .build(); + Item item4 = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("My item 4") + .withType("Controlled Vocabulary for Resource Type Genres::text::periodical::" + + "journal::contribution to journal::journal article") + .build(); + context.restoreAuthSystemState(); + + ObjectMapper mapper = new ObjectMapper(); + + ViewEventRest viewEventRest = new ViewEventRest(); + viewEventRest.setTargetType("item"); + viewEventRest.setTargetId(item.getID()); + + getClient().perform(post("/api/statistics/viewevents") + .content(mapper.writeValueAsBytes(viewEventRest)) + .contentType(contentType)) + .andExpect(status().isCreated()); + + ViewEventRest viewEventRest2 = new ViewEventRest(); + viewEventRest2.setTargetType("item"); + viewEventRest2.setTargetId(item2.getID()); + + getClient().perform(post("/api/statistics/viewevents") + .content(mapper.writeValueAsBytes(viewEventRest2)) + .contentType(contentType)) + .andExpect(status().isCreated()); + + getClient().perform(post("/api/statistics/viewevents") + .content(mapper.writeValueAsBytes(viewEventRest2)) + .contentType(contentType)) + .andExpect(status().isCreated()); + + ViewEventRest viewEventRest3 = new ViewEventRest(); + viewEventRest3.setTargetType("item"); + viewEventRest3.setTargetId(item3.getID()); + + getClient().perform(post("/api/statistics/viewevents") + .content(mapper.writeValueAsBytes(viewEventRest3)) + .contentType(contentType)) + .andExpect(status().isCreated()); + + ViewEventRest viewEventRest4 = new ViewEventRest(); + viewEventRest4.setTargetType("item"); + viewEventRest4.setTargetId(item4.getID()); + + getClient().perform(post("/api/statistics/viewevents") + .content(mapper.writeValueAsBytes(viewEventRest4)) + .contentType(contentType)) + .andExpect(status().isCreated()); + + UsageReportPointDsoTotalVisitsRest expectedPoint1 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint1.addValue("views", 1); + expectedPoint1.setType("item"); + expectedPoint1.setLabel("My item"); + expectedPoint1.setId(item.getID().toString()); + + UsageReportPointDsoTotalVisitsRest expectedPoint2 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint2.addValue("views", 2); + expectedPoint2.setType("item"); + expectedPoint2.setLabel("My item 2"); + expectedPoint2.setId(item2.getID().toString()); + + UsageReportPointDsoTotalVisitsRest expectedPoint3 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint3.addValue("views", 1); + expectedPoint3.setType("item"); + expectedPoint3.setLabel("My item 3"); + expectedPoint3.setId(item3.getID().toString()); + + UsageReportPointDsoTotalVisitsRest expectedPoint4 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint4.addValue("views", 1); + expectedPoint4.setType("item"); + expectedPoint4.setLabel("My item 4"); + expectedPoint4.setId(item4.getID().toString()); + + List points = List.of(expectedPoint1, expectedPoint2, expectedPoint3, expectedPoint4); + + UsageReportPointCityRest pointCity = new UsageReportPointCityRest(); + pointCity.addValue("views", 5); + pointCity.setId("New York"); + + UsageReportPointContinentRest pointContinent = new UsageReportPointContinentRest(); + pointContinent.addValue("views", 5); + pointContinent.setId("North America"); + + UsageReportPointCountryRest pointCountry = new UsageReportPointCountryRest(); + pointCountry.addValue("views", 5); + pointCountry.setIdAndLabel(Locale.US.getCountry(), Locale.US.getDisplayCountry(context.getCurrentLocale())); + + UsageReportPointCategoryRest articleCategory = new UsageReportPointCategoryRest(); + articleCategory.addValue("views", 1); + articleCategory.setId("article"); + + UsageReportPointCategoryRest thesisCategory = new UsageReportPointCategoryRest(); + thesisCategory.addValue("views", 3); + thesisCategory.setId("thesis"); + + UsageReportPointCategoryRest otherCategory = new UsageReportPointCategoryRest(); + otherCategory.addValue("views", 1); + otherCategory.setId("other"); + + UsageReportPointCategoryRest bookCategory = new UsageReportPointCategoryRest(); + bookCategory.addValue("views", 0); + bookCategory.setId("book"); + + UsageReportPointCategoryRest bookChapterCategory = new UsageReportPointCategoryRest(); + bookChapterCategory.addValue("views", 0); + bookChapterCategory.setId("bookChapter"); + + UsageReportPointCategoryRest datasetCategory = new UsageReportPointCategoryRest(); + datasetCategory.addValue("views", 0); + datasetCategory.setId("dataset"); + + List categories = List.of(articleCategory, thesisCategory, otherCategory, bookCategory, + bookChapterCategory, datasetCategory); + + // And request the collections global usage report (show top most popular items) + getClient(adminToken) + .perform(get("/api/statistics/usagereports/search/object") + .param("category", "community-itemReports") + .param("uri", "http://localhost:8080/server/api/core/communities/" + community.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.usagereports", not(empty()))) + .andExpect(jsonPath("$._embedded.usagereports", Matchers.containsInAnyOrder( + matchUsageReport(community.getID() + "_" + TOTAL_ITEMS_VISITS_REPORT_ID, + TOP_ITEMS_REPORT_ID, points), + matchUsageReport(community.getID() + "_" + TOP_ITEMS_CITIES_REPORT_ID, + TOP_CITIES_REPORT_ID, List.of(pointCity)), + matchUsageReport(community.getID() + "_" + TOTAL_ITEMS_VISITS_PER_MONTH_REPORT_ID, + TOTAL_VISITS_PER_MONTH_REPORT_ID, getLastMonthVisitPoints(5)), + matchUsageReport(community.getID() + "_" + TOP_ITEMS_CONTINENTS_REPORT_ID, + TOP_CONTINENTS_REPORT_ID, List.of(pointContinent)), + matchUsageReport(community.getID() + "_" + TOP_ITEMS_CATEGORIES_REPORT_ID, + TOP_CATEGORIES_REPORT_ID, categories), + matchUsageReport(community.getID() + "_" + TOP_ITEMS_COUNTRIES_REPORT_ID, + TOP_COUNTRIES_REPORT_ID, List.of(pointCountry))))); + } + + @Test + public void usageReportsSearch_Community_DownloadReports() throws Exception { + + context.turnOffAuthorisationSystem(); + + Community community = CommunityBuilder.createCommunity(context).build(); + collectionNotVisited = CollectionBuilder.createCollection(context, community).build(); + + Item item1 = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("Item 1") + .build(); + + Item item2 = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("Item 2") + .build(); + + Item item3 = ItemBuilder.createItem(context, collectionNotVisited) + .withTitle("Item 3") + .build(); + + Bitstream bitstream1 = createBitstream(item1, "Bitstream 1"); + Bitstream bitstream2 = createBitstream(item1, "Bitstream 2"); + Bitstream bitstream3 = createBitstream(item2, "Bitstream 3"); + Bitstream bitstream4 = createBitstream(item3, "Bitstream 4"); + + getClient().perform(get("/api/core/bitstreams/" + bitstream1.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream1.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream2.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream3.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream3.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream3.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream4.getID() + "/content")) + .andExpect(status().isOk()); + + getClient().perform(get("/api/core/bitstreams/" + bitstream4.getID() + "/content")) + .andExpect(status().isOk()); + + context.restoreAuthSystemState(); + + UsageReportPointDsoTotalVisitsRest expectedPoint1 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint1.addValue("views", 3); + expectedPoint1.setType("item"); + expectedPoint1.setLabel("Item 1"); + expectedPoint1.setId(item1.getID().toString()); + + UsageReportPointDsoTotalVisitsRest expectedPoint2 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint2.addValue("views", 3); + expectedPoint2.setType("item"); + expectedPoint2.setLabel("Item 2"); + expectedPoint2.setId(item2.getID().toString()); + + UsageReportPointDsoTotalVisitsRest expectedPoint3 = new UsageReportPointDsoTotalVisitsRest(); + expectedPoint3.addValue("views", 2); + expectedPoint3.setType("item"); + expectedPoint3.setLabel("Item 3"); + expectedPoint3.setId(item3.getID().toString()); + + List points = List.of(expectedPoint1, expectedPoint2, expectedPoint3); + + UsageReportPointCityRest pointCity = new UsageReportPointCityRest(); + pointCity.addValue("views", 8); + pointCity.setId("New York"); + + UsageReportPointContinentRest pointContinent = new UsageReportPointContinentRest(); + pointContinent.addValue("views", 8); + pointContinent.setId("North America"); + + UsageReportPointCountryRest pointCountry = new UsageReportPointCountryRest(); + pointCountry.addValue("views", 8); + pointCountry.setIdAndLabel(Locale.US.getCountry(), Locale.US.getDisplayCountry(context.getCurrentLocale())); + + getClient(adminToken) + .perform(get("/api/statistics/usagereports/search/object") + .param("category", "community-downloadReports") + .param("uri", "http://localhost:8080/server/api/core/communities/" + community.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.usagereports", not(empty()))) + .andExpect(jsonPath("$._embedded.usagereports", Matchers.containsInAnyOrder( + matchUsageReport(community.getID() + "_" + TOTAL_DOWNLOADS_REPORT_ID, TOP_ITEMS_REPORT_ID, points), + matchUsageReport(community.getID() + "_" + TOP_DOWNLOAD_CITIES_REPORT_ID, + TOP_CITIES_REPORT_ID, List.of(pointCity)), + matchUsageReport(community.getID() + "_" + TOTAL_DOWNLOAD_PER_MONTH_REPORT_ID, + TOTAL_VISITS_PER_MONTH_REPORT_ID, getLastMonthVisitPoints(8)), + matchUsageReport(community.getID() + "_" + TOP_DOWNLOAD_CONTINENTS_REPORT_ID, + TOP_CONTINENTS_REPORT_ID, List.of(pointContinent)), + matchUsageReport(community.getID() + "_" + TOP_DOWNLOAD_COUNTRIES_REPORT_ID, + TOP_COUNTRIES_REPORT_ID, List.of(pointCountry))))); + } + private List getLastMonthVisitPoints(int viewsLastMonth) { return getListOfVisitsPerMonthsPoints(viewsLastMonth, 0); } diff --git a/dspace/config/spring/api/discovery.xml b/dspace/config/spring/api/discovery.xml index 1ddf0da887e..6e759f05295 100644 --- a/dspace/config/spring/api/discovery.xml +++ b/dspace/config/spring/api/discovery.xml @@ -133,6 +133,10 @@ + + + + @@ -2291,6 +2295,28 @@ + + + + + + + location.coll:{0} + + + + + + + + + + + location.comm:{0} + + + + diff --git a/dspace/config/spring/rest/statistics.xml b/dspace/config/spring/rest/statistics.xml index 91a970210d3..23b528eddcb 100644 --- a/dspace/config/spring/rest/statistics.xml +++ b/dspace/config/spring/rest/statistics.xml @@ -417,6 +417,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -598,6 +774,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -610,6 +813,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -649,11 +879,15 @@ + + + +