diff --git a/smp-angular/src/app/app.module.ts b/smp-angular/src/app/app.module.ts index 05debf8ebc86740ce995dd75db4732464a2682d3..9f02ed3493493b08d9f120862c9d834e82e6ada0 100644 --- a/smp-angular/src/app/app.module.ts +++ b/smp-angular/src/app/app.module.ts @@ -188,6 +188,9 @@ import { import { ReviewDocumentPanelComponent } from "./common/panels/review-tasks-panel/review-document-panel/review-document-panel.component"; +import { + DocumentMetadataPanelComponent +} from "./common/panels/document-edit-panel/document-metadata-panel/document-metadata-panel.component"; @NgModule({ @@ -224,6 +227,7 @@ import { DocumentEventsPanelComponent, DocumentPropertiesPanelComponent, DocumentPropertyDialogComponent, + DocumentMetadataPanelComponent, DocumentVersionsPanelComponent, DomainGroupComponent, DomainPanelComponent, diff --git a/smp-angular/src/app/common/model/document-metadata-ro.model.ts b/smp-angular/src/app/common/model/document-metadata-ro.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..af3894c1c5dc1c5db038cc75c4a6492d50d2c390 --- /dev/null +++ b/smp-angular/src/app/common/model/document-metadata-ro.model.ts @@ -0,0 +1,11 @@ +import {SearchTableEntity} from "../search-table/search-table-entity.model"; + +export interface DocumentMetadataRo extends SearchTableEntity { + name?: string; + mimeType?: string; + sharingEnabled?: boolean; + referenceDocumentId?: string; + allVersions?: number[]; + publishedVersion?: number; +} + diff --git a/smp-angular/src/app/common/model/document-ro.model.ts b/smp-angular/src/app/common/model/document-ro.model.ts index c5ec808d8cebbcdbfbe88fbaef0f1ce687d0532f..c1cf99b0cadc8a3baa69afbf440cb4cfc0d7dd70 100644 --- a/smp-angular/src/app/common/model/document-ro.model.ts +++ b/smp-angular/src/app/common/model/document-ro.model.ts @@ -6,6 +6,7 @@ import { } from "./document-version-ro.model"; import {DocumentVersionEventRo} from "./document-version-event-ro.model"; import {DocumentVersionsStatus} from "../enums/document-versions-status.enum"; +import {DocumentMetadataRo} from "./document-metadata-ro.model"; export interface DocumentRo extends SearchTableEntity { mimeType?: string; @@ -21,5 +22,6 @@ export interface DocumentRo extends SearchTableEntity { documentVersionStatus?: DocumentVersionsStatus; documentVersionEvents?: DocumentVersionEventRo[]; documentVersions?: DocumentVersionRo[]; + metadata?: DocumentMetadataRo; } diff --git a/smp-angular/src/app/common/panels/document-edit-panel/document-edit-panel.component.html b/smp-angular/src/app/common/panels/document-edit-panel/document-edit-panel.component.html index 7d74a66f4be763ecc472bb24ee13f39e4c5847c5..421cf2232f40b91bd5844b77996c33f13032edc3 100644 --- a/smp-angular/src/app/common/panels/document-edit-panel/document-edit-panel.component.html +++ b/smp-angular/src/app/common/panels/document-edit-panel/document-edit-panel.component.html @@ -106,6 +106,12 @@ </smp-warning-panel> </div> <expandable-panel> + <expandable-item icon="description" + title="{{'document.metadata.panel.tab.title' | translate }}" + buttonLabel="{{'document.metadata.panel.tab.button.properties' | translate }}"> + <document-metadata-panel formControlName="documentMetadata" + ngDefaultControl></document-metadata-panel> + </expandable-item> <expandable-item icon="settings" title="{{'document.properties.panel.tab.title' | translate }}" buttonLabel="{{'document.properties.panel.tab.button.properties' | translate }}"> diff --git a/smp-angular/src/app/common/panels/document-edit-panel/document-edit-panel.component.ts b/smp-angular/src/app/common/panels/document-edit-panel/document-edit-panel.component.ts index eb676f82bd2ab500e8a2ee832891af5babb209b6..b6533c56d648be2faae7fa0d0a251f49dd921404 100644 --- a/smp-angular/src/app/common/panels/document-edit-panel/document-edit-panel.component.ts +++ b/smp-angular/src/app/common/panels/document-edit-panel/document-edit-panel.component.ts @@ -210,6 +210,7 @@ export class DocumentEditPanelComponent implements BeforeLeaveGuard, OnInit { 'documentVersionStatus': new FormControl({value: null}), 'documentVersionEvents': new FormControl({value: null}), 'documentVersions': new FormControl({value: null}), + 'documentMetadata': new FormControl({value: null}), }); this.resource = editResourceService.selectedResource; @@ -247,14 +248,13 @@ export class DocumentEditPanelComponent implements BeforeLeaveGuard, OnInit { } else { this.isResourceDocument = false; } - - } - ngOnInit(): void { if (this.editorMode === SmpDocumentEditorType.REVIEW_EDITOR) { this.initFromDocumentReview(); + } else { + this.isResourceDocument = this.editorMode === SmpDocumentEditorType.RESOURCE_EDITOR; } if (this.editorMode === SmpDocumentEditorType.REVIEW_EDITOR && !this.reviewDocument @@ -274,7 +274,6 @@ export class DocumentEditPanelComponent implements BeforeLeaveGuard, OnInit { @Input() set document(value: DocumentRo) { this._document = value; this.documentForm.disable(); - console.log("Document with properties: " + value?.properties) if (!!value) { this.documentEditor.mimeType = value.mimeType; this.documentForm.controls['mimeType'].setValue(value.mimeType); @@ -287,7 +286,9 @@ export class DocumentEditPanelComponent implements BeforeLeaveGuard, OnInit { this.documentForm.controls['documentVersionStatus'].setValue(value.documentVersionStatus); this.documentForm.controls['documentVersionEvents'].setValue(value.documentVersionEvents); this.documentForm.controls['documentVersions'].setValue(value.documentVersions); + this.documentForm.controls['documentMetadata'].setValue(value.metadata); // the method documentVersionsExists already uses the current value to check if versions exists + if (this.documentVersionsExists && this.isNotReviewMode) { this.documentForm.controls['payloadVersion'].enable(); } @@ -296,7 +297,6 @@ export class DocumentEditPanelComponent implements BeforeLeaveGuard, OnInit { } } else { this.documentForm.controls['name'].setValue(""); - this.documentForm.controls['payload'].setValue(""); this.documentForm.controls['currentResourceVersion'].setValue(""); this.documentForm.controls['payloadVersion'].setValue(""); this.documentForm.controls['payloadCreatedOn'].setValue(""); @@ -305,6 +305,7 @@ export class DocumentEditPanelComponent implements BeforeLeaveGuard, OnInit { this.documentForm.controls['documentVersionStatus'].setValue(""); this.documentForm.controls['documentVersionEvents'].setValue([]); this.documentForm.controls['documentVersions'].setValue([]); + this.documentForm.controls['documentMetadata'].setValue(null); } this.documentForm.markAsPristine(); } @@ -314,8 +315,13 @@ export class DocumentEditPanelComponent implements BeforeLeaveGuard, OnInit { if (this.documentForm.controls['payload'].dirty) { doc.payload = this.documentForm.controls['payload'].value; doc.payloadStatus = EntityStatus.UPDATED; + } else { + // no need to send payload if not changed + doc.payload = null; } + // set new properties doc.properties = this.documentForm.controls['properties'].value; + doc.metadata = this.documentForm.controls['documentMetadata'].value; return doc; } @@ -520,10 +526,12 @@ export class DocumentEditPanelComponent implements BeforeLeaveGuard, OnInit { // set from current document documentVersions: this.documentForm.controls['documentVersions'].value, properties: this.documentForm.controls['properties'].value, + metadata: this.documentForm.controls['documentMetadata'].value, } as DocumentRo; // set as current this.document = docRequest; this.documentForm.markAsDirty(); + this.documentForm.controls['payload'].markAsDirty(); } onSelectionDocumentVersionChanged(): void { diff --git a/smp-angular/src/app/common/panels/document-edit-panel/document-metadata-panel/document-metadata-panel.component.html b/smp-angular/src/app/common/panels/document-edit-panel/document-metadata-panel/document-metadata-panel.component.html new file mode 100644 index 0000000000000000000000000000000000000000..7f4a335ff614bee6f9952c3e2f7c2e398745c2f4 --- /dev/null +++ b/smp-angular/src/app/common/panels/document-edit-panel/document-metadata-panel/document-metadata-panel.component.html @@ -0,0 +1,35 @@ +<div id="document-metadata-panel" + [formGroup]="documentMetadataForm"> + + <mat-form-field style="min-width: 180px" + subscriptSizing="dynamic" + appearance="fill"> + <mat-label>{{ "document.metadata.panel.label.name" | translate }}</mat-label> + <input matInput id="name_id" + formControlName="name" + readonly> + </mat-form-field> + <mat-form-field style="min-width: 180px" + subscriptSizing="dynamic" + appearance="fill"> + <mat-label>{{ "document.metadata.panel.label.mimetype" | translate }}</mat-label> + <input matInput id="mimeType_id" + formControlName="mimeType" + readonly> + </mat-form-field> + + <mat-form-field style="min-width: 180px" + subscriptSizing="dynamic" + appearance="fill"> + <mat-label>{{ "document.metadata.panel.label.published.version" | translate }}</mat-label> + <input matInput id="publishedVersion_id" + formControlName="publishedVersion" + readonly> + </mat-form-field> + <mat-checkbox formControlName="sharingEnabled" + matTooltip="{{ 'document.metadata.panel.label.sharing.enabled' | translate }}" + id="sharingEnabled_id"> + {{ "document.metadata.panel.label.sharing.enabled" | translate }} + </mat-checkbox> +</div> + diff --git a/smp-angular/src/app/common/panels/document-edit-panel/document-metadata-panel/document-metadata-panel.component.scss b/smp-angular/src/app/common/panels/document-edit-panel/document-metadata-panel/document-metadata-panel.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..1742cb8ef27597392c89a83b3a84af4803125af5 --- /dev/null +++ b/smp-angular/src/app/common/panels/document-edit-panel/document-metadata-panel/document-metadata-panel.component.scss @@ -0,0 +1,7 @@ +#document-metadata-panel { + display: flex; + flex-direction: column; + flex-grow: 1; + padding: 0 1em; + min-width: 600px; +} diff --git a/smp-angular/src/app/common/panels/document-edit-panel/document-metadata-panel/document-metadata-panel.component.ts b/smp-angular/src/app/common/panels/document-edit-panel/document-metadata-panel/document-metadata-panel.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d1437d96717284cf1019d6b568e8f87f01adb93 --- /dev/null +++ b/smp-angular/src/app/common/panels/document-edit-panel/document-metadata-panel/document-metadata-panel.component.ts @@ -0,0 +1,165 @@ +/*- + * #START_LICENSE# + * smp-webapp + * %% + * Copyright (C) 2017 - 2024 European Commission | eDelivery | DomiSMP + * %% + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent + * versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and limitations under the Licence. + * #END_LICENSE# + */ +import { + AfterViewInit, + Component, + forwardRef, + Input, + ViewChild, +} from '@angular/core'; +import { + ControlContainer, + ControlValueAccessor, + FormBuilder, + FormControl, + FormControlDirective, + FormGroup, + NG_VALUE_ACCESSOR +} from "@angular/forms"; +import {MatDialog} from "@angular/material/dialog"; +import { + BeforeLeaveGuard +} from "../../../../window/sidenav/navigation-on-leave-guard"; +import {GlobalLookups} from "../../../global-lookups"; +import {TranslateService} from "@ngx-translate/core"; +import { + HttpErrorHandlerService +} from "../../../error/http-error-handler.service"; +import {DocumentMetadataRo} from "../../../model/document-metadata-ro.model"; + +/** + * Component to display the properties of a document in a table. The properties can be edited and saved. + * @author Joze Rihtarsic + * @since 5.1 + */ +@Component({ + selector: 'document-metadata-panel', + templateUrl: './document-metadata-panel.component.html', + styleUrls: ['./document-metadata-panel.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => DocumentMetadataPanelComponent), + multi: true + } + ] +}) +export class DocumentMetadataPanelComponent implements AfterViewInit, BeforeLeaveGuard, ControlValueAccessor { + + dataChanged = false; + private onChangeCallback: (_: any) => void = () => { + }; + + _documentMetadata: DocumentMetadataRo; + documentMetadataForm: FormGroup; + + constructor( + private globalLookups: GlobalLookups, + public dialog: MatDialog, + private controlContainer: ControlContainer, + private formBuilder: FormBuilder, + private translateService: TranslateService, + private httpErrorHandlerService: HttpErrorHandlerService) { + + this.documentMetadataForm = formBuilder.group({ + 'name': new FormControl({value: null}), + 'mimeType': new FormControl({value: null}), + 'publishedVersion': new FormControl({value: null}), + 'sharingEnabled': new FormControl({value: null}), + 'allVersions': new FormControl({value: null}), + 'referenceDocumentId': new FormControl({value: null}), + }); + } + + + @ViewChild(FormControlDirective, {static: true}) + formControlDirective: FormControlDirective; + @Input() + formControl: FormControl; + + @Input() + formControlName: string; /* get hold of FormControl instance no matter formControl or formControlName is given. If formControlName is given, then this.controlContainer.control is the parent FormGroup (or FormArray) instance. */ + get control() { + return this.formControl || this.controlContainer.control.get(this.formControlName); + } + + /** + * Implementation of the ControlValueAccessor method to write value to the component. + * @param eventList + */ + writeValue(data: DocumentMetadataRo): void { + this.documentMetadata = data; + } + + ngAfterViewInit() { + + } + + + isDirty(): boolean { + return this.documentMetadataForm.dirty; + } + + registerOnChange(fn: any): void { + this.onChangeCallback = fn; + + } + + registerOnTouched(fn: any): void { + // not implemented + } + + setDisabledState(isDisabled: boolean): void { + // not implemented + } + + + @Input() set documentMetadata(value: DocumentMetadataRo) { + this._documentMetadata = value; + this.documentMetadataForm.disable(); + + if (!!value) { + this.documentMetadataForm.controls['name'].setValue(value.name); + this.documentMetadataForm.controls['mimeType'].setValue(value.mimeType); + this.documentMetadataForm.controls['publishedVersion'].setValue(value.publishedVersion); + this.documentMetadataForm.controls['allVersions'].setValue(value.allVersions); + this.documentMetadataForm.controls['referenceDocumentId'].setValue(value.referenceDocumentId); + this.documentMetadataForm.controls['sharingEnabled'].setValue(value.sharingEnabled); + } else { + this.documentMetadataForm.controls['name'].setValue(""); + this.documentMetadataForm.controls['mimeType'].setValue(""); + this.documentMetadataForm.controls['publishedVersion'].setValue(""); + this.documentMetadataForm.controls['allVersions'].setValue([]); + this.documentMetadataForm.controls['referenceDocumentId'].setValue(""); + this.documentMetadataForm.controls['sharingEnabled'].setValue(false); + this.documentMetadataForm.controls['properties'].setValue([]); + } + this.documentMetadataForm.markAsPristine(); + } + + get documentMetadata(): DocumentMetadataRo { + let docMetadata: DocumentMetadataRo = {...this._documentMetadata}; + + // set new properties + docMetadata.sharingEnabled = this.documentMetadataForm.controls['sharingEnabled'].value; + docMetadata.name = this.documentMetadataForm.controls['name'].value; + docMetadata.referenceDocumentId = this.documentMetadataForm.controls['referenceDocumentId'].value; + return docMetadata; + } +} diff --git a/smp-angular/src/app/common/panels/document-versions-panel/document-versions-panel.component.ts b/smp-angular/src/app/common/panels/document-versions-panel/document-versions-panel.component.ts index 559fcba50d9c5d7ff6169b9d23b9e900f4c5aec4..be54e6334daaf4cbc984f7161790469947ce2fa4 100644 --- a/smp-angular/src/app/common/panels/document-versions-panel/document-versions-panel.component.ts +++ b/smp-angular/src/app/common/panels/document-versions-panel/document-versions-panel.component.ts @@ -104,8 +104,6 @@ export class DocumentVersionsPanelComponent implements AfterViewInit, BeforeLeav this.selected = selectedVersion; } - - /** * Method to handle row selection * @param row diff --git a/smp-angular/src/assets/i18n/en.json b/smp-angular/src/assets/i18n/en.json index 33d514440f85b313f845fa009322c3352862f506..0bcfdf4defd079dde93da02cb8f87d28746e259e 100644 --- a/smp-angular/src/assets/i18n/en.json +++ b/smp-angular/src/assets/i18n/en.json @@ -419,6 +419,15 @@ "document.edit.panel.tooltip.version.reject": "Submit selected document version for the review", "document.edit.panel.note.editable": "Note: Only documents in following status can be edited: [{{editableDocStatusList}}]", + "document.metadata.panel.tab.title": "Document metadata", + "document.metadata.panel.tab.button.metadata": "Metadata", + + "document.metadata.panel.label.name": "Name", + "document.metadata.panel.label.mimetype": "Mimetype", + "document.metadata.panel.label.published.version": "Published version", + "document.metadata.panel.label.sharing.enabled": "Document sharing enabled", + "document.metadata.panel.label.reference.document": "Referenced document", + "review.edit.panel.label.review": "Review", "review.edit.panel.label.column.date": "Review date", "review.edit.panel.label.column.version": "Version", diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DocumentMetadataRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DocumentMetadataRO.java new file mode 100644 index 0000000000000000000000000000000000000000..5f4399ff94336453cc5a133450a134ff33c2880b --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DocumentMetadataRO.java @@ -0,0 +1,86 @@ +/*- + * #START_LICENSE# + * smp-server-library + * %% + * Copyright (C) 2017 - 2024 European Commission | eDelivery | DomiSMP + * %% + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent + * versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and limitations under the Licence. + * #END_LICENSE# + */ +package eu.europa.ec.edelivery.smp.data.ui; + +import java.util.ArrayList; +import java.util.List; + +/** + * 'DocumentMetadataRO' represents the metadata of a document. + * + * @author Joze RIHTARSIC + * @since 5.1 + */ +public class DocumentMetadataRO extends BaseRO { + private static final long serialVersionUID = 9008583888835630040L; + + String name; + String mimeType; + String referenceDocumentId; + Integer publishedVersion; + List<Integer> allVersions; + Boolean sharingEnabled = Boolean.FALSE; + + public String getReferenceDocumentId() { + return referenceDocumentId; + } + + public void setReferenceDocumentId(String referenceDocumentId) { + this.referenceDocumentId = referenceDocumentId; + } + + public String getMimeType() { + return mimeType; + } + + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + public Integer getPublishedVersion() { + return publishedVersion; + } + + public void setPublishedVersion(Integer publishedVersion) { + this.publishedVersion = publishedVersion; + } + + public List<Integer> getAllVersions() { + if (allVersions == null) { + allVersions = new ArrayList<>(); + } + return allVersions; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Boolean getSharingEnabled() { + return sharingEnabled; + } + + public void setSharingEnabled(Boolean sharingEnabled) { + this.sharingEnabled = sharingEnabled; + } +} diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DocumentRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DocumentRO.java index bfb1199bdf5f928e100b4bb847e0d4f8473e2480..a9f335b672b971433b918c67bf4d5f5629bd5a60 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DocumentRO.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DocumentRO.java @@ -29,13 +29,10 @@ import java.util.List; public class DocumentRO extends BaseRO { private static final long serialVersionUID = 9008583888835630038L; String documentId; - String referenceDocumentId; String mimeType; Integer currentResourceVersion; List<Integer> allVersions; String name; - Boolean sharingEnabled = Boolean.FALSE; - Integer payloadVersion; String payload; private int payloadStatus = EntityROStatus.PERSISTED.getStatusNumber(); @@ -45,6 +42,7 @@ public class DocumentRO extends BaseRO { List<DocumentPropertyRO> properties = new ArrayList<>(); List<DocumentVersionEventRO> documentVersionEvents = new ArrayList<>(); List<DocumentVersionRO> documentVersions = new ArrayList<>(); + DocumentMetadataRO metadata; public String getDocumentId() { return documentId; @@ -54,12 +52,12 @@ public class DocumentRO extends BaseRO { this.documentId = documentId; } - public String getReferenceDocumentId() { - return referenceDocumentId; + public DocumentMetadataRO getMetadata() { + return metadata; } - public void setReferenceDocumentId(String referenceDocumentId) { - this.referenceDocumentId = referenceDocumentId; + public void setMetadata(DocumentMetadataRO metadata) { + this.metadata = metadata; } public String getMimeType() { @@ -74,14 +72,6 @@ public class DocumentRO extends BaseRO { return currentResourceVersion; } - public Boolean getSharingEnabled() { - return sharingEnabled; - } - - public void setSharingEnabled(Boolean sharingEnabled) { - this.sharingEnabled = sharingEnabled; - } - public void setCurrentResourceVersion(Integer currentResourceVersion) { this.currentResourceVersion = currentResourceVersion; } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDocumentService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDocumentService.java index d992be9dfbd613ece82856091eb2413d7d27f16b..2401db31a256de099025d230b032387fe09b596c 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDocumentService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDocumentService.java @@ -279,6 +279,7 @@ public class UIDocumentService { String genDoc = bos.toString(); DocumentRO result = new DocumentRO(); + result.setMetadata(new DocumentMetadataRO()); result.setPayload(genDoc); return result; } @@ -337,55 +338,6 @@ public class UIDocumentService { } } - @Transactional - public DocumentRO saveDocumentForResource(Long resourceId, DocumentRO documentRo, Long documentReference) { - - final DBResource resource = resourceDao.find(resourceId); - final DBDocument document = resource.getDocument(); - - int returnDocVersion = document.getCurrentVersion(); - boolean isPayloadChanged = documentRo.getPayloadStatus() != EntityROStatus.PERSISTED.getStatusNumber(); - if (isPayloadChanged) { - LOG.debug("Store resource payload for resource [{}]", resource.getIdentifierValue()); - DBDocumentVersion docVersion = storeResourcePayload(resource, document, documentRo); - returnDocVersion = docVersion.getVersion(); - } - - if (isDocumentPropertiesChanged(documentRo)) { - // persist non-transient properties - documentRo.getProperties().stream().filter(p -> - TransientDocumentPropertyType.fromPropertyName(p.getProperty()) == null) - .forEach(p -> persistDocumentProperty(p, document)); - } - - if (Boolean.TRUE.equals(documentRo.getSharingEnabled()) && documentReference!=null) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentSharingNotAllowed", "Document sharing is not allowed for the document with reference document"); - } - document.setSharingEnabled(documentRo.getSharingEnabled()); - - DBDocument documentReferenceEntity = null; - if (documentReference != null) { - if (Objects.equals(documentReference, document.getId())) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentReferenceNotAllowed", "Document reference cannot be the same as the document id"); - } - documentReferenceEntity = documentDao.find(documentReference); - if (documentReferenceEntity == null) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentReferenceNotFound", "Document reference not found"); - } - - if (documentReferenceEntity.getSharingEnabled() != null) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentReferenceNotValid", "Can not reference to not shared document"); - } - - if (documentReferenceEntity.getReferenceDocument() != null) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentReferenceNotValid", "Can not reference to a document that already has a reference"); - } - document.setReferenceDocument(documentReferenceEntity); - } else { - document.setReferenceDocument(null); - } - return convertWithVersion(document, returnDocVersion, getInitialProperties(resource)); - } /** @@ -495,7 +447,39 @@ public class UIDocumentService { } DBDocumentVersion documentVersion = null; if (documentRo.getPayloadVersion() == null) { - documentVersion = createNewDocumentVersionForResource(resource, document, baos.toByteArray()); + documentVersion = createNewDocumentVersion(resource.isReviewEnabled(), document, baos.toByteArray()); + } else { + documentVersion = document.getDocumentVersions().stream() + .filter(dv -> dv.getVersion() == documentRo.getPayloadVersion()) + .findFirst().orElse(null); + if (documentVersion == null) { + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentVersionNotFound", "Document version not found"); + } + documentVersion.setContent(baos.toByteArray()); + } + return documentVersion; + + } + + private DBDocumentVersion storeSubresourcePayload(DBSubresource subresource, DBResource parentResource, DBDocument document, DocumentRO documentRo) { + + DBSubresourceDef subresourceDef = subresource.getSubresourceDef(); + + ResourceHandlerSpi resourceHandler = resourceHandlerService.getSubresourceHandler(subresourceDef, subresourceDef.getResourceDef()); + RequestData data = resourceHandlerService.buildRequestDataForSubResource( + parentResource.getDomainResourceDef().getDomain(), parentResource, + subresource, new ByteArrayInputStream(documentRo.getPayload().getBytes())); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ResponseData responseData = new SpiResponseData(baos); + try { + resourceHandler.storeResource(data, responseData); + } catch (ResourceException e) { + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "StoreSubresourceValidation", ExceptionUtils.getRootCauseMessage(e)); + } + + DBDocumentVersion documentVersion = null; + if (documentRo.getPayloadVersion() == null) { + documentVersion = createNewDocumentVersion(parentResource.isReviewEnabled(), document, baos.toByteArray()); } else { documentVersion = document.getDocumentVersions().stream() .filter(dv -> dv.getVersion() == documentRo.getPayloadVersion()) @@ -509,7 +493,7 @@ public class UIDocumentService { } - public DBDocumentVersion createNewDocumentVersionForResource(DBResource resource, DBDocument document, byte[] payload) { + public DBDocumentVersion createNewDocumentVersion(boolean isReviewEnabled, DBDocument document, byte[] payload) { // create new version to document int version = document.getDocumentVersions().stream().mapToInt(DBDocumentVersion::getVersion) .max().orElse(0); @@ -522,32 +506,91 @@ public class UIDocumentService { // to get the current persist time documentVersion.prePersist(); document.getDocumentVersions().add(0, documentVersion); - if (Boolean.FALSE.equals(resource.isReviewEnabled())) { + if (Boolean.FALSE.equals(isReviewEnabled)) { document.setCurrentVersion(documentVersion.getVersion()); } return documentVersion; } + + + @Transactional + public DocumentRO saveDocumentForResource(Long resourceId, DocumentRO documentRo, Long documentReference) { + + final DBResource resource = resourceDao.find(resourceId); + final DBDocument document = resource.getDocument(); + // check if the document is new or existing document. If payload version is not null then + // return the current payload version otherwise return the current version + int returnDocVersion = documentRo.getPayloadVersion()!=null? + documentRo.getPayloadVersion(): + document.getCurrentVersion(); + + boolean isPayloadChanged = documentRo.getPayloadStatus() != EntityROStatus.PERSISTED.getStatusNumber(); + if (isPayloadChanged) { + LOG.debug("Store resource payload for resource [{}]", resource.getIdentifierValue()); + DBDocumentVersion docVersion = storeResourcePayload(resource, document, documentRo); + returnDocVersion = docVersion.getVersion(); + } + + + if (isDocumentPropertiesChanged(documentRo)) { + // persist non-transient properties + documentRo.getProperties().stream().filter(p -> + TransientDocumentPropertyType.fromPropertyName(p.getProperty()) == null) + .forEach(p -> persistDocumentProperty(p, document)); + } + + DocumentMetadataRO documentMetadataRO =documentRo.getMetadata(); + if (Boolean.TRUE.equals(documentMetadataRO.getSharingEnabled()) && documentReference!=null) { + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentSharingNotAllowed", "Document sharing is not allowed for the document with reference document"); + } + document.setSharingEnabled(documentMetadataRO.getSharingEnabled()); + + DBDocument documentReferenceEntity = null; + if (documentReference != null) { + if (Objects.equals(documentReference, document.getId())) { + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentReferenceNotAllowed", "Document reference cannot be the same as the document id"); + } + documentReferenceEntity = documentDao.find(documentReference); + if (documentReferenceEntity == null) { + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentReferenceNotFound", "Document reference not found"); + } + + if (documentReferenceEntity.getSharingEnabled() != null) { + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentReferenceNotValid", "Can not reference to not shared document"); + } + + if (documentReferenceEntity.getReferenceDocument() != null) { + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentReferenceNotValid", "Can not reference to a document that already has a reference"); + } + document.setReferenceDocument(documentReferenceEntity); + } else { + document.setReferenceDocument(null); + } + return convertWithVersion(document, returnDocVersion, getInitialProperties(resource)); + } + @Transactional public DocumentRO saveSubresourceDocumentForResource(Long subresource, Long resourceId, DocumentRO documentRo) { DBResource parentResource = resourceDao.find(resourceId); DBSubresource entity = subresourceDao.find(subresource); + DBDocument document = entity.getDocument(); DBSubresourceDef subresourceDef = entity.getSubresourceDef(); - ResourceHandlerSpi resourceHandler = resourceHandlerService.getSubresourceHandler(subresourceDef, subresourceDef.getResourceDef()); - RequestData data = resourceHandlerService.buildRequestDataForSubResource( - parentResource.getDomainResourceDef().getDomain(), parentResource, - entity, new ByteArrayInputStream(documentRo.getPayload().getBytes())); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ResponseData responseData = new SpiResponseData(bos); - try { - resourceHandler.storeResource(data, responseData); - } catch (ResourceException e) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "StoreSubresourceValidation", ExceptionUtils.getRootCauseMessage(e)); + // check if the document is new or existing document. If payload version is not null then + // return the current payload version otherwise return the current version + int returnDocVersion = documentRo.getPayloadVersion()!=null? + documentRo.getPayloadVersion(): + document.getCurrentVersion(); + + boolean isPayloadChanged = documentRo.getPayloadStatus() != EntityROStatus.PERSISTED.getStatusNumber(); + if (isPayloadChanged) { + LOG.debug("Store subresource payload for resource [{}]", entity.getIdentifierValue()); + DBDocumentVersion docVersion = storeSubresourcePayload(entity, parentResource, document, documentRo); + returnDocVersion = docVersion.getVersion(); } - DBDocument document = entity.getDocument(); - return createNewVersionAndConvert(document, bos, getInitialProperties(entity)); + return convertWithVersion(document, returnDocVersion, getInitialProperties(entity)); } /** @@ -591,31 +634,6 @@ public class UIDocumentService { } - /** - * return Create new Document version and convert DBDocument to DocumentRo - * - * @param document to convert to DocumentRo - * @param baos to write document content - * @return DocumentRo - */ - private DocumentRO createNewVersionAndConvert(DBDocument document, ByteArrayOutputStream baos, List<DocumentPropertyRO> initialProperties) { - - // get max version - int version = document.getDocumentVersions().stream().mapToInt(DBDocumentVersion::getVersion) - .max().orElse(0); - - DBDocumentVersion documentVersion = new DBDocumentVersion(); - documentVersion.setVersion(version + 1); - documentVersion.setDocument(document); - documentVersion.setContent(baos.toByteArray()); - // to get the current persist time - documentVersion.prePersist(); - - document.getDocumentVersions().add(0, documentVersion); - document.setCurrentVersion(documentVersion.getVersion()); - return convert(document, documentVersion, initialProperties); - } - public DocumentRO convertWithVersion(DBDocument document, int version, List<DocumentPropertyRO> initialProperties) { DBDocumentVersion currentVersion = null; DBDocumentVersion documentVersion = null; @@ -649,23 +667,33 @@ public class UIDocumentService { document.getName(), "Document Name", SMPPropertyTypeEnum.STRING, true); documentRo.addProperty(DOCUMENT_MIMETYPE.getPropertyName(), document.getMimeType(), "Document Mimetype", SMPPropertyTypeEnum.STRING, true); - documentRo.setSharingEnabled(document.getSharingEnabled()); documentRo.getProperties().addAll(initialProperties); - // set list of versions - document.getDocumentVersions().forEach(dv -> { - documentRo.getAllVersions().add(dv.getVersion()); - documentRo.getDocumentVersions().add(conversionService.convert(dv, DocumentVersionRO.class)); - }); + DocumentMetadataRO metadataRo = new DocumentMetadataRO(); documentRo.setDocumentId(SessionSecurityUtils.encryptedEntityId(document.getId())); if (document.getReferenceDocument() != null) { - documentRo.setReferenceDocumentId(SessionSecurityUtils.encryptedEntityId(document.getReferenceDocument().getId())); + metadataRo.setReferenceDocumentId(SessionSecurityUtils.encryptedEntityId(document.getReferenceDocument().getId())); } + metadataRo.setSharingEnabled(document.getSharingEnabled()); + metadataRo.setMimeType(document.getMimeType()); + metadataRo.setPublishedVersion(document.getCurrentVersion()); + metadataRo.setName(document.getName()); + // set list of versions + document.getDocumentVersions().forEach(dv -> { + metadataRo.getAllVersions().add(dv.getVersion()); + }); + documentRo.setMetadata(metadataRo); + // TODO remove duplicate properties use only metadataRo + document.getDocumentVersions().forEach(dv -> { + documentRo.getAllVersions().add(dv.getVersion()); + documentRo.getDocumentVersions().add(conversionService.convert(dv, DocumentVersionRO.class)); + }); documentRo.setMimeType(document.getMimeType()); documentRo.setName(document.getName()); documentRo.setCurrentResourceVersion(document.getCurrentVersion()); + // set list of versions document.getDocumentProperties().stream() .forEach(p -> { documentRo.addProperty(p.getProperty(), @@ -675,6 +703,7 @@ public class UIDocumentService { LOG.info("Document property [{}] added to document [{}]", p); }); + metadataRo.setMimeType(document.getMimeType()); if (version != null) { documentRo.setPayloadCreatedOn(version.getCreatedOn()); diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/edit/DocumentEditController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/edit/DocumentEditController.java index 5c7e29a88d92807a0c01cbc5d863e1e4ff0b44ec..6a8cbce1ea2f253fbd7e984e4588e288fece9e8e 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/edit/DocumentEditController.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/edit/DocumentEditController.java @@ -27,6 +27,7 @@ import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.services.ui.UIDocumentService; import eu.europa.ec.edelivery.smp.ui.ResourceConstants; import eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.MimeTypeUtils; import org.springframework.web.bind.annotation.*; @@ -271,8 +272,9 @@ public class DocumentEditController { logAdminAccess("saveResourceDocument"); Long resourceId = SessionSecurityUtils.decryptEntityId(resourceEncId); Long referenceDocumentId = null; - if (document.getReferenceDocumentId() != null) { - referenceDocumentId = SessionSecurityUtils.decryptEntityId(document.getReferenceDocumentId()); + String referenceDocumentEncId = document.getMetadata()!=null? document.getMetadata().getReferenceDocumentId():null; + if (StringUtils.isNotBlank(referenceDocumentEncId)) { + referenceDocumentId = SessionSecurityUtils.decryptEntityId(referenceDocumentEncId); } return uiDocumentService.saveDocumentForResource(resourceId, document, referenceDocumentId); }