Commit 9c5b353a17a21d3d392afc2e3b43d2849100cf8f

Authored by Vladyslav Prykhodko
1 parent fe00a9bd

UI: Added validation unique domain

... ... @@ -59,30 +59,31 @@
59 59 <section *ngFor="let domainInfo of clientDomainInfos(domain).controls; let n = index; trackBy: trackByParams"
60 60 class="domains-list">
61 61 <div [formGroupName]="n" fxLayout="row" fxLayoutGap="8px">
62   - <div fxLayout="row" fxLayout.xs="column" fxFlex fxLayoutGap="8px">
63   - <div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px" fxFlex.gt-xs="50">
64   - <mat-form-field fxFlex="30" fxFlex.xs class="mat-block">
65   - <mat-label translate>admin.oauth2.protocol</mat-label>
66   - <mat-select formControlName="scheme">
67   - <mat-option *ngFor="let protocol of protocols" [value]="protocol">
68   - {{ domainSchemaTranslations.get(protocol) | translate | uppercase }}
69   - </mat-option>
70   - </mat-select>
71   - </mat-form-field>
72   -
73   - <mat-form-field fxFlex class="mat-block">
74   - <mat-label translate>admin.domain-name</mat-label>
75   - <input matInput formControlName="name" required>
76   - <mat-error *ngIf="domainInfo.get('name').hasError('pattern')">
77   - {{ 'admin.error-verification-url' | translate }}
78   - </mat-error>
79   - <mat-error *ngIf="domainInfo.get('name').hasError('unique')">
80   - {{ 'admin.domain-name-unique' | translate }}
81   - </mat-error>
82   - </mat-form-field>
  62 + <div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px">
  63 + <div fxLayout="column" fxFlex.sm="60" fxFlex.gt-sm="50">
  64 + <div fxLayout="row" fxLayout.xs="column" fxLayoutGap="8px">
  65 + <mat-form-field fxFlex="30" fxFlex.xs class="mat-block">
  66 + <mat-label translate>admin.oauth2.protocol</mat-label>
  67 + <mat-select formControlName="scheme">
  68 + <mat-option *ngFor="let protocol of protocols" [value]="protocol">
  69 + {{ domainSchemaTranslations.get(protocol) | translate | uppercase }}
  70 + </mat-option>
  71 + </mat-select>
  72 + </mat-form-field>
  73 + <mat-form-field fxFlex class="mat-block">
  74 + <mat-label translate>admin.domain-name</mat-label>
  75 + <input matInput formControlName="name" required>
  76 + <mat-error *ngIf="domainInfo.get('name').hasError('pattern')">
  77 + {{ 'admin.error-verification-url' | translate }}
  78 + </mat-error>
  79 + </mat-form-field>
  80 + </div>
  81 + <mat-error *ngIf="domainInfo.hasError('unique')">
  82 + {{ 'admin.domain-name-unique' | translate }}
  83 + </mat-error>
83 84 </div>
84 85
85   - <div fxFlex>
  86 + <div fxFlex fxLayout="column">
86 87 <mat-form-field fxFlex class="mat-block">
87 88 <mat-label translate>admin.oauth2.redirect-uri-template</mat-label>
88 89 <input matInput [value]="redirectURI(domainInfo)" readonly>
... ... @@ -94,8 +95,7 @@
94 95 </button>
95 96 </mat-form-field>
96 97
97   - <mat-form-field fxFlex *ngIf="domainInfo.get('scheme').value === 'MIXED'"
98   - class="mat-block">
  98 + <mat-form-field fxFlex *ngIf="domainInfo.get('scheme').value === 'MIXED'" class="mat-block">
99 99 <mat-label></mat-label>
100 100 <input matInput [value]="redirectURIMixed(domainInfo)" readonly>
101 101 <button mat-icon-button color="primary" matSuffix type="button"
... ... @@ -106,7 +106,6 @@
106 106 </button>
107 107 </mat-form-field>
108 108 </div>
109   -
110 109 </div>
111 110
112 111 <div fxLayout="column" fxLayoutAlign="center start">
... ...
... ... @@ -178,13 +178,14 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
178 178 }
179 179 }
180 180
181   - private uniqueDomainValidator(control: AbstractControl): { [key: string]: boolean } | null {
182   - if (control.parent?.parent?.value) {
183   - const domain = control.value;
184   - const listProtocols = control.parent.parent.value
  181 + private uniqueDomainValidator(control: FormGroup): { [key: string]: boolean } | null {
  182 + if (control.parent?.value) {
  183 + const domain = control.value.name;
  184 + const listProtocols = control.parent.getRawValue()
185 185 .filter((domainInfo) => domainInfo.name === domain)
186 186 .map((domainInfo) => domainInfo.scheme);
187   - if (listProtocols.length > 1 && listProtocols.indexOf(DomainSchema.MIXED) > -1) {
  187 + if (listProtocols.length > 1 && listProtocols.indexOf(DomainSchema.MIXED) > -1 ||
  188 + new Set(listProtocols).size !== listProtocols.length) {
188 189 return {unique: true};
189 190 }
190 191 }
... ... @@ -228,10 +229,9 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
228 229 const domain = this.fb.group({
229 230 name: [domainInfo ? domainInfo.name : this.window.location.hostname, [
230 231 Validators.required,
231   - Validators.pattern('((?![:/]).)*$'),
232   - this.uniqueDomainValidator]],
  232 + Validators.pattern('((?![:/]).)*$')]],
233 233 scheme: [domainInfo?.scheme ? domainInfo.scheme : DomainSchema.HTTPS, Validators.required]
234   - });
  234 + }, {validators: this.uniqueDomainValidator});
