[CST-15074][#9849] PR review

This commit is contained in:
Vincenzo Mecca
2025-03-07 10:39:48 +01:00
parent b7f91ced1a
commit 2993425391
23 changed files with 841 additions and 123 deletions

View File

@@ -230,6 +230,7 @@ public class AccountServiceImpl implements AccountService {
registrationDataService.deleteByToken(context, token); registrationDataService.deleteByToken(context, token);
} }
@Override
public EPerson mergeRegistration(Context context, UUID personId, String token, List<String> overrides) public EPerson mergeRegistration(Context context, UUID personId, String token, List<String> overrides)
throws AuthorizeException, SQLException { throws AuthorizeException, SQLException {
@@ -301,10 +302,9 @@ public class AccountServiceImpl implements AccountService {
} }
private boolean isSameContextEPerson(Context context, EPerson eperson) { private boolean isSameContextEPerson(Context context, EPerson eperson) {
return eperson.equals(context.getCurrentUser()); return context.getCurrentUser().equals(eperson);
} }
@Override @Override
public RegistrationData renewRegistrationForEmail( public RegistrationData renewRegistrationForEmail(
Context context, RegistrationDataPatch registrationDataPatch Context context, RegistrationDataPatch registrationDataPatch
@@ -312,7 +312,7 @@ public class AccountServiceImpl implements AccountService {
try { try {
RegistrationData newRegistration = registrationDataService.clone(context, registrationDataPatch); RegistrationData newRegistration = registrationDataService.clone(context, registrationDataPatch);
registrationDataService.delete(context, registrationDataPatch.getOldRegistration()); registrationDataService.delete(context, registrationDataPatch.getOldRegistration());
fillAndSendEmail(context, newRegistration); sendRegistationLinkByEmail(context, newRegistration);
return newRegistration; return newRegistration;
} catch (SQLException | MessagingException | IOException e) { } catch (SQLException | MessagingException | IOException e) {
log.error(e); log.error(e);
@@ -353,6 +353,18 @@ public class AccountServiceImpl implements AccountService {
} }
/**
* Updates Eperson using the provided {@link RegistrationData}.<br/>
* Tries to replace {@code metadata} already set inside the {@link EPerson} with the ones
* listed inside the {@code overrides} field by taking the value from the {@link RegistrationData}. <br/>
* Updates the empty values inside the {@link EPerson} by taking them directly from the {@link RegistrationData},
* according to the method {@link AccountServiceImpl#getUpdateActions(Context, EPerson, RegistrationData)}
*
* @param context The DSpace context
* @param eperson The EPerson that should be updated
* @param registrationData The RegistrationData related to that EPerson
* @param overrides List of metadata that will be overwritten inside the EPerson
*/
protected void updateValuesFromRegistration( protected void updateValuesFromRegistration(
Context context, EPerson eperson, RegistrationData registrationData, List<String> overrides Context context, EPerson eperson, RegistrationData registrationData, List<String> overrides
) { ) {
@@ -369,6 +381,21 @@ public class AccountServiceImpl implements AccountService {
return overrides.stream().map(f -> mergeField(f, registrationData)); return overrides.stream().map(f -> mergeField(f, registrationData));
} }
/**
* This methods tries to fullfill missing values inside the {@link EPerson} by taking them directly from the
* {@link RegistrationData}. <br/>
* Returns a {@link Stream} of consumers that will be evaluated on an {@link EPerson}, this stream contains
* the following actions:
* <ul>
* <li>Copies {@code netId} and {@code email} to the {@link EPerson} <br/></li>
* <li>Copies any {@link RegistrationData#metadata} inside {@link EPerson#metadata} if isn't already set.</li>
* </ul>
*
* @param context DSpace context
* @param eperson EPerson that will be evaluated
* @param registrationData RegistrationData used as a base to copy value from.
* @return a stream of consumers to be evaluated on EPerson.
*/
protected Stream<Consumer<EPerson>> getUpdateActions( protected Stream<Consumer<EPerson>> getUpdateActions(
Context context, EPerson eperson, RegistrationData registrationData Context context, EPerson eperson, RegistrationData registrationData
) { ) {
@@ -404,6 +431,14 @@ public class AccountServiceImpl implements AccountService {
} }
} }
/**
* This method returns a Consumer that will override a given {@link MetadataValue} of the {@link EPerson} by taking
* that directly from the {@link RegistrationData}.
*
* @param field The metadatafield
* @param registrationData The RegistrationData where the metadata wil be taken
* @return a Consumer of the person that will replace that field
*/
protected Consumer<EPerson> mergeField(String field, RegistrationData registrationData) { protected Consumer<EPerson> mergeField(String field, RegistrationData registrationData) {
return person -> return person ->
allowedMergeArguments.getOrDefault( allowedMergeArguments.getOrDefault(
@@ -412,6 +447,14 @@ public class AccountServiceImpl implements AccountService {
).accept(registrationData, person); ).accept(registrationData, person);
} }
/**
* This method returns a {@link BiConsumer} that can be evaluated on any {@link RegistrationData} and
* {@link EPerson} in order to replace the value of the metadata {@code field} placed on the {@link EPerson}
* by taking the value directly from the {@link RegistrationData}.
*
* @param field The metadata that will be overwritten inside the {@link EPerson}
* @return a BiConsumer
*/
protected BiConsumer<RegistrationData, EPerson> mergeRegistrationMetadata(String field) { protected BiConsumer<RegistrationData, EPerson> mergeRegistrationMetadata(String field) {
return (registrationData, person) -> { return (registrationData, person) -> {
RegistrationDataMetadata registrationMetadata = getMetadataOrThrow(registrationData, field); RegistrationDataMetadata registrationMetadata = getMetadataOrThrow(registrationData, field);
@@ -545,6 +588,15 @@ public class AccountServiceImpl implements AccountService {
} }
} }
/**
* This method returns a link that will point to the Angular UI that will be used by the user to complete the
* registration process.
*
* @param base is the UI url of DSpace
* @param rd is the RegistrationData related to the user
* @param subPath is the specific page that will be loaded on the FE
* @return String that represents that link
*/
private static String getSpecialLink(String base, RegistrationData rd, String subPath) { private static String getSpecialLink(String base, RegistrationData rd, String subPath) {
return new StringBuffer(base) return new StringBuffer(base)
.append(base.endsWith("/") ? "" : "/") .append(base.endsWith("/") ? "" : "/")
@@ -554,7 +606,15 @@ public class AccountServiceImpl implements AccountService {
.toString(); .toString();
} }
protected void fillAndSendEmail( /**
* Fills out a given email template obtained starting from the {@link RegistrationTypeEnum}.
*
* @param context The DSpace Context
* @param rd The RegistrationData that will be used as a registration.
* @throws MessagingException
* @throws IOException
*/
protected void sendRegistationLinkByEmail(
Context context, RegistrationData rd Context context, RegistrationData rd
) throws MessagingException, IOException { ) throws MessagingException, IOException {
String base = configurationService.getProperty("dspace.ui.url"); String base = configurationService.getProperty("dspace.ui.url");
@@ -571,6 +631,15 @@ public class AccountServiceImpl implements AccountService {
log.info(LogMessage.of(() -> "Sent " + rd.getRegistrationType().getLink() + " link to " + rd.getEmail())); log.info(LogMessage.of(() -> "Sent " + rd.getRegistrationType().getLink() + " link to " + rd.getEmail()));
} }
/**
* This method fills out the given email with all the fields and sends out the email.
*
* @param email - The recipient
* @param emailFilename The name of the email
* @param specialLink - The link that will be set inside the email
* @throws IOException
* @throws MessagingException
*/
protected void fillAndSendEmail(String email, String emailFilename, String specialLink) protected void fillAndSendEmail(String email, String emailFilename, String specialLink)
throws IOException, MessagingException { throws IOException, MessagingException {
Email bean = Email.getEmail(emailFilename); Email bean = Email.getEmail(emailFilename);

View File

@@ -22,6 +22,9 @@ import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.services.factory.DSpaceServicesFactory;
/** /**
* Singleton that encapsulates the configuration of each different token {@link RegistrationTypeEnum} duration. <br/>
* Contains also utility methods to compute the expiration date of the registered token.
*
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com) * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
**/ **/
public class RegistrationDataExpirationConfiguration { public class RegistrationDataExpirationConfiguration {
@@ -61,10 +64,22 @@ public class RegistrationDataExpirationConfiguration {
return Duration.parse(MessageFormat.format(DURATION_FORMAT, typeValue)); return Duration.parse(MessageFormat.format(DURATION_FORMAT, typeValue));
} }
/**
* Retrieves the {@link Duration} configuration of a given {@link RegistrationTypeEnum}.
*
* @param type is the type of the given registration token
* @return the {@link Duration} of that specific token.
*/
public Duration getExpiration(RegistrationTypeEnum type) { public Duration getExpiration(RegistrationTypeEnum type) {
return expirationMap.get(type); return expirationMap.get(type);
} }
/**
* Retrieves the expiration date of the given {@link RegistrationTypeEnum}.
*
* @param type is the RegistrationTypeEnum of the token
* @return a Date that represents the expiration date.
*/
public Date computeExpirationDate(RegistrationTypeEnum type) { public Date computeExpirationDate(RegistrationTypeEnum type) {
if (type == null) { if (type == null) {

View File

@@ -66,7 +66,7 @@ public class RegistrationDataMetadataServiceImpl implements RegistrationDataMeta
@Override @Override
public RegistrationDataMetadata find(Context context, int id) throws SQLException { public RegistrationDataMetadata find(Context context, int id) throws SQLException {
return registrationDataMetadataDAO.findByID(context, RegistrationData.class, id); return registrationDataMetadataDAO.findByID(context, RegistrationDataMetadata.class, id);
} }
@Override @Override

View File

@@ -10,13 +10,14 @@ package org.dspace.eperson.dto;
import org.dspace.eperson.RegistrationTypeEnum; import org.dspace.eperson.RegistrationTypeEnum;
/** /**
* Class that embeds a change done for the {@link org.dspace.eperson.RegistrationData}
*
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com) * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
**/ **/
public class RegistrationDataChanges { public class RegistrationDataChanges {
private static final String EMAIL_PATTERN = @SuppressWarnings("checkstyle:LineLength")
"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)" + private static final String EMAIL_PATTERN = "^[a-zA-Z0-9.!#$%&'*+\\\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$";
"+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?";
private final String email; private final String email;
private final RegistrationTypeEnum registrationType; private final RegistrationTypeEnum registrationType;
@@ -35,14 +36,28 @@ public class RegistrationDataChanges {
this.registrationType = type; this.registrationType = type;
} }
/**
* Checks if the email is valid using the EMAIL_PATTERN.
* @return true if valid, false otherwise
*/
public boolean isValidEmail() { public boolean isValidEmail() {
return email.matches(EMAIL_PATTERN); return email.matches(EMAIL_PATTERN);
} }
/**
* Returns the email of change.
*
* @return the email of the change
*/
public String getEmail() { public String getEmail() {
return email; return email;
} }
/**
* Returns the {@link RegistrationTypeEnum} of the registration.
*
* @return the type of the change
*/
public RegistrationTypeEnum getRegistrationType() { public RegistrationTypeEnum getRegistrationType() {
return registrationType; return registrationType;
} }

View File

@@ -10,6 +10,8 @@ package org.dspace.eperson.dto;
import org.dspace.eperson.RegistrationData; import org.dspace.eperson.RegistrationData;
/** /**
* This POJO encapsulates the details of the PATCH request that updates the {@link RegistrationData}.
*
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com) * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
**/ **/
public class RegistrationDataPatch { public class RegistrationDataPatch {
@@ -22,10 +24,20 @@ public class RegistrationDataPatch {
this.changes = changes; this.changes = changes;
} }
/**
* Returns the value of the previous registration
*
* @return RegistrationData
*/
public RegistrationData getOldRegistration() { public RegistrationData getOldRegistration() {
return oldRegistration; return oldRegistration;
} }
/**
* Returns the changes related to the registration
*
* @return RegistrationDataChanges
*/
public RegistrationDataChanges getChanges() { public RegistrationDataChanges getChanges() {
return changes; return changes;
} }

View File

@@ -10,6 +10,7 @@ package org.dspace.eperson.factory;
import org.dspace.eperson.service.AccountService; import org.dspace.eperson.service.AccountService;
import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.EPersonService;
import org.dspace.eperson.service.GroupService; import org.dspace.eperson.service.GroupService;
import org.dspace.eperson.service.RegistrationDataMetadataService;
import org.dspace.eperson.service.RegistrationDataService; import org.dspace.eperson.service.RegistrationDataService;
import org.dspace.eperson.service.SubscribeService; import org.dspace.eperson.service.SubscribeService;
import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.services.factory.DSpaceServicesFactory;
@@ -28,6 +29,8 @@ public abstract class EPersonServiceFactory {
public abstract RegistrationDataService getRegistrationDataService(); public abstract RegistrationDataService getRegistrationDataService();
public abstract RegistrationDataMetadataService getRegistrationDAtaDataMetadataService();
public abstract AccountService getAccountService(); public abstract AccountService getAccountService();
public abstract SubscribeService getSubscribeService(); public abstract SubscribeService getSubscribeService();

View File

@@ -10,6 +10,7 @@ package org.dspace.eperson.factory;
import org.dspace.eperson.service.AccountService; import org.dspace.eperson.service.AccountService;
import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.EPersonService;
import org.dspace.eperson.service.GroupService; import org.dspace.eperson.service.GroupService;
import org.dspace.eperson.service.RegistrationDataMetadataService;
import org.dspace.eperson.service.RegistrationDataService; import org.dspace.eperson.service.RegistrationDataService;
import org.dspace.eperson.service.SubscribeService; import org.dspace.eperson.service.SubscribeService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -29,6 +30,8 @@ public class EPersonServiceFactoryImpl extends EPersonServiceFactory {
@Autowired(required = true) @Autowired(required = true)
private RegistrationDataService registrationDataService; private RegistrationDataService registrationDataService;
@Autowired(required = true) @Autowired(required = true)
private RegistrationDataMetadataService registrationDataMetadataService;
@Autowired(required = true)
private AccountService accountService; private AccountService accountService;
@Autowired(required = true) @Autowired(required = true)
private SubscribeService subscribeService; private SubscribeService subscribeService;
@@ -58,4 +61,8 @@ public class EPersonServiceFactoryImpl extends EPersonServiceFactory {
return subscribeService; return subscribeService;
} }
@Override
public RegistrationDataMetadataService getRegistrationDAtaDataMetadataService() {
return registrationDataMetadataService;
}
} }

View File

@@ -34,34 +34,78 @@ import org.dspace.eperson.dto.RegistrationDataPatch;
* @version $Revision$ * @version $Revision$
*/ */
public interface AccountService { public interface AccountService {
public void sendRegistrationInfo(Context context, String email) public void sendRegistrationInfo(Context context, String email)
throws SQLException, IOException, MessagingException, AuthorizeException; throws SQLException, IOException, MessagingException, AuthorizeException;
public void sendForgotPasswordInfo(Context context, String email) public void sendForgotPasswordInfo(Context context, String email)
throws SQLException, IOException, MessagingException, AuthorizeException; throws SQLException, IOException, MessagingException, AuthorizeException;
boolean existsAccountFor(Context context, String token) throws SQLException, AuthorizeException; /**
* Checks if exists an account related to the token provided
*
* @param context DSpace context
* @param token Account token
* @return true if exists, false otherwise
* @throws SQLException
* @throws AuthorizeException
*/
boolean existsAccountFor(Context context, String token)
throws SQLException, AuthorizeException;
boolean existsAccountWithEmail(Context context, String email) throws SQLException; /**
* Checks if exists an account related to the email provided
*
* @param context DSpace context
* @param email String email to search for
* @return true if exists, false otherwise
* @throws SQLException
*/
boolean existsAccountWithEmail(Context context, String email)
throws SQLException;
public EPerson getEPerson(Context context, String token) public EPerson getEPerson(Context context, String token)
throws SQLException, AuthorizeException; throws SQLException, AuthorizeException;
public String getEmail(Context context, String token) throws SQLException;
public String getEmail(Context context, String token) public void deleteToken(Context context, String token) throws SQLException;
throws SQLException;
public void deleteToken(Context context, String token) /**
throws SQLException; * Merge registration data with an existing EPerson or create a new one.
*
EPerson mergeRegistration(Context context, UUID userId, String token, List<String> overrides) * @param context DSpace context
throws AuthorizeException, SQLException; * @param userId The ID of the EPerson to merge with or create
* @param token The token to use for registration data
* @param overrides List of fields to override in the EPerson
* @return The merged or created EPerson
* @throws AuthorizeException If the user is not authorized to perform the action
* @throws SQLException If a database error occurs
*/
EPerson mergeRegistration(
Context context,
UUID userId,
String token,
List<String> overrides
) throws AuthorizeException, SQLException;
/**
*
*
* @param context
* @param registrationDataPatch
* @return
* @throws AuthorizeException
*/
RegistrationData renewRegistrationForEmail( RegistrationData renewRegistrationForEmail(
Context context, RegistrationDataPatch registrationDataPatch Context context,
RegistrationDataPatch registrationDataPatch
) throws AuthorizeException; ) throws AuthorizeException;
/**
* Checks if the {@link RegistrationData#token} is valid.
*
* @param registrationData that will be checked
* @return true if valid, false otherwise
*/
boolean isTokenValidForCreation(RegistrationData registrationData); boolean isTokenValidForCreation(RegistrationData registrationData);
} }

View File

@@ -16,17 +16,50 @@ import org.dspace.eperson.RegistrationDataMetadata;
import org.dspace.service.DSpaceCRUDService; import org.dspace.service.DSpaceCRUDService;
/** /**
* This class contains business-logic to handle {@link RegistrationDataMetadata}.
*
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com) * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
**/ **/
public interface RegistrationDataMetadataService extends DSpaceCRUDService<RegistrationDataMetadata> { public interface RegistrationDataMetadataService extends DSpaceCRUDService<RegistrationDataMetadata> {
/**
* Creates a new {@link RegistrationDataMetadata} that will be stored starting from the parameters of the method.
*
* @param context - the DSpace Context
* @param registrationData - the Registration data that will contain the metadata
* @param schema - the schema of the metadata field
* @param element - the element of the metadata field
* @param qualifier - the qualifier of the metadata field
* @param value - the value of that metadata
* @return the newly created RegistrationDataMetadata
* @throws SQLException
*/
RegistrationDataMetadata create(Context context, RegistrationData registrationData, String schema, RegistrationDataMetadata create(Context context, RegistrationData registrationData, String schema,
String element, String qualifier, String value) throws SQLException; String element, String qualifier, String value) throws SQLException;
/**
* Creates a new {@link RegistrationDataMetadata}
*
* @param context - the DSpace Context
* @param registrationData - the RegistrationData that will contain that metadata
* @param metadataField - the metadataField
* @return the newly created RegistrationDataMetadata
* @throws SQLException
*/
RegistrationDataMetadata create( RegistrationDataMetadata create(
Context context, RegistrationData registrationData, MetadataField metadataField Context context, RegistrationData registrationData, MetadataField metadataField
) throws SQLException; ) throws SQLException;
/**
* Creates a new {@link RegistrationDataMetadata}
*
* @param context - the DSpace Context
* @param registrationData - the RegistrationData that will contain that metadata
* @param metadataField - the metadataField that will be stored
* @param value - the value that will be placed inside the RegistrationDataMetadata
* @return the newly created {@link RegistrationDataMetadata}
* @throws SQLException
*/
RegistrationDataMetadata create( RegistrationDataMetadata create(
Context context, RegistrationData registrationData, MetadataField metadataField, String value Context context, RegistrationData registrationData, MetadataField metadataField, String value
) throws SQLException; ) throws SQLException;

View File

@@ -12,11 +12,11 @@
DO $$ DO $$
BEGIN BEGIN
EXECUTE 'ALTER TABLE registrationdata DROP CONSTRAINT ' || EXECUTE 'ALTER TABLE registrationdata DROP CONSTRAINT IF EXISTS ' ||
QUOTE_IDENT(( QUOTE_IDENT((
SELECT CONSTRAINT_NAME SELECT CONSTRAINT_NAME
FROM information_schema.key_column_usage FROM information_schema.key_column_usage
WHERE TABLE_SCHEMA = 'public' AND TABLE_NAME = 'registrationdata' AND COLUMN_NAME = 'email' WHERE TABLE_NAME = 'registrationdata' AND COLUMN_NAME = 'email'
)); ));
end end
$$; $$;

View File

@@ -0,0 +1,256 @@
package org.dspace.eperson;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertThrows;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import org.dspace.AbstractIntegrationTestWithDatabase;
import org.dspace.authorize.AuthorizeException;
import org.dspace.builder.EPersonBuilder;
import org.dspace.builder.MetadataFieldBuilder;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.AccountService;
import org.dspace.eperson.service.EPersonService;
import org.dspace.eperson.service.RegistrationDataService;
import org.junit.Before;
import org.junit.Test;
public class AccountServiceImplIT extends AbstractIntegrationTestWithDatabase {
public static final String ORCID_NETID = "vins01";
public static final String ORCID_EMAIL = "vins-01@fake.mail";
public static final String CUSTOM_METADATA_VALUE = "vins01-customID";
AccountService accountService =
EPersonServiceFactory.getInstance().getAccountService();
EPersonService ePersonService =
EPersonServiceFactory.getInstance().getEPersonService();
RegistrationDataService registrationDataService =
EPersonServiceFactory.getInstance().getRegistrationDataService();
;
EPerson tokenPerson;
RegistrationData orcidToken;
MetadataField metadataField;
@Before
public void setUp() throws Exception {
super.setUp();
context.turnOffAuthorisationSystem();
tokenPerson =
EPersonBuilder.createEPerson(context)
.withNameInMetadata("Vincenzo", "Mecca")
.withEmail(null)
.withNetId(null)
.withCanLogin(true)
.build();
metadataField =
MetadataFieldBuilder.createMetadataField(context, "identifier", "custom", null)
.build();
orcidToken =
registrationDataService.create(context, ORCID_NETID, RegistrationTypeEnum.ORCID);
orcidToken.setEmail(ORCID_EMAIL);
registrationDataService.addMetadata(context, orcidToken, metadataField, CUSTOM_METADATA_VALUE);
registrationDataService.update(context, orcidToken);
context.restoreAuthSystemState();
}
@Test
public void testMergedORCIDRegistration() throws SQLException, AuthorizeException {
// set current logged-in eperson
context.setCurrentUser(tokenPerson);
// try to update account details with the ORCID token
EPerson updatedEperson =
accountService.mergeRegistration(
context, tokenPerson.getID(), orcidToken.getToken(),
List.of()
);
// updates value with the one inside the ORCID token
assertThat(updatedEperson, notNullValue());
assertThat(updatedEperson.getEmail(), is(ORCID_EMAIL));
assertThat(updatedEperson.getNetid(), is(ORCID_NETID));
String customMetadataFound =
ePersonService.getMetadataFirstValue(
updatedEperson, metadataField.getMetadataSchema().getName(), metadataField.getElement(),
metadataField.getQualifier(), Item.ANY
);
// updates the metadata with the one set in the ORCID token
assertThat(customMetadataFound, is(CUSTOM_METADATA_VALUE));
// deletes the token
assertThat(registrationDataService.findByToken(context, orcidToken.getToken()), nullValue());
}
@Test
public void testMergedORCIDRegistrationWithOverwrittenMetadata() throws SQLException, AuthorizeException {
// set current logged-in eperson
context.setCurrentUser(tokenPerson);
registrationDataService.addMetadata(
context, orcidToken, "eperson", "firstname", null, "Vins"
);
registrationDataService.addMetadata(
context, orcidToken, "eperson", "lastname", null, "4Science"
);
registrationDataService.update(context, orcidToken);
// try to update account details with the ORCID token
EPerson updatedEperson =
accountService.mergeRegistration(context, tokenPerson.getID(), orcidToken.getToken(),
List.of("eperson.firstname", "eperson.lastname"));
// updates value with the one inside the ORCID token
assertThat(updatedEperson, notNullValue());
assertThat(updatedEperson.getEmail(), is(ORCID_EMAIL));
assertThat(updatedEperson.getNetid(), is(ORCID_NETID));
// overwrites values with the one from the token
assertThat(updatedEperson.getFirstName(), is("Vins"));
assertThat(updatedEperson.getLastName(), is("4Science"));
String customMetadataFound =
ePersonService.getMetadataFirstValue(
updatedEperson, metadataField.getMetadataSchema().getName(), metadataField.getElement(),
metadataField.getQualifier(), Item.ANY
);
// updates the metadata with the one set in the ORCID token
assertThat(customMetadataFound, is(CUSTOM_METADATA_VALUE));
// deletes the token
assertThat(registrationDataService.findByToken(context, orcidToken.getToken()), nullValue());
}
@Test
public void testCannotMergedORCIDRegistrationWithDifferentLoggedEperson() {
// set current logged-in admin
context.setCurrentUser(admin);
// try to update eperson details with the ORCID token while logged in as admin
assertThrows(
AuthorizeException.class,
() -> accountService.mergeRegistration(context, tokenPerson.getID(), orcidToken.getToken(), List.of())
);
}
@Test
public void testCreateUserWithRegistration() throws SQLException, AuthorizeException, IOException {
// set current logged-in eperson
context.setCurrentUser(null);
context.turnOffAuthorisationSystem();
// create an orcid validation token
RegistrationData orcidRegistration =
registrationDataService.create(context, ORCID_NETID, RegistrationTypeEnum.VALIDATION_ORCID);
registrationDataService.addMetadata(
context, orcidRegistration, "eperson", "firstname", null, "Vincenzo"
);
registrationDataService.addMetadata(
context, orcidRegistration, "eperson", "lastname", null, "Mecca"
);
orcidRegistration.setEmail(ORCID_EMAIL);
registrationDataService.update(context, orcidRegistration);
context.commit();
context.restoreAuthSystemState();
EPerson createdEPerson = null;
try {
// try to create a new account during orcid registration
createdEPerson =
accountService.mergeRegistration(context, null, orcidRegistration.getToken(), List.of());
// updates value with the one inside the validation token
assertThat(createdEPerson, notNullValue());
assertThat(createdEPerson.getFirstName(), is("Vincenzo"));
assertThat(createdEPerson.getLastName(), is("Mecca"));
assertThat(createdEPerson.getEmail(), is(ORCID_EMAIL));
assertThat(createdEPerson.getNetid(), is(ORCID_NETID));
// deletes the token
assertThat(registrationDataService.findByToken(context, orcidRegistration.getToken()), nullValue());
} finally {
context.turnOffAuthorisationSystem();
ePersonService.delete(context, context.reloadEntity(createdEPerson));
RegistrationData found = context.reloadEntity(orcidRegistration);
if (found != null) {
registrationDataService.delete(context, found);
}
context.restoreAuthSystemState();
}
}
@Test
public void testInvalidMergeWithoutValidToken() throws SQLException, AuthorizeException {
// create a register token
RegistrationData anyToken =
registrationDataService.create(context, ORCID_NETID, RegistrationTypeEnum.REGISTER);
try {
assertThrows(
AuthorizeException.class,
() -> accountService.mergeRegistration(context, null, anyToken.getToken(), List.of())
);
// sets as forgot token
anyToken.setRegistrationType(RegistrationTypeEnum.FORGOT);
registrationDataService.update(context, anyToken);
assertThrows(
AuthorizeException.class,
() -> accountService.mergeRegistration(context, null, anyToken.getToken(), List.of())
);
// sets as change_password token
anyToken.setRegistrationType(RegistrationTypeEnum.CHANGE_PASSWORD);
registrationDataService.update(context, anyToken);
assertThrows(
AuthorizeException.class,
() -> accountService.mergeRegistration(context, null, anyToken.getToken(), List.of())
);
// sets as invitation token
anyToken.setRegistrationType(RegistrationTypeEnum.INVITATION);
registrationDataService.update(context, anyToken);
assertThrows(
AuthorizeException.class,
() -> accountService.mergeRegistration(context, null, anyToken.getToken(), List.of())
);
} finally {
registrationDataService.delete(context, context.reloadEntity(anyToken));
}
}
}

View File

@@ -0,0 +1,167 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.eperson;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import org.dspace.AbstractIntegrationTestWithDatabase;
import org.dspace.builder.MetadataFieldBuilder;
import org.dspace.content.MetadataField;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.RegistrationDataMetadataService;
import org.dspace.eperson.service.RegistrationDataService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
*/
public class RegistrationDataMetadataServiceImplIT extends AbstractIntegrationTestWithDatabase {
RegistrationDataMetadataService registrationDataMetadataService =
EPersonServiceFactory.getInstance().getRegistrationDAtaDataMetadataService();
RegistrationDataService registrationDataService =
EPersonServiceFactory.getInstance().getRegistrationDataService();
MetadataField metadataField;
RegistrationData registrationData;
RegistrationDataMetadata metadata;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
context.turnOffAuthorisationSystem();
this.registrationData =
this.registrationDataService.create(context);
this.metadataField =
MetadataFieldBuilder.createMetadataField(context, "dc", "identifier", "custom")
.build();
context.restoreAuthSystemState();
}
@After
@Override
public void destroy() throws Exception {
this.registrationDataService.delete(context, registrationData);
super.destroy();
}
@Test
public void testEmptyMetadataCreation() throws Exception {
try {
metadata = registrationDataMetadataService.create(context, registrationData, metadataField);
assertThat(metadata, notNullValue());
assertThat(metadata.getValue(), nullValue());
assertThat(metadata.getRegistrationData().getID(), is(registrationData.getID()));
assertThat(metadata.getMetadataField(), is(metadataField));
} finally {
registrationDataMetadataService.delete(context, metadata);
}
}
@Test
public void testValidMetadataCreation() throws Exception {
try {
metadata =
registrationDataMetadataService.create(context, registrationData, metadataField, "my-identifier");
assertThat(metadata, notNullValue());
assertThat(metadata.getValue(), is("my-identifier"));
assertThat(metadata.getRegistrationData().getID(), is(registrationData.getID()));
assertThat(metadata.getMetadataField(), is(metadataField));
} finally {
registrationDataMetadataService.delete(context, metadata);
}
}
@Test
public void testExistingMetadataFieldMetadataCreation() throws Exception {
try {
metadata =
registrationDataMetadataService.create(
context, registrationData, "dc", "identifier", "other", "my-identifier"
);
assertThat(metadata, notNullValue());
assertThat(metadata.getValue(), is("my-identifier"));
assertThat(metadata.getRegistrationData().getID(), is(registrationData.getID()));
} finally {
registrationDataMetadataService.delete(context, metadata);
}
}
@Test
public void testFindMetadata() throws Exception {
try {
metadata = registrationDataMetadataService.create(context, registrationData, metadataField);
RegistrationDataMetadata found =
registrationDataMetadataService.find(context, metadata.getID());
assertThat(found.getID(), is(metadata.getID()));
} finally {
registrationDataMetadataService.delete(context, metadata);
}
}
@Test
public void testUpdateMetadata() throws Exception {
try {
metadata = registrationDataMetadataService.create(context, registrationData, metadataField);
metadata.setValue("custom-value");
registrationDataMetadataService.update(context, metadata);
RegistrationDataMetadata found =
registrationDataMetadataService.find(context, metadata.getID());
assertThat(found.getID(), is(metadata.getID()));
assertThat(found.getValue(), is("custom-value"));
} finally {
registrationDataMetadataService.delete(context, metadata);
}
}
@Test
public void testDeleteMetadata() throws Exception {
try {
metadata = registrationDataMetadataService.create(context, registrationData, metadataField);
RegistrationDataMetadata found =
registrationDataMetadataService.find(context, metadata.getID());
assertThat(found, notNullValue());
registrationDataMetadataService.delete(context, metadata);
found = registrationDataMetadataService.find(context, metadata.getID());
assertThat(found, nullValue());
} finally {
registrationDataMetadataService.delete(context, metadata);
}
}
}

View File

@@ -31,6 +31,9 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
/** /**
* This controller is responsible to handle {@link org.dspace.eperson.RegistrationData}
* of a given {@link org.dspace.eperson.EPerson}
*
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com) * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
**/ **/
@RestController @RestController

View File

@@ -29,6 +29,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* Converts a given {@link RegistrationRest} DTO into a {@link RegistrationData} entity.
*
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com) * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
**/ **/
@Component @Component

View File

@@ -10,6 +10,9 @@ package org.dspace.app.rest.model;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
/** /**
* This POJO represents a {@link MetadataValueRest} that will be placed inside a given
* {@link org.dspace.eperson.RegistrationData} that is coming directly from the REST controller.
*
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com) * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
**/ **/
public class RegistrationMetadataRest extends MetadataValueRest { public class RegistrationMetadataRest extends MetadataValueRest {

View File

@@ -19,6 +19,7 @@ import org.apache.commons.lang3.StringUtils;
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.rest.DiscoverableEndpointsService; import org.dspace.app.rest.DiscoverableEndpointsService;
import org.dspace.app.rest.EPersonRegistrationRestController;
import org.dspace.app.rest.Parameter; import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod; import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.exception.DSpaceBadRequestException; import org.dspace.app.rest.exception.DSpaceBadRequestException;
@@ -382,6 +383,17 @@ public class EPersonRestRepository extends DSpaceObjectRestRepository<EPerson, E
return EPersonRest.class; return EPersonRest.class;
} }
/**
* This method tries to merge the details coming from the {@link EPersonRegistrationRestController} of a given
* {@code uuid} eperson. <br/>
*
* @param context - The Dspace Context
* @param uuid - The uuid of the eperson
* @param token - A valid registration token
* @param override - An optional list of metadata fields that will be overwritten
* @return a EPersonRest entity updated with the registration data.
* @throws AuthorizeException
*/
public EPersonRest mergeFromRegistrationData( public EPersonRest mergeFromRegistrationData(
Context context, UUID uuid, String token, List<String> override Context context, UUID uuid, String token, List<String> override
) throws AuthorizeException { ) throws AuthorizeException {

View File

@@ -28,6 +28,7 @@ import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.RegistrationRest; import org.dspace.app.rest.model.RegistrationRest;
import org.dspace.app.rest.model.patch.Patch; import org.dspace.app.rest.model.patch.Patch;
import org.dspace.app.rest.repository.patch.ResourcePatch; import org.dspace.app.rest.repository.patch.ResourcePatch;
import org.dspace.app.rest.repository.patch.operation.RegistrationEmailPatchOperation;
import org.dspace.app.rest.utils.Utils; import org.dspace.app.rest.utils.Utils;
import org.dspace.app.util.AuthorizeUtil; import org.dspace.app.util.AuthorizeUtil;
import org.dspace.authenticate.service.AuthenticationService; import org.dspace.authenticate.service.AuthenticationService;
@@ -211,6 +212,25 @@ public class RegistrationRestRepository extends DSpaceRestRepository<Registratio
return converter.toRest(registrationData, utils.obtainProjection()); return converter.toRest(registrationData, utils.obtainProjection());
} }
private void validateToken(Context context, String token) {
try {
RegistrationData registrationData =
registrationDataService.findByToken(context, token);
if (registrationData == null || !registrationDataService.isValid(registrationData)) {
throw new AccessDeniedException("The token is invalid");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* This method can be used to update a {@link RegistrationData} with a given {@code id} that has a valid
* {@code token} with the actions described in the {@link Patch} object.
* This method is used to patch the email value, and will generate a completely new {@code token} that will be
* sent with an email {@link RegistrationEmailPatchOperation}.
*
*/
@Override @Override
public RegistrationRest patch( public RegistrationRest patch(
HttpServletRequest request, String apiCategory, String model, Integer id, Patch patch HttpServletRequest request, String apiCategory, String model, Integer id, Patch patch
@@ -238,18 +258,6 @@ public class RegistrationRestRepository extends DSpaceRestRepository<Registratio
return null; return null;
} }
private void validateToken(Context context, String token) {
try {
RegistrationData registrationData =
registrationDataService.findByToken(context, token);
if (registrationData == null || !registrationDataService.isValid(registrationData)) {
throw new AccessDeniedException("The token is invalid");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void setCaptchaService(CaptchaService captchaService) { public void setCaptchaService(CaptchaService captchaService) {
this.captchaService = captchaService; this.captchaService = captchaService;
} }

View File

@@ -28,6 +28,7 @@ import org.dspace.eperson.dto.RegistrationDataPatch;
import org.dspace.eperson.service.AccountService; import org.dspace.eperson.service.AccountService;
import org.dspace.eperson.service.RegistrationDataService; import org.dspace.eperson.service.RegistrationDataService;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@@ -98,7 +99,7 @@ public class EPersonRegistrationRestControllerIT extends AbstractControllerInteg
customPassword = "vins-01"; customPassword = "vins-01";
customEPerson = customEPerson =
EPersonBuilder.createEPerson(context) EPersonBuilder.createEPerson(context)
.withEmail("vincenzo.mecca@4science.com") .withEmail("vins-01@fake.mail")
.withNameInMetadata("Vins", "4Science") .withNameInMetadata("Vins", "4Science")
.withPassword(customPassword) .withPassword(customPassword)
.withCanLogin(true) .withCanLogin(true)
@@ -107,6 +108,15 @@ public class EPersonRegistrationRestControllerIT extends AbstractControllerInteg
context.restoreAuthSystemState(); context.restoreAuthSystemState();
} }
@After
public void destroy() throws Exception {
RegistrationData found = context.reloadEntity(orcidRegistration);
if (found != null) {
this.registrationDataService.delete(context, found);
}
super.destroy();
}
@Test @Test
public void givenOrcidToken_whenPostForMerge_thenUnauthorized() throws Exception { public void givenOrcidToken_whenPostForMerge_thenUnauthorized() throws Exception {
@@ -159,12 +169,19 @@ public class EPersonRegistrationRestControllerIT extends AbstractControllerInteg
registrationDataService.create(context, "0000-0000-0000-0000", RegistrationTypeEnum.VALIDATION_ORCID); registrationDataService.create(context, "0000-0000-0000-0000", RegistrationTypeEnum.VALIDATION_ORCID);
context.restoreAuthSystemState(); context.restoreAuthSystemState();
String tokenAdmin = getAuthToken(admin.getEmail(), password); try {
String tokenAdmin = getAuthToken(admin.getEmail(), password);
getClient(tokenAdmin).perform( getClient(tokenAdmin).perform(
post("/api/eperson/epersons/" + customEPerson.getID()) post("/api/eperson/epersons/" + customEPerson.getID())
.param("token", validationRegistration.getToken()) .param("token", validationRegistration.getToken())
).andExpect(status().isForbidden()); ).andExpect(status().isForbidden());
} finally {
RegistrationData found = context.reloadEntity(validationRegistration);
if (found != null) {
this.registrationDataService.delete(context, found);
}
}
} }
@@ -178,19 +195,27 @@ public class EPersonRegistrationRestControllerIT extends AbstractControllerInteg
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
RegistrationDataChanges changes = RegistrationDataChanges changes =
new RegistrationDataChanges("vincenzo.mecca@4science.com", RegistrationTypeEnum.VALIDATION_ORCID); new RegistrationDataChanges("vins-01@fake.mail", RegistrationTypeEnum.VALIDATION_ORCID);
RegistrationData validationRegistration = RegistrationData validationRegistration =
this.accountService.renewRegistrationForEmail( this.accountService.renewRegistrationForEmail(
context, new RegistrationDataPatch(orcidRegistration, changes) context, new RegistrationDataPatch(orcidRegistration, changes)
); );
context.restoreAuthSystemState(); context.restoreAuthSystemState();
String customToken = getAuthToken(customEPerson.getEmail(), customPassword); try {
String customToken = getAuthToken(customEPerson.getEmail(), customPassword);
getClient(customToken).perform( getClient(customToken).perform(
post("/api/eperson/epersons/" + customEPerson.getID()) post("/api/eperson/epersons/" + customEPerson.getID())
.param("token", validationRegistration.getToken()) .param("token", validationRegistration.getToken())
).andExpect(status().isCreated()); ).andExpect(status().isCreated());
} finally {
RegistrationData found = context.reloadEntity(validationRegistration);
if (found != null) {
this.registrationDataService.delete(context, found);
}
}
} }
@@ -204,20 +229,29 @@ public class EPersonRegistrationRestControllerIT extends AbstractControllerInteg
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
RegistrationDataChanges changes = RegistrationDataChanges changes =
new RegistrationDataChanges("vincenzo.mecca@4science.com", RegistrationTypeEnum.VALIDATION_ORCID); new RegistrationDataChanges("vins-01@fake.mail", RegistrationTypeEnum.VALIDATION_ORCID);
RegistrationData validationRegistration = RegistrationData validationRegistration =
this.accountService.renewRegistrationForEmail( this.accountService.renewRegistrationForEmail(
context, new RegistrationDataPatch(orcidRegistration, changes) context, new RegistrationDataPatch(orcidRegistration, changes)
); );
context.restoreAuthSystemState(); context.restoreAuthSystemState();
String customToken = getAuthToken(customEPerson.getEmail(), customPassword); try {
getClient(customToken).perform( String customToken = getAuthToken(customEPerson.getEmail(), customPassword);
post("/api/eperson/epersons/" + customEPerson.getID())
.param("token", validationRegistration.getToken()) getClient(customToken).perform(
.param("override", "eperson.firstname,eperson.lastname") post("/api/eperson/epersons/" + customEPerson.getID())
).andExpect(status().isCreated()); .param("token", validationRegistration.getToken())
.param("override", "eperson.firstname,eperson.lastname")
).andExpect(status().isCreated());
} finally {
RegistrationData found = context.reloadEntity(validationRegistration);
if (found != null) {
this.registrationDataService.delete(context, found);
}
}
} }
@@ -231,31 +265,39 @@ public class EPersonRegistrationRestControllerIT extends AbstractControllerInteg
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
RegistrationDataChanges changes = RegistrationDataChanges changes =
new RegistrationDataChanges("vincenzo.mecca@4science.com", RegistrationTypeEnum.VALIDATION_ORCID); new RegistrationDataChanges("vins-01@fake.mail", RegistrationTypeEnum.VALIDATION_ORCID);
RegistrationData validationRegistration = RegistrationData validationRegistration =
this.accountService.renewRegistrationForEmail( this.accountService.renewRegistrationForEmail(
context, new RegistrationDataPatch(orcidRegistration, changes) context, new RegistrationDataPatch(orcidRegistration, changes)
); );
context.restoreAuthSystemState(); context.restoreAuthSystemState();
String customToken = getAuthToken(customEPerson.getEmail(), customPassword); try {
String customToken = getAuthToken(customEPerson.getEmail(), customPassword);
getClient(customToken).perform(
post("/api/eperson/epersons/" + customEPerson.getID())
.param("token", validationRegistration.getToken())
).andExpect(status().isCreated())
.andExpect(
jsonPath("$.netid", equalTo("0000-0000-0000-0000"))
)
.andExpect(
jsonPath("$.metadata",
Matchers.allOf(
MetadataMatcher.matchMetadata("eperson.firstname", "Vins"),
MetadataMatcher.matchMetadata("eperson.lastname", "4Science"),
MetadataMatcher.matchMetadata("eperson.orcid", "0000-0000-0000-0000")
)
)
);
} finally {
RegistrationData found = context.reloadEntity(validationRegistration);
if (found != null) {
this.registrationDataService.delete(context, found);
}
}
getClient(customToken).perform(
post("/api/eperson/epersons/" + customEPerson.getID())
.param("token", validationRegistration.getToken())
).andExpect(status().isCreated())
.andExpect(
jsonPath("$.netid", equalTo("0000-0000-0000-0000"))
)
.andExpect(
jsonPath("$.metadata",
Matchers.allOf(
MetadataMatcher.matchMetadata("eperson.firstname", "Vins"),
MetadataMatcher.matchMetadata("eperson.lastname", "4Science"),
MetadataMatcher.matchMetadata("eperson.orcid", "0000-0000-0000-0000")
)
)
);
} }
@@ -269,32 +311,41 @@ public class EPersonRegistrationRestControllerIT extends AbstractControllerInteg
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
RegistrationDataChanges changes = RegistrationDataChanges changes =
new RegistrationDataChanges("vincenzo.mecca@4science.com", RegistrationTypeEnum.VALIDATION_ORCID); new RegistrationDataChanges("vins-01@fake.mail", RegistrationTypeEnum.VALIDATION_ORCID);
RegistrationData validationRegistration = RegistrationData validationRegistration =
this.accountService.renewRegistrationForEmail( this.accountService.renewRegistrationForEmail(
context, new RegistrationDataPatch(orcidRegistration, changes) context, new RegistrationDataPatch(orcidRegistration, changes)
); );
context.restoreAuthSystemState(); context.restoreAuthSystemState();
String customToken = getAuthToken(customEPerson.getEmail(), customPassword); try {
String customToken = getAuthToken(customEPerson.getEmail(), customPassword);
getClient(customToken).perform( getClient(customToken).perform(
post("/api/eperson/epersons/" + customEPerson.getID()) post("/api/eperson/epersons/" + customEPerson.getID())
.param("token", validationRegistration.getToken()) .param("token", validationRegistration.getToken())
.param("override", "eperson.firstname,eperson.lastname") .param("override", "eperson.firstname,eperson.lastname")
).andExpect(status().isCreated()) )
.andExpect( .andExpect(status().isCreated())
jsonPath("$.netid", equalTo("0000-0000-0000-0000")) .andExpect(
) jsonPath("$.netid", equalTo("0000-0000-0000-0000"))
.andExpect( )
jsonPath("$.metadata", .andExpect(
Matchers.allOf( jsonPath("$.metadata",
MetadataMatcher.matchMetadata("eperson.firstname", "Vincenzo"), Matchers.allOf(
MetadataMatcher.matchMetadata("eperson.lastname", "Mecca"), MetadataMatcher.matchMetadata("eperson.firstname", "Vincenzo"),
MetadataMatcher.matchMetadata("eperson.orcid", "0000-0000-0000-0000") MetadataMatcher.matchMetadata("eperson.lastname", "Mecca"),
) MetadataMatcher.matchMetadata("eperson.orcid", "0000-0000-0000-0000")
) )
); )
);
} finally {
RegistrationData found = context.reloadEntity(validationRegistration);
if (found != null) {
this.registrationDataService.delete(context, found);
}
}
} }
@@ -308,35 +359,45 @@ public class EPersonRegistrationRestControllerIT extends AbstractControllerInteg
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
RegistrationDataChanges changes = RegistrationDataChanges changes =
new RegistrationDataChanges("vincenzo.mecca@4science.com", RegistrationTypeEnum.VALIDATION_ORCID); new RegistrationDataChanges("vins-01@fake.mail", RegistrationTypeEnum.VALIDATION_ORCID);
RegistrationData validationRegistration = RegistrationData validationRegistration =
this.accountService.renewRegistrationForEmail( this.accountService.renewRegistrationForEmail(
context, new RegistrationDataPatch(orcidRegistration, changes) context, new RegistrationDataPatch(orcidRegistration, changes)
); );
context.restoreAuthSystemState();
String customToken = getAuthToken(customEPerson.getEmail(), customPassword); try {
getClient(customToken).perform( context.restoreAuthSystemState();
post("/api/eperson/epersons/" + customEPerson.getID())
.param("token", validationRegistration.getToken())
.param("override", "eperson.phone")
).andExpect(status().isBadRequest());
context.turnOffAuthorisationSystem(); String customToken = getAuthToken(customEPerson.getEmail(), customPassword);
MetadataField phoneMf =
metadataFieldService.findByElement(context, "eperson", "phone", null);
registrationDataService.addMetadata( getClient(customToken).perform(
context, validationRegistration, phoneMf, "1234567890" post("/api/eperson/epersons/" + customEPerson.getID())
); .param("token", validationRegistration.getToken())
context.restoreAuthSystemState(); .param("override", "eperson.phone")
).andExpect(status().isBadRequest());
getClient(customToken).perform( context.turnOffAuthorisationSystem();
post("/api/eperson/epersons/" + customEPerson.getID()) MetadataField phoneMf =
.param("token", validationRegistration.getToken()) metadataFieldService.findByElement(context, "eperson", "phone", null);
.param("override", "eperson.phone")
).andExpect(status().isBadRequest()); registrationDataService.addMetadata(
context, validationRegistration, phoneMf, "1234567890"
);
context.restoreAuthSystemState();
getClient(customToken).perform(
post("/api/eperson/epersons/" + customEPerson.getID())
.param("token", validationRegistration.getToken())
.param("override", "eperson.phone")
).andExpect(status().isBadRequest());
} finally {
RegistrationData found = context.reloadEntity(validationRegistration);
if (found != null) {
this.registrationDataService.delete(context, found);
}
}
} }

View File

@@ -3208,7 +3208,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
String registrationEmail = "vincenzo.mecca@4science.com"; String registrationEmail = "vins-01@fake.mail";
RegistrationData orcidRegistration = RegistrationData orcidRegistration =
createRegistrationData(RegistrationTypeEnum.ORCID, registrationEmail); createRegistrationData(RegistrationTypeEnum.ORCID, registrationEmail);
@@ -3249,7 +3249,7 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
String registrationEmail = "vincenzo.mecca@4science.com"; String registrationEmail = "vins-01@fake.mail";
RegistrationData orcidRegistration = RegistrationData orcidRegistration =
createRegistrationData(RegistrationTypeEnum.VALIDATION_ORCID, registrationEmail); createRegistrationData(RegistrationTypeEnum.VALIDATION_ORCID, registrationEmail);

View File

@@ -684,7 +684,7 @@ public class RegistrationRestRepositoryIT extends AbstractControllerIntegrationT
assertThat(registrationData.getToken(), not(emptyOrNullString())); assertThat(registrationData.getToken(), not(emptyOrNullString()));
String token = registrationData.getToken(); String token = registrationData.getToken();
String newMail = "vincenzo.mecca@4science.com"; String newMail = "vins-01@fake.mail";
String patchContent = getPatchContent( String patchContent = getPatchContent(
List.of(new ReplaceOperation("/email", newMail)) List.of(new ReplaceOperation("/email", newMail))
); );
@@ -709,7 +709,7 @@ public class RegistrationRestRepositoryIT extends AbstractControllerIntegrationT
assertThat(registrationData.getToken(), not(emptyOrNullString())); assertThat(registrationData.getToken(), not(emptyOrNullString()));
String token = registrationData.getToken(); String token = registrationData.getToken();
String newMail = "vincenzo.mecca@4science.com"; String newMail = "vins-01@fake.mail";
String patchContent = getPatchContent( String patchContent = getPatchContent(
List.of(new AddOperation("/email", newMail)) List.of(new AddOperation("/email", newMail))
); );
@@ -746,7 +746,7 @@ public class RegistrationRestRepositoryIT extends AbstractControllerIntegrationT
assertThat(registrationData.getToken(), not(emptyOrNullString())); assertThat(registrationData.getToken(), not(emptyOrNullString()));
String token = registrationData.getToken(); String token = registrationData.getToken();
String newMail = "vincenzo.mecca@4science.com"; String newMail = "vins-01@fake.mail";
String patchContent = getPatchContent( String patchContent = getPatchContent(
List.of(new ReplaceOperation("/email", newMail)) List.of(new ReplaceOperation("/email", newMail))
); );
@@ -780,7 +780,7 @@ public class RegistrationRestRepositoryIT extends AbstractControllerIntegrationT
assertThat(registrationData.getToken(), not(emptyOrNullString())); assertThat(registrationData.getToken(), not(emptyOrNullString()));
String token = registrationData.getToken(); String token = registrationData.getToken();
String newMail = "vincenzo.mecca@4science.com"; String newMail = "vins-01@fake.mail";
String patchContent = getPatchContent( String patchContent = getPatchContent(
List.of(new AddOperation("/email", newMail)) List.of(new AddOperation("/email", newMail))
); );
@@ -814,7 +814,7 @@ public class RegistrationRestRepositoryIT extends AbstractControllerIntegrationT
assertThat(registrationData.getToken(), not(emptyOrNullString())); assertThat(registrationData.getToken(), not(emptyOrNullString()));
String token = registrationData.getToken(); String token = registrationData.getToken();
String newMail = "vincenzo.mecca@4science.com"; String newMail = "vins-01@fake.mail";
String patchContent = getPatchContent( String patchContent = getPatchContent(
List.of(new AddOperation("/email", newMail)) List.of(new AddOperation("/email", newMail))
); );
@@ -878,7 +878,7 @@ public class RegistrationRestRepositoryIT extends AbstractControllerIntegrationT
assertThat(registrationData.getToken(), not(emptyOrNullString())); assertThat(registrationData.getToken(), not(emptyOrNullString()));
token = registrationData.getToken(); token = registrationData.getToken();
newMail = "vincenzo.mecca@4science.com"; newMail = "vins-01@fake.mail";
patchContent = getPatchContent( patchContent = getPatchContent(
List.of(new ReplaceOperation("/email", newMail)) List.of(new ReplaceOperation("/email", newMail))
); );
@@ -929,7 +929,7 @@ public class RegistrationRestRepositoryIT extends AbstractControllerIntegrationT
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
final EPerson vins = final EPerson vins =
EPersonBuilder.createEPerson(context) EPersonBuilder.createEPerson(context)
.withEmail("vincenzo.mecca@4science.com") .withEmail("vins-01@fake.mail")
.withNameInMetadata("Vincenzo", "Mecca") .withNameInMetadata("Vincenzo", "Mecca")
.withOrcid("0101-0101-0101-0101") .withOrcid("0101-0101-0101-0101")
.build(); .build();
@@ -974,7 +974,7 @@ public class RegistrationRestRepositoryIT extends AbstractControllerIntegrationT
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
final EPerson vins = final EPerson vins =
EPersonBuilder.createEPerson(context) EPersonBuilder.createEPerson(context)
.withEmail("vincenzo.mecca@4science.com") .withEmail("vins-01@fake.mail")
.withNameInMetadata("Vincenzo", "Mecca") .withNameInMetadata("Vincenzo", "Mecca")
.withOrcid("0101-0101-0101-0101") .withOrcid("0101-0101-0101-0101")
.build(); .build();

View File

@@ -1629,18 +1629,26 @@ google.recaptcha.site-verify = https://www.google.com/recaptcha/api/siteverify
#------------------------------------------------------------------# #------------------------------------------------------------------#
# Configuration for the duration of the token depending on the type # Configuration for the duration of the token depending on the type
# the format used should be compatible with the standard DURATION format, # the format used should be compatible with the standard DURATION format (ISO-8601),
# but without the prefix `PT`: # but without the prefix `PT`:
# #
# - PT1H -> 1H // hours # - PT1H -> 1H // hours
# - PT1M -> 1M // minutes # - PT1M -> 1M // minutes
# - PT1S -> 1S // seconds # - PT1S -> 1S // seconds
# #
# reference: https://www.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm
#
# Sets the token expiration to complete the login with orcid to be 1H
eperson.registration-data.token.orcid.expiration = 1H eperson.registration-data.token.orcid.expiration = 1H
# Sets the token expiration for the email validation sent with orcid login to be 1H
eperson.registration-data.token.validation_orcid.expiration = 1H eperson.registration-data.token.validation_orcid.expiration = 1H
# Sets the token expiration for the forgot token type to be 24H
eperson.registration-data.token.forgot.expiration = 24H eperson.registration-data.token.forgot.expiration = 24H
# Sets the token expiration for the register token type to be 24H
eperson.registration-data.token.register.expiration = 24H eperson.registration-data.token.register.expiration = 24H
# Sets the token expiration for the invitation token type to be 24H
eperson.registration-data.token.invitation.expiration = 24H eperson.registration-data.token.invitation.expiration = 24H
# Sets the token expiration for the change_password token type to be 1H
eperson.registration-data.token.change_password.expiration = 1H eperson.registration-data.token.change_password.expiration = 1H
# Configuration that enables the schedulable tasks related to the registration # Configuration that enables the schedulable tasks related to the registration

View File

@@ -19,4 +19,4 @@ If you need assistance with your account, please email
or call us at ${phone}. or call us at ${phone}.
#end #end
The DSpace-CRIS Team The ${config.get("dspace.name")} Team

View File

@@ -19,4 +19,4 @@ If you need assistance with your account, please email
or call us at ${phone}. or call us at ${phone}.
#end #end
The DSpace-CRIS Team The ${config.get("dspace.name")} Team