diff --git a/smp-angular/src/_smp-all-themes.scss b/smp-angular/src/_smp-all-themes.scss index 6deaa632784c6d80eaf1380dd85d63dc64e3e6ba..333fd2ac018b34233041b4126a7e10e0bfcec2b5 100644 --- a/smp-angular/src/_smp-all-themes.scss +++ b/smp-angular/src/_smp-all-themes.scss @@ -6,6 +6,7 @@ @use 'app/window/sidenav/nav-tree/_nav-tree.component-theme' as nav-tree; @use 'app/common/search-table/_search-table.component-theme' as search-table; @use 'app/user-settings/user-access-tokens/access-token-panel/_access-token-panel.component-theme' as access-token-panel; +@use 'app/common/panels/expandable-panel-component/expandable-panel.component' as expandable-panel; @mixin all-component-colors($theme) { @include toolbar.set-component-colors($theme); @@ -13,7 +14,7 @@ @include nav-tree.set-component-colors($theme); @include search-table.set-component-colors($theme); @include access-token-panel.set-component-colors($theme); - + @include expandable-panel.set-component-colors($theme); /* shared classes*/ .smp-data-panel:hover { background-color: smp.get-theme-color($theme, primary, 300); diff --git a/smp-angular/src/_smp-theme-helper.scss b/smp-angular/src/_smp-theme-helper.scss index 65987b9e58d7afeeda4bb0cdee4a15cb5c88f730..7d4c57de2affec7f8d1ae673b9bf02fb8a16ac94 100644 --- a/smp-angular/src/_smp-theme-helper.scss +++ b/smp-angular/src/_smp-theme-helper.scss @@ -2,7 +2,10 @@ @use 'sass:map'; @use '@angular/material' as mat; - +@function get-theme-type($smp-theme ) { + $color-config: mat.get-color-config($smp-theme); + @return map.get($color-config, type); +} @function get-theme-color($smp-theme, $color: primary, $hue: null, $opacity: null ) { $color-config: mat.get-color-config($smp-theme); diff --git a/smp-angular/src/app/common/model/document-version-event-ro.model.ts b/smp-angular/src/app/common/model/document-version-event-ro.model.ts index 17ba3452cb5e9845d821fa7fcadb66eb656afc17..89997e43dadc95402b9939001845ebba4addb931 100644 --- a/smp-angular/src/app/common/model/document-version-event-ro.model.ts +++ b/smp-angular/src/app/common/model/document-version-event-ro.model.ts @@ -1,4 +1,5 @@ import {SearchTableEntity} from "../search-table/search-table-entity.model"; +import {DocumentVersionsStatus} from "../enums/document-versions-status.enum"; export interface DocumentVersionEventRo extends SearchTableEntity { eventType: string; @@ -6,5 +7,6 @@ export interface DocumentVersionEventRo extends SearchTableEntity { username: string; eventSourceType: string; details: string; + documentVersionStatus?: DocumentVersionsStatus; } diff --git a/smp-angular/src/app/common/panels/document-events-panel/document-events-panel.component.html b/smp-angular/src/app/common/panels/document-events-panel/document-events-panel.component.html index 595803b18bee6c38ec1ab5f23f31667a9cfcbfc9..fec6a514721fd8f362a73afeaf4e9f38e52d4485 100644 --- a/smp-angular/src/app/common/panels/document-events-panel/document-events-panel.component.html +++ b/smp-angular/src/app/common/panels/document-events-panel/document-events-panel.component.html @@ -23,6 +23,12 @@ </th> <td mat-cell *matCellDef="let row">{{ row.eventType }}</td> </ng-container> + <ng-container matColumnDef="status"> + <th mat-header-cell *matHeaderCellDef + mat-sort-header>{{ "document.events.panel.label.status" | translate }} + </th> + <td mat-cell *matCellDef="let row">{{ row.documentVersionStatus }}</td> + </ng-container> <ng-container matColumnDef="username"> <th mat-header-cell *matHeaderCellDef diff --git a/smp-angular/src/app/common/panels/document-events-panel/document-events-panel.component.ts b/smp-angular/src/app/common/panels/document-events-panel/document-events-panel.component.ts index be12ada60435b5ee346e4f7839f801928143fb7e..afcd2c325b2ef1f30ed0ecc3fbefbae7b67cc8f3 100644 --- a/smp-angular/src/app/common/panels/document-events-panel/document-events-panel.component.ts +++ b/smp-angular/src/app/common/panels/document-events-panel/document-events-panel.component.ts @@ -62,7 +62,7 @@ import {GlobalLookups} from "../../global-lookups"; export class DocumentEventsPanelComponent implements AfterViewInit, BeforeLeaveGuard, ControlValueAccessor { - displayedColumns: string[] = ['date', 'eventType', 'username', 'eventSource']; + displayedColumns: string[] = ['date', 'eventType', 'status','username', 'eventSource']; private onChangeCallback: (_: any) => void = () => { }; eventDataSource: MatTableDataSource<DocumentVersionEventRo> = new MatTableDataSource(); @@ -109,6 +109,7 @@ export class DocumentEventsPanelComponent implements AfterViewInit, BeforeLeaveG this.eventDataSource.filterPredicate = (data: DocumentVersionEventRo, filter: string) => { return data.eventType?.toLowerCase().includes(filter) || data.username?.toLowerCase().includes(filter) + || data.documentVersionStatus?.toLowerCase().includes(filter) || data.eventSourceType?.toLowerCase().includes(filter) || data.eventOn?.toLocaleString().toLowerCase().includes(filter); }; diff --git a/smp-angular/src/app/common/panels/expandable-panel-component/expandable-panel.component.html b/smp-angular/src/app/common/panels/expandable-panel-component/expandable-panel.component.html index 38ec97dc121a133f64109aae5aa130978f49a72b..97e7dd58cc30df1655fcf2283f745d71f29e10b3 100644 --- a/smp-angular/src/app/common/panels/expandable-panel-component/expandable-panel.component.html +++ b/smp-angular/src/app/common/panels/expandable-panel-component/expandable-panel.component.html @@ -3,8 +3,8 @@ <ng-content></ng-content> </div> <!-- table Toolbar --> - <div style="width: 42px"> - <button mat-mini-fab + <div style="width: 32px"> + <button class="button-deselected" attr.aria-label="{{ 'expandable.panel.label.expand.collapse' | translate }}" matTooltip="{{ 'document.properties.panel.tooltip.expand.collapse' | translate }}" (click)="onToggleExpandButtonClicked()"> diff --git a/smp-angular/src/app/common/panels/expandable-panel-component/expandable-panel.component.scss b/smp-angular/src/app/common/panels/expandable-panel-component/expandable-panel.component.scss index dcc099038e537562550909e7c49f647368335edf..0c2c84087ed89e523ff91169ddcc68f085e43705 100644 --- a/smp-angular/src/app/common/panels/expandable-panel-component/expandable-panel.component.scss +++ b/smp-angular/src/app/common/panels/expandable-panel-component/expandable-panel.component.scss @@ -1,3 +1,31 @@ +@use '../../../../_smp-theme-helper' as smp; + +@mixin set-component-colors($theme) { + + .button-selected { + padding: 3px 3px !important; + border-radius: 15%; + background-color: smp.get-theme-color($theme, primary, 500) !important; + box-shadow: 0 1px 2px 0 rgba(0,0,0,0.2), 0 1px 2px 0 rgba(0,0,0,0.2); + color: smp.get-theme-color($theme, primary, 500-contrast) !important; + border-style: none; + } + + .button-deselected :hover { + background-color: smp.get-theme-color($theme, primary, 800, 0.5) !important; + color: smp.get-theme-color($theme, primary, 500-contrast) !important; + } + + .button-deselected { + padding: 1px 3px !important; + border-radius: 15%; + background: transparent; + color: smp.get-theme-color($theme, primary, 500-contrast) !important; + border-style: none; + } + +} + #expand-panel_id { display: flex; flex-direction: column; @@ -12,9 +40,5 @@ writing-mode: vertical-rl; } -.button-deselected { - margin: 1px 3px !important; - background: transparent; - border-style: none; -} + diff --git a/smp-angular/src/app/common/panels/expandable-panel-component/expandable-panel.component.ts b/smp-angular/src/app/common/panels/expandable-panel-component/expandable-panel.component.ts index 46dd3e71e116c09b18ab4abf9eb29b77423ff82c..a8652284650a9acdda3f41705909eff5e4d5a9f1 100644 --- a/smp-angular/src/app/common/panels/expandable-panel-component/expandable-panel.component.ts +++ b/smp-angular/src/app/common/panels/expandable-panel-component/expandable-panel.component.ts @@ -77,7 +77,7 @@ export class ExpandablePanelComponent implements AfterViewInit { } getButtonClass(index: number) { - return index === this.selectedIndex ? 'mat-raised-button' : 'mat-raised-button button-deselected'; + return index === this.selectedIndex ? 'button-selected' : 'button-deselected'; } onDoubleClick(item: ExpandableItemComponent, index: number) { diff --git a/smp-angular/src/app/edit/edit-resources/edit-resource.component.ts b/smp-angular/src/app/edit/edit-resources/edit-resource.component.ts index 51fbcb161bdff6cab5c253da1fc022a572574cde..2457d3bddc8e16e18e9aa3e1c79c064634da49d5 100644 --- a/smp-angular/src/app/edit/edit-resources/edit-resource.component.ts +++ b/smp-angular/src/app/edit/edit-resources/edit-resource.component.ts @@ -4,7 +4,9 @@ import {MatPaginator, PageEvent} from "@angular/material/paginator"; import {DomainRo} from "../../common/model/domain-ro.model"; import {GroupRo} from "../../common/model/group-ro.model"; import {MemberTypeEnum} from "../../common/enums/member-type.enum"; -import {ResourceDefinitionRo} from "../../system-settings/admin-extension/resource-definition-ro.model"; +import { + ResourceDefinitionRo +} from "../../system-settings/admin-extension/resource-definition-ro.model"; import {ResourceRo} from "../../common/model/resource-ro.model"; import {EditResourceController} from "./edit-resource.controller"; import {MatTableDataSource} from "@angular/material/table"; @@ -24,7 +26,7 @@ export class EditResourceComponent implements OnInit, BeforeLeaveGuard { @ViewChild("resourcePaginator") paginator: MatPaginator; constructor(private editResourceController: EditResourceController) { - this.dataSource = editResourceController; + this.dataSource = editResourceController; } ngOnInit() { @@ -37,7 +39,8 @@ export class EditResourceComponent implements OnInit, BeforeLeaveGuard { } } - ngAfterViewInit():void { + + ngAfterViewInit(): void { // bind data to resource controller this.dataSource.paginator = this.paginator; } @@ -50,6 +53,7 @@ export class EditResourceComponent implements OnInit, BeforeLeaveGuard { get hasResources(): boolean { return this.editResourceController.data?.length > 0; } + get domainList(): DomainRo[] { return this.editResourceController.domainList; }; diff --git a/smp-angular/src/app/edit/edit-resources/edit-resource.controller.ts b/smp-angular/src/app/edit/edit-resources/edit-resource.controller.ts index 4cc6192e27b82fe489eb235a9471925e60cd4dad..7332599da2c305c2b284ccc5b21905fc9be2f022 100644 --- a/smp-angular/src/app/edit/edit-resources/edit-resource.controller.ts +++ b/smp-angular/src/app/edit/edit-resources/edit-resource.controller.ts @@ -13,6 +13,7 @@ import { AlertMessageService } from "../../common/alert-message/alert-message.service"; import {MatTableDataSource} from "@angular/material/table"; +import {SecurityEventService} from "../../security/security-event.service"; /** * The purpose of the EditResourceController is to control the data of edit resource components when navigating @@ -43,8 +44,30 @@ export class EditResourceController extends MatTableDataSource<ResourceRo> { private groupService: EditGroupService, private resourceService: EditResourceService, private alertService: AlertMessageService, + private securityEventService: SecurityEventService ) { super(); + this.securityEventService.onLogoutSuccessEvent().subscribe(value => { + this.clearSelectedData(); + }); + this.securityEventService.onLoginSuccessEvent().subscribe(value => { + this.clearSelectedData(); + }); + } + + + private clearSelectedData() { + this.domainList = []; + this.groupList = []; + this._selectedDomain = null; + this._selectedGroup = null; + this._selectedResource = null; + this._selectedDomainResourceDefs = []; + this.pageIndex = 0; + this.pageSize = 10; + this.resourcesFilter = {}; + this.isLoadingResults = false; + super.data = []; } get selectedDomain(): DomainRo { diff --git a/smp-angular/src/app/edit/edit-resources/resource-details-panel/resource-details-panel.component.html b/smp-angular/src/app/edit/edit-resources/resource-details-panel/resource-details-panel.component.html index fe07b3bbaf6f3cd3c246f2637f779d53c0c98419..0418cd9753bbb420d4bc4c1971411d87d2971612 100644 --- a/smp-angular/src/app/edit/edit-resources/resource-details-panel/resource-details-panel.component.html +++ b/smp-angular/src/app/edit/edit-resources/resource-details-panel/resource-details-panel.component.html @@ -1,7 +1,6 @@ <div id="edit-resource-panel" class="mat-elevation-z2"> <mat-toolbar class="mat-elevation-z2"> <mat-toolbar-row class="smp-toolbar-row"> - <button id="showResource" mat-raised-button color="primary" matTooltip="{{ 'resource.details.panel.tooltip.show.resource' | translate }}" @@ -41,10 +40,15 @@ > </mat-form-field> <mat-checkbox formControlName="reviewEnabled" + (click)="onReviewEnabledChanged($event)" matTooltip="{{ 'resource.details.panel.label.resource.review.enabled' | translate }}" id="reviewEnabled_id"> {{ "resource.details.panel.tooltip.resource.review.enabled" | translate }} </mat-checkbox> + <smp-warning-panel *ngIf="showReviewEnabledHint" + type="warning" + icon="warning" + label="{{ 'resource.details.panel.review.disabled.confirmation.dialog.description' | translate }}"></smp-warning-panel> <mat-form-field style="width:100%"> <mat-label>{{ "resource.details.panel.label.resource.visibility" | translate }}</mat-label> <select matNativeControl formControlName="visibility" @@ -76,5 +80,4 @@ [label]="visibilityDescription" ></smp-warning-panel> </form> - </div> diff --git a/smp-angular/src/app/edit/edit-resources/resource-details-panel/resource-details-panel.component.ts b/smp-angular/src/app/edit/edit-resources/resource-details-panel/resource-details-panel.component.ts index e99996e62e652ca2296eb736ebb392e4bbc3dd56..62bb3c2a895157ae7d51d3042e2ccba1ed486ad9 100644 --- a/smp-angular/src/app/edit/edit-resources/resource-details-panel/resource-details-panel.component.ts +++ b/smp-angular/src/app/edit/edit-resources/resource-details-panel/resource-details-panel.component.ts @@ -25,6 +25,9 @@ import { WindowSpinnerService } from "../../../common/services/window-spinner.service"; import {EditResourceController} from "../edit-resource.controller"; +import { + ConfirmationDialogComponent +} from "../../../common/dialogs/confirmation-dialog/confirmation-dialog.component"; @Component({ @@ -173,4 +176,30 @@ export class ResourceDetailsPanelComponent implements BeforeLeaveGuard { public onResetButtonClicked() { this.resourceForm.reset(this._resource); } + + async onReviewEnabledChanged(event: any) { + let newReviewEnabled: boolean = event.target.checked; + let showWarning: boolean = this._resource?.reviewEnabled && !newReviewEnabled; + + + if (showWarning) { + this.dialog.open(ConfirmationDialogComponent, { + data: { + title: await lastValueFrom(this.translateService.get("resource.details.panel.review.disabled.confirmation.dialog.title")), + description: await lastValueFrom(this.translateService.get("resource.details.panel.review.disabled.confirmation.dialog.description")) + } + }).afterClosed().subscribe(result => { + if (!result) { + // prevent default does not work in case of "async" + this.resourceForm.controls['reviewEnabled'].setValue(true); + this.resourceForm.controls['reviewEnabled'].markAsPristine(); + } + }); + } + } + + get showReviewEnabledHint(): boolean { + return this._resource?.reviewEnabled === true + && this.resourceForm.get('reviewEnabled').value !== true; + } } diff --git a/smp-angular/src/app/resource-search/resource-search-controller.ts b/smp-angular/src/app/resource-search/resource-search-controller.ts index 44695c9b9b02352f79dcfe8b2881effa371a343f..097b3865186a9bd4a4cb7750f866598d3c94b1c8 100644 --- a/smp-angular/src/app/resource-search/resource-search-controller.ts +++ b/smp-angular/src/app/resource-search/resource-search-controller.ts @@ -1,13 +1,22 @@ -import {SearchTableController} from '../common/search-table/search-table-controller'; -import {MatDialog, MatDialogConfig, MatDialogRef} from '@angular/material/dialog'; +import { + SearchTableController +} from '../common/search-table/search-table-controller'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {ResourceSearchRo} from './resource-search-ro.model'; import {of} from "rxjs/internal/observable/of"; -import {SearchTableValidationResult} from "../common/search-table/search-table-validation-result.model"; -import {SearchTableEntity} from "../common/search-table/search-table-entity.model"; +import { + SearchTableValidationResult +} from "../common/search-table/search-table-validation-result.model"; +import { + SearchTableEntity +} from "../common/search-table/search-table-entity.model"; export class ResourceSearchController implements SearchTableController { - constructor(public dialog: MatDialog) { } + constructor(public dialog: MatDialog) { + + + } public showDetails(row): MatDialogRef<any> { return null; @@ -20,7 +29,8 @@ export class ResourceSearchController implements SearchTableController { return null; } - public delete(row: any) { } + public delete(row: any) { + } newDialog(config): MatDialogRef<any> { if (config && config.data && config.data.edit) { @@ -34,10 +44,11 @@ export class ResourceSearchController implements SearchTableController { return null; } - public dataSaved() {} + public dataSaved() { + } - validateDeleteOperation(rows: Array<SearchTableEntity>){ - return of( this.newValidationResult(true) ); + validateDeleteOperation(rows: Array<SearchTableEntity>) { + return of(this.newValidationResult(true)); } public newValidationResult(result: boolean, message?: string): SearchTableValidationResult { @@ -54,7 +65,7 @@ export class ResourceSearchController implements SearchTableController { isRecordChanged(oldModel, newModel): boolean { for (var property in oldModel) { - const isEqual = this.isEqual(newModel[property],oldModel[property]); + const isEqual = this.isEqual(newModel[property], oldModel[property]); if (!isEqual) { return true; // Property has changed } diff --git a/smp-angular/src/app/resource-search/resource-search.component.ts b/smp-angular/src/app/resource-search/resource-search.component.ts index b447010189c2927373b70cf8df2bf0d001720701..c8a85b61666de30b0e01c4f64e36196d79ff1da6 100644 --- a/smp-angular/src/app/resource-search/resource-search.component.ts +++ b/smp-angular/src/app/resource-search/resource-search.component.ts @@ -10,18 +10,27 @@ import { } from '@angular/core'; import {ColumnPicker} from '../common/column-picker/column-picker.model'; import {MatDialog} from '@angular/material/dialog'; -import {AlertMessageService} from '../common/alert-message/alert-message.service'; +import { + AlertMessageService +} from '../common/alert-message/alert-message.service'; import {ResourceSearchController} from './resource-search-controller'; import {HttpClient} from '@angular/common/http'; import {SmpConstants} from "../smp.constants"; import {GlobalLookups} from "../common/global-lookups"; -import {SearchTableComponent} from "../common/search-table/search-table.component"; +import { + SearchTableComponent +} from "../common/search-table/search-table.component"; import {ResourceSearchRo} from "./resource-search-ro.model"; import {SubresourceSearchRo} from "./subresource-search-ro.model"; -import {ResourceFilterOptionsService} from "../common/services/resource-filter-options.service"; -import {ResourceFilterOptionsRo} from "../common/model/resource-filter-options-ro.model"; +import { + ResourceFilterOptionsService +} from "../common/services/resource-filter-options.service"; +import { + ResourceFilterOptionsRo +} from "../common/model/resource-filter-options-ro.model"; import {TranslateService} from "@ngx-translate/core"; import {lastValueFrom} from "rxjs"; +import {SecurityEventService} from "../security/security-event.service"; @Component({ templateUrl: './resource-search.component.html', @@ -47,9 +56,14 @@ export class ResourceSearchComponent implements OnInit, AfterViewInit, AfterView public dialog: MatDialog, private changeDetector: ChangeDetectorRef, private resourceFilterOptionsService: ResourceFilterOptionsService, - private translateService: TranslateService) { + private translateService: TranslateService, + private securityEventService: SecurityEventService) { this.baseUrl = SmpConstants.REST_PUBLIC_SEARCH_RESOURCE; + this.securityEventService.onLogoutSuccessEvent().subscribe(value => { + // refresh the search table pn logout + this.searchTable.search(); + }); } ngOnInit() { @@ -64,6 +78,7 @@ export class ResourceSearchComponent implements OnInit, AfterViewInit, AfterView this.alertService.exception(await lastValueFrom(this.translateService.get("resource.search.error.fetch.resource.metadata")), err); } }); + } async initColumns() { @@ -127,15 +142,15 @@ export class ResourceSearchComponent implements OnInit, AfterViewInit, AfterView } createResourceURL(row: ResourceSearchRo) { - return (!row?.domainCode? "" : row.domainCode+ '/') - + (!row?.resourceDefUrlSegment?"" : row.resourceDefUrlSegment + '/') - + encodeURIComponent((!row.participantScheme ? '' : row.participantScheme) + '::' + row.participantIdentifier); + return (!row?.domainCode ? "" : row.domainCode + '/') + + (!row?.resourceDefUrlSegment ? "" : row.resourceDefUrlSegment + '/') + + encodeURIComponent((!row.participantScheme ? '' : row.participantScheme) + '::' + row.participantIdentifier); } createServiceMetadataURL(row: ResourceSearchRo, rowSMD: SubresourceSearchRo) { return this.createResourceURL(row) - + '/' + rowSMD.subresourceDefUrlSegment + '/' - + encodeURIComponent((!rowSMD.documentIdentifierScheme ? '' : rowSMD.documentIdentifierScheme) + '::' + rowSMD.documentIdentifier); + + '/' + rowSMD.subresourceDefUrlSegment + '/' + + encodeURIComponent((!rowSMD.documentIdentifierScheme ? '' : rowSMD.documentIdentifierScheme) + '::' + rowSMD.documentIdentifier); } details(row: any) { diff --git a/smp-angular/src/assets/i18n/en.json b/smp-angular/src/assets/i18n/en.json index 1564fdd71c3d3a5d2862fd21cd7c95ce81e345ec..baf7e2719b59ac13c0166c3d7d4e97c40685b4d9 100644 --- a/smp-angular/src/assets/i18n/en.json +++ b/smp-angular/src/assets/i18n/en.json @@ -134,6 +134,7 @@ "document.events.panel.label.filter": "Filter", "document.events.panel.label.date": "Date", "document.events.panel.label.type": "Event type", + "document.events.panel.label.status": "Status", "document.events.panel.label.username": "Username", "document.events.panel.label.source": "Event Source", "document.events.panel.label.no.properties.found": "No DocumentVersion events found", @@ -351,6 +352,8 @@ "resource.details.panel.title": "Resources", "resource.details.panel.button.reset": "Reset", "resource.details.panel.button.save": "Save", + "resource.details.panel.review.disabled.confirmation.dialog.title": "Review disabled?", + "resource.details.panel.review.disabled.confirmation.dialog.description": "All document versions with review statuses (UNDER_REVIEW, APPROVED, REJECTED) will be set to DRAFT\nDo you want to continue?", "document.edit.panel.button.back": "Back", "document.edit.panel.button.cancel": "Cancel", "document.edit.panel.button.document.wizard": "Document wizard", diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBDocumentVersionEventToDocumentVersionEventROConverter.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBDocumentVersionEventToDocumentVersionEventROConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..5e2bf586f84d4fc7722068137535e542d11b112a --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBDocumentVersionEventToDocumentVersionEventROConverter.java @@ -0,0 +1,44 @@ +package eu.europa.ec.edelivery.smp.conversion; + + +import eu.europa.ec.edelivery.smp.data.model.DBDomain; +import eu.europa.ec.edelivery.smp.data.model.doc.DBDocumentVersionEvent; +import eu.europa.ec.edelivery.smp.data.ui.DocumentVersionEventRO; +import eu.europa.ec.edelivery.smp.logging.SMPLogger; +import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; +import org.apache.commons.beanutils.BeanUtils; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +import java.lang.reflect.InvocationTargetException; + +/** + * Converter for domain DAO entity {@link DBDomain} to + * enriched webservice object {@link eu.europa.ec.edelivery.smp.data.ui.DomainPublicRO}. + * + * @author Joze Rihtarsic + * @since 5.1 + */ +@Component +public class DBDocumentVersionEventToDocumentVersionEventROConverter + implements Converter<DBDocumentVersionEvent, DocumentVersionEventRO> { + private static final SMPLogger LOG = SMPLoggerFactory.getLogger(DBDocumentVersionEventToDocumentVersionEventROConverter.class); + + @Override + public DocumentVersionEventRO convert(DBDocumentVersionEvent source) { + + if (source == null) { + return null; + } + DocumentVersionEventRO target = new DocumentVersionEventRO(); + try { + BeanUtils.copyProperties(target, source); + target.setDocumentVersionStatus(source.getStatus()); + } catch (IllegalAccessException | InvocationTargetException e) { + LOG.error("Error occurred while converting DBDomain", e); + return null; + } + return target; + } + +} diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/enums/DocumentVersionEventType.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/enums/DocumentVersionEventType.java index 7dc30b30b45f1a2e10dd5c7dec0c0a86acb922a4..84031c27c9a06a5570fc1626e07174e3abd25500 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/enums/DocumentVersionEventType.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/enums/DocumentVersionEventType.java @@ -15,5 +15,6 @@ public enum DocumentVersionEventType { RETIRE, APPROVE, REJECT, - ERROR + ERROR, + SETTINGS_CHANGE, } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBDocumentVersionEvent.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBDocumentVersionEvent.java index 54fa7c8dc2274b4164451c4c68b4e19067fdd3b6..1592cba7b57f940e92661e6ddfb33a21b356d738 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBDocumentVersionEvent.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBDocumentVersionEvent.java @@ -20,6 +20,7 @@ package eu.europa.ec.edelivery.smp.data.model.doc; import eu.europa.ec.edelivery.smp.data.dao.utils.ColumnDescription; import eu.europa.ec.edelivery.smp.data.enums.DocumentVersionEventType; +import eu.europa.ec.edelivery.smp.data.enums.DocumentVersionStatusType; import eu.europa.ec.edelivery.smp.data.enums.EventSourceType; import eu.europa.ec.edelivery.smp.data.model.BaseEntity; import eu.europa.ec.edelivery.smp.data.model.CommonColumnsLengths; @@ -61,6 +62,11 @@ public class DBDocumentVersionEvent extends BaseEntity { @ColumnDescription(comment = "Document version event type") private DocumentVersionEventType eventType = DocumentVersionEventType.CREATE; + @Enumerated(EnumType.STRING) + @Column(name = "EVENT_STATUS", nullable = false) + @ColumnDescription(comment = "Document version event type") + private DocumentVersionStatusType status = DocumentVersionStatusType.DRAFT; + @Column(name = "EVENT_ON") @ColumnDescription(comment = "Date time of the event") private OffsetDateTime eventOn; @@ -127,6 +133,14 @@ public class DBDocumentVersionEvent extends BaseEntity { this.eventSourceType = eventSourceType; } + public DocumentVersionStatusType getStatus() { + return status; + } + + public void setStatus(DocumentVersionStatusType status) { + this.status = status; + } + public String getDetails() { return details; } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DocumentVersionEventRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DocumentVersionEventRO.java index da9f630f73c4f35957b6e49d93901da5494efd00..3c57005fbeb227a5235c0e50de5051846450bc14 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DocumentVersionEventRO.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DocumentVersionEventRO.java @@ -2,6 +2,7 @@ package eu.europa.ec.edelivery.smp.data.ui; import eu.europa.ec.edelivery.smp.data.enums.DocumentVersionEventType; +import eu.europa.ec.edelivery.smp.data.enums.DocumentVersionStatusType; import eu.europa.ec.edelivery.smp.data.enums.EventSourceType; import java.time.OffsetDateTime; @@ -18,6 +19,7 @@ public class DocumentVersionEventRO extends BaseRO { private static final long serialVersionUID = 9008583888835630037L; private DocumentVersionEventType eventType = DocumentVersionEventType.CREATE; + private DocumentVersionStatusType documentVersionStatus = DocumentVersionStatusType.DRAFT; private OffsetDateTime eventOn; private String username; private EventSourceType eventSourceType = EventSourceType.OTHER; @@ -63,4 +65,13 @@ public class DocumentVersionEventRO extends BaseRO { public void setDetails(String details) { this.details = details; } + + + public DocumentVersionStatusType getDocumentVersionStatus() { + return documentVersionStatus; + } + + public void setDocumentVersionStatus(DocumentVersionStatusType status) { + this.documentVersionStatus = status; + } } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/resource/DocumentVersionService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/resource/DocumentVersionService.java index 0041dfc9c60f6c148415c376330d4cd601c6a214..a11e2e11818cd90a5eb60ffe8a7138ccb5155d8e 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/resource/DocumentVersionService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/resource/DocumentVersionService.java @@ -47,7 +47,9 @@ public class DocumentVersionService { String details, boolean publish) { DBDocumentVersion dbDocumentVersion = new DBDocumentVersion(); - DBDocumentVersionEvent dbEvent = createDocumentVersionEvent(DocumentVersionEventType.CREATE, eventSourceType, details); + DBDocumentVersionEvent dbEvent = createDocumentVersionEvent(DocumentVersionEventType.CREATE, + DocumentVersionStatusType.DRAFT, + eventSourceType, details); dbDocumentVersion.addNewDocumentVersionEvent(dbEvent); dbDocumentVersion.setStatus(DocumentVersionStatusType.DRAFT); if (publish) { @@ -65,7 +67,8 @@ public class DocumentVersionService { * @param details details of the event */ public void retireDocumentVersion(DBDocumentVersion dbDocumentVersion, EventSourceType eventSourceType, String details) { - DBDocumentVersionEvent dbEvent = createDocumentVersionEvent(DocumentVersionEventType.RETIRE, eventSourceType, details); + DBDocumentVersionEvent dbEvent = createDocumentVersionEvent(DocumentVersionEventType.RETIRE, + DocumentVersionStatusType.RETIRED, eventSourceType, details); dbDocumentVersion.addNewDocumentVersionEvent(dbEvent); dbDocumentVersion.setStatus(DocumentVersionStatusType.RETIRED); } @@ -73,13 +76,14 @@ public class DocumentVersionService { /** * Method sets document version status to published and adds Publish event to the document version list of events * - * @param dbDocumentVersion document version to be published - * @param eventSourceType event source type + * @param dbDocumentVersion document version to be published + * @param eventSourceType event source type * @param addFirstPublishEvent if true, the event will be added to fist place in the list of events (because the list is in reverse order it is * necessary to add it to the first place when adding single event, but when adding multiple events, the order should be reversed) */ public void publishDocumentVersion(DBDocumentVersion dbDocumentVersion, EventSourceType eventSourceType, boolean addFirstPublishEvent) { - DBDocumentVersionEvent dbEvent = createDocumentVersionEvent(DocumentVersionEventType.PUBLISH, eventSourceType, null); + DBDocumentVersionEvent dbEvent = createDocumentVersionEvent(DocumentVersionEventType.PUBLISH, + DocumentVersionStatusType.PUBLISHED, eventSourceType, null); dbDocumentVersion.addNewDocumentVersionEvent(dbEvent, addFirstPublishEvent); dbDocumentVersion.setStatus(DocumentVersionStatusType.PUBLISHED); } @@ -93,7 +97,8 @@ public class DocumentVersionService { * @param message message to be sent to the resource administrators */ public void rejectDocumentVersion(DBDocumentVersion dbDocumentVersion, EventSourceType eventSourceType, String message) { - DBDocumentVersionEvent dbEvent = createDocumentVersionEvent(DocumentVersionEventType.REJECT, eventSourceType, message); + DBDocumentVersionEvent dbEvent = createDocumentVersionEvent(DocumentVersionEventType.REJECT, + DocumentVersionStatusType.REJECTED, eventSourceType, message); dbDocumentVersion.addNewDocumentVersionEvent(dbEvent); dbDocumentVersion.setStatus(DocumentVersionStatusType.REJECTED); } @@ -107,7 +112,8 @@ public class DocumentVersionService { * @param message message to be sent to the resource administrators */ public void approveDocumentVersion(DBDocumentVersion dbDocumentVersion, EventSourceType eventSourceType, String message) { - DBDocumentVersionEvent dbEvent = createDocumentVersionEvent(DocumentVersionEventType.APPROVE, eventSourceType, message); + DBDocumentVersionEvent dbEvent = createDocumentVersionEvent(DocumentVersionEventType.APPROVE, + DocumentVersionStatusType.APPROVED, eventSourceType, message); dbDocumentVersion.addNewDocumentVersionEvent(dbEvent); dbDocumentVersion.setStatus(DocumentVersionStatusType.APPROVED); } @@ -120,7 +126,9 @@ public class DocumentVersionService { * @param eventSourceType event source type */ public void requestReviewDocumentVersion(DBDocumentVersion dbDocumentVersion, EventSourceType eventSourceType) { - DBDocumentVersionEvent dbEvent = createDocumentVersionEvent(DocumentVersionEventType.REQUEST_REVIEW, eventSourceType, null); + DBDocumentVersionEvent dbEvent = createDocumentVersionEvent(DocumentVersionEventType.REQUEST_REVIEW, + DocumentVersionStatusType.UNDER_REVIEW, + eventSourceType, null); dbDocumentVersion.addNewDocumentVersionEvent(dbEvent); dbDocumentVersion.setStatus(DocumentVersionStatusType.UNDER_REVIEW); } @@ -135,6 +143,7 @@ public class DocumentVersionService { * @return */ public DBDocumentVersionEvent createDocumentVersionEvent(DocumentVersionEventType eventType, + DocumentVersionStatusType statusType, EventSourceType eventSourceType, String details) { @@ -146,7 +155,7 @@ public class DocumentVersionService { } else { LOG.debug("User details not found for event creation "); } - + dbEvent.setStatus(statusType); dbEvent.setEventOn(OffsetDateTime.now()); dbEvent.setEventType(eventType); dbEvent.setEventSourceType(eventSourceType); diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/resource/ResourceStorage.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/resource/ResourceStorage.java index 5e1dffd7989edd9c94297f914073d5e91a7f88a0..c3f65bdb9d0662eab88b90669c5e8732dc35ec82 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/resource/ResourceStorage.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/resource/ResourceStorage.java @@ -165,9 +165,8 @@ public class ResourceStorage { documentProperties.put(DOCUMENT_NAME.getPropertyName(), document.getName()); documentProperties.put(DOCUMENT_MIMETYPE.getPropertyName(), document.getMimeType()); documentProperties.put(DOCUMENT_VERSION.getPropertyName(), document.getCurrentVersion()); - document.getDocumentProperties().forEach(property -> { - documentProperties.put(property.getProperty(), property.getValue()); - }); + document.getDocumentProperties().forEach(property -> + documentProperties.put(property.getProperty(), property.getValue())); return documentProperties; } @@ -202,7 +201,9 @@ public class ResourceStorage { document.getDocumentVersions().stream() .filter(v -> v.getStatus() == DocumentVersionStatusType.PUBLISHED) .forEach(v -> {v.setStatus(DocumentVersionStatusType.RETIRED); - v.getDocumentVersionEvents().add(documentVersionService.createDocumentVersionEvent(DocumentVersionEventType.RETIRE, EventSourceType.REST_API, null));}); + v.getDocumentVersionEvents().add(documentVersionService.createDocumentVersionEvent(DocumentVersionEventType.RETIRE, + DocumentVersionStatusType.RETIRED, + EventSourceType.REST_API, null));}); managedResource.getDocument().addNewDocumentVersion(version); return managedResource; } 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 f63f4bc624254ef2161111ed26094abeb7921396..aa5794db32df91cab09452598ccceabf299c650b 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 @@ -52,18 +52,29 @@ import org.springframework.transaction.annotation.Transactional; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; import static eu.europa.ec.smp.spi.enums.TransientDocumentPropertyType.*; +/** + * Service for handling document operations for the UI + * + * @author Joze RIHTARSIC + * @since 5.0 + */ @Service public class UIDocumentService { private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIDocumentService.class); + private static final List<DocumentVersionStatusType> REVIEW_STATUSES = Arrays.asList(DocumentVersionStatusType.UNDER_REVIEW, DocumentVersionStatusType.APPROVED, DocumentVersionStatusType.REJECTED); + public static final String DOCUMENT_VERSION_NOT_FOUND = "Document version not found"; + public static final String DOCUMENT_VERSION_NOT_FOUND_TAG = "DocumentVersionNotFound"; + public static final String DOCUMENT_ID_MISMATCH_TAG = "DocumentIdMismatch"; + public static final String DOCUMENT_ID_MISMATCH = "Document id does not match the resource document id"; + + + final ResourceDao resourceDao; final SubresourceDao subresourceDao; final DocumentDao documentDao; @@ -118,7 +129,7 @@ public class UIDocumentService { DBDocument document = resource.getDocument(); if (!Objects.equals(document.getId(), documentId)) { LOG.warn("Document id [{}] does not match the resource document id [{}]", documentId, document.getId()); - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentIdMismatch", "Document id does not match the resource document id"); + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, DOCUMENT_ID_MISMATCH_TAG, DOCUMENT_ID_MISMATCH); } return publishDocumentVersion(document, version, resource.isReviewEnabled(), getInitialProperties(resource)); } @@ -131,7 +142,7 @@ public class UIDocumentService { DBResource resource = resourceDao.find(resourceId); DBDocument document = subresource.getDocument(); if (!Objects.equals(document.getId(), documentId)) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentIdMismatch", "Document id does not match the resource document id"); + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, DOCUMENT_ID_MISMATCH_TAG, DOCUMENT_ID_MISMATCH); } return publishDocumentVersion(document, version, resource.isReviewEnabled(), getInitialProperties(subresource)); } @@ -143,7 +154,7 @@ public class UIDocumentService { .filter(dv -> dv.getVersion() == version) .findFirst().orElse(null); if (documentVersion == null) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentVersionNotFound", "Document version not found"); + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, DOCUMENT_VERSION_NOT_FOUND_TAG, DOCUMENT_VERSION_NOT_FOUND); } if (isReviewEnabled && documentVersion.getStatus() != DocumentVersionStatusType.APPROVED) { throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentVersionAlreadyPublished", "Document version has wrong status"); @@ -169,7 +180,7 @@ public class UIDocumentService { DBResource resource = resourceDao.find(resourceId); DBDocument document = resource.getDocument(); if (!Objects.equals(document.getId(), documentId)) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentIdMismatch", "Document id does not match the resource document id"); + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, DOCUMENT_ID_MISMATCH_TAG, DOCUMENT_ID_MISMATCH); } return requestReviewDocumentVersion(document, version, resource.isReviewEnabled(), getInitialProperties(resource)); } @@ -181,7 +192,7 @@ public class UIDocumentService { DBSubresource subresource = subresourceDao.find(subresourceId); DBDocument document = subresource.getDocument(); if (!Objects.equals(document.getId(), documentId)) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentIdMismatch", "Document id does not match the resource document id"); + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, DOCUMENT_ID_MISMATCH_TAG, DOCUMENT_ID_MISMATCH); } return requestReviewDocumentVersion(document, version, resource.isReviewEnabled(), getInitialProperties(subresource)); } @@ -192,7 +203,7 @@ public class UIDocumentService { .filter(dv -> dv.getVersion() == version) .findFirst().orElse(null); if (documentVersion == null) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentVersionNotFound", "Document version not found"); + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, DOCUMENT_VERSION_NOT_FOUND_TAG, DOCUMENT_VERSION_NOT_FOUND); } if (!isReviewEnabled) { @@ -221,7 +232,7 @@ public class UIDocumentService { DBResource resource = resourceDao.find(resourceId); DBDocument document = resource.getDocument(); if (!Objects.equals(document.getId(), documentId)) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentIdMismatch", "Document id does not match the resource document id"); + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, DOCUMENT_ID_MISMATCH_TAG, DOCUMENT_ID_MISMATCH); } return reviewActionDocumentVersion(document, version, resource.isReviewEnabled(), action, message, getInitialProperties(resource)); } @@ -233,7 +244,7 @@ public class UIDocumentService { DBSubresource subresource = subresourceDao.find(subresourceId); DBDocument document = subresource.getDocument(); if (!Objects.equals(document.getId(), documentId)) { - throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentIdMismatch", "Document id does not match the subresource document id"); + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, DOCUMENT_ID_MISMATCH_TAG, "Document id does not match the subresource document id"); } return reviewActionDocumentVersion(document, version, resource.isReviewEnabled(), action, message, getInitialProperties(subresource)); } @@ -249,7 +260,7 @@ public class UIDocumentService { DBDocumentVersion documentVersion = document.getDocumentVersions().stream() .filter(dv -> dv.getVersion() == version) .findFirst() - .orElseThrow(() -> new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentVersionNotFound", "Document version not found")); + .orElseThrow(() -> new SMPRuntimeException(ErrorCode.INVALID_REQUEST, DOCUMENT_VERSION_NOT_FOUND_TAG, DOCUMENT_VERSION_NOT_FOUND)); if (!reviewEnabled) { throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "DocumentReviewNotEnabled", "Document Review is not enabled for the document"); @@ -450,20 +461,10 @@ public class UIDocumentService { throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "StoreResourceValidation", ExceptionUtils.getRootCauseMessage(e)); } - DBDocumentVersion documentVersion; - if (documentRo.getPayloadVersion() == null) { - documentVersion = createNewDocumentVersion(document, payload); - } 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(payload); - } - return documentVersion; - + // create new version to document or update existing version + return documentRo.getPayloadVersion() == null ? + createNewDocumentVersion(document, payload) : + updatedDocumentVersion(document, payload, documentRo.getPayloadVersion()); } private DBDocumentVersion storeSubresourcePayload(DBSubresource subresource, DBResource parentResource, DBDocument document, DocumentRO documentRo) { @@ -481,24 +482,36 @@ public class UIDocumentService { } catch (ResourceException e) { throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, "StoreSubresourceValidation", ExceptionUtils.getRootCauseMessage(e)); } + // create new version to document or update existing version + return documentRo.getPayloadVersion() == null ? + createNewDocumentVersion(document, payload) : + updatedDocumentVersion(document, payload, documentRo.getPayloadVersion()); + } - DBDocumentVersion documentVersion ; - if (documentRo.getPayloadVersion() == null) { - documentVersion = createNewDocumentVersion(document, payload); - } 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(payload); + /** + * Method sets new payload to the existing documentVersion with the given version and loges the event to documentVersion + * event list. The method returns the updated document version. + * + * @param document document to update + * @param payload new payload + * @param version version of the document to update + */ + protected DBDocumentVersion updatedDocumentVersion(DBDocument document, byte[] payload, int version) { + DBDocumentVersion documentVersion = document.getDocumentVersions().stream() + .filter(dv -> dv.getVersion() == version) + .findFirst().orElse(null); + if (documentVersion == null) { + throw new SMPRuntimeException(ErrorCode.INVALID_REQUEST, DOCUMENT_VERSION_NOT_FOUND_TAG, DOCUMENT_VERSION_NOT_FOUND); } - return documentVersion; + documentVersion.setContent(payload); + DBDocumentVersionEvent event = documentVersionService.createDocumentVersionEvent( + DocumentVersionEventType.UPDATE, DocumentVersionStatusType.DRAFT, EventSourceType.UI, null); + documentVersion.addNewDocumentVersionEvent(event); + return documentVersion; } - public DBDocumentVersion createNewDocumentVersion(DBDocument document, byte[] payload) { + protected DBDocumentVersion createNewDocumentVersion(DBDocument document, byte[] payload) { // create new version to document int version = document.getDocumentVersions().stream().mapToInt(DBDocumentVersion::getVersion) .max().orElse(0); @@ -550,6 +563,7 @@ public class UIDocumentService { storeResourcePayload(resource, document, documentRo) : storeSubresourcePayload(subresource, resource, document, documentRo); returnDocVersion = docVersion.getVersion(); + } if (isDocumentPropertiesChanged(documentRo)) { @@ -799,9 +813,8 @@ public class UIDocumentService { docConfigRo.setPublishedVersion(document.getCurrentVersion()); docConfigRo.setName(document.getName()); // set list of versions - document.getDocumentVersions().forEach(dv -> { - docConfigRo.getAllVersions().add(dv.getVersion()); - }); + document.getDocumentVersions().forEach(dv -> + docConfigRo.getAllVersions().add(dv.getVersion())); documentRo.setDocumentConfiguration(docConfigRo); document.getDocumentVersions().forEach(dv -> { @@ -829,17 +842,48 @@ public class UIDocumentService { documentRo.setPayload(new String(version.getContent())); documentRo.setDocumentVersionStatus(version.getStatus()); // set ven - version.getDocumentVersionEvents().stream().forEach(e -> { - DocumentVersionEventRO eventRo = new DocumentVersionEventRO(); - eventRo.setEventType(e.getEventType()); - eventRo.setEventOn(e.getEventOn()); - eventRo.setUsername(e.getUsername()); - eventRo.setEventSourceType(e.getEventSourceType()); - eventRo.setDetails(e.getDetails()); - documentRo.addDocumentVersionEvent(eventRo); - }); + version.getDocumentVersionEvents().stream().forEach(e -> + documentRo.addDocumentVersionEvent( + conversionService.convert(e, DocumentVersionEventRO.class)) + ); } return documentRo; } + /** + * Method validates all document versions and updates version in review process + * to NON REVIEW status. The change is logged as new event on version list. + * + * @param document + */ + public void updateToNonReviewStatuses(DBDocument document) { + updateDocumentVersionStatus(document, DocumentVersionEventType.SETTINGS_CHANGE, + REVIEW_STATUSES, + DocumentVersionStatusType.DRAFT); + } + + /* + * Method updates the document version status for the given document. The method updates the status for all + * document versions that have the old status. The change is logged as new event on version list. + */ + private void updateDocumentVersionStatus(DBDocument document, DocumentVersionEventType eventType, + List<DocumentVersionStatusType> oldStatus, + DocumentVersionStatusType newStatus) { + if (document == null) { + LOG.debug("DBDocument is null, cannot update document version status"); + return; + } + List<DBDocumentVersion> documentVersions = document.getDocumentVersions(); + documentVersions.forEach(version -> { + if (oldStatus.contains(version.getStatus())) { + DBDocumentVersionEvent docEvent = documentVersionService.createDocumentVersionEvent(eventType, + newStatus, + EventSourceType.UI, + null); + version.addNewDocumentVersionEvent(docEvent); + version.setStatus(newStatus); + } + }); + } + } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIResourceService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIResourceService.java index b37f4bfa94964cc5aef47bf171bb1942705aa254..66f218822763248d09989295785298a1b1f4287f 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIResourceService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIResourceService.java @@ -87,7 +87,6 @@ public class UIResourceService { private final DocumentVersionService documentVersionService; - public UIResourceService(ResourceDao resourceDao, ResourceMemberDao resourceMemberDao, ResourceDefDao resourceDefDao, DomainResourceDefDao domainResourceDefDao, UserDao userDao, GroupDao groupDao, IdentifierService identifierService, @@ -294,10 +293,22 @@ public class UIResourceService { DBResource resource = resourceDao.find(resourceId); resource.setVisibility(resourceRO.getVisibility()); if (resourceRO.isReviewEnabled() != null) { + Boolean newValue = isTrue(resourceRO.isReviewEnabled()); + Boolean oldValue = isTrue(resource.isReviewEnabled()); + // update resource review enabled in case if it was null before + resource.setReviewEnabled(newValue); + // check if new status is disabled and changed + if (oldValue != newValue && !newValue) { + // update all document versions to non review status + uiDocumentService.updateToNonReviewStatuses(resource.getDocument()); + // update statuses for all subresources + resource.getSubresources().stream().forEach(subResource -> + uiDocumentService.updateToNonReviewStatuses(subResource.getDocument())); + } resource.setReviewEnabled(isTrue(resourceRO.isReviewEnabled())); } ResourceRO resourceROResult = conversionService.convert(resource, ResourceRO.class); - if (StringUtils.isNotBlank(resourceRO.getResourceId())){ + if (StringUtils.isNotBlank(resourceRO.getResourceId())) { // return the same encrypted id so the UI can use update old resource resourceROResult.setResourceId(resourceRO.getResourceId()); } diff --git a/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb.ddl b/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb.ddl index a0f9e4b3479802b0be1a0b746e4bd8de8ab27738..3c2c4bea2ee9d0cdb61d6fc265aedcf44d6edd1d 100644 --- a/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb.ddl +++ b/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb.ddl @@ -243,6 +243,7 @@ EVENT_ON datetime comment 'Date time of the event', EVENT_SOURCE varchar(255) CHARACTER SET utf8 COLLATE utf8_bin not null comment 'Event source UI, API', EVENT_TYPE varchar(255) CHARACTER SET utf8 COLLATE utf8_bin not null comment 'Document version event type', + EVENT_STATUS varchar(255) CHARACTER SET utf8 COLLATE utf8_bin not null comment 'Document version event type', EVENT_BY_USERNAME varchar(64) CHARACTER SET utf8 COLLATE utf8_bin comment 'username identifier of the user who triggered the event', FK_DOCUMENT_VERSION_ID bigint, primary key (ID) diff --git a/smp-webapp/src/main/smp-setup/database-scripts/oracle10g.ddl b/smp-webapp/src/main/smp-setup/database-scripts/oracle10g.ddl index b1264295003ae4144f59e7f43fd95af171264d51..f0527aa413f1bbdf02733d5419d6d08f638dc3db 100644 --- a/smp-webapp/src/main/smp-setup/database-scripts/oracle10g.ddl +++ b/smp-webapp/src/main/smp-setup/database-scripts/oracle10g.ddl @@ -387,6 +387,7 @@ create sequence SMP_USER_SEQ start with 1 increment by 1; EVENT_ON timestamp, EVENT_SOURCE varchar2(255 char) not null, EVENT_TYPE varchar2(255 char) not null, + EVENT_STATUS varchar2(255 char) not null, EVENT_BY_USERNAME varchar2(64 char), FK_DOCUMENT_VERSION_ID number(19,0), primary key (ID) @@ -410,6 +411,9 @@ create sequence SMP_USER_SEQ start with 1 increment by 1; comment on column SMP_DOCUMENT_VERSION_EVENT.EVENT_TYPE is 'Document version event type'; + comment on column SMP_DOCUMENT_VERSION_EVENT.EVENT_STATUS is + 'Document version event type'; + comment on column SMP_DOCUMENT_VERSION_EVENT.EVENT_BY_USERNAME is 'username identifier of the user who triggered the event';