diff --git a/libs/common/src/abstractions/organization-domain/org-domain-api.service.abstraction.ts b/libs/common/src/abstractions/organization-domain/org-domain-api.service.abstraction.ts new file mode 100644 index 00000000000..fe300b7c24e --- /dev/null +++ b/libs/common/src/abstractions/organization-domain/org-domain-api.service.abstraction.ts @@ -0,0 +1,12 @@ +import { OrganizationDomainResponse } from "../../models/response/organization-domain.response"; + +export class OrgDomainApiServiceAbstraction { + getByOrgId: (orgId: string) => Promise; + getByOrgIdAndOrgDomainId: ( + orgId: string, + orgDomainId: string + ) => Promise; + post: (orgId: string, orgDomain: OrganizationDomainResponse) => Promise; + verify: (orgId: string, orgDomainId: string) => Promise; + delete: (orgId: string, orgDomainId: string) => Promise; +} diff --git a/libs/common/src/abstractions/organization-domain/org-domain.service.abstraction.ts b/libs/common/src/abstractions/organization-domain/org-domain.service.abstraction.ts new file mode 100644 index 00000000000..98256f35f20 --- /dev/null +++ b/libs/common/src/abstractions/organization-domain/org-domain.service.abstraction.ts @@ -0,0 +1,18 @@ +import { Observable } from "rxjs"; + +import { OrganizationDomainResponse } from "../../models/response/organization-domain.response"; + +export abstract class OrgDomainReadServiceAbstraction { + orgDomains$: Observable; + + get: (orgDomainId: string) => Promise; +} + +// Note: this separate class is designed to hold methods that are not +// meant to be used in components (e.g., data write methods) +export abstract class OrgDomainFullServiceAbstraction extends OrgDomainReadServiceAbstraction { + upsert: (orgDomains: OrganizationDomainResponse[]) => void; + replace: (orgDomains: OrganizationDomainResponse[]) => void; + clearCache: () => Promise; + delete: (orgDomainIds: string[]) => void; +} diff --git a/libs/common/src/models/request/organization-domain.request.ts b/libs/common/src/models/request/organization-domain.request.ts new file mode 100644 index 00000000000..98be6c3caf3 --- /dev/null +++ b/libs/common/src/models/request/organization-domain.request.ts @@ -0,0 +1,11 @@ +import { OrganizationDomainResponse } from "../response/organization-domain.response"; + +export class OrganizationDomainRequest { + txt: string; + domainName: string; + + constructor(orgDomainResponse: OrganizationDomainResponse) { + this.txt = orgDomainResponse.txt; + this.domainName = orgDomainResponse.domainName; + } +} diff --git a/libs/common/src/models/response/organization-domain.response.ts b/libs/common/src/models/response/organization-domain.response.ts new file mode 100644 index 00000000000..e57cfed3e47 --- /dev/null +++ b/libs/common/src/models/response/organization-domain.response.ts @@ -0,0 +1,29 @@ +import { BaseResponse } from "./base.response"; + +export class OrganizationDomainResponse extends BaseResponse { + id: string; + organizationId: string; + txt: string; + domainName: string; + creationDate: string; + nextRunDate: string; + jobRunCount: number; + verifiedDate?: string; + + constructor(response: any) { + super(response); + this.id = this.getResponseProperty("Id"); + this.organizationId = this.getResponseProperty("OrganizationId"); + this.txt = this.getResponseProperty("Txt"); + this.domainName = this.getResponseProperty("DomainName"); + this.creationDate = this.getResponseProperty("CreationDate"); + this.nextRunDate = this.getResponseProperty("NextRunDate"); + this.jobRunCount = this.getResponseProperty("JobRunCount"); + this.verifiedDate = this.getResponseProperty("VerifiedDate"); + + // Might be worth converting string dates to actual dates for ease of use + // this.creationDate = obj.creationDate != null ? new Date(obj.creationDate) : null; + // this.nextRunDate = obj.nextRunDate != null ? new Date(obj.nextRunDate) : null; + // this.verifiedDate = obj.verifiedDate != null ? new Date(obj.verifiedDate) : null; + } +} diff --git a/libs/common/src/services/organization-domain/org-domain-api.service.ts b/libs/common/src/services/organization-domain/org-domain-api.service.ts new file mode 100644 index 00000000000..b93d1288ca9 --- /dev/null +++ b/libs/common/src/services/organization-domain/org-domain-api.service.ts @@ -0,0 +1,69 @@ +import { OrgDomainApiServiceAbstraction } from "../../abstractions/organization-domain/org-domain-api.service.abstraction"; +import { OrganizationDomainRequest } from "../../models/request/organization-domain.request"; +import { OrganizationDomainResponse } from "../../models/response/organization-domain.response"; +import { ApiService } from "../api.service"; + +import { OrgDomainService } from "./org-domain.service"; + +export class OrgDomainApiService implements OrgDomainApiServiceAbstraction { + constructor(private orgDomainService: OrgDomainService, private apiService: ApiService) {} + + async getByOrgId(orgId: string): Promise { + const result = await this.apiService.send( + "GET", + `/organizations/${orgId}/domain`, + null, + true, + true + ); + return new OrganizationDomainResponse(result); + } + async getByOrgIdAndOrgDomainId( + orgId: string, + orgDomainId: string + ): Promise { + const result = await this.apiService.send( + "GET", + `/organizations/${orgId}/domain/${orgDomainId}`, + null, + true, + true + ); + return new OrganizationDomainResponse(result); + } + + async post(orgId: string, orgDomain: OrganizationDomainResponse): Promise { + const request = new OrganizationDomainRequest(orgDomain); + + const result = await this.apiService.send( + "POST", + `/organizations/${orgId}`, + request, + true, + true + ); + + const response = new OrganizationDomainResponse(result); + + await this.orgDomainService.upsert([response]); + + return response; + } + + async verify(orgId: string, orgDomainId: string): Promise { + const result: boolean = await this.apiService.send( + "POST", + `/organizations/${orgId}/${orgDomainId}/verify`, + null, + true, + true + ); + + return result; + } + + async delete(orgId: string, orgDomainId: string): Promise { + this.apiService.send("DELETE", `/organizations/${orgId}/${orgDomainId}`, null, true, false); + await this.orgDomainService.delete([orgDomainId]); + } +} diff --git a/libs/common/src/services/organization-domain/org-domain.service.ts b/libs/common/src/services/organization-domain/org-domain.service.ts new file mode 100644 index 00000000000..776380e7dea --- /dev/null +++ b/libs/common/src/services/organization-domain/org-domain.service.ts @@ -0,0 +1,66 @@ +import { BehaviorSubject } from "rxjs"; + +import { OrgDomainFullServiceAbstraction } from "../../abstractions/organization-domain/org-domain.service.abstraction"; +import { OrganizationDomainResponse } from "../../models/response/organization-domain.response"; + +export class OrgDomainService implements OrgDomainFullServiceAbstraction { + protected _orgDomains$: BehaviorSubject = new BehaviorSubject([]); + + orgDomains$ = this._orgDomains$.asObservable(); + + // eslint-disable-next-line @typescript-eslint/no-empty-function + constructor() {} + + async get(orgDomainId: string): Promise { + const orgDomains: OrganizationDomainResponse[] = this._orgDomains$.getValue(); + + return orgDomains.find((orgDomain) => orgDomain.id === orgDomainId); + } + + upsert(orgDomains: OrganizationDomainResponse[]): void { + const existingOrgDomains: OrganizationDomainResponse[] = this._orgDomains$.getValue(); + + orgDomains.forEach((orgDomain: OrganizationDomainResponse) => { + // Determine if passed in orgDomain exists in existing array: + const index = existingOrgDomains.findIndex( + (existingOrgDomain) => existingOrgDomain.id === orgDomain.id + ); + if (index !== -1) { + // existing + existingOrgDomains[index] = orgDomain; + } else { + // new item + existingOrgDomains.push(orgDomain); + } + }); + + this._orgDomains$.next(existingOrgDomains); + } + + replace(orgDomains: OrganizationDomainResponse[]): void { + this._orgDomains$.next(orgDomains); + } + + async clearCache(): Promise { + this._orgDomains$.next([]); + } + + delete(orgDomainIds: string[]): void { + const existingOrgDomains: OrganizationDomainResponse[] = this._orgDomains$.getValue(); + + orgDomainIds.forEach((orgDomainId: string) => { + const index = existingOrgDomains.findIndex( + (existingOrgDomain) => existingOrgDomain.id === orgDomainId + ); + if (index !== -1) { + // existing + delete existingOrgDomains[index]; + } else { + // eslint-disable-next-line no-console + console.warn(`Unable to delete OrgDomainId: ${orgDomainId}`); + } + }); + + this._orgDomains$.next(existingOrgDomains); + } +}