mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-10 03:23:13 +00:00
[CST-5306] Improvements on ResearcherProfileRestRepository
This commit is contained in:
@@ -8,32 +8,26 @@
|
|||||||
package org.dspace.app.exception;
|
package org.dspace.app.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides an exception to be used when a conflict on a resource
|
* This class provides an exception to be used when trying to save a resource
|
||||||
* occurs.
|
* that already exists.
|
||||||
*
|
*
|
||||||
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class ResourceConflictException extends RuntimeException {
|
public class ResourceAlreadyExistsException extends RuntimeException {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final Object resource;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a ResourceConflictException with a message and the conflicting
|
* Create a ResourceAlreadyExistsException with a message and the already
|
||||||
* resource.
|
* existing resource.
|
||||||
*
|
*
|
||||||
* @param message the error message
|
* @param message the error message
|
||||||
* @param resource the resource that caused the conflict
|
* @param resource the resource that caused the conflict
|
||||||
*/
|
*/
|
||||||
public ResourceConflictException(String message, Object resource) {
|
public ResourceAlreadyExistsException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
this.resource = resource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getResource() {
|
|
||||||
return resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@@ -52,6 +52,11 @@ public class ResearcherProfile {
|
|||||||
return dspaceObjectOwner.getValue();
|
return dspaceObjectOwner.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A profile is considered visible if accessible by anonymous users. This method
|
||||||
|
* returns true if the given item has a READ policy related to ANONYMOUS group,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
public boolean isVisible() {
|
public boolean isVisible() {
|
||||||
return item.getResourcePolicies().stream()
|
return item.getResourcePolicies().stream()
|
||||||
.filter(policy -> policy.getGroup() != null)
|
.filter(policy -> policy.getGroup() != null)
|
||||||
|
@@ -9,7 +9,6 @@ package org.dspace.app.profile;
|
|||||||
|
|
||||||
import static java.util.Optional.empty;
|
import static java.util.Optional.empty;
|
||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
import static org.apache.commons.lang3.ArrayUtils.contains;
|
|
||||||
import static org.dspace.content.authority.Choices.CF_ACCEPTED;
|
import static org.dspace.content.authority.Choices.CF_ACCEPTED;
|
||||||
import static org.dspace.core.Constants.READ;
|
import static org.dspace.core.Constants.READ;
|
||||||
import static org.dspace.eperson.Group.ANONYMOUS;
|
import static org.dspace.eperson.Group.ANONYMOUS;
|
||||||
@@ -24,7 +23,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.dspace.app.exception.ResourceConflictException;
|
import org.dspace.app.exception.ResourceAlreadyExistsException;
|
||||||
import org.dspace.app.profile.service.ResearcherProfileService;
|
import org.dspace.app.profile.service.ResearcherProfileService;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.authorize.service.AuthorizeService;
|
import org.dspace.authorize.service.AuthorizeService;
|
||||||
@@ -105,8 +104,7 @@ public class ResearcherProfileServiceImpl implements ResearcherProfileService {
|
|||||||
|
|
||||||
Item profileItem = findResearcherProfileItemById(context, ePerson.getID());
|
Item profileItem = findResearcherProfileItemById(context, ePerson.getID());
|
||||||
if (profileItem != null) {
|
if (profileItem != null) {
|
||||||
ResearcherProfile profile = new ResearcherProfile(profileItem);
|
throw new ResourceAlreadyExistsException("A profile is already linked to the provided User");
|
||||||
throw new ResourceConflictException("A profile is already linked to the provided User", profile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection collection = findProfileCollection(context)
|
Collection collection = findProfileCollection(context)
|
||||||
@@ -136,7 +134,7 @@ public class ResearcherProfileServiceImpl implements ResearcherProfileService {
|
|||||||
if (isHardDeleteEnabled()) {
|
if (isHardDeleteEnabled()) {
|
||||||
deleteItem(context, profileItem);
|
deleteItem(context, profileItem);
|
||||||
} else {
|
} else {
|
||||||
removeDspaceObjectOwnerMetadata(context, profileItem);
|
removeOwnerMetadata(context, profileItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -161,47 +159,63 @@ public class ResearcherProfileServiceImpl implements ResearcherProfileService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResearcherProfile claim(final Context context, final EPerson ePerson, final URI uri)
|
public ResearcherProfile claim(Context context, EPerson ePerson, URI uri)
|
||||||
throws SQLException, AuthorizeException, SearchServiceException {
|
throws SQLException, AuthorizeException, SearchServiceException {
|
||||||
|
|
||||||
Item profileItem = findResearcherProfileItemById(context, ePerson.getID());
|
Item profileItem = findResearcherProfileItemById(context, ePerson.getID());
|
||||||
if (profileItem != null) {
|
if (profileItem != null) {
|
||||||
ResearcherProfile profile = new ResearcherProfile(profileItem);
|
throw new ResourceAlreadyExistsException("A profile is already linked to the provided User");
|
||||||
throw new ResourceConflictException("A profile is already linked to the provided User", profile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item item = findItemByURI(context, uri)
|
Item item = findItemByURI(context, uri)
|
||||||
.orElseThrow(() -> new IllegalArgumentException("No item found by URI " + uri));
|
.orElseThrow(() -> new IllegalArgumentException("No item found by URI " + uri));
|
||||||
|
|
||||||
if (!item.isArchived() || item.isWithdrawn() || notClaimableEntityType(item)) {
|
if (!item.isArchived() || item.isWithdrawn()) {
|
||||||
throw new IllegalArgumentException("Provided uri does not represent a valid Item to be claimed");
|
throw new IllegalArgumentException(
|
||||||
|
"Only archived items can be claimed to create a researcher profile. Item ID: " + item.getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasProfileType(item)) {
|
||||||
|
throw new IllegalArgumentException("The provided item has not a profile type. Item ID: " + item.getID());
|
||||||
}
|
}
|
||||||
|
|
||||||
String existingOwner = itemService.getMetadataFirstValue(item, "dspace", "object", "owner", Item.ANY);
|
String existingOwner = itemService.getMetadataFirstValue(item, "dspace", "object", "owner", Item.ANY);
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(existingOwner)) {
|
if (StringUtils.isNotBlank(existingOwner)) {
|
||||||
throw new IllegalArgumentException("Item with provided uri has already an owner");
|
throw new IllegalArgumentException("Item with provided uri has already an owner - ID: " + existingOwner);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
itemService.addMetadata(context, item, "dspace", "object", "owner", null,
|
itemService.addMetadata(context, item, "dspace", "object", "owner", null,
|
||||||
ePerson.getName(), ePerson.getID().toString(), CF_ACCEPTED);
|
ePerson.getName(), ePerson.getID().toString(), CF_ACCEPTED);
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
return new ResearcherProfile(item);
|
return new ResearcherProfile(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasProfileType(Item item) {
|
||||||
|
String profileType = getProfileType();
|
||||||
|
if (StringUtils.isBlank(profileType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return profileType.equals(itemService.getEntityType(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProfileType() {
|
||||||
|
return configurationService.getProperty("researcher-profile.entity-type", "Person");
|
||||||
|
}
|
||||||
|
|
||||||
private Optional<Item> findItemByURI(final Context context, final URI uri) throws SQLException {
|
private Optional<Item> findItemByURI(final Context context, final URI uri) throws SQLException {
|
||||||
String path = uri.getPath();
|
String path = uri.getPath();
|
||||||
UUID uuid = UUIDUtils.fromString(path.substring(path.lastIndexOf("/") + 1));
|
UUID uuid = UUIDUtils.fromString(path.substring(path.lastIndexOf("/") + 1));
|
||||||
return ofNullable(itemService.find(context, uuid));
|
return ofNullable(itemService.find(context, uuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean notClaimableEntityType(final Item item) {
|
/**
|
||||||
String entityType = itemService.getEntityType(item);
|
* Search for an profile item owned by an eperson with the given id.
|
||||||
return !contains(configurationService.getArrayProperty("claimable.entityType"), entityType);
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
private Item findResearcherProfileItemById(Context context, UUID id) throws SQLException, AuthorizeException {
|
private Item findResearcherProfileItemById(Context context, UUID id) throws SQLException, AuthorizeException {
|
||||||
|
|
||||||
String profileType = getProfileType();
|
String profileType = getProfileType();
|
||||||
@@ -218,6 +232,10 @@ public class ResearcherProfileServiceImpl implements ResearcherProfileService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Profile collection based on a configuration or searching for a
|
||||||
|
* collection of researcher profile type.
|
||||||
|
*/
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private Optional<Collection> findProfileCollection(Context context) throws SQLException, SearchServiceException {
|
private Optional<Collection> findProfileCollection(Context context) throws SQLException, SearchServiceException {
|
||||||
UUID uuid = UUIDUtils.fromString(configurationService.getProperty("researcher-profile.collection.uuid"));
|
UUID uuid = UUIDUtils.fromString(configurationService.getProperty("researcher-profile.collection.uuid"));
|
||||||
@@ -246,6 +264,9 @@ public class ResearcherProfileServiceImpl implements ResearcherProfileService {
|
|||||||
return ofNullable((Collection) indexableObjects.get(0).getIndexedObject());
|
return ofNullable((Collection) indexableObjects.get(0).getIndexedObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new profile item for the given ePerson in the provided collection.
|
||||||
|
*/
|
||||||
private Item createProfileItem(Context context, EPerson ePerson, Collection collection)
|
private Item createProfileItem(Context context, EPerson ePerson, Collection collection)
|
||||||
throws AuthorizeException, SQLException {
|
throws AuthorizeException, SQLException {
|
||||||
|
|
||||||
@@ -259,22 +280,34 @@ public class ResearcherProfileServiceImpl implements ResearcherProfileService {
|
|||||||
|
|
||||||
item = installItemService.installItem(context, workspaceItem);
|
item = installItemService.installItem(context, workspaceItem);
|
||||||
|
|
||||||
|
if (isNewProfilePrivateByDefault()) {
|
||||||
Group anonymous = groupService.findByName(context, ANONYMOUS);
|
Group anonymous = groupService.findByName(context, ANONYMOUS);
|
||||||
authorizeService.removeGroupPolicies(context, item, anonymous);
|
authorizeService.removeGroupPolicies(context, item, anonymous);
|
||||||
|
}
|
||||||
|
|
||||||
authorizeService.addPolicy(context, item, READ, ePerson);
|
authorizeService.addPolicy(context, item, READ, ePerson);
|
||||||
|
|
||||||
return item;
|
return reloadItem(context, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isHardDeleteEnabled() {
|
private boolean isHardDeleteEnabled() {
|
||||||
return configurationService.getBooleanProperty("researcher-profile.hard-delete.enabled");
|
return configurationService.getBooleanProperty("researcher-profile.hard-delete.enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeDspaceObjectOwnerMetadata(Context context, Item profileItem) throws SQLException {
|
private boolean isNewProfilePrivateByDefault() {
|
||||||
|
return configurationService.getBooleanProperty("researcher-profile.set-new-profile-private");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeOwnerMetadata(Context context, Item profileItem) throws SQLException {
|
||||||
List<MetadataValue> metadata = itemService.getMetadata(profileItem, "dspace", "object", "owner", Item.ANY);
|
List<MetadataValue> metadata = itemService.getMetadata(profileItem, "dspace", "object", "owner", Item.ANY);
|
||||||
itemService.removeMetadataValues(context, profileItem, metadata);
|
itemService.removeMetadataValues(context, profileItem, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Item reloadItem(Context context, Item item) throws SQLException {
|
||||||
|
context.uncacheEntity(item);
|
||||||
|
return context.reloadEntity(item);
|
||||||
|
}
|
||||||
|
|
||||||
private void deleteItem(Context context, Item profileItem) throws SQLException, AuthorizeException {
|
private void deleteItem(Context context, Item profileItem) throws SQLException, AuthorizeException {
|
||||||
try {
|
try {
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
@@ -286,8 +319,4 @@ public class ResearcherProfileServiceImpl implements ResearcherProfileService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getProfileType() {
|
|
||||||
return configurationService.getProperty("researcher-profile.type", "Person");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -13,6 +13,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import org.dspace.app.profile.ResearcherProfile;
|
import org.dspace.app.profile.ResearcherProfile;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
|
import org.dspace.content.Item;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.discovery.SearchServiceException;
|
import org.dspace.discovery.SearchServiceException;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
@@ -52,8 +53,10 @@ public interface ResearcherProfileService {
|
|||||||
throws AuthorizeException, SQLException, SearchServiceException;
|
throws AuthorizeException, SQLException, SearchServiceException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the association between the researcher profile and eperson related to
|
* Delete the profile with the given id. Based on the
|
||||||
* the input uuid.
|
* researcher-profile.hard-delete.enabled configuration, this method deletes the
|
||||||
|
* related item or removes the association between the researcher profile and
|
||||||
|
* eperson related to the input uuid.
|
||||||
*
|
*
|
||||||
* @param context the relevant DSpace Context.
|
* @param context the relevant DSpace Context.
|
||||||
* @param id the researcher profile id
|
* @param id the researcher profile id
|
||||||
@@ -63,11 +66,13 @@ public interface ResearcherProfileService {
|
|||||||
public void deleteById(Context context, UUID id) throws SQLException, AuthorizeException;
|
public void deleteById(Context context, UUID id) throws SQLException, AuthorizeException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the visibility of the given profile using the given new visible value
|
* Changes the visibility of the given profile using the given new visible
|
||||||
|
* value.
|
||||||
*
|
*
|
||||||
* @param context the relevant DSpace Context.
|
* @param context the relevant DSpace Context.
|
||||||
* @param profile the researcher profile to update
|
* @param profile the researcher profile to update
|
||||||
* @param visible the visible value to set
|
* @param visible the visible value to set. If true the profile will
|
||||||
|
* be visible to all users.
|
||||||
* @throws SQLException
|
* @throws SQLException
|
||||||
* @throws AuthorizeException
|
* @throws AuthorizeException
|
||||||
*/
|
*/
|
||||||
@@ -78,9 +83,30 @@ public interface ResearcherProfileService {
|
|||||||
* Claims and links an eperson to an existing DSpaceObject
|
* Claims and links an eperson to an existing DSpaceObject
|
||||||
* @param context the relevant DSpace Context.
|
* @param context the relevant DSpace Context.
|
||||||
* @param ePerson the ePerson
|
* @param ePerson the ePerson
|
||||||
* @param uri uri of existing DSpaceObject to be linked to the eperson
|
* @param uri uri of existing Item to be linked to the
|
||||||
* @return
|
* eperson
|
||||||
|
* @return the created profile
|
||||||
|
* @throws IllegalArgumentException if the given uri is not related to an
|
||||||
|
* archived item or if the item cannot be
|
||||||
|
* claimed
|
||||||
*/
|
*/
|
||||||
ResearcherProfile claim(Context context, EPerson ePerson, URI uri)
|
ResearcherProfile claim(Context context, EPerson ePerson, URI uri)
|
||||||
throws SQLException, AuthorizeException, SearchServiceException;
|
throws SQLException, AuthorizeException, SearchServiceException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given item has an entity type compatible with that of the
|
||||||
|
* researcher profile. If the given item does not have an entity type, the check
|
||||||
|
* returns false.
|
||||||
|
*
|
||||||
|
* @param item the item to check
|
||||||
|
* @return the check result
|
||||||
|
*/
|
||||||
|
boolean hasProfileType(Item item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the profile entity type, if any.
|
||||||
|
*
|
||||||
|
* @return the profile type
|
||||||
|
*/
|
||||||
|
String getProfileType();
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||||
@@ -20,11 +21,14 @@ import org.dspace.eperson.service.EPersonService;
|
|||||||
import org.dspace.util.UUIDUtils;
|
import org.dspace.util.UUIDUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Implementation of {@link ChoiceAuthority} based on EPerson. Allows you to set
|
||||||
|
* the id of an eperson as authority.
|
||||||
*
|
*
|
||||||
* @author Mykhaylo Boychuk (4science.it)
|
* @author Mykhaylo Boychuk (4science.it)
|
||||||
*/
|
*/
|
||||||
public class EPersonAuthority implements ChoiceAuthority {
|
public class EPersonAuthority implements ChoiceAuthority {
|
||||||
private static final Logger log = Logger.getLogger(EPersonAuthority.class);
|
|
||||||
|
private static final Logger log = LogManager.getLogger(EPersonAuthority.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the name assigned to the specific instance by the PluginService, @see
|
* the name assigned to the specific instance by the PluginService, @see
|
||||||
|
@@ -144,5 +144,3 @@ authentication-ip.Student = 6.6.6.6
|
|||||||
useProxies = true
|
useProxies = true
|
||||||
proxies.trusted.ipranges = 7.7.7.7
|
proxies.trusted.ipranges = 7.7.7.7
|
||||||
proxies.trusted.include_ui_ip = true
|
proxies.trusted.include_ui_ip = true
|
||||||
|
|
||||||
researcher-profile.type = Person
|
|
@@ -23,7 +23,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given user can claim the given item.
|
* Checks if the given user can claim the given item. An item can be claimed
|
||||||
|
* only if the show claim is enabled for it (see
|
||||||
|
* {@link org.dspace.app.rest.authorization.impl.ShowClaimItemFeature}).
|
||||||
*
|
*
|
||||||
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
*
|
*
|
||||||
|
@@ -11,7 +11,6 @@ import java.sql.SQLException;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
|
||||||
import org.dspace.app.profile.service.ResearcherProfileService;
|
import org.dspace.app.profile.service.ResearcherProfileService;
|
||||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||||
@@ -21,7 +20,6 @@ import org.dspace.authorize.AuthorizeException;
|
|||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
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.services.ConfigurationService;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -45,15 +43,11 @@ public class ShowClaimItemFeature implements AuthorizationFeature {
|
|||||||
|
|
||||||
private final ItemService itemService;
|
private final ItemService itemService;
|
||||||
private final ResearcherProfileService researcherProfileService;
|
private final ResearcherProfileService researcherProfileService;
|
||||||
private final ConfigurationService configurationService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ShowClaimItemFeature(ItemService itemService,
|
public ShowClaimItemFeature(ItemService itemService, ResearcherProfileService researcherProfileService) {
|
||||||
ResearcherProfileService researcherProfileService,
|
|
||||||
ConfigurationService configurationService) {
|
|
||||||
this.itemService = itemService;
|
this.itemService = itemService;
|
||||||
this.researcherProfileService = researcherProfileService;
|
this.researcherProfileService = researcherProfileService;
|
||||||
this.configurationService = configurationService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -67,25 +61,18 @@ public class ShowClaimItemFeature implements AuthorizationFeature {
|
|||||||
String id = ((ItemRest) object).getId();
|
String id = ((ItemRest) object).getId();
|
||||||
Item item = itemService.find(context, UUID.fromString(id));
|
Item item = itemService.find(context, UUID.fromString(id));
|
||||||
|
|
||||||
return claimableEntityType(item) && hasNotAlreadyAProfile(context);
|
return researcherProfileService.hasProfileType(item) && hasNotAlreadyAProfile(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasNotAlreadyAProfile(Context context) {
|
private boolean hasNotAlreadyAProfile(Context context) {
|
||||||
try {
|
try {
|
||||||
return researcherProfileService.findById(context, context.getCurrentUser().getID()) == null;
|
return researcherProfileService.findById(context, context.getCurrentUser().getID()) == null;
|
||||||
} catch (SQLException | AuthorizeException e) {
|
} catch (SQLException | AuthorizeException e) {
|
||||||
LOG.warn("Error while checking if eperson has a ResearcherProfileAssociated: {}",
|
LOG.warn("Error while checking if eperson has a ResearcherProfileAssociated: {}", e.getMessage(), e);
|
||||||
e.getMessage(), e);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean claimableEntityType(Item item) {
|
|
||||||
String[] claimableEntityTypes = configurationService.getArrayProperty("claimable.entityType");
|
|
||||||
String entityType = itemService.getEntityType(item);
|
|
||||||
return ArrayUtils.contains(claimableEntityTypes, entityType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getSupportedTypes() {
|
public String[] getSupportedTypes() {
|
||||||
return new String[] {ItemRest.CATEGORY + "." + ItemRest.NAME};
|
return new String[] {ItemRest.CATEGORY + "." + ItemRest.NAME};
|
||||||
|
@@ -20,16 +20,12 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
|
|
||||||
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.exception.ResourceConflictException;
|
import org.dspace.app.exception.ResourceAlreadyExistsException;
|
||||||
import org.dspace.app.rest.converter.ConverterService;
|
|
||||||
import org.dspace.app.rest.model.RestModel;
|
|
||||||
import org.dspace.app.rest.utils.ContextUtil;
|
import org.dspace.app.rest.utils.ContextUtil;
|
||||||
import org.dspace.app.rest.utils.Utils;
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.springframework.beans.TypeMismatchException;
|
import org.springframework.beans.TypeMismatchException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.data.repository.support.QueryMethodParameterConversionException;
|
import org.springframework.data.repository.support.QueryMethodParameterConversionException;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
@@ -72,12 +68,6 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
|
|||||||
@Inject
|
@Inject
|
||||||
private ConfigurationService configurationService;
|
private ConfigurationService configurationService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ConverterService converterService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private Utils utils;
|
|
||||||
|
|
||||||
@ExceptionHandler({AuthorizeException.class, RESTAuthorizationException.class, AccessDeniedException.class})
|
@ExceptionHandler({AuthorizeException.class, RESTAuthorizationException.class, AccessDeniedException.class})
|
||||||
protected void handleAuthorizeException(HttpServletRequest request, HttpServletResponse response, Exception ex)
|
protected void handleAuthorizeException(HttpServletRequest request, HttpServletResponse response, Exception ex)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
@@ -177,10 +167,10 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
|
|||||||
HttpStatus.BAD_REQUEST.value());
|
HttpStatus.BAD_REQUEST.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(ResourceConflictException.class)
|
@ExceptionHandler(ResourceAlreadyExistsException.class)
|
||||||
protected ResponseEntity<? extends RestModel> resourceConflictException(ResourceConflictException ex) {
|
protected void resourceConflictException(HttpServletRequest request, HttpServletResponse response,
|
||||||
RestModel resource = converterService.toRest(ex.getResource(), utils.obtainProjection());
|
ResourceAlreadyExistsException ex) throws IOException {
|
||||||
return new ResponseEntity<RestModel>(resource, HttpStatus.CONFLICT);
|
sendErrorResponse(request, response, null, ex.getMessage(), HttpStatus.UNPROCESSABLE_ENTITY.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(MissingParameterException.class)
|
@ExceptionHandler(MissingParameterException.class)
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
package org.dspace.app.rest.login.impl;
|
package org.dspace.app.rest.login.impl;
|
||||||
|
|
||||||
import static org.apache.commons.collections4.IteratorUtils.toList;
|
import static org.apache.commons.collections4.IteratorUtils.toList;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.dspace.content.authority.Choices.CF_ACCEPTED;
|
import static org.dspace.content.authority.Choices.CF_ACCEPTED;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -53,15 +54,21 @@ public class ResearcherProfileAutomaticClaim implements PostLoggedInAction {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EPersonService ePersonService;
|
private EPersonService ePersonService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The field of the eperson to search for.
|
||||||
|
*/
|
||||||
private final String ePersonField;
|
private final String ePersonField;
|
||||||
|
|
||||||
private final String profileFiled;
|
/**
|
||||||
|
* The field of the profile item to search.
|
||||||
|
*/
|
||||||
|
private final String profileField;
|
||||||
|
|
||||||
public ResearcherProfileAutomaticClaim(String ePersonField, String profileField) {
|
public ResearcherProfileAutomaticClaim(String ePersonField, String profileField) {
|
||||||
Assert.notNull(ePersonField, "An eperson field is required to perform automatic claim");
|
Assert.notNull(ePersonField, "An eperson field is required to perform automatic claim");
|
||||||
Assert.notNull(profileField, "An profile field is required to perform automatic claim");
|
Assert.notNull(profileField, "An profile field is required to perform automatic claim");
|
||||||
this.ePersonField = ePersonField;
|
this.ePersonField = ePersonField;
|
||||||
this.profileFiled = profileField;
|
this.profileField = profileField;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -72,6 +79,10 @@ public class ResearcherProfileAutomaticClaim implements PostLoggedInAction {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isBlank(researcherProfileService.getProfileType())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
claimProfile(context, currentUser);
|
claimProfile(context, currentUser);
|
||||||
} catch (SQLException | AuthorizeException e) {
|
} catch (SQLException | AuthorizeException e) {
|
||||||
@@ -89,7 +100,7 @@ public class ResearcherProfileAutomaticClaim implements PostLoggedInAction {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Item item = findClaimableItem(context, currentUser);
|
Item item = findClaimableProfile(context, currentUser);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
itemService.addMetadata(context, item, "dspace", "object", "owner",
|
itemService.addMetadata(context, item, "dspace", "object", "owner",
|
||||||
null, fullName, id.toString(), CF_ACCEPTED);
|
null, fullName, id.toString(), CF_ACCEPTED);
|
||||||
@@ -101,16 +112,16 @@ public class ResearcherProfileAutomaticClaim implements PostLoggedInAction {
|
|||||||
return researcherProfileService.findById(context, context.getCurrentUser().getID()) != null;
|
return researcherProfileService.findById(context, context.getCurrentUser().getID()) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Item findClaimableItem(Context context, EPerson currentUser)
|
private Item findClaimableProfile(Context context, EPerson currentUser) throws SQLException, AuthorizeException {
|
||||||
throws SQLException, AuthorizeException {
|
|
||||||
|
|
||||||
String value = getValueToSearchFor(context, currentUser);
|
String value = getValueToSearchFor(context, currentUser);
|
||||||
if (StringUtils.isEmpty(value)) {
|
if (StringUtils.isEmpty(value)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Item> items = toList(itemService.findArchivedByMetadataField(context, profileFiled, value)).stream()
|
List<Item> items = toList(itemService.findArchivedByMetadataField(context, profileField, value)).stream()
|
||||||
.filter(this::hasNotCrisOwner)
|
.filter(this::hasNotOwner)
|
||||||
|
.filter(researcherProfileService::hasProfileType)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
return items.size() == 1 ? items.get(0) : null;
|
return items.size() == 1 ? items.get(0) : null;
|
||||||
@@ -123,7 +134,7 @@ public class ResearcherProfileAutomaticClaim implements PostLoggedInAction {
|
|||||||
return ePersonService.getMetadataFirstValue(currentUser, new MetadataFieldName(ePersonField), Item.ANY);
|
return ePersonService.getMetadataFirstValue(currentUser, new MetadataFieldName(ePersonField), Item.ANY);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasNotCrisOwner(Item item) {
|
private boolean hasNotOwner(Item item) {
|
||||||
return CollectionUtils.isEmpty(itemService.getMetadata(item, "dspace", "object", "owner", Item.ANY));
|
return CollectionUtils.isEmpty(itemService.getMetadata(item, "dspace", "object", "owner", Item.ANY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -52,7 +52,7 @@ public class ResearcherProfileEPersonLinkRepository extends AbstractDSpaceRestRe
|
|||||||
* @param projection the projection object
|
* @param projection the projection object
|
||||||
* @return the ePerson rest representation
|
* @return the ePerson rest representation
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("hasPermission(#id, 'PROFILE', 'READ')")
|
@PreAuthorize("hasPermission(#id, 'EPERSON', 'READ')")
|
||||||
public EPersonRest getEPerson(@Nullable HttpServletRequest request, UUID id,
|
public EPersonRest getEPerson(@Nullable HttpServletRequest request, UUID id,
|
||||||
@Nullable Pageable pageable, Projection projection) {
|
@Nullable Pageable pageable, Projection projection) {
|
||||||
|
|
||||||
|
@@ -46,9 +46,7 @@ import org.springframework.stereotype.Component;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Component(ResearcherProfileRest.CATEGORY + "." + ResearcherProfileRest.NAME)
|
@Component(ResearcherProfileRest.CATEGORY + "." + ResearcherProfileRest.NAME)
|
||||||
@ConditionalOnProperty(
|
@ConditionalOnProperty(value = "researcher-profile.entity-type")
|
||||||
value = "researcher-profile.type"
|
|
||||||
)
|
|
||||||
public class ResearcherProfileRestRepository extends DSpaceRestRepository<ResearcherProfileRest, UUID> {
|
public class ResearcherProfileRestRepository extends DSpaceRestRepository<ResearcherProfileRest, UUID> {
|
||||||
|
|
||||||
public static final String NO_VISIBILITY_CHANGE_MSG = "Refused to perform the Researcher Profile patch based "
|
public static final String NO_VISIBILITY_CHANGE_MSG = "Refused to perform the Researcher Profile patch based "
|
||||||
@@ -136,7 +134,7 @@ public class ResearcherProfileRestRepository extends DSpaceRestRepository<Resear
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@PreAuthorize("hasPermission(#id, 'PROFILE', 'WRITE')")
|
@PreAuthorize("hasPermission(#id, 'PROFILE', 'DELETE')")
|
||||||
protected void delete(Context context, UUID id) {
|
protected void delete(Context context, UUID id) {
|
||||||
try {
|
try {
|
||||||
researcherProfileService.deleteById(context, id);
|
researcherProfileService.deleteById(context, id);
|
||||||
|
@@ -23,7 +23,7 @@ import org.springframework.stereotype.Component;
|
|||||||
* Implementation for ResearcherProfile visibility patches.
|
* Implementation for ResearcherProfile visibility patches.
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* <code> curl -X PATCH http://${dspace.server.url}/api/cris/profiles/<:id-eperson> -H "
|
* <code> curl -X PATCH http://${dspace.server.url}/api/eperson/profiles/<:id-eperson> -H "
|
||||||
* Content-Type: application/json" -d '[{ "op": "replace", "path": "
|
* Content-Type: application/json" -d '[{ "op": "replace", "path": "
|
||||||
* /visible", "value": true]'
|
* /visible", "value": true]'
|
||||||
* </code>
|
* </code>
|
||||||
|
@@ -98,7 +98,6 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
configurationService.setProperty("researcher-profile.collection.uuid", personCollection.getID().toString());
|
configurationService.setProperty("researcher-profile.collection.uuid", personCollection.getID().toString());
|
||||||
configurationService.setProperty("claimable.entityType", "Person");
|
|
||||||
|
|
||||||
context.setCurrentUser(user);
|
context.setCurrentUser(user);
|
||||||
|
|
||||||
@@ -257,6 +256,23 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
.andExpect(jsonPath("$.name", is(name)));
|
.andExpect(jsonPath("$.name", is(name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateAndReturnWithPublicProfile() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("researcher-profile.set-new-profile-private", false);
|
||||||
|
String id = user.getID().toString();
|
||||||
|
|
||||||
|
String authToken = getAuthToken(user.getEmail(), password);
|
||||||
|
|
||||||
|
getClient(authToken).perform(post("/api/eperson/profiles/")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isCreated())
|
||||||
|
.andExpect(jsonPath("$.id", is(id)))
|
||||||
|
.andExpect(jsonPath("$.visible", is(true)))
|
||||||
|
.andExpect(jsonPath("$.type", is("profile")))
|
||||||
|
.andExpect(jsonPath("$", matchLinks("http://localhost/api/eperson/profiles/" + id, "item", "eperson")));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that an admin can call the createAndReturn endpoint to store a new
|
* Verify that an admin can call the createAndReturn endpoint to store a new
|
||||||
* researcher profile related to another user.
|
* researcher profile related to another user.
|
||||||
@@ -345,10 +361,7 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
|
|
||||||
getClient(authToken).perform(post("/api/eperson/profiles/")
|
getClient(authToken).perform(post("/api/eperson/profiles/")
|
||||||
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
.andExpect(status().isConflict())
|
.andExpect(status().isUnprocessableEntity());
|
||||||
.andExpect(jsonPath("$.id", is(id)))
|
|
||||||
.andExpect(jsonPath("$.visible", is(false)))
|
|
||||||
.andExpect(jsonPath("$.type", is("profile")));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,6 +775,37 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutomaticProfileClaimByEmailWithRegularEntity() throws Exception {
|
||||||
|
|
||||||
|
String userToken = getAuthToken(user.getEmail(), password);
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
Item itemToBeClaimed = ItemBuilder.createItem(context, personCollection)
|
||||||
|
.withPersonEmail(user.getEmail())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
String id = user.getID().toString();
|
||||||
|
|
||||||
|
getClient(userToken).perform(get("/api/eperson/profiles/{id}", id))
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
|
||||||
|
// the automatic claim is done after the user login
|
||||||
|
String newUserToken = getAuthToken(user.getEmail(), password);
|
||||||
|
|
||||||
|
getClient(newUserToken).perform(get("/api/eperson/profiles/{id}", id))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
// the profile item should be the same
|
||||||
|
String firstItemId = itemToBeClaimed.getID().toString();
|
||||||
|
String secondItemId = getItemIdByProfileId(newUserToken, id);
|
||||||
|
assertEquals("The item should be the same", firstItemId, secondItemId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoAutomaticProfileClaimOccursIfManyClaimableItemsAreFound() throws Exception {
|
public void testNoAutomaticProfileClaimOccursIfManyClaimableItemsAreFound() throws Exception {
|
||||||
|
|
||||||
@@ -909,7 +953,7 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
getClient(authToken).perform(post("/api/eperson/profiles/")
|
getClient(authToken).perform(post("/api/eperson/profiles/")
|
||||||
.contentType(TEXT_URI_LIST)
|
.contentType(TEXT_URI_LIST)
|
||||||
.content("http://localhost:8080/server/api/core/items/" + otherPerson.getID().toString()))
|
.content("http://localhost:8080/server/api/core/items/" + otherPerson.getID().toString()))
|
||||||
.andExpect(status().isConflict());
|
.andExpect(status().isUnprocessableEntity());
|
||||||
|
|
||||||
// other person trying to claim same profile
|
// other person trying to claim same profile
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
@@ -1032,7 +1076,7 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
getClient(authToken)
|
getClient(authToken)
|
||||||
.perform(post("/api/eperson/profiles/").contentType(TEXT_URI_LIST)
|
.perform(post("/api/eperson/profiles/").contentType(TEXT_URI_LIST)
|
||||||
.content("http://localhost:8080/server/api/core/items/" + id))
|
.content("http://localhost:8080/server/api/core/items/" + id))
|
||||||
.andExpect(status().isConflict());
|
.andExpect(status().isUnprocessableEntity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getItemIdByProfileId(String token, String id) throws Exception {
|
private String getItemIdByProfileId(String token, String id) throws Exception {
|
||||||
|
@@ -24,7 +24,6 @@ import org.dspace.builder.CommunityBuilder;
|
|||||||
import org.dspace.builder.ItemBuilder;
|
import org.dspace.builder.ItemBuilder;
|
||||||
import org.dspace.content.Collection;
|
import org.dspace.content.Collection;
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.services.ConfigurationService;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -39,9 +38,6 @@ public class CanClaimItemFeatureIT extends AbstractControllerIntegrationTest {
|
|||||||
private Item collectionAProfile;
|
private Item collectionAProfile;
|
||||||
private Item collectionBProfile;
|
private Item collectionBProfile;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ConfigurationService configurationService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ItemConverter itemConverter;
|
private ItemConverter itemConverter;
|
||||||
|
|
||||||
@@ -73,8 +69,6 @@ public class CanClaimItemFeatureIT extends AbstractControllerIntegrationTest {
|
|||||||
collectionAProfile = ItemBuilder.createItem(context, personCollection).build();
|
collectionAProfile = ItemBuilder.createItem(context, personCollection).build();
|
||||||
collectionBProfile = ItemBuilder.createItem(context, claimableCollectionB).build();
|
collectionBProfile = ItemBuilder.createItem(context, claimableCollectionB).build();
|
||||||
|
|
||||||
configurationService.addPropertyValue("claimable.entityType", "Person");
|
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
canClaimProfileFeature = authorizationFeatureService.find(CanClaimItemFeature.NAME);
|
canClaimProfileFeature = authorizationFeatureService.find(CanClaimItemFeature.NAME);
|
||||||
@@ -173,22 +167,6 @@ public class CanClaimItemFeatureIT extends AbstractControllerIntegrationTest {
|
|||||||
.andExpect(jsonPath("$.page.totalElements", equalTo(0)));
|
.andExpect(jsonPath("$.page.totalElements", equalTo(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWithoutClaimableEntities() throws Exception {
|
|
||||||
|
|
||||||
configurationService.setProperty("claimable.entityType", null);
|
|
||||||
|
|
||||||
getClient(getAuthToken(context.getCurrentUser().getEmail(), password))
|
|
||||||
.perform(get("/api/authz/authorizations/search/object")
|
|
||||||
.param("uri", uri(collectionAProfile))
|
|
||||||
.param("eperson", context.getCurrentUser().getID().toString())
|
|
||||||
.param("feature", canClaimProfileFeature.getName()))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$._embedded").doesNotExist())
|
|
||||||
.andExpect(jsonPath("$.page.totalElements", equalTo(0)));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private String uri(Item item) {
|
private String uri(Item item) {
|
||||||
ItemRest itemRest = itemConverter.convert(item, Projection.DEFAULT);
|
ItemRest itemRest = itemConverter.convert(item, Projection.DEFAULT);
|
||||||
String itemRestURI = utils.linkToSingleResource(itemRest, "self").getHref();
|
String itemRestURI = utils.linkToSingleResource(itemRest, "self").getHref();
|
||||||
|
@@ -24,7 +24,6 @@ import org.dspace.builder.CommunityBuilder;
|
|||||||
import org.dspace.builder.ItemBuilder;
|
import org.dspace.builder.ItemBuilder;
|
||||||
import org.dspace.content.Collection;
|
import org.dspace.content.Collection;
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.services.ConfigurationService;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -40,9 +39,6 @@ public class ShowClaimItemFeatureIT extends AbstractControllerIntegrationTest {
|
|||||||
private Item collectionAProfile;
|
private Item collectionAProfile;
|
||||||
private Item collectionBProfile;
|
private Item collectionBProfile;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ConfigurationService configurationService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ItemConverter itemConverter;
|
private ItemConverter itemConverter;
|
||||||
|
|
||||||
@@ -74,8 +70,6 @@ public class ShowClaimItemFeatureIT extends AbstractControllerIntegrationTest {
|
|||||||
collectionAProfile = ItemBuilder.createItem(context, personCollection).build();
|
collectionAProfile = ItemBuilder.createItem(context, personCollection).build();
|
||||||
collectionBProfile = ItemBuilder.createItem(context, claimableCollectionB).build();
|
collectionBProfile = ItemBuilder.createItem(context, claimableCollectionB).build();
|
||||||
|
|
||||||
configurationService.addPropertyValue("claimable.entityType", "Person");
|
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
showClaimProfileFeature = authorizationFeatureService.find(ShowClaimItemFeature.NAME);
|
showClaimProfileFeature = authorizationFeatureService.find(ShowClaimItemFeature.NAME);
|
||||||
@@ -174,22 +168,6 @@ public class ShowClaimItemFeatureIT extends AbstractControllerIntegrationTest {
|
|||||||
.andExpect(jsonPath("$.page.totalElements", equalTo(0)));
|
.andExpect(jsonPath("$.page.totalElements", equalTo(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWithoutClaimableEntities() throws Exception {
|
|
||||||
|
|
||||||
configurationService.setProperty("claimable.entityType", null);
|
|
||||||
|
|
||||||
getClient(getAuthToken(context.getCurrentUser().getEmail(), password))
|
|
||||||
.perform(get("/api/authz/authorizations/search/object")
|
|
||||||
.param("uri", uri(collectionAProfile))
|
|
||||||
.param("eperson", context.getCurrentUser().getID().toString())
|
|
||||||
.param("feature", showClaimProfileFeature.getName()))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$._embedded").doesNotExist())
|
|
||||||
.andExpect(jsonPath("$.page.totalElements", equalTo(0)));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private String uri(Item item) {
|
private String uri(Item item) {
|
||||||
ItemRest itemRest = itemConverter.convert(item, Projection.DEFAULT);
|
ItemRest itemRest = itemConverter.convert(item, Projection.DEFAULT);
|
||||||
String itemRestURI = utils.linkToSingleResource(itemRest, "self").getHref();
|
String itemRestURI = utils.linkToSingleResource(itemRest, "self").getHref();
|
||||||
|
@@ -1379,17 +1379,6 @@ sherpa.romeo.url = https://v2.sherpa.ac.uk/cgi/retrieve
|
|||||||
# register for a new API key
|
# register for a new API key
|
||||||
sherpa.romeo.apikey =
|
sherpa.romeo.apikey =
|
||||||
|
|
||||||
##### Authority Control Settings #####
|
|
||||||
#plugin.named.org.dspace.content.authority.ChoiceAuthority = \
|
|
||||||
# org.dspace.content.authority.SampleAuthority = Sample, \
|
|
||||||
# org.dspace.content.authority.SHERPARoMEOPublisher = SRPublisher, \
|
|
||||||
# org.dspace.content.authority.SHERPARoMEOJournalTitle = SRJournalTitle, \
|
|
||||||
# org.dspace.content.authority.SolrAuthority = SolrAuthorAuthority
|
|
||||||
|
|
||||||
#Uncomment to enable ORCID authority control
|
|
||||||
#plugin.named.org.dspace.content.authority.ChoiceAuthority = \
|
|
||||||
# org.dspace.content.authority.SolrAuthority = SolrAuthorAuthority
|
|
||||||
|
|
||||||
# URL of ORCID API
|
# URL of ORCID API
|
||||||
# Defaults to using the Public API V3 (pub.orcid.org)
|
# Defaults to using the Public API V3 (pub.orcid.org)
|
||||||
orcid.api.url = https://pub.orcid.org/v3.0
|
orcid.api.url = https://pub.orcid.org/v3.0
|
||||||
@@ -1404,69 +1393,6 @@ orcid.clientsecret =
|
|||||||
#ORCID JWT Endpoint
|
#ORCID JWT Endpoint
|
||||||
orcid.oauth.url = https://orcid.org/oauth/token
|
orcid.oauth.url = https://orcid.org/oauth/token
|
||||||
|
|
||||||
## The DCInputAuthority plugin is automatically configured with every
|
|
||||||
## value-pairs element in input-forms.xml, namely:
|
|
||||||
## common_identifiers, common_types, common_iso_languages
|
|
||||||
##
|
|
||||||
## The DSpaceControlledVocabulary plugin is automatically configured
|
|
||||||
## with every *.xml file in [dspace]/config/controlled-vocabularies,
|
|
||||||
## and creates a plugin instance for each, using base filename as the name.
|
|
||||||
## eg: nsi, srsc.
|
|
||||||
## Each DSpaceControlledVocabulary plugin comes with three configuration options:
|
|
||||||
# vocabulary.plugin._plugin_.hierarchy.store = <true|false> # default: true
|
|
||||||
# vocabulary.plugin._plugin_.hierarchy.suggest = <true|false> # default: false
|
|
||||||
# vocabulary.plugin._plugin_.delimiter = "<string>" # default: "::"
|
|
||||||
##
|
|
||||||
## An example using "srsc" can be found later in this section
|
|
||||||
|
|
||||||
plugin.selfnamed.org.dspace.content.authority.ChoiceAuthority = \
|
|
||||||
org.dspace.content.authority.DCInputAuthority, \
|
|
||||||
org.dspace.content.authority.DSpaceControlledVocabulary
|
|
||||||
|
|
||||||
##
|
|
||||||
## This sets the default lowest confidence level at which a metadata value is included
|
|
||||||
## in an authority-controlled browse (and search) index. It is a symbolic
|
|
||||||
## keyword, one of the following values (listed in descending order):
|
|
||||||
## accepted
|
|
||||||
## uncertain
|
|
||||||
## ambiguous
|
|
||||||
## notfound
|
|
||||||
## failed
|
|
||||||
## rejected
|
|
||||||
## novalue
|
|
||||||
## unset
|
|
||||||
## See manual or org.dspace.content.authority.Choices source for descriptions.
|
|
||||||
authority.minconfidence = ambiguous
|
|
||||||
|
|
||||||
# Configuration settings for ORCID based authority control.
|
|
||||||
# Uncomment the lines below to enable configuration
|
|
||||||
#choices.plugin.dc.contributor.author = SolrAuthorAuthority
|
|
||||||
#choices.presentation.dc.contributor.author = authorLookup
|
|
||||||
#authority.controlled.dc.contributor.author = true
|
|
||||||
#authority.author.indexer.field.1=dc.contributor.author
|
|
||||||
|
|
||||||
##
|
|
||||||
## This sets the lowest confidence level at which a metadata value is included
|
|
||||||
## in an authority-controlled browse (and search) index. It is a symbolic
|
|
||||||
## keyword from the same set as for the default "authority.minconfidence"
|
|
||||||
#authority.minconfidence.dc.contributor.author = accepted
|
|
||||||
|
|
||||||
## demo: subject code autocomplete, using srsc as authority
|
|
||||||
## (DSpaceControlledVocabulary plugin must be enabled)
|
|
||||||
## Warning: when enabling this feature any controlled vocabulary configuration in the input-forms.xml for the metadata field will be overridden.
|
|
||||||
#vocabulary.plugin.srsc.hierarchy.store = true
|
|
||||||
#vocabulary.plugin.srsc.hierarchy.suggest = true
|
|
||||||
#vocabulary.plugin.srsc.delimiter = "::"
|
|
||||||
|
|
||||||
# publisher name lookup through SHERPA/RoMEO:
|
|
||||||
#choices.plugin.dc.publisher = SRPublisher
|
|
||||||
#choices.presentation.dc.publisher = suggest
|
|
||||||
|
|
||||||
## demo: journal title lookup, with ISSN as authority
|
|
||||||
#choices.plugin.dc.title.alternative = SRJournalTitle
|
|
||||||
#choices.presentation.dc.title.alternative = suggest
|
|
||||||
#authority.controlled.dc.title.alternative = true
|
|
||||||
|
|
||||||
##### Google Scholar Metadata Configuration #####
|
##### Google Scholar Metadata Configuration #####
|
||||||
google-metadata.config = ${dspace.dir}/config/crosswalks/google-metadata.properties
|
google-metadata.config = ${dspace.dir}/config/crosswalks/google-metadata.properties
|
||||||
google-metadata.enable = true
|
google-metadata.enable = true
|
||||||
@@ -1632,6 +1558,7 @@ include = ${module_dir}/rest.cfg
|
|||||||
include = ${module_dir}/iiif.cfg
|
include = ${module_dir}/iiif.cfg
|
||||||
include = ${module_dir}/solr-statistics.cfg
|
include = ${module_dir}/solr-statistics.cfg
|
||||||
include = ${module_dir}/solrauthority.cfg
|
include = ${module_dir}/solrauthority.cfg
|
||||||
|
include = ${module_dir}/researcher-profile.cfg
|
||||||
include = ${module_dir}/spring.cfg
|
include = ${module_dir}/spring.cfg
|
||||||
include = ${module_dir}/submission-curation.cfg
|
include = ${module_dir}/submission-curation.cfg
|
||||||
include = ${module_dir}/sword-client.cfg
|
include = ${module_dir}/sword-client.cfg
|
||||||
|
@@ -4,12 +4,83 @@
|
|||||||
# These configs are used by the authority framework #
|
# These configs are used by the authority framework #
|
||||||
#---------------------------------------------------------------#
|
#---------------------------------------------------------------#
|
||||||
|
|
||||||
|
## The DCInputAuthority plugin is automatically configured with every
|
||||||
|
## value-pairs element in input-forms.xml, namely:
|
||||||
|
## common_identifiers, common_types, common_iso_languages
|
||||||
|
##
|
||||||
|
## The DSpaceControlledVocabulary plugin is automatically configured
|
||||||
|
## with every *.xml file in [dspace]/config/controlled-vocabularies,
|
||||||
|
## and creates a plugin instance for each, using base filename as the name.
|
||||||
|
## eg: nsi, srsc.
|
||||||
|
## Each DSpaceControlledVocabulary plugin comes with three configuration options:
|
||||||
|
# vocabulary.plugin._plugin_.hierarchy.store = <true|false> # default: true
|
||||||
|
# vocabulary.plugin._plugin_.hierarchy.suggest = <true|false> # default: false
|
||||||
|
# vocabulary.plugin._plugin_.delimiter = "<string>" # default: "::"
|
||||||
|
##
|
||||||
|
## An example using "srsc" can be found later in this section
|
||||||
|
|
||||||
|
plugin.selfnamed.org.dspace.content.authority.ChoiceAuthority = \
|
||||||
|
org.dspace.content.authority.DCInputAuthority, \
|
||||||
|
org.dspace.content.authority.DSpaceControlledVocabulary
|
||||||
|
|
||||||
|
##
|
||||||
|
## This sets the default lowest confidence level at which a metadata value is included
|
||||||
|
## in an authority-controlled browse (and search) index. It is a symbolic
|
||||||
|
## keyword, one of the following values (listed in descending order):
|
||||||
|
## accepted
|
||||||
|
## uncertain
|
||||||
|
## ambiguous
|
||||||
|
## notfound
|
||||||
|
## failed
|
||||||
|
## rejected
|
||||||
|
## novalue
|
||||||
|
## unset
|
||||||
|
## See manual or org.dspace.content.authority.Choices source for descriptions.
|
||||||
|
authority.minconfidence = ambiguous
|
||||||
|
|
||||||
|
# Configuration settings for ORCID based authority control.
|
||||||
|
# Uncomment the lines below to enable configuration
|
||||||
|
#choices.plugin.dc.contributor.author = SolrAuthorAuthority
|
||||||
|
#choices.presentation.dc.contributor.author = authorLookup
|
||||||
|
#authority.controlled.dc.contributor.author = true
|
||||||
|
#authority.author.indexer.field.1=dc.contributor.author
|
||||||
|
|
||||||
|
##
|
||||||
|
## This sets the lowest confidence level at which a metadata value is included
|
||||||
|
## in an authority-controlled browse (and search) index. It is a symbolic
|
||||||
|
## keyword from the same set as for the default "authority.minconfidence"
|
||||||
|
#authority.minconfidence.dc.contributor.author = accepted
|
||||||
|
|
||||||
|
## demo: subject code autocomplete, using srsc as authority
|
||||||
|
## (DSpaceControlledVocabulary plugin must be enabled)
|
||||||
|
## Warning: when enabling this feature any controlled vocabulary configuration in the input-forms.xml for the metadata field will be overridden.
|
||||||
|
#vocabulary.plugin.srsc.hierarchy.store = true
|
||||||
|
#vocabulary.plugin.srsc.hierarchy.suggest = true
|
||||||
|
#vocabulary.plugin.srsc.delimiter = "::"
|
||||||
|
|
||||||
|
# publisher name lookup through SHERPA/RoMEO:
|
||||||
|
#choices.plugin.dc.publisher = SRPublisher
|
||||||
|
#choices.presentation.dc.publisher = suggest
|
||||||
|
|
||||||
|
## demo: journal title lookup, with ISSN as authority
|
||||||
|
#choices.plugin.dc.title.alternative = SRJournalTitle
|
||||||
|
#choices.presentation.dc.title.alternative = suggest
|
||||||
|
#authority.controlled.dc.title.alternative = true
|
||||||
|
|
||||||
##### Authority Control Settings #####
|
##### Authority Control Settings #####
|
||||||
|
#plugin.named.org.dspace.content.authority.ChoiceAuthority = \
|
||||||
|
# org.dspace.content.authority.SampleAuthority = Sample, \
|
||||||
|
# org.dspace.content.authority.SHERPARoMEOPublisher = SRPublisher, \
|
||||||
|
# org.dspace.content.authority.SHERPARoMEOJournalTitle = SRJournalTitle, \
|
||||||
|
# org.dspace.content.authority.SolrAuthority = SolrAuthorAuthority
|
||||||
|
|
||||||
|
#Uncomment to enable ORCID authority control
|
||||||
|
#plugin.named.org.dspace.content.authority.ChoiceAuthority = \
|
||||||
|
# org.dspace.content.authority.SolrAuthority = SolrAuthorAuthority
|
||||||
|
|
||||||
plugin.named.org.dspace.content.authority.ChoiceAuthority = \
|
plugin.named.org.dspace.content.authority.ChoiceAuthority = \
|
||||||
org.dspace.content.authority.EPersonAuthority = EPersonAuthority
|
org.dspace.content.authority.EPersonAuthority = EPersonAuthority
|
||||||
|
|
||||||
|
|
||||||
choices.plugin.dspace.object.owner = EPersonAuthority
|
choices.plugin.dspace.object.owner = EPersonAuthority
|
||||||
choices.presentation.dspace.object.owner = suggest
|
choices.presentation.dspace.object.owner = suggest
|
||||||
authority.controlled.dspace.object.owner = true
|
authority.controlled.dspace.object.owner = true
|
15
dspace/config/modules/researcher-profile.cfg
Normal file
15
dspace/config/modules/researcher-profile.cfg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#---------------------------------------------------------------#
|
||||||
|
#------------------- PROFILE CONFIGURATIONS --------------------#
|
||||||
|
#---------------------------------------------------------------#
|
||||||
|
|
||||||
|
#the entity type of the researcher profile
|
||||||
|
researcher-profile.entity-type = Person
|
||||||
|
|
||||||
|
# the uuid of the collection where store the researcher profiles created from scratch
|
||||||
|
researcher-profile.collection.uuid =
|
||||||
|
|
||||||
|
# if true when the profile is deleted even the related item is deleted, if false only the link between profile and item is removed
|
||||||
|
researcher-profile.hard-delete.enabled = false
|
||||||
|
|
||||||
|
#true if the new profiles should be private (without anonymous read policy), false otherwise
|
||||||
|
researcher-profile.set-new-profile-private = true
|
@@ -48,7 +48,7 @@
|
|||||||
<schema>dspace</schema>
|
<schema>dspace</schema>
|
||||||
<element>object</element>
|
<element>object</element>
|
||||||
<qualifier>owner</qualifier>
|
<qualifier>owner</qualifier>
|
||||||
<scope_note>Stores the reference to the eperson that own the item </scope_note>
|
<scope_note>Used to support researcher profiles</scope_note>
|
||||||
</dc-type>
|
</dc-type>
|
||||||
|
|
||||||
</dspace-dc-types>
|
</dspace-dc-types>
|
||||||
|
Reference in New Issue
Block a user