Code development platform for open source projects from the European Union institutions :large_blue_circle: EU Login authentication by SMS has been phased out. To see alternatives please check here

Skip to content
Snippets Groups Projects
Commit 0129cfad authored by Joze RIHTARSIC's avatar Joze RIHTARSIC
Browse files

Add Oasis SMP 2.0 implementation

parent fa2c321a
Branches
Tags
No related merge requests found
Showing
with 587 additions and 116 deletions
......@@ -32,6 +32,13 @@
background-color: smp.get-theme-color($theme, primary, 300);
}
.mat-mdc-table .mat-mdc-header-cell {
padding: 5px !important;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 1px 2px 0 rgba(0, 0, 0, 0.24);
background-color: smp.get-theme-color($theme, primary, 800, 0.1) !important;
text-align: center;
}
}
import 'hammerjs';
import {
AccessTokenGenerationDialogComponent
} from "./common/dialogs/access-token-generation-dialog/access-token-generation-dialog.component";
import {
AccessTokenPanelComponent
} from "./user-settings/user-access-tokens/access-token-panel/access-token-panel.component";
import {AccessTokenGenerationDialogComponent} from "./common/dialogs/access-token-generation-dialog/access-token-generation-dialog.component";
import {AccessTokenPanelComponent} from "./user-settings/user-access-tokens/access-token-panel/access-token-panel.component";
import {AdminDomainComponent} from "./system-settings/admin-domain/admin-domain.component";
import {AdminDomainService} from "./system-settings/admin-domain/admin-domain.service";
import {AdminKeystoreComponent} from "./system-settings/admin-keystore/admin-keystore.component";
import {AdminKeystoreService} from "./system-settings/admin-keystore/admin-keystore.service";
import {AdminTruststoreComponent} from "./system-settings/admin-truststore/admin-truststore.component";
import {AdminTruststoreService} from "./system-settings/admin-truststore/admin-truststore.service";
import {AlertComponent} from "./alert/alert.component";
......@@ -22,29 +22,26 @@ import {BrowserModule} from '@angular/platform-browser';
import {CancelDialogComponent} from './common/dialogs/cancel-dialog/cancel-dialog.component';
import {CapitalizeFirstPipe} from './common/capitalize-first.pipe';
import {CertificateDialogComponent} from "./common/dialogs/certificate-dialog/certificate-dialog.component";
import {
CertificatePanelComponent
} from "./common/panels/certificate-panel/certificate-panel.component";
import {CertificatePanelComponent} from "./common/panels/certificate-panel/certificate-panel.component";
import {CertificateService} from './system-settings/user/certificate.service';
import {ClearInvalidDirective} from './custom-date/clear-invalid.directive';
import {ColumnPickerComponent} from './common/column-picker/column-picker.component';
import {ConfirmationDialogComponent} from './common/dialogs/confirmation-dialog/confirmation-dialog.component';
import {CredentialDialogComponent} from "./common/dialogs/credential-dialog/credential-dialog.component";
import {DataPanelComponent} from "./common/data-panel/data-panel.component";
import {DataPanelComponent} from "./common/panels/data-panel/data-panel.component";
import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatNativeDateModule} from "@angular/material/core";
import {DatePipe} from './custom-date/date.pipe';
import {DefaultPasswordDialogComponent} from './security/default-password-dialog/default-password-dialog.component';
import {DialogComponent} from './common/dialogs/dialog/dialog.component';
import {DirtyGuard} from './common/dirty.guard';
import {DomainComponent} from './system-settings/domain/domain.component';
import {
DomainDetailsDialogComponent
} from './system-settings/domain/domain-details-dialog/domain-details-dialog.component';
import {DomainDetailsDialogComponent} from './system-settings/domain/domain-details-dialog/domain-details-dialog.component';
import {DomainPanelComponent} from "./system-settings/admin-domain/domain-panel/domain-panel.component";
import {DomainResourceTypePanelComponent} from "./system-settings/admin-domain/domain-resource-type-panel/domain-resource-type-panel.component";
import {DomainSelectorComponent} from './common/domain-selector/domain-selector.component';
import {DomainService} from './security/domain.service';
import {DomainSmlIntegrationPanelComponent} from "./system-settings/admin-domain/domain-sml-panel/domain-sml-integration-panel.component";
import {DownloadService} from './download/download.service';
import {
ExpiredPasswordDialogComponent
} from './common/dialogs/expired-password-dialog/expired-password-dialog.component';
import {ExpiredPasswordDialogComponent} from './common/dialogs/expired-password-dialog/expired-password-dialog.component';
import {ExtendedHttpClient, extendedHttpClientCreator} from './http/extended-http-client';
import {ExtensionComponent} from "./system-settings/admin-extension/extension.component";
import {ExtensionPanelComponent} from "./system-settings/admin-extension/extension-panel/extension-panel.component";
......@@ -57,12 +54,8 @@ import {HttpClient, HttpClientModule, HttpClientXsrfModule} from '@angular/commo
import {HttpEventService} from './http/http-event.service';
import {InformationDialogComponent} from "./common/dialogs/information-dialog/information-dialog.component";
import {IsAuthorized} from './security/is-authorized.directive';
import {
KeystoreEditDialogComponent
} from "./system-settings/domain/keystore-edit-dialog/keystore-edit-dialog.component";
import {
KeystoreImportDialogComponent
} from "./system-settings/admin-keystore/keystore-import-dialog/keystore-import-dialog.component";
import {KeystoreEditDialogComponent} from "./system-settings/domain/keystore-edit-dialog/keystore-edit-dialog.component";
import {KeystoreImportDialogComponent} from "./system-settings/admin-keystore/keystore-import-dialog/keystore-import-dialog.component";
import {KeystoreService} from "./system-settings/domain/keystore.service";
import {LoginComponent} from './login/login.component';
import {MatButtonModule} from "@angular/material/button";
......@@ -75,7 +68,6 @@ import {MatIconModule} from "@angular/material/icon";
import {MatInputModule} from '@angular/material/input';
import {MatListModule} from "@angular/material/list";
import {MatMenuModule} from "@angular/material/menu";
import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatNativeDateModule} from "@angular/material/core";
import {MatPaginatorModule} from "@angular/material/paginator";
import {MatProgressSpinnerModule} from "@angular/material/progress-spinner";
import {MatSelectModule} from "@angular/material/select";
......@@ -91,36 +83,22 @@ import {NavTree} from "./window/sidenav/nav-tree/nav-tree.component";
import {NavigationService} from "./window/sidenav/navigation-model.service";
import {NgModule} from '@angular/core';
import {NgxDatatableModule} from '@swimlane/ngx-datatable';
import {
ObjectPropertiesDialogComponent
} from "./common/dialogs/object-properties-dialog/object-properties-dialog.component";
import {ObjectPropertiesDialogComponent} from "./common/dialogs/object-properties-dialog/object-properties-dialog.component";
import {PasswordChangeDialogComponent} from "./common/dialogs/password-change-dialog/password-change-dialog.component";
import {PropertyComponent} from "./system-settings/property/property.component";
import {
PropertyDetailsDialogComponent
} from "./system-settings/property/property-details-dialog/property-details-dialog.component";
import {
ResourceDetailsDialogComponent
} from "./system-settings/admin-extension/resource-details-dialog/resource-details-dialog.component";
import {PropertyDetailsDialogComponent} from "./system-settings/property/property-details-dialog/property-details-dialog.component";
import {ResourceDetailsDialogComponent} from "./system-settings/admin-extension/resource-details-dialog/resource-details-dialog.component";
import {RowLimiterComponent} from './common/row-limiter/row-limiter.component';
import {SaveDialogComponent} from './common/dialogs/save-dialog/save-dialog.component';
import {SearchTableComponent} from './common/search-table/search-table.component';
import {SecurityEventService} from './security/security-event.service';
import {SecurityService} from './security/security.service';
import {
ServiceGroupDetailsDialogComponent
} from './service-group-edit/service-group-details-dialog/service-group-details-dialog.component';
import {ServiceGroupDetailsDialogComponent} from './service-group-edit/service-group-details-dialog/service-group-details-dialog.component';
import {ServiceGroupEditComponent} from './service-group-edit/service-group-edit.component';
import {
ServiceGroupExtensionWizardDialogComponent
} from './service-group-edit/service-group-extension-wizard-dialog/service-group-extension-wizard-dialog.component';
import {
ServiceGroupMetadataDialogComponent
} from './service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component';
import {ServiceGroupExtensionWizardDialogComponent} from './service-group-edit/service-group-extension-wizard-dialog/service-group-extension-wizard-dialog.component';
import {ServiceGroupMetadataDialogComponent} from './service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component';
import {ServiceGroupSearchComponent} from './service-group-search/service-group-search.component';
import {
ServiceMetadataWizardDialogComponent
} from './service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component';
import {ServiceMetadataWizardDialogComponent} from './service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component';
import {SharedModule} from './common/module/shared.module';
import {SidenavComponent} from './window/sidenav/sidenav.component';
import {SmlIntegrationService} from "./system-settings/domain/sml-integration.service";
......@@ -130,9 +108,7 @@ import {SpinnerComponent} from './common/spinner/spinner.component';
import {ThemeService} from "./common/theme-service/theme.service";
import {ToolbarComponent} from "./window/toolbar/toolbar.component";
import {UserAccessTokensComponent} from "./user-settings/user-access-tokens/user-access-tokens.component";
import {
UserCertificatePanelComponent
} from "./user-settings/user-certificates/user-certificate-panel/user-certificate-panel.component";
import {UserCertificatePanelComponent} from "./user-settings/user-certificates/user-certificate-panel/user-certificate-panel.component";
import {UserCertificatesComponent} from "./user-settings/user-certificates/user-certificates.component";
import {UserComponent} from './system-settings/user/user.component';
import {UserDetailsDialogComponent} from './system-settings/user/user-details-dialog/user-details-dialog.component';
......@@ -151,14 +127,13 @@ import {
NGX_MAT_MOMENT_FORMATS, NgxMatMomentAdapter,
NgxMatMomentModule
} from "@angular-material-components/moment-adapter";
import {AdminKeystoreComponent} from "./system-settings/admin-keystore/admin-keystore.component";
import {AdminKeystoreService} from "./system-settings/admin-keystore/admin-keystore.service";
@NgModule({
declarations: [
AccessTokenGenerationDialogComponent,
AccessTokenPanelComponent,
AdminDomainComponent,
AdminTruststoreComponent,
AdminKeystoreComponent,
AlertComponent,
......@@ -180,7 +155,10 @@ import {AdminKeystoreService} from "./system-settings/admin-keystore/admin-keyst
DefaultPasswordDialogComponent,
DialogComponent,
DomainComponent,
DomainPanelComponent,
DomainSmlIntegrationPanelComponent,
DomainDetailsDialogComponent,
DomainResourceTypePanelComponent,
DomainSelectorComponent,
ExpiredPasswordDialogComponent,
ExtensionComponent,
......@@ -258,13 +236,15 @@ import {AdminKeystoreService} from "./system-settings/admin-keystore/admin-keyst
routing,
],
providers: [
AdminDomainService,
AdminKeystoreService,
AdminTruststoreService,
AlertMessageService,
AuthenticatedGuard,
AuthorizedAdminGuard,
AuthorizedGuard,
CertificateService,
DatePipe,
DirtyGuard,
DomainService,
DownloadService,
ExtensionService,
......@@ -277,8 +257,6 @@ import {AdminKeystoreService} from "./system-settings/admin-keystore/admin-keyst
SmlIntegrationService,
SmpInfoService,
ThemeService,
AdminTruststoreService,
AdminKeystoreService,
UserDetailsService,
UserService,
{
......
......@@ -2,11 +2,8 @@ import {RouterModule, Routes} from '@angular/router';
import {LoginComponent} from './login/login.component';
import {ServiceGroupSearchComponent} from './service-group-search/service-group-search.component';
import {ServiceGroupEditComponent} from './service-group-edit/service-group-edit.component';
import {DomainComponent} from './system-settings/domain/domain.component';
import {AuthenticatedGuard} from './guards/authenticated.guard';
import {UserComponent} from './system-settings/user/user.component';
import {DirtyGuard} from "./common/dirty.guard";
import {AuthorizedAdminGuard} from "./guards/authorized-admin.guard";
import {AlertComponent} from "./alert/alert.component";
import {PropertyComponent} from "./system-settings/property/property.component";
import {UserProfileComponent} from "./user-settings/user-profile/user-profile.component";
......@@ -16,35 +13,42 @@ import {UserCertificatesComponent} from "./user-settings/user-certificates/user-
import {ExtensionComponent} from "./system-settings/admin-extension/extension.component";
import {AdminTruststoreComponent} from "./system-settings/admin-truststore/admin-truststore.component";
import {AdminKeystoreComponent} from "./system-settings/admin-keystore/admin-keystore.component";
import {AdminDomainComponent} from "./system-settings/admin-domain/admin-domain.component";
import {dirtyDeactivateGuard} from "./guards/dirty.guard";
const appRoutes: Routes = [
{path: '', component: ServiceGroupSearchComponent},
{path: 'search', redirectTo: ''},
{path: 'edit', component: ServiceGroupEditComponent, canActivate: [AuthenticatedGuard], canDeactivate: [DirtyGuard]},
{
path: 'edit',
component: ServiceGroupEditComponent,
canActivate: [AuthenticatedGuard],
canDeactivate: [dirtyDeactivateGuard]
},
{path: 'login', component: LoginComponent},
{
path: 'system-settings',
canActivateChild: [authGuard],
children: [
{ path: 'domain', component: DomainComponent },
{ path: 'user', component: UserComponent },
{ path: 'properties', component: PropertyComponent },
{ path: 'keystore', component: AdminKeystoreComponent },
{ path: 'truststore', component: AdminTruststoreComponent },
{ path: 'extension', component: ExtensionComponent },
{ path: 'alert', component: AlertComponent },
{path: 'domain', component: AdminDomainComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'user', component: UserComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'properties', component: PropertyComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'keystore', component: AdminKeystoreComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'truststore', component: AdminTruststoreComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'extension', component: ExtensionComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'alert', component: AlertComponent, canDeactivate: [dirtyDeactivateGuard]},
]
},
{
path: 'user-settings',
canActivateChild: [authGuard],
children: [
{ path: 'user-profile', component: UserProfileComponent },
{ path: 'user-access-token', component: UserAccessTokensComponent },
{ path: 'user-certificate', component: UserCertificatesComponent },
{ path: 'user-membership', component: UserProfileComponent },
{path: 'user-profile', component: UserProfileComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'user-access-token', component: UserAccessTokensComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'user-certificate', component: UserCertificatesComponent, canDeactivate: [dirtyDeactivateGuard]},
{path: 'user-membership', component: UserProfileComponent, canDeactivate: [dirtyDeactivateGuard]},
]
},
{path: '**', redirectTo: ''},
......
import { TestBed, async, inject } from '@angular/core/testing';
import { DirtyGuard } from './dirty.guard';
describe('DirtyGuard', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [DirtyGuard]
});
});
it('should ...', inject([DirtyGuard], (guard: DirtyGuard) => {
expect(guard).toBeTruthy();
}));
});
import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, CanDeactivate, RouterStateSnapshot} from '@angular/router';
import {Observable} from 'rxjs';
import {MatDialog} from '@angular/material/dialog';
import {CancelDialogComponent} from './dialogs/cancel-dialog/cancel-dialog.component';
@Injectable()
export class DirtyGuard implements CanActivate, CanDeactivate<any> {
constructor(public dialog: MatDialog) {
};
canActivate(next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return true;
}
canDeactivate(component: any, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if (component.isDirty && !component.isDirty()) return true;
return this.dialog.open(CancelDialogComponent).afterClosed();
}
}
......@@ -80,7 +80,7 @@ export class GlobalLookups {
let domainUrl = SmpConstants.REST_PUBLIC_DOMAIN_SEARCH;
// for authenticated admin use internal url which returns more data!
if (this.securityService.isCurrentUserSystemAdmin()) {
domainUrl = SmpConstants.REST_INTERNAL_DOMAIN_MANAGE;
domainUrl = SmpConstants.REST_INTERNAL_DOMAIN_MANAGE_DEPRECATED;
}
this.refreshDomainLookup(domainUrl);
}
......
......@@ -5,4 +5,6 @@ export interface SearchTableEntity {
index?: number;
status: EntityStatus;
deleted?: boolean;
actionMessage?: string;
}
import {inject} from '@angular/core';
import {NavigationService} from "../window/sidenav/navigation-model.service";
import {CancelDialogComponent} from "../common/dialogs/cancel-dialog/cancel-dialog.component";
import {MatDialog} from "@angular/material/dialog";
import {BeforeLeaveGuard} from "../window/sidenav/navigation-on-leave-guard";
export const dirtyDeactivateGuard = (component: BeforeLeaveGuard) => {
const navigationService = inject(NavigationService);
const dialog = inject(MatDialog);
if (component.isDirty && !component.isDirty()) return true;
return dialog.open(CancelDialogComponent).afterClosed().toPromise().then((cancelChanges: boolean) => {
// rollback the navigation
if (!cancelChanges) {
navigationService.selectPreviousNode()
}
return cancelChanges;
});
}
......@@ -52,11 +52,15 @@ export class SmpConstants {
//------------------------------
// internal endpoints
public static readonly REST_INTERNAL_ALERT_MANAGE = SmpConstants.REST_INTERNAL + 'alert';
public static readonly REST_INTERNAL_DOMAIN_MANAGE = SmpConstants.REST_INTERNAL + 'domain';
public static readonly REST_INTERNAL_DOMAIN_MANAGE_DEPRECATED = SmpConstants.REST_INTERNAL + 'domain';
public static readonly REST_INTERNAL_DOMAIN_MANAGE = SmpConstants.REST_INTERNAL + 'domain' +
'/' + SmpConstants.PATH_PARAM_ENC_USER_ID;
public static readonly REST_INTERNAL_EXTENSION_MANAGE = SmpConstants.REST_INTERNAL + 'extension';
public static readonly REST_INTERNAL_PROPERTY_MANAGE = SmpConstants.REST_INTERNAL + 'property';
public static readonly REST_INTERNAL_PROPERTY_VALIDATE = SmpConstants.REST_INTERNAL_PROPERTY_MANAGE + '/validate';
public static readonly REST_INTERNAL_DOMAIN_VALIDATE_DELETE = SmpConstants.REST_INTERNAL_DOMAIN_MANAGE + '/validate-delete';
public static readonly REST_INTERNAL_DOMAIN_VALIDATE_DELETE = SmpConstants.REST_INTERNAL_DOMAIN_MANAGE_DEPRECATED + '/validate-delete';
public static readonly REST_INTERNAL_USER_MANAGE = SmpConstants.REST_INTERNAL + 'user';
public static readonly REST_INTERNAL_USER_GENERATE_ACCESS_TOKEN = SmpConstants.REST_INTERNAL_USER_MANAGE +
'/' + SmpConstants.PATH_PARAM_ENC_USER_ID + '/' + 'generate-access-token-for' + '/' + SmpConstants.PATH_PARAM_ENC_MANAGED_USER_ID;
......
#admin-domain-panel {
display: flex;
flex-flow: column;
align-items: center;
height: 100%;
min-height: 600px;
padding: 0 2em;
}
#domain-filter {
width: 100%;
padding-top: 1em;
}
#admin-domain-table {
width: 100%;
padding-top: 1em;
}
#custom-file-upload {
display: none;
}
.custom-file-upload {
display: block;
cursor: pointer;
}
<div id="admin-domain-panel">
<data-panel id="admin-domain-data-panel"
title="System Domain administration"
text="System Domain administration panel is a tool for creating and removing domains from DomiSMP"
[labelColumnContent]="searchDomainPanel">
<mat-tab-group style="height: 100%">
<mat-tab label="Domain data">
<domain-panel
[domain]="selected"
[keystoreCertificates]="keystoreCertificates"
></domain-panel>
</mat-tab>
<mat-tab label="Resources">
<domain-resource-type-panel [domain]="selected"></domain-resource-type-panel>
</mat-tab>
<mat-tab label="SML integration">
<domain-sml-integration-panel [domain]="selected"></domain-sml-integration-panel>
</mat-tab>
<mat-tab label="Members"> Content 3</mat-tab>
</mat-tab-group>
</data-panel>
</div>
<ng-template #searchDomainPanel>
<mat-form-field id="domain-filter">
<mat-label>Filter Domain by domain code</mat-label>
<input matInput (keyup)="applyDomainFilter($event)" placeholder="Domain code" #inputDomainFilter>
</mat-form-field>
<mat-toolbar>
<mat-toolbar-row class="mat-elevation-z5">
<button mat-raised-button mat-flat-button color="primary"
(click)="onCreateDomainClicked()">Create domain
</button>
<button mat-raised-button
[disabled]="!selected"
color="primary"
(click)="onDeleteSelectedDomainClicked()">
<mat-icon>delete</mat-icon>
<span>Delete selected</span>
</button>
</mat-toolbar-row>
</mat-toolbar>
<table class="mat-elevation-z2" id="admin-domain-table" mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="domainCode">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Domain code</th>
<td mat-cell *matCellDef="let row" [matTooltip]="row.domainCode">{{row.domainCode}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let odd = odd; let row; columns: displayedColumns;"
(click)="domainSelected(row)"
[ngClass]="{'datatable-row-selected': row==selected,'datatable-row-odd': odd}"
></tr>
<tr class="mat-row" *matNoDataRow>
<td *ngIf="inputDomainFilter.value;else noDataFound" class="mat-cell" colspan="2">No data matching the filter "{{inputDomainFilter.value}}
"
</td>
<ng-template #noDataFound>
<td class="mat-cell" colspan="2">No data</td>
</ng-template>
</tr>
</table>
<mat-paginator class="mat-elevation-z2" id="extension-paginator"
[hidePageSize]="true"
[showFirstLastButtons]="true"
[pageSize]="5" aria-label="Select page"></mat-paginator>
</ng-template>
-->
import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
import {MatTableDataSource} from "@angular/material/table";
import {MatPaginator} from "@angular/material/paginator";
import {MatSort} from "@angular/material/sort";
import {AdminDomainService} from "./admin-domain.service";
import {AlertMessageService} from "../../common/alert-message/alert-message.service";
import {ConfirmationDialogComponent} from "../../common/dialogs/confirmation-dialog/confirmation-dialog.component";
import {MatDialog} from "@angular/material/dialog";
import {EntityStatus} from "../../common/model/entity-status.model";
import {DomainRo} from "../domain/domain-ro.model";
import {AdminKeystoreService} from "../admin-keystore/admin-keystore.service";
import {CertificateRo} from "../user/certificate-ro.model";
import {BeforeLeaveGuard} from "../../window/sidenav/navigation-on-leave-guard";
@Component({
moduleId: module.id,
templateUrl: './admin-domain.component.html',
styleUrls: ['./admin-domain.component.css']
})
export class AdminDomainComponent implements OnInit, AfterViewInit, BeforeLeaveGuard {
displayedColumns: string[] = ['domainCode'];
dataSource: MatTableDataSource<DomainRo> = new MatTableDataSource();
selected?: DomainRo;
domainList: DomainRo[];
keystoreCertificates: CertificateRo[];
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
constructor(private domainService: AdminDomainService,
private keystoreService: AdminKeystoreService,
private alertService: AlertMessageService,
private dialog: MatDialog) {
domainService.onDomainUpdatedEvent().subscribe(updatedTruststore => {
this.updateDomainList(updatedTruststore);
}
);
domainService.onDomainEntryUpdatedEvent().subscribe(updatedCertificate => {
this.updateDomain(updatedCertificate);
}
);
keystoreService.onKeystoreUpdatedEvent().subscribe(keystoreCertificates => {
this.keystoreCertificates = keystoreCertificates;
}
);
domainService.getDomains();
keystoreService.getKeystoreData();
}
ngOnInit(): void {
// filter predicate for search the domain
this.dataSource.filterPredicate =
(data: DomainRo, filter: string) => {
return !filter || -1 != data.domainCode.toLowerCase().indexOf(filter.trim().toLowerCase())
};
}
ngAfterViewInit() {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
updateDomainList(domainList: DomainRo[]) {
this.domainList = domainList
this.dataSource.data = this.domainList;
}
updateDomain(domain: DomainRo) {
if (domain == null) {
return;
}
if (domain.status == EntityStatus.NEW) {
this.domainList.push(domain)
this.selected = domain;
this.alertService.success("Domain: [" + domain.domainCode + "] was created!");
} else if (domain.status == EntityStatus.REMOVED) {
this.alertService.success("Domain: [" + domain.domainCode + "] is removed!");
this.selected = null;
this.domainList = this.domainList.filter(item => item.domainCode !== domain.domainCode)
} else if (domain.status == EntityStatus.ERROR) {
this.alertService.error("ERROR: " + domain.actionMessage);
}
this.dataSource.data = this.domainList;
}
applyDomainFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
if (this.dataSource.paginator) {
this.dataSource.paginator.firstPage();
}
}
onCreateDomainClicked() {
}
onDeleteSelectedDomainClicked() {
this.dialog.open(ConfirmationDialogComponent, {
data: {
title: "Delete domain " + this.selected.domainCode + " from DomiSMP",
description: "Action will permanently delete domain! Do you wish to continue?"
}
}).afterClosed().subscribe(result => {
if (result) {
this.deleteDomain(this.selected);
}
});
}
deleteDomain(domain: DomainRo) {
}
public domainSelected(selected: DomainRo) {
this.selected = selected;
}
isDirty(): boolean {
return false;
}
}
import {Injectable} from '@angular/core';
import {Observable, Subject} from 'rxjs';
import {HttpClient} from '@angular/common/http';
import {SecurityService} from "../../security/security.service";
import {AlertMessageService} from "../../common/alert-message/alert-message.service";
import {DomainRo} from "../domain/domain-ro.model";
import {User} from "../../security/user.model";
import {SmpConstants} from "../../smp.constants";
@Injectable()
export class AdminDomainService {
private domainUpdateSubject = new Subject<DomainRo[]>();
private domainEntryUpdateSubject = new Subject<DomainRo>();
constructor(
private http: HttpClient,
private securityService: SecurityService,
private alertService: AlertMessageService) {
}
public getDomains() {
const currentUser: User = this.securityService.getCurrentUser();
this.http.get<DomainRo[]>(SmpConstants.REST_INTERNAL_DOMAIN_MANAGE
.replace(SmpConstants.PATH_PARAM_ENC_USER_ID, currentUser.userId))
.subscribe((result: DomainRo[]) => {
this.notifyDomainsUpdated(result);
}, (error: any) => {
this.alertService.error(error.error?.errorDescription)
});
}
notifyDomainsUpdated(res: DomainRo[]) {
this.domainUpdateSubject.next(res);
}
notifyDomainEntryUpdated(res: DomainRo) {
this.domainEntryUpdateSubject.next(res);
}
onDomainUpdatedEvent(): Observable<DomainRo[]> {
return this.domainUpdateSubject.asObservable();
}
onDomainEntryUpdatedEvent(): Observable<DomainRo> {
return this.domainEntryUpdateSubject.asObservable();
}
}
<div id="domain-panel" class="mat-elevation-z2" >
<form [formGroup]="domainForm" (ngSubmit)="onSaveClicked()">
<h3>Domain details</h3>
<mat-form-field style="width:100%">
<mat-label>Domain Code</mat-label>
<input matInput placeholder="Domain Code"
id="domainCode_id" #domainCode
matTooltip="The SMP's domain code. The code must be unique and is used in HTTP header 'Domain' or URL path sequence when retrieving /creating the resource using the webservice API"
formControlName="domainCode" maxlength="63"
(keydown)="onFieldKeyPressed('domainCode', 'domainCodeTimeout')"
required>
<mat-hint align="end">For WS API integration: the Domain property</mat-hint>
<div
*ngIf="(!editMode && domainForm.controls['domainCode'].touched || editMode) && domainForm.controls['domainCode'].hasError('pattern')"
style="color:red; font-size: 70%">
Domain code must contain only chars and numbers and must be less than 63 chars long.
</div>
<div
*ngIf="!!fieldWarningTimeoutMap.domainCodeTimeout"
style="color:darkorange; font-size: 70%">
Domain code must contain only chars and numbers and must be less than 63 chars long.
</div>
<div
*ngIf="(!editMode && domainForm.controls['domainCode'].touched || editMode) && domainForm.controls['domainCode'].hasError('notInList')"
style="color:red; font-size: 70%">
The Domain code already exists!
</div>
</mat-form-field>
<mat-form-field style="width:100%">
<input matInput placeholder="SML domain"
matTooltip="The domain-specific part of the SML DNS zone (e.g., ‘mydomain’ for mydomain.sml.dns.zone or leave empty for sml.dns.zone). Note: has informative value only, SML DNS zone used for publishing is based on SML configuration."
name="smlSubdomain"
(keydown)="onFieldKeyPressed('domainCode', 'smlSubdomainTimeout')"
id="smldomain_id"
formControlName="smlSubdomain" maxlength="63">
<mat-hint align="end">The domain-specific part of the SML DNS zone (e.g., ‘mydomain’ for
mydomain.sml.dns.zone).
</mat-hint>
<div
*ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode)
&& domainForm.controls['smlSubdomain'].hasError('pattern')"
style="color:red; font-size: 70%">
SML domain should be up to 63 characters long, should only contain alphanumeric and hyphen characters,
should not start with a digit nor a hyphen and should not end with a hyphen.
</div>
<div
*ngIf="!!fieldWarningTimeoutMap.smlSubdomainTimeout"
style="color:darkorange; font-size: 70%">
SML domain should be up to 63 characters long, should only contain alphanumeric and hyphen characters,
should not start with a digit nor a hyphen and should not end with a hyphen.
</div>
<div
*ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode) && domainForm.controls['smlSubdomain'].hasError('notInList')"
style="color:red; font-size: 70%">
The SML subdomain is already defined!
</div>
<div
*ngIf="(!editMode && domainForm.controls['smlSubdomain'].hasError('blankDomainError'))"
style="color:red; font-size: 70%">
Domain with empty sml subdomain already exists!
</div>
</mat-form-field>
<mat-form-field style="width:100%">
<mat-select placeholder="Response signature Certificate (Signature CertAlias)"
formControlName="signatureKeyAlias"
name="cert"
matTooltip="Certificate is used for signing REST responses for the domain."
id="signatureKeyAlias_id">
<mat-option [value]="''">Choose certificate for signing soap response</mat-option>
<mat-option *ngFor="let cert of keystoreCertificates" [value]="cert.alias">
{{cert.alias}} ({{cert.certificateId}})
</mat-option>
</mat-select>
<mat-hint align="end">Empty value will cause that Resource responses will not be signed by SMP!
</mat-hint>
</mat-form-field>
</form>
</div>
#domain-panel {
padding: 1em;
}
import {Component, Input,} from '@angular/core';
import {DomainRo} from "../../domain/domain-ro.model";
import {AbstractControl, FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
import {AdminDomainService} from "../admin-domain.service";
import {AlertMessageService} from "../../../common/alert-message/alert-message.service";
import {MatDialog} from "@angular/material/dialog";
import {CertificateRo} from "../../user/certificate-ro.model";
@Component({
selector: 'domain-panel',
templateUrl: './domain-panel.component.html',
styleUrls: ['./domain-panel.component.scss']
})
export class DomainPanelComponent {
// Request from test team can not automate test if this is less than 10 seconds :(. Initialy it was 2s
readonly warningTimeout : number = 10000;
readonly domainCodePattern = '^[a-zA-Z0-9]{1,63}$';
readonly dnsDomainPattern = '^([a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?){0,63}$';
readonly subDomainPattern = this.dnsDomainPattern;
readonly smpIdDomainPattern = this.dnsDomainPattern;
fieldWarningTimeoutMap = {
domainCodeTimeout: null,
smlSubdomainTimeout: null,
};
_domain: DomainRo = null;
domainForm: FormGroup;
editMode: boolean;
createMode: boolean;
@Input() keystoreCertificates:CertificateRo[];
@Input() currentDomains:DomainRo[];
notInList(list: string[], exception: string) {
if (!list || !exception) {
return (c: AbstractControl): { [key: string]: any } => {
return null;
}
}
return (c: AbstractControl): { [key: string]: any } => {
if (c.value && c.value !== exception && list.includes(c.value))
return {'notInList': {valid: false}};
return null;
}
}
/**
* Show warning if domain code exceed the maxlength.
* @param value
*/
onFieldKeyPressed(controlName: string, showTheWarningReference:string) {
let value = this.domainForm.get(controlName).value
if (!!value && value.length >= 63 && !this.fieldWarningTimeoutMap[showTheWarningReference]) {
this.fieldWarningTimeoutMap[showTheWarningReference] = setTimeout(() => {
this.fieldWarningTimeoutMap[showTheWarningReference] = null;
}, this.warningTimeout);
}
}
constructor(private domainService: AdminDomainService,
private alertService: AlertMessageService,
private dialog: MatDialog,
private formBuilder: FormBuilder) {
this.domainForm = formBuilder.group({
'domainCode': new FormControl({value: '', readonly: this.createMode}, [Validators.pattern(this.domainCodePattern),
this.notInList(this.currentDomains?.map(a => a.domainCode), this._domain?.domainCode)]),
'smlSubdomain': new FormControl({value: '', readonly: this.editMode}, [Validators.pattern(this.subDomainPattern),
this.notInList(this.currentDomains?.map(a => a.smlSubdomain), this._domain?.smlSubdomain)]),
'signatureKeyAlias': new FormControl({value: '', readonly: this.editMode}),
});
}
get domain(): DomainRo {
return this._domain;
}
@Input() set domain(value: DomainRo) {
this._domain = value;
if (!!value) {
this.domainForm.controls['domainCode'].setValue(this._domain.domainCode);
this.domainForm.controls['smlSubdomain'].setValue(this._domain.smlSubdomain);
this.domainForm.controls['smlSmpId'].setValue(this._domain.smlSmpId);
this.domainForm.controls['smlClientKeyAlias'].setValue(this._domain.smlClientKeyAlias);
this.domainForm.controls['smlClientCertHeader'].setValue(this._domain.smlClientCertHeader);
this.domainForm.controls['signatureKeyAlias'].setValue(this._domain.signatureKeyAlias);
this.domainForm.controls['smlRegistered'].setValue(this._domain.smlRegistered);
this.domainForm.controls['smlClientCertAuth'].setValue(this._domain.smlClientCertAuth);
} else {
this.domainForm.controls['domainCode'].setValue("");
this.domainForm.controls['smlSubdomain'].setValue("");
this.domainForm.controls['smlSmpId'].setValue("");
this.domainForm.controls['smlClientKeyAlias'].setValue("");
this.domainForm.controls['smlClientCertHeader'].setValue("");
this.domainForm.controls['signatureKeyAlias'].setValue("");
this.domainForm.controls['smlRegistered'].setValue("");
this.domainForm.controls['smlClientCertAuth'].setValue("");
}
this.domainForm.markAsPristine();
}
onSaveClicked(){
}
}
<form [formGroup]="domainForm" (ngSubmit)="onSaveClicked()">
<div id="domain-resource-type-panel" class="mat-elevation-z2">
<h3>Domain resource type configuration</h3>
<mat-selection-list #shoes>
<mat-list-option *ngFor="let resDef of domiSMPResourceDefinitions">
{{resDef.identifier}}
</mat-list-option>
</mat-selection-list>
</div>
</form>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment