package eu.eudat.logic.managers; import eu.eudat.data.entities.Credential; import eu.eudat.data.entities.EmailConfirmation; import eu.eudat.data.entities.UserDMP; import eu.eudat.data.entities.UserInfo; import eu.eudat.data.entities.UserToken; import eu.eudat.elastic.criteria.DmpCriteria; import eu.eudat.elastic.entities.Collaborator; import eu.eudat.elastic.entities.Dmp; import eu.eudat.elastic.repository.DmpRepository; import eu.eudat.exceptions.emailconfirmation.HasConfirmedEmailException; import eu.eudat.exceptions.emailconfirmation.TokenExpiredException; import eu.eudat.logic.services.ApiContext; import eu.eudat.logic.services.operations.DatabaseRepository; import eu.eudat.models.data.security.Principal; import eu.eudat.queryable.QueryableList; import eu.eudat.queryable.jpa.predicates.OrderByPredicate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import javax.transaction.Transactional; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @Component public class MergeEmailConfirmationManager { private static Logger logger = LoggerFactory.getLogger(MergeEmailConfirmationManager.class); private ApiContext apiContext; private DatabaseRepository databaseRepository; private DmpRepository dmpRepository; @Autowired public MergeEmailConfirmationManager(ApiContext apiContext) { this.apiContext = apiContext; this.databaseRepository = apiContext.getOperationsContext().getDatabaseRepository(); this.dmpRepository = apiContext.getOperationsContext().getElasticRepository().getDmpRepository(); } @Transactional public String confirmEmail(String token) throws TokenExpiredException, HasConfirmedEmailException { EmailConfirmation loginConfirmationEmail = apiContext.getOperationsContext() .getDatabaseRepository().getLoginConfirmationEmailDao().asQueryable() .where((builder, root) -> builder.equal(root.get("token"), UUID.fromString(token))).getSingle(); if (loginConfirmationEmail.getExpiresAt().compareTo(new Date()) < 0) throw new TokenExpiredException("Token has expired."); UserInfo userToBeMerged = databaseRepository.getUserInfoDao().asQueryable() .where((builder, root) -> builder.equal(root.get("id"), loginConfirmationEmail.getUserId())).getSingle(); String userToBeMergedEmail = userToBeMerged.getEmail(); try { Map map = new ObjectMapper().readValue(loginConfirmationEmail.getData(), HashMap.class); UUID otherUserId = UUID.fromString((String) map.get("userId")); UserInfo user = databaseRepository.getUserInfoDao().asQueryable() .where((builder, root) -> builder.equal(root.get("id"), otherUserId)).getSingle(); // Checks if mail is used by another user. If it is, merges the new the old. mergeNewUserToOld(user, userToBeMerged, Integer.valueOf((String) map.get("provider"))); expireUserToken(userToBeMerged); loginConfirmationEmail.setIsConfirmed(true); databaseRepository.getLoginConfirmationEmailDao().createOrUpdate(loginConfirmationEmail); } catch (Exception e) { logger.error(e.getMessage(), e); } return userToBeMergedEmail; } public void sendConfirmationEmail(String email, Principal principal, UUID userId, Integer provider) throws HasConfirmedEmailException { UserInfo user = apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().find(principal.getId()); if (user.getEmail() != null && !user.getEmail().equals(email)) { apiContext.getUtilitiesService().getConfirmationEmailService().createMergeConfirmationEmail( databaseRepository.getLoginConfirmationEmailDao(), apiContext.getUtilitiesService().getMailService(), email, userId, principal, provider ); } } @Transactional private void mergeNewUserToOld(UserInfo newUser, UserInfo oldUser, Integer provider) { Credential credential = databaseRepository.getCredentialDao().asQueryable().where((builder, root) -> builder.and(builder.equal(root.get("userInfo"), oldUser), builder.equal(root.get("provider"), provider))).getSingle(); credential.setUserInfo(newUser); databaseRepository.getCredentialDao().createOrUpdate(credential); List userDmps = databaseRepository.getUserDmpDao().asQueryable().where((builder, root) -> builder.equal(root.get("user"), oldUser)).toList(); userDmps.forEach(userDmp -> { userDmp.setUser(newUser); databaseRepository.getUserDmpDao().createOrUpdate(userDmp); }); try { DmpCriteria dmpCriteria = new DmpCriteria(); dmpCriteria.setCollaborators(Collections.singletonList(oldUser.getId())); List elasticDmpsIds = dmpRepository.query(dmpCriteria); for(Dmp dmpId: elasticDmpsIds){ Dmp dmp = dmpRepository.findDocument(dmpId.getId().toString()); if(dmp.getDatasets() != null) { dmp.getDatasets().forEach(dataset -> { if(dataset.getCollaborators() != null) { for (Collaborator collaborator : dataset.getCollaborators()) { if (collaborator.getId().equals(oldUser.getId().toString())) { collaborator.setId(newUser.getId().toString()); collaborator.setName(newUser.getName()); } } } }); } if(dmp.getCollaborators() != null) { for (Collaborator collaborator : dmp.getCollaborators()) { if (collaborator.getId().equals(oldUser.getId().toString())) { collaborator.setId(newUser.getId().toString()); collaborator.setName(newUser.getName()); } } } dmpRepository.createOrUpdate(dmp); } } catch (IOException e){ logger.warn("Warning: Could not fetch dmps from elastic.", e); } oldUser.setUserStatus((short)1); oldUser.setEmail(null); List credentials = databaseRepository.getCredentialDao().asQueryable().where((builder, root) -> builder.equal(root.get("userInfo"), oldUser)).toList(); credentials.forEach(cred -> { if (cred.getId() != credential.getId()) { databaseRepository.getCredentialDao().delete(cred); } }); databaseRepository.getUserInfoDao().createOrUpdate(oldUser); } private void expireUserToken(UserInfo user) { UserToken userToken = databaseRepository.getUserTokenDao().asQueryable() .where((builder, root) -> builder.equal(root.get("user"), user)) .orderBy((builder, root) -> builder.desc(root.get("issuedAt"))) .take(1).toList().get(0); userToken.setExpiresAt(new Date()); databaseRepository.getUserTokenDao().createOrUpdate(userToken); } }