diff --git a/dmp-backend/core/src/main/java/eu/eudat/errorcode/ErrorThesaurusProperties.java b/dmp-backend/core/src/main/java/eu/eudat/errorcode/ErrorThesaurusProperties.java index 525e3014f..7ae85ad8d 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/errorcode/ErrorThesaurusProperties.java +++ b/dmp-backend/core/src/main/java/eu/eudat/errorcode/ErrorThesaurusProperties.java @@ -74,4 +74,44 @@ public class ErrorThesaurusProperties { public void setDmpIsFinalized(ErrorDescription dmpIsFinalized) { this.dmpIsFinalized = dmpIsFinalized; } + + private ErrorDescription dmpCanNotChange; + + public ErrorDescription getDmpCanNotChange() { + return dmpCanNotChange; + } + + public void setDmpCanNotChange(ErrorDescription dmpCanNotChange) { + this.dmpCanNotChange = dmpCanNotChange; + } + + private ErrorDescription dmpDescriptionTemplateCanNotChange; + + public ErrorDescription getDmpDescriptionTemplateCanNotChange() { + return dmpDescriptionTemplateCanNotChange; + } + + public void setDmpDescriptionTemplateCanNotChange(ErrorDescription dmpDescriptionTemplateCanNotChange) { + this.dmpDescriptionTemplateCanNotChange = dmpDescriptionTemplateCanNotChange; + } + + private ErrorDescription invalidDescriptionTemplate; + + public ErrorDescription getInvalidDescriptionTemplate() { + return invalidDescriptionTemplate; + } + + public void setInvalidDescriptionTemplate(ErrorDescription invalidDescriptionTemplate) { + this.invalidDescriptionTemplate = invalidDescriptionTemplate; + } + + private ErrorDescription descriptionIsFinalized; + + public ErrorDescription getDescriptionIsFinalized() { + return descriptionIsFinalized; + } + + public void setDescriptionIsFinalized(ErrorDescription descriptionIsFinalized) { + this.descriptionIsFinalized = descriptionIsFinalized; + } } diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/Dmp.java b/dmp-backend/core/src/main/java/eu/eudat/model/Dmp.java index 838110ab1..f815edd2e 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/model/Dmp.java +++ b/dmp-backend/core/src/main/java/eu/eudat/model/Dmp.java @@ -99,6 +99,10 @@ public class Dmp { public static final String _descriptions = "descriptions"; + private List entityDois; + + public static final String _entityDois = "entityDois"; + public UUID getId() { return id; } @@ -274,4 +278,12 @@ public class Dmp { public void setDescriptions(List descriptions) { this.descriptions = descriptions; } + + public List getEntityDois() { + return entityDois; + } + + public void setEntityDois(List entityDois) { + this.entityDois = entityDois; + } } diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/builder/DmpBuilder.java b/dmp-backend/core/src/main/java/eu/eudat/model/builder/DmpBuilder.java index 33470d18f..061843e29 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/model/builder/DmpBuilder.java +++ b/dmp-backend/core/src/main/java/eu/eudat/model/builder/DmpBuilder.java @@ -1,6 +1,7 @@ package eu.eudat.model.builder; import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.commons.enums.EntityType; import eu.eudat.convention.ConventionService; import eu.eudat.data.DmpEntity; import eu.eudat.model.*; @@ -54,6 +55,9 @@ public class DmpBuilder extends BaseBuilder { List models = new ArrayList<>(); + FieldSet entityDoisFields = fields.extractPrefixed(this.asPrefix(Dmp._entityDois)); + Map> entityDoisMap = this.collectEntityDois(entityDoisFields, data); + FieldSet dmpReferencesFields = fields.extractPrefixed(this.asPrefix(Dmp._dmpReferences)); Map> dmpReferencesMap = this.collectDmpReferences(dmpReferencesFields, data); @@ -89,6 +93,7 @@ public class DmpBuilder extends BaseBuilder { if (fields.hasField(this.asIndexer(Dmp._hash))) m.setHash(this.hashValue(d.getUpdatedAt())); if (!userFields.isEmpty() && userItemsMap != null && userItemsMap.containsKey(d.getCreatorId())) m.setCreator(userItemsMap.get(d.getCreatorId())); if (!blueprintFields.isEmpty() && blueprintItemsMap != null && blueprintItemsMap.containsKey(d.getBlueprintId())) m.setBlueprint(blueprintItemsMap.get(d.getBlueprintId())); + if (entityDoisMap != null && !entityDoisMap.isEmpty() && entityDoisMap.containsKey(d.getId())) m.setEntityDois(entityDoisMap.get(d.getId())); if (dmpReferencesMap != null && !dmpReferencesMap.isEmpty() && dmpReferencesMap.containsKey(d.getId())) m.setDmpReferences(dmpReferencesMap.get(d.getId())); if (dmpUsersMap != null && !dmpUsersMap.isEmpty() && dmpUsersMap.containsKey(d.getId())) m.setDmpUsers(dmpUsersMap.get(d.getId())); if (descriptionsMap != null && !descriptionsMap.isEmpty() && descriptionsMap.containsKey(d.getId())) m.setDescriptions(descriptionsMap.get(d.getId())); @@ -117,7 +122,25 @@ public class DmpBuilder extends BaseBuilder { return itemMap; } - + + private Map> collectEntityDois(FieldSet fields, List data) throws MyApplicationException { + if (fields.isEmpty() || data.isEmpty()) return null; + this.logger.debug("checking related - {}", EntityDoi.class.getSimpleName()); + + Map> itemMap; + FieldSet clone = new BaseFieldSet(fields.getFields()).ensure(this.asIndexer(EntityDoi._entityId)); + EntityDoiQuery query = this.queryFactory.query(EntityDoiQuery.class).authorize(this.authorize).types(EntityType.DMP).entityIds(data.stream().map(DmpEntity::getId).distinct().collect(Collectors.toList())); + itemMap = this.builderFactory.builder(EntityDoiBuilder.class).authorize(this.authorize).asMasterKey(query, clone, EntityDoi::getEntityId); + + if (!fields.hasField(this.asIndexer(EntityDoi._entityId))) { + itemMap.values().stream().flatMap(List::stream).filter(x -> x != null && x.getEntityId() != null).peek(x -> { + x.setEntityId(null); + }); + } + + return itemMap; + } + private Map collectDmpBlueprints(FieldSet fields, List data) throws MyApplicationException { if (fields.isEmpty() || data.isEmpty()) return null; diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/censorship/DmpCensor.java b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/DmpCensor.java index 51528bdf7..806a0250a 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/model/censorship/DmpCensor.java +++ b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/DmpCensor.java @@ -46,6 +46,7 @@ public class DmpCensor extends BaseCensor { this.censorFactory.censor(DmpReferenceCensor.class).censor(dmpReferencesFields, userId); FieldSet creatorFields = fields.extractPrefixed(this.asIndexerPrefix(Dmp._creator)); this.censorFactory.censor(UserCensor.class).censor(creatorFields, userId); + FieldSet doisFields = fields.extractPrefixed(this.asIndexerPrefix(Dmp._entityDois)); + this.censorFactory.censor(EntityDoiCensor.class).censor(doisFields, userId); } - } diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java index d72208a37..08416d1c4 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/description/DescriptionServiceImpl.java @@ -17,8 +17,7 @@ import eu.eudat.data.*; import eu.eudat.errorcode.ErrorThesaurusProperties; import eu.eudat.event.DescriptionTouchedEvent; import eu.eudat.event.EventBroker; -import eu.eudat.model.Description; -import eu.eudat.model.DescriptionReference; +import eu.eudat.model.*; import eu.eudat.model.builder.DescriptionBuilder; import eu.eudat.model.deleter.DescriptionDeleter; import eu.eudat.model.deleter.DescriptionReferenceDeleter; @@ -54,9 +53,7 @@ import org.springframework.stereotype.Service; import javax.management.InvalidApplicationException; import java.io.IOException; import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; @Service @@ -130,32 +127,104 @@ public class DescriptionServiceImpl implements DescriptionService { data = this.entityManager.find(DescriptionEntity.class, model.getId()); if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), Description.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 (data.getStatus() == DescriptionStatus.Finalized) throw new MyForbiddenException("Can not update finalized template"); + if (data.getStatus().equals(DescriptionStatus.Finalized)) throw new MyValidationException(this.errors.getDescriptionIsFinalized().getCode(), this.errors.getDescriptionIsFinalized().getMessage()); + if (!data.getDmpId().equals(model.getDmpId())) throw new MyValidationException(this.errors.getDmpCanNotChange().getCode(), this.errors.getDmpCanNotChange().getMessage()); + if (!data.getDmpDescriptionTemplateId().equals(model.getDmpDescriptionTemplateId())) throw new MyValidationException(this.errors.getDmpDescriptionTemplateCanNotChange().getCode(), this.errors.getDmpDescriptionTemplateCanNotChange().getMessage()); } else { data = new DescriptionEntity(); data.setId(UUID.randomUUID()); data.setIsActive(IsActive.Active); data.setCreatedAt(Instant.now()); + data.setDmpId(model.getDmpId()); + data.setDmpDescriptionTemplateId(model.getDmpDescriptionTemplateId()); } + DmpDescriptionTemplateEntity dmpDescriptionTemplate = this.entityManager.find(DmpDescriptionTemplateEntity.class, data.getDescriptionTemplateId()); + if (dmpDescriptionTemplate == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{data.getDescriptionTemplateId(), DmpDescriptionTemplate.class.getSimpleName()}, LocaleContextHolder.getLocale())); + + DescriptionTemplateEntity descriptionTemplateEntity = this.entityManager.find(DescriptionTemplateEntity.class, model.getDescriptionTemplateId()); + if (descriptionTemplateEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getDescriptionTemplateId(), DescriptionTemplate.class.getSimpleName()}, LocaleContextHolder.getLocale())); + + if (!dmpDescriptionTemplate.getDescriptionTemplateGroupId().equals(descriptionTemplateEntity.getGroupId())) throw new MyValidationException(this.errors.getInvalidDescriptionTemplate().getCode(), this.errors.getInvalidDescriptionTemplate().getMessage()); + + DmpEntity dmp = this.entityManager.find(DmpEntity.class, data.getDmpId()); + if (dmp == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{data.getDmpId(), Dmp.class.getSimpleName()}, LocaleContextHolder.getLocale())); + + if (dmp.getStatus().equals(DmpStatus.Finalized) && isUpdate) throw new MyValidationException(this.errors.getDmpIsFinalized().getCode(), this.errors.getDmpIsFinalized().getMessage()); + data.setLabel(model.getLabel()); data.setProperties(this.jsonHandlingService.toJson(this.buildPropertyDefinitionEntity(model.getProperties()))); data.setStatus(model.getStatus()); data.setDescription(model.getDescription()); data.setDescriptionTemplateId(model.getDescriptionTemplateId()); - data.setDmpDescriptionTemplateId(model.getDmpDescriptionTemplateId()); data.setUpdatedAt(Instant.now()); if (isUpdate) this.entityManager.merge(data); else this.entityManager.persist(data); this.persistTags(data.getId(), model.getTags()); + this.persistDescriptionReferences(data.getId(), model.getReferences()); this.entityManager.flush(); + + if (isUpdate){ + if (!data.getStatus() .equals(DescriptionStatus.Finalized)) { + //TODO + //this.sendNotification(dataset1, dataset1.getDmp(), userInfo, NotificationType.DATASET_MODIFIED); + } else { + //TODO + //this.sendNotification(dataset1, dataset1.getDmp(), userInfo, NotificationType.DATASET_MODIFIED_FINALISED); + } + } + //this.deleteOldFilesAndAddNew(datasetWizardModel, userInfo); //TODO this.eventBroker.emit(new DescriptionTouchedEvent(data.getId())); return this.builderFactory.builder(DescriptionBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(BaseFieldSet.build(fields, Description._id), data); } + public void descriptionForce(DescriptionEntity description) throws Exception { + List datasetProfileValidators = new LinkedList<>(); + DescriptionTemplateEntity descriptionTemplateEntity = this.entityManager.find(DescriptionTemplateEntity.class, description.getDescriptionTemplateId()); + if (descriptionTemplateEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{description.getDescriptionTemplateId(), DescriptionTemplate.class.getSimpleName()}, LocaleContextHolder.getLocale())); + eu.eudat.commons.types.descriptiontemplate.DefinitionEntity definition = this.xmlHandlingService.fromXml(eu.eudat.commons.types.descriptiontemplate.DefinitionEntity.class, descriptionTemplateEntity.getDefinition()); +// DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); +// DocumentBuilder builder = builderFactory.newDocumentBuilder(); +// Document xmlDocument = builder.parse(new ByteArrayInputStream(profile.getDefinition().getBytes())); +// +// XPath xPath = XPathFactory.newInstance().newXPath(); +// String expression = "//validation/@type[.=1]/ancestor::field/@id"; +// NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET); +// +// for (int i = 0; i < nodeList.getLength(); i++) { +// Node node = nodeList.item(i); +// datasetProfileValidators.add(node.getNodeValue()); +// } +// +// expression = "//validation/@type[.=1]/ancestor::fieldSet"; +// nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET); +// +// +// JSONObject obj = new JSONObject(description.getProperties()); +// VisibilityRuleService visibilityRuleService = new VisibilityRuleServiceImpl(); +// visibilityRuleService.setProperties(obj.toMap()); +// +// description.setProfile(profile); +// PagedDatasetProfile pagedDatasetProfile = this.getPagedProfile(new DatasetWizardModel(), description); +// visibilityRuleService.buildVisibilityContext(pagedDatasetProfile.getRules()); +// +// +// String failedField = null; +// +// for (String validator : datasetProfileValidators) { +// if (obj.has(validator) && isNullOrEmpty(obj.getString(validator)) && isElementVisible(nodeList, validator, visibilityRuleService)) { +// //throw new Exception("Field value of " + validator + " must be filled."); +// failedField = validator; +// break; +// } +// } + +// return failedField; + } + @Override public Description persistStatus(DescriptionStatusPersist model, FieldSet fields) { logger.debug(new MapLogEntry("persisting data dmp").And("model", model).And("fields", fields)); @@ -246,63 +315,69 @@ public class DescriptionServiceImpl implements DescriptionService { this.deleterFactory.deleter(DescriptionTagDeleter.class).delete(toDelete); } + + private void persistDescriptionReferences(UUID id, List persists) throws InvalidApplicationException { + if (persists == null) persists = new ArrayList<>(); - private void persistDescriptionReferences(UUID id, List models) throws InvalidApplicationException { - if (models == null) models = new ArrayList<>(); - - List items = this.queryFactory.query(DescriptionReferenceQuery.class).isActive(IsActive.Active).descriptionIds(id).collect(); - List existingReferences = this.queryFactory.query(ReferenceQuery.class).isActive(IsActive.Active).ids(models.stream().filter(x-> this.conventionService.isValidGuid(x.getReference().getId())).map(x-> x.getReference().getId()).distinct().toList()).collect(); + List existingItems = this.queryFactory.query(DescriptionReferenceQuery.class).isActive(IsActive.Active).descriptionIds(id).collect(); + Map existingReferencesMap = this.queryFactory.query(ReferenceQuery.class).isActive(IsActive.Active).ids(persists.stream().filter(x-> x.getReference().getId() != null).map(x-> x.getReference().getId()).toList()).collect() + .stream() + .collect(Collectors.toMap(ReferenceEntity::getId, x-> x));; List updatedCreatedIds = new ArrayList<>(); - for (DescriptionReferencePersist model : models) { - Boolean isUpdate = this.conventionService.isValidGuid(model.getId()); + for (DescriptionReferencePersist persist : persists) { + Boolean isUpdate = this.conventionService.isValidGuid(persist.getId()); + DescriptionReferenceEntity data; if (isUpdate) { - data = items.stream().filter(x -> x.getId().equals(model.getId())).findFirst().orElse(null); - if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), DescriptionReference.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 (!data.getReferenceId().equals(model.getReference().getId())) throw new MyForbiddenException("Can not change reference of DescriptionReferenceEntity"); + data = this.entityManager.find(DescriptionReferenceEntity.class, persist.getId()); + if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{persist.getId(), DescriptionReference.class.getSimpleName()}, LocaleContextHolder.getLocale())); + if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(persist.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); + if (!data.getReferenceId().equals(persist.getReference().getId())) throw new MyValidationException("reference can not changed"); } else { data = new DescriptionReferenceEntity(); data.setId(UUID.randomUUID()); - data.setIsActive(IsActive.Active); + data.setDescriptionId(id); data.setCreatedAt(Instant.now()); + data.setIsActive(IsActive.Active); } - ReferenceEntity referenceEntity = this.persisReference(existingReferences, model.getReference()); - data.setReferenceId(referenceEntity.getId()); - data.setUpdatedAt(Instant.now()); + ReferenceEntity reference = this.persistReference(existingReferencesMap, persist.getReference()); + data.setReferenceId(reference.getId()); + data.setUpdatedAt(Instant.now()); + if (isUpdate) this.entityManager.merge(data); else 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()); + List toDelete = existingItems.stream().filter(x-> updatedCreatedIds.stream().noneMatch(y-> y.equals(x.getId()))).collect(Collectors.toList()); this.deleterFactory.deleter(DescriptionReferenceDeleter.class).delete(toDelete); } + + private ReferenceEntity persistReference(Map existingReferencesMap , ReferencePersist persist){ + Boolean isUpdate = this.conventionService.isValidGuid(persist.getId()); - private ReferenceEntity persisReference(List existingReferences, ReferencePersist model) throws InvalidApplicationException { - Boolean isUpdate = this.conventionService.isValidGuid(model.getId()); ReferenceEntity data; if (isUpdate) { - data = existingReferences.stream().filter(x -> x.getId().equals(model.getId())).findFirst().orElse(null); - if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), DescriptionReference.class.getSimpleName()}, LocaleContextHolder.getLocale())); - if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(model.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); + data = this.entityManager.find(ReferenceEntity.class, persist.getId()); + if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{persist.getId(), Reference.class.getSimpleName()}, LocaleContextHolder.getLocale())); + if (!this.conventionService.hashValue(data.getUpdatedAt()).equals(persist.getHash())) throw new MyValidationException(this.errors.getHashConflict().getCode(), this.errors.getHashConflict().getMessage()); } else { data = new ReferenceEntity(); data.setId(UUID.randomUUID()); - data.setIsActive(IsActive.Active); data.setCreatedAt(Instant.now()); + data.setIsActive(IsActive.Active); } + data.setDefinition(this.xmlHandlingService.toXmlSafe(this.buildDefinitionEntity(persist.getDefinition()))); + data.setUpdatedAt(Instant.now()); + data.setReference(persist.getReference()); + data.setAbbreviation(persist.getAbbreviation()); + data.setSource(persist.getSource()); + data.setSourceType(persist.getSourceType()); + data.setUpdatedAt(Instant.now()); - data.setDefinition(this.xmlHandlingService.toXmlSafe(this.buildDefinitionEntity(model.getDefinition()))); - data.setUpdatedAt(Instant.now()); - data.setReference(model.getReference()); - data.setAbbreviation(model.getAbbreviation()); - data.setSource(model.getSource()); - data.setSourceType(model.getSourceType()); - data.setUpdatedAt(Instant.now()); if (isUpdate) this.entityManager.merge(data); else this.entityManager.persist(data); diff --git a/dmp-backend/web/src/main/resources/config/errors.yml b/dmp-backend/web/src/main/resources/config/errors.yml index dc198536b..e3600eae7 100644 --- a/dmp-backend/web/src/main/resources/config/errors.yml +++ b/dmp-backend/web/src/main/resources/config/errors.yml @@ -35,3 +35,15 @@ error-thesaurus: dmp-is-finalized: code: 116 message: To perform this action you will need to revert DMP's finalisation + dmp-can-not-change: + code: 117 + message: dmp can not change + dmp-description-template-can-not-change: + code: 118 + message: dmp description template can not change + invalid-description-template: + code: 118 + message: invalid description template id + description-is-finalized: + code: 119 + message: To perform this action you will need to revert description finalisation