[CST-5306] Improvements on ResearcherProfileRestRepository

This commit is contained in:
Luca Giamminonni
2022-04-22 14:32:20 +02:00
parent 626775347b
commit ee6cf3d60c
20 changed files with 284 additions and 227 deletions

View File

@@ -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;
}
} }

View File

@@ -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)

View File

@@ -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");
}
} }

View File

@@ -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();
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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)
* *

View File

@@ -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};

View File

@@ -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)

View File

@@ -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));
} }

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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();

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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>