From 393962ce4427ecca5c22b3b5b8e5eea7a457fa6f Mon Sep 17 00:00:00 2001 From: Joze RIHTARSIC <joze.rihtarsic@ext.ec.europa.eu> Date: Fri, 19 Oct 2018 13:25:55 +0200 Subject: [PATCH] update service group search add service metadata dialog update service group deialog --- smp-angular/package-lock.json | 6 +- .../src/app/alerts/alerts.component.ts | 3 +- smp-angular/src/app/app.component.html | 2 +- smp-angular/src/app/app.module.ts | 7 +- smp-angular/src/app/app.routes.ts | 2 +- .../search-table/search-table.component.html | 3 + .../search-table/search-table.component.ts | 29 +++-- .../domain-details-dialog.component.html | 65 ++++++---- .../domain-details-dialog.component.ts | 34 +++-- ...ervice-group-details-dialog.component.html | 72 +++++++---- .../service-group-details-dialog.component.ts | 50 ++++---- .../service-group-edit-controller.ts | 43 +++++-- .../service-group-edit-ro.model.ts | 2 + .../service-group-edit.component.css | 16 +++ .../service-group-edit.component.html | 39 +++--- .../service-group-edit.component.ts | 116 +++++++++++++++--- ...rvice-group-metadata-dialog.component.html | 89 ++++++++------ ...service-group-metadata-dialog.component.ts | 55 ++++++++- .../service-metadata-edit-ro.model.ts | 9 +- .../service-group-search.component.css | 20 ++- .../service-group-search.component.html | 36 +++--- .../service-group-search.component.ts | 34 +++-- smp-angular/src/app/smp.constants.ts | 2 + .../ec/edelivery/smp/data/dao/BaseDao.java | 7 +- .../smp/data/dao/ServiceGroupDao.java | 81 ++++++++++++ .../smp/data/model/DBServiceGroupDomain.java | 4 + .../smp/data/ui/ServiceMetadataRO.java | 10 ++ .../exceptions/SMPTestIsALiveException.java | 12 ++ .../edelivery/smp/logging/SMPMessageCode.java | 17 +-- .../services/ui/UIServiceGroupService.java | 30 ++++- .../ui/filters/ServiceGroupFilter.java | 2 +- .../dao/ServiceGroupDaoIntegrationBase.java | 19 ++- .../dao/ServiceGroupDaoIntegrationTest.java | 49 ++++++++ .../edelivery/smp/config/SmpWebAppConfig.java | 5 +- .../smp/controllers/RootController.java | 65 ++++++++++ .../smp/monitor/MonitorResource.java | 8 +- .../ec/edelivery/smp/ui/SearchResource.java | 5 +- .../smp/ui/ServiceGroupResource.java | 16 ++- .../smp/ui/exception/UIException.java | 28 +++++ .../validation/ServiceMetadataValidator.java | 28 +++++ smp-webapp/src/main/resources/index.html | 32 +++++ smp-webapp/src/main/webapp/index.html | 31 +++++ .../main/webapp/static_resources/index.html | 1 + .../smp/monitor/MonitorResourceTest.java | 3 +- 44 files changed, 929 insertions(+), 258 deletions(-) create mode 100644 smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/SMPTestIsALiveException.java rename {smp-webapp/src/main/java/eu/europa/ec/edelivery/smp => smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services}/ui/filters/ServiceGroupFilter.java (91%) create mode 100644 smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/RootController.java create mode 100644 smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/exception/UIException.java create mode 100644 smp-webapp/src/main/resources/index.html create mode 100644 smp-webapp/src/main/webapp/index.html diff --git a/smp-angular/package-lock.json b/smp-angular/package-lock.json index 7bd1dcb8d..6eab6f6b0 100644 --- a/smp-angular/package-lock.json +++ b/smp-angular/package-lock.json @@ -3403,9 +3403,9 @@ } }, "file-saver": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.3.tgz", - "integrity": "sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg==" + "version": "1.3.3", + "resolved": "http://registry.npmjs.org/file-saver/-/file-saver-1.3.3.tgz", + "integrity": "sha1-zdTETTqiZOrC9o7BZbx5HDSvEjI=" }, "filename-regex": { "version": "2.0.1", diff --git a/smp-angular/src/app/alerts/alerts.component.ts b/smp-angular/src/app/alerts/alerts.component.ts index 320be0f5a..1efd1223a 100644 --- a/smp-angular/src/app/alerts/alerts.component.ts +++ b/smp-angular/src/app/alerts/alerts.component.ts @@ -206,10 +206,11 @@ export class AlertsComponent implements OnInit { this.aTypes = result.alertsType; this.loading = false; - +/* if(this.count > AlertComponent.MAX_COUNT_CSV) { this.alertService.error("Maximum number of rows reached for downloading CSV"); } + */ }, (error: any) => { console.log("error getting the alerts:" + error); this.loading = false; diff --git a/smp-angular/src/app/app.component.html b/smp-angular/src/app/app.component.html index 4957b3e62..bc76e90bb 100644 --- a/smp-angular/src/app/app.component.html +++ b/smp-angular/src/app/app.component.html @@ -4,7 +4,7 @@ <div id="topLogo"> <img src="assets/images/smp_logo_icon.svg" [attr.height]="fullMenu ? '74px' : '40px'" [attr.width]="fullMenu ? '74px' : '40px'"/> <div id="topLogoText" *ngIf="fullMenu"> - <h1>eDeliver SMP <span>Administration <br>Console</span></h1> + <h1>eDelivery SMP <span>Administration <br>Console</span></h1> </div> </div> diff --git a/smp-angular/src/app/app.module.ts b/smp-angular/src/app/app.module.ts index 721bd6f1c..a748369f2 100644 --- a/smp-angular/src/app/app.module.ts +++ b/smp-angular/src/app/app.module.ts @@ -2,7 +2,7 @@ import {BrowserModule} from '@angular/platform-browser'; import {NgModule} from '@angular/core'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {HttpClient, HttpClientModule} from '@angular/common/http'; -import { FlexLayoutModule } from "@angular/flex-layout"; +import {FlexLayoutModule} from "@angular/flex-layout"; import { MatButtonModule, MatDialogModule, @@ -17,7 +17,7 @@ import { MatDatepicker, MatCardModule, MatDatepickerModule, - MatSlideToggleModule, + MatSlideToggleModule, MatTab, MatAccordion, MatTabsModule, } from '@angular/material'; import "hammerjs"; @@ -71,6 +71,7 @@ import {DownloadService} from './download/download.service'; import {UserService} from './user/user.service'; import {RoleService} from './security/role.service'; import {CertificateService} from './user/certificate.service'; +import {GlobalLookups} from "./common/global-lookups"; @NgModule({ declarations: [ @@ -130,6 +131,7 @@ import {CertificateService} from './user/certificate.service'; MatListModule, MatSidenavModule, MatSelectModule, + MatTabsModule, MatSlideToggleModule, routing, ReactiveFormsModule, @@ -151,6 +153,7 @@ import {CertificateService} from './user/certificate.service'; UserService, CertificateService, RoleService, + GlobalLookups, { provide: ExtendedHttpClient, useFactory: extendedHttpClientCreator, diff --git a/smp-angular/src/app/app.routes.ts b/smp-angular/src/app/app.routes.ts index 9044c4b66..079536ecb 100644 --- a/smp-angular/src/app/app.routes.ts +++ b/smp-angular/src/app/app.routes.ts @@ -20,4 +20,4 @@ const appRoutes: Routes = [ ]; -export const routing = RouterModule.forRoot(appRoutes); +export const routing = RouterModule.forRoot(appRoutes, {useHash: true}); diff --git a/smp-angular/src/app/common/search-table/search-table.component.html b/smp-angular/src/app/common/search-table/search-table.component.html index 2b52cd6f8..67c1b7e94 100644 --- a/smp-angular/src/app/common/search-table/search-table.component.html +++ b/smp-angular/src/app/common/search-table/search-table.component.html @@ -71,6 +71,9 @@ <ng-template #rowActions let-row="row" ngx-datatable-cell-template> <div> + <ng-container [ngTemplateOutlet]="additionalRowActionButtons" + [ngTemplateOutletContext]="{row:row}"></ng-container> + <button mat-icon-button color="primary" [disabled]="row.deleted || loading" (click)="editSearchTableEntityRow(row)" tooltip="Edit"> <mat-icon>edit</mat-icon> diff --git a/smp-angular/src/app/common/search-table/search-table.component.ts b/smp-angular/src/app/common/search-table/search-table.component.ts index 27ecf945b..61af407ce 100644 --- a/smp-angular/src/app/common/search-table/search-table.component.ts +++ b/smp-angular/src/app/common/search-table/search-table.component.ts @@ -30,6 +30,7 @@ export class SearchTableComponent implements OnInit { @ViewChild('rowIndex') rowIndex: TemplateRef<any>; @Input() @ViewChild('additionalToolButtons') additionalToolButtons: TemplateRef<any>; + @Input() @ViewChild('additionalRowActionButtons') additionalRowActionButtons: TemplateRef<any>; @Input() @ViewChild('searchPanel') searchPanel: TemplateRef<any>; @Input() @ViewChild('tableRowDetailContainer') tableRowDetailContainer: TemplateRef<any>; @@ -65,6 +66,7 @@ export class SearchTableComponent implements OnInit { protected alertService: AlertService, private downloadService: DownloadService, public dialog: MatDialog) { + } ngOnInit() { @@ -79,8 +81,8 @@ export class SearchTableComponent implements OnInit { this.columnActions = { cellTemplate: this.rowActions, name: 'Actions', - width: 120, - maxWidth:150, + width: 250, + maxWidth:250, sortable: false }; this.columnExpandDetails= { @@ -108,7 +110,6 @@ export class SearchTableComponent implements OnInit { this.columnPicker.selectedColumns.push(this.columnActions); } } - this.page(this.offset, this.rowLimiter.pageSize, this.orderBy, this.asc); } getRowClass(row) { @@ -156,10 +157,10 @@ export class SearchTableComponent implements OnInit { status: SearchTableEntityStatus.PERSISTED, deleted: false} }); - + /* if(this.count > AlertComponent.MAX_COUNT_CSV) { this.alertService.error("Maximum number of rows reached for downloading CSV"); - } + }*/ }, (error: any) => { this.alertService.error("Error occurred:" + error); }); @@ -207,10 +208,10 @@ export class SearchTableComponent implements OnInit { }); formRef.afterClosed().subscribe(result => { if (result) { - this.rows = [...this.rows, {...formRef.componentInstance.current}]; + this.rows = [...this.rows, {...formRef.componentInstance.getCurrent()}]; //this.rows = this.rows.concat(formRef.componentInstance.current); this.count++; - // this.searchTable.refresh(); + // this.searchtable.refresh(); } else { this.unselectRows(); } @@ -305,11 +306,20 @@ export class SearchTableComponent implements OnInit { const status = row.status === SearchTableEntityStatus.PERSISTED ? SearchTableEntityStatus.UPDATED : row.status; - this.rows[rowNumber] = {...formRef.componentInstance.current, status}; - this.rows = [...this.rows]; + this.rows[rowNumber] = {...formRef.componentInstance.getCurrent(), status}; + this.rows = [...this.rows]; } }); } + public updateTableRow(rowNumber:number, row:any, status:SearchTableEntityStatus ) { + this.rows[rowNumber] = {...row, status}; + this.rows = [...this.rows]; + } + public getRowNumber(row:any){ + return this.rows.indexOf(row); + } + + private editSearchTableEntityRow(row: SearchTableEntity) { let rowNumber = this.rows.indexOf(row); this.editSearchTableEntity(rowNumber); @@ -326,6 +336,7 @@ export class SearchTableComponent implements OnInit { if (row.status === SearchTableEntityStatus.NEW) { this.rows.splice(this.rows.indexOf(row), 1); } else { + this.searchTableController.delete(row); row.status = SearchTableEntityStatus.REMOVED; row.deleted = true; } diff --git a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.html b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.html index 48af80189..49f9bcb12 100644 --- a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.html +++ b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.html @@ -1,48 +1,59 @@ <h2 mat-dialog-title>{{formTitle}}</h2> <mat-dialog-content> - + <form [formGroup]="domainForm"> <mat-card> + <mat-card-title>Domain properties</mat-card-title> <mat-card-content> - <div class="panel"> <fieldset style="border: none;"> <mat-form-field style="width:100%"> - <input matInput placeholder="Domain Code ()" name="domainCode" value="{{current.domainCode}}" id="domainCode_id" - (blur)="updateDomainCode($event)" [formControl]="domainForm.controls['domainCode']" maxlength="255" required> + <input matInput placeholder="Domain Code (For WS API integration: the Domain property.)" name="domainCode" id="domainCode_id" + [formControl]="domainForm.controls['domainCode']" maxlength="255" required> <div *ngIf="(!editMode && domainForm.controls['domainCode'].touched || editMode) && domainForm.controls['domainCode'].hasError('pattern')" style="color:red; font-size: 70%"> - Domain could must contain only chars. + Domain could must contain only chars and numbers. </div> </mat-form-field> <mat-form-field style="width:100%"> - <input matInput placeholder="SML domain (Part of DNS Zone: ex.eHealth: 'ehealth', peppol: '', ..)" name="smlSubdomain" value="{{current.smlSubdomain}}" id="smldomain_id" - (blur)="updateSmlDomain($event)" [formControl]="domainForm.controls['smlSubdomain']" maxlength="255" required> + <input matInput placeholder="SML domain (Part of DNS Zone: ex.eHealth: 'ehealth', peppol: '', ..)" name="smlSubdomain" id="smldomain_id" + [formControl]="domainForm.controls['smlSubdomain']" maxlength="255" > <div *ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode) && domainForm.controls['smlSubdomain'].hasError('pattern')" style="color:red; font-size: 70%"> - SML domain must be valid DNS part (AlphaNumeric with optional char -). + SML domain must be valid DNS part (AlphaNumeric with optional char - or must be empty for peppol). </div> </mat-form-field> <mat-form-field style="width:100%"> - <input matInput placeholder="SML SMP identifier (SMP ID used for SML )" name="smlSmpId" value="{{current.smlSmpId}}" id="smlSMPId_id" - (blur)="updateSmlSmpId($event)" [formControl]="domainForm.controls['smlSmpId']" maxlength="255" required> - <div *ngIf="(!editMode && domainForm.controls['smlSmpId'].touched || editMode) && domainForm.controls['smlSmpId'].hasError('pattern')" style="color:red; font-size: 70%"> - SML SMP ID must be valid DNS part (AlphaNumeric with optional char -). - </div> - - </mat-form-field> - <mat-form-field style="width:100%"> - <input matInput placeholder="SML Client certificate" name="Client certificate" value="{{current.smlClientKeyAlias}}" id="smlClientKeyAlias_id" - (blur)="updateSmlClientKeyAlias($event)" [formControl]="domainForm.controls['smlClientKeyAlias']" maxlength="255" required> - </mat-form-field> - <mat-form-field style="width:100%"> - <input matInput placeholder="Response signature Certificate" name="signatureKeyAlias" value="{{current.signatureKeyAlias}}" id="signatureKeyAlias_id" - (blur)="updateSignatureKeyAlias($event)" [formControl]="domainForm.controls['signatureKeyAlias']" maxlength="255" required> + <input matInput placeholder="Response signature Certificate" name="signatureKeyAlias" id="signatureKeyAlias_id" + [formControl]="domainForm.controls['signatureKeyAlias']" maxlength="255" > </mat-form-field> </fieldset> - <!-- label class="custom-file-upload"> - <input #fileInput type="file" id="custom-file-upload" accept=".cer" (change)="uploadCertificate()" > - <span class="custom-file-upload-inner">Import</span> - </label--> - </div> </mat-card-content> </mat-card> + <mat-card> + <mat-card-title>SML integration data</mat-card-title> + <mat-card-content> + <fieldset style="border: none;"> + <mat-form-field style="width:100%"> + <input matInput placeholder="SML SMP identifier (SMP ID used for SML )" name="smlSmpId" id="smlSMPId_id" + [formControl]="domainForm.controls['smlSmpId']" maxlength="255" required> + <div *ngIf="(!editMode && domainForm.controls['smlSmpId'].touched || editMode) && domainForm.controls['smlSmpId'].hasError('pattern')" style="color:red; font-size: 70%"> + SML SMP ID must be valid DNS part (AlphaNumeric with optional char -). + </div> + + </mat-form-field> + <mat-form-field style="width:100%"> + <input matInput placeholder="ClientCert Header" name="Client certificate" id="smlClientHeader_id" + [formControl]="domainForm.controls['smlClientKeyAlias']" maxlength="255" > + </mat-form-field> + <mat-form-field style="width:100%"> + <input matInput placeholder="ClientCert Alias" name="Client certificate" id="smlClientKeyAlias_id" + [formControl]="domainForm.controls['smlClientKeyAlias']" maxlength="255" > + </mat-form-field> + </fieldset> + <!-- label class="custom-file-upload"> + <input #fileInput type="file" id="custom-file-upload" accept=".cer" (change)="uploadCertificate()" > + <span class="custom-file-upload-inner">Import</span> + </label--> + </mat-card-content> + </mat-card> + </form> </mat-dialog-content> <table class="buttonsRow"> diff --git a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts index 092a11652..d2204ad31 100644 --- a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts +++ b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts @@ -18,15 +18,13 @@ export class DomainDetailsDialogComponent { static readonly NEW_MODE = 'New Domain'; static readonly EDIT_MODE = 'Domain Edit'; - readonly dnsDomainPattern = '^(?!(\\d|-|_).+)[a-zA-Z0-9-]{1,63}$'; - readonly domainCodePattern = '^[a-zA-Z]{1,255}$'; + readonly dnsDomainPattern = '^(?![0-9]+$)(?!.*-$)(?!-)[a-zA-Z0-9-]{0,63}$'; + readonly domainCodePattern = '^[a-zA-Z0-9]{1,255}$'; editMode: boolean; formTitle: string; current: DomainRo & { confirmation?: string }; domainForm: FormGroup; - - domain; @@ -52,16 +50,22 @@ export class DomainDetailsDialogComponent { this.domainForm = fb.group({ - 'domainCode': new FormControl({value: this.current.domainCode, disabled: this.editMode}, [Validators.pattern(this.domainCodePattern)]), - 'smlSubdomain': new FormControl({value: this.current.smlSubdomain, disabled: this.editMode}, [Validators.pattern(this.dnsDomainPattern)]), - 'smlSmpId': new FormControl({value: this.current.smlSmpId}, [Validators.required, Validators.pattern(this.dnsDomainPattern)]), - 'smlClientKeyAlias': new FormControl({value: this.current.smlClientKeyAlias}, null), - 'signatureKeyAlias': new FormControl({value: this.current.signatureKeyAlias}, null), - + 'domainCode': new FormControl({value:'', disabled: this.editMode}, [Validators.pattern(this.domainCodePattern)]), + 'smlSubdomain': new FormControl({value: '', disabled: this.editMode}, [Validators.pattern(this.dnsDomainPattern)]), + 'smlSmpId': new FormControl({value: ''}, [Validators.pattern(this.dnsDomainPattern)]), + 'smlClientKeyAlias': new FormControl({value: ''}, null), + 'signatureKeyAlias': new FormControl({value:''}, null), }, { //validator: this.passwordConfirmationValidator }); + this.domainForm.controls['domainCode'].setValue(this.current.domainCode); + this.domainForm.controls['smlSubdomain'].setValue(this.current.smlSubdomain); + this.domainForm.controls['smlSmpId'].setValue(this.current.smlSmpId); + this.domainForm.controls['smlClientKeyAlias'].setValue(this.current.smlClientKeyAlias); + this.domainForm.controls['signatureKeyAlias'].setValue(this.current.signatureKeyAlias); + + } submitForm() { this.checkValidity(this.domainForm) @@ -81,7 +85,17 @@ export class DomainDetailsDialogComponent { }); } + public getCurrent(): DomainRo { + + this.current.domainCode = this.domainForm.value['domainCode']; + this.current.smlSubdomain = this.domainForm.value['smlSubdomain']; + this.current.smlSmpId = this.domainForm.value['smlSmpId']; + this.current.smlClientKeyAlias = this.domainForm.value['smlClientKeyAlias']; + this.current.signatureKeyAlias = this.domainForm.value['signatureKeyAlias']; + return this.current; + + } updateDomainCode(event) { this.current.domainCode = event.target.value; } diff --git a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.html b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.html index d29e25dc3..8161bf22d 100644 --- a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.html +++ b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.html @@ -1,11 +1,12 @@ <h2 mat-dialog-title>{{formTitle}}</h2> -<mat-dialog-content style="height:600px;width:1100px"> +<mat-dialog-content style="height:620px;width:1200px"> <div fxLayout="row"> <div fxLayout="column"> <mat-card fxFlex="200px"> - <mat-card-title>Identifier</mat-card-title> - <mat-card-content> + <!-- mat-card-title>Identifier</mat-card-title --> + <mat-card-content style="height: 100px"> + <div class="panel"> <mat-form-field style="width:100%"> <input matInput placeholder="Participant identifier" name="participantIdentifier" value="{{current.participantIdentifier}}" id="participantIdentifier_id" @@ -29,25 +30,54 @@ Participant scheme must not be empty. </div> </mat-form-field> + </div> </mat-card-content> </mat-card> <mat-card> - <mat-card-title>Owners</mat-card-title> + <!-- mat-card-title>Owners/Domains</mat-card-title --> <mat-card-content> - <p>Selected user count: {{usersSelected.selectedOptions.selected.length}}</p> - <mat-selection-list #usersSelected [compareWith]="compareUserById" - (selectionChange)="userListChanged(usersSelected.selectedOptions.selected,$event)" - [formControl]="formControlUsers" - style="height: 200px; overflow-y: scroll; overflow-x: auto;"> - <mat-list-option *ngFor="let user of userlist" [value]='user'> - {{user.id}} - {{user.username?user.username:user.id}} - </mat-list-option> - </mat-selection-list> - <div - *ngIf="(!editMode && dialogForm.controls['users'].touched || editMode) && dialogForm.controls['users'].hasError('minCountOwners')" - style="color:red; font-size: 70%"> - At least one user (owner) must be selected! - </div> + + <mat-accordion> + <mat-expansion-panel [expanded]="true"> + <mat-expansion-panel-header> + <mat-panel-title>Owners</mat-panel-title> + <mat-panel-description> + Selected user count: {{usersSelected.selectedOptions.selected.length}} + </mat-panel-description> + </mat-expansion-panel-header> + <mat-selection-list #usersSelected [compareWith]="compareTableItemById" + (selectionChange)="userListChanged(usersSelected.selectedOptions.selected,$event)" + [formControl]="formControlUsers" + style="height: 200px; overflow-y: scroll; overflow-x: auto;"> + <mat-list-option *ngFor="let user of userlist" [value]='user'> + {{user.id}} - {{user.username?user.username:user.id}} + </mat-list-option> + </mat-selection-list> + </mat-expansion-panel> + + <mat-expansion-panel > + <mat-expansion-panel-header> + <mat-panel-title>Domains</mat-panel-title> + <mat-panel-description> + Selected domain count: {{domainSelected.selectedOptions.selected.length}} + </mat-panel-description> + </mat-expansion-panel-header> + <mat-selection-list #domainSelected [compareWith]="compareTableItemById" + [formControl]="formControlDomain" + style="height: 200px; overflow-y: scroll; overflow-x: auto;"> + <mat-list-option *ngFor="let domain of domainList" [value]='domain'> + {{domain.domainCode}} ({{domain.smlSubdomain}}) + </mat-list-option> + </mat-selection-list> + </mat-expansion-panel> + </mat-accordion> + + + <div + *ngIf="(!editMode && dialogForm.controls['users'].touched || editMode) && dialogForm.controls['users'].hasError('minSelectedListCount')" + style="color:red; font-size: 70%"> + At least one user (owner) must be selected! + </div> </mat-card-content> </mat-card> </div> @@ -58,9 +88,9 @@ <p> Extension is automatically wrapped to root element to form vaild XML! No ExtensionWrapper element is needed. </p> - <mat-form-field> - <textarea id="extensionTextArea" resizeable="false" placeholder="Extension" name="extension" ></textarea> - </mat-form-field> + <!--mat-form-field> + < textarea id="extensionTextArea" resizeable="false" placeholder="Extension" name="extension"></textarea> + </mat-form-field --> </mat-card-content> </mat-card> </div> diff --git a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts index 1af2b0bd1..7d17a32f1 100644 --- a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts +++ b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts @@ -12,6 +12,7 @@ import {SearchTableEntityStatus} from "../../common/search-table/search-table-en import {DomainRo} from "../../domain/domain-ro.model"; import {ServiceGroupEditRo} from "../service-group-edit-ro.model"; import {ServiceMetadataEditRo} from "../service-metadata-edit-ro.model"; +import {GlobalLookups} from "../../common/global-lookups"; @Component({ selector: 'app-messagelog-details', @@ -27,6 +28,7 @@ export class ServiceGroupDetailsDialogComponent { userObserver: Observable< SearchTableResult> ; domainObserver: Observable< SearchTableResult> ; userlist: Array<UserRo> = []; + domainList: Array<DomainRo> = []; editMode: boolean; formTitle: string; current: ServiceGroupEditRo & { confirmation?: string }; @@ -34,12 +36,13 @@ export class ServiceGroupDetailsDialogComponent { dialogForm: FormGroup; dialogFormBuilder: FormBuilder; formControlUsers: FormControl; + formControlDomain: FormControl; /* selectedDomain: DomainRo; domainList: Array<any>; */ - minCountOwners(min: number) { + minSelectedListCount(min: number) { return (c: AbstractControl): {[key: string]: any} => { if (c.value.length >= min) return null; @@ -48,13 +51,14 @@ export class ServiceGroupDetailsDialogComponent { } } - constructor(protected http: HttpClient, public dialogRef: MatDialogRef<ServiceGroupDetailsDialogComponent>, - private alertService: AlertService, + constructor(protected http: HttpClient, + public dialogRef: MatDialogRef<ServiceGroupDetailsDialogComponent>, + private alertService: AlertService, + private lookups: GlobalLookups, @Inject(MAT_DIALOG_DATA) public data: any, private fb: FormBuilder) { // init user list - - this.userObserver = this.http.get<SearchTableResult>(SmpConstants.REST_USER); + this.userObserver = this.http.get<SearchTableResult>(SmpConstants.REST_USER); this.userObserver.subscribe((users: SearchTableResult) => { this.userlist = new Array(users.serviceEntities.length) .map((v, index) => users.serviceEntities[index] as UserRo); @@ -62,24 +66,21 @@ export class ServiceGroupDetailsDialogComponent { this.userlist = users.serviceEntities.map(serviceEntity => { return {...<UserRo>serviceEntity} }); - this.updateData(); + this.updateUserData(); }); - /* - // init domains - this.domainObserver = this.http.get<SearchTableResult>(SmpConstants.REST_DOMAIN); - this.domainObserver.subscribe((domains: SearchTableResult) => { + // domain service group + this.lookups.getDomainLookupObservable().subscribe((domains: SearchTableResult) => { this.domainList = new Array(domains.serviceEntities.length) - .map((v, index) => {domains.serviceEntities[index] as DomainRo; - if ( this.editMode && v.domainCode ===data.row.domainCode) { - this.selectedDomain = v as DomainRo; - } - }); + .map((v, index) => domains.serviceEntities[index] as DomainRo); this.domainList = domains.serviceEntities.map(serviceEntity => { - return {...serviceEntity} + return {...<DomainRo>serviceEntity} }); + this.updateDomainData(); }); -*/ + + + this.dialogFormBuilder = fb; this.editMode = data.edit; this.formTitle = this.editMode ? ServiceGroupDetailsDialogComponent.EDIT_MODE: ServiceGroupDetailsDialogComponent.NEW_MODE; @@ -98,25 +99,28 @@ export class ServiceGroupDetailsDialogComponent { }; this.dialogForm = this.dialogFormBuilder.group({ - 'participantIdentifier': new FormControl({value: this.current.participantIdentifier, disabled: this.editMode}, this.editMode ? Validators.required : null), 'participantScheme': new FormControl({value: this.current.participantScheme, disabled: this.editMode}, this.editMode ? Validators.required : null), 'domainCode': new FormControl({value: this.current.domainCode},this.editMode ? Validators.required : null), - //'users': [new FormControl({value: this.current.users}, [ this.minCountOwners(1)] )], }); } - updateData(){ + updateUserData(){ this.formControlUsers = new FormControl(this.current.users); - this.formControlUsers.setValidators( [ this.minCountOwners(1)]); - + this.formControlUsers.setValidators( [ this.minSelectedListCount(1)]); this.dialogForm.addControl("users",this.formControlUsers ); } + updateDomainData(){ + this.formControlDomain = new FormControl(this.current.domains); + this.formControlDomain.setValidators( [ this.minSelectedListCount(1)]); + this.dialogForm.addControl("domains",this.formControlDomain ); + } + submitForm() { this.checkValidity(this.dialogForm) @@ -150,7 +154,7 @@ export class ServiceGroupDetailsDialogComponent { this.current.users.push(usr.value); } } - compareUserById(item1, item2): boolean{ + compareTableItemById(item1, item2): boolean{ return item1.id=== item2.id; } diff --git a/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts b/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts index fa802d8a0..23dc032ef 100644 --- a/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts +++ b/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts @@ -5,43 +5,70 @@ import {ServiceGroupEditRo} from './service-group-edit-ro.model'; import {SearchTableEntityStatus} from '../common/search-table/search-table-entity-status.model'; import {ServiceMetadataEditRo} from "./service-metadata-edit-ro.model"; import {DomainDetailsDialogComponent} from "../domain/domain-details-dialog/domain-details-dialog.component"; +import {ServiceGroupMetadataDialogComponent} from "./service-group-metadata-dialog/service-group-metadata-dialog.component"; export class ServiceGroupEditController implements SearchTableController { - constructor(public dialog: MatDialog) { } + constructor(public dialog: MatDialog) { + } - public showDetails( row: any, config?: MatDialogConfig,) { + public showDetails(row: any, config?: MatDialogConfig,) { let dialogRef: MatDialogRef<ServiceGroupDetailsDialogComponent> = this.dialog.open(ServiceGroupDetailsDialogComponent); dialogRef.afterClosed().subscribe(result => { //Todo: }); - } - public showMetadataList(row: any) { + public edit(row: any) { } + public delete(row: any) { - public edit(row: any) { } + // set all rows as deleted + let sgRow = row as ServiceGroupEditRo; + sgRow.serviceMetadata.forEach(function(part, index, metaDataList) { + metaDataList[index].status = SearchTableEntityStatus.REMOVED; + metaDataList[index].deleted=true; + }); - public delete(row: any) { } + } public newDialog(config?: MatDialogConfig): MatDialogRef<ServiceGroupDetailsDialogComponent> { return this.dialog.open(ServiceGroupDetailsDialogComponent, config); } + public newMetadataDialog(config?: MatDialogConfig): MatDialogRef<ServiceGroupMetadataDialogComponent> { + return this.dialog.open(ServiceGroupMetadataDialogComponent, config); + } + public newRow(): ServiceGroupEditRo { return { id: null, index: null, - participantIdentifier:'', + participantIdentifier: '', participantScheme: '', domainCode: '', smlSubdomain: '', - serviceMetadata:[], + serviceMetadata: [], users: [], + domains: [], + status: SearchTableEntityStatus.NEW + }; + } + + public newServiceMetadataRow(): ServiceMetadataEditRo { + return { + id:null, + documentIdentifier: '', + documentIdentifierScheme: '', + smlSubdomain: '', + domainCode: '', + processSchema: '', + processIdentifier: '', + endpointUrl: '', + endpointCertificate: '', status: SearchTableEntityStatus.NEW }; } diff --git a/smp-angular/src/app/service-group-edit/service-group-edit-ro.model.ts b/smp-angular/src/app/service-group-edit/service-group-edit-ro.model.ts index 9b626bc7e..0fcbd1d60 100644 --- a/smp-angular/src/app/service-group-edit/service-group-edit-ro.model.ts +++ b/smp-angular/src/app/service-group-edit/service-group-edit-ro.model.ts @@ -1,6 +1,7 @@ import { ServiceMetadataEditRo } from './service-metadata-edit-ro.model'; import {SearchTableEntity} from "../common/search-table/search-table-entity.model"; import {UserRo} from "../user/user-ro.model"; +import {DomainRo} from "../domain/domain-ro.model"; export interface ServiceGroupEditRo extends SearchTableEntity { id: number; @@ -9,5 +10,6 @@ export interface ServiceGroupEditRo extends SearchTableEntity { domainCode:'', smlSubdomain:'', serviceMetadata: Array<ServiceMetadataEditRo>; + domains: Array<DomainRo>; users: Array<UserRo>; } diff --git a/smp-angular/src/app/service-group-edit/service-group-edit.component.css b/smp-angular/src/app/service-group-edit/service-group-edit.component.css index d1a612141..14b69d931 100644 --- a/smp-angular/src/app/service-group-edit/service-group-edit.component.css +++ b/smp-angular/src/app/service-group-edit/service-group-edit.component.css @@ -16,3 +16,19 @@ .datatable-body{ overflow-y: scroll; } + + +/deep/ .inner-table { + margin-left: 100px; + width: 80%; +} + +/deep/ .inner-table .datatable-body-cell { + padding: 1.5em 2px !important; + +} + +/deep/ .inner-table .mat-icon-button { + height: auto !important;; + line-height: unset !important; +} diff --git a/smp-angular/src/app/service-group-edit/service-group-edit.component.html b/smp-angular/src/app/service-group-edit/service-group-edit.component.html index 894019e35..1db04a19c 100644 --- a/smp-angular/src/app/service-group-edit/service-group-edit.component.html +++ b/smp-angular/src/app/service-group-edit/service-group-edit.component.html @@ -1,4 +1,4 @@ -<smp-search-table +<smp-search-table #searchTable page_id='edit_id' title='Edit' [columnPicker]="columnPicker" @@ -8,16 +8,20 @@ [filter]="filter" [searchTableController]="serviceGroupEditController" [tableRowDetailContainer]="tableRowDetailContainer" + [additionalRowActionButtons]="additionalRowActionButtons" > <ng-template #rowMetadataAction let-row="row" let-value="value" ngx-datatable-cell-template> - <button mat-button color="primary" (click)="metadataRowButtonAction(row)" id="metadataRowButtonAction{{row.$$index}}_id" tooltip="Metadata"> <mat-icon>view_list</mat-icon> <span>Metadata</span> </button> + </ng-template> + <ng-template #rowSMPUrlLinkAction let-row="row" let-value="value" ngx-datatable-cell-template> + <a target="_blank" + href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}" >Open URL</a> </ng-template> @@ -30,26 +34,25 @@ <input matInput placeholder="Participant schema" name="patricipantSchema" [(ngModel)]="filter.messageId" #messageId="ngModel" id="participanschema_id"> </mat-form-field> - <mat-select placeholder="Domain " [(ngModel)]="filter.messageStatus" name="messageStatus" - id="messagestatus_id"> + + <mat-select placeholder="Domain (sml subdomain)" [(ngModel)]="filter.domain" name="domain" + id="domain_id"> <mat-option [value]="''"> </mat-option> - <mat-option *ngFor="let mstatus of msgStatus" [value]="mstatus"> - {{mstatus}} + <mat-option *ngFor="let domain of domainlist" [value]="domain.domainCode"> + {{domain.domainCode}} ({{domain.smlSubdomain}}) </mat-option> </mat-select> </ng-template> - <ng-template #additionalToolButtons> - <div style="background-color: #03A9F4; display: inline-block; width: 3px; height: 100%; margin-right: 8px"> - </div> - <button mat-raised-button color="primary" - id="metadatabutton_id"> - <mat-icon>view_list</mat-icon> - <span>Metadata</span> - </button> + <ng-template #additionalToolButtons></ng-template> + <ng-template #additionalRowActionButtons let-row="row"> + <button mat-icon-button color="primary" [disabled]="row?.deleted || loading" + (click)="onAddMetadataRow(row)" tooltip="Edit"> + <mat-icon>playlist_add</mat-icon> + </button> </ng-template> <ng-template #tableRowDetailContainer let-row="row"> @@ -59,14 +62,14 @@ </div> <div *ngIf="row.serviceMetadata.length !== 0" > <ngx-datatable - class='material striped' - style="width: 80%" + class='inner-table material striped' [loadingIndicator]="loading" [rows]='row.serviceMetadata' [columnMode]='"force"' [headerHeight]='50' [footerHeight]='50' - [rowHeight]='"auto"'> + [rowHeight]='"auto"' + [rowClass]="getRowClass"> <ngx-datatable-column prop="domainCode" name="Domain" maxWidth="250" ></ngx-datatable-column> <ngx-datatable-column prop="documentIdentifierScheme" name="Document identifier scheme" maxWidth="350" ></ngx-datatable-column> <ngx-datatable-column prop="documentIdentifier" name="Document identifier" maxWidth="250" ></ngx-datatable-column> @@ -86,7 +89,7 @@ <mat-icon>edit</mat-icon> </button> <button mat-icon-button color="primary" [disabled]="rowSmd.deleted || loading" - (click)="onDeleteMetadataRowActionClicked(rowSmd)" tooltip="Delete"> + (click)="onDeleteMetadataRowActionClicked(row, rowSmd)" tooltip="Delete"> <mat-icon>delete</mat-icon> </button> </div> diff --git a/smp-angular/src/app/service-group-edit/service-group-edit.component.ts b/smp-angular/src/app/service-group-edit/service-group-edit.component.ts index b81066cb4..73b6f9211 100644 --- a/smp-angular/src/app/service-group-edit/service-group-edit.component.ts +++ b/smp-angular/src/app/service-group-edit/service-group-edit.component.ts @@ -9,28 +9,36 @@ import {SmpConstants} from "../smp.constants"; import {Observable} from "rxjs/internal/Observable"; import {UserRo} from "../user/user-ro.model"; import {SearchTableResult} from "../common/search-table/search-table-result.model"; +import {SearchTableEntityStatus} from "../common/search-table/search-table-entity-status.model"; +import {SearchTableComponent} from "../common/search-table/search-table.component"; +import {ServiceMetadataEditRo} from "./service-metadata-edit-ro.model"; +import {ServiceGroupEditRo} from "./service-group-edit-ro.model"; +import {GlobalLookups} from "../common/global-lookups"; +import {DomainRo} from "../domain/domain-ro.model"; @Component({ moduleId: module.id, - templateUrl:'./service-group-edit.component.html', + templateUrl: './service-group-edit.component.html', styleUrls: ['./service-group-edit.component.css'] }) export class ServiceGroupEditComponent implements OnInit { @ViewChild('rowMetadataAction') rowMetadataAction: TemplateRef<any> @ViewChild('rowActions') rowActions: TemplateRef<any>; - @ViewChild('rowSMPUrlLinkAction') rowSMPUrlLinkAction: TemplateRef<any> + @ViewChild('rowSMPUrlLinkAction') rowSMPUrlLinkAction: TemplateRef<any>; + @ViewChild('searchTable') searchTable: SearchTableComponent; columnPicker: ColumnPicker = new ColumnPicker(); serviceGroupEditController: ServiceGroupEditController; filter: any = {}; baseUrl: string = SmpConstants.REST_EDIT; - userObserver: Observable< SearchTableResult> ; - domainObserver: Observable< SearchTableResult> ; + userObserver: Observable<SearchTableResult>; + domainObserver: Observable<SearchTableResult>; userlist: Array<UserRo> = []; + domainlist: Array<any>; - constructor(protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) { + constructor(protected lookups: GlobalLookups, protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) { this.userObserver = this.http.get<SearchTableResult>(SmpConstants.REST_USER); this.userObserver.subscribe((users: SearchTableResult) => { @@ -41,29 +49,43 @@ export class ServiceGroupEditComponent implements OnInit { return {...<UserRo>serviceEntity} }); }); + + this.lookups.getDomainLookupObservable().subscribe((domains: SearchTableResult) => { + this.domainlist = new Array(domains.serviceEntities.length) + .map((v, index) => domains.serviceEntities[index] as DomainRo); + + this.domainlist = domains.serviceEntities.map(serviceEntity => { + return {...<DomainRo>serviceEntity} + }); + }); } ngOnInit() { + + this.serviceGroupEditController = new ServiceGroupEditController(this.dialog); this.columnPicker.allColumns = [ { name: 'Metadata size', prop: 'serviceMetadata.length', - width: 80, - maxWidth: 120 + width: 120, + maxWidth: 120, + resizable: "false" }, { name: 'Owners size', prop: 'users.length', - width: 80, - maxWidth: 120 + width: 120, + maxWidth: 120, + resizable: "false" }, { name: 'Participant scheme', prop: 'participantScheme', - width: 250, - maxWidth: 300 + width: 300, + maxWidth: 300, + resizable: "false" }, { name: 'Participant identifier', @@ -72,8 +94,9 @@ export class ServiceGroupEditComponent implements OnInit { { cellTemplate: this.rowSMPUrlLinkAction, name: 'OASIS ServiceGroup URL', - width: 150, + width: 250, maxWidth: 250, + resizable: "false", sortable: false }, @@ -84,19 +107,72 @@ export class ServiceGroupEditComponent implements OnInit { }); } - metadataRowButtonAction(row: any){ - this.serviceGroupEditController.showMetadataList(row); - } - details(row: any) { this.serviceGroupEditController.showDetails(row); } - onEditMetadataRow(row:any){ - alert("edit" + row); + onAddMetadataRow(row: any) { + let rowNumber = this.searchTable.rows.indexOf(row); + + const formRef: MatDialogRef<any> = this.serviceGroupEditController.newMetadataDialog({ + data: {edit: true, serviceGroup: row, metadata: null} + }); + formRef.afterClosed().subscribe(result => { + if (result) { + const status = row.status === SearchTableEntityStatus.PERSISTED + ? SearchTableEntityStatus.UPDATED + : row.status; + + let data = this.serviceGroupEditController.newServiceMetadataRow(); + data.documentIdentifier = "aaaaaaaaa"; + data.documentIdentifierScheme = "aaaaaaaaa"; + row.serviceMetadata.push(data); + + this.searchTable.updateTableRow(rowNumber, row, status); + //this.searchTable.rows[rowNumber] = {...row, status}; + //this.searchTable.rows = [...this.searchTable.rows]; + /* + const status = row.status === SearchTableEntityStatus.PERSISTED + ? SearchTableEntityStatus.UPDATED + : row.status; + this.rows[rowNumber] = {...formRef.componentInstance.current, status}; + this.rows = [...this.rows];*/ + + } + }); + + } + + getRowClass(row) { + return { + 'table-row-new': (row.status === SearchTableEntityStatus.NEW), + 'table-row-updated': (row.status === SearchTableEntityStatus.UPDATED), + 'deleted': (row.status === SearchTableEntityStatus.REMOVED) + }; } - onDeleteMetadataRowActionClicked(row:any){ - alert("delete" + row); + + onEditMetadataRow(metaDataRow: any) { + + } + + onDeleteMetadataRowActionClicked(serviceGroupRow: any, metaDataRow: any) { + let rowNumber = this.searchTable.rows.indexOf(serviceGroupRow); + + if (metaDataRow.status === SearchTableEntityStatus.NEW) { + serviceGroupRow.splice(serviceGroupRow.indexOf(metaDataRow), 1); + } else { + metaDataRow.status = SearchTableEntityStatus.REMOVED; + metaDataRow.deleted = true; + // set row as updated + const status = serviceGroupRow.status === SearchTableEntityStatus.PERSISTED + ? SearchTableEntityStatus.UPDATED + : serviceGroupRow.status; + serviceGroupRow.status = status; + + // do not do that it updates the whole table + // this.searchTable.rows[rowNumber] = {...serviceGroupRow, status}; + // this.searchTable.rows = [...this.searchTable.rows]; + } } } diff --git a/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.html b/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.html index efb822ceb..0e54d9c7b 100644 --- a/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.html +++ b/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.html @@ -1,41 +1,58 @@ <h2 mat-dialog-title>ServiceGroup Metadata</h2> -<mat-dialog-content style="height:460px;width:950px"> - <textarea style="width: 100%; height: 95%"><ServiceMetadata xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05"> - <ServiceInformation> - <ParticipantIdentifier scheme="participantSchema">participantIdentifier</ParticipantIdentifier> - <DocumentIdentifier scheme="docSchema">docTypeIdentifier</DocumentIdentifier> - <ProcessList> - <Process> - <ProcessIdentifier scheme="cenbii-procid-ubl">urn:www.cenbii.eu:profile:bii04:ver1.0</ProcessIdentifier> - <ServiceEndpointList> - <Endpoint transportProfile="busdox-transport-start"> - <EndpointURI>https://poland.pl/theService</EndpointURI> - <RequireBusinessLevelSignature>true</RequireBusinessLevelSignature> - <ServiceActivationDate>2003-01-01T00:00:00</ServiceActivationDate> - <ServiceExpirationDate>2020-05-01T00:00:00</ServiceExpirationDate> - <Certificate>MIICUTCCAbqgAwIBAgIEWoKrxzANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQGEwJCRTEcMBoGA1UECgwTRXVyb3BlYW4gQ29tbWlzc2lvbjEYMBYGA1UECwwPRElHSVQgZURlbGl2ZXJ5MSYwJAYDVQQDDB1TYW1wbGUgU2lnbmF0dXJlcyBDZXJ0aWZpY2F0ZTAeFw0xODAyMTMwOTEzMjBaFw0zODAyMTMwOTEzMjBaMG0xCzAJBgNVBAYTAkJFMRwwGgYDVQQKDBNFdXJvcGVhbiBDb21taXNzaW9uMRgwFgYDVQQLDA9ESUdJVCBlRGVsaXZlcnkxJjAkBgNVBAMMHVNhbXBsZSBTaWduYXR1cmVzIENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIWYibbbJ6YT3uLQ0oup8kB1jJO/o16nlRfB3CbCbmpGZ2r+zCh67EMstKLltuk3peJ6QTcSaFV2oS1KLKWxwWsV4iEs5qggA5BTkzUicTsQWw39OcPPe0wniJeXdNUlOUFP2ab0ZQ9UMrJgVtlyF2uLijoKx1XR0mpTKmajh1CQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBABoFFJ+vgOo/78SPv73+MEdxkydn5EMsZ+Q4Vt1BmBaq78RcjeS7LpvPZtRxSzW+w59825BbaOCJ5K0oc6lwOXc+SS0ZI0JK2vMlp/2REFLedqHqnhpSWFKWM0Zrq80o1SzBQHC1hq95RXml6RzzPEEK0Ll0dVH7HXRpekRScGic</Certificate> - <ServiceDescription>Sample description of invoicing service</ServiceDescription> - <TechnicalContactUrl>https://example.com</TechnicalContactUrl> - </Endpoint> - </ServiceEndpointList> - <Extension> - <ExtensionID>optional sample ID</ExtensionID> - <ExtensionName>UTF-8 characters are handled, i.e. polish special ones: zażółć gęślą jaźń</ExtensionName> - <ExtensionAgencyID>text</ExtensionAgencyID> - <ExtensionAgencyName>text</ExtensionAgencyName> - <ex:dummy xmlns:ex="http://test.eu">dummy1</ex:dummy> - </Extension> - <Extension> - <ex:dummy xmlns:ex="http://test.eu">dumm2</ex:dummy> - </Extension> - </Process> - </ProcessList> - <Extension> - <ex:dummynode xmlns:ex="http://test.eu">Sample not mandatory extension</ex:dummynode> - </Extension> - </ServiceInformation> -</ServiceMetadata></textarea> +<mat-dialog-content style="height:460px;width:950px"> + <mat-tab-group fxFlex="column"> + <mat-tab label="Metadata data"> + <mat-form-field style="width:100%"> + <input matInput placeholder="Document identifier schema" name="documentIdentifierScheme" id="documentIdentifierScheme_id" + [formControl]="dialogForm.controls['documentIdentifierScheme']" maxlength="255"> + + </mat-form-field> + + <mat-form-field style="width:100%"> + <input matInput placeholder="Document identifier" name="documentIdentifier" id="documentIdentifier_id" + [formControl]="dialogForm.controls['documentIdentifier']" maxlength="255" required> + + <div *ngIf="(!editMode && dialogForm.controls['documentIdentifier'].touched || editMode) && dialogForm.controls['documentIdentifier'].hasError('required')" style="color:red; font-size: 70%"> + Document identifier must not be empty. + </div> + </mat-form-field> + + <mat-form-field style="width:100%"> + <input matInput placeholder="Process schema" name="processSchema" id="processSchema_id" + [formControl]="dialogForm.controls['processSchema']" maxlength="255" required> + + <div *ngIf="(!editMode && dialogForm.controls['processSchema'].touched || editMode) && dialogForm.controls['processSchema'].hasError('required')" style="color:red; font-size: 70%"> + Process identifier must not be empty. + </div> + </mat-form-field> + + <mat-form-field style="width:100%"> + <input matInput placeholder="Process identifier" name="processidentifier" id="processidentifier_id" + [formControl]="dialogForm.controls['processIdentifier']" maxlength="255" required> + + <div *ngIf="(!editMode && dialogForm.controls['processIdentifier'].touched || editMode) && dialogForm.controls['processIdentifier'].hasError('required')" style="color:red; font-size: 70%"> + Process identifier must not be empty. + </div> + </mat-form-field> + + <mat-form-field style="width:100%"> + <input matInput placeholder="Endpoint Url" name="endpointUrl" id="endpointUrl_id" + [formControl]="dialogForm.controls['endpointUrl']" maxlength="255" required> + + <div *ngIf="(!editMode && dialogForm.controls['endpointUrl'].touched || editMode) && dialogForm.controls['endpointUrl'].hasError('required')" style="color:red; font-size: 70%"> + Endpoint URL must not be empty. + </div> + </mat-form-field> + + + + </mat-tab> + <mat-tab label="XML"> + <h1>Some more tab content</h1> + <textarea style="width: 100%; height: 95%"></textarea> + </mat-tab> + </mat-tab-group> </mat-dialog-content> <mat-dialog-actions> diff --git a/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.ts b/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.ts index 196c6499d..544447520 100644 --- a/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.ts +++ b/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.ts @@ -1,5 +1,11 @@ -import {Component} from '@angular/core'; -import {MatDialogRef} from '@angular/material'; +import {Component, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material'; +import {FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms"; +import {DomainRo} from "../../domain/domain-ro.model"; +import {AlertService} from "../../alert/alert.service"; +import {DomainDetailsDialogComponent} from "../../domain/domain-details-dialog/domain-details-dialog.component"; +import {SearchTableEntityStatus} from "../../common/search-table/search-table-entity-status.model"; +import {ServiceMetadataEditRo} from "../service-metadata-edit-ro.model"; @Component({ selector: 'app-messagelog-dialog', @@ -8,7 +14,50 @@ import {MatDialogRef} from '@angular/material'; }) export class ServiceGroupMetadataDialogComponent { - constructor(public dialogRef: MatDialogRef<ServiceGroupMetadataDialogComponent>) { + static readonly NEW_MODE = 'New ServiceMetadata'; + static readonly EDIT_MODE = 'Domain ServiceMetadata'; + + editMode: boolean; + formTitle: string; + current: ServiceMetadataEditRo & { confirmation?: string }; + dialogForm: FormGroup; + + + constructor(private dialogRef: MatDialogRef<ServiceGroupMetadataDialogComponent>, + private alertService: AlertService, + @Inject(MAT_DIALOG_DATA) public data: any, + private fb: FormBuilder) { + + this.editMode = data.edit; + this.formTitle = this.editMode ? ServiceGroupMetadataDialogComponent.EDIT_MODE: ServiceGroupMetadataDialogComponent.NEW_MODE; + this.current = this.editMode + ? { + ...data.row, + } + : { + documentIdentifier: '', + documentIdentifierScheme: '', + smlSubdomain: '', + domainCode: '', + processSchema: '', + processIdentifier: '', + endpointUrl: '', + endpointCertificate: '', + status: SearchTableEntityStatus.NEW, + }; + + this.dialogForm = fb.group({ + + 'documentIdentifier': new FormControl({value: this.current.documentIdentifier}, [Validators.required]), + 'documentIdentifierScheme': new FormControl({value: this.current.documentIdentifierScheme }, null), + 'domainCode': new FormControl({value: this.current.domainCode}, [Validators.required]), + 'processSchema': new FormControl({value: this.current.processSchema}, [Validators.required]), + 'processIdentifier': new FormControl({value: this.current.processIdentifier}, [Validators.required]), + 'endpointUrl': new FormControl({value: this.current.endpointUrl}, [Validators.required]), + 'endpointCertificate': new FormControl({value: this.current.endpointCertificate}, null), + + }); + } } diff --git a/smp-angular/src/app/service-group-edit/service-metadata-edit-ro.model.ts b/smp-angular/src/app/service-group-edit/service-metadata-edit-ro.model.ts index c6c2b94be..ab2123729 100644 --- a/smp-angular/src/app/service-group-edit/service-metadata-edit-ro.model.ts +++ b/smp-angular/src/app/service-group-edit/service-metadata-edit-ro.model.ts @@ -1,9 +1,14 @@ import {SearchTableEntity} from "../common/search-table/search-table-entity.model"; -import {ServiceGroupDetailsDialogComponent} from "./service-group-details-dialog/service-group-details-dialog.component"; + export interface ServiceMetadataEditRo extends SearchTableEntity { documentIdentifier: string; - documentIdentifierScheme: string; + documentIdentifierScheme : string; smlSubdomain: string; domainCode: string; + processSchema: string; + processIdentifier: string; + endpointUrl: string; + endpointCertificate: string; + } diff --git a/smp-angular/src/app/service-group-search/service-group-search.component.css b/smp-angular/src/app/service-group-search/service-group-search.component.css index d1a612141..65c9eab51 100644 --- a/smp-angular/src/app/service-group-search/service-group-search.component.css +++ b/smp-angular/src/app/service-group-search/service-group-search.component.css @@ -5,8 +5,8 @@ /* --- Button ---*/ .group-btn { - margin-top:20px; - } + margin-top:20px; +} #hiddenButtonId { position: fixed; @@ -16,3 +16,19 @@ .datatable-body{ overflow-y: scroll; } + + +/deep/ .inner-table { + margin-left: 100px; + width: 80%; +} + +/deep/ .inner-table .datatable-body-cell { + padding: 1.5em 2px !important; + +} + +/deep/ .inner-table .mat-icon-button { + height: auto !important;; + line-height: unset !important; +} diff --git a/smp-angular/src/app/service-group-search/service-group-search.component.html b/smp-angular/src/app/service-group-search/service-group-search.component.html index ab20e7b28..190aeca38 100644 --- a/smp-angular/src/app/service-group-search/service-group-search.component.html +++ b/smp-angular/src/app/service-group-search/service-group-search.component.html @@ -11,8 +11,6 @@ [showActionButtons]="false" [showIndexColumn]="true" > - - <ng-template #rowExtensionAction let-row="row" let-value="value" ngx-datatable-cell-template> <button mat-button color="primary" @@ -25,8 +23,7 @@ <ng-template #rowSMPUrlLinkAction let-row="row" let-value="value" ngx-datatable-cell-template> <a target="_blank" - href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}" >Open URL</a> - + href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}">Open URL</a> </ng-template> @@ -40,25 +37,18 @@ <input matInput placeholder="Participant scheme" name="patricipantScheme" [(ngModel)]="filter.participantScheme" #messageId="ngModel" id="participantScheme"> </mat-form-field> - <mat-select placeholder="Domain " [(ngModel)]="filter.domain" name="domain" + <mat-select placeholder="Domain (sml subdomain)" [(ngModel)]="filter.domain" name="domain" id="domain_id"> <mat-option [value]="''"> </mat-option> - <mat-option *ngFor="let domain of domainlist" [value]="domain.smlSubdomain"> - {{domain.smlSubdomain}} + <mat-option *ngFor="let domain of domainlist" [value]="domain.domainCode"> + {{domain.domainCode}} ({{domain.smlSubdomain}}) </mat-option> </mat-select> </ng-template> - - <ng-template #additionalToolButtons> - <!-- button mat-raised-button color="primary" - id="extensionbutton_id"> - <mat-icon>code</mat-icon> - <span>Extension</span> - </button --> </ng-template> <ng-template #tableRowDetailContainer let-row="row"> @@ -66,24 +56,28 @@ <div *ngIf="row.serviceMetadata.length===0" style="padding-left:20px;"> No service metadata </div> - <div *ngIf="row.serviceMetadata.length !== 0" > + <div *ngIf="row.serviceMetadata.length !== 0"> <ngx-datatable class='material striped' style="width: 80%" [loadingIndicator]="loading" [rows]='row.serviceMetadata' - [columnMode]='"force"' + [columnMode]='"force"' [headerHeight]='50' [footerHeight]='50' [rowHeight]='"auto"'> - <ngx-datatable-column prop="domainCode" name="Domain" maxWidth="250" ></ngx-datatable-column> - <ngx-datatable-column prop="documentIdentifierScheme" name="Document identifier scheme" maxWidth="350" ></ngx-datatable-column> - <ngx-datatable-column prop="documentIdentifier" name="Document identifier" maxWidth="250" ></ngx-datatable-column> - <ngx-datatable-column [cellTemplate]="rowMetadataSMPUrlLinkAction" name="URL" maxWidth="250" ></ngx-datatable-column> + <ngx-datatable-column prop="domainCode" name="Domain" maxWidth="250"></ngx-datatable-column> + <ngx-datatable-column prop="documentIdentifierScheme" name="Document identifier scheme" + maxWidth="350"></ngx-datatable-column> + <ngx-datatable-column prop="documentIdentifier" name="Document identifier" + maxWidth="250"></ngx-datatable-column> + <ngx-datatable-column [cellTemplate]="rowMetadataSMPUrlLinkAction" name="URL" + maxWidth="250"></ngx-datatable-column> <ng-template #rowMetadataSMPUrlLinkAction let-rowSmd="row" ngx-datatable-cell-template> <a target="_blank" - href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}/services/{{rowSmd.documentIdentifierScheme}}::{{rowSmd.documentIdentifier}}" >Open URL</a> + href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}/services/{{rowSmd.documentIdentifierScheme}}::{{rowSmd.documentIdentifier}}">Open + URL</a> </ng-template> </ngx-datatable> diff --git a/smp-angular/src/app/service-group-search/service-group-search.component.ts b/smp-angular/src/app/service-group-search/service-group-search.component.ts index 04d95e9f0..bc8111bc7 100644 --- a/smp-angular/src/app/service-group-search/service-group-search.component.ts +++ b/smp-angular/src/app/service-group-search/service-group-search.component.ts @@ -9,10 +9,11 @@ import {Observable} from "rxjs/index"; import {SearchTableResult} from "../common/search-table/search-table-result.model"; import {DomainRo} from "../domain/domain-ro.model"; import {SmpConstants} from "../smp.constants"; +import {GlobalLookups} from "../common/global-lookups"; @Component({ moduleId: module.id, - templateUrl:'./service-group-search.component.html', + templateUrl: './service-group-search.component.html', styleUrls: ['./service-group-search.component.css'] }) export class ServiceGroupSearchComponent implements OnInit { @@ -25,20 +26,11 @@ export class ServiceGroupSearchComponent implements OnInit { serviceGroupSearchController: ServiceGroupSearchController; filter: any = {}; domainlist: Array<any>; - domainObserver: Observable< SearchTableResult> ; - contextPath: string = location.pathname.substring(0,location.pathname.length -3); // remove /ui s + contextPath: string = location.pathname.substring(0, location.pathname.length - 3); // remove /ui s baseUrl: string = SmpConstants.REST_SEARCH; - constructor(protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) { - this.domainObserver = this.http.get<SearchTableResult>(SmpConstants.REST_DOMAIN); - this.domainObserver.subscribe((domains: SearchTableResult) => { - this.domainlist = new Array(domains.serviceEntities.length) - .map((v, index) => domains.serviceEntities[index] as DomainRo); + constructor(protected lookups: GlobalLookups, protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) { - this.domainlist = domains.serviceEntities.map(serviceEntity => { - return {...serviceEntity} - }); - }); } ngOnDestroy() { @@ -46,6 +38,15 @@ export class ServiceGroupSearchComponent implements OnInit { } ngOnInit() { + this.lookups.getDomainLookupObservable().subscribe((domains: SearchTableResult) => { + this.domainlist = new Array(domains.serviceEntities.length) + .map((v, index) => domains.serviceEntities[index] as DomainRo); + + this.domainlist = domains.serviceEntities.map(serviceEntity => { + return {...serviceEntity} + }); + }); + this.serviceGroupSearchController = new ServiceGroupSearchController(this.dialog); this.columnPicker.allColumns = [ @@ -71,18 +72,11 @@ export class ServiceGroupSearchComponent implements OnInit { maxWidth: 250, sortable: false }, - /* - { - cellTemplate: this.rowExtensionAction, - name: 'Extension', - width: 80, - sortable: false - }*/ ]; this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => { - return ["Metadata size", "Participant scheme", "Participant identifier","OASIS ServiceGroup URL"].indexOf(col.name) != -1 + return ["Metadata size", "Participant scheme", "Participant identifier", "OASIS ServiceGroup URL"].indexOf(col.name) != -1 }); } diff --git a/smp-angular/src/app/smp.constants.ts b/smp-angular/src/app/smp.constants.ts index f78f13a5f..e0b6974de 100644 --- a/smp-angular/src/app/smp.constants.ts +++ b/smp-angular/src/app/smp.constants.ts @@ -4,4 +4,6 @@ export class SmpConstants { public static readonly REST_USER = 'rest/user'; public static readonly REST_SEARCH = 'rest/search'; public static readonly REST_EDIT = 'rest/servicegroup'; + public static readonly REST_METADATA = 'rest/servicemetadata'; + } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/BaseDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/BaseDao.java index f941d6f16..2a92ab63f 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/BaseDao.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/BaseDao.java @@ -14,6 +14,7 @@ package eu.europa.ec.edelivery.smp.data.dao; import eu.europa.ec.edelivery.smp.data.model.BaseEntity; +import eu.europa.ec.edelivery.smp.exceptions.SMPTestIsALiveException; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.services.ServiceGroupService; @@ -65,10 +66,12 @@ public abstract class BaseDao<E extends BaseEntity> { * @param entity */ @Transactional - public void testPersist(E entity, String message) { + public void testPersist(E entity, boolean rollbackWithException, String message) { memEManager.persist(entity); memEManager.flush(); - throw new RuntimeException(message); + if (rollbackWithException) { + throw new SMPTestIsALiveException(message); + } } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDao.java index cd58acc6f..2d4c3827b 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDao.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDao.java @@ -12,14 +12,21 @@ */ package eu.europa.ec.edelivery.smp.data.dao; +import eu.europa.ec.edelivery.smp.data.model.DBDomain; import eu.europa.ec.edelivery.smp.data.model.DBServiceGroup; +import eu.europa.ec.edelivery.smp.data.model.DBServiceGroupDomain; import eu.europa.ec.edelivery.smp.exceptions.ErrorCode; +import eu.europa.ec.edelivery.smp.services.ui.filters.ServiceGroupFilter; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Repository; import javax.persistence.NoResultException; import javax.persistence.NonUniqueResultException; import javax.persistence.TypedQuery; +import javax.persistence.criteria.*; import javax.transaction.Transactional; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; /** @@ -81,7 +88,81 @@ public class ServiceGroupDao extends BaseDao<DBServiceGroup> { memEManager.remove(memEManager.contains(dbServiceGroup) ? dbServiceGroup : memEManager.merge(dbServiceGroup)); } + public long getServiceGroupCount(ServiceGroupFilter filters, DBDomain domain) { + CriteriaQuery<Long> cqCount = createSearchCriteria(filters, true, + null, + null, domain); + return memEManager.createQuery(cqCount).getSingleResult(); + } + + public List<DBServiceGroup> getServiceGroupList(int startingAt, int maxResultCnt, + String sortField, + String sortOrder, ServiceGroupFilter filters, DBDomain domain) { + + List<DBServiceGroup> lstResult; + try { + CriteriaQuery<DBServiceGroup> cq = createSearchCriteria(filters, + false, sortField, + sortOrder, domain); + TypedQuery<DBServiceGroup> q = memEManager.createQuery(cq); + if (maxResultCnt > 0) { + q.setMaxResults(maxResultCnt); + } + if (startingAt > 0) { + q.setFirstResult(startingAt); + } + lstResult = q.getResultList(); + } catch (NoResultException ex) { + //LOG.warn("No result for '" + filterType.getName() + "' does not have a setter!", ex); + lstResult = new ArrayList<>(); + } + return lstResult; + } + + protected CriteriaQuery createSearchCriteria(ServiceGroupFilter searchParams, + boolean forCount, String sortField, String sortOrder, DBDomain domain) { + CriteriaBuilder cb = memEManager.getCriteriaBuilder(); + CriteriaQuery cq = forCount ? cb.createQuery(Long.class) : cb.createQuery(DBServiceGroup.class); + Root<DBServiceGroup> serviceGroup = cq.from(DBServiceGroup.class); + if (forCount) { + cq.select(cb.count(serviceGroup)); + } else if (sortField != null) { + if (sortOrder != null && sortOrder.equalsIgnoreCase("desc")) { + cq.orderBy(cb.asc(serviceGroup.get(sortField))); + } else { + cq.orderBy(cb.desc(serviceGroup.get(sortField))); + } + } else { + if (!StringUtils.isBlank(defaultSortMethod)) { + cq.orderBy(cb.desc(serviceGroup.get(defaultSortMethod))); + } + } + + // Join<DBServiceGroupDomain, DBDomain> serviceGroupDomainJoinDomain = null; + Join<DBServiceGroup, DBServiceGroupDomain> serviceGroupJoinServiceGroupDomain = null; + //Join<DBServiceGroupDomain, DBDomain> serviceGroupDomainJoinDomain = null; + if (domain!=null){ + serviceGroupJoinServiceGroupDomain = serviceGroup.join("serviceGroupDomains", JoinType.INNER); + serviceGroupJoinServiceGroupDomain = serviceGroupJoinServiceGroupDomain.on(cb.equal(serviceGroupJoinServiceGroupDomain.get("domain"), domain)); + } + + + // set order by + if (searchParams != null) { + List<Predicate> lstPredicate = createPredicates(searchParams, serviceGroup, cb); + + if (serviceGroupJoinServiceGroupDomain!=null) { + lstPredicate.add(serviceGroupJoinServiceGroupDomain.getOn()); + } + + if (!lstPredicate.isEmpty()) { + Predicate[] tblPredicate = lstPredicate.stream().toArray(Predicate[]::new); + cq.where(cb.and(tblPredicate)); + } + } + return cq; + } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroupDomain.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroupDomain.java index d47915011..9e5fc783b 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroupDomain.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroupDomain.java @@ -46,6 +46,10 @@ public class DBServiceGroupDomain extends BaseEntity { // list<> and set<> does not make any difference in hi // hibernate performance this case! + // this list could also be on ServiceGroup entity because it does not make any difference for + // dynamic discovery but it is here just user -service group admin to know for which + // domain he orignally registred a service - to make metadata more organized... + @OneToMany(mappedBy = "serviceGroupDomain", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceMetadataRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceMetadataRO.java index f47c78dc5..6d8605402 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceMetadataRO.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceMetadataRO.java @@ -17,6 +17,8 @@ public class ServiceMetadataRO extends BaseRO { String smlSubdomain; String domainCode; + String xmlContent; + public String getDocumentIdentifier() { return documentIdentifier; } @@ -48,4 +50,12 @@ public class ServiceMetadataRO extends BaseRO { public void setDomainCode(String domainCode) { this.domainCode = domainCode; } + + public String getXmlContent() { + return xmlContent; + } + + public void setXmlContent(String xmlContent) { + this.xmlContent = xmlContent; + } } \ No newline at end of file diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/SMPTestIsALiveException.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/SMPTestIsALiveException.java new file mode 100644 index 000000000..56e2841a6 --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/SMPTestIsALiveException.java @@ -0,0 +1,12 @@ +package eu.europa.ec.edelivery.smp.exceptions; + +/** + * Exception for testing database connection - rollback exception + */ +public class SMPTestIsALiveException extends RuntimeException { + + public SMPTestIsALiveException(String message ) { + super(message); + } + +} diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/logging/SMPMessageCode.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/logging/SMPMessageCode.java index aeb63d031..7db631120 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/logging/SMPMessageCode.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/logging/SMPMessageCode.java @@ -16,18 +16,19 @@ public enum SMPMessageCode implements MessageCode { BUS_HTTP_DELETE_END_SERVICE_GROUP ("BUS-004", "End Http DELETE ServiceGroup from user {} from host: {}. ServiceGroup id: {}."), BUS_HTTP_GET_SERVICE_GROUP ("BUS-005", "Http GET ServiceGroup from host: {}, ServiceGroup id: {}."), BUS_HTTP_GET_END_SERVICE_GROUP ("BUS-006", "End Http GET ServiceGroup from host: {}, ServiceGroup id: {}."), + BUS_HTTP_GET_END_STATIC_CONTENT ("BUS-007", "End Http GET static content from host: {}, Path: {}."), - BUS_HTTP_PUT_SERVICE_METADATA ("BUS-007", "Http PUT ServiceGroupMetadata from user {} from host: {}. ServiceGroup with domain: {}, ServiceGroup id: {} , metadata id {}."), - BUS_HTTP_PUT_END_SERVICE_METADATA ("BUS-008", "End http PUT ServiceGroupMetadata from user {}, host: {}. ServiceGroup with domain {}, ServiceGroup id: {} , metadata id {}, created {}"), - BUS_HTTP_DELETE_SERVICE_METADATA ("BUS-009", "Http DELETE ServiceGroupMetadata from user {} from host: {}. ServiceGroup id: {} , metadata id {}."), - BUS_HTTP_DELETE_END_SERVICE_METADATA ("BUS-010", "End Http DELETE ServiceGroupMetadata from user {} from host: {}. ServiceGroup id: {} , metadata id {}."), + BUS_HTTP_PUT_SERVICE_METADATA ("BUS-008", "Http PUT ServiceGroupMetadata from user {} from host: {}. ServiceGroup with domain: {}, ServiceGroup id: {} , metadata id {}."), + BUS_HTTP_PUT_END_SERVICE_METADATA ("BUS-009", "End http PUT ServiceGroupMetadata from user {}, host: {}. ServiceGroup with domain {}, ServiceGroup id: {} , metadata id {}, created {}"), + BUS_HTTP_DELETE_SERVICE_METADATA ("BUS-010", "Http DELETE ServiceGroupMetadata from user {} from host: {}. ServiceGroup id: {} , metadata id {}."), + BUS_HTTP_DELETE_END_SERVICE_METADATA ("BUS-011", "End Http DELETE ServiceGroupMetadata from user {} from host: {}. ServiceGroup id: {} , metadata id {}."), - BUS_HTTP_GET_SERVICE_METADATA ("BUS-011", "Http GET ServiceGroup from host: {}, ServiceGroup id: {}, metadata id {}."), - BUS_HTTP_GET_END_SERVICE_METADATA ("BUS-012", "End Http GET ServiceGroup from host: {}, ServiceGroup id: {}, metadata id {}."), + BUS_HTTP_GET_SERVICE_METADATA ("BUS-012", "Http GET ServiceGroup from host: {}, ServiceGroup id: {}, metadata id {}."), + BUS_HTTP_GET_END_SERVICE_METADATA ("BUS-013", "End Http GET ServiceGroup from host: {}, ServiceGroup id: {}, metadata id {}."), - BUS_SAVE_SERVICE_GROUP ("BUS-013", "Start inserting/updating ServiceGroup for domain {}, part. Id: {} part. schema {}."), - BUS_SAVE_SERVICE_GROUP_FAILED ("BUS-014", "Inserting/updating ServiceGroup for domain {}, part. Id: {} part. schema {} failed! Error: [{}]"), + BUS_SAVE_SERVICE_GROUP ("BUS-014", "Start inserting/updating ServiceGroup for domain {}, part. Id: {} part. schema {}."), + BUS_SAVE_SERVICE_GROUP_FAILED ("BUS-015", "Inserting/updating ServiceGroup for domain {}, part. Id: {} part. schema {} failed! Error: [{}]"), BUS_INVALID_XML("BUS-030", "Invalid XML for {}. Error: [{}]"), diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupService.java index de751e9a9..3670a5651 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupService.java @@ -1,8 +1,10 @@ package eu.europa.ec.edelivery.smp.services.ui; import eu.europa.ec.edelivery.smp.data.dao.BaseDao; +import eu.europa.ec.edelivery.smp.data.dao.DomainDao; import eu.europa.ec.edelivery.smp.data.dao.ServiceGroupDao; import eu.europa.ec.edelivery.smp.data.dao.UserDao; +import eu.europa.ec.edelivery.smp.data.model.DBDomain; import eu.europa.ec.edelivery.smp.data.model.DBServiceGroup; import eu.europa.ec.edelivery.smp.data.model.DBUser; import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupRO; @@ -10,6 +12,10 @@ import eu.europa.ec.edelivery.smp.data.ui.ServiceMetadataRO; import eu.europa.ec.edelivery.smp.data.ui.ServiceResult; import eu.europa.ec.edelivery.smp.data.ui.UserRO; import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus; +import eu.europa.ec.edelivery.smp.logging.SMPLogger; +import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; +import eu.europa.ec.edelivery.smp.services.ui.filters.ServiceGroupFilter; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -17,10 +23,14 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Optional; @Service public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, ServiceGroupRO> { + private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIServiceGroupService.class); + @Autowired + DomainDao domainDao; @Autowired ServiceGroupDao serviceGroupDao; @@ -45,18 +55,30 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service */ @Transactional public ServiceResult<ServiceGroupRO> getTableList(int page, int pageSize, - String sortField, - String sortOrder, Object filter) { + String sortField, + String sortOrder, ServiceGroupFilter filter, String domainCode) { + + DBDomain d = null; + if (!StringUtils.isBlank(domainCode)){ + Optional<DBDomain> od = domainDao.getDomainByCode(domainCode); + if (od.isPresent()){ + d = od.get(); + } else { + LOG.error("Domain with code {} does not exists ", domainCode); + } + + } + ServiceResult<ServiceGroupRO> sg = new ServiceResult<>(); sg.setPage(page < 0 ? 0 : page); sg.setPageSize(pageSize); - long iCnt = getDatabaseDao().getDataListCount(filter); + long iCnt = serviceGroupDao.getServiceGroupCount(filter, d); sg.setCount(iCnt); if (iCnt > 0) { int iStartIndex = pageSize < 0 ? -1 : page * pageSize; - List<DBServiceGroup> lst = getDatabaseDao().getDataList(iStartIndex, pageSize, sortField, sortOrder, filter); + List<DBServiceGroup> lst = serviceGroupDao.getServiceGroupList(iStartIndex, pageSize, sortField, sortOrder, filter, d); List<ServiceGroupRO> lstRo = new ArrayList<>(); for (DBServiceGroup dbServiceGroup : lst) { diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/filters/ServiceGroupFilter.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/ServiceGroupFilter.java similarity index 91% rename from smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/filters/ServiceGroupFilter.java rename to smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/ServiceGroupFilter.java index 8e2fa893e..08e5a2543 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/filters/ServiceGroupFilter.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/ServiceGroupFilter.java @@ -1,4 +1,4 @@ -package eu.europa.ec.edelivery.smp.ui.filters; +package eu.europa.ec.edelivery.smp.services.ui.filters; public class ServiceGroupFilter { private String participantIdentifier; diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationBase.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationBase.java index af6e2beb9..89daa0fda 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationBase.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationBase.java @@ -5,6 +5,7 @@ import eu.europa.ec.edelivery.smp.data.model.DBDomain; import eu.europa.ec.edelivery.smp.data.model.DBServiceGroup; import eu.europa.ec.edelivery.smp.data.model.DBServiceMetadata; import eu.europa.ec.edelivery.smp.data.model.DBUser; +import eu.europa.ec.edelivery.smp.testutil.TestConstants; import eu.europa.ec.edelivery.smp.testutil.TestDBUtils; import org.junit.Before; import org.junit.Rule; @@ -56,14 +57,28 @@ public abstract class ServiceGroupDaoIntegrationBase extends AbstractBaseDao{ @Transactional public DBServiceGroup createAndSaveNewServiceGroup(){ + return createAndSaveNewServiceGroup(TEST_DOMAIN_CODE_1, TestConstants.TEST_SG_ID_1, TestConstants.TEST_SG_SCHEMA_1); + } - DBDomain d = domainDao.getDomainByCode(TEST_DOMAIN_CODE_1).get(); - DBServiceGroup sg = TestDBUtils.createDBServiceGroup(); + private DBServiceGroup createAndSaveNewServiceGroup(String domain, String participantId, String participantSchema){ + DBDomain d = domainDao.getDomainByCode(domain).get(); + DBServiceGroup sg = TestDBUtils.createDBServiceGroup(participantId, participantSchema); sg.addDomain(d); testInstance.persistFlushDetach(sg); return sg; } + + @Transactional + public void createAndSaveNewServiceGroups(int iCount, String domain, String participant){ + + int i =0; + while (i++ < iCount){ + createAndSaveNewServiceGroup(domain, participant+":"+i, TestConstants.TEST_SG_SCHEMA_1); + + } + } + @Transactional public DBServiceGroup createAndSaveNewServiceGroupWithMetadata(){ diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationTest.java index a59b51b75..1451cc3ac 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationTest.java @@ -2,6 +2,8 @@ package eu.europa.ec.edelivery.smp.data.dao; import eu.europa.ec.edelivery.smp.data.model.DBDomain; import eu.europa.ec.edelivery.smp.data.model.DBServiceGroup; +import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupRO; +import eu.europa.ec.edelivery.smp.data.ui.ServiceResult; import eu.europa.ec.edelivery.smp.testutil.TestConstants; import eu.europa.ec.edelivery.smp.testutil.TestDBUtils; import org.junit.Test; @@ -10,6 +12,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.transaction.Transactional; import java.util.Arrays; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -160,4 +163,50 @@ public class ServiceGroupDaoIntegrationTest extends ServiceGroupDaoIntegrationBa assertFalse(optResDel.isPresent()); } + @Test + public void testGetServiceGroupListNotEmpty(){ + // given + // add additional domain + DBDomain d2 = TestDBUtils.createDBDomain(TEST_DOMAIN_CODE_2); + domainDao.persistFlushDetach(d2); + createAndSaveNewServiceGroups(10, TEST_DOMAIN_CODE_1, TestConstants.TEST_SG_ID_1); + createAndSaveNewServiceGroups(5, TEST_DOMAIN_CODE_2, TestConstants.TEST_SG_ID_2); + //when + List<DBServiceGroup> res = testInstance.getServiceGroupList(-1,-1,null, null,null, null); + // then + assertNotNull(res); + assertEquals(15, res.size()); + + } + + @Test + public void testGetServiceGroupListByDomain(){ + // given + // add additional domain + DBDomain d2 = TestDBUtils.createDBDomain(TEST_DOMAIN_CODE_2); + domainDao.persistFlushDetach(d2); + createAndSaveNewServiceGroups(10, TEST_DOMAIN_CODE_1, TestConstants.TEST_SG_ID_1); + createAndSaveNewServiceGroups(5, TEST_DOMAIN_CODE_2, TestConstants.TEST_SG_ID_2); + + //when + List<DBServiceGroup> res = testInstance.getServiceGroupList(-1,-1,null, null,null, d2); + // then + assertNotNull(res); + assertEquals(5, res.size()); + + } + + @Test + public void testGetTableListEmpty(){ + + // given + + //when + List<DBServiceGroup> res = testInstance.getServiceGroupList(-1,-1,null, null,null, null); + // then + assertNotNull(res); + assertTrue(res.isEmpty()); + + } + } \ No newline at end of file diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java index da24d8c4e..91141c049 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java @@ -34,15 +34,14 @@ import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE; "eu.europa.ec.edelivery.smp.ui"}) @Import({GlobalMethodSecurityConfig.class, ErrorMappingControllerAdvice.class}) public class SmpWebAppConfig implements WebMvcConfigurer { - +/* @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("/index.html"); registry.addViewController("/ui/").setViewName("/ui/index.html"); - //Home page used by SMP 2.x and 3.x - needed for backward compatibility in some EC's environments registry.addViewController("/web/index.html").setViewName("/index.html"); - } + }*/ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/RootController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/RootController.java new file mode 100644 index 000000000..0384287dc --- /dev/null +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/RootController.java @@ -0,0 +1,65 @@ +/* + * Copyright 2017 European Commission | CEF eDelivery + * + * 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 attached in file: LICENCE-EUPL-v1.2.pdf + * + * 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. + */ + +package eu.europa.ec.edelivery.smp.controllers; + +import eu.europa.ec.edelivery.smp.logging.SMPLogger; +import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; +import eu.europa.ec.edelivery.smp.logging.SMPMessageCode; +import org.apache.commons.lang.StringUtils; +import org.apache.cxf.helpers.IOUtils; +import org.springframework.core.annotation.Order; +import org.springframework.http.MediaType; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE; +import static org.springframework.core.Ordered.LOWEST_PRECEDENCE; + + +@RestController +@RequestMapping("/") +public class RootController { + + private static final SMPLogger LOG = SMPLoggerFactory.getLogger(RootController.class); + + + @GetMapping( produces = MediaType.TEXT_HTML_VALUE, value={"", "/", "web/index.html","index.html"}) + @Order(HIGHEST_PRECEDENCE) + public byte[] getServiceGroup(HttpServletRequest httpReq) throws IOException { + String host = httpReq.getRemoteHost(); + LOG.businessInfo(SMPMessageCode.BUS_HTTP_GET_END_STATIC_CONTENT,host,httpReq.getPathInfo()); + return IOUtils.readBytesFromStream(RootController.class.getResourceAsStream("/index.html")); + } + + /** + * redirect angular pages to index.html + * solve the 404 error on refresh + * @param model + * @return +*/ + //@GetMapping(value={"/ui","/ui/edit","/ui/search","/ui/search","/ui/domain","/ui/user"}) + @GetMapping(value={"/ui"}) + public ModelAndView redirectWithUsingRedirectPrefix(ModelMap model) { + return new ModelAndView("redirect:/ui/index.html", model); + } + + public String getRemoteHost(HttpServletRequest httpReq){ + String host = httpReq.getHeader("X-Forwarded-For"); + return StringUtils.isBlank(host)?httpReq.getRemoteHost():host; + } +} diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java index 96850dbca..0c17693b9 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java @@ -7,12 +7,14 @@ import eu.europa.ec.edelivery.smp.data.dao.DomainDao; import eu.europa.ec.edelivery.smp.data.dao.ServiceGroupDao; import eu.europa.ec.edelivery.smp.data.model.DBDomain; import eu.europa.ec.edelivery.smp.data.model.DBServiceGroup; +import eu.europa.ec.edelivery.smp.exceptions.SMPTestIsALiveException; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.services.ServiceGroupService; import eu.europa.ec.edelivery.smp.validation.ServiceGroupValidator; import eu.europa.ec.smp.api.exceptions.XmlInvalidAgainstSchemaException; import eu.europa.ec.smp.api.validators.BdxSmpOasisValidator; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.cxf.helpers.IOUtils; import org.oasis_open.docs.bdxr.ns.smp._2016._05.ServiceGroup; import org.springframework.beans.factory.annotation.Autowired; @@ -86,8 +88,10 @@ public class MonitorResource { boolean suc = false; try { suc= testDatabase(); - }catch (Exception ex){ + }catch (SMPTestIsALiveException ex){ suc = Objects.equals(TEST_DB_SUCCESSFUL_ROLLBACK, ex.getMessage()); + } catch(Throwable th) { + LOG.error("Error occured while testing database connection: Msg:" + ExceptionUtils.getRootCauseMessage(th), th); } return suc?ResponseEntity.ok().build():ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); @@ -107,7 +111,7 @@ public class MonitorResource { newSg.addDomain(lstDomain.get(0)); // add initial domain newSg.setSmlRegistered(false); // persist (make sure this is not in transaction) - serviceGroupDao.testPersist(newSg, TEST_DB_SUCCESSFUL_ROLLBACK); + serviceGroupDao.testPersist(newSg,true, TEST_DB_SUCCESSFUL_ROLLBACK); return false; } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/SearchResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/SearchResource.java index db693136d..05af6c1b4 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/SearchResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/SearchResource.java @@ -6,7 +6,7 @@ import eu.europa.ec.edelivery.smp.data.ui.ServiceResult; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.services.ui.UIServiceGroupService; -import eu.europa.ec.edelivery.smp.ui.filters.ServiceGroupFilter; +import eu.europa.ec.edelivery.smp.services.ui.filters.ServiceGroupFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -50,6 +50,7 @@ public class SearchResource { ServiceGroupFilter sgf = new ServiceGroupFilter(); sgf.setParticipantIdentifierLike(participantIdentifier); sgf.setParticipantSchemeLike(participantScheme); - return uiServiceGroupService.getTableList(page,pageSize, orderBy, orderType, sgf ); + + return uiServiceGroupService.getTableList(page,pageSize, orderBy, orderType, sgf, domain); } } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ServiceGroupResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ServiceGroupResource.java index 543657db9..0c7f620e0 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ServiceGroupResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ServiceGroupResource.java @@ -7,12 +7,13 @@ import eu.europa.ec.edelivery.smp.data.ui.ServiceResult; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.services.ui.UIServiceGroupService; +import eu.europa.ec.edelivery.smp.services.ui.filters.ServiceGroupFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; -import javax.annotation.PostConstruct; +import javax.annotation .PostConstruct; import java.util.Arrays; /** @@ -24,7 +25,7 @@ import java.util.Arrays; @RequestMapping(value = "/ui/rest/servicegroup") public class ServiceGroupResource { - private static final SMPLogger LOG = SMPLoggerFactory.getLogger(DomainResource.class); + private static final SMPLogger LOG = SMPLoggerFactory.getLogger(ServiceGroupResource.class); @Autowired private UIServiceGroupService uiServiceGroupService; @@ -42,11 +43,16 @@ public class ServiceGroupResource { @RequestParam(value = "pageSize", defaultValue = "10") int pageSize, @RequestParam(value = "orderBy", required = false) String orderBy, @RequestParam(value = "orderType", defaultValue = "asc", required = false) String orderType, - @RequestParam(value = "participantId", required = false) String participantId, - @RequestParam(value = "participantSchema", required = false) String participantSchema, + @RequestParam(value = "participantId", required = false) String participantIdentifier, + @RequestParam(value = "participantSchema", required = false) String participantScheme, @RequestParam(value = "domain", required = false) String domain ) { - return uiServiceGroupService.getTableList(page, pageSize, orderBy, orderType, null); + LOG.info("Search for page: {}, page size: {}, part. id: {}, part sch: {}, domain {}",page, pageSize, participantIdentifier, participantScheme, domain ); + ServiceGroupFilter sgf = new ServiceGroupFilter(); + sgf.setParticipantIdentifierLike(participantIdentifier); + sgf.setParticipantSchemeLike(participantScheme); + + return uiServiceGroupService.getTableList(page,pageSize, orderBy, orderType, sgf, domain); } @ResponseBody diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/exception/UIException.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/exception/UIException.java new file mode 100644 index 000000000..0cb934e4b --- /dev/null +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/exception/UIException.java @@ -0,0 +1,28 @@ +package eu.europa.ec.edelivery.smp.ui.exception; + +import org.springframework.http.HttpStatus; + +import java.util.Arrays; +import java.util.List; + +public class UIException { + + + private HttpStatus status; + private String message; + private List<String> errors; + + public UIException(HttpStatus status, String message, List<String> errors) { + super(); + this.status = status; + this.message = message; + this.errors = errors; + } + + public UIException(HttpStatus status, String message, String error) { + super(); + this.status = status; + this.message = message; + errors = Arrays.asList(error); + } + } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/validation/ServiceMetadataValidator.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/validation/ServiceMetadataValidator.java index 219fe5922..202a26d9c 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/validation/ServiceMetadataValidator.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/validation/ServiceMetadataValidator.java @@ -74,6 +74,34 @@ public class ServiceMetadataValidator { validateServiceInformation(serviceInformation); } + public ServiceInformationType validate(String serviceGroupIdStr, + byte[] serviceMetadataBody + ) throws XmlInvalidAgainstSchemaException { + + BdxSmpOasisValidator.validateXSD(serviceMetadataBody); + + ParticipantIdentifierType serviceGroupId = asParticipantId(serviceGroupIdStr); + ServiceMetadata serviceMetadata = ServiceMetadataConverter.unmarshal(serviceMetadataBody); + ServiceInformationType serviceInformation = serviceMetadata.getServiceInformation(); + + if (serviceInformation == null) { + String errorMessage = "Missing service information"; + throw new BadRequestException(WRONG_FIELD, errorMessage); + } + + + + if (!serviceGroupId.equals(serviceInformation.getParticipantIdentifier())) { + String errorMessage = String.format("Save service metadata was called with bad Participant ID parameters. Message body param: %s URL param: %s", + asString(serviceInformation.getParticipantIdentifier()), + asString(serviceGroupId)); + log.info(errorMessage); + throw new BadRequestException(WRONG_FIELD, errorMessage); + } + validateServiceInformation(serviceInformation); + return serviceInformation; + } + private void validateServiceInformation(ServiceInformationType serviceInformation) { ProcessListType processList = serviceInformation.getProcessList(); if (processList == null) { diff --git a/smp-webapp/src/main/resources/index.html b/smp-webapp/src/main/resources/index.html new file mode 100644 index 000000000..3f5273e65 --- /dev/null +++ b/smp-webapp/src/main/resources/index.html @@ -0,0 +1,32 @@ +<!-- + ~ Copyright 2017 European Commission | CEF eDelivery + ~ + ~ 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 attached in file: LICENCE-EUPL-v1.2.pdf + ~ + ~ 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. + --> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <title>SMP</title> + <link rel="shortcut icon" href="favicon-16x16.png" /> + <style type="text/css"> + body { font-family: Arial, Helvetica, sans-serif; } + a, a:link, a:visited, a:hover, a:active { color: blue; } + </style> + </head> + <body> + <h1>SMP (Service Metadata Publishing)</h1> + <h2>Version: ${project.version}</h2> + <h6>Build timestamp: ${buildtimestamp}</h6> + <h6>Specification: <a href="http://docs.oasis-open.org/bdxr/bdx-smp/v1.0/bdx-smp-v1.0.html" target="_blank">http://docs.oasis-open.org/bdxr/bdx-smp/v1.0/bdx-smp-v1.0.html</a></h6> + <h6>UI: <a href="ui/index.html" target="_blank">eDelivery SMP</a></h6> + </body> +</html> diff --git a/smp-webapp/src/main/webapp/index.html b/smp-webapp/src/main/webapp/index.html new file mode 100644 index 000000000..c870461f3 --- /dev/null +++ b/smp-webapp/src/main/webapp/index.html @@ -0,0 +1,31 @@ +<!-- + ~ Copyright 2017 European Commission | CEF eDelivery + ~ + ~ 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 attached in file: LICENCE-EUPL-v1.2.pdf + ~ + ~ 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. + --> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <title>SMP</title> + <link rel="shortcut icon" href="favicon-16x16.png" /> + <style type="text/css"> + body { font-family: Arial, Helvetica, sans-serif; } + a, a:link, a:visited, a:hover, a:active { color: blue; } + </style> + </head> + <body> + <h1>SMP (Service Metadata Publishing)</h1> + <h2>Version: ${project.version}</h2> + <h6>Build timestamp: ${buildtimestamp}</h6> + <h6>Specification: <a href="http://docs.oasis-open.org/bdxr/bdx-smp/v1.0/bdx-smp-v1.0.html" target="_blank">http://docs.oasis-open.org/bdxr/bdx-smp/v1.0/bdx-smp-v1.0.html</a></h6> + </body> +</html> diff --git a/smp-webapp/src/main/webapp/static_resources/index.html b/smp-webapp/src/main/webapp/static_resources/index.html index c870461f3..3f5273e65 100644 --- a/smp-webapp/src/main/webapp/static_resources/index.html +++ b/smp-webapp/src/main/webapp/static_resources/index.html @@ -27,5 +27,6 @@ <h2>Version: ${project.version}</h2> <h6>Build timestamp: ${buildtimestamp}</h6> <h6>Specification: <a href="http://docs.oasis-open.org/bdxr/bdx-smp/v1.0/bdx-smp-v1.0.html" target="_blank">http://docs.oasis-open.org/bdxr/bdx-smp/v1.0/bdx-smp-v1.0.html</a></h6> + <h6>UI: <a href="ui/index.html" target="_blank">eDelivery SMP</a></h6> </body> </html> diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/monitor/MonitorResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/monitor/MonitorResourceTest.java index b680d69b8..e85f8aeee 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/monitor/MonitorResourceTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/monitor/MonitorResourceTest.java @@ -4,6 +4,7 @@ import eu.europa.ec.edelivery.smp.config.PropertiesTestConfig; import eu.europa.ec.edelivery.smp.config.SmpAppConfig; import eu.europa.ec.edelivery.smp.config.SmpWebAppConfig; import eu.europa.ec.edelivery.smp.config.SpringSecurityConfig; +import eu.europa.ec.edelivery.smp.exceptions.SMPTestIsALiveException; import eu.europa.ec.edelivery.smp.monitor.MonitorResource; import org.junit.Before; import org.junit.Rule; @@ -95,7 +96,7 @@ public class MonitorResourceTest { public void testDatabase() { // given expectedEx.expectMessage("TEST_DB_SUCCESSFUL_ROLLBACK MESSAGE"); - expectedEx.expect(RuntimeException.class); + expectedEx.expect(SMPTestIsALiveException.class); // when boolean bval = testInstance.testDatabase(); //then -- GitLab