Skip to content

Commit

Permalink
Merged in task/dspace-cris-2023_02_x/DSC-1904 (pull request DSpace#2751)
Browse files Browse the repository at this point in the history
Task/dspace cris 2023 02 x/DSC-1904

Approved-by: Giuseppe Digilio
  • Loading branch information
vins01-4science authored and atarix83 committed Sep 18, 2024
2 parents d82c430 + 4307bdf commit 8439936
Show file tree
Hide file tree
Showing 4 changed files with 287 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* 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.discovery;

import java.sql.SQLException;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.core.LogHelper;
import org.dspace.eperson.service.GroupService;
import org.springframework.beans.factory.annotation.Autowired;

/**
* Plugin that filters out non-administered items from administrative searches for collections and communities admins.
*
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
*/
public class SolrServiceAdministrativeSearchRestrictionPlugin implements SolrServiceSearchPlugin {

private static final Logger log =
org.apache.logging.log4j.LogManager.getLogger(SolrServiceAdministrativeSearchRestrictionPlugin.class);
public static final String SEARCH_CONFIGURATION_PREFIX = "administrative";

@Autowired
protected AuthorizeService authorizeService;
@Autowired
protected GroupService groupService;

private static boolean isAdministrativeConfiguration(DiscoverQuery discoveryQuery) {
return discoveryQuery != null &&
StringUtils.isNotBlank(discoveryQuery.getDiscoveryConfigurationName()) &&
discoveryQuery.getDiscoveryConfigurationName().startsWith(SEARCH_CONFIGURATION_PREFIX);
}

@Override
public void additionalSearchParameters(Context context, DiscoverQuery discoveryQuery, SolrQuery solrQuery) {
try {

// Only apply this plugin to administrative searches
if (!isAdministrativeConfiguration(discoveryQuery)) {
return;
}

// Only apply this plugin to non-administrators
if (isAdmin(context)) {
return;
}

// Only apply this plugin to community / collection administrators
if (!isCommunityCollAdmin(context)) {
return;
}

// Applies filter query to restrict search results to only those that are administrate by the current user
solrQuery.addFilterQuery(
Stream.concat(
groupService.allMemberGroupsSet(context, context.getCurrentUser())
.stream()
.map(group -> "g" + group.getID()),
Stream.of(context.getCurrentUser())
.filter(Objects::nonNull)
.map(eperson -> String.valueOf(eperson.getID()))
)
.collect(Collectors.joining(" OR ", "admin:(", ")"))
);
} catch (SQLException e) {
log.error(LogHelper.getHeader(context, "Error while adding resource policy information to query", ""), e);
}
}

private boolean isCommunityCollAdmin(Context context) throws SQLException {
return this.authorizeService.isCollectionAdmin(context) || this.authorizeService.isCommunityAdmin(context);
}

private boolean isAdmin(Context context) throws SQLException {
return authorizeService.isAdmin(context);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
</bean>
<bean id="solrServiceBestMatchIndexingPlugin" class="org.dspace.discovery.SolrServiceBestMatchIndexingPlugin"/>
<bean id="solrServiceBestMatchStrictIndexingPlugin" class="org.dspace.discovery.SolrServiceStrictBestMatchIndexingPlugin"/>
<bean id="solrServiceAdministrativeSearchRestrictionPlugin" class="org.dspace.discovery.SolrServiceAdministrativeSearchRestrictionPlugin"/>
<bean id="sharedWorkspaceSolrIndexPlugin" class="org.dspace.discovery.SharedWorkspaceSolrIndexPlugin">
<constructor-arg name="additionalReadMetadata" ref="sharedWorkspaceAuthorMetadataFields"/>
</bean>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5506,6 +5506,201 @@ public void discoverSearchObjectsTestForAdministrativeViewAdmin() throws Excepti
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));
}

@Test
public void discoverSearchObjectsTestForAdministrativeViewCollCommAdministrators() throws Exception {

//We turn off the authorization system in order to create the structure as defined below
context.turnOffAuthorisationSystem();

//** GIVEN **

//1. A community-collection structure with one parent community with sub-community and two collections.

EPerson commAdmin =
EPersonBuilder.createEPerson(context)
.withEmail("[email protected]")
.withPassword(password)
.withNameInMetadata("Community", "Admin")
.withCanLogin(true)
.build();

EPerson subCommAdmin =
EPersonBuilder.createEPerson(context)
.withEmail("[email protected]")
.withPassword(password)
.withNameInMetadata("SubCommunity", "Admin")
.withCanLogin(true)
.build();

EPerson collAdmin =
EPersonBuilder.createEPerson(context)
.withEmail("[email protected]")
.withPassword(password)
.withNameInMetadata("Collection", "Admin")
.withCanLogin(true)
.build();

parentCommunity = CommunityBuilder
.createCommunity(context)
.withName("Parent Community")
.withAdminGroup(commAdmin)
.build();
Community child1 = CommunityBuilder
.createSubCommunity(context, parentCommunity)
.withName("Sub Community")
.withAdminGroup(subCommAdmin)
.build();
Collection col1 = CollectionBuilder
.createCollection(context, child1)
.withName("Collection 1")
.withAdminGroup(collAdmin)
.build();
Collection col2 = CollectionBuilder
.createCollection(context, child1)
.withName("Collection 2")
.build();
Collection col3 = CollectionBuilder
.createCollection(context, parentCommunity)
.withName("Collection 3")
.build();

//2. One public item, one private, one withdrawn.

ItemBuilder.createItem(context, col1)
.withTitle("COL1 Test Item")
.withIssueDate("2010-10-17")
.withAuthor("Smith, Donald")
.withSubject("ExtraEntry")
.build();

ItemBuilder.createItem(context, col2)
.withTitle("COL2 Test Item")
.withIssueDate("2024-09-16")
.withAuthor("Smith, Maria")
.withAuthor("Doe, Jane")
.build();

ItemBuilder.createItem(context, col2)
.withTitle("COL2-1 Test Item")
.withIssueDate("2024-09-16")
.withAuthor("Smith, Maria")
.withAuthor("Doe, Jane")
.build();

ItemBuilder.createItem(context, col3)
.withTitle("COL3 Test Item")
.withIssueDate("2024-09-16")
.withAuthor("Smith, Maria")
.withAuthor("Doe, Jane")
.build();

context.restoreAuthSystemState();

String adminToken = getAuthToken(admin.getEmail(), password);

getClient(adminToken).perform(get("/api/discover/search/objects")
.param("configuration", "administrativeView")
.param("query", "Test"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.type", is("discover")))
.andExpect(jsonPath("$._embedded.searchResult.page", is(
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 4)
)))
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects",
Matchers.containsInAnyOrder(
SearchResultMatcher.matchOnItemName(
"item", "items", "COL1 Test Item"
),
SearchResultMatcher.matchOnItemName(
"item", "items", "COL2 Test Item"
),
SearchResultMatcher.matchOnItemName(
"item", "items", "COL2-1 Test Item"
),
SearchResultMatcher.matchOnItemName(
"item", "items", "COL3 Test Item"
)
)
))
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));

String commAdminToken = getAuthToken(commAdmin.getEmail(), password);

getClient(commAdminToken).perform(get("/api/discover/search/objects")
.param("configuration", "administrativeView")
.param("query", "Test"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.type", is("discover")))
.andExpect(jsonPath("$._embedded.searchResult.page", is(
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 4)
)))
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects",
Matchers.containsInAnyOrder(
SearchResultMatcher.matchOnItemName(
"item", "items", "COL1 Test Item"
),
SearchResultMatcher.matchOnItemName(
"item", "items", "COL2 Test Item"
),
SearchResultMatcher.matchOnItemName(
"item", "items", "COL2-1 Test Item"
),
SearchResultMatcher.matchOnItemName(
"item", "items", "COL3 Test Item"
)
)
))
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")));

String collAdminToken = getAuthToken(collAdmin.getEmail(), password);

getClient(collAdminToken).perform(get("/api/discover/search/objects")
.param("configuration", "administrativeView")
.param("query", "Test"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.type", is("discover")))
.andExpect(jsonPath("$._embedded.searchResult.page", is(
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 1)
)))
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects",
Matchers.containsInAnyOrder(
SearchResultMatcher.matchOnItemName(
"item", "items", "COL1 Test Item"
)
)
))
.andExpect(jsonPath("$._links.self.href",
containsString("/api/discover/search/objects"))
);

String subCommAdminToken = getAuthToken(subCommAdmin.getEmail(), password);

getClient(subCommAdminToken).perform(get("/api/discover/search/objects")
.param("configuration", "administrativeView")
.param("query", "Test"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.type", is("discover")))
.andExpect(jsonPath("$._embedded.searchResult.page", is(
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3)
)))
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects",
Matchers.containsInAnyOrder(
SearchResultMatcher.matchOnItemName(
"item", "items", "COL1 Test Item"
),
SearchResultMatcher.matchOnItemName(
"item", "items", "COL2 Test Item"
),
SearchResultMatcher.matchOnItemName(
"item", "items", "COL2-1 Test Item"
)
)
))
.andExpect(jsonPath("$._links.self.href",
containsString("/api/discover/search/objects"))
);
}

@Test
public void discoverSearchObjectsTestForAdministrativeViewWithFilters() throws Exception {

Expand Down
1 change: 1 addition & 0 deletions dspace/config/spring/api/discovery.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
<bean id="sharedWorkspaceSolrIndexPlugin" class="org.dspace.discovery.SharedWorkspaceSolrIndexPlugin">
<constructor-arg name="additionalReadMetadata" ref="sharedWorkspaceAuthorMetadataFields"/>
</bean>
<bean id="solrServiceAdministrativeSearchRestrictionPlugin" class="org.dspace.discovery.SolrServiceAdministrativeSearchRestrictionPlugin"/>

<util:list id="sharedWorkspaceAuthorMetadataFields" value-type="java.lang.String">
<value>dc.contributor.author</value>
Expand Down

0 comments on commit 8439936

Please sign in to comment.