mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
SG-680 - DomainAddEditDialog - Unique domain name enforcement implemented
This commit is contained in:
@@ -5568,6 +5568,9 @@
|
|||||||
"domainVerified": {
|
"domainVerified": {
|
||||||
"message": "Domain verified"
|
"message": "Domain verified"
|
||||||
},
|
},
|
||||||
|
"duplicateDomainError": {
|
||||||
|
"message": "You can't claim the same domain twice."
|
||||||
|
},
|
||||||
"domainNotVerified": {
|
"domainNotVerified": {
|
||||||
"message": "$DOMAIN$ not verified. Check your DNS record.",
|
"message": "$DOMAIN$ not verified. Check your DNS record.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
@@ -5577,5 +5580,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Utils } from "@bitwarden/common/misc/utils";
|
|||||||
import { OrganizationDomainRequest } from "@bitwarden/common/services/organization-domain/requests/organization-domain.request";
|
import { OrganizationDomainRequest } from "@bitwarden/common/services/organization-domain/requests/organization-domain.request";
|
||||||
|
|
||||||
import { domainNameValidator } from "./domain-name.validator";
|
import { domainNameValidator } from "./domain-name.validator";
|
||||||
|
import { uniqueInArrayValidator } from "./unique-in-array.validator";
|
||||||
export interface DomainAddEditDialogData {
|
export interface DomainAddEditDialogData {
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
orgDomain: OrganizationDomainResponse;
|
orgDomain: OrganizationDomainResponse;
|
||||||
@@ -26,11 +27,17 @@ export class DomainAddEditDialogComponent implements OnInit {
|
|||||||
disablePadding = false;
|
disablePadding = false;
|
||||||
|
|
||||||
// TODO: should invalidDomainNameMessage have something like: "'https://', 'http://', or 'www.' domain prefixes not allowed."
|
// TODO: should invalidDomainNameMessage have something like: "'https://', 'http://', or 'www.' domain prefixes not allowed."
|
||||||
// TODO: write separate uniqueIn validator w/ translated msg: "You can’t claim the same domain twice."
|
|
||||||
domainForm: FormGroup = this.formBuilder.group({
|
domainForm: FormGroup = this.formBuilder.group({
|
||||||
domainName: [
|
domainName: [
|
||||||
"",
|
"",
|
||||||
[Validators.required, domainNameValidator(this.i18nService.t("invalidDomainNameMessage"))],
|
[
|
||||||
|
Validators.required,
|
||||||
|
domainNameValidator(this.i18nService.t("invalidDomainNameMessage")),
|
||||||
|
uniqueInArrayValidator(
|
||||||
|
this.data.existingDomainNames,
|
||||||
|
this.i18nService.t("duplicateDomainError")
|
||||||
|
),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
txt: [{ value: null, disabled: true }],
|
txt: [{ value: null, disabled: true }],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms";
|
||||||
|
export function uniqueInArrayValidator(values: Array<string>, errorMessage: string): ValidatorFn {
|
||||||
|
return (control: AbstractControl): ValidationErrors | null => {
|
||||||
|
const value = control.value;
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lowerTrimmedValue = value.toLowerCase().trim();
|
||||||
|
|
||||||
|
// check if the entered value is unique
|
||||||
|
if (values.some((val) => val.toLowerCase().trim() === lowerTrimmedValue)) {
|
||||||
|
return {
|
||||||
|
nonUniqueValue: {
|
||||||
|
message: errorMessage,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute, Params } from "@angular/router";
|
import { ActivatedRoute, Params } from "@angular/router";
|
||||||
import { concatMap, Observable, Subject, takeUntil } from "rxjs";
|
import { concatMap, Observable, Subject, take, takeUntil } from "rxjs";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
@@ -68,7 +68,7 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
|||||||
const domainAddEditDialogData: DomainAddEditDialogData = {
|
const domainAddEditDialogData: DomainAddEditDialogData = {
|
||||||
organizationId: this.organizationId,
|
organizationId: this.organizationId,
|
||||||
orgDomain: null,
|
orgDomain: null,
|
||||||
existingDomainNames: [],
|
existingDomainNames: this.getExistingDomainNames(),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dialogService.open(DomainAddEditDialogComponent, {
|
this.dialogService.open(DomainAddEditDialogComponent, {
|
||||||
@@ -80,7 +80,7 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
|||||||
const domainAddEditDialogData: DomainAddEditDialogData = {
|
const domainAddEditDialogData: DomainAddEditDialogData = {
|
||||||
organizationId: this.organizationId,
|
organizationId: this.organizationId,
|
||||||
orgDomain: orgDomain,
|
orgDomain: orgDomain,
|
||||||
existingDomainNames: [],
|
existingDomainNames: this.getExistingDomainNames(),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dialogService.open(DomainAddEditDialogComponent, {
|
this.dialogService.open(DomainAddEditDialogComponent, {
|
||||||
@@ -88,6 +88,15 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getExistingDomainNames(): Array<string> {
|
||||||
|
let existingDomainNames: string[];
|
||||||
|
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||||
|
this.orgDomains$.pipe(take(1)).subscribe((orgDomains: Array<OrganizationDomainResponse>) => {
|
||||||
|
existingDomainNames = orgDomains.map((o) => o.domainName);
|
||||||
|
});
|
||||||
|
return existingDomainNames;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.componentDestroyed$.next();
|
this.componentDestroyed$.next();
|
||||||
this.componentDestroyed$.complete();
|
this.componentDestroyed$.complete();
|
||||||
|
|||||||
Reference in New Issue
Block a user