From 44b0a1100f19225fef098785db92d78af5ef75e1 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 10 Sep 2020 15:14:37 +0300 Subject: [PATCH] Add new device credentials MQTT_BASIC --- .../device-credentials-dialog.component.html | 31 +++++++ .../device-credentials-dialog.component.ts | 85 +++++++++++++++++-- ui-ngx/src/app/shared/models/device.models.ts | 14 ++- .../assets/locale/locale.constant-en_US.json | 6 ++ 4 files changed, 126 insertions(+), 10 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.html b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.html index 1cf9911aa8..f1b5b442ce 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.html @@ -58,6 +58,37 @@ {{ 'device.rsa-key-required' | translate }} +
+ + device.client-id + + + {{ 'device.client-id-pattern' | translate }} + + + + device.user-name + + + {{ 'device.user-name-required' | translate }} + + + + device.password + + + + + {{ 'device.client-id-or-user-name-necessary' | translate }} + +
diff --git a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.ts index ccbe1affe8..4cfcc90a2a 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.ts @@ -19,9 +19,23 @@ import { ErrorStateMatcher } from '@angular/material/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms'; +import { + FormBuilder, + FormControl, + FormGroup, + FormGroupDirective, + NgForm, + ValidationErrors, + ValidatorFn, + Validators +} from '@angular/forms'; import { DeviceService } from '@core/http/device.service'; -import { credentialTypeNames, DeviceCredentials, DeviceCredentialsType } from '@shared/models/device.models'; +import { + credentialTypeNames, + DeviceCredentialMQTTBasic, + DeviceCredentials, + DeviceCredentialsType +} from '@shared/models/device.models'; import { DialogComponent } from '@shared/components/dialog.component'; import { Router } from '@angular/router'; @@ -53,6 +67,8 @@ export class DeviceCredentialsDialogComponent extends credentialTypeNamesMap = credentialTypeNames; + hidePassword = true; + constructor(protected store: Store, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: DeviceCredentialsDialogData, @@ -69,7 +85,12 @@ export class DeviceCredentialsDialogComponent extends this.deviceCredentialsFormGroup = this.fb.group({ credentialsType: [DeviceCredentialsType.ACCESS_TOKEN], credentialsId: [''], - credentialsValue: [''] + credentialsValue: [''], + credentialsBasic: this.fb.group({ + clientId: ['', [Validators.pattern(/^[A-Za-z0-9]+$/)]], + userName: [''], + password: [''] + }, {validators: this.atLeastOne(Validators.required, ['clientId', 'userName'])}) }); if (this.isReadOnly) { this.deviceCredentialsFormGroup.disable({emitEvent: false}); @@ -89,10 +110,17 @@ export class DeviceCredentialsDialogComponent extends this.deviceService.getDeviceCredentials(this.data.deviceId).subscribe( (deviceCredentials) => { this.deviceCredentials = deviceCredentials; + let credentialsValue = deviceCredentials.credentialsValue; + let credentialsBasic = {clientId: null, userName: null, password: null}; + if (deviceCredentials.credentialsType === DeviceCredentialsType.MQTT_BASIC) { + credentialsValue = null; + credentialsBasic = deviceCredentials.credentialsValue as DeviceCredentialMQTTBasic; + } this.deviceCredentialsFormGroup.patchValue({ credentialsType: deviceCredentials.credentialsType, credentialsId: deviceCredentials.credentialsId, - credentialsValue: deviceCredentials.credentialsValue + credentialsValue, + credentialsBasic }); this.updateValidators(); } @@ -100,12 +128,16 @@ export class DeviceCredentialsDialogComponent extends } credentialsTypeChanged(): void { - this.deviceCredentialsFormGroup.patchValue( - {credentialsId: null, credentialsValue: null}, {emitEvent: true}); + this.deviceCredentialsFormGroup.patchValue({ + credentialsId: null, + credentialsValue: null, + credentialsBasic: {clientId: '', userName: '', password: ''} + }, {emitEvent: true}); this.updateValidators(); } updateValidators(): void { + this.hidePassword = true; const crendetialsType = this.deviceCredentialsFormGroup.get('credentialsType').value as DeviceCredentialsType; switch (crendetialsType) { case DeviceCredentialsType.ACCESS_TOKEN: @@ -113,27 +145,66 @@ export class DeviceCredentialsDialogComponent extends this.deviceCredentialsFormGroup.get('credentialsId').updateValueAndValidity(); this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([]); this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity(); + this.deviceCredentialsFormGroup.get('credentialsBasic').disable(); break; case DeviceCredentialsType.X509_CERTIFICATE: this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([Validators.required]); this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity(); this.deviceCredentialsFormGroup.get('credentialsId').setValidators([]); this.deviceCredentialsFormGroup.get('credentialsId').updateValueAndValidity(); + this.deviceCredentialsFormGroup.get('credentialsBasic').disable(); break; + case DeviceCredentialsType.MQTT_BASIC: + this.deviceCredentialsFormGroup.get('credentialsBasic').enable(); + this.deviceCredentialsFormGroup.get('credentialsBasic').updateValueAndValidity(); + this.deviceCredentialsFormGroup.get('credentialsId').setValidators([]); + this.deviceCredentialsFormGroup.get('credentialsId').updateValueAndValidity(); + this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([]); + this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity(); } } + private atLeastOne(validator: ValidatorFn, controls: string[] = null) { + return (group: FormGroup): ValidationErrors | null => { + if (!controls) { + controls = Object.keys(group.controls); + } + const hasAtLeastOne = group?.controls && controls.some(k => !validator(group.controls[k])); + + return hasAtLeastOne ? null : {atLeastOne: true}; + }; + } + cancel(): void { this.dialogRef.close(null); } save(): void { this.submitted = true; - this.deviceCredentials = {...this.deviceCredentials, ...this.deviceCredentialsFormGroup.value}; + const deviceCredentialsValue = this.deviceCredentialsFormGroup.value; + if (deviceCredentialsValue.credentialsType === DeviceCredentialsType.MQTT_BASIC) { + deviceCredentialsValue.credentialsValue = deviceCredentialsValue.credentialsBasic; + } + delete deviceCredentialsValue.credentialsBasic; + this.deviceCredentials = {...this.deviceCredentials, ...deviceCredentialsValue}; this.deviceService.saveDeviceCredentials(this.deviceCredentials).subscribe( (deviceCredentials) => { this.dialogRef.close(deviceCredentials); } ); } + + passwordChanged() { + const value = this.deviceCredentialsFormGroup.get('credentialsBasic.password').value; + if (value !== '') { + this.deviceCredentialsFormGroup.get('credentialsBasic.userName').setValidators([Validators.required]); + if (this.deviceCredentialsFormGroup.get('credentialsBasic.userName').untouched) { + this.deviceCredentialsFormGroup.get('credentialsBasic.userName').markAsTouched({onlySelf: true}); + } + this.deviceCredentialsFormGroup.get('credentialsBasic.userName').updateValueAndValidity(); + } else { + this.deviceCredentialsFormGroup.get('credentialsBasic.userName').setValidators([]); + this.deviceCredentialsFormGroup.get('credentialsBasic.userName').updateValueAndValidity(); + } + } } diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index 264ec6c70d..a71c5db36c 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -292,13 +292,15 @@ export interface DeviceInfo extends Device { export enum DeviceCredentialsType { ACCESS_TOKEN = 'ACCESS_TOKEN', - X509_CERTIFICATE = 'X509_CERTIFICATE' + X509_CERTIFICATE = 'X509_CERTIFICATE', + MQTT_BASIC = 'MQTT_BASIC' } export const credentialTypeNames = new Map( [ [DeviceCredentialsType.ACCESS_TOKEN, 'Access token'], - [DeviceCredentialsType.X509_CERTIFICATE, 'X.509 Certificate'], + [DeviceCredentialsType.X509_CERTIFICATE, 'MQTT X.509'], + [DeviceCredentialsType.MQTT_BASIC, 'MQTT Basic'] ] ); @@ -306,7 +308,13 @@ export interface DeviceCredentials extends BaseData { deviceId: DeviceId; credentialsType: DeviceCredentialsType; credentialsId: string; - credentialsValue: string; + credentialsValue: string | DeviceCredentialMQTTBasic; +} + +export interface DeviceCredentialMQTTBasic { + clientId: string; + userName: string; + password: string; } export interface DeviceSearchQuery extends EntitySearchQuery { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 9a41d1bf2a..91d78a4147 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -718,6 +718,12 @@ "access-token-invalid": "Access token length must be from 1 to 20 characters.", "rsa-key": "RSA public key", "rsa-key-required": "RSA public key is required.", + "client-id": "Client ID", + "client-id-pattern": "Contains invalid character.", + "user-name": "User Name", + "user-name-required": "User Name is required.", + "client-id-or-user-name-necessary": "Client ID and/or User Name are necessary", + "password": "Password", "secret": "Secret", "secret-required": "Secret is required.", "device-type": "Device type",