diff --git a/smp-angular/src/_smp-all-themes.scss b/smp-angular/src/_smp-all-themes.scss index 16ce626ff0ae6aa989a9cbfc520f162b4639ff0b..bc95c360d997d60ed03881787d00d352d145bf26 100644 --- a/smp-angular/src/_smp-all-themes.scss +++ b/smp-angular/src/_smp-all-themes.scss @@ -20,7 +20,7 @@ } .datatable-row-odd { - background-color: smp.get-theme-color($theme, primary, 0.2) !important; + background-color: smp.get-theme-color($theme, primary,50, 0.2) !important; } .datatable-row-selected { diff --git a/smp-angular/src/app/app.module.ts b/smp-angular/src/app/app.module.ts index d9066bee7f86bdd95104248e14a86ff1508b12e6..a0ac74f8bab50e95009abafe65d7e94a10dfd6d0 100644 --- a/smp-angular/src/app/app.module.ts +++ b/smp-angular/src/app/app.module.ts @@ -99,7 +99,6 @@ import {ServiceGroupExtensionWizardDialogComponent} from './service-group-edit/s import {ServiceGroupMetadataDialogComponent} from './service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component'; import {ServiceGroupSearchComponent} from './service-group-search/service-group-search.component'; import {ServiceMetadataWizardDialogComponent} from './service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component'; -import {SharedModule} from './common/module/shared.module'; import {SidenavComponent} from './window/sidenav/sidenav.component'; import {SmlIntegrationService} from "./system-settings/domain/sml-integration.service"; import {SmpInfoService} from './app-info/smp-info.service'; @@ -232,7 +231,6 @@ import { NgxMatDatetimePickerModule, NgxMatMomentModule, ReactiveFormsModule, - SharedModule, routing, ], providers: [ diff --git a/smp-angular/src/app/common/directive/attribute/click-stop-propagation.directive.ts b/smp-angular/src/app/common/directive/attribute/click-stop-propagation.directive.ts deleted file mode 100644 index 2b55e17de5cf7b489ddaa6400b671d6ecbb18f8d..0000000000000000000000000000000000000000 --- a/smp-angular/src/app/common/directive/attribute/click-stop-propagation.directive.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {Directive, HostListener} from '@angular/core'; - -@Directive({ - selector: "[click-stop-propagation]" -}) -export class ClickStopPropagationDirective { - @HostListener("click", ["$event"]) - public onClick(event: any): void { - event.preventDefault(); - } -} diff --git a/smp-angular/src/app/common/enums/visibility.enum.ts b/smp-angular/src/app/common/enums/visibility.enum.ts new file mode 100644 index 0000000000000000000000000000000000000000..446815b94ba2eeef4bb7a3f28112d0b9ef872f58 --- /dev/null +++ b/smp-angular/src/app/common/enums/visibility.enum.ts @@ -0,0 +1,14 @@ +export enum VisibilityEnum { + /** + * Resource, group of domain is marked as PUBLIC. + */ + Public= 'PUBLIC', + /** + * Access to the resource is within the domain/group. Users must be authenticated and must be members of the domain/group/resource in order to read it. + */ + Internal= 'INTERNAL', + /** + * Access to the resource is possible only to the resource members + */ + Private= 'PRIVATE' +} diff --git a/smp-angular/src/app/common/module/shared.module.ts b/smp-angular/src/app/common/module/shared.module.ts deleted file mode 100644 index 412ffe7e359559f3d9763daad7af379e24bb17f3..0000000000000000000000000000000000000000 --- a/smp-angular/src/app/common/module/shared.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {NgModule} from '@angular/core'; - -import {ClickStopPropagationDirective} from 'app/common/directive/attribute/click-stop-propagation.directive'; - -@NgModule({ - declarations: [ - ClickStopPropagationDirective - ], - exports: [ - ClickStopPropagationDirective - ] -}) -export class SharedModule { -} diff --git a/smp-angular/src/app/guards/auth.guard.ts b/smp-angular/src/app/guards/auth.guard.ts index 278a3f716de036445cebc4060e99958469a2b40d..4b8f9fc1e65411be3d114d5e2eaba1c626659450 100644 --- a/smp-angular/src/app/guards/auth.guard.ts +++ b/smp-angular/src/app/guards/auth.guard.ts @@ -10,16 +10,11 @@ export const authGuard = () => { const alertService = inject(AlertMessageService); const router = inject(Router); - console.log("guard - check for authentication: " + router.url) - // test if logged in securityService.isAuthenticated(true).subscribe((isAuthenticated: boolean) => { - console.log("Refresh application configuration is authenticated " + isAuthenticated ) if (isAuthenticated) { - console.log("guard - it is authenticated") return true; } else { - console.log("guard - it is not authenticated") alertService.error('You have been logged out because of inactivity or missing access permissions.', true); // Redirect to the login page navigationService.reset(); diff --git a/smp-angular/src/app/login/login.component.css b/smp-angular/src/app/login/login.component.css index 6d50e21e71d5532e77a9a3c1910d21d5b63215f6..bb1da45b6e5c3d2d6c64b0911b4149e3e5346221 100644 --- a/smp-angular/src/app/login/login.component.css +++ b/smp-angular/src/app/login/login.component.css @@ -2,3 +2,5 @@ a:link { text-decoration: none; } a:visited { text-decoration: none; } a:hover { text-decoration: none; } a:active { text-decoration: none; } + + diff --git a/smp-angular/src/app/login/login.component.html b/smp-angular/src/app/login/login.component.html index 338b1044e52444f57e121c21936badcfbcf5e40d..5e74eaad32869274e23716884eeed3b0ea90e8f4 100644 --- a/smp-angular/src/app/login/login.component.html +++ b/smp-angular/src/app/login/login.component.html @@ -3,44 +3,37 @@ <mat-card *ngIf="isUserAuthSSOEnabled() == true" fxFlex="400px" [style]="'width:400px;height:300px;margin:10px'"> <mat-card-title>SSO Login: {{lookups.cachedApplicationInfo.ssoAuthenticationLabel}}</mat-card-title> <mat-card-content style="align-items: center;justify-content: center;display: flex;height: 200px;"> - <a mat-raised-button color="primary" href="{{lookups.cachedApplicationInfo.ssoAuthenticationURI}}" [style]="'width=150px'"> + <a mat-raised-button color="primary" href="{{lookups.cachedApplicationInfo.ssoAuthenticationURI}}" + [style]="'width=150px'"> <mat-icon>input</mat-icon> <span> SSO Login</span> </a> </mat-card-content> </mat-card> - <mat-card *ngIf="isUserAuthPasswdEnabled() == true" fxFlex="400px" [style]="'width:400px;height:300px;margin:10px'"> + <mat-card *ngIf="isUserAuthPasswdEnabled() == true" fxFlex="400px" [style]="'width:400px;height:300px;margin:10px;'"> <mat-card-title>SMP Login</mat-card-title> - <mat-card-content style="align-items: center;justify-content: center;display: flex;height: 200px;"> + <mat-card-content style="align-items: center;justify-content: center;display: flex;flex-direction:column; height: 200px;"> <form name="loginForm" #loginForm="ngForm" (ngSubmit)="login()"> - <table cellspacing="0"> - <tr> - <td> - <mat-form-field> + <mat-form-field style="width: 100%"> + <mat-label>Username</mat-label> <input matInput placeholder="Username" name="username" [(ngModel)]="model.username" #username="ngModel" - required id="username_id"> + id="username_id" + auto-focus-directive + required> </mat-form-field> - </td> - </tr> - <tr> - <td> - <mat-form-field> + <mat-form-field style="width: 100%"> + <mat-label>Password</mat-label> <input type="password" matInput placeholder="Password" name="password" [(ngModel)]="model.password" #password="ngModel" required id="password_id"> </mat-form-field> - </td> - </tr> - <tr> - <td> + <button mat-raised-button color="primary" [disabled]="!loginForm.form.valid" id="loginbutton_id" [style]="'width:150px'"> <mat-icon>input</mat-icon> <span> Login</span> </button> - </td> - </tr> - </table> + </form> </mat-card-content> </mat-card> 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 435755996ea6eeb449bcfe679a7673dfc8b084e4..9812820ac85fbe8d987b51bee7ec7a200550721e 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 @@ -10,7 +10,7 @@ import {ServiceGroupEditRo} from "../service-group-edit-ro.model"; import {GlobalLookups} from "../../common/global-lookups"; import {ServiceGroupExtensionWizardDialogComponent} from "../service-group-extension-wizard-dialog/service-group-extension-wizard-dialog.component"; import {ServiceGroupValidationRo} from "./service-group-validation-edit-ro.model"; -import {DomainRo} from "../../system-settings/domain/domain-ro.model"; +import {DomainRo} from "../../system-settings/admin-domain/domain-ro.model"; import {ServiceGroupDomainEditRo} from "../service-group-domain-edit-ro.model"; import {ConfirmationDialogComponent} from "../../common/dialogs/confirmation-dialog/confirmation-dialog.component"; import {SecurityService} from "../../security/security.service"; diff --git a/smp-angular/src/app/smp.constants.ts b/smp-angular/src/app/smp.constants.ts index cfb427ed2d52151c875e9514cd0950d9d637b597..fc490b5fe8fbb316e589a7b195bc58397972efdb 100644 --- a/smp-angular/src/app/smp.constants.ts +++ b/smp-angular/src/app/smp.constants.ts @@ -6,7 +6,15 @@ export class SmpConstants { public static readonly DATE_TIME_FORMAT = 'dd/MM/yyyy HH:mm:ss z'; public static readonly DATE_FORMAT = 'dd/MM/yyyy'; + + public static readonly PATH_ACTION_DELETE = 'delete'; + public static readonly PATH_ACTION_UPDATE = 'update'; + public static readonly PATH_ACTION_CREATE = 'create'; + public static readonly PATH_ACTION_UPDATE_RESOURCE_TYPES = 'update-resource-types'; + + public static readonly PATH_ACTION_UPDATE_SML_INTEGRATION = 'update-sml-integration-data'; public static readonly PATH_PARAM_ENC_USER_ID = '{user-id}'; + public static readonly PATH_PARAM_ENC_DOMAIN_ID = '{domainr-id}'; public static readonly PATH_PARAM_CERT_ALIAS = '{cert-alias}'; public static readonly PATH_PARAM_ENC_CREDENTIAL_ID = '{credential-id}'; public static readonly PATH_PARAM_ENC_MANAGED_USER_ID = '{managed-user-id}'; @@ -57,6 +65,23 @@ export class SmpConstants { public static readonly REST_INTERNAL_DOMAIN_MANAGE = SmpConstants.REST_INTERNAL + 'domain' + '/' + SmpConstants.PATH_PARAM_ENC_USER_ID; + public static readonly REST_INTERNAL_DOMAIN_MANAGE_DELETE = SmpConstants.REST_INTERNAL + 'domain' + + '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' +SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + '/' + SmpConstants.PATH_ACTION_DELETE; + + public static readonly REST_INTERNAL_DOMAIN_MANAGE_UPDATE = SmpConstants.REST_INTERNAL + 'domain' + + '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' +SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + '/' + SmpConstants.PATH_ACTION_UPDATE; + + public static readonly REST_INTERNAL_DOMAIN_MANAGE_CREATE = SmpConstants.REST_INTERNAL + 'domain' + + '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' + SmpConstants.PATH_ACTION_CREATE; + + + public static readonly REST_INTERNAL_DOMAIN_MANAGE_UPDATE_SML_INTEGRATION = SmpConstants.REST_INTERNAL + 'domain' + + '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' +SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + '/' + SmpConstants.PATH_ACTION_UPDATE_SML_INTEGRATION; + + + public static readonly REST_INTERNAL_DOMAIN_MANAGE_UPDATE_RESOURCE_TYPES = SmpConstants.REST_INTERNAL + 'domain' + + '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' +SmpConstants.PATH_PARAM_ENC_DOMAIN_ID + '/' + SmpConstants.PATH_ACTION_UPDATE_RESOURCE_TYPES; + public static readonly REST_INTERNAL_EXTENSION_MANAGE = SmpConstants.REST_INTERNAL + 'extension'; public static readonly REST_INTERNAL_PROPERTY_MANAGE = SmpConstants.REST_INTERNAL + 'property'; public static readonly REST_INTERNAL_PROPERTY_VALIDATE = SmpConstants.REST_INTERNAL_PROPERTY_MANAGE + '/validate'; @@ -74,12 +99,12 @@ export class SmpConstants { public static readonly REST_INTERNAL_KEYSTORE_UPLOAD = SmpConstants.REST_INTERNAL_KEYSTORE_MANAGE + '/' + 'upload' + '/' + SmpConstants.PATH_PARAM_KEYSTORE_TYPE + '/' + SmpConstants.PATH_PARAM_KEYSTORE_PWD; - public static readonly REST_INTERNAL_KEYSTORE_DELETE_ENTRY = SmpConstants.REST_INTERNAL_KEYSTORE_MANAGE + '/' + 'delete' + public static readonly REST_INTERNAL_KEYSTORE_DELETE_ENTRY = SmpConstants.REST_INTERNAL_KEYSTORE_MANAGE + '/' + SmpConstants.PATH_ACTION_DELETE + '/' + SmpConstants.PATH_PARAM_CERT_ALIAS; public static readonly REST_INTERNAL_TRUSTSTORE_MANAGE = SmpConstants.REST_INTERNAL + 'truststore' + '/' + SmpConstants.PATH_PARAM_ENC_USER_ID; public static readonly REST_INTERNAL_TRUSTSTORE_UPLOAD_CERT = SmpConstants.REST_INTERNAL_TRUSTSTORE_MANAGE + '/' + 'upload-certificate'; - public static readonly REST_INTERNAL_TRUSTSTORE_DELETE_CERT = SmpConstants.REST_INTERNAL_TRUSTSTORE_MANAGE + '/' + 'delete' + '/' + SmpConstants.PATH_PARAM_CERT_ALIAS; + public static readonly REST_INTERNAL_TRUSTSTORE_DELETE_CERT = SmpConstants.REST_INTERNAL_TRUSTSTORE_MANAGE + '/' + SmpConstants.PATH_ACTION_DELETE + '/' + SmpConstants.PATH_PARAM_CERT_ALIAS; public static readonly REST_PUBLIC_USER_NAVIGATION_TREE = SmpConstants.REST_PUBLIC_USER + '/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' + 'navigation-tree'; diff --git a/smp-angular/src/app/system-settings/admin-domain/admin-domain.component.html b/smp-angular/src/app/system-settings/admin-domain/admin-domain.component.html index d996f6d2c42d4b05a4f5b66114f474852bbc64bd..6659889fa59b21f7e086e1cb9cf6f40010d537f9 100644 --- a/smp-angular/src/app/system-settings/admin-domain/admin-domain.component.html +++ b/smp-angular/src/app/system-settings/admin-domain/admin-domain.component.html @@ -5,25 +5,37 @@ [labelColumnContent]="searchDomainPanel"> - <mat-tab-group style="height: 100%"> + <mat-tab-group #domainTabs style="height: 100%" > <mat-tab label="Domain data"> - <domain-panel - [domain]="selected" - [keystoreCertificates]="keystoreCertificates" + <domain-panel #domainPanelComponent + [domain]="selected" + [keystoreCertificates]="keystoreCertificates" + [domiSMPResourceDefinitions]="domiSMPResourceDefinitions" + (onSaveBasicDataEvent)="onSaveEvent($event)" + (onDiscardNew)="onDiscardNew()" ></domain-panel> </mat-tab> - <mat-tab label="Resources"> - <domain-resource-type-panel [domain]="selected"></domain-resource-type-panel> + <mat-tab label="Resource Types"> + <domain-resource-type-panel #domainResourceTypePanelComponent + [domain]="selected" + [domiSMPResourceDefinitions]="domiSMPResourceDefinitions" + (onSaveResourceTypesEvent)="onSaveResourceTypesEvent($event)" + ></domain-resource-type-panel> </mat-tab> <mat-tab label="SML integration"> - <domain-sml-integration-panel [domain]="selected"></domain-sml-integration-panel> + <domain-sml-integration-panel #domainSmlIntegrationPanelComponent + [keystoreCertificates]="keystoreCertificates" + [domain]="selected" + (onSaveSmlIntegrationDataEvent)="onSaveSmlIntegrationDataEvent($event)" + ></domain-sml-integration-panel> + </mat-tab> + <mat-tab label="Members"> + Content 3 </mat-tab> - <mat-tab label="Members"> Content 3</mat-tab> </mat-tab-group> </data-panel> </div> - <ng-template #searchDomainPanel> <mat-form-field id="domain-filter"> <mat-label>Filter Domain by domain code</mat-label> @@ -32,12 +44,15 @@ <mat-toolbar> <mat-toolbar-row class="mat-elevation-z5"> - <button mat-raised-button mat-flat-button color="primary" - (click)="onCreateDomainClicked()">Create domain + <button mat-raised-button + mat-flat-button color="primary" + onDiscardNew + (click)="onCreateDomainClicked()" + >Create domain </button> <button mat-raised-button - [disabled]="!selected" + [disabled]="canNotDelete" color="primary" (click)="onDeleteSelectedDomainClicked()"> <mat-icon>delete</mat-icon> @@ -59,8 +74,8 @@ <tr class="mat-row" *matNoDataRow> - <td *ngIf="inputDomainFilter.value;else noDataFound" class="mat-cell" colspan="2">No data matching the filter "{{inputDomainFilter.value}} - " + <td *ngIf="inputDomainFilter.value;else noDataFound" class="mat-cell" colspan="2">No data matching the filter + "{{inputDomainFilter.value}}" </td> <ng-template #noDataFound> <td class="mat-cell" colspan="2">No data</td> @@ -74,4 +89,3 @@ [pageSize]="5" aria-label="Select page"></mat-paginator> </ng-template> ---> diff --git a/smp-angular/src/app/system-settings/admin-domain/admin-domain.component.ts b/smp-angular/src/app/system-settings/admin-domain/admin-domain.component.ts index 73dc9f5b377e53fea58d3449b6affc35fcd5c426..fc99742e94006ab32d082f7d5a1afeeeb5075d45 100644 --- a/smp-angular/src/app/system-settings/admin-domain/admin-domain.component.ts +++ b/smp-angular/src/app/system-settings/admin-domain/admin-domain.component.ts @@ -7,10 +7,18 @@ import {AlertMessageService} from "../../common/alert-message/alert-message.serv import {ConfirmationDialogComponent} from "../../common/dialogs/confirmation-dialog/confirmation-dialog.component"; import {MatDialog} from "@angular/material/dialog"; import {EntityStatus} from "../../common/model/entity-status.model"; -import {DomainRo} from "../domain/domain-ro.model"; +import {DomainRo} from "./domain-ro.model"; import {AdminKeystoreService} from "../admin-keystore/admin-keystore.service"; import {CertificateRo} from "../user/certificate-ro.model"; import {BeforeLeaveGuard} from "../../window/sidenav/navigation-on-leave-guard"; +import {ResourceDefinitionRo} from "../admin-extension/resource-definition-ro.model"; +import {ExtensionService} from "../admin-extension/extension.service"; +import {ExtensionRo} from "../admin-extension/extension-ro.model"; +import {MatTabGroup} from "@angular/material/tabs"; +import {CancelDialogComponent} from "../../common/dialogs/cancel-dialog/cancel-dialog.component"; +import {DomainPanelComponent} from "./domain-panel/domain-panel.component"; +import {DomainResourceTypePanelComponent} from "./domain-resource-type-panel/domain-resource-type-panel.component"; +import {DomainSmlIntegrationPanelComponent} from "./domain-sml-panel/domain-sml-integration-panel.component"; @Component({ @@ -22,15 +30,27 @@ export class AdminDomainComponent implements OnInit, AfterViewInit, BeforeLeaveG displayedColumns: string[] = ['domainCode']; dataSource: MatTableDataSource<DomainRo> = new MatTableDataSource(); selected?: DomainRo; - domainList: DomainRo[]; - keystoreCertificates: CertificateRo[]; + domainList: DomainRo[] = []; + keystoreCertificates: CertificateRo[] = []; + domiSMPResourceDefinitions: ResourceDefinitionRo[] = []; + + currenTabIndex: number = 0; + handleTabClick; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; + @ViewChild('domainPanelComponent') domainPanelComponent: DomainPanelComponent; + @ViewChild('domainResourceTypePanelComponent') domainResourceTypePanelComponent: DomainResourceTypePanelComponent; + @ViewChild('domainSmlIntegrationPanelComponent') domainSmlIntegrationPanelComponent: DomainSmlIntegrationPanelComponent; + + + @ViewChild('domainTabs') domainTabs: MatTabGroup; + constructor(private domainService: AdminDomainService, private keystoreService: AdminKeystoreService, + private extensionService: ExtensionService, private alertService: AlertMessageService, private dialog: MatDialog) { @@ -43,15 +63,28 @@ export class AdminDomainComponent implements OnInit, AfterViewInit, BeforeLeaveG this.updateDomain(updatedCertificate); } ); - keystoreService.onKeystoreUpdatedEvent().subscribe(keystoreCertificates => { this.keystoreCertificates = keystoreCertificates; } ); + extensionService.onExtensionsUpdatesEvent().subscribe(updatedExtensions => { + this.updateExtensions(updatedExtensions); + } + ); + + extensionService.getExtensions(); domainService.getDomains(); keystoreService.getKeystoreData(); } + updateExtensions(extensions: ExtensionRo[]) { + + let allResourceDefinition: ResourceDefinitionRo[] = []; + extensions.forEach(ext => allResourceDefinition.push(...ext.resourceDefinitions)) + + this.domiSMPResourceDefinitions = allResourceDefinition; + } + ngOnInit(): void { // filter predicate for search the domain this.dataSource.filterPredicate = @@ -63,6 +96,39 @@ export class AdminDomainComponent implements OnInit, AfterViewInit, BeforeLeaveG ngAfterViewInit() { this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; + // currenctly MatTab has only onTabChanged which is a bit to late. Register new listener to internal + // _handleClick handler + this.registerTabClick(); + } + + registerTabClick(): void { + // Get the handler reference + this.handleTabClick = this.domainTabs._handleClick; + + this.domainTabs._handleClick = (tab, header, newTabIndex) => { + + if (newTabIndex == this.currenTabIndex) { + return; + } + + if (this.isCurrentTabDirty()) { + let canChangeTab = this.dialog.open(CancelDialogComponent).afterClosed().toPromise<boolean>(); + canChangeTab.then((canChange: boolean) => { + if (canChange) { + // reset + this.resetCurrentTabData() + this.handleTabClick.apply(this.domainTabs, [tab, header, newTabIndex]); + this.currenTabIndex = newTabIndex; + if (this.isNewDomain()){ + this.selected = null; + } + } + }); + } else { + this.handleTabClick.apply(this.domainTabs, [tab, header, newTabIndex]); + this.currenTabIndex = newTabIndex; + } + } } updateDomainList(domainList: DomainRo[]) { @@ -80,7 +146,13 @@ export class AdminDomainComponent implements OnInit, AfterViewInit, BeforeLeaveG this.domainList.push(domain) this.selected = domain; this.alertService.success("Domain: [" + domain.domainCode + "] was created!"); - } else if (domain.status == EntityStatus.REMOVED) { + } else if (domain.status == EntityStatus.UPDATED) { + // update value in the array + let itemIndex = this.domainList.findIndex(item => item.domainId == domain.domainId); + this.domainList[itemIndex] = domain; + this.selected = domain; + } + else if (domain.status == EntityStatus.REMOVED) { this.alertService.success("Domain: [" + domain.domainCode + "] is removed!"); this.selected = null; this.domainList = this.domainList.filter(item => item.domainCode !== domain.domainCode) @@ -99,10 +171,65 @@ export class AdminDomainComponent implements OnInit, AfterViewInit, BeforeLeaveG } } + resetUnsavedDataValidation() { + // current tab not changed - OK to change it + if (!this.isCurrentTabDirty()) { + return true; + } + + let canChangeTab = this.dialog.open(CancelDialogComponent).afterClosed().toPromise<boolean>(); + canChangeTab.then((canChange: boolean) => { + if (canChange) { + // reset + this.resetCurrentTabData() + } + }); + } + onCreateDomainClicked() { + this.domainTabs.selectedIndex = 0; + this.selected = this.newDomain(); + this.domainPanelComponent.setFocus(); } + public newDomain(): DomainRo { + return { + index: null, + domainCode: '', + smlSubdomain: '', + smlSmpId: '', + smlParticipantIdentifierRegExp: '', + smlClientCertHeader: '', + smlClientKeyAlias: '', + signatureKeyAlias: '', + status: EntityStatus.NEW, + smlRegistered: false, + smlClientCertAuth: false, + } + } + + onSaveEvent(domain: DomainRo){ + if (this.isNewDomain()) { + this.domainService.createDomain(domain); + } else { + this.domainService.updateDomain(domain); + } + } + + onDiscardNew(){ + this.selected = null; + } + + onSaveResourceTypesEvent(domain: DomainRo){ + this.domainService.updateDomainResourceTypes(domain); + } + + onSaveSmlIntegrationDataEvent(domain: DomainRo){ + this.domainService.updateDomainSMLIntegrationData(domain); + } + + onDeleteSelectedDomainClicked() { this.dialog.open(ConfirmationDialogComponent, { data: { @@ -117,16 +244,70 @@ export class AdminDomainComponent implements OnInit, AfterViewInit, BeforeLeaveG } deleteDomain(domain: DomainRo) { - + this.domainService.deleteDomains(domain); } - public domainSelected(selected: DomainRo) { - this.selected = selected; + public domainSelected(domainSelected: DomainRo) { + if (this.selected === domainSelected) { + return; + } + if (this.isCurrentTabDirty()) { + let canChangeTab = this.dialog.open(CancelDialogComponent).afterClosed().toPromise<boolean>(); + canChangeTab.then((canChange: boolean) => { + if (canChange) { + // reset + this.resetCurrentTabData(); + this.selected = domainSelected; + } + }); + } else { + this.selected = domainSelected; + } } + isDirty(): boolean { + return this.isCurrentTabDirty(); + } + + isCurrentTabDirty(): boolean { + + switch (this.currenTabIndex) { + case 0: + return this.domainPanelComponent?.isDirty(); + case 1: + return this.domainResourceTypePanelComponent?.isDirty(); + case 2: + return this.domainSmlIntegrationPanelComponent?.isDirty(); + } return false; } + isNewDomain():boolean{ + return this.selected!=null && !this.selected.domainId + } + + resetCurrentTabData(): void { + + switch (this.currenTabIndex) { + case 0: + this.domainPanelComponent.onResetButtonClicked(); + break; + case 1: + this.domainPanelComponent.onResetButtonClicked(); + break + case 2: + this.domainSmlIntegrationPanelComponent.onResetButtonClicked(); + break + } + } + + get canNotDelete():boolean{ + return !this.selected || this.domainSmlIntegrationPanelComponent.isDomainRegistered || this.isNewDomain() + } + + get editMode(): boolean { + return this.isCurrentTabDirty(); + } } diff --git a/smp-angular/src/app/system-settings/admin-domain/admin-domain.service.ts b/smp-angular/src/app/system-settings/admin-domain/admin-domain.service.ts index d96105d6123e9dcfa14e5782c750b1841bf9fdb8..3c9969c09e73bb91b6a44f3e89bac8f7d836f82b 100644 --- a/smp-angular/src/app/system-settings/admin-domain/admin-domain.service.ts +++ b/smp-angular/src/app/system-settings/admin-domain/admin-domain.service.ts @@ -4,7 +4,7 @@ import {Observable, Subject} from 'rxjs'; import {HttpClient} from '@angular/common/http'; import {SecurityService} from "../../security/security.service"; import {AlertMessageService} from "../../common/alert-message/alert-message.service"; -import {DomainRo} from "../domain/domain-ro.model"; +import {DomainRo} from "./domain-ro.model"; import {User} from "../../security/user.model"; import {SmpConstants} from "../../smp.constants"; @@ -31,6 +31,70 @@ export class AdminDomainService { }); } + public deleteDomains(domain: DomainRo) { + const currentUser: User = this.securityService.getCurrentUser(); + this.http.delete<DomainRo>(SmpConstants.REST_INTERNAL_DOMAIN_MANAGE_DELETE + .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, currentUser.userId) + .replace(SmpConstants.PATH_PARAM_ENC_DOMAIN_ID, domain.domainId)) + .subscribe((result: DomainRo) => { + this.notifyDomainEntryUpdated(result); + }, (error: any) => { + this.alertService.error(error.error?.errorDescription) + }); + } + + public updateDomain(domain: DomainRo) { + const currentUser: User = this.securityService.getCurrentUser(); + this.http.post<DomainRo>(SmpConstants.REST_INTERNAL_DOMAIN_MANAGE_UPDATE + .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, currentUser.userId) + .replace(SmpConstants.PATH_PARAM_ENC_DOMAIN_ID, domain.domainId) + , domain) + .subscribe((result: DomainRo) => { + this.notifyDomainEntryUpdated(result); + }, (error: any) => { + this.alertService.error(error.error?.errorDescription) + }); + } + + + public createDomain(domain: DomainRo) { + const currentUser: User = this.securityService.getCurrentUser(); + this.http.put<DomainRo>(SmpConstants.REST_INTERNAL_DOMAIN_MANAGE_CREATE + .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, currentUser.userId) + , domain) + .subscribe((result: DomainRo) => { + this.notifyDomainEntryUpdated(result); + }, (error: any) => { + this.alertService.error(error.error?.errorDescription) + }); + } + + public updateDomainSMLIntegrationData(domain: DomainRo) { + const currentUser: User = this.securityService.getCurrentUser(); + this.http.post<DomainRo>(SmpConstants.REST_INTERNAL_DOMAIN_MANAGE_UPDATE_SML_INTEGRATION + .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, currentUser.userId) + .replace(SmpConstants.PATH_PARAM_ENC_DOMAIN_ID, domain.domainId) + , domain) + .subscribe((result: DomainRo) => { + this.notifyDomainEntryUpdated(result); + }, (error: any) => { + this.alertService.error(error.error?.errorDescription) + }); + } + + public updateDomainResourceTypes(domain: DomainRo) { + const currentUser: User = this.securityService.getCurrentUser(); + this.http.post<DomainRo>(SmpConstants.REST_INTERNAL_DOMAIN_MANAGE_UPDATE_RESOURCE_TYPES + .replace(SmpConstants.PATH_PARAM_ENC_USER_ID, currentUser.userId) + .replace(SmpConstants.PATH_PARAM_ENC_DOMAIN_ID, domain.domainId) + , domain.resourceDefinitions) + .subscribe((result: DomainRo) => { + this.notifyDomainEntryUpdated(result); + }, (error: any) => { + this.alertService.error(error.error?.errorDescription) + }); + } + notifyDomainsUpdated(res: DomainRo[]) { this.domainUpdateSubject.next(res); diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-panel/domain-panel.component.html b/smp-angular/src/app/system-settings/admin-domain/domain-panel/domain-panel.component.html index 1c0c9390e5cb7b627771c213e98b0e513561a823..dd7b49082647f0e1ef20842af9bbd3b26b70a9f1 100644 --- a/smp-angular/src/app/system-settings/admin-domain/domain-panel/domain-panel.component.html +++ b/smp-angular/src/app/system-settings/admin-domain/domain-panel/domain-panel.component.html @@ -1,14 +1,31 @@ <div id="domain-panel" class="mat-elevation-z2" > - <form [formGroup]="domainForm" (ngSubmit)="onSaveClicked()"> + <form [formGroup]="domainForm" > + <mat-toolbar> + <mat-toolbar-row> + <button id="cancelButton" mat-raised-button (click)="onResetButtonClicked()" color="primary" + [disabled]="!resetButtonEnabled"> + <mat-icon>refresh</mat-icon> + <span>Reset</span> + </button> + <button id="saveButton" mat-raised-button (click)="onSaveButtonClicked()" color="primary" + [disabled]="!submitButtonEnabled"> + <mat-icon>save</mat-icon> + <span>Save</span> + </button> + + </mat-toolbar-row> + </mat-toolbar> <h3>Domain details</h3> + <div class="panel" *ngIf="_domain!=null && !_domain.domainId"><p style="font-weight: bold">Enter data and click 'Save' to create new domain</div> <mat-form-field style="width:100%"> <mat-label>Domain Code</mat-label> <input matInput placeholder="Domain Code" id="domainCode_id" #domainCode - matTooltip="The SMP's domain code. The code must be unique and is used in HTTP header 'Domain' or URL path sequence when retrieving /creating the resource using the webservice API" + matTooltip="The SMP's domain code. The code must be unique and is used in HTTP header 'Domain' or URL path sequence when retrieving/creating the resource using the webservice API" formControlName="domainCode" maxlength="63" (keydown)="onFieldKeyPressed('domainCode', 'domainCodeTimeout')" - required> + required + auto-focus-directive> <mat-hint align="end">For WS API integration: the Domain property</mat-hint> <div *ngIf="(!editMode && domainForm.controls['domainCode'].touched || editMode) && domainForm.controls['domainCode'].hasError('pattern')" @@ -27,43 +44,9 @@ </div> </mat-form-field> <mat-form-field style="width:100%"> - <input matInput placeholder="SML domain" - matTooltip="The domain-specific part of the SML DNS zone (e.g., ‘mydomain’ for mydomain.sml.dns.zone or leave empty for sml.dns.zone). Note: has informative value only, SML DNS zone used for publishing is based on SML configuration." - name="smlSubdomain" - (keydown)="onFieldKeyPressed('domainCode', 'smlSubdomainTimeout')" - id="smldomain_id" - formControlName="smlSubdomain" maxlength="63"> - <mat-hint align="end">The domain-specific part of the SML DNS zone (e.g., ‘mydomain’ for - mydomain.sml.dns.zone). - </mat-hint> - <div - *ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode) - && domainForm.controls['smlSubdomain'].hasError('pattern')" - style="color:red; font-size: 70%"> - SML domain should be up to 63 characters long, should only contain alphanumeric and hyphen characters, - should not start with a digit nor a hyphen and should not end with a hyphen. - </div> - <div - *ngIf="!!fieldWarningTimeoutMap.smlSubdomainTimeout" - style="color:darkorange; font-size: 70%"> - SML domain should be up to 63 characters long, should only contain alphanumeric and hyphen characters, - should not start with a digit nor a hyphen and should not end with a hyphen. - </div> - <div - *ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode) && domainForm.controls['smlSubdomain'].hasError('notInList')" - style="color:red; font-size: 70%"> - The SML subdomain is already defined! - </div> - <div - *ngIf="(!editMode && domainForm.controls['smlSubdomain'].hasError('blankDomainError'))" - style="color:red; font-size: 70%"> - Domain with empty sml subdomain already exists! - </div> - </mat-form-field> - <mat-form-field style="width:100%"> + <mat-label>Response signature Certificate (Signature CertAlias)</mat-label> <mat-select placeholder="Response signature Certificate (Signature CertAlias)" formControlName="signatureKeyAlias" - name="cert" matTooltip="Certificate is used for signing REST responses for the domain." id="signatureKeyAlias_id"> <mat-option [value]="''">Choose certificate for signing soap response</mat-option> @@ -74,5 +57,40 @@ <mat-hint align="end">Empty value will cause that Resource responses will not be signed by SMP! </mat-hint> </mat-form-field> + + <mat-form-field style="width:100%"> + <mat-label>Visibility of the domain</mat-label> + <mat-select placeholder="Visibility of the domain" + formControlName="visibility" + name="visibility" + matTooltip="Visibility of the domain." + id="domainVisibility_id"> + <mat-option [value]="''" diabled>Choose visibility of the domain</mat-option> + <mat-option *ngFor="let visibility of domainVisibilityOptions" + [value]="visibility.value"> + {{visibility.key}} + </mat-option> + </mat-select> + <mat-hint align="end">Domain visibility. In case of Internal user must be authenticated + to get read the domain resources + </mat-hint> + </mat-form-field> + + <mat-form-field style="width:100%"> + <mat-label>Default resource type for the domain</mat-label> + <mat-select placeholder="Default resource type for the domain" + formControlName="defaultResourceTypeIdentifier" + matTooltip="Default resource type for the domain." + id="domainDefaultResourceType_id"> + <mat-option [value]="''">Choose Default resource type for the domain</mat-option> + <mat-option *ngFor="let resDef of domainResourceTypes" + [value]="resDef.identifier"> + {{resDef.name}} ({{resDef.identifier}}) + </mat-option> + </mat-select> + <mat-hint align="end">Domain visibility. In case of Internal user must be authenticated + to get read the domain resources + </mat-hint> + </mat-form-field> </form> </div> diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-panel/domain-panel.component.ts b/smp-angular/src/app/system-settings/admin-domain/domain-panel/domain-panel.component.ts index 885fbeef0714333d1c892f9ddedc1b960ea234c7..312422f3d13f56d07635f989e5a4f46dd504f76f 100644 --- a/smp-angular/src/app/system-settings/admin-domain/domain-panel/domain-panel.component.ts +++ b/smp-angular/src/app/system-settings/admin-domain/domain-panel/domain-panel.component.ts @@ -1,10 +1,13 @@ -import {Component, Input,} from '@angular/core'; -import {DomainRo} from "../../domain/domain-ro.model"; +import {Component, ElementRef, EventEmitter, Input, Output, ViewChild,} from '@angular/core'; +import {DomainRo} from "../domain-ro.model"; import {AbstractControl, FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms"; import {AdminDomainService} from "../admin-domain.service"; import {AlertMessageService} from "../../../common/alert-message/alert-message.service"; import {MatDialog} from "@angular/material/dialog"; import {CertificateRo} from "../../user/certificate-ro.model"; +import {VisibilityEnum} from "../../../common/enums/visibility.enum"; +import {ResourceDefinitionRo} from "../../admin-extension/resource-definition-ro.model"; +import {BeforeLeaveGuard} from "../../../window/sidenav/navigation-on-leave-guard"; @Component({ @@ -12,18 +15,19 @@ import {CertificateRo} from "../../user/certificate-ro.model"; templateUrl: './domain-panel.component.html', styleUrls: ['./domain-panel.component.scss'] }) -export class DomainPanelComponent { +export class DomainPanelComponent implements BeforeLeaveGuard { + @Output() onSaveBasicDataEvent: EventEmitter<DomainRo> = new EventEmitter(); - // Request from test team can not automate test if this is less than 10 seconds :(. Initialy it was 2s - readonly warningTimeout : number = 10000; + @Output() onDiscardNew: EventEmitter<any> = new EventEmitter(); + readonly warningTimeout: number = 50000; readonly domainCodePattern = '^[a-zA-Z0-9]{1,63}$'; - readonly dnsDomainPattern = '^([a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?){0,63}$'; - readonly subDomainPattern = this.dnsDomainPattern; - readonly smpIdDomainPattern = this.dnsDomainPattern; + readonly domainVisibilityOptions = Object.keys(VisibilityEnum) + .filter(el => el !== "Private").map(el => { + return {key: el, value: VisibilityEnum[el]} + }); fieldWarningTimeoutMap = { domainCodeTimeout: null, - smlSubdomainTimeout: null, }; _domain: DomainRo = null; @@ -31,8 +35,12 @@ export class DomainPanelComponent { editMode: boolean; createMode: boolean; - @Input() keystoreCertificates:CertificateRo[]; - @Input() currentDomains:DomainRo[]; + @Input() keystoreCertificates: CertificateRo[]; + @Input() currentDomains: DomainRo[]; + @Input() domiSMPResourceDefinitions: ResourceDefinitionRo[]; + + + @ViewChild('domainCode', {static: false}) domainCodeField: ElementRef; notInList(list: string[], exception: string) { if (!list || !exception) { @@ -52,7 +60,7 @@ export class DomainPanelComponent { * Show warning if domain code exceed the maxlength. * @param value */ - onFieldKeyPressed(controlName: string, showTheWarningReference:string) { + onFieldKeyPressed(controlName: string, showTheWarningReference: string) { let value = this.domainForm.get(controlName).value if (!!value && value.length >= 63 && !this.fieldWarningTimeoutMap[showTheWarningReference]) { @@ -63,23 +71,27 @@ export class DomainPanelComponent { } - constructor(private domainService: AdminDomainService, private alertService: AlertMessageService, private dialog: MatDialog, private formBuilder: FormBuilder) { this.domainForm = formBuilder.group({ - 'domainCode': new FormControl({value: '', readonly: this.createMode}, [Validators.pattern(this.domainCodePattern), + 'domainCode': new FormControl({value: '', readonly: true}, [Validators.pattern(this.domainCodePattern), this.notInList(this.currentDomains?.map(a => a.domainCode), this._domain?.domainCode)]), - 'smlSubdomain': new FormControl({value: '', readonly: this.editMode}, [Validators.pattern(this.subDomainPattern), - this.notInList(this.currentDomains?.map(a => a.smlSubdomain), this._domain?.smlSubdomain)]), - 'signatureKeyAlias': new FormControl({value: '', readonly: this.editMode}), + 'signatureKeyAlias': new FormControl({value: '', readonly: true}), + 'visibility': new FormControl({value: '', readonly: true}), + 'defaultResourceTypeIdentifier': new FormControl({value: '', disabled: this.isNewDomain()}), }); } get domain(): DomainRo { - return this._domain; + let newDomain = {...this._domain}; + newDomain.domainCode = this.domainForm.get('domainCode').value; + newDomain.signatureKeyAlias = this.domainForm.get('signatureKeyAlias').value; + newDomain.visibility = this.domainForm.get('visibility').value; + newDomain.defaultResourceTypeIdentifier = this.domainForm.get('defaultResourceTypeIdentifier').value; + return newDomain; } @Input() set domain(value: DomainRo) { @@ -87,28 +99,56 @@ export class DomainPanelComponent { if (!!value) { this.domainForm.controls['domainCode'].setValue(this._domain.domainCode); - this.domainForm.controls['smlSubdomain'].setValue(this._domain.smlSubdomain); - this.domainForm.controls['smlSmpId'].setValue(this._domain.smlSmpId); - this.domainForm.controls['smlClientKeyAlias'].setValue(this._domain.smlClientKeyAlias); - this.domainForm.controls['smlClientCertHeader'].setValue(this._domain.smlClientCertHeader); this.domainForm.controls['signatureKeyAlias'].setValue(this._domain.signatureKeyAlias); - this.domainForm.controls['smlRegistered'].setValue(this._domain.smlRegistered); - this.domainForm.controls['smlClientCertAuth'].setValue(this._domain.smlClientCertAuth); + this.domainForm.controls['visibility'].setValue(this._domain.visibility); + this.domainForm.controls['defaultResourceTypeIdentifier'].setValue(this._domain.defaultResourceTypeIdentifier); + this.domainForm.enable(); } else { this.domainForm.controls['domainCode'].setValue(""); - this.domainForm.controls['smlSubdomain'].setValue(""); - this.domainForm.controls['smlSmpId'].setValue(""); - this.domainForm.controls['smlClientKeyAlias'].setValue(""); - this.domainForm.controls['smlClientCertHeader'].setValue(""); this.domainForm.controls['signatureKeyAlias'].setValue(""); - this.domainForm.controls['smlRegistered'].setValue(""); - this.domainForm.controls['smlClientCertAuth'].setValue(""); + this.domainForm.controls['visibility'].setValue(VisibilityEnum.Public); + this.domainForm.controls['defaultResourceTypeIdentifier'].setValue(""); + this.domainForm.disable(); } - this.domainForm.markAsPristine(); } - onSaveClicked(){ + isNewDomain(): boolean { + return this._domain != null && !this._domain.domainId + } + isDirty(): boolean { + return this.isNewDomain() || this.domainForm?.dirty; } + + get domainResourceTypes(){ + if (!this._domain || !this._domain.resourceDefinitions){ + return []; + } + return this.domiSMPResourceDefinitions.filter(resType => this._domain.resourceDefinitions.includes(resType.identifier)) + } + get submitButtonEnabled(): boolean { + return this.domainForm.valid && this.domainForm.dirty; + } + + get resetButtonEnabled(): boolean { + return this.domainForm.dirty || this.isNewDomain(); + } + + public onSaveButtonClicked() { + this.onSaveBasicDataEvent.emit(this.domain); + } + + public onResetButtonClicked() { + if (this.isNewDomain()) { + this.onDiscardNew.emit(); + } else { + this.domainForm.reset(this._domain); + } + } + + public setFocus() { + setTimeout(() => this.domainCodeField.nativeElement.focus()); + } + } diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-resource-type-panel/domain-resource-type-panel.component.html b/smp-angular/src/app/system-settings/admin-domain/domain-resource-type-panel/domain-resource-type-panel.component.html index d039a4943d0746c78392f84e4d932d2139c88668..a25e11f6faf755e1ec8ab9cab933f17ce84faa37 100644 --- a/smp-angular/src/app/system-settings/admin-domain/domain-resource-type-panel/domain-resource-type-panel.component.html +++ b/smp-angular/src/app/system-settings/admin-domain/domain-resource-type-panel/domain-resource-type-panel.component.html @@ -1,13 +1,28 @@ -<form [formGroup]="domainForm" (ngSubmit)="onSaveClicked()"> +<form [formGroup]="domainForm" > <div id="domain-resource-type-panel" class="mat-elevation-z2"> + <mat-toolbar> + <mat-toolbar-row> + <button id="cancelButton" mat-raised-button (click)="onResetButtonClicked()" color="primary" + [disabled]="!resetButtonEnabled"> + <mat-icon>refresh</mat-icon> + <span>Reset</span> + </button> + <button id="saveButton" mat-raised-button (click)="onSaveClicked()" color="primary" + [disabled]="!submitButtonEnabled"> + <mat-icon>save</mat-icon> + <span>Save</span> + </button> + + </mat-toolbar-row> + </mat-toolbar> <h3>Domain resource type configuration</h3> - <mat-selection-list #shoes> - <mat-list-option *ngFor="let resDef of domiSMPResourceDefinitions"> - {{resDef.identifier}} + <mat-selection-list formControlName="resourceDefinitions"> + <mat-list-option *ngFor="let resDef of domiSMPResourceDefinitions" + [matTooltip]="resDef.description" + [value]="resDef.identifier"> + {{resDef.identifier}} ({{resDef.urlSegment}}) </mat-list-option> </mat-selection-list> - - </div> </form> diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-resource-type-panel/domain-resource-type-panel.component.ts b/smp-angular/src/app/system-settings/admin-domain/domain-resource-type-panel/domain-resource-type-panel.component.ts index 9eb20b304fe44179d074def18b745885d41ea9e2..f6879ded4ffc92973369be5a780ed8615f7255bf 100644 --- a/smp-angular/src/app/system-settings/admin-domain/domain-resource-type-panel/domain-resource-type-panel.component.ts +++ b/smp-angular/src/app/system-settings/admin-domain/domain-resource-type-panel/domain-resource-type-panel.component.ts @@ -1,9 +1,8 @@ -import {Component, Input,} from '@angular/core'; -import {DomainRo} from "../../domain/domain-ro.model"; -import {FormBuilder, FormGroup} from "@angular/forms"; -import {ExtensionService} from "../../admin-extension/extension.service"; -import {ExtensionRo} from "../../admin-extension/extension-ro.model"; +import {Component, EventEmitter, Input, Output,} from '@angular/core'; +import {DomainRo} from "../domain-ro.model"; +import {FormBuilder, FormControl, FormGroup} from "@angular/forms"; import {ResourceDefinitionRo} from "../../admin-extension/resource-definition-ro.model"; +import {BeforeLeaveGuard} from "../../../window/sidenav/navigation-on-leave-guard"; @Component({ @@ -11,44 +10,58 @@ import {ResourceDefinitionRo} from "../../admin-extension/resource-definition-ro templateUrl: './domain-resource-type-panel.component.html', styleUrls: ['./domain-resource-type-panel.component.scss'] }) -export class DomainResourceTypePanelComponent { - +export class DomainResourceTypePanelComponent implements BeforeLeaveGuard { + @Output() onSaveResourceTypesEvent: EventEmitter<DomainRo> = new EventEmitter(); _domain: DomainRo = null; - - domiSMPResourceDefinitions: ResourceDefinitionRo[] = []; + createMode: boolean = false; + @Input() domiSMPResourceDefinitions: ResourceDefinitionRo[] = []; domainForm: FormGroup; - get domain(): DomainRo { - return this._domain; + let newDomain = {...this._domain}; + newDomain.resourceDefinitions = this.domainForm.get('resourceDefinitions').value; + return newDomain; } @Input() set domain(value: DomainRo) { this._domain = value; + if (!!value) { + this.domainForm.controls['resourceDefinitions'].setValue(this._domain.resourceDefinitions); + this.domainForm.enable(); + } else { + this.domainForm.controls['resourceDefinitions'].setValue([]); + this.domainForm.disable(); + } + this.domainForm.markAsPristine(); } constructor( - private formBuilder: FormBuilder, - extensionService: ExtensionService - ) { - extensionService.onExtensionsUpdatesEvent().subscribe(updatedExtensions => { - this.updateExtensions(updatedExtensions); - } - ); + private formBuilder: FormBuilder) { - extensionService.getExtensions(); + this.domainForm = formBuilder.group({ + 'resourceDefinitions': new FormControl({value: '', readonly: this.createMode}) + }); } - updateExtensions(extensions: ExtensionRo[]) { + onSaveClicked() { + this.onSaveResourceTypesEvent.emit(this.domain); + } - let allResourceDefinition: ResourceDefinitionRo[] = []; - extensions.forEach(ext => allResourceDefinition.push(...ext.resourceDefinitions)) - this.domiSMPResourceDefinitions = allResourceDefinition; + + get submitButtonEnabled(): boolean { + return this.domainForm.valid && this.domainForm.dirty; } - onSaveClicked() { + get resetButtonEnabled(): boolean { + return this.domainForm.dirty; + } + public onResetButtonClicked(){ + this.domainForm.reset(this._domain); + } + isDirty(): boolean { + return this.domainForm.dirty; } } diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-ro.model.ts b/smp-angular/src/app/system-settings/admin-domain/domain-ro.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..f80a78cf64614ad3766c8950cb34821a7ca6af67 --- /dev/null +++ b/smp-angular/src/app/system-settings/admin-domain/domain-ro.model.ts @@ -0,0 +1,20 @@ +import {SearchTableEntity} from '../../common/search-table/search-table-entity.model'; +import {VisibilityEnum} from "../../common/enums/visibility.enum"; + +export interface DomainRo extends SearchTableEntity { + domainId?: string; + domainCode?: string; + smlSubdomain?: string; + smlSmpId?: string; + smlParticipantIdentifierRegExp?: string; + smlClientCertHeader?: string; + smlClientKeyAlias?: string; + signatureKeyAlias?: string; + smlRegistered?: boolean; + smlClientCertAuth?: boolean; + visibility?:VisibilityEnum; + defaultResourceTypeIdentifier?:string; + resourceDefinitions?: string[] + +} + diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-sml-panel/domain-sml-integration-panel.component.html b/smp-angular/src/app/system-settings/admin-domain/domain-sml-panel/domain-sml-integration-panel.component.html index 128585c2af296f253abd99638a3d8f2b1ee92122..8b3d5eb799acfdbc34b4f06e9faa2d8fcb6a137e 100644 --- a/smp-angular/src/app/system-settings/admin-domain/domain-sml-panel/domain-sml-integration-panel.component.html +++ b/smp-angular/src/app/system-settings/admin-domain/domain-sml-panel/domain-sml-integration-panel.component.html @@ -1,25 +1,108 @@ -<form [formGroup]="domainForm" (ngSubmit)="onSaveClicked()"> +<form [formGroup]="domainForm" > <div id="domain-sml-integration-panel" class="mat-elevation-z2"> + <mat-toolbar> + <mat-toolbar-row> + <button id="cancelButton" mat-raised-button (click)="onResetButtonClicked()" color="primary" + [disabled]="!resetButtonEnabled"> + <mat-icon>refresh</mat-icon> + <span>Reset</span> + </button> + <button id="saveButton" mat-raised-button (click)="onSaveButtonClicked()" color="primary" + [disabled]="!submitButtonEnabled"> + <mat-icon>save</mat-icon> + <span>Save</span> + </button> + <tool-button-spacer></tool-button-spacer> + + <button id="registerButton" mat-raised-button (click)="smlRegisterSelectedDomain()" + [disabled]="!enableSMLRegister()" color="primary"> + <mat-icon>link</mat-icon> + <span>Register</span> + </button> + <button id="unregisterButton" mat-raised-button (click)="smlUnregisterSelectedDomain()" + [disabled]="!enableSMLUnregister()" color="primary"> + <mat-icon>link_off</mat-icon> + <span>Unregister</span> + </button> + </mat-toolbar-row> + </mat-toolbar> <h3>SML integration data</h3> + <div class="panel" *ngIf="isDomainRegistered"><p style="font-weight: bold">Domain is registered to SML!</p>The Registered domain can not be deleted or changed the SMP SML identifier</div> + <mat-form-field style="width:100%"> + <input matInput placeholder="SML domain" + matTooltip="The domain-specific part of the SML DNS zone (e.g., ‘mydomain’ for mydomain.sml.dns.zone or leave empty for sml.dns.zone). Note: has informative value only, SML DNS zone used for publishing is based on SML configuration." + name="smlSubdomain" + id="smldomain_id" + (keydown)="onFieldKeyPressed('smlSubdomain', 'smlDomainCodeTimeout')" + formControlName="smlSubdomain" + maxlength="63"> + <mat-hint align="end">The domain-specific part of the SML DNS zone (e.g., ‘mydomain’ for + mydomain.sml.dns.zone). + </mat-hint> + <div + *ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode) + && domainForm.controls['smlSubdomain'].hasError('pattern')" + style="color:red; font-size: 70%"> + SML domain should be up to 63 characters long, should only contain alphanumeric and hyphen characters, + should not start with a digit nor a hyphen and should not end with a hyphen. + </div> + <div + *ngIf="!!fieldWarningTimeoutMap.smlDomainCodeTimeout" + style="color:darkorange; font-size: 70%"> + SML domain should be up to 63 characters long, should only contain alphanumeric and hyphen characters, + should not start with a digit nor a hyphen and should not end with a hyphen. + </div> + <div + *ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode) && domainForm.controls['smlSubdomain'].hasError('notInList')" + style="color:red; font-size: 70%"> + The SML subdomain is already defined! + </div> + <div + *ngIf="(!editMode && domainForm.controls['smlSubdomain'].hasError('blankDomainError'))" + style="color:red; font-size: 70%"> + Domain with empty sml subdomain already exists! + </div> + </mat-form-field> <mat-form-field style="width:100%"> <mat-label>SML SMP identifier</mat-label> <input matInput placeholder="SML SMP identifier" name="smlSmpId" id="smlSMPId_id" #smlSMPId - formControlName="smlSmpId" maxlength="63"> + formControlName="smlSmpId" + (keydown)="onFieldKeyPressed('smlSmpId', 'smlsmpidTimeout')" + + maxlength="63"> <mat-hint align="end">SMP ID used for SML</mat-hint> + <div + *ngIf="(!editMode && domainForm.controls['smlSmpId'].touched || editMode) && domainForm.controls['smlSmpId'].hasError('pattern')" + style="color:red; font-size: 70%"> + SML SMP ID should be up to 63 characters long, should only contain alphanumeric and hyphen characters, + should not start with a digit nor a hyphen and should not end with a hyphen. + </div> + <div + *ngIf="!!fieldWarningTimeoutMap.smlsmpidTimeout" + style="color:darkorange; font-size: 70%"> + SML SMP ID should be up to 63 characters long, should only contain alphanumeric and hyphen characters, + should not start with a digit nor a hyphen and should not end with a hyphen. + </div> + <div + *ngIf="(!editMode && domainForm.controls['smlSmpId'].touched || editMode) && domainForm.controls['smlSmpId'].hasError('notInList')" + style="color:red; font-size: 70%"> + SML SMP ID already exists! + </div> </mat-form-field> <mat-form-field style="width:100%" matTooltip="Client Certificate used for SML authentication. The SML Client-Cert http Header is also generated from the certificate"> - <mat-label>SML Client Certificate Alias</mat-label> <mat-select placeholder="SML ClientCert Alias" formControlName="smlClientKeyCertificate" - name="cert" id="smlClientKeyAlias_id"> - <mat-option [value]="''">Choose certificate for SML integration</mat-option> + <mat-option [value]="''">Choose certificate for signing soap response</mat-option> + <mat-option *ngFor="let cert of keystoreCertificates" [value]="cert.alias"> + {{cert.alias}} ({{cert.certificateId}}) + </mat-option> </mat-select> </mat-form-field> @@ -30,6 +113,6 @@ id="smlClientCertHeaderAuth_id"> Use ClientCert http header authentication. </mat-slide-toggle> - </div> + </form> diff --git a/smp-angular/src/app/system-settings/admin-domain/domain-sml-panel/domain-sml-integration-panel.component.ts b/smp-angular/src/app/system-settings/admin-domain/domain-sml-panel/domain-sml-integration-panel.component.ts index e4d3619b1564116a612f49ed52f7bda14ccfbf60..9d71722ac830892ce9235cdaa0b4856b3b5f06bf 100644 --- a/smp-angular/src/app/system-settings/admin-domain/domain-sml-panel/domain-sml-integration-panel.component.ts +++ b/smp-angular/src/app/system-settings/admin-domain/domain-sml-panel/domain-sml-integration-panel.component.ts @@ -1,9 +1,15 @@ -import {Component, Input,} from '@angular/core'; -import {DomainRo} from "../../domain/domain-ro.model"; -import {FormBuilder, FormControl, FormGroup} from "@angular/forms"; +import {Component, EventEmitter, Input, Output,} from '@angular/core'; +import {DomainRo} from "../domain-ro.model"; +import {AbstractControl, FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms"; import {AdminDomainService} from "../admin-domain.service"; import {AlertMessageService} from "../../../common/alert-message/alert-message.service"; import {MatDialog} from "@angular/material/dialog"; +import {CertificateRo} from "../../user/certificate-ro.model"; +import {BeforeLeaveGuard} from "../../../window/sidenav/navigation-on-leave-guard"; +import {ConfirmationDialogComponent} from "../../../common/dialogs/confirmation-dialog/confirmation-dialog.component"; +import {SMLResult} from "../../domain/sml-result.model"; +import {SmlIntegrationService} from "../../domain/sml-integration.service"; +import {GlobalLookups} from "../../../common/global-lookups"; @Component({ @@ -11,52 +17,259 @@ import {MatDialog} from "@angular/material/dialog"; templateUrl: './domain-sml-integration-panel.component.html', styleUrls: ['./domain-sml-integration-panel.component.scss'] }) -export class DomainSmlIntegrationPanelComponent { - +export class DomainSmlIntegrationPanelComponent implements BeforeLeaveGuard { + @Output() onSaveSmlIntegrationDataEvent: EventEmitter<DomainRo> = new EventEmitter(); + readonly dnsDomainPattern = '^([a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?){0,63}$'; + readonly subDomainPattern = this.dnsDomainPattern; + readonly smpIdDomainPattern = this.dnsDomainPattern; _domain: DomainRo = null; domainForm: FormGroup; + readonly warningTimeout: number = 50000; + fieldWarningTimeoutMap = { + domainCodeTimeout: null, + smlDomainCodeTimeout: null, + smlsmpidTimeout: null, + }; + editMode: boolean; + + + notInList(list: string[], exception: string) { + if (!list || !exception) { + return (c: AbstractControl): { [key: string]: any } => { + return null; + } + } + + return (c: AbstractControl): { [key: string]: any } => { + if (c.value && c.value !== exception && list.includes(c.value)) + return {'notInList': {valid: false}}; + return null; + } + } + + /** + * Show warning if domain code exceed the maxlength. + * @param value + */ + onFieldKeyPressed(controlName: string, showTheWarningReference: string) { + let value = this.domainForm.get(controlName).value + + if (!!value && value.length >= 63 && !this.fieldWarningTimeoutMap[showTheWarningReference]) { + this.fieldWarningTimeoutMap[showTheWarningReference] = setTimeout(() => { + this.fieldWarningTimeoutMap[showTheWarningReference] = null; + }, this.warningTimeout); + } + } + constructor(private domainService: AdminDomainService, private alertService: AlertMessageService, + protected smlIntegrationService: SmlIntegrationService, + protected lookups: GlobalLookups, private dialog: MatDialog, private formBuilder: FormBuilder) { this.domainForm = formBuilder.group({ - - 'smlSmpId': new FormControl({value: '', readonly: true}), + 'smlSubdomain': new FormControl({ + value: '', + disabled: this.editMode + }, [Validators.pattern(this.subDomainPattern), + this.notInList(this.lookups.cachedDomainList.map(a => a.smlSubdomain), this._domain?.smlSubdomain)]), + 'smlSmpId': new FormControl({ + value: '', + disabled: this.isDomainRegistered + }, [Validators.pattern(this.smpIdDomainPattern), + this.notInList(this.lookups.cachedDomainList.map(a => a.smlSmpId), this._domain?.smlSmpId)]), 'smlClientCertHeader': new FormControl({value: '', readonly: true}), 'smlClientKeyAlias': new FormControl({value: '', readonly: true}), + 'smlClientCertAuth': new FormControl({value: '', readonly: true}), 'smlClientKeyCertificate': new FormControl({value: '', readonly: true}), 'smlRegistered': new FormControl({value: '', readonly: true}), - 'smlClientCertAuth': new FormControl({value: '', readonly: true}), + }); } get domain(): DomainRo { - return this._domain; + + let newDomain = {...this._domain}; + newDomain.smlSubdomain = this.domainForm.get('smlSubdomain').value; + newDomain.smlSmpId = this.domainForm.get('smlSmpId').value; + newDomain.smlClientKeyAlias = this.domainForm.get('smlClientKeyAlias').value; + newDomain.smlClientCertHeader = this.domainForm.get('smlClientCertHeader').value; + newDomain.smlClientCertAuth = this.domainForm.get('smlClientCertAuth').value; + return newDomain; } @Input() set domain(value: DomainRo) { this._domain = value; - if (!!this._domain) { + if (!!this._domain) { + this.domainForm.controls['smlSubdomain'].setValue(this._domain.smlSubdomain); this.domainForm.controls['smlSmpId'].setValue(this._domain.smlSmpId); this.domainForm.controls['smlClientKeyAlias'].setValue(this._domain.smlClientKeyAlias); this.domainForm.controls['smlClientCertHeader'].setValue(this._domain.smlClientCertHeader); this.domainForm.controls['smlRegistered'].setValue(this._domain.smlRegistered); this.domainForm.controls['smlClientCertAuth'].setValue(this._domain.smlClientCertAuth); + this.domainForm.enable(); } else { - this.domainForm.controls['smlSmpId'].setValue(""); + this.domainForm.controls['smlSubdomain'].setValue(""); + this.domainForm.controls['smlSmpId'].setValue(""); this.domainForm.controls['smlClientKeyAlias'].setValue(""); this.domainForm.controls['smlClientCertHeader'].setValue(""); this.domainForm.controls['smlRegistered'].setValue(""); this.domainForm.controls['smlClientCertAuth'].setValue(""); + this.domainForm.disable(); } this.domainForm.markAsPristine(); } - onSaveClicked(){ + @Input() keystoreCertificates: CertificateRo[]; + + get submitButtonEnabled(): boolean { + return this.domainForm.valid && this.domainForm.dirty; + } + + get resetButtonEnabled(): boolean { + return this.domainForm.dirty; + } + + public onSaveButtonClicked() { + this.onSaveSmlIntegrationDataEvent.emit(this.domain); + } + public onResetButtonClicked() { + this.domainForm.reset(this._domain); } + + isDirty(): boolean { + return this.domainForm.dirty; + } + + + get isSMPIntegrationOn() { + return this.lookups.cachedApplicationConfig?.smlIntegrationOn + } + + enableSMLRegister(): boolean { + if (!this._domain || !this.isSMPIntegrationOn || this.isDirty()) { + return false; + } + + if (!this._domain.smlClientCertHeader && this._domain.smlClientCertAuth) { + return false; + } + if (!this._domain.smlClientKeyAlias && !this._domain.smlClientCertAuth) { + return false; + } + + // entity must be first persisted in order to be enabled to registering to SML + return !this._domain.smlRegistered; + } + + enableSMLUnregister(): boolean { + if (!this._domain || !this.isSMPIntegrationOn || this.isDirty()) { + return false; + } + + if (this._domain.smlClientCertHeader && this._domain.smlClientCertAuth) { + return false; + } + if (!this._domain.smlClientKeyAlias && !this._domain.smlClientCertAuth) { + return false; + } + + // entity must be first persisted in order to be enabled to registering to SML + return this.isDomainRegistered; + } + + get isDomainRegistered() { + return this._domain?.smlRegistered; + } + + + smlUnregisterSelectedDomain() { + if (!this._domain) { + return false; + } + + this.dialog.open(ConfirmationDialogComponent, { + data: { + title: "Unregister domain to SML", + description: "Action will unregister domain: " + this._domain + " and all its resources from SML. Do you wish to continue?" + } + }).afterClosed().subscribe(result => { + if (result) { + this.smlUnregisterDomain(this._domain); + } + }) + } + + smlRegisterSelectedDomain() { + if (!this._domain) { + return false; + } + + this.dialog.open(ConfirmationDialogComponent, { + data: { + title: "Register domain to SML", + description: "Action will register domain: " + this._domain + " and all its service groups to SML. Do you wish to continue?" + } + }).afterClosed().subscribe(result => { + if (result) { + this.smlRegisterDomain(this._domain); + } + }) + } + + smlRegisterDomain(domain: DomainRo) { + //this.searchTable.showSpinner = true; + + this.smlIntegrationService.registerDomainToSML$(domain.domainCode).toPromise().then((res: SMLResult) => { + // this.searchTable.showSpinner = false; + if (res) { + if (res.success) { + this.alertService.success("Domain " + domain.domainCode + " registered to sml!"); + this.lookups.refreshDomainLookupForLoggedUser(); + domain.smlRegistered = true; + } else { + this.alertService.exception('Error occurred while registering domain:' + domain.domainCode, res.errorMessage); + } + } else { + this.alertService.exception('Error occurred while registering domain:' + domain.domainCode, "Unknown error. Check logs."); + } + }, + err => { + // this.searchTable.showSpinner = false; + this.alertService.exception('Error occurred while registering domain:' + domain.domainCode, err); + } + ) + } + + smlUnregisterDomain(domain: DomainRo) { + // this.searchTable.showSpinner = true; + this.smlIntegrationService.unregisterDomainToSML$(domain.domainCode).toPromise().then((res: SMLResult) => { + // this.searchTable.showSpinner = false; + if (res) { + if (res.success) { + this.alertService.success("Domain " + domain.domainCode + " unregistered from sml!"); + this.lookups.refreshDomainLookupForLoggedUser(); + domain.smlRegistered = false; + } else { + this.alertService.exception('Error occurred while unregistering domain:' + domain.domainCode, res.errorMessage); + } + } else { + this.alertService.exception('Error occurred while registering domain:' + domain.domainCode, "Unknown error. Check logs."); + } + } + , + err => { + // this.searchTable.showSpinner = false; + this.alertService.exception('Error occurred while unregistering domain:' + domain.domainCode, err); + } + ) + + } + + } diff --git a/smp-angular/src/app/system-settings/domain/domain-controller.ts b/smp-angular/src/app/system-settings/domain/domain-controller.ts index 87efd4c2c542fbf20bb2dbbc441136fea626e089..e89b284f1f5992225413261f50734f1a5255372e 100644 --- a/smp-angular/src/app/system-settings/domain/domain-controller.ts +++ b/smp-angular/src/app/system-settings/domain/domain-controller.ts @@ -1,10 +1,9 @@ import {SearchTableController} from '../../common/search-table/search-table-controller'; import {MatDialog, MatDialogConfig, MatDialogRef} from '@angular/material/dialog'; import {DomainDetailsDialogComponent} from './domain-details-dialog/domain-details-dialog.component'; -import {DomainRo} from './domain-ro.model'; +import {DomainRo} from '../admin-domain/domain-ro.model'; import {EntityStatus} from '../../common/model/entity-status.model'; import {GlobalLookups} from "../../common/global-lookups"; -import {of} from "rxjs/internal/observable/of"; import {SearchTableValidationResult} from "../../common/search-table/search-table-validation-result.model"; import {SearchTableEntity} from "../../common/search-table/search-table-entity.model"; import {SmpConstants} from "../../smp.constants"; diff --git a/smp-angular/src/app/system-settings/domain/domain-details-dialog/domain-details-dialog.component.ts b/smp-angular/src/app/system-settings/domain/domain-details-dialog/domain-details-dialog.component.ts index 7d8ed9099497bc9838802ae49f16dbe0aa553be3..74d8f06f1c780d5274ac570f40466acbfa1793c8 100644 --- a/smp-angular/src/app/system-settings/domain/domain-details-dialog/domain-details-dialog.component.ts +++ b/smp-angular/src/app/system-settings/domain/domain-details-dialog/domain-details-dialog.component.ts @@ -1,7 +1,7 @@ import {Component, Inject} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; import {AbstractControl, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators} from "@angular/forms"; -import {DomainRo} from "../domain-ro.model"; +import {DomainRo} from "../../admin-domain/domain-ro.model"; import {AlertMessageService} from "../../../common/alert-message/alert-message.service"; import {EntityStatus} from "../../../common/model/entity-status.model"; import {GlobalLookups} from "../../../common/global-lookups"; diff --git a/smp-angular/src/app/system-settings/domain/domain-result.model.ts b/smp-angular/src/app/system-settings/domain/domain-result.model.ts index bfc5bd6eee51247aee0023b03ac7ce98c10650b6..5800872e283f7c8dce20bb63ed9d75123174c05b 100644 --- a/smp-angular/src/app/system-settings/domain/domain-result.model.ts +++ b/smp-angular/src/app/system-settings/domain/domain-result.model.ts @@ -1,4 +1,4 @@ -import {DomainRo} from './domain-ro.model'; +import {DomainRo} from '../admin-domain/domain-ro.model'; export interface DomainResult { serviceEntities: Array<DomainRo>; diff --git a/smp-angular/src/app/system-settings/domain/domain-ro.model.ts b/smp-angular/src/app/system-settings/domain/domain-ro.model.ts deleted file mode 100644 index ac8f8ffc538ad2d3b5e4ed78f4552a6881e8d5c3..0000000000000000000000000000000000000000 --- a/smp-angular/src/app/system-settings/domain/domain-ro.model.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {SearchTableEntity} from '../../common/search-table/search-table-entity.model'; - -export interface DomainRo extends SearchTableEntity { - domainCode: string; - smlSubdomain: string; - smlSmpId: string; - smlParticipantIdentifierRegExp: string; - smlClientCertHeader: string; - smlClientKeyAlias: string; - signatureKeyAlias: string; - smlRegistered: boolean; - smlClientCertAuth: boolean; - - -} - diff --git a/smp-angular/src/app/system-settings/domain/domain.component.ts b/smp-angular/src/app/system-settings/domain/domain.component.ts index c52208983a9df1d22f10888860a108e2bc2c9e4d..fe627f9965571905732d7fc86826bdb6d5fa75c8 100644 --- a/smp-angular/src/app/system-settings/domain/domain.component.ts +++ b/smp-angular/src/app/system-settings/domain/domain.component.ts @@ -17,7 +17,7 @@ import {SmpConstants} from "../../smp.constants"; import {GlobalLookups} from "../../common/global-lookups"; import {SearchTableComponent} from "../../common/search-table/search-table.component"; import {SecurityService} from "../../security/security.service"; -import {DomainRo} from "./domain-ro.model"; +import {DomainRo} from "../admin-domain/domain-ro.model"; import {ConfirmationDialogComponent} from "../../common/dialogs/confirmation-dialog/confirmation-dialog.component"; import {EntityStatus} from "../../common/model/entity-status.model"; import {KeystoreEditDialogComponent} from "./keystore-edit-dialog/keystore-edit-dialog.component"; diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBDomainToDomainROConverter.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBDomainToDomainROConverter.java index bc8e6da1b9f2f31deea1372c6b5943bc23317e6d..240afa3de72b01910016dbddf8e59642bb61ec34 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBDomainToDomainROConverter.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/DBDomainToDomainROConverter.java @@ -4,11 +4,14 @@ import eu.europa.ec.edelivery.smp.data.model.DBDomain; import eu.europa.ec.edelivery.smp.data.ui.DomainRO; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; +import eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils; import org.apache.commons.beanutils.BeanUtils; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.stream.Collectors; /** @@ -24,6 +27,9 @@ public class DBDomainToDomainROConverter implements Converter<DBDomain, DomainRO DomainRO target = new DomainRO(); try { BeanUtils.copyProperties(target, source); + List<String> domainDocuments = source.getDomainResourceDefs().stream().map(dbDomainResourceDef -> dbDomainResourceDef.getResourceDef().getIdentifier()).collect(Collectors.toList()); + target.getResourceDefinitions().addAll(domainDocuments); + target.setDomainId(SessionSecurityUtils.encryptedEntityId(source.getId())); } catch (IllegalAccessException | InvocationTargetException e) { LOG.error("Error occurred while converting DBExtension", e); return null; 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 1adc588db4d02b8eba79bcbe5cc917abf766b08b..cfed00e8771030bcf7a6fb246562d1c302416ac2 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 @@ -85,7 +85,6 @@ public abstract class BaseDao<E extends BaseEntity> { memEManager.detach(entity); } - public void persist(E entity) { memEManager.persist(entity); diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainDao.java index a46c240ae62c48b5e508ab6a07366c7e4b900bd2..3be0c75925e09d688cfa54de152cfe1b41cd581e 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainDao.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainDao.java @@ -14,13 +14,14 @@ 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.DBDomainDeleteValidation; import eu.europa.ec.edelivery.smp.exceptions.ErrorCode; import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Repository; -import javax.persistence.*; +import javax.persistence.NoResultException; +import javax.persistence.NonUniqueResultException; +import javax.persistence.TypedQuery; import javax.transaction.Transactional; import java.util.List; import java.util.Optional; @@ -37,7 +38,6 @@ import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.ILLEGAL_STATE_DOMA public class DomainDao extends BaseDao<DBDomain> { - /** * Returns the only single record from smp_domain table. * Returns Optional.empty() if there is more than 1 record present. @@ -103,6 +103,13 @@ public class DomainDao extends BaseDao<DBDomain> { } } + public Long getResourceCountForDomain(Long domainId) { + TypedQuery<Long> query = memEManager.createNamedQuery(QUERY_RESOURCES_BY_DOMAIN_ID_COUNT, Long.class); + + query.setParameter(PARAM_DOMAIN_ID, domainId); + return query.getSingleResult(); + } + /** * Check if domain for domain code exists. If not SMPRuntimeException with DOMAIN_NOT_EXISTS is thrown. * If code is null or blank - then null is returned. @@ -139,17 +146,4 @@ public class DomainDao extends BaseDao<DBDomain> { return false; } - /** - * Validation report for domain which are used by service groups from list of domain ids.. - * - * @param domainIds - * @return - */ - public List<DBDomainDeleteValidation> validateDomainsForDelete(List<Long> domainIds) { - TypedQuery<DBDomainDeleteValidation> query = memEManager.createNamedQuery("DBDomainDeleteValidation.validateDomainUsage", - DBDomainDeleteValidation.class); - query.setParameter("domainIds", domainIds); - return query.getResultList(); - } - } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainResourceDefDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainResourceDefDao.java index fd99331b6861d28b6375db0523a028fd5e956281..120294a5142600499b1f62ff7c1e85fe893cdfbd 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainResourceDefDao.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainResourceDefDao.java @@ -93,5 +93,12 @@ public class DomainResourceDefDao extends BaseDao<DBDomainResourceDef> { } } + public DBDomainResourceDef create(DBDomain domain, DBResourceDef resourceDef) { + DBDomainResourceDef domainResourceDef = new DBDomainResourceDef(); + domainResourceDef.setDomain(domain); + domainResourceDef.setResourceDef(resourceDef); + return merge(domainResourceDef); + } + } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/QueryNames.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/QueryNames.java index 25906a1be32a660aec43a67169ce39199fdabe46..91adae1882c65e937f61860c61d43e9093861c1b 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/QueryNames.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/QueryNames.java @@ -12,7 +12,6 @@ public class QueryNames { public static final String QUERY_DOMAIN_ALL = "DBDomain.getAll"; - public static final String QUERY_DOMAIN_IMPLEMENTATION_NAME = "DBDomain.getByClassName"; public static final String QUERY_DOMAIN_CODE = "DBDomain.getDomainByCode"; public static final String QUERY_EXTENSION_ALL = "DBExtension.getAll"; public static final String QUERY_EXTENSION_BY_IDENTIFIER = "DBExtension.getByIdentifier"; @@ -36,6 +35,8 @@ public class QueryNames { public static final String QUERY_RESOURCE_BY_IDENTIFIER_RESOURCE_DEF_DOMAIN = "DBResource.getResByIdentifierAndResourceDefAndDomain"; + public static final String QUERY_RESOURCES_BY_DOMAIN_ID_COUNT = "DBResource.getResByDomainIdCount"; + public static final String QUERY_RESOURCES_BY_DOMAIN_ID_RESOURCE_DEF_ID_COUNT = "DBResource.getResByDomainIdAndResourceDefCount"; public static final String QUERY_RESOURCE_MEMBER_ALL = "DBResourceMember.getAll"; diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ResourceDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ResourceDao.java index d74c0421169612043b9633df191f7b2b91d6a8d8..4cf1de9388b16241f1d49cbc2347308292c20a19 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ResourceDao.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ResourceDao.java @@ -135,6 +135,13 @@ public class ResourceDao extends BaseDao<DBResource> { } } + public Long getResourceCountForDomainIdAndResourceDefId(Long domainId, Long resourceDefId) { + TypedQuery<Long> query = memEManager.createNamedQuery(QUERY_RESOURCES_BY_DOMAIN_ID_RESOURCE_DEF_ID_COUNT, Long.class); + query.setParameter(PARAM_DOMAIN_ID, domainId); + query.setParameter(PARAM_RESOURCE_DEF_ID, resourceDefId); + return query.getSingleResult(); + } + /** * Method removes the resource from DB. Related entities (cascade): sub-resources, Document, Document version, * group memberships, diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java index 8141623cb128fbabc914eb9fd520f1fc72c07814..63e5c96bf93b730f036a21f0b4c6294b19ef98d9 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java @@ -24,8 +24,7 @@ import javax.persistence.*; import java.util.ArrayList; import java.util.List; -import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.QUERY_DOMAIN_ALL; -import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.QUERY_DOMAIN_CODE; +import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*; /** * Created by gutowpa on 16/01/2018. @@ -37,24 +36,11 @@ import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.QUERY_DOMAIN_CODE; }) @NamedQuery(name = QUERY_DOMAIN_ALL, query = "SELECT d FROM DBDomain d order by d.id asc") @NamedQuery(name = QUERY_DOMAIN_CODE, query = "SELECT d FROM DBDomain d WHERE d.domainCode = :domain_code") -@NamedNativeQuery(name = "DBDomainDeleteValidation.validateDomainUsage", - resultSetMapping = "DBDomainDeleteValidationMapping", - query = "select D.ID as id, D.DOMAIN_CODE as domainCode, D.SML_SUBDOMAIN as smlSubdomain, COUNT(SGD.ID) as useCount " + - " from SMP_DOMAIN D INNER JOIN SMP_DOMAIN_RESOURCE_DEF SGD ON (D.ID =SGD.FK_DOMAIN_ID) " + - " WHERE D.ID IN (:domainIds)" + - " GROUP BY D.ID, D.DOMAIN_CODE, D.SML_SUBDOMAIN") @NamedNativeQuery(name = "DBDomain.updateNullSignAlias", query = "update SMP_DOMAIN set SIGNATURE_KEY_ALIAS=:alias WHERE SIGNATURE_KEY_ALIAS IS null") @NamedNativeQuery(name = "DBDomain.updateNullSMLAlias", query = "update SMP_DOMAIN set SIGNATURE_KEY_ALIAS=:alias " + "WHERE SML_CLIENT_KEY_ALIAS IS null") -@SqlResultSetMapping(name = "DBDomainDeleteValidationMapping", classes = { - @ConstructorResult(targetClass = DBDomainDeleteValidation.class, - columns = {@ColumnResult(name = "id", type = Long.class), - @ColumnResult(name = "domainCode", type = String.class), - @ColumnResult(name = "smlSubdomain", type = String.class), - @ColumnResult(name = "useCount", type = Integer.class)}) -}) @org.hibernate.annotations.Table(appliesTo = "SMP_DOMAIN", comment = "SMP can handle multiple domains. This table contains domain specific data") public class DBDomain extends BaseEntity { @@ -115,7 +101,7 @@ public class DBDomain extends BaseEntity { orphanRemoval = true, fetch = FetchType.LAZY ) - private List<DBGroup> domainGroups; + private List<DBGroup> domainGroups = new ArrayList<>(); @OneToMany( mappedBy = "domain", @@ -123,7 +109,7 @@ public class DBDomain extends BaseEntity { orphanRemoval = true, fetch = FetchType.LAZY ) - private List<DBDomainResourceDef> domainResourceDefs; + private List<DBDomainResourceDef> domainResourceDefs= new ArrayList<>(); @Override public Long getId() { diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBResource.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBResource.java index b90f19f722b4938834bf3341f228991ad1f80042..5f14b3f3785d91921c142532f335571f49796718 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBResource.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBResource.java @@ -29,7 +29,7 @@ import java.util.List; import java.util.Objects; import java.util.StringJoiner; -import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.QUERY_RESOURCE_BY_IDENTIFIER_RESOURCE_DEF_DOMAIN; +import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*; @Entity @Audited @@ -40,19 +40,24 @@ import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.QUERY_RESOURCE_BY_I @Index(name = "SMP_RS_SCH_IDX", columnList = "IDENTIFIER_SCHEME") }) @org.hibernate.annotations.Table(appliesTo = "SMP_RESOURCE", comment = "SMP resource Identifier and scheme") -@NamedQueries({ - @NamedQuery(name = QUERY_RESOURCE_BY_IDENTIFIER_RESOURCE_DEF_DOMAIN, query = "SELECT d FROM DBResource d WHERE d.domainResourceDef.domain.id = :domain_id " + - " AND d.domainResourceDef.resourceDef.id=:resource_def_id" + - " AND d.identifierValue = :identifier_value " + - " AND (:identifier_scheme IS NULL AND d.identifierScheme IS NULL " + - " OR d.identifierScheme = :identifier_scheme)" - ), - @NamedQuery(name = "DBResource.getServiceGroupByID", query = "SELECT d FROM DBResource d WHERE d.id = :id"), - @NamedQuery(name = "DBResource.getServiceGroupByIdentifier", query = "SELECT d FROM DBResource d WHERE d.identifierValue = :participantIdentifier " + - " AND (:participantScheme IS NULL AND d.identifierScheme IS NULL " + - " OR d.identifierScheme = :participantScheme)"), - @NamedQuery(name = "DBResource.deleteById", query = "DELETE FROM DBResource d WHERE d.id = :id"), -}) +@NamedQuery(name = QUERY_RESOURCE_BY_IDENTIFIER_RESOURCE_DEF_DOMAIN, query = "SELECT d FROM DBResource d WHERE d.domainResourceDef.domain.id = :domain_id " + + " AND d.domainResourceDef.resourceDef.id=:resource_def_id" + + " AND d.identifierValue = :identifier_value " + + " AND (:identifier_scheme IS NULL AND d.identifierScheme IS NULL " + + " OR d.identifierScheme = :identifier_scheme)") + +@NamedQuery(name = QUERY_RESOURCES_BY_DOMAIN_ID_RESOURCE_DEF_ID_COUNT, query = "SELECT count(d.id) FROM DBResource d WHERE d.domainResourceDef.domain.id = :domain_id " + + " and d.domainResourceDef.resourceDef.id = :resource_def_id ") + +@NamedQuery(name = QUERY_RESOURCES_BY_DOMAIN_ID_COUNT, query = "SELECT count(d.id) FROM DBResource d WHERE d.domainResourceDef.domain.id = :domain_id ") + + +@NamedQuery(name = "DBResource.getServiceGroupByID", query = "SELECT d FROM DBResource d WHERE d.id = :id") +@NamedQuery(name = "DBResource.getServiceGroupByIdentifier", query = "SELECT d FROM DBResource d WHERE d.identifierValue = :participantIdentifier " + + " AND (:participantScheme IS NULL AND d.identifierScheme IS NULL " + + " OR d.identifierScheme = :participantScheme)") +@NamedQuery(name = "DBResource.deleteById", query = "DELETE FROM DBResource d WHERE d.id = :id") + @NamedNativeQueries({ @NamedNativeQuery(name = "DBResource.deleteAllOwnerships", query = "DELETE FROM SMP_RESOURCE_MEMBER WHERE FK_SG_ID=:serviceGroupId") }) diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialRO.java index febcbe804a2b3ffd6b32cd29e87ee3bd6de5ff96..2f7a6f97b49e561a740e4ba9a4df4f232f37b27b 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialRO.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CredentialRO.java @@ -11,7 +11,7 @@ import java.time.OffsetDateTime; */ public class CredentialRO extends BaseRO { - static final long serialVersionUID = 9008583888835630000L; + private static final long serialVersionUID = 9008583888835630000L; String credentialId; String name; diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DomainRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DomainRO.java index 93a862cf3a66a1bc82ba5b142bef7a11c79e69fb..51fca3e65202879a836e4b5c94d517bcfb997f53 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DomainRO.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DomainRO.java @@ -1,6 +1,11 @@ package eu.europa.ec.edelivery.smp.data.ui; +import eu.europa.ec.edelivery.smp.data.enums.VisibilityType; + +import java.util.ArrayList; +import java.util.List; + /** * @author Joze Rihtarsic * @since 4.1 @@ -8,25 +13,28 @@ package eu.europa.ec.edelivery.smp.data.ui; public class DomainRO extends BaseRO { - private static final long serialVersionUID = 9008583888835630008L; - Long id; - String domainCode; - String smlSubdomain; - String smlSmpId; - String smlClientCertHeader; - String smlClientKeyAlias; - String signatureKeyAlias; - boolean smlClientCertAuth; - boolean smlRegistered; + private String domainId; + private String domainCode; + private String smlSubdomain; + private String smlSmpId; + private String smlClientCertHeader; + private String smlClientKeyAlias; + private String signatureKeyAlias; + private boolean smlClientCertAuth; + private boolean smlRegistered; + private VisibilityType visibility; + private String defaultResourceTypeIdentifier; + private List<GroupRO> groups = new ArrayList<>(); + private List<String> resourceDefinitions = new ArrayList<>(); - public Long getId() { - return id; + public String getDomainId() { + return domainId; } - public void setId(Long id) { - this.id = id; + public void setDomainId(String domainId) { + this.domainId = domainId; } public String getDomainCode() { @@ -92,4 +100,28 @@ public class DomainRO extends BaseRO { public void setSmlRegistered(boolean smlRegistered) { this.smlRegistered = smlRegistered; } + + public VisibilityType getVisibility() { + return visibility; + } + + public void setVisibility(VisibilityType visibility) { + this.visibility = visibility; + } + + public String getDefaultResourceTypeIdentifier() { + return defaultResourceTypeIdentifier; + } + + public void setDefaultResourceTypeIdentifier(String defaultResourceTypeIdentifier) { + this.defaultResourceTypeIdentifier = defaultResourceTypeIdentifier; + } + + public List<GroupRO> getGroups() { + return groups; + } + + public List<String> getResourceDefinitions() { + return resourceDefinitions; + } } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DomainResourceDefinitionRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DomainResourceDefinitionRO.java new file mode 100644 index 0000000000000000000000000000000000000000..c1278c4ac5c96c84d557d99c9e378cb8353aab58 --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DomainResourceDefinitionRO.java @@ -0,0 +1,42 @@ +package eu.europa.ec.edelivery.smp.data.ui; + + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Joze Rihtarsic + * @since 5.0 + */ + +public class DomainResourceDefinitionRO extends BaseRO { + private static final long serialVersionUID = 9008583888835630027L; + + String domainResourceId; + private String resourceId; + private String resourceIdentifier; + + public String getDomainResourceId() { + return domainResourceId; + } + + public void setDomainResourceId(String domainResourceId) { + this.domainResourceId = domainResourceId; + } + + public String getResourceId() { + return resourceId; + } + + public void setResourceId(String resourceId) { + this.resourceId = resourceId; + } + + public String getResourceIdentifier() { + return resourceIdentifier; + } + + public void setResourceIdentifier(String resourceIdentifier) { + this.resourceIdentifier = resourceIdentifier; + } +} diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/GroupRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/GroupRO.java new file mode 100644 index 0000000000000000000000000000000000000000..14201214c164e9c4ccd03894a96ab89556cda845 --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/GroupRO.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 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.data.ui; + +import eu.europa.ec.edelivery.smp.data.enums.VisibilityType; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +/** + * The group of resources with shared resource management rights. The user with group admin has rights to create/delete + * resources for the group. + * + * @author Joze Rihtarsic + * @since 5.0 + */ +public class GroupRO extends BaseRO { + private static final long serialVersionUID = 9008583888835630026L; + + private String groupId; + private String groupName; + private String groupDescription; + private VisibilityType visibility = VisibilityType.PUBLIC; + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public String getGroupDescription() { + return groupDescription; + } + + public void setGroupDescription(String groupDescription) { + this.groupDescription = groupDescription; + } + + public VisibilityType getVisibility() { + return visibility; + } + + public void setVisibility(VisibilityType visibility) { + this.visibility = visibility; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + GroupRO groupRO = (GroupRO) o; + + return new EqualsBuilder().append(groupId, groupRO.groupId).append(groupName, groupRO.groupName).append(groupDescription, groupRO.groupDescription).append(visibility, groupRO.visibility).isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37).append(groupId).toHashCode(); + } + + @Override + public String toString() { + return "GroupRO{" + + "groupId='" + groupId + '\'' + + ", groupName='" + groupName + '\'' + + ", groupDescription='" + groupDescription + '\'' + + ", visibility=" + visibility + + '}'; + } +} diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainService.java index 9475d3deffdf0dcd0ecfe3976aef32d03e969fa6..1154bd5cc8fcf68273b2ae95cd4daaff86baa719 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainService.java @@ -1,19 +1,23 @@ 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.*; +import eu.europa.ec.edelivery.smp.data.enums.VisibilityType; import eu.europa.ec.edelivery.smp.data.model.DBDomain; -import eu.europa.ec.edelivery.smp.data.model.DBDomainDeleteValidation; -import eu.europa.ec.edelivery.smp.data.ui.DeleteEntityValidation; +import eu.europa.ec.edelivery.smp.data.model.DBDomainResourceDef; +import eu.europa.ec.edelivery.smp.data.model.ext.DBResourceDef; import eu.europa.ec.edelivery.smp.data.ui.DomainRO; import eu.europa.ec.edelivery.smp.data.ui.ServiceResult; import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus; +import eu.europa.ec.edelivery.smp.exceptions.BadRequestException; +import eu.europa.ec.edelivery.smp.exceptions.ErrorBusinessCode; +import eu.europa.ec.edelivery.smp.logging.SMPLogger; +import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.sml.SmlConnector; +import org.apache.commons.lang3.StringUtils; import org.springframework.core.convert.ConversionService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.io.StringWriter; import java.util.List; import java.util.stream.Collectors; @@ -25,13 +29,22 @@ import java.util.stream.Collectors; @Service public class UIDomainService extends UIServiceBase<DBDomain, DomainRO> { + private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIDomainService.class); + + private DomainDao domainDao; + private ResourceDao resourceDao; + private ResourceDefDao resourceDefDao; + private DomainResourceDefDao domainResourceDefDao; private ConversionService conversionService; private SmlConnector smlConnector; - public UIDomainService(ConversionService conversionService, DomainDao domainDao, SmlConnector smlConnector) { + public UIDomainService(ConversionService conversionService, DomainDao domainDao, ResourceDao resourceDao, ResourceDefDao resourceDefDao, DomainResourceDefDao domainResourceDefDao, SmlConnector smlConnector) { this.conversionService = conversionService; this.domainDao = domainDao; + this.resourceDao = resourceDao; + this.resourceDefDao = resourceDefDao; + this.domainResourceDefDao = domainResourceDefDao; this.smlConnector = smlConnector; } @@ -59,58 +72,135 @@ public class UIDomainService extends UIServiceBase<DBDomain, DomainRO> { return super.getTableList(page, pageSize, sortField, sortOrder, filter); } + @Transactional public List<DomainRO> getAllDomains() { List<DBDomain> domains = domainDao.getAllDomains(); - return domains.stream().map(domain -> conversionService.convert(domain, DomainRO.class)) .collect(Collectors.toList()); } @Transactional - public void updateDomainList(List<DomainRO> lst) { - for (DomainRO dRo : lst) { - if (dRo.getStatus() == EntityROStatus.NEW.getStatusNumber()) { - DBDomain dDb = convertFromRo(dRo); - domainDao.persistFlushDetach(dDb); - } else if (dRo.getStatus() == EntityROStatus.UPDATED.getStatusNumber()) { - DBDomain upd = domainDao.find(dRo.getId()); - upd.setSmlSmpId(dRo.getSmlSmpId()); - upd.setSmlClientKeyAlias(dRo.getSmlClientKeyAlias()); - upd.setSmlClientCertHeader(dRo.getSmlClientCertHeader()); - upd.setSmlSubdomain(dRo.getSmlSubdomain()); - upd.setDomainCode(dRo.getDomainCode()); - upd.setSignatureKeyAlias(dRo.getSignatureKeyAlias()); - upd.setSmlClientCertAuth(dRo.isSmlClientCertAuth()); - domainDao.update(upd); - } else if (dRo.getStatus() == EntityROStatus.REMOVE.getStatusNumber()) { - domainDao.removeByDomainCode(dRo.getDomainCode()); - } + public void createDomainData(DomainRO data) { + DBDomain domain = new DBDomain(); + domain.setDomainCode(data.getDomainCode()); + domain.setDefaultResourceTypeIdentifier(data.getDefaultResourceTypeIdentifier()); + domain.setSignatureKeyAlias(data.getSignatureKeyAlias()); + domain.setVisibility(data.getVisibility() == null? VisibilityType.PUBLIC:data.getVisibility()); + domainDao.persistFlushDetach(domain); + } + + + /** + * Update only basic domain data from DomainRO object. Ignore other + * @param domainId + * @param data + * @return + */ + @Transactional + public void updateBasicDomainData(Long domainId, DomainRO data) { + DBDomain domain = domainDao.find(domainId); + if (domain == null) { + LOG.warn("Can not delete domain for ID [{}], because it does not exists!", domainId); + throw new BadRequestException(ErrorBusinessCode.NOT_FOUND, "Domain does not exist in database!"); + } + domain.setDomainCode(data.getDomainCode()); + domain.setDefaultResourceTypeIdentifier(data.getDefaultResourceTypeIdentifier()); + domain.setSignatureKeyAlias(data.getSignatureKeyAlias()); + domain.setVisibility(data.getVisibility()); + } + + @Transactional + public void updateDomainSmlIntegrationData(Long domainId, DomainRO data) { + DBDomain domain = domainDao.find(domainId); + if (domain == null) { + throw new BadRequestException(ErrorBusinessCode.NOT_FOUND, "Domain does not exist in database!"); } + if (domain.isSmlRegistered() && StringUtils.equals(data.getSmlSmpId(), domain.getSmlSmpId())){ + String msg = "SMP-SML identifier must not change for registered domain ["+domain.getDomainCode()+"]!"; + throw new BadRequestException(ErrorBusinessCode.NOT_FOUND, msg); + } + + domain.setSmlSubdomain(data.getSmlSubdomain()); + domain.setSmlSmpId(data.getSmlSmpId()); + domain.setSmlClientKeyAlias(data.getSmlClientKeyAlias()); + domain.setSmlClientCertHeader(data.getSmlClientCertHeader()); + domain.setSmlClientCertAuth(data.isSmlClientCertAuth()); } - public DeleteEntityValidation validateDeleteRequest(DeleteEntityValidation dev) { - List<Long> idList = dev.getListIds().stream().map(encId -> Long.parseLong(encId)).collect(Collectors.toList()); - List<DBDomainDeleteValidation> lstMessages = domainDao.validateDomainsForDelete(idList); - dev.setValidOperation(lstMessages.isEmpty()); - if (!dev.isValidOperation()) { - StringWriter sw = new StringWriter(); - sw.write("Could not delete domains used by Service groups! "); - lstMessages.forEach(msg -> { - dev.getListDeleteNotPermitedIds().add(msg.getId() + ""); - sw.write("Domain: "); - sw.write(msg.getDomainCode()); - sw.write(" ("); - sw.write(msg.getDomainCode()); - sw.write(" )"); - sw.write(" uses by:"); - sw.write(msg.getCount().toString()); - sw.write(" SG."); - - }); - dev.setStringMessage(sw.toString()); + @Transactional + public void updateResourceDefDomainList(Long domainId, List<String> resourceDefIds) { + DBDomain domain = domainDao.find(domainId); + if (domain == null) { + LOG.warn("Can not delete domain for ID [{}], because it does not exists!", domainId); + throw new BadRequestException(ErrorBusinessCode.NOT_FOUND, "Domain does not exist in database!"); } - return dev; + + //filter and validate resources to be removed + List<DBDomainResourceDef> removedDoReDef = domain.getDomainResourceDefs().stream() + .filter(doredef -> !resourceDefIds.contains(doredef.getResourceDef().getIdentifier()) + && validateRemoveDomainResourceDef(domain, doredef.getResourceDef()) + ).collect(Collectors.toList()); + + removedDoReDef.forEach(domainResourceDef -> domain.getDomainResourceDefs().remove(domainResourceDef)); + List<String> currentIdentifiers = domain.getDomainResourceDefs().stream().map(domainResourceDef -> domainResourceDef.getResourceDef().getIdentifier()).collect(Collectors.toList()); + + resourceDefIds.stream() + .filter(identifier -> !currentIdentifiers.contains(identifier)) + .map(identifier -> resourceDefDao.getResourceDefByIdentifier(identifier) + .orElseThrow(() -> new BadRequestException(ErrorBusinessCode.INVALID_INPUT_DATA, "Identifier [" + identifier + "] does not exists"))) + .forEach(resourceDef -> + domainResourceDefDao.create(domain, resourceDef) + ); } + @Transactional + public DomainRO getDomainData(Long domainId){ + DBDomain domain = domainDao.find(domainId); + return conversionService.convert(domain, DomainRO.class); + } + + @Transactional + public DomainRO getDomainDataByDomainCode(String domainCode){ + DBDomain domain = domainDao.getDomainByCode(domainCode).orElse(null); + return conversionService.convert(domain, DomainRO.class); + } + + private boolean validateRemoveDomainResourceDef(DBDomain domain, DBResourceDef resourceDef) { + + Long count = resourceDao.getResourceCountForDomainIdAndResourceDefId(domain.getId(), resourceDef.getId()); + if (count > 0) { + String msg = "Can not remove resource definition [" + resourceDef.getIdentifier() + "] from domain [" + domain.getDomainCode() + + "], because it has resources. Resource count [" + count + "]!"; + throw new BadRequestException(ErrorBusinessCode.INVALID_INPUT_DATA, msg); + } + return true; + } + + @Transactional + public DomainRO deleteDomain(Long domainId) { + + DBDomain domain = domainDao.find(domainId); + if (domain == null) { + LOG.warn("Can not delete domain for ID [{}], because it does not exists!", domainId); + throw new BadRequestException(ErrorBusinessCode.NOT_FOUND, "Domain does not exist in database!"); + } + if (domain.isSmlRegistered()) { + LOG.info("Can not delete domain for ID [{}], is registered to SML!", domainId); + throw new BadRequestException(ErrorBusinessCode.INVALID_INPUT_DATA, "Can not delete domain because it is registered to SML service! Unregister domain from SML service!"); + } + + Long count = domainDao.getResourceCountForDomain(domainId); + if (count > 0) { + LOG.info("Can not delete domain for ID [{}], because it has resources. Resource count [{}]!", domainId, count); + throw new BadRequestException(ErrorBusinessCode.INVALID_INPUT_DATA, "Can not delete domain because it has resources [" + count + "]! Delete resources first!"); + } + + domainDao.remove(domain); + DomainRO domainRO = conversionService.convert(domain, DomainRO.class); + domainRO.setStatus(EntityROStatus.REMOVE.getStatusNumber()); + return domainRO; + } + + } diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/AbstractBaseDao.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/AbstractBaseDao.java index 29058e85e3db59f487fbcbd5f9440b584de7f41b..5f1b2dcb53b99fb548ae1733f206ac23c13909db 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/AbstractBaseDao.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/AbstractBaseDao.java @@ -41,7 +41,7 @@ import static eu.europa.ec.edelivery.smp.testutil.TestConstants.TEST_SML_SUBDOMA public abstract class AbstractBaseDao { @Autowired - TestUtilsDao testUtilsDao; + protected TestUtilsDao testUtilsDao; public static final String BUILD_FOLDER = "target"; public static final Path SECURITY_PATH= Paths.get(BUILD_FOLDER, "smp"); public static final String DATABASE_URL = "jdbc:h2:file:./target/DomiSmpTestDb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=TRUE;AUTO_SERVER=TRUE;"; diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/DomainDaoIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/DomainDaoIntegrationTest.java index 84c1f0772fb8210db2cc1ae59bbf0db079e740ab..030c520aa9ce0acab5fc9d4673e5aff8648d44b2 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/DomainDaoIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/DomainDaoIntegrationTest.java @@ -5,7 +5,7 @@ import eu.europa.ec.edelivery.smp.data.model.doc.DBResource; import eu.europa.ec.edelivery.smp.exceptions.ErrorCode; import eu.europa.ec.edelivery.smp.testutil.TestConstants; import eu.europa.ec.edelivery.smp.testutil.TestDBUtils; -import org.junit.Ignore; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -28,8 +28,11 @@ public class DomainDaoIntegrationTest extends AbstractBaseDao { @Autowired DomainDao testInstance; - @Autowired - ResourceDao serviceGroupDao; + + @Before + public void prepareDatabase() { + testUtilsDao.clearData(); + } @Rule public ExpectedException expectedEx = ExpectedException.none(); @@ -155,32 +158,23 @@ public class DomainDaoIntegrationTest extends AbstractBaseDao { } @Test - public void testValidateUsersForDeleteOKScenario() { + public void testValidateDeleteOKScenario() { // set DBDomain d = TestDBUtils.createDBDomain(); testInstance.persistFlushDetach(d); // execute - List<DBDomainDeleteValidation> lst = testInstance.validateDomainsForDelete(Collections.singletonList(d.getId())); - assertTrue(lst.isEmpty()); + Long cnt = testInstance.getResourceCountForDomain(d.getId()); + assertEquals(0, cnt.intValue()); } @Test - @Ignore - public void testValidateUsersForDeleteUserIsOwner() { + public void testValidateDeleteHasResources() { // set - DBDomain d = TestDBUtils.createDBDomain(); - testInstance.persistFlushDetach(d); - - DBResource sg = TestDBUtils.createDBResource(); - // sg.addDomain(d); + testUtilsDao.createSubresources(); + DBDomain d = testUtilsDao.getD1(); + Long cnt = testInstance.getResourceCountForDomain(d.getId()); - serviceGroupDao.persistFlushDetach(sg); - - // execute - List<DBDomainDeleteValidation> lst = testInstance.validateDomainsForDelete(Collections.singletonList(d.getId())); - assertEquals(1, lst.size()); - assertEquals(d.getDomainCode(), lst.get(0).getDomainCode()); - assertEquals(1, lst.get(0).getCount().intValue()); + assertEquals(1, cnt.intValue()); } } diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AbstractServiceTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AbstractServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b1ee76acc10da0765aa8fd8829341ae326375515 --- /dev/null +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/AbstractServiceTest.java @@ -0,0 +1,15 @@ +package eu.europa.ec.edelivery.smp.services; + +import eu.europa.ec.edelivery.smp.data.dao.AbstractBaseDao; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; + +@ContextConfiguration(classes = {AbstractServiceTest.DomiSMPServicesConfig.class}) +public abstract class AbstractServiceTest extends AbstractBaseDao { + @Configuration + @ComponentScan({"eu.europa.ec.edelivery.smp"}) + public static class DomiSMPServicesConfig { + + } +} diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainServiceIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainServiceIntegrationTest.java index 84e9273db8e66d994e342bb55974634edc3428f1..d9c36484fc49f9a3d77e0355f01e277f41112a9c 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainServiceIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainServiceIntegrationTest.java @@ -81,40 +81,5 @@ public class UIDomainServiceIntegrationTest extends AbstractServiceIntegrationTe assertNotNull(res.getServiceEntities().get(0).getSmlSubdomain()); } - @Test - public void validateDeleteRequest(){ - - DeleteEntityValidation dev= new DeleteEntityValidation(); - dev.getListIds().add("10"); - DeleteEntityValidation res = testInstance.validateDeleteRequest(dev); - assertEquals(true, res.isValidOperation()); - } - - @Test - public void validateDeleteRequestNotToDelete(){ - // given - DBDomain d = TestDBUtils.createDBDomain("domain"); - DBDomain d2 = TestDBUtils.createDBDomain("domain1"); - - domainDao.persistFlushDetach(d); - domainDao.persistFlushDetach(d2); - DBResource sg = TestDBUtils.createDBResource(); - // sg.addDomain(d); - serviceGroupDao.persistFlushDetach(sg); - - // when - DeleteEntityValidation dev= new DeleteEntityValidation(); - dev.getListIds().add(d.getId()+""); - dev.getListIds().add(d2.getId()+""); - - DeleteEntityValidation res = testInstance.validateDeleteRequest(dev); - - // then - assertEquals(false, res.isValidOperation()); - assertEquals(1, res.getListDeleteNotPermitedIds().size()); - assertEquals(d.getId()+"", res.getListDeleteNotPermitedIds().get(0)); - assertEquals("Could not delete domains used by Service groups! Domain: domain (domain ) uses by:1 SG.", res.getStringMessage()); - - } } diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainServiceTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9813f4592b3fec979bb9b74b03eb3ed6384d326f --- /dev/null +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIDomainServiceTest.java @@ -0,0 +1,112 @@ +package eu.europa.ec.edelivery.smp.services.ui; + +import eu.europa.ec.edelivery.smp.data.dao.DomainDao; +import eu.europa.ec.edelivery.smp.data.enums.VisibilityType; +import eu.europa.ec.edelivery.smp.data.model.DBDomain; +import eu.europa.ec.edelivery.smp.data.ui.DomainRO; +import eu.europa.ec.edelivery.smp.services.AbstractServiceTest; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.*; + +public class UIDomainServiceTest extends AbstractServiceTest { + + @Autowired + UIDomainService testInstance; + @Autowired + DomainDao domainDao; + + @Before + public void prepareDatabase() { + testUtilsDao.clearData(); + testUtilsDao.createResourceDefinitionsForDomains(); + } + + @Test + public void getAllDomains() { + List<DomainRO> domainROS = testInstance.getAllDomains(); + assertEquals(2, domainROS.size()); + } + + @Test + public void updateDomainData() { + + DomainRO domainRO = new DomainRO(); + domainRO.setDomainCode("NewCode"); + domainRO.setVisibility(VisibilityType.INTERNAL); + domainRO.setSignatureKeyAlias("NewAlias"); + domainRO.setDefaultResourceTypeIdentifier("New ID"); + DBDomain domain = testUtilsDao.getD1(); + testInstance.updateBasicDomainData(domain.getId(), domainRO); + DBDomain result = domainDao.find(domain.getId()); + + assertEquals(domainRO.getDomainCode(), result.getDomainCode()); + assertEquals(domainRO.getVisibility(), result.getVisibility()); + assertEquals(domainRO.getSignatureKeyAlias(), result.getSignatureKeyAlias()); + assertEquals(domainRO.getDefaultResourceTypeIdentifier(), result.getDefaultResourceTypeIdentifier()); + } + + @Test + public void updateSMLDomainData() { + + DomainRO domainRO = new DomainRO(); + domainRO.setSmlSubdomain("New SmlSubdomain"); + domainRO.setSmlSmpId("NewSmlSmpId"); + domainRO.setSmlClientKeyAlias("NewClientKeyAlias"); + domainRO.setSmlClientCertHeader("NewtCertHeader"); + domainRO.setSmlClientCertAuth(false); + DBDomain domain = testUtilsDao.getD1(); + testInstance.updateDomainSmlIntegrationData(domain.getId(), domainRO); + DBDomain result = domainDao.find(domain.getId()); + + assertEquals(domainRO.getSmlSubdomain(), result.getSmlSubdomain()); + assertEquals(domainRO.getSmlSmpId(), result.getSmlSmpId()); + assertEquals(domainRO.getSmlClientKeyAlias(), result.getSmlClientKeyAlias()); + assertEquals(domainRO.getSmlClientCertHeader(), result.getSmlClientCertHeader()); + assertEquals(domainRO.isSmlClientCertAuth(), result.isSmlClientCertAuth()); + } + + @Test + public void updateDomainResourceListClear() { + DBDomain testDomain = testUtilsDao.getD1(); + DomainRO domainRO = testInstance.getDomainData(testDomain.getId()); + assertFalse(domainRO.getResourceDefinitions().isEmpty()); + testInstance.updateResourceDefDomainList(testDomain.getId(), Collections.emptyList()); + + DomainRO result = testInstance.getDomainData(testDomain.getId()); + assertTrue(result.getResourceDefinitions().isEmpty()); + } + + @Test + public void updateDomainResourceListAddNew() { + DBDomain testDomain = testUtilsDao.getD2(); + DomainRO domainRO = testInstance.getDomainData(testDomain.getId()); + String restDef2 = testUtilsDao.getResourceDefCpp().getIdentifier(); + + List<String> existingList = domainRO.getResourceDefinitions(); + assertFalse(existingList.contains(restDef2)); + existingList.add(restDef2); + testInstance.updateResourceDefDomainList(testDomain.getId(), existingList); + + DomainRO result = testInstance.getDomainData(testDomain.getId()); + assertTrue(result.getResourceDefinitions().contains(restDef2)); + } + + @Test + public void deleteDomain() { + DBDomain domain = testUtilsDao.getD1(); + DBDomain test = domainDao.find(domain.getId()); + assertNotNull(test); + testInstance.deleteDomain(domain.getId()); + + DBDomain result = domainDao.find(domain.getId()); + assertNull(result); + } + + +} diff --git a/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql b/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql index 1bbf75e83a333089662f6e356b1081c78b89ea88..7f56ba1ad0a13afcc2db0b5dd43ab99dff4b65ea 100644 --- a/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql +++ b/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql @@ -37,7 +37,9 @@ insert into SMP_CERTIFICATE (ID, CERTIFICATE_ID, SUBJECT, ISSUER, SERIALNUMBER,V insert into SMP_DOMAIN (ID, DOMAIN_CODE, VISIBILITY, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, SML_CLIENT_CERT_AUTH,SML_REGISTERED, CREATED_ON, LAST_UPDATED_ON) values -(1, 'testdomain','PUBLIC', 'test-domain', 'CEF-SMP-002','sample_key',1,0, NOW(), NOW()); +(1, 'testdomain','PUBLIC', 'test-domain', 'CEF-SMP-002','sample_key',1,0, NOW(), NOW()), +(2, 'testdomain1','PUBLIC', 'test-domain1', 'CEF-SMP-003','sample_key',1,0, NOW(), NOW()), +(3, 'testdomain2','PUBLIC', 'test-domain2', 'CEF-SMP-004','sample_key',1,0, NOW(), NOW()); insert into SMP_EXTENSION ( ID, IDENTIFIER, IMPLEMENTATION_NAME, NAME, VERSION, DESCRIPTION, CREATED_ON, LAST_UPDATED_ON) values (1, 'edelivery-oasis-smp-extension', 'OasisSMPExtension','Oasis SMP 1.0 and 2.0','1.0', 'Oasis SMP 1.0 and 2.0 extension', NOW(), NOW()); diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/error/AbstractErrorControllerAdvice.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/error/AbstractErrorControllerAdvice.java index 9ed316716e90a752e44b4167e1f2dd5508c4fe0a..b0599a87ea324044aa72e91547ed86111310f65b 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/error/AbstractErrorControllerAdvice.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/error/AbstractErrorControllerAdvice.java @@ -3,6 +3,7 @@ package eu.europa.ec.edelivery.smp.error; import ec.services.smp._1.ErrorResponse; import eu.europa.ec.edelivery.smp.data.ui.exceptions.ErrorResponseRO; import eu.europa.ec.edelivery.smp.error.exceptions.SMPResponseStatusException; +import eu.europa.ec.edelivery.smp.exceptions.BadRequestException; import eu.europa.ec.edelivery.smp.exceptions.ErrorBusinessCode; import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException; import org.slf4j.Logger; @@ -13,8 +14,7 @@ import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.AuthenticationException; import static eu.europa.ec.edelivery.smp.exceptions.ErrorBusinessCode.TECHNICAL; -import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; -import static org.springframework.http.HttpStatus.UNAUTHORIZED; +import static org.springframework.http.HttpStatus.*; abstract class AbstractErrorControllerAdvice { @@ -34,11 +34,15 @@ abstract class AbstractErrorControllerAdvice { }else if (runtimeException instanceof AccessDeniedException){ AccessDeniedException ex = (AccessDeniedException)runtimeException; response = buildAndLog(UNAUTHORIZED, ErrorBusinessCode.UNAUTHORIZED, ex.getMessage(), ex); + }else if (runtimeException instanceof BadRequestException){ + BadRequestException ex = (BadRequestException)runtimeException; + response = buildAndLog(UNPROCESSABLE_ENTITY, ex.getErrorBusinessCode(), ex.getMessage(), ex); } else { response = buildAndLog(INTERNAL_SERVER_ERROR, TECHNICAL, "Unexpected technical error occurred.", runtimeException); } - String errorCodeId = response.getBody() instanceof ErrorResponseRO?((ErrorResponseRO) response.getBody()).getErrorUniqueId():((ErrorResponse) response.getBody()).getErrorUniqueId(); + String errorCodeId = response.getBody() instanceof ErrorResponseRO? + ((ErrorResponseRO) response.getBody()).getErrorUniqueId():((ErrorResponse) response.getBody()).getErrorUniqueId(); LOG.error("Unhandled exception occurred, unique ID: [{}]", errorCodeId, runtimeException); return response; } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/error/UIErrorControllerAdvice.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/error/UIErrorControllerAdvice.java index 20a4fc75c85e49e92f48331f4d3ff39979ad35dc..65b28c447602a996b173e2bf9d87cd423f27b861 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/error/UIErrorControllerAdvice.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/error/UIErrorControllerAdvice.java @@ -15,6 +15,7 @@ package eu.europa.ec.edelivery.smp.error; import eu.europa.ec.edelivery.smp.data.ui.exceptions.ErrorResponseRO; import eu.europa.ec.edelivery.smp.error.exceptions.SMPResponseStatusException; +import eu.europa.ec.edelivery.smp.exceptions.BadRequestException; import eu.europa.ec.edelivery.smp.exceptions.ErrorBusinessCode; import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException; import org.springframework.http.HttpStatus; @@ -34,12 +35,16 @@ import static java.lang.String.format; * @author Joze Rihtarsic * @since 4.2 */ -@RestControllerAdvice("eu.europa.ec.edelivery.smp.ui.external") +@RestControllerAdvice({"eu.europa.ec.edelivery.smp.ui"}) public class UIErrorControllerAdvice extends AbstractErrorControllerAdvice { - @Override - @ExceptionHandler({BadCredentialsException.class, RuntimeException.class, SMPRuntimeException.class, SMPResponseStatusException.class, AuthenticationException.class,}) + @ExceptionHandler({BadCredentialsException.class, + RuntimeException.class, + SMPRuntimeException.class, + SMPResponseStatusException.class, + AuthenticationException.class, + BadRequestException.class}) public ResponseEntity handleRuntimeException(RuntimeException ex) { return super.handleRuntimeException(ex); } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResource.java index 8b4c9f8eb3b14475fb6950e90f5ecfadce5100ae..f023208609ed721b98a02a475dbf2fca6fe9f099 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResource.java @@ -2,23 +2,18 @@ package eu.europa.ec.edelivery.smp.ui.internal; import eu.europa.ec.edelivery.smp.data.model.DBDomain; -import eu.europa.ec.edelivery.smp.data.ui.DeleteEntityValidation; -import eu.europa.ec.edelivery.smp.data.ui.DomainRO; -import eu.europa.ec.edelivery.smp.data.ui.SMLIntegrationResult; -import eu.europa.ec.edelivery.smp.data.ui.ServiceResult; -import eu.europa.ec.edelivery.smp.data.ui.auth.SMPAuthority; +import eu.europa.ec.edelivery.smp.data.ui.*; +import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus; import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.services.DomainService; import eu.europa.ec.edelivery.smp.services.ui.UIDomainService; import eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils; -import org.springframework.security.access.annotation.Secured; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.MimeTypeUtils; import org.springframework.web.bind.annotation.*; -import java.util.Arrays; import java.util.List; import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.*; @@ -46,18 +41,6 @@ public class DomainAdminResource { } - @GetMapping(produces = {MimeTypeUtils.APPLICATION_JSON_VALUE}) - public ServiceResult<DomainRO> geDomainList( - @RequestParam(value = PARAM_PAGINATION_PAGE, defaultValue = "0") int page, - @RequestParam(value = PARAM_PAGINATION_PAGE_SIZE, defaultValue = "10") int pageSize, - @RequestParam(value = PARAM_PAGINATION_ORDER_BY, required = false) String orderBy, - @RequestParam(value = PARAM_PAGINATION_ORDER_TYPE, defaultValue = "asc", required = false) String orderType, - @RequestParam(value = PARAM_QUERY_USER, required = false) String user) { - - LOG.info("Search for page: {}, page size: {}, user: {}", page, pageSize, user); - return uiDomainService.getTableList(page, pageSize, orderBy, orderType, null); - } - @GetMapping(path = "/{user-enc-id}", produces = MimeTypeUtils.APPLICATION_JSON_VALUE) @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and @smpAuthorizationService.isSystemAdministrator") public List<DomainRO> getAllDomainList(@PathVariable("user-enc-id") String userEncId) { @@ -65,33 +48,73 @@ public class DomainAdminResource { return uiDomainService.getAllDomains(); } - /** - * List of domains to be added or updated - * - * @param updateEntities - */ - @PutMapping(produces = MimeTypeUtils.APPLICATION_JSON_VALUE, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE) - @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN}) - public void updateDomainList(@RequestBody DomainRO[] updateEntities) { - uiDomainService.updateDomainList(Arrays.asList(updateEntities)); + @DeleteMapping(path = "/{user-enc-id}/{domain-enc-id}/delete", produces = MimeTypeUtils.APPLICATION_JSON_VALUE) + @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and @smpAuthorizationService.isSystemAdministrator") + public DomainRO deleteDomain(@PathVariable("user-enc-id") String userEncId, + @PathVariable("domain-enc-id") String domainEncId) { + logAdminAccess("deleteDomain:" + domainEncId); + Long domainId = SessionSecurityUtils.decryptEntityId(domainEncId); + LOG.info("Delete domain with id [{}]", domainId); + + return uiDomainService.deleteDomain(domainId); } + @PutMapping(path = "/{user-enc-id}/create", produces = MimeTypeUtils.APPLICATION_JSON_VALUE, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE) + @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and @smpAuthorizationService.isSystemAdministrator") + public DomainRO createBasicDomainData(@PathVariable("user-enc-id") String userEncId, + @RequestBody DomainRO domainData) { + logAdminAccess("createBasicDomainData" ); - /** - * Validated if domains with provided IDs can be deleted and returns the result in DeleteEntityValidation. - * - * @param listOfDomainIds - * @return - */ + uiDomainService.createDomainData(domainData); - @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN}) - @PutMapping(value = "validate-delete", produces = MimeTypeUtils.APPLICATION_JSON_VALUE) - public DeleteEntityValidation validateDeleteDomain(@RequestBody List<String> listOfDomainIds) { + DomainRO domainRO = uiDomainService.getDomainDataByDomainCode(domainData.getDomainCode()); + domainRO.setStatus(EntityROStatus.NEW.getStatusNumber()); + return domainRO; + } + @PostMapping(path = "/{user-enc-id}/{domain-enc-id}/update", produces = MimeTypeUtils.APPLICATION_JSON_VALUE, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE) + @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and @smpAuthorizationService.isSystemAdministrator") + public DomainRO updateBasicDomainData(@PathVariable("user-enc-id") String userEncId, + @PathVariable("domain-enc-id") String domainEncId, + @RequestBody DomainRO domainData) { + logAdminAccess("updateBasicDomainData:" + domainEncId); + Long domainId = SessionSecurityUtils.decryptEntityId(domainEncId); + LOG.info("Update basic domain with id [{}]", domainId); + uiDomainService.updateBasicDomainData(domainId, domainData); + + DomainRO domainRO = uiDomainService.getDomainData(domainId); + domainRO.setStatus(EntityROStatus.UPDATED.getStatusNumber()); + return domainRO; + } - DeleteEntityValidation dres = new DeleteEntityValidation(); - dres.getListIds().addAll(listOfDomainIds); - return uiDomainService.validateDeleteRequest(dres); + @PostMapping(path = "/{user-enc-id}/{domain-enc-id}/update-resource-types", produces = MimeTypeUtils.APPLICATION_JSON_VALUE, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE) + @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and @smpAuthorizationService.isSystemAdministrator") + public DomainRO updateResourceDefDomainList(@PathVariable("user-enc-id") String userEncId, + @PathVariable("domain-enc-id") String domainEncId, + @RequestBody List<String> resourceDefs) { + logAdminAccess("updateResourceDefDomainList:" + domainEncId); + Long domainId = SessionSecurityUtils.decryptEntityId(domainEncId); + LOG.info("Update basic domain with id [{}]", domainId); + uiDomainService.updateResourceDefDomainList(domainId, resourceDefs); + DomainRO domainRO = uiDomainService.getDomainData(domainId); + domainRO.setStatus(EntityROStatus.UPDATED.getStatusNumber()); + return domainRO; } + @PostMapping(path = "/{user-enc-id}/{domain-enc-id}/update-sml-integration-data", produces = MimeTypeUtils.APPLICATION_JSON_VALUE, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE) + @PreAuthorize("@smpAuthorizationService.isCurrentlyLoggedIn(#userEncId) and @smpAuthorizationService.isSystemAdministrator") + public DomainRO updateSmlIntegrationData(@PathVariable("user-enc-id") String userEncId, + @PathVariable("domain-enc-id") String domainEncId, + @RequestBody DomainRO domainData) { + logAdminAccess("updateSmlIntegrationData:" + domainEncId); + Long domainId = SessionSecurityUtils.decryptEntityId(domainEncId); + LOG.info("Update domain integration data for id [{}]", domainId); + uiDomainService.updateDomainSmlIntegrationData(domainId, domainData); + DomainRO domainRO = uiDomainService.getDomainData(domainId); + domainRO.setStatus(EntityROStatus.UPDATED.getStatusNumber()); + return domainRO; + } + + + @PreAuthorize("@smpAuthorizationService.systemAdministrator || @smpAuthorizationService.isCurrentlyLoggedIn(#userId)") @PutMapping(value = "/{user-id}/sml-register/{domain-code}") public SMLIntegrationResult registerDomainAndParticipants(@PathVariable("user-id") String userId, diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/test/testutils/MockMvcUtils.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/test/testutils/MockMvcUtils.java index 420820e8da359f93315f8b564f73ff1d8d799815..9c911b2aafbc2ca7c71e69933740bd66fdd9840e 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/test/testutils/MockMvcUtils.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/test/testutils/MockMvcUtils.java @@ -1,7 +1,9 @@ package eu.europa.ec.edelivery.smp.test.testutils; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.databind.type.CollectionType; import eu.europa.ec.edelivery.smp.data.ui.UserRO; import org.springframework.http.HttpHeaders; import org.springframework.mock.web.MockHttpSession; @@ -16,6 +18,8 @@ import org.springframework.web.context.WebApplicationContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; +import java.io.UnsupportedEncodingException; +import java.util.List; import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.CONTEXT_PATH_PUBLIC_SECURITY; import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.CONTEXT_PATH_PUBLIC_SECURITY_AUTHENTICATION; @@ -136,4 +140,16 @@ public class MockMvcUtils { return mvc; } + public static <T> List<T> parseResponseArray(MvcResult result, Class<T> clazz) throws UnsupportedEncodingException, JsonProcessingException { + CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(List.class, clazz); + return mapper.readValue(result.getResponse().getContentAsString(), collectionType); + } + + public static <T> T parseResponse(MvcResult result, Class<T> clazz) throws UnsupportedEncodingException, JsonProcessingException { + return mapper.readValue(result.getResponse().getContentAsString(), clazz); + } + + public static String serializeObject(Object object) throws JsonProcessingException { + return mapper.writeValueAsString(object); + } } diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/DomainResourceIntegrationTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/DomainResourceIntegrationTest.java index dcd87e6dff3091ad8bf1046cd541d7a6f7572494..2df22e7604bdfdd39c717057f7663e53e2b6bbd9 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/DomainResourceIntegrationTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/external/DomainResourceIntegrationTest.java @@ -84,8 +84,8 @@ public class DomainResourceIntegrationTest { DomainRO sgro = mapper.convertValue(sgMap, DomainRO.class); assertNotNull(sgro.getDomainCode()); assertNotNull(sgro.getSmlSubdomain()); - // for public endpot all other data must be null! - assertNull(sgro.getId()); + // for public endpoint all other data must be null! + assertNull(sgro.getDomainId()); assertNull(sgro.getSmlSmpId()); assertNull(sgro.getSignatureKeyAlias()); }); diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResourceIntegrationTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResourceIntegrationTest.java index d2d85719ea03b3b347e7d1ce8adbfdca14781de1..43c7fc0d2698e58a45c1c37cdf94d5f1c756024f 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResourceIntegrationTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/internal/DomainAdminResourceIntegrationTest.java @@ -2,10 +2,15 @@ package eu.europa.ec.edelivery.smp.ui.internal; import com.fasterxml.jackson.databind.ObjectMapper; import eu.europa.ec.edelivery.smp.data.dao.DomainDao; +import eu.europa.ec.edelivery.smp.data.model.DBDomain; import eu.europa.ec.edelivery.smp.data.ui.DeleteEntityValidation; +import eu.europa.ec.edelivery.smp.data.ui.DomainRO; +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.test.SmpTestWebAppConfig; import eu.europa.ec.edelivery.smp.test.testutils.MockMvcUtils; import eu.europa.ec.edelivery.smp.ui.ResourceConstants; +import org.apache.commons.lang3.StringUtils; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -20,12 +25,14 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.web.context.WebApplicationContext; -import static eu.europa.ec.edelivery.smp.test.testutils.MockMvcUtils.loginWithSystemAdmin; +import java.util.List; + +import static eu.europa.ec.edelivery.smp.test.testutils.MockMvcUtils.*; import static org.hamcrest.Matchers.stringContainsInOrder; import static org.junit.Assert.*; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_METHOD; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -54,31 +61,121 @@ public class DomainAdminResourceIntegrationTest { } @Test - public void updateDomainListOkDelete() throws Exception { -// given when - assertEquals("CEF-SMP-002", domainDao.getDomainByCode("domainTwo").get().getSmlSmpId()); + public void testGetAllDomains() throws Exception { + List<DBDomain> domain = domainDao.getAllDomains(); MockHttpSession session = loginWithSystemAdmin(mvc); - MvcResult result = mvc.perform(put(PATH) - .session(session) - .with(csrf()) - .header("Content-Type", " application/json") - .content("[{\"status\":3,\"index\":9,\"id\":2,\"domainCode\":\"domainTwo\",\"smlSubdomain\":\"newdomain\",\"smlSmpId\":\"CEF-SMP-010\",\"smlParticipantIdentifierRegExp\":null,\"smlClientCertHeader\":null,\"smlClientKeyAlias\":null,\"signatureKeyAlias\":\"sig-key\",\"smlClientCertAuth\":true,\"smlRegistered\":false}]")) // delete domain with id 2 + UserRO userRO = MockMvcUtils.getLoggedUserData(mvc, session); + + MvcResult result = mvc.perform(get(PATH + "/" + userRO.getUserId()) + .session(session) + .with(csrf()) + .header("Content-Type", " application/json")) .andExpect(status().isOk()).andReturn(); - // check if exists - assertFalse(domainDao.getDomainByCode("domainTwo").isPresent()); + List<DomainRO> response = parseResponseArray(result, DomainRO.class); + assertEquals(domain.size(), response.size()); + } + + @Test + public void testDeleteDomainOK() throws Exception { + // given - delete domain two :) + String domainCode = "domainTwo"; + MockHttpSession session = loginWithSystemAdmin(mvc); + UserRO userRO = MockMvcUtils.getLoggedUserData(mvc, session); + DomainRO domainToDelete = getDomain(domainCode, userRO, session); + assertNotNull(domainToDelete); + + MvcResult result = mvc.perform(delete(PATH + "/" + userRO.getUserId() + "/" + domainToDelete.getDomainId() + "" + "/delete") + .session(session) + .with(csrf()) + .header("Content-Type", " application/json")) // delete domain with id 2 + .andExpect(status().isOk()).andReturn(); + DomainRO resultObject = parseResponse(result, DomainRO.class); + // + assertNotNull(resultObject); + assertEquals(domainCode, resultObject.getDomainCode()); + assertEquals(EntityROStatus.REMOVE.getStatusNumber(), resultObject.getStatus()); + } + + @Test + public void updateDomainData() throws Exception { + String domainCode = "domainTwo"; + MockHttpSession session = loginWithSystemAdmin(mvc); + UserRO userRO = MockMvcUtils.getLoggedUserData(mvc, session); + DomainRO domainToUpdate = getDomain(domainCode, userRO, session); + domainToUpdate.setDomainCode("NewCode"); + domainToUpdate.setSignatureKeyAlias("New alias"); + + MvcResult result = mvc.perform(post(PATH + "/" + userRO.getUserId() + "/" + domainToUpdate.getDomainId() + "" + "/update") + .session(session) + .with(csrf()) + .header("Content-Type", " application/json") + .content(entitiToString(domainToUpdate))) + .andExpect(status().isOk()).andReturn(); + DomainRO resultObject = parseResponse(result, DomainRO.class); + // + assertNotNull(resultObject); + assertEquals(domainToUpdate.getDomainCode(), resultObject.getDomainCode()); + assertEquals(EntityROStatus.UPDATED.getStatusNumber(), resultObject.getStatus()); + } + @Test + public void updateDomainSmlIntegrationData() throws Exception { + String domainCode = "domainTwo"; + MockHttpSession session = loginWithSystemAdmin(mvc); + UserRO userRO = MockMvcUtils.getLoggedUserData(mvc, session); + DomainRO domainToUpdate = getDomain(domainCode, userRO, session); + domainToUpdate.setSmlSubdomain("NewCode"); + domainToUpdate.setSmlClientKeyAlias("New alias"); + + MvcResult result = mvc.perform(post(PATH + "/" + userRO.getUserId() + "/" + domainToUpdate.getDomainId() + "" + "/update-sml-integration-data") + .session(session) + .with(csrf()) + .header("Content-Type", " application/json") + .content(entitiToString(domainToUpdate))) + .andExpect(status().isOk()).andReturn(); + DomainRO resultObject = parseResponse(result, DomainRO.class); + // + assertNotNull(resultObject); + assertEquals(domainToUpdate.getDomainCode(), resultObject.getDomainCode()); + assertEquals(EntityROStatus.UPDATED.getStatusNumber(), resultObject.getStatus()); } + @Test + @Ignore + public void updateDomainDataAddNewResourceDef() throws Exception { + // set the webapp_integration_test_data.sql for resourceDefID + String resourceDefID = "edelivery-oasis-cppa"; + String domainCode = "domainTwo"; + MockHttpSession session = loginWithSystemAdmin(mvc); + UserRO userRO = MockMvcUtils.getLoggedUserData(mvc, session); + DomainRO domainToUpdate = getDomain(domainCode, userRO, session); + domainToUpdate.getResourceDefinitions().add(resourceDefID); + MvcResult result = mvc.perform(post(PATH + "/" + userRO.getUserId() + "/" + domainToUpdate.getDomainId() + "" + "/update-resource-types") + .session(session) + .with(csrf()) + .header("Content-Type", " application/json") + .content(entitiToString(domainToUpdate.getResourceDefinitions()))) + .andExpect(status().isOk()).andReturn(); + DomainRO resultObject = parseResponse(result, DomainRO.class); + // + assertNotNull(resultObject); + assertEquals(domainToUpdate.getDomainCode(), resultObject.getDomainCode()); + assertEquals(EntityROStatus.UPDATED.getStatusNumber(), resultObject.getStatus()); + } + +/* @Test public void updateDomainListNotExists() throws Exception { // given when MockHttpSession session = loginWithSystemAdmin(mvc); + + MvcResult result = mvc.perform(put(PATH) - .session(session) - .with(csrf()) - .header("Content-Type", " application/json") - .content("[{\"status\":3,\"index\":9,\"id\":10,\"domainCode\":\"domainTwoNotExist\",\"smlSubdomain\":\"newdomain\",\"smlSmpId\":\"CEF-SMP-010\",\"smlParticipantIdentifierRegExp\":null,\"smlClientCertHeader\":null,\"smlClientKeyAlias\":null,\"signatureKeyAlias\":\"sig-key\",\"smlClientCertAuth\":true,\"smlRegistered\":false}]")) // delete domain with id 2 + .session(session) + .with(csrf()) + .header("Content-Type", " application/json") + .content("[{\"status\":3,\"index\":9,\"id\":10,\"domainCode\":\"domainTwoNotExist\",\"smlSubdomain\":\"newdomain\",\"smlSmpId\":\"CEF-SMP-010\",\"smlParticipantIdentifierRegExp\":null,\"smlClientCertHeader\":null,\"smlClientKeyAlias\":null,\"signatureKeyAlias\":\"sig-key\",\"smlClientCertAuth\":true,\"smlRegistered\":false}]")) // delete domain with id 2 .andExpect(status().isOk()).andReturn(); } @@ -87,10 +184,10 @@ public class DomainAdminResourceIntegrationTest { // given when MockHttpSession session = loginWithSystemAdmin(mvc); MvcResult result = mvc.perform(put(PATH + "/validate-delete") - .session(session) - .with(csrf()) - .header("Content-Type", " application/json") - .content("[2]")) // delete domain with id 2 + .session(session) + .with(csrf()) + .header("Content-Type", " application/json") + .content("[2]")) // delete domain with id 2 .andExpect(status().isOk()).andReturn(); //them @@ -110,10 +207,10 @@ public class DomainAdminResourceIntegrationTest { assertEquals("CEF-SMP-002", domainDao.getDomainByCode("domainTwo").get().getSmlSmpId()); MockHttpSession session = loginWithSystemAdmin(mvc); MvcResult result = mvc.perform(put(PATH) - .session(session) - .with(csrf()) - .header("Content-Type", " application/json") - .content("[{\"status\":1,\"index\":9,\"id\":2,\"domainCode\":\"domainTwo\",\"smlSubdomain\":\"newdomain\",\"smlSmpId\":\"CEF-SMP-010\",\"smlParticipantIdentifierRegExp\":null,\"smlClientCertHeader\":null,\"smlClientKeyAlias\":null,\"signatureKeyAlias\":\"sig-key\",\"smlClientCertAuth\":true,\"smlRegistered\":false}]")) // delete domain with id 2 + .session(session) + .with(csrf()) + .header("Content-Type", " application/json") + .content("[{\"status\":1,\"index\":9,\"id\":2,\"domainCode\":\"domainTwo\",\"smlSubdomain\":\"newdomain\",\"smlSmpId\":\"CEF-SMP-010\",\"smlParticipantIdentifierRegExp\":null,\"smlClientCertHeader\":null,\"smlClientKeyAlias\":null,\"signatureKeyAlias\":\"sig-key\",\"smlClientCertAuth\":true,\"smlRegistered\":false}]")) // delete domain with id 2 .andExpect(status().isOk()).andReturn(); // check if exists @@ -125,10 +222,10 @@ public class DomainAdminResourceIntegrationTest { // given when MockHttpSession session = loginWithSystemAdmin(mvc); MvcResult result = mvc.perform(put(PATH + "/validate-delete") - .session(session) - .with(csrf()) - .header("Content-Type", " application/json") - .content("[1]")) // delete domain with id 2 + .session(session) + .with(csrf()) + .header("Content-Type", " application/json") + .content("[1]")) // delete domain with id 2 .andExpect(status().isOk()).andReturn(); //them @@ -149,25 +246,50 @@ public class DomainAdminResourceIntegrationTest { // domainTwo - domain code MockHttpSession session = loginWithSystemAdmin(mvc); mvc.perform(put(PATH + "/3/sml-register/domainTwo") - .session(session) - .with(csrf()) - .header("Content-Type", " application/json")) + .session(session) + .with(csrf()) + .header("Content-Type", " application/json")) .andExpect(status().isOk()) .andExpect(content().string(stringContainsInOrder("Configuration error: [SML integration is not enabled!]!"))); } @Test - @Ignore public void unregisterDomainAndParticipants() throws Exception { // given when // 3- user id // domainTwo - domain code MockHttpSession session = loginWithSystemAdmin(mvc); mvc.perform(put(PATH + "/3/sml-unregister/domainTwo") - .session(session) - .with(csrf()) - .header("Content-Type", " application/json")) + .session(session) + .with(csrf()) + .header("Content-Type", " application/json")) .andExpect(status().isOk()) .andExpect(content().string(stringContainsInOrder("Configuration error: SML integration is not enabled!!"))); } +*/ + + private List<DomainRO> getAllDomains(UserRO userRO, MockHttpSession session) throws Exception { + MvcResult result = mvc.perform(get(PATH + "/" + userRO.getUserId()) + .session(session) + .with(csrf()) + .header("Content-Type", " application/json")) + .andExpect(status().isOk()).andReturn(); + return parseResponseArray(result, DomainRO.class); + } + + private DomainRO getDomain(String domainCode, UserRO userRO, MockHttpSession session) throws Exception { + List<DomainRO> allDomains = getAllDomains(userRO, session); + + return allDomains.stream() + .filter(domainRO -> StringUtils.equals(domainCode, domainRO.getDomainCode())) + .findFirst().orElse(null); + + } + + private String entitiToString(Object object ) throws Exception { + return serializeObject(object); + + + } + } diff --git a/smp-webapp/src/test/resources/webapp_integration_test_data.sql b/smp-webapp/src/test/resources/webapp_integration_test_data.sql index f8604ad490c1a722d5c7853c3013c62c7010631e..5adcfae389deed091116d647d148050fbedd71b5 100644 --- a/smp-webapp/src/test/resources/webapp_integration_test_data.sql +++ b/smp-webapp/src/test/resources/webapp_integration_test_data.sql @@ -107,7 +107,8 @@ insert into SMP_EXTENSION ( ID, IDENTIFIER, IMPLEMENTATION_NAME, NAME, VERSION, (1, 'edelivery-oasis-smp-extension', 'OasisSMPExtension','Oasis SMP 1.0 and 2.0','1.0', 'Oasis SMP 1.0 and 2.0 extension', NOW(), NOW()); insert into SMP_RESOURCE_DEF ( ID, FK_EXTENSION_ID, URL_SEGMENT, IDENTIFIER, DESCRIPTION, MIME_TYPE, NAME, CREATED_ON, LAST_UPDATED_ON) values -(1, 1, 'smp-1', 'edelivery-oasis-smp-1.0-servicegroup', 'Service group', 'application/xml','Oasis SMP ServiceGroup', NOW(), NOW()); +(1, 1, 'smp-1', 'edelivery-oasis-smp-1.0-servicegroup', 'Service group', 'application/xml','Oasis SMP ServiceGroup', NOW(), NOW()), +(2, 1, 'cpa-1', 'edelivery-oasis-cppa', 'Cppa document group', 'application/xml','Oasis SMP cpa document', NOW(), NOW()); insert into SMP_SUBRESOURCE_DEF (ID,FK_RESOURCE_DEF_ID,URL_SEGMENT, IDENTIFIER, DESCRIPTION, MIME_TYPE, NAME, CREATED_ON, LAST_UPDATED_ON) values (1,1, 'services', 'edelivery-oasis-smp-1.0-servicemetadata', 'ServiceMetadata', 'application/xml','Oasis SMP ServiceMetadata', NOW(), NOW()); -- register document types for domain