235 235 return domain;
236 236 }
237 237
... ... @@ -288,6 +288,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
288 288 this.changeMapperConfigType(clientRegistration, registrationData.mapperConfig.type, registrationData.mapperConfig);
289 289 } else {
290 290 this.changeMapperConfigType(clientRegistration, MapperConfigType.BASIC);
  291 + this.setProviderDefaultValue(defaultProviderName, clientRegistration);
291 292 }
292 293
293 294 this.subscriptions.push(clientRegistration.get('mapperConfig.type').valueChanges.subscribe((value) => {
... ... @@ -296,33 +297,37 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
296 297
297 298 this.subscriptions.push(clientRegistration.get('additionalInfo.providerName').valueChanges.subscribe((provider) => {
298 299 (clientRegistration.get('scope') as FormArray).clear();
299   - if (provider === 'Custom') {
300   - const defaultSettings = {...this.defaultProvider, ...{id: clientRegistration.get('id').value}};
301   - clientRegistration.reset(defaultSettings, {emitEvent: false});
302   - clientRegistration.get('accessTokenUri').enable();
303   - clientRegistration.get('authorizationUri').enable();
304   - clientRegistration.get('jwkSetUri').enable();
305   - clientRegistration.get('userInfoUri').enable();
306   - } else {
307   - const template = this.templates.get(provider);
308   - delete template.id;
309   - delete template.additionalInfo;
310   - template.clientId = '';
311   - template.clientSecret = '';
312   - template.scope.forEach(() => {
313   - (clientRegistration.get('scope') as FormArray).push(this.fb.control(''));
314   - });
315   - clientRegistration.get('accessTokenUri').disable();
316   - clientRegistration.get('authorizationUri').disable();
317   - clientRegistration.get('jwkSetUri').disable();
318   - clientRegistration.get('userInfoUri').disable();
319   - clientRegistration.patchValue(template, {emitEvent: false});
320   - }
  300 + this.setProviderDefaultValue(provider, clientRegistration);
321 301 }));
322 302
323 303 return clientRegistration;
324 304 }
325 305
  306 + private setProviderDefaultValue(provider: string, clientRegistration: FormGroup) {
  307 + if (provider === 'Custom') {
  308 + const defaultSettings = {...this.defaultProvider, ...{id: clientRegistration.get('id').value}};
  309 + clientRegistration.reset(defaultSettings, {emitEvent: false});
  310 + clientRegistration.get('accessTokenUri').enable();
  311 + clientRegistration.get('authorizationUri').enable();
  312 + clientRegistration.get('jwkSetUri').enable();
  313 + clientRegistration.get('userInfoUri').enable();
  314 + } else {
  315 + const template = this.templates.get(provider);
  316 + delete template.id;
  317 + delete template.additionalInfo;
  318 + template.clientId = '';
  319 + template.clientSecret = '';
  320 + template.scope.forEach(() => {
  321 + (clientRegistration.get('scope') as FormArray).push(this.fb.control(''));
  322 + });
  323 + clientRegistration.get('accessTokenUri').disable();
  324 + clientRegistration.get('authorizationUri').disable();
  325 + clientRegistration.get('jwkSetUri').disable();
  326 + clientRegistration.get('userInfoUri').disable();
  327 + clientRegistration.patchValue(template, {emitEvent: false});
  328 + }
  329 + }
  330 +
326 331 private changeMapperConfigType(control: AbstractControl, type: MapperConfigType, predefinedValue?: MapperConfig) {
327 332 const mapperConfig = control.get('mapperConfig') as FormGroup;
328 333 if (type === MapperConfigType.BASIC) {
... ...
... ... @@ -121,7 +121,7 @@
121 121 "minimum-max-failed-login-attempts-range": "Maximum number of failed login attempts can't be negative",
122 122 "user-lockout-notification-email": "In case user account lockout, send notification to email",
123 123 "domain-name": "Domain name",
124   - "domain-name-unique": "Domain name need to unique for the system.",
  124 + "domain-name-unique": "Domain name and protocol need to unique.",
125 125 "error-verification-url": "A domain name shouldn't contain symbols '/' and ':'. Example: thingsboard.io",
126 126 "oauth2": {
127 127 "access-token-uri": "Access token URI",
... ...