added option to update a description template if it is obsolete

This commit is contained in:
Sofia Papacharalampous 2024-04-04 17:02:43 +03:00
parent ef6970ffe6
commit c71d0e96c3
11 changed files with 214 additions and 14 deletions

View File

@ -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<UpdateDescriptionTemplatePersist> {
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<UpdateDescriptionTemplatePersist> modelClass() {
return UpdateDescriptionTemplatePersist.class;
}
@Override
protected List<Specification> 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()))
);
}
}
}

View File

@ -18,6 +18,7 @@ import eu.eudat.model.censorship.DescriptionCensor;
import eu.eudat.model.censorship.PublicDescriptionCensor; import eu.eudat.model.censorship.PublicDescriptionCensor;
import eu.eudat.model.persist.DescriptionPersist; import eu.eudat.model.persist.DescriptionPersist;
import eu.eudat.model.persist.DescriptionStatusPersist; import eu.eudat.model.persist.DescriptionStatusPersist;
import eu.eudat.model.persist.UpdateDescriptionTemplatePersist;
import eu.eudat.model.result.QueryResult; import eu.eudat.model.result.QueryResult;
import eu.eudat.query.DescriptionQuery; import eu.eudat.query.DescriptionQuery;
import eu.eudat.query.DmpQuery; 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() + "\"") .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + storageFile.getName() + (storageFile.getExtension().startsWith(".") ? "" : ".") + storageFile.getExtension() + "\"")
.body(new ByteArrayResource(file)); .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;
}
} }

View File

@ -149,3 +149,8 @@ export interface DescriptionSectionPermissionResolver {
sectionIds: Guid[]; sectionIds: Guid[];
permissions: string[]; permissions: string[];
} }
export interface UpdateDescriptionTemplatePersist {
id: Guid;
descriptionTemplateGroupId: Guid;
}

View File

@ -1,7 +1,7 @@
import { HttpClient, HttpHeaders, HttpParamsOptions, HttpResponse } from '@angular/common/http'; import { HttpClient, HttpHeaders, HttpParamsOptions, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { IsActive } from '@app/core/common/enum/is-active.enum'; 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 { DescriptionLookup } from '@app/core/query/description.lookup';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-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 }); return this.httpClient.get(`${this.apiBase}/${id}/export/${format}`, { responseType: 'blob', observe: 'response', headers: this.headers });
} }
public updateDescriptionTemplate(item: UpdateDescriptionTemplatePersist): Observable<boolean> {
const url = `${this.apiBase}/update-description-template`;
return this.http.post<boolean>(url, item).pipe(
catchError((error: any) => throwError(error)));
}
// //
// Autocomplete Commons // Autocomplete Commons
// //

View File

