diff --git a/smp-angular/src/app/app.component.html b/smp-angular/src/app/app.component.html index 03084d47bb1436fb36a76059f62baa8e8581fbd5..07100d47197342ef692222c620df450c715e7449 100644 --- a/smp-angular/src/app/app.component.html +++ b/smp-angular/src/app/app.component.html @@ -9,21 +9,21 @@ </div> </div> - <button mat-raised-button class="sideNavButton" [routerLink]="['/']" id="search_id"> + <button mat-raised-button class="sideNavButton" [routerLink]="['/']" id="sidebar_search_id"> <mat-icon matTooltip="Search" matTooltipDisabled="{{fullMenu}}" matTooltipDisabled="right">search</mat-icon> <span>Search</span> </button> - <button mat-raised-button class="sideNavButton" *ngIf="isCurrentUserSMPAdmin() || isCurrentUserServiceGroupAdmin()" [routerLink]="['/edit']" id="edit_id"> + <button mat-raised-button class="sideNavButton" *ngIf="isCurrentUserSMPAdmin() || isCurrentUserServiceGroupAdmin()" [routerLink]="['/edit']" id="sidebar_edit_id"> <mat-icon matTooltip="Edit" matTooltipDisabled="{{fullMenu}}" matTooltipDisabled="right">edit</mat-icon> <span>Edit</span> </button> - <button mat-raised-button class="sideNavButton" [routerLink]="['/domain']" *ngIf="isCurrentUserSystemAdmin()" id="domain_id"> + <button mat-raised-button class="sideNavButton" [routerLink]="['/domain']" *ngIf="isCurrentUserSystemAdmin()" id="sidebar_domain_id"> <mat-icon matTooltip="Domain" matTooltipDisabled="{{fullMenu}}" matTooltipDisabled="right">domain</mat-icon> <span>Domain</span> </button> <!-- button mat-raised-button class="sideNavButton" [routerLink]="['/user']" *ngIf="hasAdmin()" id="user_id" --> - <button mat-raised-button class="sideNavButton" [routerLink]="['/user']" *ngIf="isCurrentUserSystemAdmin()" id="user_id"> + <button mat-raised-button class="sideNavButton" [routerLink]="['/user']" *ngIf="isCurrentUserSystemAdmin()" id="sidebar_user_id"> <mat-icon matTooltip="Users" matTooltipDisabled="{{fullMenu}}" matTooltipDisabled="right">people</mat-icon> <span>Users</span> </button> @@ -57,16 +57,16 @@ </mat-sidenav> <!-- primary content --> - <div id=".my-content" style="position:absolute; bottom:5px; top:5px; right: 5px; left: 5px"> + <div fxLayout="column" id=".my-content" style="position:absolute; bottom:5px; top:5px; right: 5px; left: 5px"> + <alert style=" left:220px; top:0;right:0;z-index: 500"></alert> - - <div id="sandwichMenuHolder" style="z-index: 500"> + <div id="sandwichMenuHolder" style="z-index: 500"> <div id="sandwichMenu"> <a *ngIf="!currentUser" [routerLink]="['/login']" > Login </a> - <span *ngIf="currentUser" >User: {{currentUser}} </span > + <span *ngIf="currentUser" >{{getCurrentUserRoleDescription}}: {{currentUser}} </span > <button mat-icon-button [mat-menu-trigger-for]="settingsMenu" id="settingsmenu_id" matTooltip="Menu"> <mat-icon>menu</mat-icon> @@ -100,8 +100,8 @@ </mat-menu> </div> </div> - <alert style="position:fixed; left:220px; top:0;right:0;z-index: 500"></alert> - <div id="routerHolder" style="min-height: 100%" > + + <div fxFill="100" id="routerHolder" style="min-height: 100%" > <router-outlet></router-outlet> </div> diff --git a/smp-angular/src/app/app.component.ts b/smp-angular/src/app/app.component.ts index 2c2f1eb1a85f7ffc347bd9d76a6b2e3010e88cf0..13e5676e385ed45bc840e232d5f055070daa4c63 100644 --- a/smp-angular/src/app/app.component.ts +++ b/smp-angular/src/app/app.component.ts @@ -70,6 +70,19 @@ export class AppComponent implements OnInit { return user ? user.username : ""; } + + get getCurrentUserRoleDescription(): string { + if (this.securityService.isCurrentUserSystemAdmin()){ + return "System administrator"; + } else if (this.securityService.isCurrentUserSMPAdmin()){ + return "SMP administrator"; + } else if (this.securityService.isCurrentUserServiceGroupAdmin()){ + return "Service group administrator" + } + return ""; + } + + logout(event: Event): void { event.preventDefault(); this.router.navigate(['/search']).then((ok) => { diff --git a/smp-angular/src/app/app.routes.ts b/smp-angular/src/app/app.routes.ts index a1eaebe8bc3bfff2fc376068602cc6941e08fddb..0e81c975ffceaa96c2aed5e6334ba3ac6da89ae8 100644 --- a/smp-angular/src/app/app.routes.ts +++ b/smp-angular/src/app/app.routes.ts @@ -13,7 +13,7 @@ const appRoutes: Routes = [ {path: 'search', redirectTo: ''}, {path: 'edit', component: ServiceGroupEditComponent, canActivate: [AuthenticatedGuard], canDeactivate: [DirtyGuard]}, {path: 'domain', component: DomainComponent, canActivate: [AuthenticatedGuard], canDeactivate: [DirtyGuard]}, - {path: 'user', component: UserComponent, canActivate: [AuthenticatedGuard], canDeactivate: [DirtyGuard]}, + {path: 'user', component: UserComponent, canDeactivate: [DirtyGuard]}, {path: 'login', component: LoginComponent}, {path: '**', redirectTo: ''} ]; diff --git a/smp-angular/src/app/common/global-lookups.ts b/smp-angular/src/app/common/global-lookups.ts index 413139126d0a90228ba7f39d09eb3e01190ece8d..1d8fa0d6255689f92eaa88b02d942d9c36c7031e 100644 --- a/smp-angular/src/app/common/global-lookups.ts +++ b/smp-angular/src/app/common/global-lookups.ts @@ -1,10 +1,11 @@ import {Injectable, OnInit} from '@angular/core'; -import {HttpClient} from "@angular/common/http"; +import {HttpClient, HttpParams} from "@angular/common/http"; import {DomainRo} from "../domain/domain-ro.model"; import {SearchTableResult} from "./search-table/search-table-result.model"; import {SmpConstants} from "../smp.constants"; import {Observable} from "rxjs/internal/Observable"; import {UserRo} from "../user/user-ro.model"; +import {SecurityService} from "../security/security.service"; /** * Purpose of object is to fetch lookups as domains and users @@ -19,7 +20,7 @@ export class GlobalLookups implements OnInit { cachedUserList: Array<any> = []; - constructor(protected http: HttpClient){ + constructor(protected securityService: SecurityService, protected http: HttpClient){ this.refreshDomainLookup(); this.refreshUserLookup(); } @@ -28,8 +29,11 @@ export class GlobalLookups implements OnInit { } public refreshDomainLookup(){ + let params: HttpParams = new HttpParams() + .set('page', '-1') + .set('pageSize', '-1'); // init domains - this.domainObserver = this.http.get<SearchTableResult>(SmpConstants.REST_DOMAIN); + this.domainObserver = this.http.get<SearchTableResult>(SmpConstants.REST_DOMAIN,{params}); this.domainObserver.subscribe((domains: SearchTableResult) => { let gotList = new Array(domains.serviceEntities.length) .map((v, index) => domains.serviceEntities[index] as DomainRo); @@ -41,16 +45,22 @@ export class GlobalLookups implements OnInit { } public refreshUserLookup(){ - // init users - this.userObserver = this.http.get<SearchTableResult>(SmpConstants.REST_USER); - this.userObserver.subscribe((users: SearchTableResult) => { - let gotList = new Array(users.serviceEntities.length) - .map((v, index) => users.serviceEntities[index] as UserRo); - this.cachedUserList = users.serviceEntities.map(serviceEntity => { - return {...serviceEntity} + // call service if authenticated + if (this.securityService.isAuthenticated(false)) { + let params: HttpParams = new HttpParams() + .set('page', '-1') + .set('pageSize', '-1'); + // init users + this.userObserver = this.http.get<SearchTableResult>(SmpConstants.REST_USER, {params}); + this.userObserver.subscribe((users: SearchTableResult) => { + let gotList = new Array(users.serviceEntities.length) + .map((v, index) => users.serviceEntities[index] as UserRo); + this.cachedUserList = users.serviceEntities.map(serviceEntity => { + return {...serviceEntity} + }); }); - }); + } } diff --git a/smp-angular/src/app/common/search-table/search-table-controller.ts b/smp-angular/src/app/common/search-table/search-table-controller.ts index 9ccf73d49cacd4d672869323348bee5edabd6409..9eece017e263a64835fc3095bf05744180f9f012 100644 --- a/smp-angular/src/app/common/search-table/search-table-controller.ts +++ b/smp-angular/src/app/common/search-table/search-table-controller.ts @@ -4,6 +4,8 @@ import {SearchTableEntity} from './search-table-entity.model'; export interface SearchTableController { showDetails(row); edit(row); + + validateDeleteOperation(rows: Array<SearchTableEntity>); delete(row); newRow(): SearchTableEntity; newDialog(config?: MatDialogConfig): MatDialogRef<any>; diff --git a/smp-angular/src/app/common/search-table/search-table-validation-result.model.ts b/smp-angular/src/app/common/search-table/search-table-validation-result.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..62a345a91b035d1e577e35370e6b01f843e03e50 --- /dev/null +++ b/smp-angular/src/app/common/search-table/search-table-validation-result.model.ts @@ -0,0 +1,9 @@ +import {ɵstringify} from "@angular/core"; + +export interface SearchTableValidationResult{ + validOperation: boolean; + stringMessage?: string; + + listId?: Array<number>; + listDeleteNotPermitedId?: Array<number>; +} diff --git a/smp-angular/src/app/common/search-table/search-table.component.html b/smp-angular/src/app/common/search-table/search-table.component.html index 653e98ff143bbe8f4af643441092e292a6a595b1..a4ac6285658cd7d97808aa5ee39820551e69792c 100644 --- a/smp-angular/src/app/common/search-table/search-table.component.html +++ b/smp-angular/src/app/common/search-table/search-table.component.html @@ -1,4 +1,4 @@ -<div fxLayout="column" style="position: absolute; top: 5px; bottom: 5px; left: 5px; right: 5px;"> +<div fxLayout="column" fxFill="100" style=" top: 5px; bottom: 5px; left: 5px; right: 5px;"> <h1 flex id="{{id}}_header_id" style="margin: 0 !important;">{{title}}</h1> <div *ngIf="showSearchPanel" fxFlex="20" class="selectionCriteria"> <mat-card> @@ -77,7 +77,7 @@ (click)="editSearchTableEntityRow(row)" tooltip="Edit"> <mat-icon>edit</mat-icon> </button> - <button mat-icon-button color="primary" [disabled]="row.deleted || loading" + <button *ngIf="allowDeleteItems" mat-icon-button color="primary" [disabled]="row.deleted || loading" (click)="onDeleteRowActionClicked(row)" tooltip="Delete"> <mat-icon>delete</mat-icon> </button> @@ -107,7 +107,7 @@ <span>Save</span> </button> <!-- new button enabled --> - <button id="newButton" mat-raised-button (click)="onNewButtonClicked()" + <button *ngIf="allowNewItems" id="newButton" mat-raised-button (click)="onNewButtonClicked()" [disabled]="loading || !allowNewItems" color="primary"> <mat-icon>add</mat-icon> <span>New</span> @@ -117,8 +117,8 @@ <mat-icon>edit</mat-icon> <span>Edit</span> </button> - <button id="deleteButton" mat-raised-button (click)="onDeleteButtonClicked()" - [disabled]="!deleteButtonEnabled || loading" color="primary"> + <button *ngIf="allowDeleteItems" id="deleteButton" mat-raised-button (click)="onDeleteButtonClicked()" + [disabled]="!deleteButtonEnabled || loading || !allowDeleteItems" color="primary"> <mat-icon>delete</mat-icon> <span>Delete</span> </button> diff --git a/smp-angular/src/app/common/search-table/search-table.component.ts b/smp-angular/src/app/common/search-table/search-table.component.ts index 5403d18067c29e83ce4f6620472a8407e6742581..a0f858eae8ac7256f2b3c969ca46d09c76462996 100644 --- a/smp-angular/src/app/common/search-table/search-table.component.ts +++ b/smp-angular/src/app/common/search-table/search-table.component.ts @@ -14,7 +14,7 @@ import {SaveDialogComponent} from '../save-dialog/save-dialog.component'; import {DownloadService} from '../../download/download.service'; import {HttpClient, HttpParams} from '@angular/common/http'; import {ConfirmationDialogComponent} from "../confirmation-dialog/confirmation-dialog.component"; -import {SecurityService} from "../../security/security.service"; +import {SearchTableValidationResult} from "./search-table-validation-result.model"; @Component({ @@ -45,6 +45,8 @@ export class SearchTableComponent implements OnInit { @Input() showSearchPanel: boolean = true; @Input() showIndexColumn: boolean = false; @Input() allowNewItems: boolean = false; + @Input() allowDeleteItems: boolean = false; + loading = false; @@ -164,25 +166,35 @@ export class SearchTableComponent implements OnInit { } private pageInternal(offset: number, pageSize: number, orderBy: string, asc: boolean) { + + this.getTableDataEntries$(offset, pageSize, orderBy, asc).subscribe((result: SearchTableResult) => { - this.offset = offset; - this.rowLimiter.pageSize = pageSize; - this.orderBy = orderBy; - this.asc = asc; - - this.unselectRows(); - this.forceRefresh=false; - this.count = result.count; // must be set else table can not calculate page numbers - this.rows = result.serviceEntities.map(serviceEntity => { - return { - ...serviceEntity, - status: SearchTableEntityStatus.PERSISTED, - deleted: false - } - }); + + // empty page - probably refresh from delete...check if we can go one page back + // try again + if (result.count < 1 && offset > 0) { + this.pageInternal(offset--, pageSize, orderBy, asc) + } + else { + this.offset = offset; + this.rowLimiter.pageSize = pageSize; + this.orderBy = orderBy; + this.asc = asc; + this.unselectRows(); + this.forceRefresh = false; + this.count = result.count; // must be set else table can not calculate page numbers + this.rows = result.serviceEntities.map(serviceEntity => { + return { + ...serviceEntity, + status: SearchTableEntityStatus.PERSISTED, + deleted: false + } + }); + } }, (error: any) => { this.alertService.error("Error occurred:" + error); }); + } onPage(event) { @@ -317,7 +329,7 @@ export class SearchTableComponent implements OnInit { } get safeRefresh(): boolean { - return !(!this.submitButtonsEnabled || this.forceRefresh) ; + return !(!this.submitButtonsEnabled || this.forceRefresh); } private editSearchTableEntity(rowNumber: number) { @@ -352,23 +364,24 @@ export class SearchTableComponent implements OnInit { } private deleteSearchTableEntities(rows: Array<SearchTableEntity>) { - // TODO: add validation support to existing controllers - // if (this.searchTableController.validateDeleteOperation(rows)) { - // this.alertService.error('You cannot delete the logged in user: ' + this.securityService.getCurrentUser().username); - // return; - // } - - for (const row of rows) { - if (row.status === SearchTableEntityStatus.NEW) { - this.rows.splice(this.rows.indexOf(row), 1); + + this.searchTableController.validateDeleteOperation(rows).subscribe( (res: SearchTableValidationResult) => { + if (!res.validOperation) { + this.alertService.exception("Delete validation error", res.stringMessage, false); } else { - this.searchTableController.delete(row); - row.status = SearchTableEntityStatus.REMOVED; - row.deleted = true; + for (const row of rows) { + if (row.status === SearchTableEntityStatus.NEW) { + this.rows.splice(this.rows.indexOf(row), 1); + } else { + this.searchTableController.delete(row); + row.status = SearchTableEntityStatus.REMOVED; + row.deleted = true; + } + } + this.unselectRows(); } - } + }); - this.unselectRows() } private unselectRows() { @@ -384,7 +397,7 @@ export class SearchTableComponent implements OnInit { } - isDirty (): boolean { + isDirty(): boolean { return this.submitButtonsEnabled; } } diff --git a/smp-angular/src/app/domain/domain-controller.ts b/smp-angular/src/app/domain/domain-controller.ts index 6eb47da5f56ffc97ee327c5b99ee4335e9266512..34843c6ceb53c7233b79311255413b958fa89648 100644 --- a/smp-angular/src/app/domain/domain-controller.ts +++ b/smp-angular/src/app/domain/domain-controller.ts @@ -4,13 +4,19 @@ import {DomainDetailsDialogComponent} from './domain-details-dialog/domain-detai import {DomainRo} from './domain-ro.model'; import {SearchTableEntityStatus} from '../common/search-table/search-table-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"; +import {HttpClient} from "@angular/common/http"; export class DomainController implements SearchTableController { - constructor(protected lookups: GlobalLookups, public dialog: MatDialog) { + constructor(protected http: HttpClient, protected lookups: GlobalLookups, public dialog: MatDialog) { } public showDetails( row: any) { + let dialogRef: MatDialogRef<DomainDetailsDialogComponent> = this.dialog.open(DomainDetailsDialogComponent); dialogRef.afterClosed().subscribe(result => { //Todo: @@ -43,4 +49,16 @@ export class DomainController implements SearchTableController { public dataSaved() { this.lookups.refreshDomainLookup(); } + + validateDeleteOperation(rows: Array<SearchTableEntity>){ + var deleteRowIds = rows.map(rows => rows.id); + return this.http.post<SearchTableValidationResult>(SmpConstants.REST_DOMAIN_VALIDATE_DELETE, deleteRowIds); + } + + public newValidationResult(result: boolean, message: string): SearchTableValidationResult { + return { + validOperation: result, + stringMessage: '', + } + } } diff --git a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts index 611a900677398b590108fa3d8d182c41175e9b97..9c04e0d6138a8da74db013dfea8652b0e47520a0 100644 --- a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts +++ b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts @@ -54,7 +54,6 @@ export class DomainDetailsDialogComponent { }; this.domainForm = fb.group({ - 'domainCode': new FormControl({value: '', disabled: this.editMode}, [Validators.pattern(this.domainCodePattern), this.notInList(this.lookups.cachedDomainList.map(a => a.domainCode), this.current.domainCode)]), 'smlSubdomain': new FormControl({ diff --git a/smp-angular/src/app/domain/domain.component.html b/smp-angular/src/app/domain/domain.component.html index 0ee884f9dd034394be8a6e649391c2d80a07348d..6c74119981c88cefb2d101174b542de4ae5e1f36 100644 --- a/smp-angular/src/app/domain/domain.component.html +++ b/smp-angular/src/app/domain/domain.component.html @@ -10,6 +10,7 @@ [showSearchPanel]="false" [filter]="filter" [allowNewItems]="securityService.isCurrentUserSystemAdmin()" + [allowDeleteItems]="securityService.isCurrentUserSystemAdmin()" > <ng-template #additionalToolButtons > diff --git a/smp-angular/src/app/domain/domain.component.ts b/smp-angular/src/app/domain/domain.component.ts index 90125dc5b822aab895fa94099cd6a8edd9ed67e2..8518423dce86d26514b2fce098a77c9c895cb99c 100644 --- a/smp-angular/src/app/domain/domain.component.ts +++ b/smp-angular/src/app/domain/domain.component.ts @@ -36,7 +36,7 @@ export class DomainComponent implements OnInit { } ngOnInit() { - this.domainController = new DomainController(this.lookups, this.dialog); + this.domainController = new DomainController(this.http, this.lookups, this.dialog); this.columnPicker.allColumns = [ { 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 26ab7a1dcd19bbd08ecfbac273aaa7639df37042..c06b53371210d0e538d2b4a505449686dafa9337 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 @@ -281,7 +281,7 @@ export class ServiceGroupDetailsDialogComponent implements OnInit { if (!event.option.selected) { this.dialog.open(ConfirmationDialogComponent, { data: { - title: "Registred serviceMetadata on domain!", + title: "Registered serviceMetadata on domain!", description: "Unregistration of domain will also delete it's serviceMetadata. Do you want to continue?" } }).afterClosed().subscribe(result => { diff --git a/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts b/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts index 7c37c53c17cc47f8898b989110fba3075d4da0a1..cc104cd21b3b19ae6a88eabef357d59168b536cb 100644 --- a/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts +++ b/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts @@ -5,6 +5,9 @@ import {ServiceGroupEditRo} from './service-group-edit-ro.model'; import {SearchTableEntityStatus} from '../common/search-table/search-table-entity-status.model'; import {ServiceMetadataEditRo} from "./service-metadata-edit-ro.model"; import {ServiceGroupMetadataDialogComponent} from "./service-group-metadata-dialog/service-group-metadata-dialog.component"; +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"; export class ServiceGroupEditController implements SearchTableController { @@ -70,5 +73,15 @@ export class ServiceGroupEditController implements SearchTableController { } public dataSaved() {} + validateDeleteOperation(rows: Array<SearchTableEntity>){ + return of( this.newValidationResult(true, '') ); + } + + public newValidationResult(result: boolean, message: string): SearchTableValidationResult { + return { + validOperation: result, + stringMessage: message, + } + } } diff --git a/smp-angular/src/app/service-group-edit/service-group-edit.component.html b/smp-angular/src/app/service-group-edit/service-group-edit.component.html index c6a1c3f5952b8057c6d0672ef1ed5c3a6b8c01c8..7261ff60dc329ff97cebf79346a3844499c47086 100644 --- a/smp-angular/src/app/service-group-edit/service-group-edit.component.html +++ b/smp-angular/src/app/service-group-edit/service-group-edit.component.html @@ -10,6 +10,7 @@ [tableRowDetailContainer]="tableRowDetailContainer" [additionalRowActionButtons]="additionalRowActionButtons" [allowNewItems]="securityService.isCurrentUserSMPAdmin()" + [allowDeleteItems]="securityService.isCurrentUserSMPAdmin()" > <ng-template #rowMetadataAction let-row="row" let-value="value" ngx-datatable-cell-template> @@ -36,10 +37,9 @@ <input matInput placeholder="Participant scheme" name="patricipantScheme" [(ngModel)]="filter.participantScheme" #messageId="ngModel" id="participantScheme"> </mat-form-field> - <mat-select placeholder="Domain (sml subdomain)" [(ngModel)]="filter.domain" name="domain" + <mat-select placeholder="All Domains" [(ngModel)]="filter.domain" name="domain" id="domain_id"> - <mat-option [value]="''"> - </mat-option> + <mat-option [value]="''">All Domains</mat-option> <mat-option *ngFor="let domain of lookups.cachedDomainList" [value]="domain.domainCode"> {{domain.domainCode}} ({{domain.smlSubdomain}}) </mat-option> diff --git a/smp-angular/src/app/service-group-search/service-group-search-controller.ts b/smp-angular/src/app/service-group-search/service-group-search-controller.ts index 2432c65feea3ce49fdea13bcc6f05d58a9286e3c..532423d31fd23b8da17d8b37663ed3a1a9fed1be 100644 --- a/smp-angular/src/app/service-group-search/service-group-search-controller.ts +++ b/smp-angular/src/app/service-group-search/service-group-search-controller.ts @@ -1,6 +1,9 @@ import {SearchTableController} from '../common/search-table/search-table-controller'; import {MatDialog, MatDialogConfig} from '@angular/material'; import {ServiceGroupSearchRo} from './service-group-search-ro.model'; +import {of} from "rxjs/internal/observable/of"; +import {SearchTableValidationResult} from "../common/search-table/search-table-validation-result.model"; +import {SearchTableEntity} from "../common/search-table/search-table-entity.model"; export class ServiceGroupSearchController implements SearchTableController { @@ -25,4 +28,15 @@ export class ServiceGroupSearchController implements SearchTableController { } public dataSaved() {} + + validateDeleteOperation(rows: Array<SearchTableEntity>){ + return of( this.newValidationResult(true) ); + } + + public newValidationResult(result: boolean, message?: string): SearchTableValidationResult { + return { + validOperation: null, + stringMessage: message, + } + } } diff --git a/smp-angular/src/app/smp.constants.ts b/smp-angular/src/app/smp.constants.ts index b43f00990272fc932ebe02e0c6e65d2b05fc2a77..cdded6c53ba93102b76dec3f6ca96984696a77c9 100644 --- a/smp-angular/src/app/smp.constants.ts +++ b/smp-angular/src/app/smp.constants.ts @@ -11,9 +11,12 @@ export class SmpConstants { public static readonly REST_CERTIFICATE = `${SmpConstants.REST_USER}/certdata`; + public static readonly REST_USER_VALIDATE_DELETE = `${SmpConstants.REST_USER}/validateDelete`; + public static readonly REST_DOMAIN_VALIDATE_DELETE = `${SmpConstants.REST_DOMAIN}/validateDelete`; public static readonly REST_SERVICE_GROUP_EXTENSION = `${SmpConstants.REST_EDIT}/extension`; public static readonly REST_SERVICE_GROUP_EXTENSION_VALIDATE = `${SmpConstants.REST_SERVICE_GROUP_EXTENSION}/validate`; public static readonly REST_SERVICE_GROUP_EXTENSION_FORMAT = `${SmpConstants.REST_SERVICE_GROUP_EXTENSION}/format`; public static readonly REST_METADATA_VALIDATE = `${SmpConstants.REST_METADATA}/validate`; + } diff --git a/smp-angular/src/app/user/user-controller.ts b/smp-angular/src/app/user/user-controller.ts index e144f0682294b09f1f170771dbdf52743a62370e..05183dd42101b50b83a7ed8b7dc28528d0477fa8 100644 --- a/smp-angular/src/app/user/user-controller.ts +++ b/smp-angular/src/app/user/user-controller.ts @@ -3,10 +3,18 @@ import {MatDialog, MatDialogConfig, MatDialogRef} from '@angular/material'; import {UserDetailsDialogComponent} from './user-details-dialog/user-details-dialog.component'; import {UserRo} from './user-ro.model'; import {SearchTableEntityStatus} from '../common/search-table/search-table-entity-status.model'; +import {GlobalLookups} from "../common/global-lookups"; +import {CertificateRo} from "./certificate-ro.model"; +import {SearchTableEntity} from "../common/search-table/search-table-entity.model"; +import {of} from "rxjs/internal/observable/of"; +import {SearchTableValidationResult} from "../common/search-table/search-table-validation-result.model"; +import {ServiceMetadataValidationEditRo} from "../service-group-edit/service-group-metadata-dialog/service-metadata-validation-edit-ro.model"; +import {SmpConstants} from "../smp.constants"; +import {HttpClient} from "@angular/common/http"; export class UserController implements SearchTableController { - constructor(public dialog: MatDialog) { } + constructor(protected http: HttpClient, protected lookups: GlobalLookups, public dialog: MatDialog) { } public showDetails(row: any) { let dialogRef: MatDialogRef<UserDetailsDialogComponent> = this.dialog.open(UserDetailsDialogComponent); @@ -17,7 +25,9 @@ export class UserController implements SearchTableController { public edit(row: any) { } - public delete(row: any) { } + public delete(row: any) { + + } public newDialog(config?: MatDialogConfig): MatDialogRef<UserDetailsDialogComponent> { return this.dialog.open(UserDetailsDialogComponent, config); @@ -36,6 +46,25 @@ export class UserController implements SearchTableController { } } + public dataSaved() { + this.lookups.refreshUserLookup(); } + + validateDeleteOperation(rows: Array<SearchTableEntity>){ + var deleteRowIds = rows.map(rows => rows.id); + return this.http.post<SearchTableValidationResult>(SmpConstants.REST_USER_VALIDATE_DELETE, deleteRowIds); + } + + public newValidationResult(lst: Array<number>): SearchTableValidationResult { + return { + validOperation: false, + stringMessage: null, + listId:lst, + } + } + + + + } diff --git a/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.html b/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.html index 55dc6f5558e101f305ec28838ad8495ab6fe7205..66fff3fb6ad733ad9db2902b30f081646c404a37 100644 --- a/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.html +++ b/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.html @@ -29,7 +29,7 @@ <div fxLayout="row"> <mat-card fxFlex="40"> <mat-card-title> - <mat-slide-toggle mat-no-ink class="mat-primary" [formControl]="userForm.controls['userToggle']" + <mat-slide-toggle mat-no-ink class="mat-primary" [formControl]="userForm.controls['userToggle']" (change)="onUserToggleChanged($event)" id="userDetailsToggle_id"> User/password authentication </mat-slide-toggle> @@ -49,7 +49,7 @@ </mat-form-field> <mat-slide-toggle *ngIf="editMode" mat-no-ink class="mat-primary" [formControl]="userForm.controls['passwordToggle']" - (change)="onPasswordToggleChanged($event)" id="upasswordToggle_id"> + (change)="onPasswordToggleChanged($event)" id="passwordToggle_id"> Change password </mat-slide-toggle> @@ -89,7 +89,8 @@ </mat-card> <mat-card fxFlex="60"> <mat-card-title> - <mat-slide-toggle mat-no-ink class="mat-primary" [formControl]="userForm.controls['certificateToggle']" + <mat-slide-toggle mat-no-ink class="mat-primary" (change)="onCertificateToggleChanged($event)" + [formControl]="userForm.controls['certificateToggle']" id="certificateToggle_id"> Certificate authentication </mat-slide-toggle> diff --git a/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.ts b/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.ts index d2f7756ec56624348749a579d926b621bb3f3ed3..40879322e604c4fb3bc5e24c163392d275c289bf 100644 --- a/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.ts +++ b/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, ViewChild} from '@angular/core'; +import {Component, Inject, TemplateRef, ViewChild} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef, MatSlideToggleChange} from '@angular/material'; import {FormBuilder, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators} from '@angular/forms'; import {UserService} from '../user.service'; @@ -9,6 +9,7 @@ import {AlertService} from '../../alert/alert.service'; import {CertificateService} from '../certificate.service'; import {CertificateRo} from "../certificate-ro.model"; import {DatePipe} from "../../custom-date/date.pipe"; +import {UserController} from "../user-controller"; @Component({ selector: 'user-details-dialog', @@ -17,6 +18,9 @@ import {DatePipe} from "../../custom-date/date.pipe"; }) export class UserDetailsDialogComponent { + + @ViewChild('fileInput') private fileInput; + static readonly NEW_MODE = 'New User'; static readonly EDIT_MODE = 'User Edit'; @@ -30,9 +34,10 @@ export class UserDetailsDialogComponent { existingRoles = []; userForm: FormGroup; current: UserRo; + tempStoreForCertificate: CertificateRo = UserDetailsDialogComponent.newCertificteRo(); + tempStoreForUser: UserRo = UserDetailsDialogComponent.newUserRo(); + - @ViewChild('fileInput') - private fileInput; private passwordConfirmationValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => { const userToggle = control.get('userToggle'); @@ -73,13 +78,7 @@ export class UserDetailsDialogComponent { ...data.row, password: '', // ensures the user password is cleared before editing confirmation: '', - certificate: { - subject: data.row.subject, - validFrom: data.row.validFrom, - validTo: data.row.validTo, - issuer: data.row.issuer, - serialNumber: data.row.serialNumber, - } + certificate:data.row.certificate? data.row.certificate: UserDetailsDialogComponent.newCertificteRo() }: { active: true, username: '', @@ -89,47 +88,77 @@ export class UserDetailsDialogComponent { role: '', status: SearchTableEntityStatus.NEW, statusPassword: SearchTableEntityStatus.NEW, - certificate: {}, + certificate: UserDetailsDialogComponent.newCertificteRo(), }; - const userDetailsToggled: boolean = this.current && !!this.current.username; - const passwordToggle: boolean = !this.editMode; + // The password authentication is if username exists + // if is off on clear than clear the username! + const bUserPasswordAuthentication: boolean = !!this.current.username; + const bSetPassword: boolean = false; + // calculate allowed roles + this.existingRoles = this.getAllowedRoles(this.current.role); + + // set empty form ! do not bind it to current object ! this.userForm = fb.group({ // common values - 'active': new FormControl({ value: this.current.active},[]), - 'emailAddress': new FormControl({ value:this.current.emailAddress },[ Validators.pattern(this.emailPattern)]), - 'role': new FormControl({ value: this.current.role }, Validators.required), + 'active': new FormControl({ value: ''},[]), + 'emailAddress': new FormControl({ value:'' },[ Validators.pattern(this.emailPattern)]), + 'role': new FormControl({ value: '' }, Validators.required), // username/password authentication - 'userToggle': new FormControl(userDetailsToggled), - 'passwordToggle': new FormControl(passwordToggle), - 'username': new FormControl({ value: this.current.username, disabled: this.editMode || !userDetailsToggled }, this.editMode ? Validators.nullValidator : null), - 'password': new FormControl({ value: this.current.password, disabled: !userDetailsToggled && !passwordToggle}, + 'userToggle': new FormControl(bUserPasswordAuthentication), + 'passwordToggle': new FormControl({value: bSetPassword, disabled:!bUserPasswordAuthentication}), + 'username': new FormControl({ value: '', disabled: this.editMode || !bUserPasswordAuthentication }, this.editMode ? Validators.nullValidator : null), + 'password': new FormControl({ value: '', disabled: !bUserPasswordAuthentication || !bSetPassword}, [Validators.required, Validators.pattern(this.passwordPattern)]), - 'confirmation': new FormControl({ value: this.current.password, disabled: !userDetailsToggled && !passwordToggle}, + 'confirmation': new FormControl({ value: '', disabled: !bUserPasswordAuthentication || !bSetPassword}, Validators.pattern(this.passwordPattern)), // certificate authentication - 'certificateToggle': new FormControl(this.current && this.current.certificate && !!this.current.certificate.subject), - 'subject': new FormControl({ value: this.current.certificate.subject, disabled: true }, Validators.required), - 'validFrom': new FormControl({ value: this.current.certificate.validFrom, disabled: true }, Validators.required), - 'validTo': new FormControl({ value: this.current.certificate.validTo, disabled: true }, Validators.required), - 'issuer': new FormControl({ value: this.current.certificate.issuer, disabled: true }, Validators.required), - 'serialNumber': new FormControl({ value: this.current.certificate.serialNumber, disabled: true }, Validators.required), - 'certificateId': new FormControl({ value: this.current.certificate.serialNumber, disabled: true }, Validators.required), + 'certificateToggle': new FormControl(this.current && this.current.certificate && !!this.current.certificate.certificateId), + 'subject': new FormControl({ value: '', disabled: true }, Validators.required), + 'validFrom': new FormControl({ value: '', disabled: true }, Validators.required), + 'validTo': new FormControl({ value: '', disabled: true }, Validators.required), + 'issuer': new FormControl({ value: '', disabled: true }, Validators.required), + 'serialNumber': new FormControl({ value: '', disabled: true }, Validators.required), + 'certificateId': new FormControl({ value: '', disabled: true }, Validators.required), }, { validator: [this.passwordConfirmationValidator, this.atLeastOneToggleCheckedValidator, this.certificateValidator] }); + // bind values to form! not property + this.userForm.controls['active'].setValue(this.current.active); + this.userForm.controls['emailAddress'].setValue(this.current.emailAddress); + this.userForm.controls['role'].setValue(this.current.role); + // username/password authentication + this.userForm.controls['username'].setValue(this.current.username); + this.userForm.controls['password'].setValue(this.current.password); + // certificate authentication + this.userForm.controls['subject'].setValue(this.current.certificate.subject); + this.userForm.controls['validFrom'].setValue(this.current.certificate.validFrom); + this.userForm.controls['validTo'].setValue(this.current.certificate.validTo); + this.userForm.controls['issuer'].setValue(this.current.certificate.issuer); + this.userForm.controls['serialNumber'].setValue(this.current.certificate.serialNumber); + this.userForm.controls['certificateId'].setValue(this.current.certificate.certificateId); + + // if edit mode and user is given - toggle is dissabled + // username should not be changed.! + if (this.editMode && !!this.current.username){ + this.userForm.controls['userToggle'].disable(); + } +/* Do not need retrieve roles from server because client must alreay be aware of + the roles... this.userService.getUserRoles$().subscribe(userRoles => { this.userRoles = userRoles.json(); this.existingRoles = this.editMode ? this.getAllowedRoles(this.userRoles, this.current.role) : this.userRoles; - }); + });*/ } + + submitForm() { this.dialogRef.close(true); } @@ -140,13 +169,20 @@ export class UserDetailsDialogComponent { const reader = new FileReader(); reader.onload = (e) => { this.certificateService.uploadCertificate$(reader.result).subscribe((res: CertificateRo) => { - this.userForm.patchValue({ - 'subject': res.subject, - 'validFrom': this.datePipe.transform(res.validFrom.toString(), this.dateFormat), - 'validTo': this.datePipe.transform(res.validTo.toString(), this.dateFormat), - 'issuer': res.issuer, - 'serialNumber': res.serialNumber - }); + if (res && res.certificateId){ + this.userForm.patchValue({ + 'subject': res.subject, + //'validFrom': this.datePipe.transform(res.validFrom.toString(), this.dateFormat), + //'validTo': this.datePipe.transform(res.validTo.toString(), this.dateFormat), + 'validFrom': res.validFrom, + 'validTo': res.validTo, + 'issuer': res.issuer, + 'serialNumber': res.serialNumber, + 'certificateId': res.certificateId + }); + } else { + this.alertService.exception("Error occured while reading certificate.", "Check if uploaded file has valid certificate type?", false); + } }, err => { this.alertService.exception('Error uploading certificate file ' + file.name, err); @@ -160,33 +196,135 @@ export class UserDetailsDialogComponent { reader.readAsBinaryString(file); } + onCertificateToggleChanged({checked}: MatSlideToggleChange) { + + if (checked) { + // fill from temp + this.userForm.controls['certificateId'].setValue( this.tempStoreForCertificate.certificateId); + this.userForm.controls['subject'].setValue( this.tempStoreForCertificate.subject); + this.userForm.controls['issuer'].setValue( this.tempStoreForCertificate.issuer); + this.userForm.controls['serialNumber'].setValue( this.tempStoreForCertificate.serialNumber); + this.userForm.controls['validFrom'].setValue( this.tempStoreForCertificate.validFrom); + this.userForm.controls['validFrom'].setValue( this.tempStoreForCertificate.validFrom); + this.userForm.controls['validTo'].setValue( this.tempStoreForCertificate.validTo); + } else { + // store data to temp, set values to null + this.tempStoreForCertificate.certificateId = this.userForm.controls['certificateId'].value; + this.tempStoreForCertificate.subject = this.userForm.controls['subject'].value; + this.tempStoreForCertificate.issuer = this.userForm.controls['issuer'].value; + this.tempStoreForCertificate.serialNumber = this.userForm.controls['serialNumber'].value; + this.tempStoreForCertificate.validFrom = this.userForm.controls['validFrom'].value; + this.tempStoreForCertificate.validTo = this.userForm.controls['validTo'].value; + + this.userForm.controls['certificateId'].setValue(""); + this.userForm.controls['subject'].setValue(""); + this.userForm.controls['issuer'].setValue(""); + this.userForm.controls['serialNumber'].setValue(""); + this.userForm.controls['validFrom'].setValue(""); + this.userForm.controls['validTo'].setValue(""); + } + + } + onUserToggleChanged({checked}: MatSlideToggleChange) { const action = checked ? 'enable' : 'disable'; - this.userForm.get('username')[checked && !this.editMode ? 'enable' : 'disable'](); - //this.userForm.get('role')[action](); - //this.userForm.get('password')[action](); - //this.userForm.get('confirmation')[action](); + this.userForm.get('username')[action](); + this.userForm.get('password')[action](); + this.userForm.get('confirmation')[action](); + + if(checked){ + this.userForm.controls['username'].setValue( this.tempStoreForUser.username); + this.userForm.controls['password'].setValue( this.tempStoreForUser.password); + } else { + // store data to temp, set values to null + this.tempStoreForUser.username = this.userForm.controls['username'].value; + this.tempStoreForUser.password = this.userForm.controls['password'].value; + + + this.userForm.controls['username'].setValue(""); + this.userForm.controls['password'].setValue(""); + } + this.userForm.controls['passwordToggle'].setValue(checked || !this.editMode); + } + onPasswordToggleChanged({checked}: MatSlideToggleChange) { const action = checked ? 'enable' : 'disable'; this.userForm.get('password')[action](); this.userForm.get('confirmation')[action](); + if (!checked) { + this.userForm.get('password').setValue(''); + this.userForm.get('confirmation').setValue(''); + } } - getCurrent(): UserRo { + public getCurrent(): UserRo { + this.current.active =this.userForm.get('active').value; + this.current.emailAddress =this.userForm.get('emailAddress').value; + this.current.role =this.userForm.get('role').value; + // certificate data + if(this.userForm.get('certificateToggle')) { + this.current.certificate.certificateId = this.userForm.controls['certificateId'].value; + this.current.certificate.subject = this.userForm.controls['subject'].value; + this.current.certificate.issuer = this.userForm.controls['issuer'].value; + this.current.certificate.serialNumber = this.userForm.controls['serialNumber'].value; + this.current.certificate.validFrom = this.userForm.controls['validFrom'].value; + this.current.certificate.validTo = this.userForm.controls['validTo'].value; + } else { + this.current.certificate = null; + } + // set username and password for new + if (!this.editMode && this.userForm.get('userToggle')) { + this.current.username = this.userForm.controls['username'].value; + this.current.password = this.userForm.controls['password'].value; + } + // if edit mode and password on - set password + else if (this.editMode && this.userForm.get('passwordToggle')) { + this.current.password = this.userForm.controls['password'].value; + } + + // update data return this.current; } // filters out roles so that the user cannot change from system administrator to the other roles or vice-versa - private getAllowedRoles(allRoles, userRole) { - if (userRole === Role.SYSTEM_ADMIN) { + private getAllowedRoles(userRole) { + if (!this.editMode){ + return Object.keys(Role); + } + else if (userRole === Role.SYSTEM_ADMIN) { return [Role.SYSTEM_ADMIN]; } else { - return allRoles.filter(role => role !== Role.SYSTEM_ADMIN); + return Object.keys(Role).filter(role => role !== Role.SYSTEM_ADMIN); + } + } + + public static newCertificteRo(): CertificateRo { + return { + subject: '', + validFrom: null, + validTo: null, + issuer: '', + serialNumber: '', + certificateId: '', + fingerprints:'', + } + } + + public static newUserRo():UserRo { + return { + id: null, + index: null, + username: '', + emailAddress: '', + role: '', + active: true, + status: SearchTableEntityStatus.NEW, + statusPassword: SearchTableEntityStatus.NEW } } } diff --git a/smp-angular/src/app/user/user.component.html b/smp-angular/src/app/user/user.component.html index 81ee627ae40bbcbf52cb8317d9b590837290c0b8..ab28f1acf70e4dfca1902b7658307566371feea3 100644 --- a/smp-angular/src/app/user/user.component.html +++ b/smp-angular/src/app/user/user.component.html @@ -9,6 +9,7 @@ [showSearchPanel]="false" [filter]="filter" [allowNewItems]="securityService.isCurrentUserSystemAdmin()" + [allowDeleteItems]="securityService.isCurrentUserSystemAdmin()" > <ng-template #roleCellTemplate let-value="value" ngx-datatable-cell-template>{{getRoleLabel(value)}}</ng-template> diff --git a/smp-angular/src/app/user/user.component.ts b/smp-angular/src/app/user/user.component.ts index becea140cfa95aa6399eaa192ef2e0c7c29274b6..fff78c08bd0ab234153175e5a69afbff48faddd7 100644 --- a/smp-angular/src/app/user/user.component.ts +++ b/smp-angular/src/app/user/user.component.ts @@ -6,6 +6,7 @@ import {UserController} from './user-controller'; import {HttpClient} from '@angular/common/http'; import {SearchTableComponent} from "../common/search-table/search-table.component"; import {SecurityService} from "../security/security.service"; +import {GlobalLookups} from "../common/global-lookups"; @Component({ templateUrl:'./user.component.html', @@ -22,14 +23,15 @@ export class UserComponent implements OnInit { userController: UserController; filter: any = {}; - constructor(public securityService: SecurityService, + constructor(private lookups: GlobalLookups, + public securityService: SecurityService, protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) { } ngOnInit() { - this.userController = new UserController(this.dialog); + this.userController = new UserController(this.http, this.lookups, this.dialog); this.columnPicker.allColumns = [ { @@ -39,7 +41,7 @@ export class UserComponent implements OnInit { }, { name: 'Certificate', - prop: 'subject', + prop: 'certificate.certificateId', canAutoResize: true }, { 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 d5d9f31282a83610738fef360e391891b1804bb2..57227b0632dcccdb613774d6480014179a8a3f23 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 @@ -108,10 +108,12 @@ public abstract class BaseDao<E extends BaseEntity> { */ @Transactional public boolean removeById(Object primaryKey) { - int removedRecords = memEManager.createQuery("delete from " + entityClass.getName() + " e where e.id = :primaryKey") - .setParameter("primaryKey", primaryKey) - .executeUpdate(); - return removedRecords > 0; + // Do not use query delete else envers will not work!! + E val = find(primaryKey); + if (val!= null) { + memEManager.remove(val); + return true; + } return false; } 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 9f959911e627a761f7db433403c95303ffcad239..56b120bffda013c9e960bbe84323ec83ffb43672 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,6 +14,8 @@ package eu.europa.ec.edelivery.smp.data.dao; import eu.europa.ec.edelivery.smp.data.model.DBDomain; +import eu.europa.ec.edelivery.smp.data.model.DBDomainDeleteValidation; +import eu.europa.ec.edelivery.smp.data.model.DBUserDeleteValidation; import eu.europa.ec.edelivery.smp.exceptions.ErrorCode; import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException; import org.apache.commons.lang.StringUtils; @@ -91,7 +93,7 @@ public class DomainDao extends BaseDao<DBDomain> { * @param domainCode * @return */ - public DBDomain validateDomainCode(String domainCode){ + public DBDomain validateDomainCode(String domainCode) { DBDomain domain = null; if (!StringUtils.isBlank(domainCode)) { Optional<DBDomain> od = getDomainByCode(domainCode); @@ -111,11 +113,25 @@ public class DomainDao extends BaseDao<DBDomain> { * False if entity did not exist, so nothing was changed */ @Transactional - public boolean removeByDomainCode(String code) { - int removedRecords = memEManager.createNamedQuery("DBDomain.removeByDomainCode") - .setParameter("domainCode", code) - .executeUpdate(); - return removedRecords > 0; + public boolean removeByDomainCode(String domainCode) { + Optional<DBDomain> optd = getDomainByCode(domainCode); + if (optd.isPresent()) { + memEManager.remove(optd.get()); + return true; + } + 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/UserDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/UserDao.java index a5cb8a172b946e515cd044b25c8887d113bc2ab8..95322f3dfa7a3a9d5a6dcee6e1c2f9e0f92fb3c5 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/UserDao.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/UserDao.java @@ -14,6 +14,7 @@ package eu.europa.ec.edelivery.smp.data.dao; import eu.europa.ec.edelivery.smp.data.model.DBUser; +import eu.europa.ec.edelivery.smp.data.model.DBUserDeleteValidation; import eu.europa.ec.edelivery.smp.exceptions.ErrorCode; import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException; import org.apache.commons.lang3.StringUtils; @@ -23,6 +24,7 @@ import javax.persistence.NoResultException; import javax.persistence.NonUniqueResultException; import javax.persistence.TypedQuery; import javax.transaction.Transactional; +import java.util.List; import java.util.Optional; import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.ILLEGAL_STATE_CERT_ID_MULTIPLE_ENTRY; @@ -43,8 +45,8 @@ public class UserDao extends BaseDao<DBUser> { @Override @Transactional public void persistFlushDetach(DBUser user) { - if (StringUtils.isBlank(user.getUsername()) - && (user.getCertificate()==null || StringUtils.isBlank(user.getCertificate().getCertificateId() )) ) { + if ( StringUtils.isBlank(user.getUsername()) + && (user.getCertificate() == null || StringUtils.isBlank(user.getCertificate().getCertificateId() )) ) { throw new SMPRuntimeException(ErrorCode.INVALID_USER_NO_IDENTIFIERS); } super.persistFlushDetach(user); @@ -106,4 +108,15 @@ public class UserDao extends BaseDao<DBUser> { } } + /** + * Validation report for users which owns service group + * @param userIds + * @return + */ + public List<DBUserDeleteValidation> validateUsersForDelete(List<Long> userIds){ + TypedQuery<DBUserDeleteValidation> query = memEManager.createNamedQuery("DBUserDeleteValidation.validateUsersForOwnership", + DBUserDeleteValidation.class); + query.setParameter("idList", userIds); + return query.getResultList(); + } } \ No newline at end of file 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 23652e66a28c39b130aa2d94375f4f0e13127e0d..b005771bc587246d63ac1c3760c72063d054b7f0 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 @@ -28,19 +28,33 @@ import java.time.LocalDateTime; @NamedQuery(name = "DBDomain.getDomainByCode", query = "SELECT d FROM DBDomain d WHERE d.domainCode = :domainCode"), @NamedQuery(name = "DBDomain.getDomainByID", query = "SELECT d FROM DBDomain d WHERE d.id = :id"), @NamedQuery(name = "DBDomain.getAll", query = "SELECT d FROM DBDomain d"), - @NamedQuery(name = "DBDomain.removeByDomainCode", query = "DELETE FROM DBDomain d WHERE d.domainCode = :domainCode") +}) +@NamedNativeQueries({ + @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_SERVICE_GROUP_DOMAIN SGD ON (D.ID =SGD.FK_DOMAIN_ID) " + + " WHERE D.ID IN (:domainIds)" + + "GROUP BY D.DOMAIN_CODE, D.SML_SUBDOMAIN;"), +}) +@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)}) }) public class DBDomain extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "domain_generator") - @SequenceGenerator(name="domain_generator", sequenceName = "SMP_DOMAIN_SEQ", allocationSize = 1, initialValue = 1) - @Column(name = "ID" ) + @SequenceGenerator(name = "domain_generator", sequenceName = "SMP_DOMAIN_SEQ", allocationSize = 1, initialValue = 1) + @Column(name = "ID") Long id; - @Column(name = "DOMAIN_CODE", length = CommonColumnsLengths.MAX_DOMAIN_CODE_LENGTH, nullable = false, unique = true) + @Column(name = "DOMAIN_CODE", length = CommonColumnsLengths.MAX_DOMAIN_CODE_LENGTH, nullable = false, unique = true) String domainCode; - @Column(name = "SML_SUBDOMAIN", length = CommonColumnsLengths.MAX_SML_SUBDOMAIN_LENGTH, unique = true) + @Column(name = "SML_SUBDOMAIN", length = CommonColumnsLengths.MAX_SML_SUBDOMAIN_LENGTH, unique = true) String smlSubdomain; @Column(name = "SML_SMP_ID", length = CommonColumnsLengths.MAX_SML_SMP_ID_LENGTH) String smlSmpId; @@ -53,7 +67,7 @@ public class DBDomain extends BaseEntity { @Column(name = "SIGNATURE_KEY_ALIAS", length = CommonColumnsLengths.MAX_CERT_ALIAS_LENGTH) String signatureKeyAlias; - @Column(name = "CREATED_ON" , nullable = false) + @Column(name = "CREATED_ON", nullable = false) LocalDateTime createdOn; @Column(name = "LAST_UPDATED_ON", nullable = false) LocalDateTime lastUpdatedOn; @@ -130,7 +144,7 @@ public class DBDomain extends BaseEntity { @PrePersist public void prePersist() { - if(createdOn == null) { + if (createdOn == null) { createdOn = LocalDateTime.now(); } lastUpdatedOn = LocalDateTime.now(); diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomainDeleteValidation.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomainDeleteValidation.java new file mode 100644 index 0000000000000000000000000000000000000000..40f8d55de213a43577605fa1b2ae538a45928ee4 --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomainDeleteValidation.java @@ -0,0 +1,44 @@ +package eu.europa.ec.edelivery.smp.data.model; + + +public class DBDomainDeleteValidation { + + Long id; + String domainCode; + String smlSubdomain; + Integer count; + + public DBDomainDeleteValidation() { + } + + public DBDomainDeleteValidation(Long id, String domainCode, String smlSubdomain, Integer count) { + this.id = id; + this.domainCode = domainCode; + this.smlSubdomain = smlSubdomain; + this.count = count; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getDomainCode() { + return domainCode; + } + + public void setDomainCode(String domainCode) { + this.domainCode = domainCode; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } +} diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBUser.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBUser.java index 3027071e028e65fc7fea09715aef60da779291bf..2d0d28fff88f727d657ea7e8d75bfcc502ca02f8 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBUser.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBUser.java @@ -27,6 +27,24 @@ import java.util.Objects; @NamedQuery(name = "DBUser.getUserByUsernameInsensitive", query = "SELECT u FROM DBUser u WHERE lower(u.username) = lower(:username)"), @NamedQuery(name = "DBUser.getUserByCertificateId", query = "SELECT u FROM DBUser u WHERE u.certificate.certificateId = :certificateId"), }) +@NamedNativeQueries({ + @NamedNativeQuery(name = "DBUserDeleteValidation.validateUsersForOwnership", + resultSetMapping="DBUserDeleteValidationMapping", + query = "SELECT S.ID as ID, S.USERNAME as USERNAME, " + + " C.CERTIFICATE_ID as certificateId, COUNT(S.ID) as ownedCount FROM " + + " SMP_USER S LEFT JOIN SMP_CERTIFICATE C ON (S.ID=C.ID) " + + " INNER JOIN SMP_OWNERSHIP SG ON (S.ID = SG.FK_USER_ID) " + + " WHERE S.ID IN (:idList)" + + " GROUP BY S.ID, S.USERNAME, C.CERTIFICATE_ID"), +}) +@SqlResultSetMapping(name="DBUserDeleteValidationMapping", classes = { + @ConstructorResult(targetClass = DBUserDeleteValidation.class, + columns = {@ColumnResult(name="id" , type=Long.class), + @ColumnResult(name="username",type=String.class), + @ColumnResult(name="certificateId",type=String.class), + @ColumnResult(name="ownedCount",type=Integer.class)}) +}) + public class DBUser extends BaseEntity { @Id @@ -51,7 +69,8 @@ public class DBUser extends BaseEntity { @Column(name = "ROLE", length = CommonColumnsLengths.MAX_USER_ROLE_LENGTH) private String role; - @OneToOne(mappedBy = "dbUser", cascade = CascadeType.ALL, fetch = FetchType.EAGER, optional = true) + @OneToOne(mappedBy = "dbUser", cascade = CascadeType.ALL, fetch = FetchType.EAGER, optional = true, + orphanRemoval = true) private DBCertificate certificate; @Column(name = "CREATED_ON" , nullable = false) diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBUserDeleteValidation.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBUserDeleteValidation.java new file mode 100644 index 0000000000000000000000000000000000000000..c855562991763b16acff0ef23a606be16861ec7e --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBUserDeleteValidation.java @@ -0,0 +1,57 @@ +package eu.europa.ec.edelivery.smp.data.model; + + +import org.hibernate.envers.Audited; + +import javax.persistence.*; + + +public class DBUserDeleteValidation { + + Long id; + String username; + String certificateId; + Integer count; + + public DBUserDeleteValidation() { + } + + public DBUserDeleteValidation(Long id, String username, String certificateId, Integer count) { + this.id = id; + this.username = username; + this.certificateId = certificateId; + this.count = count; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getCertificateId() { + return certificateId; + } + + public void setCertificateId(String certificateId) { + this.certificateId = certificateId; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer iCount) { + this.count = iCount; + } +} diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CertificateRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CertificateRO.java index 7637bdfc8ef1fabb45799351ff8c214b22dfa421..572a4c3cf6dd542e98f3f59a96e5ad7252cf73d2 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CertificateRO.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CertificateRO.java @@ -1,6 +1,8 @@ package eu.europa.ec.edelivery.smp.data.ui; -import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.util.Date; /** * @author Joze Rihtarsic @@ -15,10 +17,12 @@ public class CertificateRO extends BaseRO { private String issuer; private String serialNumber; private String encodedValue; - private LocalDateTime validFrom; - private LocalDateTime validTo; + @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd,HH:mm", timezone="CET") + private Date validFrom; + @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd,HH:mm", timezone="CET") + private Date validTo; - public CertificateRO(){ + public CertificateRO() { } public static long getSerialVersionUID() { @@ -57,19 +61,19 @@ public class CertificateRO extends BaseRO { this.serialNumber = serialNumber; } - public LocalDateTime getValidFrom() { + public Date getValidFrom() { return validFrom; } - public void setValidFrom(LocalDateTime validFrom) { + public void setValidFrom(Date validFrom) { this.validFrom = validFrom; } - public LocalDateTime getValidTo() { + public Date getValidTo() { return validTo; } - public void setValidTo(LocalDateTime validTo) { + public void setValidTo(Date validTo) { this.validTo = validTo; } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DeleteEntityValidation.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DeleteEntityValidation.java new file mode 100644 index 0000000000000000000000000000000000000000..a73ba49aaddeb95984589aac7f43721d1acd0f4e --- /dev/null +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/DeleteEntityValidation.java @@ -0,0 +1,43 @@ +package eu.europa.ec.edelivery.smp.data.ui; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class DeleteEntityValidation implements Serializable { + + private static final long serialVersionUID = -4971552086560325308L; + + + boolean validOperation; + String stringMessage; + List<Long> listIds= new ArrayList<>(); + List<Long> listDeleteNotPermitedIds = new ArrayList<>(); + + public boolean isValidOperation() { + return validOperation; + } + + public void setValidOperation(boolean validOperation) { + this.validOperation = validOperation; + } + + public String getStringMessage() { + return stringMessage; + } + + public void setStringMessage(String stringMessage) { + this.stringMessage = stringMessage; + } + + public List<Long> getListIds() { + return listIds; + } + + + public List<Long> getListDeleteNotPermitedIds() { + return listDeleteNotPermitedIds; + } + + +} diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/UserRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/UserRO.java index 98928df5b5f6f9e0895c30114e6b38d7f96d1b67..0204221bfa104b74e3176d03b559b6b9645c9e2e 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/UserRO.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/UserRO.java @@ -2,7 +2,6 @@ package eu.europa.ec.edelivery.smp.data.ui; import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus; -import java.io.Serializable; import java.time.LocalDateTime; import java.util.List; @@ -24,7 +23,7 @@ public class UserRO extends BaseRO { private boolean active = true; private String role; private Long id; - private CertificateRO certificateData; + private CertificateRO certificate; private int statusPassword = EntityROStatus.PERSISTED.getStatusNumber(); public UserRO(){ @@ -87,12 +86,12 @@ public class UserRO extends BaseRO { this.role = role; } - public CertificateRO getCertificateData() { - return certificateData; + public CertificateRO getCertificate() { + return certificate; } - public void setCertificateData(CertificateRO certificate) { - this.certificateData = certificate; + public void setCertificate(CertificateRO certificate) { + this.certificate = certificate; } public List<String> getAuthorities() { return authorities; diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java index bcf7791e2d3e7b9fc11def6bf1a4eb00e0501799..830ed41ff1ee75377bdb45875649edc9ae8ed4a7 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java @@ -16,7 +16,7 @@ public enum ErrorCode { DOMAIN_NOT_EXISTS(404,"SMP:111",ErrorBusinessCode.NOT_FOUND, "Invalid domain '%s'!"), INVALID_DOMAIN_CODE(400,"SMP:112",ErrorBusinessCode.FORMAT_ERROR,"Provided Domain Code '%s' does not match required pattern: '%s'"), ILLEGAL_STATE_DOMAIN_MULTIPLE_ENTRY(500,"SMP:113",ErrorBusinessCode.TECHNICAL,"More than one domain entry (domain: '%s') is defined in database!"), - MISSING_DOMAIN(400,"SMP:114",ErrorBusinessCode.MISSING_FIELD,"More than one domain registred on SMP. The domain must be defined!"), + MISSING_DOMAIN(400,"SMP:114",ErrorBusinessCode.MISSING_FIELD,"More than one domain registered on SMP. The domain must be defined!"), // user error messages @@ -31,7 +31,7 @@ public enum ErrorCode { // service group error ILLEGAL_STATE_SG_MULTIPLE_ENTRY (500,"SMP:130",ErrorBusinessCode.TECHNICAL,"More than one service group ( part. id: %s, part. sch.: '%s') is defined in database!"), SG_NOT_EXISTS(404,"SMP:131",ErrorBusinessCode.NOT_FOUND,"ServiceGroup not found (dpart. id: '%s', part. sch.: '%s')!"), - SG_NOT_REGISTRED_FOR_DOMAIN(400,"SMP:131",ErrorBusinessCode.NOT_FOUND,"Service group not registred for domain (domain: %s, part. id:~ '%s', part. sch.: '%s')!"), + SG_NOT_REGISTRED_FOR_DOMAIN(400,"SMP:131",ErrorBusinessCode.NOT_FOUND,"Service group not registered for domain (domain: %s, part. id:~ '%s', part. sch.: '%s')!"), INVALID_EXTENSION_FOR_SG (400,"SMP:132",ErrorBusinessCode.XSD_INVALID,"Invalid extension for service group (part. id: '%s', part. sch.: '%s'). Error: %s!"), DUPLICATE_DOMAIN_FOR_SG (400,"SMP:133",ErrorBusinessCode.INVALID_INPUT_DATA,"Repeated domain for Service group (part. id: '%s', part. sch.: '%s', domainCode %s, smlDomain %s).!"), MISSING_SG_ID (400,"SMP:134",ErrorBusinessCode.INVALID_INPUT_DATA,"Missing service group(part. id: '%s', part. sch.: '%s'!"), 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 e534efe6b74e63bea19a0aeb5d13e4a9f32a0987..dc20c876c71dad5ad22817acd1c42962322ac88b 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 @@ -3,13 +3,18 @@ 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.model.DBDomain; +import eu.europa.ec.edelivery.smp.data.model.DBDomainDeleteValidation; +import eu.europa.ec.edelivery.smp.data.model.DBUserDeleteValidation; +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.ServiceResult; import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.StringWriter; import java.time.LocalDateTime; import java.util.List; @@ -68,4 +73,25 @@ public class UIDomainService extends UIServiceBase<DBDomain, DomainRO> { } } + public DeleteEntityValidation validateDeleteRequest(DeleteEntityValidation dev){ + List<DBDomainDeleteValidation> lstMessages = domainDao.validateDomainsForDelete(dev.getListIds()); + dev.setValidOperation(lstMessages.isEmpty()); + 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()); + return dev; + } + } diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceBase.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceBase.java index c796fc57f0d7491f4b66dde05b38e9376c32fc31..fef300c5c3c06794b09c224a99754a4b6a8178f9 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceBase.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceBase.java @@ -50,12 +50,25 @@ abstract class UIServiceBase<E extends BaseEntity, R> { ServiceResult<R> sg = new ServiceResult<>(); sg.setPage(page<0?0:page); - sg.setPageSize(pageSize); + long iCnt = getDatabaseDao().getDataListCount(filter); + if (pageSize < 0) { // if page size iz -1 return all results and set pageSize to maxCount + pageSize = (int)iCnt; + } + sg.setPageSize(pageSize); sg.setCount(iCnt); if (iCnt > 0) { int iStartIndex = pageSize<0?-1:page * pageSize; + + if (iStartIndex >= iCnt && page > 0){ + page = page -1; + sg.setPage(page); // go back for a page + iStartIndex = pageSize<0?-1:page * pageSize; + } + + + List<E> lst = getDatabaseDao().getDataList(iStartIndex, pageSize, sortField, sortOrder, filter); List<R> lstRo = new ArrayList<>(); diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java index abdffd9e233b34d8f0852c96d74caeec1bd7d0a7..488a219316e6f2237642be39e7e7509eb99757b2 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java @@ -6,30 +6,29 @@ import eu.europa.ec.edelivery.smp.data.dao.BaseDao; import eu.europa.ec.edelivery.smp.data.dao.UserDao; import eu.europa.ec.edelivery.smp.data.model.DBCertificate; import eu.europa.ec.edelivery.smp.data.model.DBUser; +import eu.europa.ec.edelivery.smp.data.model.DBUserDeleteValidation; import eu.europa.ec.edelivery.smp.data.ui.CertificateRO; +import eu.europa.ec.edelivery.smp.data.ui.DeleteEntityValidation; import eu.europa.ec.edelivery.smp.data.ui.ServiceResult; import eu.europa.ec.edelivery.smp.data.ui.UserRO; import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus; import eu.europa.ec.edelivery.smp.logging.SMPLogger; import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; -import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.bcrypt.BCrypt; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; +import java.io.*; import java.math.BigInteger; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.sql.Date; import java.time.LocalDateTime; import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.Base64; import java.util.List; @@ -38,8 +37,8 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> { private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIUserService.class); - private static final byte[] S_PEM_START_TAG= "-----BEGIN CERTIFICATE-----\n".getBytes(); - private static final byte[] S_PEM_END_TAG= "\n-----END CERTIFICATE-----".getBytes(); + private static final byte[] S_PEM_START_TAG = "-----BEGIN CERTIFICATE-----\n".getBytes(); + private static final byte[] S_PEM_END_TAG = "\n-----END CERTIFICATE-----".getBytes(); @Autowired UserDao userDao; @@ -76,6 +75,9 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> { if (userRO.getStatus() == EntityROStatus.NEW.getStatusNumber()) { DBUser dbUser = convertFromRo(userRO); + if (!StringUtils.isBlank(userRO.getPassword())) { + dbUser.setPassword(BCryptPasswordHash.hashPassword(userRO.getPassword())); + } userDao.persistFlushDetach(dbUser); } else if (userRO.getStatus() == EntityROStatus.UPDATED.getStatusNumber()) { DBUser dbUser = userDao.find(userRO.getId()); @@ -84,26 +86,21 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> { dbUser.setActive(userRO.isActive()); // check for new password if (!StringUtils.isBlank(userRO.getPassword())) { - if (!StringUtils.isBlank(dbUser.getPassword())) { - if (!BCrypt.checkpw(userRO.getPassword(), dbUser.getPassword())) { - LOG.debug("User with id {} changed password!", dbUser.getId()); - - dbUser.setPassword(BCryptPasswordHash.hashPassword(userRO.getPassword().trim())); - dbUser.setPasswordChanged(LocalDateTime.now()); - } - } else { - dbUser.setPassword(BCryptPasswordHash.hashPassword(userRO.getPassword())); - } + dbUser.setPassword(BCryptPasswordHash.hashPassword(userRO.getPassword())); } // update certificate data - if (userRO.getCertificateData() == null) { + if (userRO.getCertificate() == null || StringUtils.isBlank(userRO.getCertificate().getCertificateId())) { dbUser.setCertificate(null); } else { - CertificateRO certificateRO = userRO.getCertificateData(); + CertificateRO certificateRO = userRO.getCertificate(); DBCertificate dbCertificate = dbUser.getCertificate() != null ? dbUser.getCertificate() : new DBCertificate(); dbUser.setCertificate(dbCertificate); - dbCertificate.setValidFrom(certificateRO.getValidFrom()); - dbCertificate.setValidFrom(certificateRO.getValidTo()); + if (certificateRO.getValidFrom()!=null) { + dbCertificate.setValidFrom(LocalDateTime.ofInstant(certificateRO.getValidFrom().toInstant(), ZoneId.systemDefault())); + } + if (certificateRO.getValidTo()!=null) { + dbCertificate.setValidTo(LocalDateTime.ofInstant(certificateRO.getValidTo().toInstant(), ZoneId.systemDefault())); + } dbCertificate.setCertificateId(certificateRO.getCertificateId()); dbCertificate.setSerialNumber(certificateRO.getSerialNumber()); dbCertificate.setSubject(certificateRO.getSubject()); @@ -135,17 +132,17 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> { cro.setIssuer(issuer); // set serial as HEX cro.setSerialNumber(serial.toString(16)); - cro.setValidFrom(LocalDateTime.ofInstant(cert.getNotBefore().toInstant(), ZoneId.systemDefault())); - cro.setValidTo(LocalDateTime.ofInstant(cert.getNotAfter().toInstant(), ZoneId.systemDefault())); + cro.setValidFrom(cert.getNotBefore()); + cro.setValidTo(cert.getNotAfter()); cro.setEncodedValue(Base64.getMimeEncoder().encodeToString(cert.getEncoded())); return cro; } - public boolean isCertificatePemEncoded(byte[] certData){ - if (certData!=null && certData.length >S_PEM_START_TAG.length){ + public boolean isCertificatePemEncoded(byte[] certData) { + if (certData != null && certData.length > S_PEM_START_TAG.length) { - for (int i=0; i<certData.length;i++){ + for (int i = 0; i < certData.length; i++) { if (certData[i] != S_PEM_START_TAG[i]) { return false; } @@ -157,19 +154,20 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> { /** * Method tests if certificate is in PEM format. If not it creates pem format else returns original data. + * * @param certData - certificate data * @return * @throws IOException */ - public ByteArrayInputStream createPEMFormat(byte[] certData) throws IOException { + public ByteArrayInputStream createPEMFormat(byte[] certData) throws IOException { ByteArrayInputStream is; - if (isCertificatePemEncoded(certData)){ + if (isCertificatePemEncoded(certData)) { is = new ByteArrayInputStream(certData); } else { ByteArrayOutputStream bos = new ByteArrayOutputStream(); - bos.write(S_PEM_START_TAG); - bos.write(Base64.getMimeEncoder().encode(certData)); - bos.write(S_PEM_END_TAG); + bos.write(S_PEM_START_TAG); + bos.write(Base64.getMimeEncoder().encode(certData)); + bos.write(S_PEM_END_TAG); is = new ByteArrayInputStream(bos.toByteArray()); } return is; @@ -181,41 +179,79 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> { @Override public UserRO convertToRo(DBUser d) { - try { - UserRO dro = new UserRO(); - BeanUtils.copyProperties(dro, d); - - if (d.getCertificate() != null) { - CertificateRO certData = new CertificateRO(); - BeanUtils.copyProperties(certData, d.getCertificate()); - dro.setCertificateData(certData); + + UserRO dro = new UserRO(); + dro.setEmailAddress(d.getEmailAddress()); + dro.setUsername(d.getUsername()); + dro.setRole(d.getRole()); + dro.setPassword(d.getPassword()); + dro.setPasswordChanged(d.getPasswordChanged()); + dro.setActive(d.isActive()); + dro.setId(d.getId()); + + if (d.getCertificate() != null) { + CertificateRO certData = new CertificateRO(); + if (d.getCertificate().getValidTo() != null) { + + certData.setValidTo(Date.from(d.getCertificate().getValidTo().toInstant(ZoneOffset.UTC))); } - return dro; - } catch (InvocationTargetException | IllegalAccessException e) { - String msg = "Error occurred while converting to RO Entity for " + UserRO.class.getName(); - LOG.error(msg, e); - throw new RuntimeException(msg, e); + if (d.getCertificate().getValidFrom() != null) { + certData.setValidFrom(Date.from(d.getCertificate().getValidFrom().toInstant(ZoneOffset.UTC))); + } + certData.setCertificateId(d.getCertificate().getCertificateId()); + certData.setSerialNumber(d.getCertificate().getSerialNumber()); + certData.setIssuer(d.getCertificate().getIssuer()); + certData.setSubject(d.getCertificate().getSubject()); + dro.setCertificate(certData); } + return dro; + } + + public DeleteEntityValidation validateDeleteRequest(DeleteEntityValidation dev){ + List<DBUserDeleteValidation> lstMessages = userDao.validateUsersForDelete(dev.getListIds()); + dev.setValidOperation(lstMessages.isEmpty()); + StringWriter sw = new StringWriter(); + sw.write("Could not delete user with ownerships! "); + lstMessages.forEach(msg ->{ + dev.getListDeleteNotPermitedIds().add(msg.getId()); + sw.write("User: "); + sw.write(StringUtils.isBlank(msg.getUsername())?msg.getCertificateId(): msg.getUsername()); + sw.write(" owns SG count: "); + sw.write( msg.getCount().toString()); + sw.write( ". "); + }); + dev.setStringMessage(sw.toString()); + return dev; } + @Override public DBUser convertFromRo(UserRO d) { - try { - DBUser dro = new DBUser(); - BeanUtils.copyProperties(dro, d); - DBCertificate cert = new DBCertificate(); - if (d.getCertificateData() != null) { - DBCertificate certData = new DBCertificate(); - BeanUtils.copyProperties(certData, d.getCertificateData()); - dro.setCertificate(cert); + DBUser dro = new DBUser(); + dro.setEmailAddress(d.getEmailAddress()); + dro.setUsername(d.getUsername()); + dro.setRole(d.getRole()); + dro.setPassword(d.getPassword()); + dro.setActive(d.isActive()); + dro.setId(d.getId()); + dro.setPasswordChanged(d.getPasswordChanged()); + if (d.getCertificate() != null) { + DBCertificate certData = new DBCertificate(); + if (d.getCertificate().getValidTo() != null) { + certData.setValidTo(LocalDateTime.ofInstant(d.getCertificate().getValidTo().toInstant(), ZoneId.systemDefault())); } + if (d.getCertificate().getValidFrom() != null) { + certData.setValidFrom(LocalDateTime.ofInstant(d.getCertificate().getValidFrom().toInstant(), ZoneId.systemDefault())); + } + certData.setCertificateId(d.getCertificate().getCertificateId()); + certData.setSerialNumber(d.getCertificate().getSerialNumber()); + certData.setIssuer(d.getCertificate().getIssuer()); + certData.setSubject(d.getCertificate().getSubject()); - return dro; - } catch (InvocationTargetException | IllegalAccessException e) { - String msg = "Error occurred while converting to RO Entity for " + UserRO.class.getName(); - LOG.error(msg, e); - throw new RuntimeException(msg, e); + dro.setCertificate(certData); } + return dro; + } } 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 413448452226257d79c8124b0d24577db7ae2bce..ce7f681c4c083b12124eacd18839161f5567df2a 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 @@ -1,9 +1,10 @@ package eu.europa.ec.edelivery.smp.data.dao; import eu.europa.ec.edelivery.smp.config.H2JPATestConfiguration; -import eu.europa.ec.edelivery.smp.data.model.DBDomain; +import eu.europa.ec.edelivery.smp.data.model.*; 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.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -14,6 +15,8 @@ import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import java.util.Collections; +import java.util.List; import java.util.Optional; import static org.junit.Assert.*; @@ -29,6 +32,9 @@ public class DomainDaoIntegrationTest extends AbstractBaseDao { @Autowired DomainDao testInstance; + @Autowired + ServiceGroupDao serviceGroupDao; + @Rule public ExpectedException expectedEx = ExpectedException.none(); @@ -154,6 +160,36 @@ public class DomainDaoIntegrationTest extends AbstractBaseDao { assertTrue(res); optDmn = testInstance.getDomainByCode(TestConstants.TEST_DOMAIN_CODE_1); assertFalse(optDmn.isPresent()); + } + + + @Test + public void testValidateUsersForDeleteOKScenario() { + // set + DBDomain d = TestDBUtils.createDBDomain(); + testInstance.persistFlushDetach(d); + // execute + List<DBDomainDeleteValidation> lst = testInstance.validateDomainsForDelete(Collections.singletonList(d.getId())); + assertTrue(lst.isEmpty()); + } + + @Test + public void testValidateUsersForDeleteUserIsOwner() { + // set + DBDomain d = TestDBUtils.createDBDomain(); + testInstance.persistFlushDetach(d); + + DBServiceGroup sg = TestDBUtils.createDBServiceGroup(); + sg.addDomain(d); + + 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()); } } \ No newline at end of file diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/UserDaoIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/UserDaoIntegrationTest.java index bc6181fadd85f6e68d2c205dc6afc5ef7db08b37..633bd4e738b4a8649754dfaebbf79374b11f53d2 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/UserDaoIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/UserDaoIntegrationTest.java @@ -1,6 +1,9 @@ package eu.europa.ec.edelivery.smp.data.dao; +import eu.europa.ec.edelivery.smp.data.model.DBDomain; +import eu.europa.ec.edelivery.smp.data.model.DBServiceGroup; import eu.europa.ec.edelivery.smp.data.model.DBUser; +import eu.europa.ec.edelivery.smp.data.model.DBUserDeleteValidation; import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException; import eu.europa.ec.edelivery.smp.testutil.TestConstants; import eu.europa.ec.edelivery.smp.testutil.TestDBUtils; @@ -8,25 +11,32 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; import java.time.temporal.ChronoUnit; +import java.util.Collections; +import java.util.List; import java.util.Optional; +import java.util.UUID; import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.INVALID_USER_NO_IDENTIFIERS; import static org.junit.Assert.*; /** - * Purpose of class is to test all resource methods with database. + * Purpose of class is to test all resource methods with database. * * @author Joze Rihtarsic * @since 4.1 */ -public class UserDaoIntegrationTest extends AbstractBaseDao{ +public class UserDaoIntegrationTest extends AbstractBaseDao { @Autowired UserDao testInstance; + @Autowired + ServiceGroupDao serviceGroupDao; + @Rule public ExpectedException expectedEx = ExpectedException.none(); @@ -52,7 +62,7 @@ public class UserDaoIntegrationTest extends AbstractBaseDao{ //test Optional<DBUser> ou = testInstance.findUserByUsername(TestConstants.USERNAME_1); - assertTrue(u!=ou.get()); + assertTrue(u != ou.get()); assertEquals(u, ou.get()); assertEquals(u.getEmailAddress(), ou.get().getEmailAddress()); assertEquals(u.getPassword(), ou.get().getPassword()); @@ -70,7 +80,7 @@ public class UserDaoIntegrationTest extends AbstractBaseDao{ //test Optional<DBUser> ou = testInstance.findUserByCertificateId(TestConstants.USER_CERT_1); - assertTrue(u!=ou.get()); + assertTrue(u != ou.get()); assertEquals(u, ou.get()); assertEquals(u.getEmailAddress(), ou.get().getEmailAddress()); assertEquals(u.getCertificate().getCertificateId(), ou.get().getCertificate().getCertificateId()); @@ -88,7 +98,7 @@ public class UserDaoIntegrationTest extends AbstractBaseDao{ //test Optional<DBUser> ou = testInstance.findUserByIdentifier(TestConstants.USER_CERT_1); - assertTrue(u!=ou.get()); + assertTrue(u != ou.get()); assertEquals(u, ou.get()); assertEquals(u.getEmailAddress(), ou.get().getEmailAddress()); assertEquals(u.getCertificate().getCertificateId(), ou.get().getCertificate().getCertificateId()); @@ -107,11 +117,26 @@ public class UserDaoIntegrationTest extends AbstractBaseDao{ //test Optional<DBUser> ou = testInstance.findUserByIdentifier(TestConstants.USERNAME_1); - assertTrue(u!=ou.get()); + assertTrue(u != ou.get()); assertEquals(u, ou.get()); assertEquals(u.getEmailAddress(), ou.get().getEmailAddress()); } + @Test + public void deleteUserWithCertificate() { + // givem + DBUser u = TestDBUtils.createDBUserByCertificate(UUID.randomUUID().toString()); + testInstance.persistFlushDetach(u); + assertNotNull(u.getId()); + + // when then + testInstance.removeById(u.getId()); + //test + Optional<DBUser> ou = testInstance.findUserByIdentifier(u.getCertificate().getCertificateId()); + assertFalse(ou.isPresent()); + + } + @Test public void findBlankUsernameUser() { // set @@ -143,6 +168,7 @@ public class UserDaoIntegrationTest extends AbstractBaseDao{ Optional<DBUser> ou = testInstance.findUserByIdentifier(TestConstants.USERNAME_2); assertFalse(ou.isPresent()); } + @Test public void findCaseInsensitiveUsernameUser() { // set @@ -158,4 +184,33 @@ public class UserDaoIntegrationTest extends AbstractBaseDao{ assertEquals(u.getEmailAddress(), ou.get().getEmailAddress()); } + + @Test + public void testValidateUsersForDeleteOKScenario() { + // set + DBUser u = TestDBUtils.createDBUserByUsername(TestConstants.USERNAME_1.toLowerCase()); + testInstance.persistFlushDetach(u); + + // execute + List<DBUserDeleteValidation> lst = testInstance.validateUsersForDelete(Collections.singletonList(u.getId())); + assertTrue(lst.isEmpty()); + } + + @Test + public void testValidateUsersForDeleteUserIsOwner() { + // set + DBUser u = TestDBUtils.createDBUserByUsername(TestConstants.USERNAME_1.toLowerCase()); + DBServiceGroup sg = TestDBUtils.createDBServiceGroup(); + testInstance.persistFlushDetach(u); + sg.addUser(u); + + serviceGroupDao.persistFlushDetach(sg); + + + // execute + List<DBUserDeleteValidation> lst = testInstance.validateUsersForDelete(Collections.singletonList(u.getId())); + assertEquals(1, lst.size()); + assertEquals(u.getUsername(), lst.get(0).getUsername()); + assertEquals(1, lst.get(0).getCount().intValue()); + } } \ No newline at end of file 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 74a1277eb7daed99162a9eb4d55ae7476ea55a4f..b71c5ed8c7de56cbc5147e2403c9a2c4722b7e7f 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 @@ -47,7 +47,7 @@ public class UIDomainServiceIntegrationTest extends AbstractServiceIntegrationTe assertNotNull(res); assertEquals(0, res.getCount().intValue()); assertEquals(0, res.getPage().intValue()); - assertEquals(-1, res.getPageSize().intValue()); + assertEquals(0, res.getPageSize().intValue()); assertEquals(0, res.getServiceEntities().size()); assertNull(res.getFilter()); } @@ -65,7 +65,7 @@ public class UIDomainServiceIntegrationTest extends AbstractServiceIntegrationTe assertNotNull(res); assertEquals(15, res.getCount().intValue()); assertEquals(0, res.getPage().intValue()); - assertEquals(-1, res.getPageSize().intValue()); + assertEquals(15, res.getPageSize().intValue()); assertEquals(15, res.getServiceEntities().size()); assertNull(res.getFilter()); diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java index 9393fa3b71fb13a2dbc526a9c4467fa6e2cf41d9..c8ca20248fc23798dcaba5f68dcb7dffb73eab2a 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java @@ -22,10 +22,7 @@ import java.io.IOException; import java.security.cert.CertificateException; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; -import java.util.Calendar; -import java.util.Collections; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import static org.junit.Assert.*; @@ -63,7 +60,7 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest assertNotNull(res); assertEquals(0, res.getCount().intValue()); assertEquals(0, res.getPage().intValue()); - assertEquals(-1, res.getPageSize().intValue()); + assertEquals(0, res.getPageSize().intValue()); assertEquals(0, res.getServiceEntities().size()); assertNull(res.getFilter()); } @@ -80,7 +77,7 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest assertNotNull(res); assertEquals(15, res.getCount().intValue()); assertEquals(0, res.getPage().intValue()); - assertEquals(-1, res.getPageSize().intValue()); + assertEquals(15, res.getPageSize().intValue()); assertEquals(15, res.getServiceEntities().size()); assertNull(res.getFilter()); @@ -135,7 +132,7 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest assertEquals(iCnt+1, iCntNew); Optional<DBUser> oUsr = userDao.findUserByUsername(user.getUsername()); assertTrue(oUsr.isPresent()); - assertEquals(user.getPassword(), oUsr.get().getPassword()); + assertTrue(BCrypt.checkpw(user.getPassword(), oUsr.get().getPassword())); // password must be encrypted assertEquals(user.getUsername(), oUsr.get().getUsername()); assertEquals(user.getRole(), oUsr.get().getRole()); assertEquals(user.getEmailAddress(), oUsr.get().getEmailAddress()); @@ -148,8 +145,10 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest insertDataObjects(15); long iCnt = userDao.getDataListCount(null); - LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES); - LocalDateTime future =now.plusYears(1); + Calendar calTo = Calendar.getInstance(); + calTo.add(Calendar.YEAR, 1); + Date now = Calendar.getInstance().getTime(); + Date future =calTo.getTime(); UserRO user = new UserRO(); user.setPassword(UUID.randomUUID().toString()); @@ -163,7 +162,7 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest cert.setCertificateId(UUID.randomUUID().toString()); cert.setValidFrom(now); cert.setValidTo(future); - user.setCertificateData(cert); + user.setCertificate(cert); user.setStatus(EntityROStatus.NEW.getStatusNumber()); @@ -175,7 +174,7 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest assertEquals(iCnt+1, iCntNew); Optional<DBUser> oUsr = userDao.findUserByUsername(user.getUsername()); assertTrue(oUsr.isPresent()); - assertEquals(user.getPassword(), oUsr.get().getPassword()); + assertTrue(BCrypt.checkpw(user.getPassword(), oUsr.get().getPassword())); // password must be encrypted assertEquals(user.getUsername(), oUsr.get().getUsername()); assertEquals(user.getRole(), oUsr.get().getRole()); assertEquals(user.getEmailAddress(), oUsr.get().getEmailAddress()); @@ -188,12 +187,54 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest assertEquals(future, cert.getValidTo()); } - @Test - public void testUserRemoveCertificate() { + public void testAddUserWithOnlyCertificate() { // given + insertDataObjects(15); + long iCnt = userDao.getDataListCount(null); + + Calendar calTo = Calendar.getInstance(); + calTo.add(Calendar.YEAR, 1); + Date now = Calendar.getInstance().getTime(); + Date future =calTo.getTime(); + + UserRO user = new UserRO(); + + user.setRole("ROLE"); + CertificateRO cert = new CertificateRO(); + cert.setSubject(UUID.randomUUID().toString()); + cert.setIssuer(UUID.randomUUID().toString()); + cert.setSerialNumber(UUID.randomUUID().toString()); + cert.setCertificateId(UUID.randomUUID().toString()); + cert.setValidFrom(now); + cert.setValidTo(future); + user.setCertificate(cert); + + user.setStatus(EntityROStatus.NEW.getStatusNumber()); + //when + testInstance.updateUserList(Collections.singletonList(user)); + // then + long iCntNew = userDao.getDataListCount(null); + assertEquals(iCnt+1, iCntNew); + Optional<DBUser> oUsr = userDao.findUserByIdentifier(user.getCertificate().getCertificateId()); + assertTrue(oUsr.isPresent()); + assertEquals(user.getRole(), oUsr.get().getRole()); + assertEquals(user.getEmailAddress(), oUsr.get().getEmailAddress()); + assertNotNull(oUsr.get().getCertificate()); + assertEquals(cert.getCertificateId(), cert.getCertificateId()); + assertEquals(cert.getSubject(), cert.getSubject()); + assertEquals(cert.getIssuer(), cert.getIssuer()); + assertEquals(cert.getSerialNumber(), cert.getSerialNumber()); + assertEquals(now, cert.getValidFrom()); + assertEquals(future, cert.getValidTo()); + } + + + @Test + public void testUserRemoveCertificate() { + // given LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES); LocalDateTime future =now.plusYears(1); @@ -214,10 +255,10 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest ServiceResult<UserRO> urTest = testInstance.getTableList(-1,-1,null, null, null); assertEquals(1, urTest.getServiceEntities().size()); UserRO userRO = urTest.getServiceEntities().get(0); - assertNotNull(userRO.getCertificateData()); + assertNotNull(userRO.getCertificate()); //when - userRO.setCertificateData(null); + userRO.setCertificate(null); userRO.setStatus(EntityROStatus.UPDATED.getStatusNumber()); testInstance.updateUserList(Collections.singletonList(userRO)); @@ -225,7 +266,7 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest ServiceResult<UserRO> res = testInstance.getTableList(-1,-1,null, null, null); assertEquals(1, urTest.getServiceEntities().size()); UserRO userResRO = urTest.getServiceEntities().get(0); - assertNull(userResRO.getCertificateData()); + assertNull(userResRO.getCertificate()); } @@ -264,7 +305,7 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest assertEquals("3", cer.getSerialNumber()); assertNotNull(cer.getValidFrom()); assertNotNull(cer.getValidTo()); - assertTrue(cer.getValidFrom().isBefore(cer.getValidTo())); + assertTrue(cer.getValidFrom().before(cer.getValidTo())); } @Test @@ -281,7 +322,7 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest assertEquals("474980c51478cf62761667461aef5e8e", cer.getSerialNumber()); assertNotNull(cer.getValidFrom()); assertNotNull(cer.getValidTo()); - assertTrue(cer.getValidFrom().isBefore(cer.getValidTo())); + assertTrue(cer.getValidFrom().before(cer.getValidTo())); } } diff --git a/smp-server-library/src/test/resources/truststore/NewPeppolAP1.crt b/smp-server-library/src/test/resources/truststore/NewPeppolAP1.crt deleted file mode 100644 index 01776da16c00a9089467f4849dc7679e08e1582b..0000000000000000000000000000000000000000 Binary files a/smp-server-library/src/test/resources/truststore/NewPeppolAP1.crt and /dev/null differ diff --git a/smp-server-library/src/test/resources/truststore/NewPeppolAP2.crt b/smp-server-library/src/test/resources/truststore/NewPeppolAP2.crt deleted file mode 100644 index afaa0f8ed3825834888eb6b0241044bb3ff5148e..0000000000000000000000000000000000000000 --- a/smp-server-library/src/test/resources/truststore/NewPeppolAP2.crt +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- MIIFyzCCA7OgAwIBAgIQR0mAxRR4z2J2FmdGGu9ejjANBgkqhkiG9w0BAQsFADBr -MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQT3BlblBFUFBPTCBBSVNCTDEWMBQGA1UE -CxMNRk9SIFRFU1QgT05MWTEpMCcGA1UEAxMgUEVQUE9MIEFDQ0VTUyBQT0lOVCBU -RVNUIENBIC0gRzIwHhcNMTgwNDE3MDAwMDAwWhcNMjAwNDA2MjM1OTU5WjBYMRIw -EAYDVQQDDAlQT1AwMDAwMDQxFzAVBgNVBAsMDlBFUFBPTCBURVNUIEFQMRwwGgYD -VQQKDBNFdXJvcGVhbiBDb21taXNzaW9uMQswCQYDVQQGEwJCRTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKJkqEcBWQ5L9QM+a+jg8YYalSlktpfqQowu -X+X4xZ+Sgmy7OtbxSciHJQjaRbOTCzjnLL/K2zaZdC/0xob32bX1yT7i95gYMmpU -JL8GVijtvOxCPyKPKdVBfk6NDOKNLKoSN6Zv3Eldn2wLuIru3iMvBycOds7hyYTg -1pFchrhHlMRvtWZQnrngc3I64crnZbaYY+KY5RYy5mNDN3BzDC3By3KYIL2VZNRb -347QKij4BMqTe69PWduYlamjI+HnNttkrAOSKYY0PHpUIxcoxqEStUhqC/AK0eZm -X4NLz6cOXT+01dYUWGy0u/I2T4IPFisn3FaIEBmDoGrNdV7UCLECAwEAAaOCAXww -ggF4MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgOoMBYGA1UdJQEB/wQMMAoG -CCsGAQUFBwMCMB0GA1UdDgQWBBQ+CXL5Yjkduz8B0Tb0Qrq6sumZ7DBdBgNVHR8E -VjBUMFKgUKBOhkxodHRwOi8vcGtpLWNybC5zeW1hdXRoLmNvbS9jYV82YTkzNzcz -NGEzOTNhMDgwNWJmMzNjZGE4YjMzMTA5My9MYXRlc3RDUkwuY3JsMDcGCCsGAQUF -BwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL3BraS1vY3NwLnN5bWF1dGguY29t -MB8GA1UdIwQYMBaAFGtvS7bxN7orPH8Yzborsrl8KjfrMC0GCmCGSAGG+EUBEAME -HzAdBhNghkgBhvhFARABAgMBAYGpkOEDFgY5NTc2MDgwOQYKYIZIAYb4RQEQBQQr -MCkCAQAWJGFIUjBjSE02THk5d2Eya3RjbUV1YzNsdFlYVjBhQzVqYjIwPTANBgkq -hkiG9w0BAQsFAAOCAgEAFniNKek5ZSbmbn9svJaDX8yvbl6yX1UDpteayKUztkGz -M5+hAgpQz97hayLTturSJR8pO1WjeaYYiXseRGy9cLnxbzSSOyMzYATyEZx4f65F -DfJbsK2pWQEbgwcxFcKVn4rNOMt6Whh9bcMtBhpYMH+6mEhjXfRcJ108z+P3MHyi -XuFTD4oCwR5Y82xIRNTf4xPuyeVI86SR61CSZIq9gnns4YXpJtE/dpJIHybzcre3 -APTgYuCbBbyYbjh4Wn2hYEkYAFeQdIZuz9Xnvd0EZWzFWKjrX0dtDvETuOzEtkno -TI4lZCDK+W+YMrwIBsTM7b9in6gXXugJD+EdzwR7Pnl0YQIqObwifmDeR6wdM8Ny -ylyEELPBc1N96hjEMPkdL/XwLZ+m1Nij8/VNIEaQ1UhG2wtXMFVIlkxI3J55BFoO -Rwot/3z5VMoZQzBlH1xs9eTrVvHgsDJ2k8X7zqhGW00Yym+HNIL+tJxNvNM1RtJp -qY9aihjxlgkckASz5HpuRBJ2l0v3Di4scdprxCRVXAiic1Ff6goff7GT99p/cuVv -PH65AOoUpGcS6xfAmTolig9hZnNFl1aR+x4dF9CZpN6d4pIK6iD4ULg568yHgoOR -PHOUpVRNAJY5n0MmapG4/YdI4LWdgSj5m/s1UQwhmdWIqvCt64upzh7hwJeUQ1g= ------END CERTIFICATE----- \ No newline at end of file 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 aa3b950ce5196f20988e314278713e516902e8b0..61a5fabfa73541fad2d638abe60c44fad292114d 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 @@ -52,4 +52,9 @@ insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KE insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (7, 'domainG','subdomain007', 'CEF-SMP-007','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (8, 'domainH','subdomain008', 'CEF-SMP-008','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (9, 'domainI','subdomain009', 'CEF-SMP-009','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (10, 'domainJ','subdomain009', 'CEF-SMP-009','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (11, 'domainJ','subdomain010', 'CEF-SMP-010','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); +insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (12, 'domainK','subdomain011', 'CEF-SMP-011','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP()); + + update SMP_DOMAIN_SEQ set next_val=100 where next_val=1; diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java index b4aa325dd4dc7edf40b3bdcebf3ed5bfb3761394..21be72f17687c5163bd9f0a30dca22e961795f1d 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java @@ -55,12 +55,12 @@ public class MonitorResource { private static final String TEST_PART_SCHEMA = "test-actorid-qns"; private static final String TEST_PART_ID = "urn:test:is:alive"; - private static final String TEST_EXTENSION_XML ="<Extension xmlns=\"http://docs.oasis-open.org/bdxr/ns/SMP/2016/05\"><ex:dummynode xmlns:ex=\"http://test.eu\">Sample not mandatory extension</ex:dummynode></Extension>"; - private static final String TEST_DB_SUCCESSFUL_ROLLBACK ="TEST_DB_SUCCESSFUL_ROLLBACK MESSAGE"; + private static final String TEST_EXTENSION_XML = "<Extension xmlns=\"http://docs.oasis-open.org/bdxr/ns/SMP/2016/05\"><ex:dummynode xmlns:ex=\"http://test.eu\">Sample not mandatory extension</ex:dummynode></Extension>"; + private static final String TEST_DB_SUCCESSFUL_ROLLBACK = "TEST_DB_SUCCESSFUL_ROLLBACK MESSAGE"; - @RequestMapping(method = RequestMethod.GET,path = "/is-alive") - @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN,SMPAuthority.S_AUTHORITY_TOKEN_SMP_ADMIN}) + @RequestMapping(method = RequestMethod.GET, path = "/is-alive") + @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN, SMPAuthority.S_AUTHORITY_TOKEN_SMP_ADMIN}) public ResponseEntity isAlive() { String user = SecurityContextHolder.getContext().getAuthentication().getName(); @@ -80,26 +80,26 @@ public class MonitorResource { BdxSmpOasisValidator.validateXSD(bServiceGroup); serviceGroup = ServiceGroupConverter.unmarshal(bServiceGroup); serviceGroupValidator - .validate(TEST_PART_SCHEMA+ "::"+TEST_PART_ID, serviceGroup); + .validate(TEST_PART_SCHEMA + "::" + TEST_PART_ID, serviceGroup); } catch (XmlInvalidAgainstSchemaException ex) { LOG.error("Error reading testing resource file", ex); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } boolean suc = false; try { - suc= testDatabase(); - }catch (SMPTestIsALiveException ex){ + suc = testDatabase(); + } catch (SMPTestIsALiveException ex) { suc = Objects.equals(TEST_DB_SUCCESSFUL_ROLLBACK, ex.getMessage()); - } catch(Throwable th) { + } catch (RuntimeException th) { LOG.error("Error occured while testing database connection: Msg:" + ExceptionUtils.getRootCauseMessage(th), th); } - return suc?ResponseEntity.ok().build():ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + return suc ? ResponseEntity.ok().build() : ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } - protected boolean testDatabase(){ + protected boolean testDatabase() { List<DBDomain> lstDomain = domainDao.getAllDomains(); - if (lstDomain.isEmpty()){ + if (lstDomain.isEmpty()) { LOG.error("Bad configuration! At least one domain must be configured!"); return false; } @@ -110,7 +110,7 @@ public class MonitorResource { newSg.setExtension(TEST_EXTENSION_XML.getBytes()); newSg.addDomain(lstDomain.get(0)); // add initial domain // persist (make sure this is not in transaction) - serviceGroupDao.testPersist(newSg,true, TEST_DB_SUCCESSFUL_ROLLBACK); + serviceGroupDao.testPersist(newSg, true, TEST_DB_SUCCESSFUL_ROLLBACK); return false; } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/DomainResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/DomainResource.java index 262d6e2883023d87fe3d88379924fe5eb1ae1942..e94afe48d3720f079307d1c72542f72022b11acb 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/DomainResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/DomainResource.java @@ -1,7 +1,10 @@ package eu.europa.ec.edelivery.smp.ui; +import eu.europa.ec.edelivery.smp.auth.SMPAuthenticationToken; import eu.europa.ec.edelivery.smp.auth.SMPAuthority; +import eu.europa.ec.edelivery.smp.data.model.DBUser; +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.ServiceResult; import eu.europa.ec.edelivery.smp.logging.SMPLogger; @@ -9,10 +12,13 @@ import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.services.ui.UIDomainService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.annotation.Secured; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import javax.annotation.PostConstruct; import java.util.Arrays; +import java.util.List; /** * @author Joze Rihtarsic @@ -53,4 +59,14 @@ public class DomainResource { LOG.info("GOT LIST OF DomainRO to UPDATE: " + updateEntities.length); uiDomainService.updateDomainList(Arrays.asList(updateEntities)); } + + @PutMapping(produces = {"application/json"}) + @RequestMapping(path = "validateDelete", method = RequestMethod.POST) + @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN}) + public DeleteEntityValidation validateDeleteUsers(@RequestBody List<Long> query) { + + DeleteEntityValidation dres = new DeleteEntityValidation(); + dres.getListIds().addAll(query); + return uiDomainService.validateDeleteRequest(dres); + } } diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/UserResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/UserResource.java index 1f5131a626da85ea6568071407358e3db736d047..1ff2692b28fad23d514465e535db0b1e8cc068e3 100644 --- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/UserResource.java +++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/UserResource.java @@ -1,8 +1,12 @@ package eu.europa.ec.edelivery.smp.ui; +import eu.europa.ec.edelivery.smp.auth.SMPAuthenticationToken; import eu.europa.ec.edelivery.smp.auth.SMPAuthority; +import eu.europa.ec.edelivery.smp.auth.SMPRole; +import eu.europa.ec.edelivery.smp.data.model.DBUser; import eu.europa.ec.edelivery.smp.data.ui.CertificateRO; +import eu.europa.ec.edelivery.smp.data.ui.DeleteEntityValidation; import eu.europa.ec.edelivery.smp.data.ui.ServiceResult; import eu.europa.ec.edelivery.smp.data.ui.UserRO; import eu.europa.ec.edelivery.smp.logging.SMPLogger; @@ -10,12 +14,15 @@ import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory; import eu.europa.ec.edelivery.smp.services.ui.UIUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.annotation.Secured; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import javax.annotation.PostConstruct; import java.io.IOException; import java.security.cert.CertificateException; import java.util.Arrays; +import java.util.List; /** * @author Joze Rihtarsic @@ -40,7 +47,7 @@ public class UserResource { @ResponseBody @RequestMapping(method = RequestMethod.GET) //update gui to call this when somebody is logged in. - // @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN, SMPAuthority.S_AUTHORITY_TOKEN_SMP_ADMIN, SMPAuthority.S_AUTHORITY_TOKEN_SERVICE_GROUP_ADMIN}) + @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN, SMPAuthority.S_AUTHORITY_TOKEN_SMP_ADMIN, SMPAuthority.S_AUTHORITY_TOKEN_SERVICE_GROUP_ADMIN}) public ServiceResult<UserRO> getUsers( @RequestParam(value = "page", defaultValue = "0") int page, @RequestParam(value = "pageSize", defaultValue = "10") int pageSize, @@ -60,6 +67,7 @@ public class UserResource { } @RequestMapping(path = "certdata", method = RequestMethod.POST) + @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN}) public CertificateRO uploadFile(@RequestBody byte[] data) { LOG.info("Got certificate data: " + data.length); try { @@ -70,4 +78,22 @@ public class UserResource { return null; } + + @PutMapping(produces = {"application/json"}) + @RequestMapping(path = "validateDelete", method = RequestMethod.POST) + @Secured({SMPAuthority.S_AUTHORITY_TOKEN_SYSTEM_ADMIN}) + public DeleteEntityValidation validateDeleteUsers(@RequestBody List<Long> query) { + // test if looged user + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + SMPAuthenticationToken authToken = (SMPAuthenticationToken) authentication; + DBUser user = authToken.getUser(); + DeleteEntityValidation dres = new DeleteEntityValidation(); + if (query.contains(user.getId())){ + dres.setValidOperation(false); + dres.setStringMessage("Could not delete logged user!"); + return dres; + } + dres.getListIds().addAll(query); + return uiUserService.validateDeleteRequest(dres); + } }