diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/persist/UpdateDescriptionTemplatePersist.java b/dmp-backend/core/src/main/java/eu/eudat/model/persist/UpdateDescriptionTemplatePersist.java new file mode 100644 index 000000000..2598c726a --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/persist/UpdateDescriptionTemplatePersist.java @@ -0,0 +1,72 @@ +package eu.eudat.model.persist; + +import eu.eudat.commons.validation.BaseValidator; +import eu.eudat.convention.ConventionService; +import eu.eudat.errorcode.ErrorThesaurusProperties; +import gr.cite.tools.validation.specification.Specification; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.MessageSource; +import org.springframework.context.annotation.Scope; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +public class UpdateDescriptionTemplatePersist { + + private UUID id; + + public static final String _id = "id"; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + private UUID descriptionTemplateGroupId; + + public static final String _descriptionTemplateGroupId = "descriptionTemplateGroupId"; + + public UUID getDescriptionTemplateGroupId() { + return descriptionTemplateGroupId; + } + + public void setDescriptionTemplateGroupId(UUID descriptionTemplateGroupId) { + this.descriptionTemplateGroupId = descriptionTemplateGroupId; + } + + @Component(UpdateDescriptionTemplatePersistValidator.ValidatorName) + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public static class UpdateDescriptionTemplatePersistValidator extends BaseValidator { + + public static final String ValidatorName = "UpdateDescriptionTemplatePersistValidator"; + + private final MessageSource messageSource; + + protected UpdateDescriptionTemplatePersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource) { + super(conventionService, errors); + this.messageSource = messageSource; + } + + @Override + protected Class modelClass() { + return UpdateDescriptionTemplatePersist.class; + } + + @Override + protected List specifications(UpdateDescriptionTemplatePersist item) { + return Arrays.asList( + this.spec() + .must(() -> this.isValidGuid(item.getId())) + .failOn(UpdateDescriptionTemplatePersist._id) + .failWith(messageSource.getMessage("Validation_Required", new Object[]{UpdateDescriptionTemplatePersist._id}, LocaleContextHolder.getLocale())) + ); + } + } + +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DescriptionController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DescriptionController.java index 005c04e6c..bd0e03269 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DescriptionController.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DescriptionController.java @@ -18,6 +18,7 @@ import eu.eudat.model.censorship.DescriptionCensor; import eu.eudat.model.censorship.PublicDescriptionCensor; import eu.eudat.model.persist.DescriptionPersist; import eu.eudat.model.persist.DescriptionStatusPersist; +import eu.eudat.model.persist.UpdateDescriptionTemplatePersist; import eu.eudat.model.result.QueryResult; import eu.eudat.query.DescriptionQuery; import eu.eudat.query.DmpQuery; @@ -267,4 +268,15 @@ public class DescriptionController { .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + storageFile.getName() + (storageFile.getExtension().startsWith(".") ? "" : ".") + storageFile.getExtension() + "\"") .body(new ByteArrayResource(file)); } + + @PostMapping("update-description-template") +// @Transactional + @ValidationFilterAnnotation(validator = UpdateDescriptionTemplatePersist.UpdateDescriptionTemplatePersistValidator.ValidatorName, argumentName = "model") + public Boolean updateDescriptionTemplate(@RequestBody UpdateDescriptionTemplatePersist model) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, IOException { + logger.debug(new MapLogEntry("persisting" + Description.class.getSimpleName()).And("model", model)); + + // TODO + + return true; + } } diff --git a/dmp-frontend/src/app/core/model/description/description.ts b/dmp-frontend/src/app/core/model/description/description.ts index 1f722dff8..781672c47 100644 --- a/dmp-frontend/src/app/core/model/description/description.ts +++ b/dmp-frontend/src/app/core/model/description/description.ts @@ -149,3 +149,8 @@ export interface DescriptionSectionPermissionResolver { sectionIds: Guid[]; permissions: string[]; } + +export interface UpdateDescriptionTemplatePersist { + id: Guid; + descriptionTemplateGroupId: Guid; +} diff --git a/dmp-frontend/src/app/core/services/description/description.service.ts b/dmp-frontend/src/app/core/services/description/description.service.ts index 4bcc22e32..eb0f75948 100644 --- a/dmp-frontend/src/app/core/services/description/description.service.ts +++ b/dmp-frontend/src/app/core/services/description/description.service.ts @@ -1,7 +1,7 @@ import { HttpClient, HttpHeaders, HttpParamsOptions, HttpResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { IsActive } from '@app/core/common/enum/is-active.enum'; -import { Description, DescriptionPersist, DescriptionSectionPermissionResolver, DescriptionStatusPersist, PublicDescription } from '@app/core/model/description/description'; +import { Description, DescriptionPersist, DescriptionSectionPermissionResolver, DescriptionStatusPersist, PublicDescription, UpdateDescriptionTemplatePersist } from '@app/core/model/description/description'; import { DescriptionLookup } from '@app/core/query/description.lookup'; import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; @@ -114,6 +114,13 @@ export class DescriptionService { return this.httpClient.get(`${this.apiBase}/${id}/export/${format}`, { responseType: 'blob', observe: 'response', headers: this.headers }); } + public updateDescriptionTemplate(item: UpdateDescriptionTemplatePersist): Observable { + const url = `${this.apiBase}/update-description-template`; + + return this.http.post(url, item).pipe( + catchError((error: any) => throwError(error))); + } + // // Autocomplete Commons // diff --git a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.html b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.html index d322083b9..f17d13496 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.html +++ b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.html @@ -50,8 +50,10 @@ -
{{descriptionTemplate.label}}
-
{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-TEMPLATE-VERSION'| translate}} {{descriptionTemplate.version}}
+
+ {{descriptionTemplate.label}}, + {{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-TEMPLATE-VERSION'| translate}} {{descriptionTemplate.version}} +
{{formGroup.get('descriptionTemplateId').getError('backendError').message}} diff --git a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.ts b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.ts index 2fa09a366..635649175 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.ts @@ -1,5 +1,6 @@ import { Component, Input } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; +import { MatDialog } from '@angular/material/dialog'; import { IsActive } from '@app/core/common/enum/is-active.enum'; import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; import { Description } from '@app/core/model/description/description'; @@ -10,6 +11,7 @@ import { DescriptionService } from '@app/core/services/description/description.s import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/operators'; +import { DeprecatedDescriptionTemplateDialog } from './dialog-description-template/deprecated-description-template-dialog.component'; @Component({ selector: 'app-description-base-fields-editor-component', @@ -23,20 +25,55 @@ export class DescriptionBaseFieldsEditorComponent extends BaseComponent { availableDescriptionTemplates: DescriptionTemplate[] = []; viewOnly = false; //TODO: not used. - constructor( - ) { super(); } + constructor(private dialog: MatDialog, + private descriptionService: DescriptionService) { + super(); + } ngOnInit() { - const dmpDescriptionTemplates: DmpDescriptionTemplate[] = this.description.dmp.dmpDescriptionTemplates.filter(x => x.sectionId == this.description.dmpDescriptionTemplate.sectionId && x.isActive == IsActive.Active); - const currentVersionsOfDescriptionTemplates = dmpDescriptionTemplates.map(x => x.currentDescriptionTemplate); - //Check if the used tempalte in included in the current list. If not add it. - if (this.description.descriptionTemplate && currentVersionsOfDescriptionTemplates.find(x => x.id == this.description?.descriptionTemplate?.id) == null) { - this.availableDescriptionTemplates.push(this.description.descriptionTemplate) - } - this.availableDescriptionTemplates.push(...currentVersionsOfDescriptionTemplates); + this.loadDescriptionTemplates(); } public compareWith(object1: any, object2: any) { return object1 && object2 && object1.id === object2.id; - } + } + + private loadDescriptionTemplates(): void { + const dmpDescriptionTemplates: DmpDescriptionTemplate[] = this.description.dmp.dmpDescriptionTemplates.filter(x => x.sectionId == this.description.dmpDescriptionTemplate.sectionId && x.isActive == IsActive.Active); + const currentVersionsOfDescriptionTemplates = dmpDescriptionTemplates.map(x => x.currentDescriptionTemplate); + if (this.description.descriptionTemplate && currentVersionsOfDescriptionTemplates.find(x => x.id == this.description?.descriptionTemplate?.id) == null) { + if (this.description.status === 0) { + this.openDeprecatedDescriptionTemplateDialog(); + } else { + this.availableDescriptionTemplates.push(this.description.descriptionTemplate); + } + } + this.availableDescriptionTemplates.push(...currentVersionsOfDescriptionTemplates); + } + + private openDeprecatedDescriptionTemplateDialog(): void { + const dialogRef = this.dialog.open(DeprecatedDescriptionTemplateDialog, { + data: { + label: this.description.descriptionTemplate.label + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe( + result => { + if(result) { + this.descriptionService.updateDescriptionTemplate({ + id: this.description.id, + descriptionTemplateGroupId: this.description.descriptionTemplate.groupId + }) + .subscribe( + result => { + if (result) { + this.loadDescriptionTemplates(); + } + }, + error => console.error(error)); + } else { + this.availableDescriptionTemplates.push(this.description.descriptionTemplate); + } + }); + } } diff --git a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/dialog-description-template/deprecated-description-template-dialog.component.html b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/dialog-description-template/deprecated-description-template-dialog.component.html new file mode 100644 index 000000000..de174b192 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/dialog-description-template/deprecated-description-template-dialog.component.html @@ -0,0 +1,26 @@ +
+
+
+

{{ 'DESCRIPTION-EDITOR.DEPRECATED-DESCRIPTION-TEMPLATE.TITLE' | translate}} {{ data.label }}

+
+
+ close +
+
+ +
+
+ {{ 'DESCRIPTION-EDITOR.DEPRECATED-DESCRIPTION-TEMPLATE.MESSAGE' | translate}} +
+
+
+
+ +
+
+
+ +
+
+
+
diff --git a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/dialog-description-template/deprecated-description-template-dialog.component.scss b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/dialog-description-template/deprecated-description-template-dialog.component.scss new file mode 100644 index 000000000..ae3e36775 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/dialog-description-template/deprecated-description-template-dialog.component.scss @@ -0,0 +1,4 @@ + +.close-btn:hover{ + cursor: pointer; +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/dialog-description-template/deprecated-description-template-dialog.component.ts b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/dialog-description-template/deprecated-description-template-dialog.component.ts new file mode 100644 index 000000000..23315d490 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/dialog-description-template/deprecated-description-template-dialog.component.ts @@ -0,0 +1,25 @@ +import { Component, Inject, OnInit } from "@angular/core"; +import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog"; + +@Component({ + selector: 'app-deprecated-description-template-dialog', + templateUrl: 'deprecated-description-template-dialog.component.html', + styleUrls: ['deprecated-description-template-dialog.component.scss'] +}) +export class DeprecatedDescriptionTemplateDialog implements OnInit { + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any + ) { } + + ngOnInit(): void { + } + + cancel(): void { + this.dialogRef.close(); + } + + update(): void { + this.dialogRef.close(true); + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.module.ts b/dmp-frontend/src/app/ui/description/editor/description-editor.module.ts index 55b7b6c4d..d1ae96d26 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-editor.module.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.module.ts @@ -14,6 +14,7 @@ import { RichTextEditorModule } from '@app/library/rich-text-editor/rich-text-ed import { TagsFieldModule } from '@app/ui/tag/tags-field/tags-field.module'; import { PrefillDescriptionDialogComponent } from './prefill-description/prefill-description.component'; import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { DeprecatedDescriptionTemplateDialog } from './description-base-fields-editor/dialog-description-template/deprecated-description-template-dialog.component'; @NgModule({ imports: [ @@ -32,7 +33,8 @@ import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.mod declarations: [ DescriptionEditorComponent, DescriptionBaseFieldsEditorComponent, - PrefillDescriptionDialogComponent + PrefillDescriptionDialogComponent, + DeprecatedDescriptionTemplateDialog ], exports: [ ], diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index d99d18a79..078dbeef4 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -722,6 +722,14 @@ "LOCKED-DIALOG": { "TITLE": "Description is locked", "MESSAGE": "Somebody else is modifying the description at this moment. You may view the description but you cannot make any changes. If you would like to modify it please come back later." + }, + "DEPRECATED-DESCRIPTION-TEMPLATE": { + "TITLE": "Found a newer version of ", + "MESSAGE": "The selected description template has become obsolete. Would you like to update it?", + "ACTIONS": { + "CANCEL": "Cancel", + "UPDATE": "Update" + } } }, "DESCRIPTION-COPY-DIALOG": {