@ -50,8 +50,10 @@
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-select placeholder="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-TEMPLATE-PLACEHOLDER'| translate}}" [required]="true" [compareWith]="compareWith" [formControl]="formGroup.get('descriptionTemplateId')"> <mat-select placeholder="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-TEMPLATE-PLACEHOLDER'| translate}}" [required]="true" [compareWith]="compareWith" [formControl]="formGroup.get('descriptionTemplateId')">
<mat-option *ngFor="let descriptionTemplate of availableDescriptionTemplates" [value]="descriptionTemplate.id" class="multiline-mat-option"> <mat-option *ngFor="let descriptionTemplate of availableDescriptionTemplates" [value]="descriptionTemplate.id" class="multiline-mat-option">
<div>{{descriptionTemplate.label}}</div> <div>
<div>{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-TEMPLATE-VERSION'| translate}} {{descriptionTemplate.version}}</div> <span>{{descriptionTemplate.label}}, </span>
<span>{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-TEMPLATE-VERSION'| translate}} {{descriptionTemplate.version}}</span>
</div>
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="formGroup.get('descriptionTemplateId').hasError('backendError')">{{formGroup.get('descriptionTemplateId').getError('backendError').message}}</mat-error> <mat-error *ngIf="formGroup.get('descriptionTemplateId').hasError('backendError')">{{formGroup.get('descriptionTemplateId').getError('backendError').message}}</mat-error>

View File

@ -1,5 +1,6 @@
import { Component, Input } from '@angular/core'; import { Component, Input } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms'; import { UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { IsActive } from '@app/core/common/enum/is-active.enum'; import { IsActive } from '@app/core/common/enum/is-active.enum';
import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { Description } from '@app/core/model/description/description'; 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 { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
import { BaseComponent } from '@common/base/base.component'; import { BaseComponent } from '@common/base/base.component';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { DeprecatedDescriptionTemplateDialog } from './dialog-description-template/deprecated-description-template-dialog.component';
@Component({ @Component({
selector: 'app-description-base-fields-editor-component', selector: 'app-description-base-fields-editor-component',
@ -23,20 +25,55 @@ export class DescriptionBaseFieldsEditorComponent extends BaseComponent {
availableDescriptionTemplates: DescriptionTemplate[] = []; availableDescriptionTemplates: DescriptionTemplate[] = [];
viewOnly = false; //TODO: not used. viewOnly = false; //TODO: not used.
constructor( constructor(private dialog: MatDialog,
) { super(); } private descriptionService: DescriptionService) {
super();
}
ngOnInit() { ngOnInit() {
const dmpDescriptionTemplates: DmpDescriptionTemplate[] = this.description.dmp.dmpDescriptionTemplates.filter(x => x.sectionId == this.description.dmpDescriptionTemplate.sectionId && x.isActive == IsActive.Active); this.loadDescriptionTemplates();
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);
} }
public compareWith(object1: any, object2: any) { public compareWith(object1: any, object2: any) {
return object1 && object2 && object1.id === object2.id; 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);
}
});
}
} }

View File

@ -0,0 +1,26 @@
<div class="container-fluid">
<div class="row d-flex mt-2">
<div class="col-auto align-self-center">
<h4> {{ 'DESCRIPTION-EDITOR.DEPRECATED-DESCRIPTION-TEMPLATE.TITLE' | translate}} {{ data.label }}</h4>
</div>
<div class="col-auto ml-auto">
<mat-icon class="close-btn" (click)="cancel()">close</mat-icon>
</div>
</div>
<mat-dialog-content>
<div class="row">
<div class="col-12">
<span>{{ 'DESCRIPTION-EDITOR.DEPRECATED-DESCRIPTION-TEMPLATE.MESSAGE' | translate}}</span>
</div>
</div>
<div class="row mt-2">
<div class="col-auto">
<button type="button" class="default-btn" (click)="cancel()"><span>{{ 'DESCRIPTION-EDITOR.DEPRECATED-DESCRIPTION-TEMPLATE.ACTIONS.CANCEL' | translate}}</span></button>
</div>
<div class="col"></div>
<div class="col-auto">
<button type="button" class="normal-btn" (click)="update()"><span>{{ 'DESCRIPTION-EDITOR.DEPRECATED-DESCRIPTION-TEMPLATE.ACTIONS.UPDATE' | translate}}</span></button>
</div>
</div>
</mat-dialog-content>
</div>

View File

@ -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<DeprecatedDescriptionTemplateDialog>,
@Inject(MAT_DIALOG_DATA) public data: any
) { }
ngOnInit(): void {
}
cancel(): void {
this.dialogRef.close();
}
update(): void {
this.dialogRef.close(true);
}
}

View File

@ -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 { TagsFieldModule } from '@app/ui/tag/tags-field/tags-field.module';
import { PrefillDescriptionDialogComponent } from './prefill-description/prefill-description.component'; import { PrefillDescriptionDialogComponent } from './prefill-description/prefill-description.component';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; 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({ @NgModule({
imports: [ imports: [
@ -32,7 +33,8 @@ import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.mod
declarations: [ declarations: [
DescriptionEditorComponent, DescriptionEditorComponent,
DescriptionBaseFieldsEditorComponent, DescriptionBaseFieldsEditorComponent,
PrefillDescriptionDialogComponent PrefillDescriptionDialogComponent,
DeprecatedDescriptionTemplateDialog
], ],
exports: [ exports: [
], ],

View File

@ -722,6 +722,14 @@
"LOCKED-DIALOG": { "LOCKED-DIALOG": {
"TITLE": "Description is locked", "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." "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": { "DESCRIPTION-COPY-DIALOG": {