chore: complete the mail domain setup
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
FROM node:22-alpine AS base
|
FROM node:22-alpine AS base
|
||||||
|
|
||||||
RUN npm install -g corepack@latest
|
RUN npm install -g corepack@latest
|
||||||
RUN corepack enable && corepack prepare pnpm --activate
|
RUN corepack enable && corepack prepare pnpm@9 --activate
|
||||||
|
|
||||||
# Install tzdata to support timezone settings
|
# Install tzdata to support timezone settings
|
||||||
RUN apk add --no-cache tzdata
|
RUN apk add --no-cache tzdata
|
||||||
|
|||||||
+1
-1
@@ -129,5 +129,5 @@
|
|||||||
"git add ."
|
"git add ."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.12.1+sha512.f0dda8580f0ee9481c5c79a1d927b9164f2c478e90992ad268bbb2465a736984391d6333d2c327913578b2804af33474ca554ba29c04a8b13060a717675ae3ac"
|
"packageManager": "pnpm@9.15.9+sha512.68046141893c66fad01c079231128e9afb89ef87e2691d69e4d40eee228988295fd4682181bae55b58418c3a253bde65a505ec7c5f9403ece5cc3cd37dcf2531"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,34 +45,24 @@ export class DomainsController {
|
|||||||
return this.domainsService.deleteDomain(paramDto.id);
|
return this.domainsService.deleteDomain(paramDto.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(":id/setup")
|
@Get("setup")
|
||||||
@ApiOperation({ summary: "Get domain setup instructions" })
|
@ApiOperation({ summary: "Get domain setup instructions" })
|
||||||
@ApiResponse({ status: 200, description: "Domain setup instructions retrieved" })
|
@ApiResponse({ status: 200, description: "Domain setup instructions retrieved" })
|
||||||
getDomainSetupInstructions(@Param() paramDto: ParamDto) {
|
getDomainSetupInstructions(@BusinessDec("id") businessId: string) {
|
||||||
return this.domainsService.getDomainSetupInstructions(paramDto.id);
|
return this.domainsService.getDomainSetupInstructions(businessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(":id/dns-records")
|
@Get("dns-records")
|
||||||
@ApiOperation({ summary: "Get DNS records for domain" })
|
@ApiOperation({ summary: "Get DNS records for domain" })
|
||||||
@ApiResponse({ status: 200, description: "DNS records retrieved successfully" })
|
@ApiResponse({ status: 200, description: "DNS records retrieved successfully" })
|
||||||
getDomainDnsRecords(@Param() paramDto: ParamDto) {
|
getDomainDnsRecords(@BusinessDec("id") businessId: string) {
|
||||||
return this.domainsService.getDomainDnsRecords(paramDto.id);
|
return this.domainsService.getDomainDnsRecords(businessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(":id/verification-status")
|
@Get("verify-dns")
|
||||||
@ApiOperation({ summary: "Check domain verification status" })
|
@ApiOperation({ summary: "Check DNS records, verify domain configuration and return verification status" })
|
||||||
@ApiResponse({ status: 200, description: "Domain verification status checked" })
|
@ApiResponse({ status: 200, description: "DNS records verified and status returned" })
|
||||||
checkDomainVerificationStatus(@Param() paramDto: ParamDto) {
|
verifyDnsRecords(@BusinessDec("id") businessId: string) {
|
||||||
return this.domainsService.checkDomainVerificationStatus(paramDto.id);
|
return this.domainsService.checkDomainVerificationStatus(businessId);
|
||||||
}
|
|
||||||
|
|
||||||
@Post(":id/check-dns")
|
|
||||||
@ApiOperation({ summary: "Check DNS records and update verification status" })
|
|
||||||
@ApiResponse({ status: 200, description: "DNS records checked and updated" })
|
|
||||||
async checkDnsRecords(@Param() paramDto: ParamDto) {
|
|
||||||
// Trigger DNS verification
|
|
||||||
await this.domainsService.verifyDomain(paramDto.id);
|
|
||||||
// Return updated status
|
|
||||||
return this.domainsService.checkDomainVerificationStatus(paramDto.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ export class DnsService {
|
|||||||
private readonly logger = new Logger(DnsService.name);
|
private readonly logger = new Logger(DnsService.name);
|
||||||
|
|
||||||
private readonly mailServerDomain: string = "mail.danakcorp.com";
|
private readonly mailServerDomain: string = "mail.danakcorp.com";
|
||||||
private readonly spfRecord: string = `v=spf1 include:${this.mailServerDomain} ~all`;
|
private readonly serverDomain: string = "danakcorp.com";
|
||||||
private readonly dmarcRecord: string = `v=DMARC1; p=quarantine; rua=mailto:dmarc@${this.mailServerDomain}; ruf=mailto:dmarc@${this.mailServerDomain}`;
|
private readonly spfRecord: string = `v=spf1 mx include:${this.serverDomain} ~all`;
|
||||||
|
// private readonly dmarcRecord: string = `v=DMARC1; p=quarantine; rua=mailto:dmarc@${this.serverDomain}; ruf=mailto:dmarc@${this.serverDomain}`;
|
||||||
|
|
||||||
private readonly resolveTxt = promisify(dns.resolveTxt);
|
private readonly resolveTxt = promisify(dns.resolveTxt);
|
||||||
private readonly resolveCname = promisify(dns.resolveCname);
|
private readonly resolveCname = promisify(dns.resolveCname);
|
||||||
@@ -107,10 +108,11 @@ export class DnsService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// DMARC Record
|
// DMARC Record
|
||||||
|
const dmarcRecord = `v=DMARC1; p=quarantine; rua=mailto:dmarc@${domain.name}; ruf=mailto:dmarc@${domain.name}`;
|
||||||
requiredRecords.push({
|
requiredRecords.push({
|
||||||
name: `_dmarc.${domain.name}`,
|
name: `_dmarc.${domain.name}`,
|
||||||
type: DNSRecordType.DMARC,
|
type: DNSRecordType.DMARC,
|
||||||
value: this.dmarcRecord,
|
value: dmarcRecord,
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
description: "DMARC policy record",
|
description: "DMARC policy record",
|
||||||
});
|
});
|
||||||
@@ -269,7 +271,11 @@ export class DnsService {
|
|||||||
const txtRecords = await this.resolveTxt(dnsRecord.name);
|
const txtRecords = await this.resolveTxt(dnsRecord.name);
|
||||||
const flatRecords = txtRecords.flat();
|
const flatRecords = txtRecords.flat();
|
||||||
|
|
||||||
return flatRecords.some((record) => record.includes(dnsRecord.value) || record === dnsRecord.value);
|
// Join all TXT record parts together (handles multi-part TXT records like DKIM)
|
||||||
|
const joinedRecord = flatRecords.join("");
|
||||||
|
|
||||||
|
// Check if the expected value matches either the joined record or any individual part
|
||||||
|
return joinedRecord === dnsRecord.value || flatRecords.some((record) => record.includes(dnsRecord.value) || record === dnsRecord.value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.debug(`TXT record verification failed for ${dnsRecord.name}:`, error instanceof Error ? error.message : "Unknown error");
|
this.logger.debug(`TXT record verification failed for ${dnsRecord.name}:`, error instanceof Error ? error.message : "Unknown error");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -56,26 +56,10 @@ export class DomainsService {
|
|||||||
await this.dnsService.generateRequiredDnsRecords(domain);
|
await this.dnsService.generateRequiredDnsRecords(domain);
|
||||||
|
|
||||||
// Generate and create DKIM record
|
// Generate and create DKIM record
|
||||||
try {
|
await this.setupDomainDkim(domain, "default");
|
||||||
const dkimKeys = await this.dnsService.generateDKIMKeysByMailServer(domain.name, "default");
|
|
||||||
|
|
||||||
// Update domain with DKIM keys
|
|
||||||
domain.dkimPrivateKey = dkimKeys.privateKey;
|
|
||||||
domain.dkimPublicKey = dkimKeys.publicKey;
|
|
||||||
|
|
||||||
// Create DKIM DNS record
|
|
||||||
await this.dnsService.createDKIMRecord(domain, "default", dkimKeys.dnsTxt.name, dkimKeys.dnsTxt.value, dkimKeys.wildduckId);
|
|
||||||
|
|
||||||
await this.em.persistAndFlush(domain);
|
await this.em.persistAndFlush(domain);
|
||||||
|
|
||||||
this.logger.log(`DKIM automatically enabled for domain ${name}`);
|
|
||||||
} catch (error) {
|
|
||||||
this.logger.warn(`Failed to create DKIM for domain ${name}:`, error);
|
|
||||||
// Continue with domain creation even if DKIM fails
|
|
||||||
domain.dkimEnabled = false;
|
|
||||||
await this.em.persistAndFlush(domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create initial verification
|
// Create initial verification
|
||||||
|
|
||||||
this.logger.log(`Domain ${name} created for business ${businessId} with all required records`);
|
this.logger.log(`Domain ${name} created for business ${businessId} with all required records`);
|
||||||
@@ -98,16 +82,6 @@ export class DomainsService {
|
|||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get domain by name
|
|
||||||
*/
|
|
||||||
async getDomainByName(name: string) {
|
|
||||||
const domain = await this.domainRepository.findByName(name);
|
|
||||||
if (!domain) throw new BadRequestException(DomainMessage.DOMAIN_NOT_FOUND);
|
|
||||||
|
|
||||||
return { domain };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get domains for a business
|
* Get domains for a business
|
||||||
*/
|
*/
|
||||||
@@ -173,13 +147,40 @@ export class DomainsService {
|
|||||||
return { domain };
|
return { domain };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup DKIM for domain
|
||||||
|
*/
|
||||||
|
private async setupDomainDkim(domain: Domain, selector: string) {
|
||||||
|
try {
|
||||||
|
const dkimKeys = await this.dnsService.generateDKIMKeysByMailServer(domain.name, selector);
|
||||||
|
|
||||||
|
// Update domain with DKIM keys
|
||||||
|
domain.dkimPrivateKey = dkimKeys.privateKey;
|
||||||
|
domain.dkimPublicKey = dkimKeys.publicKey;
|
||||||
|
|
||||||
|
// Create DKIM DNS record
|
||||||
|
await this.dnsService.createDKIMRecord(domain, selector, dkimKeys.dnsTxt.name, dkimKeys.dnsTxt.value, dkimKeys.wildduckId);
|
||||||
|
|
||||||
|
this.logger.log(`DKIM automatically enabled for domain ${domain.name}`);
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.warn(`Failed to create DKIM for domain ${domain.name}:`, error);
|
||||||
|
// Continue with domain creation even if DKIM fails
|
||||||
|
domain.dkimEnabled = false;
|
||||||
|
domain.dkimPrivateKey = undefined;
|
||||||
|
domain.dkimPublicKey = undefined;
|
||||||
|
domain.dkimSelector = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup domain in mail server
|
* Setup domain in mail server
|
||||||
*/
|
*/
|
||||||
private async setupDomainInMailServer(domain: Domain) {
|
private async setupDomainInMailServer(domain: Domain) {
|
||||||
try {
|
try {
|
||||||
// Create DKIM keys if enabled
|
// Only create DKIM keys if enabled and not already created
|
||||||
if (domain.dkimEnabled && domain.dkimSelector) {
|
if (domain.dkimEnabled && domain.dkimSelector && !domain.dkimPrivateKey) {
|
||||||
|
this.logger.log(`Creating DKIM keys for domain ${domain.name} in mail server`);
|
||||||
|
|
||||||
const dkimKey = await firstValueFrom(
|
const dkimKey = await firstValueFrom(
|
||||||
this.mailServerService.dkim.createDKIMKey({
|
this.mailServerService.dkim.createDKIMKey({
|
||||||
domain: domain.name,
|
domain: domain.name,
|
||||||
@@ -189,6 +190,8 @@ export class DomainsService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!dkimKey.success) throw new BadRequestException(MailServerMessage.FAILED_TO_CREATE_DKIM_KEY);
|
if (!dkimKey.success) throw new BadRequestException(MailServerMessage.FAILED_TO_CREATE_DKIM_KEY);
|
||||||
|
} else if (domain.dkimEnabled && domain.dkimPrivateKey) {
|
||||||
|
this.logger.log(`DKIM already exists for domain ${domain.name}, skipping creation`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.log(`Mail server setup completed for domain ${domain.name}`);
|
this.logger.log(`Mail server setup completed for domain ${domain.name}`);
|
||||||
@@ -198,56 +201,16 @@ export class DomainsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable DKIM for domain
|
|
||||||
*/
|
|
||||||
async enableDKIM(id: string, selector?: string) {
|
|
||||||
const domain = await this.getDomainById(id);
|
|
||||||
|
|
||||||
const dkimSelector = selector || "default";
|
|
||||||
|
|
||||||
// Generate DKIM keys
|
|
||||||
const dkimKeys = await this.dnsService.generateDKIMKeysByMailServer(domain.name, dkimSelector);
|
|
||||||
|
|
||||||
domain.dkimEnabled = true;
|
|
||||||
domain.dkimSelector = dkimSelector;
|
|
||||||
domain.dkimPrivateKey = dkimKeys.privateKey;
|
|
||||||
domain.dkimPublicKey = dkimKeys.publicKey;
|
|
||||||
|
|
||||||
// Create DKIM DNS record
|
|
||||||
await this.dnsService.createDKIMRecord(domain, dkimSelector, dkimKeys.dnsTxt.name, dkimKeys.dnsTxt.value, dkimKeys.wildduckId);
|
|
||||||
|
|
||||||
await this.em.persistAndFlush(domain);
|
|
||||||
this.logger.log(`DKIM enabled for domain ${domain.name}`);
|
|
||||||
|
|
||||||
return { domain };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get domain statistics
|
|
||||||
*/
|
|
||||||
async getDomainStats(businessId: string) {
|
|
||||||
return this.domainRepository.getBusinessDomainStats(businessId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check all domains that need verification
|
|
||||||
*/
|
|
||||||
async checkDomainsNeedingVerification() {
|
|
||||||
const domain = await this.domainRepository.findNeedingCheck();
|
|
||||||
|
|
||||||
if (!domain) return { message: DomainMessage.NO_DOMAIN_FOUND };
|
|
||||||
await this.verifyDomain(domain.id);
|
|
||||||
|
|
||||||
return { message: DomainMessage.DOMAIN_CHECKED, domain: domain };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get domain setup instructions
|
* Get domain setup instructions
|
||||||
*/
|
*/
|
||||||
async getDomainSetupInstructions(domainId: string) {
|
async getDomainSetupInstructions(businessId: string) {
|
||||||
const domain = await this.getDomainById(domainId);
|
const businessDomain = await this.domainRepository.findOne({ business: { id: businessId }, deletedAt: null });
|
||||||
const { dnsRecords } = await this.dnsService.getDomainDnsRecords(domainId);
|
if (!businessDomain) throw new NotFoundException(DomainMessage.DOMAIN_NOT_FOUND);
|
||||||
|
|
||||||
|
const domain = await this.getDomainById(businessDomain.id);
|
||||||
|
|
||||||
|
const { dnsRecords } = await this.dnsService.getDomainDnsRecords(businessDomain.id);
|
||||||
|
|
||||||
return this.formatDomainSetupResponse(domain, dnsRecords);
|
return this.formatDomainSetupResponse(domain, dnsRecords);
|
||||||
}
|
}
|
||||||
@@ -255,19 +218,57 @@ export class DomainsService {
|
|||||||
/**
|
/**
|
||||||
* Get DNS records for domain
|
* Get DNS records for domain
|
||||||
*/
|
*/
|
||||||
async getDomainDnsRecords(domainId: string) {
|
async getDomainDnsRecords(businessId: string) {
|
||||||
// Verify domain exists
|
const businessDomain = await this.domainRepository.findOne({ business: { id: businessId }, deletedAt: null });
|
||||||
await this.getDomainById(domainId);
|
if (!businessDomain) throw new BadRequestException(DomainMessage.DOMAIN_NOT_FOUND);
|
||||||
return this.dnsService.getDomainDnsRecords(domainId);
|
|
||||||
|
const domain = await this.getDomainById(businessDomain.id);
|
||||||
|
|
||||||
|
const { overallStatus, recommendations } = await this.checkDomainVerificationStatus(businessId);
|
||||||
|
|
||||||
|
const { dnsRecords } = await this.dnsService.getDomainDnsRecords(domain.id);
|
||||||
|
return {
|
||||||
|
dnsRecords,
|
||||||
|
overallStatus,
|
||||||
|
recommendations,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check domain verification status
|
* Check domain verification status
|
||||||
*/
|
*/
|
||||||
async checkDomainVerificationStatus(domainId: string) {
|
async checkDomainVerificationStatus(businessId: string) {
|
||||||
await this.getDomainById(domainId);
|
const businessDomain = await this.domainRepository.findOne({ business: { id: businessId }, deletedAt: null });
|
||||||
const { dnsRecords } = await this.dnsService.getDomainDnsRecords(domainId);
|
if (!businessDomain) throw new BadRequestException(DomainMessage.DOMAIN_NOT_FOUND);
|
||||||
|
|
||||||
|
const domain = await this.getDomainById(businessDomain.id);
|
||||||
|
|
||||||
|
// Trigger DNS verification
|
||||||
|
await this.verifyDomain(domain.id);
|
||||||
|
|
||||||
|
const { dnsRecords } = await this.dnsService.getDomainDnsRecords(domain.id);
|
||||||
|
|
||||||
|
// Process DNS records for verification status
|
||||||
|
const { verificationStatuses, statusCounts, recommendations } = await this.processDnsRecordsForVerification(dnsRecords);
|
||||||
|
|
||||||
|
const isVerified = statusCounts.failed === 0 && statusCounts.pending === 0 && statusCounts.verified > 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
dnsRecords: verificationStatuses,
|
||||||
|
overallStatus: {
|
||||||
|
isVerified,
|
||||||
|
...statusCounts,
|
||||||
|
total: dnsRecords.length,
|
||||||
|
lastChecked: new Date(),
|
||||||
|
},
|
||||||
|
recommendations,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process DNS records for verification status
|
||||||
|
*/
|
||||||
|
private async processDnsRecordsForVerification(dnsRecords: DnsRecord[]) {
|
||||||
const verificationStatuses = [];
|
const verificationStatuses = [];
|
||||||
let verified = 0;
|
let verified = 0;
|
||||||
let pending = 0;
|
let pending = 0;
|
||||||
@@ -316,22 +317,24 @@ export class DomainsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isVerified = failed === 0 && pending === 0 && verified > 0;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dnsRecords: verificationStatuses,
|
verificationStatuses,
|
||||||
overallStatus: {
|
statusCounts: { verified, pending, failed },
|
||||||
isVerified,
|
|
||||||
verified,
|
|
||||||
pending,
|
|
||||||
failed,
|
|
||||||
total: dnsRecords.length,
|
|
||||||
lastChecked: new Date(),
|
|
||||||
},
|
|
||||||
recommendations,
|
recommendations,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get DNS record status counts
|
||||||
|
*/
|
||||||
|
private getDnsRecordStatusCounts(dnsRecords: DnsRecord[]) {
|
||||||
|
const verified = dnsRecords.filter((r) => r.status === VerificationStatus.VERIFIED).length;
|
||||||
|
const pending = dnsRecords.filter((r) => r.status === VerificationStatus.PENDING).length;
|
||||||
|
const failed = dnsRecords.filter((r) => r.status === VerificationStatus.FAILED).length;
|
||||||
|
|
||||||
|
return { verified, pending, failed };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format domain setup response with instructions
|
* Format domain setup response with instructions
|
||||||
*/
|
*/
|
||||||
@@ -353,20 +356,15 @@ export class DomainsService {
|
|||||||
instructions: this.generateRecordInstructions(record),
|
instructions: this.generateRecordInstructions(record),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const verified = dnsRecords.filter((r) => r.status === VerificationStatus.VERIFIED).length;
|
const statusCounts = this.getDnsRecordStatusCounts(dnsRecords);
|
||||||
const pending = dnsRecords.filter((r) => r.status === VerificationStatus.PENDING).length;
|
|
||||||
const failed = dnsRecords.filter((r) => r.status === VerificationStatus.FAILED).length;
|
|
||||||
|
|
||||||
const nextSteps = this.generateNextSteps(domain, dnsRecords);
|
const nextSteps = this.generateNextSteps(domain, dnsRecords);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
domain,
|
domain,
|
||||||
dnsRecords: dnsInstructions,
|
dnsRecords: dnsInstructions,
|
||||||
setupStatus: {
|
setupStatus: {
|
||||||
isComplete: failed === 0 && pending === 0 && verified > 0,
|
isComplete: statusCounts.failed === 0 && statusCounts.pending === 0 && statusCounts.verified > 0,
|
||||||
verified,
|
...statusCounts,
|
||||||
pending,
|
|
||||||
failed,
|
|
||||||
total: dnsRecords.length,
|
total: dnsRecords.length,
|
||||||
},
|
},
|
||||||
nextSteps,
|
nextSteps,
|
||||||
@@ -420,19 +418,25 @@ export class DomainsService {
|
|||||||
*/
|
*/
|
||||||
private generateNextSteps(domain: Domain, dnsRecords: DnsRecord[]): string[] {
|
private generateNextSteps(domain: Domain, dnsRecords: DnsRecord[]): string[] {
|
||||||
const steps: string[] = [];
|
const steps: string[] = [];
|
||||||
|
const statusCounts = this.getDnsRecordStatusCounts(dnsRecords);
|
||||||
|
|
||||||
if (domain.status === DomainStatus.PENDING) {
|
if (domain.status === DomainStatus.PENDING) {
|
||||||
steps.push(`1. ${DomainMessage.STEP_LOGIN_DNS_PANEL}`);
|
const setupSteps = [
|
||||||
steps.push(`2. ${DomainMessage.STEP_ADD_ALL_RECORDS}`);
|
DomainMessage.STEP_LOGIN_DNS_PANEL,
|
||||||
steps.push(`3. ${DomainMessage.STEP_INCLUDE_ALL_TYPES}`);
|
DomainMessage.STEP_ADD_ALL_RECORDS,
|
||||||
steps.push(`4. ${DomainMessage.STEP_WAIT_PROPAGATION}`);
|
DomainMessage.STEP_INCLUDE_ALL_TYPES,
|
||||||
steps.push(`5. ${DomainMessage.STEP_USE_CHECK_ENDPOINT}`);
|
DomainMessage.STEP_WAIT_PROPAGATION,
|
||||||
steps.push(`6. ${DomainMessage.STEP_DOMAIN_READY}`);
|
DomainMessage.STEP_USE_CHECK_ENDPOINT,
|
||||||
|
DomainMessage.STEP_DOMAIN_READY,
|
||||||
|
];
|
||||||
|
|
||||||
|
setupSteps.forEach((step, index) => {
|
||||||
|
steps.push(`${index + 1}. ${step}`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const pendingRecords = dnsRecords.filter((r) => r.status === VerificationStatus.PENDING);
|
if (statusCounts.pending > 0) {
|
||||||
if (pendingRecords.length > 0) {
|
steps.push(`📋 ${formatDomainMessage(DomainMessage.RECORDS_PENDING_VERIFICATION, { count: statusCounts.pending })}`);
|
||||||
steps.push(`📋 ${formatDomainMessage(DomainMessage.RECORDS_PENDING_VERIFICATION, { count: pendingRecords.length })}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const requiredRecords = dnsRecords.filter((r) => r.isRequired);
|
const requiredRecords = dnsRecords.filter((r) => r.isRequired);
|
||||||
|
|||||||
+8
-11
@@ -1,11 +1,11 @@
|
|||||||
import { INestApplication } from '@nestjs/common';
|
import { INestApplication } from "@nestjs/common";
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from "@nestjs/testing";
|
||||||
import * as request from 'supertest';
|
import * as request from "supertest";
|
||||||
import { App } from 'supertest/types';
|
import { App } from "supertest/types";
|
||||||
|
|
||||||
import { AppModule } from './../src/app.module';
|
import { AppModule } from "./../src/app.module";
|
||||||
|
|
||||||
describe('AppController (e2e)', () => {
|
describe("AppController (e2e)", () => {
|
||||||
let app: INestApplication<App>;
|
let app: INestApplication<App>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@@ -17,10 +17,7 @@ describe('AppController (e2e)', () => {
|
|||||||
await app.init();
|
await app.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('/ (GET)', () => {
|
it("/ (GET)", () => {
|
||||||
return request(app.getHttpServer())
|
return request(app.getHttpServer()).get("/").expect(200).expect("Hello World!");
|
||||||
.get('/')
|
|
||||||
.expect(200)
|
|
||||||
.expect('Hello World!');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user