description template fixes

This commit is contained in:
amentis 2024-04-04 17:07:04 +03:00
parent ab993c43af
commit 4de68e34b2
6 changed files with 117 additions and 18 deletions

View File

@ -1,12 +1,19 @@
package eu.eudat.model.persist;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.commons.XmlHandlingService;
import eu.eudat.commons.enums.DmpAccessType;
import eu.eudat.commons.enums.DmpStatus;
import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.types.dmpblueprint.SectionEntity;
import eu.eudat.commons.validation.BaseValidator;
import eu.eudat.data.*;
import eu.eudat.query.DescriptionQuery;
import eu.eudat.query.DmpDescriptionTemplateQuery;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.validation.ValidatorFactory;
import gr.cite.tools.validation.specification.Specification;
import eu.eudat.convention.ConventionService;
import eu.eudat.data.DmpEntity;
import eu.eudat.errorcode.ErrorThesaurusProperties;
import eu.eudat.model.persist.dmpproperties.DmpPropertiesPersist;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
@ -15,6 +22,7 @@ import org.springframework.context.annotation.Scope;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
import javax.management.InvalidApplicationException;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@ -160,11 +168,17 @@ public class DmpPersist {
private final MessageSource messageSource;
private final ValidatorFactory validatorFactory;
private final TenantEntityManager entityManager;
private final XmlHandlingService xmlHandlingService;
private final QueryFactory queryFactory;
protected DmpPersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, ValidatorFactory validatorFactory) {
protected DmpPersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, ValidatorFactory validatorFactory, TenantEntityManager entityManager, XmlHandlingService xmlHandlingService, QueryFactory queryFactory) {
super(conventionService, errors);
this.messageSource = messageSource;
this.validatorFactory = validatorFactory;
this.entityManager = entityManager;
this.xmlHandlingService = xmlHandlingService;
this.queryFactory = queryFactory;
}
@Override
@ -174,6 +188,16 @@ public class DmpPersist {
@Override
protected List<Specification> specifications(DmpPersist item) {
DmpEntity dmpEntity = null;
DmpBlueprintEntity dmpBlueprintEntity = null;
try {
dmpEntity = this.isValidGuid(item.getId()) ? this.entityManager.find(DmpEntity.class, item.getId()) : null;
if(dmpEntity != null) dmpBlueprintEntity = this.isValidGuid(item.getBlueprint()) ? this.entityManager.find(DmpBlueprintEntity.class, dmpEntity.getBlueprintId()) : null;
} catch (InvalidApplicationException e) {
throw new RuntimeException(e);
}
DmpBlueprintEntity finalDmpBlueprintEntity = dmpBlueprintEntity;
return Arrays.asList(
this.spec()
.iff(() -> this.isValidGuid(item.getId()))
@ -202,6 +226,10 @@ public class DmpPersist {
.iff(() -> item.getStatus() == DmpStatus.Finalized)
.must(() -> !this.isNull(item.getProperties()))
.failOn(DmpPersist._properties).failWith(messageSource.getMessage("Validation_Required", new Object[]{DmpPersist._properties}, LocaleContextHolder.getLocale())),
this.spec()
.iff(() -> item.getStatus() == DmpStatus.Finalized)
.must(() -> this.isDescriptionTemplateMultiplicityValid(finalDmpBlueprintEntity, item.getId()))
.failOn(DmpPersist._descriptionTemplates).failWith(messageSource.getMessage("Validation.InvalidDescriptionTemplateMultiplicity", new Object[]{DmpPersist._descriptionTemplates}, LocaleContextHolder.getLocale())),
this.refSpec()
.iff(() -> !this.isNull(item.getProperties()))
.on(DmpPersist._properties)
@ -231,6 +259,42 @@ public class DmpPersist {
.using((itm) -> this.validatorFactory.validator(DmpUserPersist.DmpUserPersistValidator.class))
);
}
private boolean isDescriptionTemplateMultiplicityValid(DmpBlueprintEntity dmpBlueprintEntity, UUID dmpId){
eu.eudat.commons.types.dmpblueprint.DefinitionEntity definition = this.xmlHandlingService.fromXmlSafe(eu.eudat.commons.types.dmpblueprint.DefinitionEntity.class, dmpBlueprintEntity.getDefinition());
if (definition == null || this.isListNullOrEmpty(definition.getSections())) return true;
List<DmpDescriptionTemplateEntity> dmpDescriptionTemplateEntities = this.queryFactory.query(DmpDescriptionTemplateQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).isActive(IsActive.Active).dmpIds(dmpId).collect();
List<DescriptionEntity> descriptionEntities = this.queryFactory.query(DescriptionQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).dmpIds(dmpId).isActive(IsActive.Active).collect();
for (SectionEntity section: definition.getSections()) {
if (section.getHasTemplates() && !this.isListNullOrEmpty(section.getDescriptionTemplates())){
for (eu.eudat.commons.types.dmpblueprint.DescriptionTemplateEntity sectionDescriptionTemplate: section.getDescriptionTemplates()) {
if (sectionDescriptionTemplate.getMaxMultiplicity() == null && sectionDescriptionTemplate.getMinMultiplicity() == null ) continue;
int descriptionsCount = 0;
for (DmpDescriptionTemplateEntity dmpDescriptionTemplate: dmpDescriptionTemplateEntities) {
if(dmpDescriptionTemplate.getSectionId().equals(section.getId())) {
for (DescriptionEntity description: descriptionEntities){
if (sectionDescriptionTemplate.getDescriptionTemplateGroupId().equals(dmpDescriptionTemplate.getDescriptionTemplateGroupId())) {
if (description.getDmpDescriptionTemplateId().equals(dmpDescriptionTemplate.getId()) && dmpDescriptionTemplate.getSectionId().equals(section.getId()))
descriptionsCount++;
}
}
}
}
if (sectionDescriptionTemplate.getMinMultiplicity() != null && sectionDescriptionTemplate.getMinMultiplicity() > descriptionsCount) return false;
if (sectionDescriptionTemplate.getMaxMultiplicity() != null && sectionDescriptionTemplate.getMaxMultiplicity() < descriptionsCount) return false;
}
}
}
return true;
}
}
}

View File

@ -514,8 +514,8 @@ public class DmpBlueprintServiceImpl implements DmpBlueprintService {
DescriptionTemplateImportExport xml = new DescriptionTemplateImportExport();
xml.setDescriptionTemplateGroupId(entity.getDescriptionTemplateGroupId());
xml.setLabel(entity.getLabel());
xml.setMinMultiplicity(entity.getMinMultiplicity());
xml.setMaxMultiplicity(entity.getMaxMultiplicity());
if (entity.getMinMultiplicity() != null ) xml.setMinMultiplicity(entity.getMinMultiplicity());
if (entity.getMaxMultiplicity() != null ) xml.setMaxMultiplicity(entity.getMaxMultiplicity());
return xml;
}

View File

@ -37,15 +37,17 @@ export class FinalPreviewComponent implements OnInit {
private generatePreviewForm() {
this.descriptionTemplate = this.buildDescriptionTemplate(this.descriptionTemplatePersist);
if(this.descriptionTemplatePersist){
this.descriptionTemplate = this.buildDescriptionTemplate(this.descriptionTemplatePersist);
const mockDescription: Description = {
descriptionTemplate: this.descriptionTemplate
const mockDescription: Description = {
descriptionTemplate: this.descriptionTemplate
}
const descriptionEditorModel = new DescriptionEditorModel().fromModel(mockDescription, mockDescription.descriptionTemplate);
this.previewPropertiesFormGroup = descriptionEditorModel.properties.buildForm() as UntypedFormGroup;
this.visibilityRulesService.setContext(this.descriptionTemplate.definition, this.previewPropertiesFormGroup);
}
const descriptionEditorModel = new DescriptionEditorModel().fromModel(mockDescription, mockDescription.descriptionTemplate);
this.previewPropertiesFormGroup = descriptionEditorModel.properties.buildForm() as UntypedFormGroup;
this.visibilityRulesService.setContext(this.descriptionTemplate.definition, this.previewPropertiesFormGroup);
}

View File

@ -225,7 +225,7 @@
[datasetProfileId]="datasetProfileId"
[validationErrorModel]="editorModel.validationErrorModel"
[validationRootPath]="selectedTocEntry.validationRootPath"
(addNewFieldSet)="addNewEntry({childType: tocEntryEnumValues.FieldSet,parent: {formGroup: $event}})" (removeFieldSet)="onRemoveEntry(_findTocEntryById($event, toCEntries))" (cloneFieldSet)="cloneFieldSet($event)" (selectedEntryId)="displayItem(_findTocEntryById($event, toCEntries))" (dataNeedsRefresh)="onDataNeedsRefresh()"
(addNewFieldSet)="addNewEntry({childType: tocEntryEnumValues.FieldSet,parent: {formGroup: $event}})" (removeFieldSet)="onRemoveEntry(_findTocEntryById($event, toCEntries))" (cloneFieldSet)="cloneFieldSet($event, selectedTocEntry.validationRootPath)" (selectedEntryId)="displayItem(_findTocEntryById($event, toCEntries))" (dataNeedsRefresh)="onDataNeedsRefresh()"
>
</app-description-template-editor-section-fieldset-component>
@ -305,7 +305,7 @@
<div>
<button mat-raised-button class="template_action_btn mr-3" (click)="cancel()">{{'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.CLOSE' | translate}}</button>
<!-- <button *ngIf="!formGroup.disabled && formGroup.get('status').value!=1" [disabled]="!formGroup.valid" mat-raised-button class="template_action_btn save-btn" type="button"> -->
<button *ngIf="!formGroup.disabled && formGroup.get('status').value!=finalized" mat-raised-button class="template_action_btn save-btn" type="button">
<button [disabled]="!formGroup.valid" *ngIf="!formGroup.disabled && formGroup.get('status').value!=finalized" mat-raised-button class="template_action_btn save-btn" type="button">
<span class="d-flex flex-row row">
<span (click)="save(); formSubmit()" class="col">{{'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.SAVE' | translate}}</span>
<mat-divider [vertical]="true"></mat-divider>
@ -315,8 +315,8 @@
</span>
</button>
<mat-menu #menuSave="matMenu">
<button [disabled]="!formGroup.valid" mat-menu-item (click)="onSubmit(true)" type="button">{{ 'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.SAVE-AND-CLOSE' | translate }}</button>
<button [disabled]="!formGroup.valid" mat-menu-item (click)="onSubmit()" type="button">{{ 'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.SAVE-AND-CONTINUE' | translate }}</button>
<button [disabled]="!formGroup.valid" mat-menu-item (click)="saveWithClose(true)" type="button">{{ 'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.SAVE-AND-CLOSE' | translate }}</button>
<button [disabled]="!formGroup.valid" mat-menu-item (click)="saveWithClose(false)" type="button">{{ 'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.SAVE-AND-CONTINUE' | translate }}</button>
</mat-menu>
<!-- <button *ngIf="formGroup.disabled || formGroup.get('status').value==1" [@finalize_btn] mat-raised-button class="template_action_btn save-btn" [disabled]="!formGroup.valid" (click)="updateAndFinalize()">

View File

@ -1,6 +1,6 @@
import { Component, OnInit, QueryList, ViewChild } from '@angular/core';
import { FormArray, FormControl, UntypedFormArray, UntypedFormGroup } from '@angular/forms';
import { FormArray, FormControl, FormGroup, UntypedFormArray, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
@ -71,6 +71,7 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
selectedTocEntry: ToCEntry;
colorizeInvalid: boolean = false;
tocEntryEnumValues = ToCEntryType;
close = false;
usersMap: Map<Guid, User> = new Map<Guid, User>();
userFormControl = new FormControl();
@ -199,7 +200,9 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
refreshOnNavigateToData(id?: Guid): void {
this.formGroup.markAsPristine();
let route = [];
if(close){
this.router.navigate(['/description-templates']);
}
if (id === null) {
route.push('../..');
} else if (this.isNew) {
@ -241,6 +244,11 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
this.persistEntity();
}
saveWithClose(close: boolean){
this.close = close;
this.formSubmit();
}
public delete() {
const value = this.formGroup.value;
if (value.id) {
@ -1007,6 +1015,31 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
}
cloneFieldSet(fieldset: FormGroup, validationRootPath: string){
const values = fieldset.getRawValue();
const parentArray = fieldset.parent as FormArray;
values.id = Guid.create().toString();
values.ordinal = parentArray.length;
values.fields.forEach(element => {
element.id = Guid.create().toString()
});
const clonedModel = new DescriptionTemplateFieldSetEditorModel(this.editorModel.validationErrorModel).fromModel(values);
const clonedForm = clonedModel.buildForm({rootPath: validationRootPath + '.fieldSets[' + parentArray.length + ']' + '.fields[' + 0 + '].'});
parentArray.push(clonedForm);
//update tocentries and make selected tocentry the cloedn
let entries = this.refreshToCEntries();
const entryfound = this._findTocEntryById(clonedForm.get('id').value, entries);
if(entryfound){
this.selectedTocEntry = entryfound;
}
}
private _updateSelectedItem(tce: ToCEntry) {
if (this.selectedTocEntry) {

View File

@ -229,7 +229,7 @@ export class DescriptionTemplateDefinitionEditorModel implements DescriptionTemp
const baseContext: ValidationContext = new ValidationContext();
const baseValidationArray: Validation[] = new Array<Validation>();
baseValidationArray.push({ key: 'pages', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}pages`)] });
baseValidationArray.push({ key: 'pages', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}pages`)] });
baseContext.validation = baseValidationArray;
return baseContext;