package eu.eudat.service.dmp; import com.fasterxml.jackson.core.JsonProcessingException; import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.Permission; import eu.eudat.authorization.authorizationcontentresolver.AuthorizationContentResolver; import eu.eudat.commons.JsonHandlingService; import eu.eudat.commons.XmlHandlingService; import eu.eudat.commons.enums.*; import eu.eudat.commons.enums.notification.NotificationContactType; import eu.eudat.commons.scope.user.UserScope; import eu.eudat.commons.types.actionconfirmation.DmpInvitationEntity; import eu.eudat.commons.types.dmp.DmpBlueprintValueEntity; import eu.eudat.commons.types.dmp.DmpContactEntity; import eu.eudat.commons.types.dmp.DmpPropertiesEntity; import eu.eudat.commons.types.dmpblueprint.ReferenceTypeFieldEntity; import eu.eudat.commons.types.dmpreference.DmpReferenceDataEntity; import eu.eudat.commons.types.notification.*; import eu.eudat.commons.types.reference.DefinitionEntity; import eu.eudat.commons.types.reference.FieldEntity; import eu.eudat.configurations.notification.NotificationProperties; import eu.eudat.convention.ConventionService; import eu.eudat.data.*; import eu.eudat.errorcode.ErrorThesaurusProperties; import eu.eudat.event.DmpTouchedEvent; import eu.eudat.event.EventBroker; import eu.eudat.integrationevent.outbox.annotationentitytouch.AnnotationEntityTouchedIntegrationEventHandler; import eu.eudat.integrationevent.outbox.dmptouched.DmpTouchedIntegrationEventHandler; import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEvent; import eu.eudat.integrationevent.outbox.notification.NotifyIntegrationEventHandler; import eu.eudat.model.*; import eu.eudat.model.builder.DmpBuilder; import eu.eudat.model.builder.DmpUserBuilder; import eu.eudat.model.deleter.*; import eu.eudat.model.file.FileEnvelope; import eu.eudat.model.persist.*; import eu.eudat.model.persist.actionconfirmation.DmpInvitationPersist; import eu.eudat.model.persist.dmpproperties.DmpBlueprintValuePersist; import eu.eudat.model.persist.dmpproperties.DmpContactPersist; import eu.eudat.model.persist.dmpproperties.DmpPropertiesPersist; import eu.eudat.model.persist.dmpreference.DmpReferenceDataPersist; import eu.eudat.model.persist.referencedefinition.DefinitionPersist; import eu.eudat.model.persist.referencedefinition.FieldPersist; import eu.eudat.query.*; import eu.eudat.service.actionconfirmation.ActionConfirmationService; import eu.eudat.service.description.DescriptionService; import eu.eudat.service.elastic.ElasticService; import eu.eudat.service.transformer.FileTransformerService; import gr.cite.commons.web.authz.service.AuthorizationService; import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.deleter.DeleterFactory; import gr.cite.tools.data.query.Ordering; import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyForbiddenException; import gr.cite.tools.exception.MyNotFoundException; import gr.cite.tools.exception.MyValidationException; import gr.cite.tools.fieldset.BaseFieldSet; import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.MapLogEntry; import gr.cite.tools.validation.ValidatorFactory; import jakarta.persistence.EntityManager; import jakarta.xml.bind.JAXBException; import org.jetbrains.annotations.NotNull; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import javax.management.InvalidApplicationException; import java.io.IOException; import java.time.Instant; import java.util.*; import java.util.stream.Collectors; @Service public class DmpServiceImpl implements DmpService { private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DmpServiceImpl.class)); private final EntityManager entityManager; private final AuthorizationService authorizationService; private final DeleterFactory deleterFactory; private final BuilderFactory builderFactory; private final QueryFactory queryFactory; private final ConventionService conventionService; private final ErrorThesaurusProperties errors; private final MessageSource messageSource; private final XmlHandlingService xmlHandlingService; private final JsonHandlingService jsonHandlingService; private final UserScope userScope; private final EventBroker eventBroker; private final DescriptionService descriptionService; private final FileTransformerService fileTransformerService; private final NotifyIntegrationEventHandler eventHandler; private final NotificationProperties notificationProperties; private final ActionConfirmationService actionConfirmationService; private final gr.cite.tools.validation.ValidatorFactory validatorFactory; private final ElasticService elasticService; private final DmpTouchedIntegrationEventHandler dmpTouchedIntegrationEventHandler; private final AnnotationEntityTouchedIntegrationEventHandler annotationEntityTouchedIntegrationEventHandler; private final AuthorizationContentResolver authorizationContentResolver; @Autowired public DmpServiceImpl( EntityManager entityManager, AuthorizationService authorizationService, DeleterFactory deleterFactory, BuilderFactory builderFactory, QueryFactory queryFactory, ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, XmlHandlingService xmlHandlingService, JsonHandlingService jsonHandlingService, UserScope userScope, EventBroker eventBroker, DescriptionService descriptionService, NotifyIntegrationEventHandler eventHandler, NotificationProperties notificationProperties, ActionConfirmationService actionConfirmationService, FileTransformerService fileTransformerService, ValidatorFactory validatorFactory, ElasticService elasticService, DmpTouchedIntegrationEventHandler dmpTouchedIntegrationEventHandler, AnnotationEntityTouchedIntegrationEventHandler annotationEntityTouchedIntegrationEventHandler, AuthorizationContentResolver authorizationContentResolver) { this.entityManager = entityManager; this.authorizationService = authorizationService; this.deleterFactory = deleterFactory; this.builderFactory = builderFactory; this.queryFactory = queryFactory; this.conventionService = conventionService; this.errors = errors; this.messageSource = messageSource; this.xmlHandlingService = xmlHandlingService; this.jsonHandlingService = jsonHandlingService; this.userScope = userScope; this.eventBroker = eventBroker; this.descriptionService = descriptionService; this.fileTransformerService = fileTransformerService; this.eventHandler = eventHandler; this.notificationProperties = notificationProperties; this.actionConfirmationService = actionConfirmationService; this.validatorFactory = validatorFactory; this.elasticService = elasticService; this.dmpTouchedIntegrationEventHandler = dmpTouchedIntegrationEventHandler; this.annotationEntityTouchedIntegrationEventHandler = annotationEntityTouchedIntegrationEventHandler; this.authorizationContentResolver = authorizationContentResolver; } public Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, IOException { Boolean isUpdate = this.conventionService.isValidGuid(model.getId()); if (isUpdate) this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(model.getId())), Permission.EditDmp); else this.authorizationService.authorizeForce(Permission.NewDmp); DmpEntity data = this.patchAndSave(model); DmpBlueprintEntity blueprintEntity = this.entityManager.find(DmpBlueprintEntity.class, data.getBlueprintId()); if (blueprintEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{data.getBlueprintId(), DmpBlueprint.class.getSimpleName()}, LocaleContextHolder.getLocale())); eu.eudat.commons.types.dmpblueprint.DefinitionEntity definition = this.xmlHandlingService.fromXmlSafe(eu.eudat.commons.types.dmpblueprint.DefinitionEntity.class, blueprintEntity.getDefinition()); if (definition == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{data.getBlueprintId(), eu.eudat.commons.types.dmpblueprint.DefinitionEntity.class.getSimpleName()}, LocaleContextHolder.getLocale())); this.patchAndSaveReferences(this.buildDmpReferencePersists(model.getProperties()), data.getId(), definition); this.patchAndSaveTemplates(data.getId(), model.getDescriptionTemplates()); if (!isUpdate && userScope.isSet()) { this.addOwner(data); if (model.getUsers() == null) model.setUsers(new ArrayList<>()); if (model.getUsers().stream().noneMatch(x-> x.getUser() != null && x.getUser().equals(this.userScope.getUserIdSafe()) && DmpUserRole.Owner.equals(x.getRole()))) model.getUsers().add(this.createOwnerPersist()); } this.eventBroker.emit(new DmpTouchedEvent(data.getId())); this.dmpTouchedIntegrationEventHandler.handle(DmpTouchedIntegrationEventHandler.buildEventFromPersistModel(model)); this.annotationEntityTouchedIntegrationEventHandler.handle(AnnotationEntityTouchedIntegrationEventHandler.buildEventFromPersistModel(model)); this.sendNotification(data); this.assignUsers(data.getId(), this.inviteUserOrAssignUsers(data.getId(), model.getUsers(), false), null, false); this.elasticService.persistDmp(data); return this.builderFactory.builder(DmpBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, Dmp._id, Dmp._hash), data); } private DmpUserPersist createOwnerPersist() { DmpUserPersist persist = new DmpUserPersist(); persist.setRole(DmpUserRole.Owner); persist.setUser(userScope.getUserIdSafe()); return persist; } private void addOwner(DmpEntity dmpEntity) throws InvalidApplicationException { DmpUserEntity data = new DmpUserEntity(); data.setId(UUID.randomUUID()); data.setIsActive(IsActive.Active); data.setCreatedAt(Instant.now()); data.setUpdatedAt(Instant.now()); data.setRole(DmpUserRole.Owner); data.setUserId(userScope.getUserId()); data.setDmpId(dmpEntity.getId()); this.entityManager.persist(data); } private void sendNotification(DmpEntity dmp) throws InvalidApplicationException { List existingUsers = this.queryFactory.query(DmpUserQuery.class) .dmpIds(dmp.getId()) .isActives(IsActive.Active) .collect(); if (existingUsers == null || existingUsers.size() <= 1){ return; } for (DmpUserEntity dmpUser : existingUsers) { if (!dmpUser.getUserId().equals(this.userScope.getUserIdSafe())){ UserEntity user = this.queryFactory.query(UserQuery.class).ids(dmpUser.getUserId()).first(); if (user != null){ this.createDmpNotificationEvent(dmp, user, NotificationContactType.EMAIL); this.createDmpNotificationEvent(dmp, user, NotificationContactType.IN_APP); } } } } private void createDmpNotificationEvent(DmpEntity dmp, UserEntity user, NotificationContactType type) throws InvalidApplicationException { NotifyIntegrationEvent event = new NotifyIntegrationEvent(); event.setUserId(this.userScope.getUserId()); UserContactInfoQuery query = this.queryFactory.query(UserContactInfoQuery.class).userIds(user.getId()); query.setOrder(new Ordering().addAscending(UserContactInfo._ordinal)); List contactPairs = new ArrayList<>(); contactPairs.add(new ContactPair(ContactInfoType.Email, query.first().getValue())); NotificationContactData contactData = new NotificationContactData(contactPairs, null, null); event.setContactHint(jsonHandlingService.toJsonSafe(contactData)); event.setContactTypeHint(type); this.applyNotificationType(dmp.getStatus(), event); NotificationFieldData data = new NotificationFieldData(); List fieldInfoList = new ArrayList<>(); fieldInfoList.add(new FieldInfo("{recipient}", DataType.String, user.getName())); fieldInfoList.add(new FieldInfo("{reasonName}", DataType.String, this.queryFactory.query(UserQuery.class).ids(this.userScope.getUserId()).first().getName())); fieldInfoList.add(new FieldInfo("{name}", DataType.String, dmp.getLabel())); fieldInfoList.add(new FieldInfo("{id}", DataType.String, dmp.getId().toString())); data.setFields(fieldInfoList); event.setData(jsonHandlingService.toJsonSafe(data)); eventHandler.handle(event); } private void applyNotificationType(DmpStatus status, NotifyIntegrationEvent event) { switch (status) { case Draft: event.setNotificationType(notificationProperties.getDmpModifiedType()); break; case Finalized: event.setNotificationType(notificationProperties.getDmpFinalisedType()); break; default: throw new MyApplicationException("Unsupported Dmp Status."); } } public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException, IOException { logger.debug("deleting dmp: {}", id); this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(id)), Permission.DeleteDmp); DmpEntity data = this.entityManager.find(DmpEntity.class, id); if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); EntityDoiQuery entityDoiQuery = this.queryFactory.query(EntityDoiQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).types(EntityType.DMP).entityIds(data.getId()); if (entityDoiQuery.count() > 0) throw new MyApplicationException("DMP is deposited can not deleted"); DmpEntity previousFinalized = null; if (data.getVersionStatus().equals(DmpVersionStatus.Current)){ DmpQuery dmpQuery = this.queryFactory.query(DmpQuery.class) .statuses(DmpStatus.Finalized) .excludedIds(data.getId()) .isActive(IsActive.Active) .groupIds(data.getGroupId()); dmpQuery.setOrder(new Ordering().addDescending(Dmp._version)); previousFinalized = dmpQuery.first(); if (previousFinalized != null){ previousFinalized.setVersionStatus(DmpVersionStatus.Current); this.entityManager.merge(previousFinalized); } data.setVersionStatus(DmpVersionStatus.NotFinalized); this.entityManager.merge(data); this.entityManager.flush(); } this.deleterFactory.deleter(DmpDeleter.class).deleteAndSaveByIds(List.of(id), false); if (previousFinalized != null) this.elasticService.persistDmp(previousFinalized); } @Override public Dmp createNewVersion(NewVersionDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, IOException { logger.debug(new MapLogEntry("persisting data bew version").And("model", model).And("fields", fields)); this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation( model.getId())), Permission.CreateNewVersionDmp); DmpEntity oldDmpEntity = this.entityManager.find(DmpEntity.class, model.getId()); if (oldDmpEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); if (!this.conventionService.hashValue(oldDmpEntity.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); List latestVersionDmps = this.queryFactory.query(DmpQuery.class) .groupIds(oldDmpEntity.getGroupId()) .isActive(IsActive.Active) .versionStatuses(DmpVersionStatus.Current) .collect(); if (latestVersionDmps.isEmpty()) throw new MyValidationException("Previous dmp not found"); if (latestVersionDmps.size() > 1) throw new MyValidationException("Multiple previous dmps found"); if (!latestVersionDmps.getFirst().getVersion().equals(oldDmpEntity.getVersion())){ throw new MyValidationException(this.errors.getDmpNewVersionConflict().getCode(), this.errors.getDmpNewVersionConflict().getMessage()); } Long notFinalizedCount = this.queryFactory.query(DmpQuery.class) .versionStatuses(DmpVersionStatus.NotFinalized) .groupIds(oldDmpEntity.getGroupId()) .isActive(IsActive.Active) .count(); if (notFinalizedCount > 0) throw new MyValidationException("Already created draft for this template"); DmpEntity newDmp = new DmpEntity(); newDmp.setId(UUID.randomUUID()); newDmp.setIsActive(IsActive.Active); newDmp.setCreatedAt(Instant.now()); newDmp.setUpdatedAt(Instant.now()); newDmp.setGroupId(oldDmpEntity.getGroupId()); newDmp.setVersionStatus(DmpVersionStatus.NotFinalized); newDmp.setVersion((short)(oldDmpEntity.getVersion() + 1)); newDmp.setDescription(model.getDescription()); newDmp.setLabel(model.getLabel()); newDmp.setLanguage(oldDmpEntity.getLanguage()); newDmp.setStatus(DmpStatus.Draft); newDmp.setProperties(oldDmpEntity.getProperties()); newDmp.setBlueprintId(model.getBlueprintId()); newDmp.setCreatorId(this.userScope.getUserId()); this.entityManager.persist(newDmp); List dmpUsers = this.queryFactory.query(DmpUserQuery.class) .dmpIds(model.getId()) .isActives(IsActive.Active) .collect(); List dmpReferences = this.queryFactory.query(DmpReferenceQuery.class) .dmpIds(model.getId()) .isActives(IsActive.Active) .collect(); List dmpDescriptionTemplates = this.queryFactory.query(DmpDescriptionTemplateQuery.class) .dmpIds(model.getId()) .isActive(IsActive.Active) .collect(); for (DmpUserEntity dmpUser : dmpUsers) { DmpUserEntity newUser = new DmpUserEntity(); newUser.setId(UUID.randomUUID()); newUser.setDmpId(newDmp.getId()); newUser.setUserId(dmpUser.getUserId()); newUser.setRole(dmpUser.getRole()); newUser.setCreatedAt(Instant.now()); newUser.setUpdatedAt(Instant.now()); newUser.setIsActive(IsActive.Active); this.entityManager.persist(newUser); } for (DmpReferenceEntity dmpReference : dmpReferences) { DmpReferenceEntity newReference = new DmpReferenceEntity(); newReference.setId(UUID.randomUUID()); newReference.setDmpId(newDmp.getId()); newReference.setReferenceId(dmpReference.getReferenceId()); newReference.setData(dmpReference.getData()); newReference.setCreatedAt(Instant.now()); newReference.setUpdatedAt(Instant.now()); newReference.setIsActive(IsActive.Active); this.entityManager.persist(newReference); } for (DmpDescriptionTemplateEntity dmpDescriptionTemplate : dmpDescriptionTemplates) { DmpDescriptionTemplateEntity newTemplate = new DmpDescriptionTemplateEntity(); newTemplate.setId(UUID.randomUUID()); newTemplate.setDmpId(newDmp.getId()); newTemplate.setDescriptionTemplateGroupId(dmpDescriptionTemplate.getDescriptionTemplateGroupId()); newTemplate.setSectionId(dmpDescriptionTemplate.getSectionId()); newTemplate.setCreatedAt(Instant.now()); newTemplate.setUpdatedAt(Instant.now()); newTemplate.setIsActive(IsActive.Active); this.entityManager.persist(newTemplate); } for (UUID descriptionId : model.getDescriptions()) { this.descriptionService.clone(newDmp.getId(), descriptionId); } this.entityManager.flush(); this.updateVersionStatusAndSave(newDmp, DmpStatus.Draft, newDmp.getStatus()); this.entityManager.flush(); this.elasticService.persistDmp(oldDmpEntity); this.elasticService.persistDmp(newDmp); return this.builderFactory.builder(DmpBuilder.class).build(BaseFieldSet.build(fields, Dmp._id), newDmp); } private void updateVersionStatusAndSave(DmpEntity data, DmpStatus previousStatus, DmpStatus newStatus) { if (previousStatus.equals(newStatus)) return; if (previousStatus.equals(DmpStatus.Finalized) && newStatus.equals(DmpStatus.Draft)){ boolean alreadyCreatedNewVersion = this.queryFactory.query(DmpQuery.class) .versionStatuses(DmpVersionStatus.NotFinalized, DmpVersionStatus.Current) .excludedIds(data.getId()) .isActive(IsActive.Active) .groupIds(data.getGroupId()) .count() > 0; if (alreadyCreatedNewVersion) throw new MyValidationException("Already new version is created"); data.setVersionStatus(DmpVersionStatus.NotFinalized); this.entityManager.merge(data); } if (newStatus.equals(DmpStatus.Finalized)) { List latestVersionDmps = this.queryFactory.query(DmpQuery.class) .versionStatuses(DmpVersionStatus.Current).isActive(IsActive.Active).groupIds(data.getGroupId()).collect(); if (latestVersionDmps.size() > 1) throw new MyValidationException("Multiple previous template found"); DmpEntity oldDmpEntity = latestVersionDmps.stream().findFirst().orElse(null); data.setVersionStatus(DmpVersionStatus.Current); if (oldDmpEntity != null) { data.setVersion((short) (oldDmpEntity.getVersion() + 1)); oldDmpEntity.setVersionStatus(DmpVersionStatus.Previous); this.entityManager.merge(oldDmpEntity); } else { data.setVersion((short) 1); } } } @Override public Dmp buildClone(CloneDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, IOException, InvalidApplicationException { this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation( model.getId())), Permission.CloneDmp); DmpEntity existingDmpEntity = this.queryFactory.query(DmpQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(model.getId()).firstAs(fields); if (!this.conventionService.isValidGuid(model.getId()) || existingDmpEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); DmpEntity newDmp = new DmpEntity(); newDmp.setId(UUID.randomUUID()); newDmp.setIsActive(IsActive.Active); newDmp.setCreatedAt(Instant.now()); newDmp.setUpdatedAt(Instant.now()); newDmp.setGroupId(UUID.randomUUID()); newDmp.setVersion((short) 1); newDmp.setVersionStatus(DmpVersionStatus.NotFinalized); newDmp.setDescription(model.getDescription()); newDmp.setLabel(model.getLabel()); newDmp.setLanguage(existingDmpEntity.getLanguage()); newDmp.setStatus(DmpStatus.Draft); newDmp.setProperties(existingDmpEntity.getProperties()); newDmp.setBlueprintId(existingDmpEntity.getBlueprintId()); newDmp.setAccessType(existingDmpEntity.getAccessType()); newDmp.setCreatorId(this.userScope.getUserId()); this.entityManager.persist(newDmp); List dmpUsers = this.queryFactory.query(DmpUserQuery.class) .dmpIds(model.getId()) .isActives(IsActive.Active) .collect(); List dmpReferences = this.queryFactory.query(DmpReferenceQuery.class) .dmpIds(model.getId()) .isActives(IsActive.Active) .collect(); List dmpDescriptionTemplates = this.queryFactory.query(DmpDescriptionTemplateQuery.class) .dmpIds(model.getId()) .isActive(IsActive.Active) .collect(); for (DmpUserEntity dmpUser : dmpUsers) { DmpUserEntity newUser = new DmpUserEntity(); newUser.setId(UUID.randomUUID()); newUser.setDmpId(newDmp.getId()); newUser.setUserId(dmpUser.getUserId()); newUser.setRole(dmpUser.getRole()); newUser.setCreatedAt(Instant.now()); newUser.setUpdatedAt(Instant.now()); newUser.setIsActive(IsActive.Active); this.entityManager.persist(newUser); } for (DmpReferenceEntity dmpReference : dmpReferences) { DmpReferenceEntity newReference = new DmpReferenceEntity(); newReference.setId(UUID.randomUUID()); newReference.setDmpId(newDmp.getId()); newReference.setReferenceId(dmpReference.getReferenceId()); newReference.setData(dmpReference.getData()); newReference.setCreatedAt(Instant.now()); newReference.setUpdatedAt(Instant.now()); newReference.setIsActive(IsActive.Active); this.entityManager.persist(newReference); } for (DmpDescriptionTemplateEntity dmpDescriptionTemplate : dmpDescriptionTemplates) { DmpDescriptionTemplateEntity newTemplate = new DmpDescriptionTemplateEntity(); newTemplate.setId(UUID.randomUUID()); newTemplate.setDmpId(newDmp.getId()); newTemplate.setDescriptionTemplateGroupId(dmpDescriptionTemplate.getDescriptionTemplateGroupId()); newTemplate.setSectionId(dmpDescriptionTemplate.getSectionId()); newTemplate.setCreatedAt(Instant.now()); newTemplate.setUpdatedAt(Instant.now()); newTemplate.setIsActive(IsActive.Active); this.entityManager.persist(newTemplate); } this.entityManager.flush(); this.elasticService.persistDmp(newDmp); DmpEntity resultingDmpEntity = this.queryFactory.query(DmpQuery.class).ids(newDmp.getId()).firstAs(fields); return this.builderFactory.builder(DmpBuilder.class).build(fields, resultingDmpEntity); } @Override public List assignUsers(UUID dmpId, List model, FieldSet fieldSet, boolean disableDelete) throws InvalidApplicationException, IOException { this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(dmpId)), Permission.AssignDmpUsers); if (model == null || model.stream().noneMatch(x-> x.getUser() != null && DmpUserRole.Owner.equals(x.getRole()))) throw new MyApplicationException("At least one owner required"); DmpEntity dmpEntity = this.entityManager.find(DmpEntity.class, dmpId); if (dmpEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{dmpId, Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); List existingUsers = this.queryFactory.query(DmpUserQuery.class) .dmpIds(dmpId) .isActives(IsActive.Active) .collect(); List updatedCreatedIds = new ArrayList<>(); for (DmpUserPersist dmpUser : model) { DmpUserEntity dmpUserEntity = existingUsers.stream().filter(x-> x.getDmpId().equals(dmpId) && x.getUserId().equals(dmpUser.getUser()) && x.getRole().equals(dmpUser.getRole()) && Objects.equals(dmpUser.getSectionId(), x.getSectionId())).findFirst().orElse(null); if (dmpUserEntity == null){ dmpUserEntity = new DmpUserEntity(); dmpUserEntity.setId(UUID.randomUUID()); dmpUserEntity.setDmpId(dmpId); dmpUserEntity.setUserId(dmpUser.getUser()); dmpUserEntity.setRole(dmpUser.getRole()); dmpUserEntity.setSectionId(dmpUser.getSectionId()); dmpUserEntity.setCreatedAt(Instant.now()); dmpUserEntity.setUpdatedAt(Instant.now()); dmpUserEntity.setIsActive(IsActive.Active); this.entityManager.persist(dmpUserEntity); } updatedCreatedIds.add(dmpUserEntity.getId()); } List toDelete = existingUsers.stream().filter(x-> updatedCreatedIds.stream().noneMatch(y-> y.equals(x.getId()))).collect(Collectors.toList()); if (!toDelete.isEmpty() && !disableDelete) this.deleterFactory.deleter(DmpUserDeleter.class).delete(toDelete); this.entityManager.flush(); List persisted = this.queryFactory.query(DmpUserQuery.class) .dmpIds(dmpId) .isActives(IsActive.Active) .collect(); this.elasticService.persistDmp(dmpEntity); return this.builderFactory.builder(DmpUserBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fieldSet, DmpUser._id, DmpUser._hash), persisted); } @Override public Dmp removeUser(DmpUserRemovePersist model, FieldSet fields) throws InvalidApplicationException, IOException { this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(model.getDmpId())), Permission.AssignDmpUsers); DmpEntity data = this.entityManager.find(DmpEntity.class, model.getDmpId()); if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); List existingUsers = this.queryFactory.query(DmpUserQuery.class) .dmpIds(model.getDmpId()).ids(model.getId()).userRoles(model.getRole()) .collect(); if (!existingUsers.isEmpty()) this.deleterFactory.deleter(DmpUserDeleter.class).delete(existingUsers); this.entityManager.flush(); DmpEntity dmpEntity = this.entityManager.find(DmpEntity.class, model.getDmpId()); if (dmpEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getDmpId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); this.elasticService.persistDmp(dmpEntity); return this.builderFactory.builder(DmpBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).build(BaseFieldSet.build(fields, Dmp._id, Dmp._hash), data); } @Override public ResponseEntity export(UUID id, String transformerId, String exportType) throws InvalidApplicationException, IOException { HttpHeaders headers = new HttpHeaders(); FileEnvelope fileEnvelope = this.fileTransformerService.exportDmp(id, transformerId, exportType); headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename()); byte[] data = fileEnvelope.getFile(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); return new ResponseEntity<>(data, headers, HttpStatus.OK); } private DmpEntity patchAndSave(DmpPersist model) throws JsonProcessingException, InvalidApplicationException { Boolean isUpdate = this.conventionService.isValidGuid(model.getId()); DmpEntity data; if (isUpdate) { data = this.entityManager.find(DmpEntity.class, model.getId()); if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); if (model.getStatus() != null && model.getStatus() == DmpStatus.Finalized && data.getStatus() != DmpStatus.Finalized) { this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(model.getId())), Permission.FinalizeDmp); data.setStatus(model.getStatus()); data.setFinalizedAt(Instant.now()); } } else { data = new DmpEntity(); data.setId(UUID.randomUUID()); data.setGroupId(UUID.randomUUID()); data.setVersion((short) 1); data.setStatus(DmpStatus.Draft); data.setVersionStatus(DmpVersionStatus.NotFinalized); data.setCreatorId(userScope.getUserId()); data.setBlueprintId(model.getBlueprint()); data.setIsActive(IsActive.Active); data.setCreatedAt(Instant.now()); } DmpStatus previousStatus = data.getStatus(); data.setLabel(model.getLabel()); data.setLanguage(model.getLanguage()); data.setProperties(this.jsonHandlingService.toJson(this.buildDmpPropertiesEntity(model.getProperties()))); data.setDescription(model.getDescription()); data.setAccessType(model.getAccessType()); data.setUpdatedAt(Instant.now()); if (isUpdate) this.entityManager.merge(data); else { this.entityManager.persist(data); } this.entityManager.flush(); this.updateVersionStatusAndSave(data, previousStatus, data.getStatus()); this.entityManager.flush(); return data; } private @NotNull DmpPropertiesEntity buildDmpPropertiesEntity(DmpPropertiesPersist persist){ DmpPropertiesEntity data = new DmpPropertiesEntity(); if (persist == null) return data; if (!this.conventionService.isListNullOrEmpty(persist.getContacts())){ data.setContacts(new ArrayList<>()); for (DmpContactPersist contactPersist: persist.getContacts()) { data.getContacts().add(this.buildDmpContactEntity(contactPersist)); } } if (persist.getDmpBlueprintValues() != null && !persist.getDmpBlueprintValues().isEmpty()){ data.setDmpBlueprintValues(new ArrayList<>()); for (DmpBlueprintValuePersist fieldValuePersist: persist.getDmpBlueprintValues().values()) { if (!this.conventionService.isNullOrEmpty(fieldValuePersist.getFieldValue())) data.getDmpBlueprintValues().add(this.buildDmpBlueprintValueEntity(fieldValuePersist)); } } return data; } private @NotNull DmpContactEntity buildDmpContactEntity(DmpContactPersist persist){ DmpContactEntity data = new DmpContactEntity(); if (persist == null) return data; data.setEmail(persist.getEmail()); data.setLastName(persist.getLastName()); data.setFirstName(persist.getFirstName()); data.setUserId(persist.getUserId()); return data; } private @NotNull DmpBlueprintValueEntity buildDmpBlueprintValueEntity(DmpBlueprintValuePersist persist){ DmpBlueprintValueEntity data = new DmpBlueprintValueEntity(); if (persist == null) return data; data.setValue(persist.getFieldValue()); data.setFieldId(persist.getFieldId()); return data; } private @NotNull List buildDmpReferencePersists(DmpPropertiesPersist persist){ List dmpReferencePersists = new ArrayList<>(); if (persist.getDmpBlueprintValues() != null && !persist.getDmpBlueprintValues().isEmpty()){ for (DmpBlueprintValuePersist fieldValuePersist: persist.getDmpBlueprintValues().values()) { if (this.conventionService.isNullOrEmpty(fieldValuePersist.getFieldValue()) && !this.conventionService.isListNullOrEmpty( fieldValuePersist.getReferences())) { for (ReferencePersist referencePersist : fieldValuePersist.getReferences()) { DmpReferencePersist dmpReferencePersist = new DmpReferencePersist(); dmpReferencePersist.setData(new DmpReferenceDataPersist()); dmpReferencePersist.getData().setBlueprintFieldId(fieldValuePersist.getFieldId()); dmpReferencePersist.setReference(referencePersist); dmpReferencePersists.add(dmpReferencePersist); } } } } return dmpReferencePersists; } private void patchAndSaveReferences(List models, UUID dmpId, eu.eudat.commons.types.dmpblueprint.DefinitionEntity blueprintDefinition) throws InvalidApplicationException { if (models == null) models = new ArrayList<>(); List dmpReferences = this.queryFactory.query(DmpReferenceQuery.class).dmpIds(dmpId).collect(); Map> dmpReferenceEntityByReferenceId = new HashMap<>(); for (DmpReferenceEntity dmpReferenceEntity : dmpReferences){ List dmpReferenceEntities = dmpReferenceEntityByReferenceId.getOrDefault(dmpReferenceEntity.getReferenceId(), null); if (dmpReferenceEntities == null) { dmpReferenceEntities = new ArrayList<>(); dmpReferenceEntityByReferenceId.put(dmpReferenceEntity.getReferenceId(), dmpReferenceEntities); } dmpReferenceEntities.add(dmpReferenceEntity); } Map dmpReferenceDataEntityMap = new HashMap<>(); for (DmpReferenceEntity dmpReferenceEntity : dmpReferences){ dmpReferenceDataEntityMap.put(dmpReferenceEntity.getId(), this.jsonHandlingService.fromJsonSafe(DmpReferenceDataEntity.class, dmpReferenceEntity.getData())); } List updatedCreatedIds = new ArrayList<>(); for (DmpReferencePersist model : models) { ReferencePersist referencePersist = model.getReference(); ReferenceEntity referenceEntity; if (this.conventionService.isValidGuid(referencePersist.getId())){ referenceEntity = this.entityManager.find(ReferenceEntity.class, referencePersist.getId()); if (referenceEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{referencePersist.getId(), Reference.class.getSimpleName()}, LocaleContextHolder.getLocale())); } else { ReferenceTypeFieldEntity fieldEntity = blueprintDefinition.getFieldById(model.getData().getBlueprintFieldId()).stream().filter(x-> x.getCategory().equals(DmpBlueprintFieldCategory.ReferenceType)).map(x-> (ReferenceTypeFieldEntity)x).findFirst().orElse(null); if (fieldEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getData().getBlueprintFieldId(), ReferenceTypeFieldEntity.class.getSimpleName()}, LocaleContextHolder.getLocale())); referenceEntity = this.queryFactory.query(ReferenceQuery.class).sourceTypes(referencePersist.getSourceType()).typeIds(fieldEntity.getReferenceTypeId()).sources(referencePersist.getSource()).isActive(IsActive.Active).references(referencePersist.getReference()).first(); if (referenceEntity == null){ referenceEntity = new ReferenceEntity(); referenceEntity.setId(UUID.randomUUID()); referenceEntity.setLabel(referencePersist.getLabel()); referenceEntity.setIsActive(IsActive.Active); referenceEntity.setCreatedAt(Instant.now()); referenceEntity.setTypeId(fieldEntity.getReferenceTypeId()); referenceEntity.setDefinition(this.xmlHandlingService.toXmlSafe(this.buildDefinitionEntity(referencePersist.getDefinition()))); referenceEntity.setUpdatedAt(Instant.now()); referenceEntity.setReference(referencePersist.getReference()); referenceEntity.setAbbreviation(referencePersist.getAbbreviation()); referenceEntity.setSource(referencePersist.getSource()); referenceEntity.setSourceType(referencePersist.getSourceType()); this.entityManager.persist(referenceEntity); } } DmpReferenceEntity data = null; List dmpReferenceEntities = dmpReferenceEntityByReferenceId.getOrDefault(referenceEntity.getId(), new ArrayList<>()); for (DmpReferenceEntity dmpReferenceEntity : dmpReferenceEntities){ DmpReferenceDataEntity dmpReferenceDataEntity = dmpReferenceDataEntityMap.getOrDefault(dmpReferenceEntity.getId(), new DmpReferenceDataEntity()); if (Objects.equals(dmpReferenceDataEntity.getBlueprintFieldId(), model.getData().getBlueprintFieldId())){ data = dmpReferenceEntity; break; } } boolean isUpdate = data != null; if (!isUpdate) { data = new DmpReferenceEntity(); data.setId(UUID.randomUUID()); data.setReferenceId(referenceEntity.getId()); data.setDmpId(dmpId); data.setCreatedAt(Instant.now()); data.setIsActive(IsActive.Active); data.setData(this.jsonHandlingService.toJsonSafe(this.buildDmpReferenceDataEntity(model.getData()))); } updatedCreatedIds.add(data.getId()); data.setUpdatedAt(Instant.now()); if (isUpdate) this.entityManager.merge(data); else this.entityManager.persist(data); } List toDelete = dmpReferences.stream().filter(x-> updatedCreatedIds.stream().noneMatch(y-> y.equals(x.getId()))).collect(Collectors.toList()); this.deleterFactory.deleter(DmpReferenceDeleter.class).delete(toDelete); this.entityManager.flush(); } private void patchAndSaveTemplates(UUID id, List models) throws InvalidApplicationException { if (models == null) models = new ArrayList<>(); List items = this.queryFactory.query(DmpDescriptionTemplateQuery.class).isActive(IsActive.Active).dmpIds(id).collect(); List updatedCreatedIds = new ArrayList<>(); for (DmpDescriptionTemplatePersist model : models) { DmpDescriptionTemplateEntity data = items.stream().filter(x -> x.getDescriptionTemplateGroupId().equals(model.getDescriptionTemplateGroupId()) && x.getSectionId().equals(model.getSectionId())).findFirst().orElse(null); if (data == null){ data = new DmpDescriptionTemplateEntity(); data.setId(UUID.randomUUID()); data.setIsActive(IsActive.Active); data.setCreatedAt(Instant.now()); data.setUpdatedAt(Instant.now()); data.setDmpId(id); data.setSectionId(model.getSectionId()); data.setDescriptionTemplateGroupId(model.getDescriptionTemplateGroupId()); this.entityManager.persist(data); } updatedCreatedIds.add(data.getId()); } List toDelete = items.stream().filter(x-> updatedCreatedIds.stream().noneMatch(y-> y.equals(x.getId()))).collect(Collectors.toList()); this.deleterFactory.deleter(DmpDescriptionTemplateDeleter.class).delete(toDelete); } private @NotNull DefinitionEntity buildDefinitionEntity(DefinitionPersist persist){ DefinitionEntity data = new DefinitionEntity(); if (persist == null) return data; if (!this.conventionService.isListNullOrEmpty(persist.getFields())){ data.setFields(new ArrayList<>()); for (FieldPersist fieldPersist: persist.getFields()) { data.getFields().add(this.buildDmpContactEntity(fieldPersist)); } } return data; } private @NotNull DmpReferenceDataEntity buildDmpReferenceDataEntity(DmpReferenceDataPersist persist){ DmpReferenceDataEntity data = new DmpReferenceDataEntity(); if (persist == null) return data; data.setBlueprintFieldId(persist.getBlueprintFieldId()); return data; } private @NotNull FieldEntity buildDmpContactEntity(FieldPersist persist){ FieldEntity data = new FieldEntity(); if (persist == null) return data; data.setCode(persist.getCode()); data.setDataType(persist.getDataType()); data.setCode(persist.getCode()); return data; } public void finalize(UUID id, List descriptionIds) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, IOException { this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(id)), Permission.FinalizeDmp); DmpEntity dmp = this.queryFactory.query(DmpQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(id).isActive(IsActive.Active).first(); if (dmp == null){ throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); } if (dmp.getStatus().equals(DmpStatus.Finalized)){ throw new MyApplicationException("DMP is already finalized"); } List descriptions = this.queryFactory.query(DescriptionQuery.class) .authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).dmpIds(id).isActive(IsActive.Active).collect(); for (DescriptionEntity description: descriptions) { if (descriptionIds.contains(description.getId())){ // description to be finalized if (description.getStatus().equals(DescriptionStatus.Finalized)){ throw new MyApplicationException("Description is already finalized"); } if (this.descriptionService.validate(List.of(description.getId())).getFirst().getResult().equals(DescriptionValidationOutput.Invalid)){ throw new MyApplicationException("Description is invalid"); } description.setStatus(DescriptionStatus.Finalized); description.setUpdatedAt(Instant.now()); description.setFinalizedAt(Instant.now()); this.entityManager.merge(description); } else if (description.getStatus().equals(DescriptionStatus.Draft)) { // description to be canceled description.setStatus(DescriptionStatus.Canceled); this.deleterFactory.deleter(DescriptionDeleter.class).delete(List.of(description), true); } } DmpStatus previousStatus = dmp.getStatus(); dmp.setStatus(DmpStatus.Finalized); dmp.setUpdatedAt(Instant.now()); dmp.setFinalizedAt(Instant.now()); this.entityManager.merge(dmp); this.entityManager.flush(); this.updateVersionStatusAndSave(dmp, previousStatus, dmp.getStatus()); this.entityManager.flush(); this.elasticService.persistDmp(dmp); this.sendNotification(dmp); } public void undoFinalize(UUID id, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException { this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(id)), Permission.UndoFinalizeDmp); DmpEntity dmp = this.queryFactory.query(DmpQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(id).isActive(IsActive.Active).firstAs(fields); if (dmp == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); if (!dmp.getStatus().equals(DmpStatus.Finalized)) throw new MyApplicationException("DMP is already drafted"); EntityDoiQuery entityDoiQuery = this.queryFactory.query(EntityDoiQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).types(EntityType.DMP).entityIds(dmp.getId()); if (entityDoiQuery.count() > 0) throw new MyApplicationException("DMP is deposited"); dmp.setStatus(DmpStatus.Draft); dmp.setUpdatedAt(Instant.now()); this.entityManager.merge(dmp); this.entityManager.flush(); this.updateVersionStatusAndSave(dmp, DmpStatus.Finalized, dmp.getStatus()); this.entityManager.flush(); this.sendNotification(dmp); } // invites public void inviteUserOrAssignUsers(UUID id, List users) throws InvalidApplicationException, JAXBException, IOException { this.inviteUserOrAssignUsers(id, users, true); } private List inviteUserOrAssignUsers(UUID id, List users, boolean persistUsers) throws InvalidApplicationException, JAXBException, IOException { this.authorizationService.authorizeAtLeastOneForce(List.of(this.authorizationContentResolver.dmpAffiliation(id)), Permission.InviteDmpUsers); DmpEntity dmp = this.queryFactory.query(DmpQuery.class).ids(id).first(); if (dmp == null){ throw new InvalidApplicationException("Dmp does not exist!"); } List usersToAssign = new ArrayList<>(); for (DmpUserPersist user :users) { UUID userId = null; if (user.getUser() != null){ userId = user.getUser(); } else if (user.getEmail() != null) { UserContactInfoEntity contactInfoEntity = this.queryFactory.query(UserContactInfoQuery.class).values(user.getEmail()).types(ContactInfoType.Email).first(); if (contactInfoEntity != null){ userId = contactInfoEntity.getUserId(); } } if (userId != null){ user.setUser(userId); usersToAssign.add(user); if (this.userScope.getUserId() != userId){ this.sendDmpInvitationExistingUser(user.getUser(), dmp, user.getRole()); } }else if (user.getEmail() != null) { this.sendDmpInvitationExternalUser(user.getEmail(),dmp, user.getRole()); } } if(!usersToAssign.isEmpty() && persistUsers) this.assignUsers(id, usersToAssign, null, true); return usersToAssign; } private void sendDmpInvitationExistingUser(UUID userId, DmpEntity dmp, DmpUserRole role) throws InvalidApplicationException { UserEntity recipient = this.queryFactory.query(UserQuery.class).ids(userId).isActive(IsActive.Active).first(); String email = this.queryFactory.query(UserContactInfoQuery.class).userIds(recipient.getId()).first().getValue(); this.createDmpInvitationExistingUserEvent(recipient, dmp, role, email, NotificationContactType.EMAIL); this.createDmpInvitationExistingUserEvent(recipient, dmp, role, email, NotificationContactType.IN_APP); } private void createDmpInvitationExistingUserEvent(UserEntity recipient, DmpEntity dmp, DmpUserRole role, String email, NotificationContactType type) throws InvalidApplicationException { NotifyIntegrationEvent event = new NotifyIntegrationEvent(); event.setUserId(this.userScope.getUserIdSafe()); List contactPairs = new ArrayList<>(); contactPairs.add(new ContactPair(ContactInfoType.Email, email)); NotificationContactData contactData = new NotificationContactData(contactPairs, null, null); event.setContactHint(jsonHandlingService.toJsonSafe(contactData)); event.setContactTypeHint(type); event.setNotificationType(notificationProperties.getDmpInvitationExistingUserType()); NotificationFieldData data = new NotificationFieldData(); List fieldInfoList = new ArrayList<>(); fieldInfoList.add(new FieldInfo("{recipient}", DataType.String, recipient.getName())); fieldInfoList.add(new FieldInfo("{reasonName}", DataType.String, this.queryFactory.query(UserQuery.class).ids(this.userScope.getUserIdSafe()).first().getName())); fieldInfoList.add(new FieldInfo("{dmpname}", DataType.String, dmp.getLabel())); fieldInfoList.add(new FieldInfo("{dmprole}", DataType.String, role.toString())); fieldInfoList.add(new FieldInfo("{id}", DataType.String, dmp.getId().toString())); data.setFields(fieldInfoList); event.setData(jsonHandlingService.toJsonSafe(data)); eventHandler.handle(event); } private void sendDmpInvitationExternalUser(String email, DmpEntity dmp, DmpUserRole role) throws JAXBException, InvalidApplicationException { String token = this.createActionConfirmation(email, dmp, role); NotifyIntegrationEvent event = new NotifyIntegrationEvent(); event.setUserId(this.userScope.getUserIdSafe()); List contactPairs = new ArrayList<>(); contactPairs.add(new ContactPair(ContactInfoType.Email, email)); NotificationContactData contactData = new NotificationContactData(contactPairs, null, null); event.setContactHint(jsonHandlingService.toJsonSafe(contactData)); event.setContactTypeHint(NotificationContactType.EMAIL); event.setNotificationType(notificationProperties.getDmpInvitationExternalUserType()); NotificationFieldData data = new NotificationFieldData(); List fieldInfoList = new ArrayList<>(); fieldInfoList.add(new FieldInfo("{recipient}", DataType.String, email)); fieldInfoList.add(new FieldInfo("{confirmationToken}", DataType.String, token)); fieldInfoList.add(new FieldInfo("{dmpname}", DataType.String, dmp.getLabel())); fieldInfoList.add(new FieldInfo("{dmprole}", DataType.String, role.toString())); data.setFields(fieldInfoList); event.setData(jsonHandlingService.toJsonSafe(data)); eventHandler.handle(event); } private String createActionConfirmation(String email, DmpEntity dmp, DmpUserRole role) throws JAXBException, InvalidApplicationException { ActionConfirmationPersist persist = new ActionConfirmationPersist(); persist.setType(ActionConfirmationType.DmpInvitation); persist.setStatus(ActionConfirmationStatus.Requested); persist.setToken(UUID.randomUUID().toString()); persist.setDmpInvitation(new DmpInvitationPersist(email, dmp.getId(), role)); persist.setExpiresAt(Instant.now().plusSeconds(this.notificationProperties.getEmailExpirationTimeSeconds())); validatorFactory.validator(ActionConfirmationPersist.ActionConfirmationPersistValidator.class).validateForce(persist); this.actionConfirmationService.persist(persist, null); return persist.getToken(); } public void dmpInvitationAccept(String token) { ActionConfirmationEntity action = this.queryFactory.query(ActionConfirmationQuery.class).tokens(token).types(ActionConfirmationType.DmpInvitation).isActive(IsActive.Active).first(); if (action == null){ throw new MyApplicationException("Token does not exist!"); } if (action.getStatus().equals(ActionConfirmationStatus.Accepted)){ throw new MyApplicationException("Invitation is already confirmed!"); } if (action.getExpiresAt().compareTo(Instant.now()) < 0){ throw new MyApplicationException("Token has expired!"); } DmpInvitationEntity dmpInvitation = this.xmlHandlingService.fromXmlSafe(DmpInvitationEntity.class, action.getData()); DmpUserEntity data = new DmpUserEntity(); data.setId(UUID.randomUUID()); data.setIsActive(IsActive.Active); data.setCreatedAt(Instant.now()); data.setUpdatedAt(Instant.now()); data.setRole(dmpInvitation.getRole()); data.setUserId(this.userScope.getUserIdSafe()); data.setDmpId(dmpInvitation.getDmpId()); this.entityManager.persist(data); action.setStatus(ActionConfirmationStatus.Accepted); this.entityManager.merge(action); } }