add validation dmp

This commit is contained in:
amentis 2024-04-08 13:47:00 +03:00
parent a71b85bb6b
commit fe6bbca30b
15 changed files with 415 additions and 30 deletions

View File

@ -44,6 +44,7 @@ public class AuditableAction {
public static final EventId Dmp_PublicLookup = new EventId(5012, "Dmp_PublicLookup"); public static final EventId Dmp_PublicLookup = new EventId(5012, "Dmp_PublicLookup");
public static final EventId Dmp_Finalize = new EventId(5013, "Dmp_Finalize"); public static final EventId Dmp_Finalize = new EventId(5013, "Dmp_Finalize");
public static final EventId Dmp_Undo_Finalize = new EventId(5014, "Dmp_Undo_Finalize"); public static final EventId Dmp_Undo_Finalize = new EventId(5014, "Dmp_Undo_Finalize");
public static final EventId Dmp_Validate = new EventId(5015, "Dmp_Validate");
public static final EventId Description_Query = new EventId(6000, "Description_Query"); public static final EventId Description_Query = new EventId(6000, "Description_Query");

View File

@ -0,0 +1,30 @@
package eu.eudat.commons.enums;
import com.fasterxml.jackson.annotation.JsonValue;
import eu.eudat.data.converters.enums.DatabaseEnum;
import java.util.Map;
public enum DmpValidationOutput implements DatabaseEnum<Short> {
Valid((short) 1),
Invalid((short) 2);
private final Short value;
DmpValidationOutput(Short value) {
this.value = value;
}
@JsonValue
public Short getValue() {
return value;
}
private static final Map<Short, DmpValidationOutput> map = EnumUtils.getEnumValueMap(DmpValidationOutput.class);
public static DmpValidationOutput of(Short i) {
return map.get(i);
}
}

View File

@ -0,0 +1,51 @@
package eu.eudat.model;
import eu.eudat.commons.enums.DmpValidationOutput;
import java.util.List;
import java.util.UUID;
public class DmpValidationResult {
private UUID id;
public static final String _id = "id";
private DmpValidationOutput result;
private List<String> errors;
public static final String _result = "result";
public DmpValidationResult() {
}
public DmpValidationResult(UUID id, DmpValidationOutput result) {
this.id = id;
this.result = result;
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public DmpValidationOutput getResult() {
return result;
}
public void setResult(DmpValidationOutput result) {
this.result = result;
}
public List<String> getErrors() {
return errors;
}
public void setErrors(List<String> errors) {
this.errors = errors;
}
}

View File

@ -36,7 +36,7 @@ public class DmpCensor extends BaseCensor {
public void censor(FieldSet fields, UUID userId) { public void censor(FieldSet fields, UUID userId) {
logger.debug(new DataLogEntry("censoring fields", fields)); logger.debug(new DataLogEntry("censoring fields", fields));
if (fields.isEmpty()) if (fields == null || fields.isEmpty())
return; return;
this.authService.authorizeForce(Permission.BrowseDmp, Permission.DeferredAffiliation); this.authService.authorizeForce(Permission.BrowseDmp, Permission.DeferredAffiliation);

View File

@ -5,6 +5,7 @@ import eu.eudat.commons.XmlHandlingService;
import eu.eudat.commons.enums.DmpAccessType; import eu.eudat.commons.enums.DmpAccessType;
import eu.eudat.commons.enums.DmpStatus; import eu.eudat.commons.enums.DmpStatus;
import eu.eudat.commons.enums.IsActive; import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.types.dmpblueprint.DefinitionEntity;
import eu.eudat.commons.types.dmpblueprint.SectionEntity; import eu.eudat.commons.types.dmpblueprint.SectionEntity;
import eu.eudat.commons.validation.BaseValidator; import eu.eudat.commons.validation.BaseValidator;
import eu.eudat.data.*; import eu.eudat.data.*;
@ -188,16 +189,16 @@ public class DmpPersist {
@Override @Override
protected List<Specification> specifications(DmpPersist item) { protected List<Specification> specifications(DmpPersist item) {
DmpEntity dmpEntity = null;
DmpBlueprintEntity dmpBlueprintEntity = null; DmpBlueprintEntity dmpBlueprintEntity = null;
try { try {
dmpEntity = this.isValidGuid(item.getId()) ? this.entityManager.find(DmpEntity.class, item.getId()) : null; dmpBlueprintEntity = this.isValidGuid(item.getBlueprint()) ? this.entityManager.find(DmpBlueprintEntity.class, item.getBlueprint()) : null;
if(dmpEntity != null) dmpBlueprintEntity = this.isValidGuid(item.getBlueprint()) ? this.entityManager.find(DmpBlueprintEntity.class, dmpEntity.getBlueprintId()) : null;
} catch (InvalidApplicationException e) { } catch (InvalidApplicationException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
DmpBlueprintEntity finalDmpBlueprintEntity = dmpBlueprintEntity; DmpBlueprintEntity finalDmpBlueprintEntity = dmpBlueprintEntity;
DefinitionEntity definition = dmpBlueprintEntity == null ? null : this.xmlHandlingService.fromXmlSafe(DefinitionEntity.class, dmpBlueprintEntity.getDefinition());
return Arrays.asList( return Arrays.asList(
this.spec() this.spec()
.iff(() -> this.isValidGuid(item.getId())) .iff(() -> this.isValidGuid(item.getId()))
@ -234,7 +235,7 @@ public class DmpPersist {
.iff(() -> !this.isNull(item.getProperties())) .iff(() -> !this.isNull(item.getProperties()))
.on(DmpPersist._properties) .on(DmpPersist._properties)
.over(item.getProperties()) .over(item.getProperties())
.using(() -> this.validatorFactory.validator(DmpPropertiesPersist.DmpPropertiesPersistValidator.class).setStatus(item.getStatus())), .using(() -> this.validatorFactory.validator(DmpPropertiesPersist.DmpPropertiesPersistValidator.class).setStatus(item.getStatus()).withDefinition(definition)),
this.spec() this.spec()
.iff(() -> item.getStatus() == DmpStatus.Finalized) .iff(() -> item.getStatus() == DmpStatus.Finalized)
.must(() -> !this.isNull(item.getLanguage())) .must(() -> !this.isNull(item.getLanguage()))

View File

@ -1,6 +1,16 @@
package eu.eudat.model.persist.dmpproperties; package eu.eudat.model.persist.dmpproperties;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.commons.enums.DmpBlueprintFieldCategory;
import eu.eudat.commons.types.dmpblueprint.DefinitionEntity;
import eu.eudat.commons.types.dmpblueprint.FieldEntity;
import eu.eudat.commons.types.dmpblueprint.ReferenceTypeFieldEntity;
import eu.eudat.commons.validation.BaseValidator; import eu.eudat.commons.validation.BaseValidator;
import eu.eudat.model.DmpDescriptionTemplate;
import eu.eudat.model.ReferenceType;
import eu.eudat.query.ReferenceTypeQuery;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.validation.ValidatorFactory; import gr.cite.tools.validation.ValidatorFactory;
import gr.cite.tools.validation.specification.Specification; import gr.cite.tools.validation.specification.Specification;
import eu.eudat.convention.ConventionService; import eu.eudat.convention.ConventionService;
@ -12,7 +22,6 @@ import org.springframework.context.annotation.Scope;
import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -55,13 +64,18 @@ public class DmpBlueprintValuePersist {
public static class DmpBlueprintValuePersistValidator extends BaseValidator<DmpBlueprintValuePersist> { public static class DmpBlueprintValuePersistValidator extends BaseValidator<DmpBlueprintValuePersist> {
private final ValidatorFactory validatorFactory; private final ValidatorFactory validatorFactory;
private final QueryFactory queryFactory;
private final MessageSource messageSource; private final MessageSource messageSource;
public static final String ValidatorName = "DmpBlueprintValuePersistValidator"; public static final String ValidatorName = "DmpBlueprintValuePersistValidator";
protected DmpBlueprintValuePersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, ValidatorFactory validatorFactory, MessageSource messageSource) { private DefinitionEntity definition;
private FieldEntity fieldEntity;
protected DmpBlueprintValuePersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, ValidatorFactory validatorFactory, QueryFactory queryFactory, MessageSource messageSource) {
super(conventionService, errors); super(conventionService, errors);
this.validatorFactory = validatorFactory; this.validatorFactory = validatorFactory;
this.queryFactory = queryFactory;
this.messageSource = messageSource; this.messageSource = messageSource;
} }
@ -72,21 +86,39 @@ public class DmpBlueprintValuePersist {
@Override @Override
protected List<Specification> specifications(DmpBlueprintValuePersist item) { protected List<Specification> specifications(DmpBlueprintValuePersist item) {
fieldEntity = definition != null && this.isValidGuid(item.getFieldId())? definition.getFieldById(item.getFieldId()).stream().findFirst().orElse(null) : null;
boolean required = fieldEntity != null && fieldEntity.isRequired();
return Arrays.asList( return Arrays.asList(
// this.spec() this.spec()
// .must(() -> !this.isValidGuid(item.getFieldId())) .must(() -> this.isValidGuid(item.getFieldId()))
// .failOn(DmpBlueprintValuePersist._fieldId).failWith(messageSource.getMessage("Validation_Required", new Object[]{DmpBlueprintValuePersist._fieldId}, LocaleContextHolder.getLocale())), .failOn(DmpBlueprintValuePersist._fieldId).failWith(messageSource.getMessage("Validation_Required", new Object[]{DmpBlueprintValuePersist._fieldId}, LocaleContextHolder.getLocale())),
// this.spec() this.spec()
// .iff(() -> this.isNull(item.getReferences()) || item.getReferences().isEmpty()) .iff(() -> fieldEntity.getCategory().equals(DmpBlueprintFieldCategory.Extra) && this.isListNullOrEmpty(item.getReferences()) && required)
// .must(() -> !this.isEmpty(item.getFieldValue())) .must(() -> !this.isEmpty(item.getFieldValue()))
// .failOn(DmpBlueprintValuePersist._fieldValue).failWith(messageSource.getMessage("Validation_Required", new Object[]{DmpBlueprintValuePersist._fieldValue}, LocaleContextHolder.getLocale())), .failOn(DmpBlueprintValuePersist._fieldValue).failWith(messageSource.getMessage("Validation_Required", new Object[]{fieldEntity.getLabel()}, LocaleContextHolder.getLocale())),
this.spec()
.iff(() -> fieldEntity.getCategory().equals(DmpBlueprintFieldCategory.ReferenceType) && this.isEmpty(item.getFieldValue()) && required)
.must(() -> !this.isListNullOrEmpty(item.getReferences()))
// TODO: Cast Exception
// .failOn(DmpBlueprintValuePersist._references).failWith(messageSource.getMessage("Validation_Required", new Object[]{!this.isEmpty(fieldEntity.getLabel()) ? fieldEntity.getLabel() : this.getReferenceTypeName(((ReferenceTypeFieldEntity) fieldEntity).getReferenceTypeId())}, LocaleContextHolder.getLocale())),
.failOn(DmpBlueprintValuePersist._references).failWith(messageSource.getMessage("Validation_Required", new Object[]{!this.isEmpty(fieldEntity.getLabel()) ? fieldEntity.getLabel() : DmpBlueprintValuePersist._references}, LocaleContextHolder.getLocale())),
this.navSpec() this.navSpec()
.iff(() -> !this.isListNullOrEmpty(item.getReferences())) .iff(() -> !this.isListNullOrEmpty(item.getReferences()))
.on(DmpBlueprintValuePersist._references) .on(DmpBlueprintValuePersist._references)
.over(item.getReferences()) .over(item.getReferences())
.using((itm) -> this.validatorFactory.validator(ReferencePersist.ReferencePersistValidator.class)) .using((itm) -> this.validatorFactory.validator(ReferencePersist.ReferenceWithoutTypePersistValidator.class))
); );
} }
public DmpBlueprintValuePersistValidator withDefinition(DefinitionEntity definition) {
this.definition = definition;
return this;
}
private String getReferenceTypeName(UUID referenceTypeId){
return this.queryFactory.query(ReferenceTypeQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(referenceTypeId).firstAs(new BaseFieldSet().ensure(ReferenceType._name)).getName();
}
} }
} }

View File

@ -1,6 +1,7 @@
package eu.eudat.model.persist.dmpproperties; package eu.eudat.model.persist.dmpproperties;
import eu.eudat.commons.enums.DmpStatus; import eu.eudat.commons.enums.DmpStatus;
import eu.eudat.commons.types.dmpblueprint.DefinitionEntity;
import eu.eudat.commons.validation.BaseValidator; import eu.eudat.commons.validation.BaseValidator;
import gr.cite.tools.validation.ValidatorFactory; import gr.cite.tools.validation.ValidatorFactory;
import gr.cite.tools.validation.specification.Specification; import gr.cite.tools.validation.specification.Specification;
@ -54,6 +55,7 @@ public class DmpPropertiesPersist {
private final MessageSource messageSource; private final MessageSource messageSource;
private DmpStatus status; private DmpStatus status;
private DefinitionEntity definition;
protected DmpPropertiesPersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, ValidatorFactory validatorFactory, MessageSource messageSource) { protected DmpPropertiesPersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, ValidatorFactory validatorFactory, MessageSource messageSource) {
super(conventionService, errors); super(conventionService, errors);
@ -74,7 +76,7 @@ public class DmpPropertiesPersist {
.on(DmpPropertiesPersist._dmpBlueprintValues) .on(DmpPropertiesPersist._dmpBlueprintValues)
.over(item.getDmpBlueprintValues()) .over(item.getDmpBlueprintValues())
.mapKey((k) -> ((UUID)k).toString()) .mapKey((k) -> ((UUID)k).toString())
.using((itm) -> this.validatorFactory.validator(DmpBlueprintValuePersist.DmpBlueprintValuePersistValidator.class)), .using((itm) -> this.validatorFactory.validator(DmpBlueprintValuePersist.DmpBlueprintValuePersistValidator.class).withDefinition(definition)),
this.navSpec() this.navSpec()
.iff(() -> this.status == DmpStatus.Finalized && !this.isListNullOrEmpty(item.getContacts())) .iff(() -> this.status == DmpStatus.Finalized && !this.isListNullOrEmpty(item.getContacts()))
.on(DmpPropertiesPersist._contacts) .on(DmpPropertiesPersist._contacts)
@ -89,6 +91,11 @@ public class DmpPropertiesPersist {
return this; return this;
} }
public DmpPropertiesPersistValidator withDefinition(DefinitionEntity definition) {
this.definition = definition;
return this;
}
} }
} }

View File

@ -2,6 +2,7 @@ package eu.eudat.service.dmp;
import eu.eudat.model.Dmp; import eu.eudat.model.Dmp;
import eu.eudat.model.DmpUser; import eu.eudat.model.DmpUser;
import eu.eudat.model.DmpValidationResult;
import eu.eudat.model.persist.*; import eu.eudat.model.persist.*;
import gr.cite.tools.exception.MyApplicationException; import gr.cite.tools.exception.MyApplicationException;
import gr.cite.tools.exception.MyForbiddenException; import gr.cite.tools.exception.MyForbiddenException;
@ -28,6 +29,8 @@ public interface DmpService {
void undoFinalize(UUID id, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, IOException; void undoFinalize(UUID id, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, IOException;
DmpValidationResult validate(UUID id) throws InvalidApplicationException;
Dmp createNewVersion(NewVersionDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, IOException, TransformerException; Dmp createNewVersion(NewVersionDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, IOException, TransformerException;
Dmp buildClone(CloneDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, IOException, InvalidApplicationException; Dmp buildClone(CloneDmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, IOException, InvalidApplicationException;

View File

@ -14,6 +14,7 @@ import eu.eudat.commons.types.dmp.DmpBlueprintValueEntity;
import eu.eudat.commons.types.dmp.DmpContactEntity; import eu.eudat.commons.types.dmp.DmpContactEntity;
import eu.eudat.commons.types.dmp.DmpPropertiesEntity; import eu.eudat.commons.types.dmp.DmpPropertiesEntity;
import eu.eudat.commons.types.dmpblueprint.ReferenceTypeFieldEntity; import eu.eudat.commons.types.dmpblueprint.ReferenceTypeFieldEntity;
import eu.eudat.commons.types.dmpblueprint.SectionEntity;
import eu.eudat.commons.types.dmpreference.DmpReferenceDataEntity; import eu.eudat.commons.types.dmpreference.DmpReferenceDataEntity;
import eu.eudat.commons.types.notification.*; import eu.eudat.commons.types.notification.*;
import eu.eudat.commons.types.reference.DefinitionEntity; import eu.eudat.commons.types.reference.DefinitionEntity;
@ -32,6 +33,7 @@ import eu.eudat.model.*;
import eu.eudat.model.builder.DmpBuilder; import eu.eudat.model.builder.DmpBuilder;
import eu.eudat.model.builder.DmpUserBuilder; import eu.eudat.model.builder.DmpUserBuilder;
import eu.eudat.model.deleter.*; import eu.eudat.model.deleter.*;
import eu.eudat.model.dmpreference.DmpReferenceData;
import eu.eudat.model.file.FileEnvelope; import eu.eudat.model.file.FileEnvelope;
import eu.eudat.model.persist.*; import eu.eudat.model.persist.*;
import eu.eudat.model.persist.actionconfirmation.DmpInvitationPersist; import eu.eudat.model.persist.actionconfirmation.DmpInvitationPersist;
@ -909,6 +911,10 @@ public class DmpServiceImpl implements DmpService {
throw new MyApplicationException("DMP is already finalized"); throw new MyApplicationException("DMP is already finalized");
} }
if (this.validate(id).getResult().equals(DescriptionValidationOutput.Invalid)){
throw new MyApplicationException("Dmp is invalid");
}
List<DescriptionEntity> descriptions = this.queryFactory.query(DescriptionQuery.class) List<DescriptionEntity> descriptions = this.queryFactory.query(DescriptionQuery.class)
.authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).dmpIds(id).isActive(IsActive.Active).collect(); .authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).dmpIds(id).isActive(IsActive.Active).collect();
@ -973,6 +979,182 @@ public class DmpServiceImpl implements DmpService {
this.sendNotification(dmp); this.sendNotification(dmp);
} }
public DmpValidationResult validate(UUID id) throws InvalidApplicationException {
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()));
DmpValidationResult dmpValidationResult = new DmpValidationResult(dmp.getId(), DmpValidationOutput.Invalid);
DmpPersist.DmpPersistValidator validator = this.validatorFactory.validator(DmpPersist.DmpPersistValidator.class);
validator.validate(this.buildDmpPersist(dmp));
if (validator.result().isValid()) dmpValidationResult.setResult(DmpValidationOutput.Valid);
else dmpValidationResult.setErrors(validator.result().getErrors().stream().map(x -> x.getErrorMessage()).collect(Collectors.toList()));
return dmpValidationResult;
}
// build persist
private @NotNull DmpPersist buildDmpPersist(DmpEntity data) throws InvalidApplicationException {
DmpPersist persist = new DmpPersist();
if (data == null) return persist;
DmpBlueprintEntity dmpBlueprintEntity = this.entityManager.find(DmpBlueprintEntity.class, data.getBlueprintId());
if (dmpBlueprintEntity == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{data.getBlueprintId(), DmpBlueprint.class.getSimpleName()}, LocaleContextHolder.getLocale()));
persist.setId(data.getId());
persist.setHash(data.getId().toString());
persist.setLabel(data.getLabel());
persist.setStatus(DmpStatus.Finalized);
persist.setDescription(data.getDescription());
persist.setBlueprint(data.getBlueprintId());
persist.setAccessType(data.getAccessType());
persist.setLanguage(data.getLanguage());
List<DmpUserEntity> dmpUserEntities = this.queryFactory.query(DmpUserQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).dmpIds(data.getId()).isActives(IsActive.Active).collect();
if (!this.conventionService.isListNullOrEmpty(dmpUserEntities)){
persist.setUsers(new ArrayList<>());
for (DmpUserEntity user: dmpUserEntities) {
persist.getUsers().add(this.buildDmpUserPersist(user));
}
};
List<DmpReferenceEntity> dmpReferenceEntities = this.queryFactory.query(DmpReferenceQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).dmpIds(data.getId()).isActives(IsActive.Active).collect();
eu.eudat.commons.types.dmpblueprint.DefinitionEntity definition = this.xmlHandlingService.fromXmlSafe(eu.eudat.commons.types.dmpblueprint.DefinitionEntity.class, dmpBlueprintEntity.getDefinition());
List<DmpDescriptionTemplateEntity> dmpDescriptionTemplateEntities = this.queryFactory.query(DmpDescriptionTemplateQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).dmpIds(data.getId()).isActive(IsActive.Active).collect();
if (!this.conventionService.isListNullOrEmpty(dmpDescriptionTemplateEntities)){
persist.setDescriptionTemplates(new ArrayList<>());
for (DmpDescriptionTemplateEntity descriptionTemplateEntity: dmpDescriptionTemplateEntities) {
persist.getDescriptionTemplates().add(this.buildDmpDescriptionTemplatePersists(descriptionTemplateEntity, definition.getSections()));
}
};
persist.setProperties(this.buildDmpPropertyDefinitionPersist( this.jsonHandlingService.fromJsonSafe(DmpPropertiesEntity.class, data.getProperties()), dmpReferenceEntities, definition.getSections()));
return persist;
}
private @NotNull DmpPropertiesPersist buildDmpPropertyDefinitionPersist(DmpPropertiesEntity data, List<DmpReferenceEntity> dmpReferenceEntities, List<SectionEntity> sectionEntities){
DmpPropertiesPersist persist = new DmpPropertiesPersist();
if (data == null) return persist;
if (!this.conventionService.isListNullOrEmpty(data.getContacts())){
persist.setContacts(new ArrayList<>());
for (DmpContactEntity contact: data.getContacts()) {
persist.getContacts().add(this.buildDmpContactPersist(contact));
}
}
List<ReferenceEntity> referencesFromAllFields = new ArrayList<>();
if (!this.conventionService.isListNullOrEmpty(dmpReferenceEntities)) {
referencesFromAllFields = this.queryFactory.query(ReferenceQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(dmpReferenceEntities.stream().map(x-> x.getReferenceId()).collect(Collectors.toList())).isActive(IsActive.Active).collect();
}
if (!this.conventionService.isListNullOrEmpty(sectionEntities)){
Map<UUID, DmpBlueprintValuePersist> dmpBlueprintValues = new HashMap<>();
for (SectionEntity sectionEntity: sectionEntities) {
if (!this.conventionService.isListNullOrEmpty(sectionEntity.getFields())){
for (eu.eudat.commons.types.dmpblueprint.FieldEntity fieldEntity: sectionEntity.getFields()) {
if (!this.conventionService.isListNullOrEmpty(dmpReferenceEntities)) {
List<ReferencePersist> referencePersists = new ArrayList<>();
for (DmpReferenceEntity dmpReferenceEntity : dmpReferenceEntities) {
DmpReferenceData referenceData = this.jsonHandlingService.fromJsonSafe(DmpReferenceData.class, dmpReferenceEntity.getData());
ReferenceEntity reference = referencesFromAllFields.stream().filter(x -> x.getId().equals(dmpReferenceEntity.getReferenceId())).collect(Collectors.toList()).getFirst();
if (referenceData.getBlueprintFieldId().equals(fieldEntity.getId()) && reference != null) {
referencePersists.add(this.buildReferencePersist(reference));
// found reference
dmpBlueprintValues.put(fieldEntity.getId(), this.buildDmpBlueprintValuePersist(fieldEntity.getId(), null, referencePersists));
}
}
}
if (!this.conventionService.isListNullOrEmpty(data.getDmpBlueprintValues())) {
for (DmpBlueprintValueEntity value : data.getDmpBlueprintValues()) {
if (value.getFieldId().equals(fieldEntity.getId())) {
// found value
dmpBlueprintValues.put(fieldEntity.getId(), this.buildDmpBlueprintValuePersist(fieldEntity.getId(), value.getValue(), null));
}
}
} else {
dmpBlueprintValues.put(fieldEntity.getId(), this.buildDmpBlueprintValuePersist(fieldEntity.getId(), null, null));
}
}
}
}
persist.setDmpBlueprintValues(dmpBlueprintValues);
}
return persist;
}
private @NotNull DmpContactPersist buildDmpContactPersist(DmpContactEntity data){
DmpContactPersist persist = new DmpContactPersist();
if (data == null) return persist;
persist.setEmail(data.getEmail());
persist.setLastName(data.getLastName());
persist.setFirstName(data.getFirstName());
persist.setUserId(data.getUserId());
return persist;
}
private @NotNull DmpUserPersist buildDmpUserPersist(DmpUserEntity data){
DmpUserPersist persist = new DmpUserPersist();
if (data == null) return persist;
persist.setUser(data.getUserId());
persist.setSectionId(data.getSectionId());
persist.setRole(data.getRole());
return persist;
}
private @NotNull DmpDescriptionTemplatePersist buildDmpDescriptionTemplatePersists(DmpDescriptionTemplateEntity data, List<SectionEntity> sectionEntities){
DmpDescriptionTemplatePersist persist = new DmpDescriptionTemplatePersist();
if (data == null) return persist;
persist.setSectionId(data.getSectionId());
persist.setDescriptionTemplateGroupId(data.getDescriptionTemplateGroupId());
return persist;
}
private @NotNull ReferencePersist buildReferencePersist(ReferenceEntity data){
ReferencePersist persist = new ReferencePersist();
if (data == null) return persist;
persist.setLabel(data.getLabel());
persist.setReference(data.getReference());
persist.setAbbreviation(data.getAbbreviation());
persist.setDescription(data.getDescription());
persist.setSource(data.getSource());
persist.setSourceType(data.getSourceType());
persist.setReference(data.getReference());
persist.setTypeId(data.getTypeId());
return persist;
}
private @NotNull DmpBlueprintValuePersist buildDmpBlueprintValuePersist(UUID fieldId, String fieldValue, List<ReferencePersist> referencePersists){
DmpBlueprintValuePersist persist = new DmpBlueprintValuePersist();
persist.setFieldId(fieldId);
if (!this.conventionService.isListNullOrEmpty(referencePersists)){
persist.setReferences(referencePersists);
}else if (fieldValue != null){
persist.setFieldValue(fieldValue);
}
return persist;
}
// invites // invites
public void inviteUserOrAssignUsers(UUID id, List<DmpUserPersist> users) throws InvalidApplicationException, JAXBException, IOException { public void inviteUserOrAssignUsers(UUID id, List<DmpUserPersist> users) throws InvalidApplicationException, JAXBException, IOException {
this.inviteUserOrAssignUsers(id, users, true); this.inviteUserOrAssignUsers(id, users, true);

View File

@ -202,6 +202,21 @@ public class DmpController {
return true; return true;
} }
@GetMapping("validate/{id}")
public DmpValidationResult validate(@PathVariable("id") UUID id) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException {
logger.debug(new MapLogEntry("validating" + Dmp.class.getSimpleName()).And("id", id));
this.censorFactory.censor(DmpCensor.class).censor(null, null);
DmpValidationResult result = this.dmpService.validate(id);
this.auditService.track(AuditableAction.Dmp_Validate, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("id", id)
));
return result;
}
@PostMapping("clone") @PostMapping("clone")
@Transactional @Transactional
@ValidationFilterAnnotation(validator = CloneDmpPersist.CloneDmpPersistValidator.ValidatorName, argumentName = "model") @ValidationFilterAnnotation(validator = CloneDmpPersist.CloneDmpPersistValidator.ValidatorName, argumentName = "model")

View File

@ -19,6 +19,7 @@ import { CloneDmpPersist, Dmp, DmpPersist, DmpUser, DmpUserInvitePersist, DmpUse
import { AuthService } from '../auth/auth.service'; import { AuthService } from '../auth/auth.service';
import { ConfigurationService } from '../configuration/configuration.service'; import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpV2Service } from '../http/base-http-v2.service'; import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { DmpValidationResult } from '@app/ui/dmp/dmp-finalize-dialog/dmp-finalize-dialog.component';
@Injectable() @Injectable()
export class DmpService { export class DmpService {
@ -110,6 +111,14 @@ export class DmpService {
catchError((error: any) => throwError(error))); catchError((error: any) => throwError(error)));
} }
validate(id: Guid): Observable<DmpValidationResult> {
const url = `${this.apiBase}/validate/${id}`;
return this.http
.get<DmpValidationResult>(url).pipe(
catchError((error: any) => throwError(error)));
}
clone(item: CloneDmpPersist, reqFields: string[] = []): Observable<Dmp> { clone(item: CloneDmpPersist, reqFields: string[] = []): Observable<Dmp> {
const url = `${this.apiBase}/clone`; const url = `${this.apiBase}/clone`;
const options = { params: { f: reqFields } }; const options = { params: { f: reqFields } };

View File

@ -263,12 +263,11 @@ export class DmpEditorComponent extends BaseEditor<DmpEditorModel, Dmp> implemen
formSubmit(): void { formSubmit(): void {
this.formService.removeAllBackEndErrors(this.formGroup); this.formService.removeAllBackEndErrors(this.formGroup);
this.formService.touchAllFormFields(this.formGroup); this.formService.touchAllFormFields(this.formGroup);
if (!this.isFormValid()) { if (this.formGroup.get('label').valid && this.formGroup.get('blueprint').valid && this.formGroup.get('status').valid
return; && this.formGroup.get('descriptionTemplates').valid) {
}
this.persistEntity(); this.persistEntity();
} }
}
public delete() { public delete() {
const value = this.formGroup.value; const value = this.formGroup.value;

View File

@ -19,7 +19,7 @@
</mat-expansion-panel-header> </mat-expansion-panel-header>
{{ dmp.description }} {{ dmp.description }}
</mat-expansion-panel> </mat-expansion-panel>
<mat-expansion-panel [expanded]="true"> <mat-expansion-panel [expanded]="true" *ngIf="isDmpValid">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
{{ 'DMP-FINALISE-DIALOG.DESCRPIPTIONS' | translate }} {{ 'DMP-FINALISE-DIALOG.DESCRPIPTIONS' | translate }}
@ -37,7 +37,7 @@
</ng-container> </ng-container>
:</span> :</span>
{{ description.label }} {{ description.label }}
<i *ngIf="!isDescriptionValid(description.id)" class="fa fa-spinner fa-spin" ></i> <i *ngIf="(descriptionValidationOutputMap.get(description.id) != descriptionValidationOutputEnum.Invalid) && (descriptionValidationOutputMap.get(description.id) != descriptionValidationOutputEnum.Valid)" class="fa fa-spinner fa-spin" ></i>
</h4> </h4>
<h4 *ngIf="description.status == descriptionStatusEnum.Finalized" class="col-11 ml-auto mt-1 mb-4">{{ description.label }}</h4> <h4 *ngIf="description.status == descriptionStatusEnum.Finalized" class="col-11 ml-auto mt-1 mb-4">{{ description.label }}</h4>
</div> </div>
@ -56,7 +56,15 @@
</div> </div>
</mat-selection-list> </mat-selection-list>
</div> </div>
<mat-error *ngIf="getFinalizedDescriptions().length === 0 && descriptionsToBeFinalized.length === 0"> <ng-container *ngIf="isDmpValid == false">
<mat-error>
{{ 'DMP-FINALISE-DIALOG.VALIDATION.INVALID-DMP' | translate }}
</mat-error>
<mat-error>
{{ dmpErrors }}
</mat-error>
</ng-container>
<mat-error *ngIf="getFinalizedDescriptions().length === 0 && descriptionsToBeFinalized.length === 0 && isDmpValid">
{{'DMP-FINALISE-DIALOG.VALIDATION.AT-LEAST-ONE-DESCRPIPTION-FINALISED' | translate}} {{'DMP-FINALISE-DIALOG.VALIDATION.AT-LEAST-ONE-DESCRPIPTION-FINALISED' | translate}}
</mat-error> </mat-error>
</div> </div>

View File

@ -5,6 +5,7 @@ import { DescriptionStatus } from '@app/core/common/enum/description-status';
import { DmpAccessType } from '@app/core/common/enum/dmp-access-type'; import { DmpAccessType } from '@app/core/common/enum/dmp-access-type';
import { Dmp } from '@app/core/model/dmp/dmp'; import { Dmp } from '@app/core/model/dmp/dmp';
import { DescriptionService } from '@app/core/services/description/description.service'; import { DescriptionService } from '@app/core/services/description/description.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { BaseComponent } from '@common/base/base.component'; import { BaseComponent } from '@common/base/base.component';
import { Guid } from '@common/types/guid'; import { Guid } from '@common/types/guid';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
@ -18,16 +19,20 @@ import { takeUntil } from 'rxjs/operators';
export class DmpFinalizeDialogComponent extends BaseComponent implements OnInit { export class DmpFinalizeDialogComponent extends BaseComponent implements OnInit {
dmp: Dmp; dmp: Dmp;
isDmpValid: boolean;
dmpErrors: string[];
dmpAccessTypeEnum = DmpAccessType; dmpAccessTypeEnum = DmpAccessType;
descriptionStatusEnum = DescriptionStatus; descriptionStatusEnum = DescriptionStatus;
descriptionValidationOutputEnum = DescriptionValidationOutput; descriptionValidationOutputEnum = DescriptionValidationOutput;
validationResults: DescriptionValidationResult[] = []; validationResults: DescriptionValidationResult[] = [];
descriptionsToBeFinalized: Guid[] = []; descriptionsToBeFinalized: Guid[] = [];
descriptionValidationOutputMap = new Map<Guid, DescriptionValidationOutput>();
constructor( constructor(
public router: Router, public router: Router,
public dialogRef: MatDialogRef<DmpFinalizeDialogComponent>, public dialogRef: MatDialogRef<DmpFinalizeDialogComponent>,
public descriptionService: DescriptionService, public descriptionService: DescriptionService,
private dmpService: DmpService,
@Inject(MAT_DIALOG_DATA) public data: any @Inject(MAT_DIALOG_DATA) public data: any
) { ) {
super(); super();
@ -35,11 +40,26 @@ export class DmpFinalizeDialogComponent extends BaseComponent implements OnInit
} }
ngOnInit(): void { ngOnInit(): void {
this.dmpService.validate(this.dmp.id).pipe(takeUntil(this._destroyed),
).subscribe(result => {
if (result.result === DmpValidationOutput.Valid){
this.validateDescriptions(this.dmp); this.validateDescriptions(this.dmp);
this.isDmpValid = true;
}else{
this.isDmpValid = false;
this.dmpErrors = result.errors;
}
});
} }
isDescriptionValid(descriptionId: Guid): boolean { isDescriptionValid(descriptionId: Guid): boolean {
return this.validationResults.find(x => x.descriptionId == descriptionId)?.result === DescriptionValidationOutput.Valid; const result = this.validationResults.find(x => x.descriptionId == descriptionId)?.result === DescriptionValidationOutput.Valid;
if (result){
this.descriptionValidationOutputMap.set(descriptionId, DescriptionValidationOutput.Valid);
} else{
this.descriptionValidationOutputMap.set(descriptionId, DescriptionValidationOutput.Invalid);
}
return result;
} }
onSubmit() { onSubmit() {
@ -48,7 +68,13 @@ export class DmpFinalizeDialogComponent extends BaseComponent implements OnInit
getFinalizedDescriptions() { getFinalizedDescriptions() {
if (!this.dmp.descriptions) return []; if (!this.dmp.descriptions) return [];
return this.dmp.descriptions.filter(x => x.status === DescriptionStatus.Finalized); const finalizedDescriptions = this.dmp.descriptions.filter(x => x.status === DescriptionStatus.Finalized);
if (finalizedDescriptions?.length > 0){
finalizedDescriptions.forEach(finalize => {
this.descriptionValidationOutputMap.set(finalize.id, DescriptionValidationOutput.Valid);
})
}
return finalizedDescriptions;
} }
close() { close() {
@ -58,6 +84,13 @@ export class DmpFinalizeDialogComponent extends BaseComponent implements OnInit
validateDescriptions(dmp: Dmp) { validateDescriptions(dmp: Dmp) {
if (!dmp.descriptions?.some(x => x.status == DescriptionStatus.Draft)) return; if (!dmp.descriptions?.some(x => x.status == DescriptionStatus.Draft)) return;
const draftDescriptions = this.dmp.descriptions.filter(x => x.status == DescriptionStatus.Draft) || [];
if ( draftDescriptions.length > 0){
draftDescriptions.forEach(draft => {
this.descriptionValidationOutputMap.set(draft.id, DescriptionValidationOutput.Pending);
});
}
this.descriptionService.validate(dmp.descriptions.filter(x => x.status == DescriptionStatus.Draft).map(x => x.id)).pipe(takeUntil(this._destroyed), this.descriptionService.validate(dmp.descriptions.filter(x => x.status == DescriptionStatus.Draft).map(x => x.id)).pipe(takeUntil(this._destroyed),
).subscribe(result => { ).subscribe(result => {
this.validationResults = result; this.validationResults = result;
@ -76,10 +109,23 @@ export interface DescriptionValidationResult {
} }
export enum DescriptionValidationOutput { export enum DescriptionValidationOutput {
Valid = 1,
Invalid = 2,
Pending = 3
}
export interface DmpValidationResult {
id: Guid;
result: DmpValidationOutput;
errors: string[];
}
export enum DmpValidationOutput {
Valid = 1, Valid = 1,
Invalid = 2 Invalid = 2
} }
export interface DmpFinalizeDialogOutput { export interface DmpFinalizeDialogOutput {
cancelled?: boolean; cancelled?: boolean;
descriptionsToBeFinalized?: Guid[]; descriptionsToBeFinalized?: Guid[];

View File

@ -1915,7 +1915,8 @@
"EMPTY": "No Descriptions for this Plan so far", "EMPTY": "No Descriptions for this Plan so far",
"FINALISE-TITLE": "Do you want to finalize any of the following Draft Descriptions?", "FINALISE-TITLE": "Do you want to finalize any of the following Draft Descriptions?",
"VALIDATION": { "VALIDATION": {
"AT-LEAST-ONE-DESCRPIPTION-FINALISED": "You need to have at least one Description Finalized" "AT-LEAST-ONE-DESCRPIPTION-FINALISED": "You need to have at least one Description Finalized",
"INVALID-DMP": "This Plan can not be finalized "
}, },
"IMPACT": "This action will finalize your Plan, and you won't be able to edit it again.", "IMPACT": "This action will finalize your Plan, and you won't be able to edit it again.",
"PUBLIC-DMP-MESSAGE": "After finalizing your Plan, it'll be published and be publicly available to the {{ APP_NAME_CAPS }} tool.", "PUBLIC-DMP-MESSAGE": "After finalizing your Plan, it'll be published and be publicly available to the {{ APP_NAME_CAPS }} tool.",