feat(domains): enhance domain management with activation states and sync options
This commit is contained in:
		| @@ -69,12 +69,15 @@ export class DnsManager { | ||||
|             this.cloudlyRef.authManager.validIdentityGuard, | ||||
|           ]); | ||||
|  | ||||
|           // Validate domain exists if domainId is provided | ||||
|           // Validate domain exists and is activated if domainId is provided | ||||
|           if (reqArg.dnsEntryData.domainId) { | ||||
|             const domain = await this.cloudlyRef.domainManager.CDomain.getDomainById(reqArg.dnsEntryData.domainId); | ||||
|             if (!domain) { | ||||
|               throw new Error(`Domain with id ${reqArg.dnsEntryData.domainId} not found`); | ||||
|             } | ||||
|             if ((domain.data as any).activationState !== 'activated') { | ||||
|               throw new Error(`Domain ${domain.data.name} is not activated; DNS changes are not allowed.`); | ||||
|             } | ||||
|             // Set the zone from the domain name | ||||
|             reqArg.dnsEntryData.zone = domain.data.name; | ||||
|           } | ||||
| @@ -97,12 +100,15 @@ export class DnsManager { | ||||
|             this.cloudlyRef.authManager.validIdentityGuard, | ||||
|           ]); | ||||
|  | ||||
|           // Validate domain exists if domainId is provided | ||||
|           // Validate domain exists and is activated if domainId is provided | ||||
|           if (reqArg.dnsEntryData.domainId) { | ||||
|             const domain = await this.cloudlyRef.domainManager.CDomain.getDomainById(reqArg.dnsEntryData.domainId); | ||||
|             if (!domain) { | ||||
|               throw new Error(`Domain with id ${reqArg.dnsEntryData.domainId} not found`); | ||||
|             } | ||||
|             if ((domain.data as any).activationState !== 'activated') { | ||||
|               throw new Error(`Domain ${domain.data.name} is not activated; DNS changes are not allowed.`); | ||||
|             } | ||||
|             // Set the zone from the domain name | ||||
|             reqArg.dnsEntryData.zone = domain.data.name; | ||||
|           } | ||||
| @@ -258,4 +264,4 @@ export class DnsManager { | ||||
|   public async stop() { | ||||
|     console.log('DNS Manager stopped'); | ||||
|   } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -36,6 +36,9 @@ export class Domain extends plugins.smartdata.SmartDataDbDoc< | ||||
|       verificationStatus: domainDataArg.verificationStatus || 'pending', | ||||
|       nameservers: domainDataArg.nameservers || [], | ||||
|       autoRenew: domainDataArg.autoRenew !== false, | ||||
|       activationState: domainDataArg.activationState || 'available', | ||||
|       syncSource: domainDataArg.syncSource ?? null, | ||||
|       lastSyncAt: domainDataArg.lastSyncAt, | ||||
|       createdAt: Date.now(), | ||||
|       updatedAt: Date.now(), | ||||
|     }; | ||||
| @@ -55,6 +58,7 @@ export class Domain extends plugins.smartdata.SmartDataDbDoc< | ||||
|     } | ||||
|     Object.assign(domain.data, domainDataArg, { | ||||
|       updatedAt: Date.now(), | ||||
|       activationState: domain.data.activationState || 'available', | ||||
|     }); | ||||
|     await domain.save(); | ||||
|     return domain; | ||||
| @@ -201,4 +205,4 @@ export class Domain extends plugins.smartdata.SmartDataDbDoc< | ||||
|     }); | ||||
|     return dnsEntries; | ||||
|   } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -7,6 +7,86 @@ import { logger } from '../logger.js'; | ||||
|  */ | ||||
| export function createPredefinedTasks(taskManager: CloudlyTaskManager) { | ||||
|    | ||||
|   // Cloudflare Domain Sync Task | ||||
|   const cfDomainSync = new plugins.taskbuffer.Task({ | ||||
|     name: 'cloudflare-domain-sync', | ||||
|     taskFunction: async () => { | ||||
|       const execution = taskManager.getCurrentExecution('cloudflare-domain-sync'); | ||||
|       try { | ||||
|         await execution?.addLog('Starting Cloudflare domain sync…', 'info'); | ||||
|         const cf = taskManager.cloudlyRef.cloudflareConnector?.cloudflare; | ||||
|         if (!cf) { | ||||
|           await execution?.addLog('Cloudflare not configured; skipping sync.', 'warning'); | ||||
|           return { created: 0, updated: 0, totalZones: 0 }; | ||||
|         } | ||||
|  | ||||
|         const zones = await cf.convenience.listZones(); | ||||
|         await execution?.setMetric('totalZones', zones.length); | ||||
|         await execution?.addLog(`Fetched ${zones.length} zones from Cloudflare`, 'info'); | ||||
|  | ||||
|         let created = 0; | ||||
|         let updated = 0; | ||||
|         const now = Date.now(); | ||||
|  | ||||
|         for (const zone of zones) { | ||||
|           // zone fields from Cloudflare typings | ||||
|           const zoneName = (zone as any).name as string; | ||||
|           const zoneId = (zone as any).id as string; | ||||
|           const zoneStatus = ((zone as any).status || 'active') as 'active'|'pending'|'suspended'|'transferred'|'expired'; | ||||
|           const nameServers: string[] = (zone as any).name_servers || []; | ||||
|  | ||||
|           const existing = await taskManager.cloudlyRef.domainManager.CDomain.getDomainByName(zoneName); | ||||
|           if (existing) { | ||||
|             if (execution && (taskManager.isCancellationRequested(execution.id) || existing.data == null)) { | ||||
|               await execution?.addLog('Cancellation requested. Stopping CF sync…', 'warning'); | ||||
|               break; | ||||
|             } | ||||
|             await execution?.addLog(`Updating domain: ${zoneName}`, 'info'); | ||||
|             await taskManager.cloudlyRef.domainManager.CDomain.updateDomain(existing.id, { | ||||
|               status: zoneStatus as any, | ||||
|               nameservers: nameServers, | ||||
|               cloudflareZoneId: zoneId, | ||||
|               syncSource: 'cloudflare', | ||||
|               lastSyncAt: now, | ||||
|               activationState: existing.data.activationState || 'available', | ||||
|             }); | ||||
|             updated++; | ||||
|           } else { | ||||
|             await execution?.addLog(`Creating domain: ${zoneName}`, 'info'); | ||||
|             await taskManager.cloudlyRef.domainManager.CDomain.createDomain({ | ||||
|               name: zoneName, | ||||
|               description: `Synced from Cloudflare zone ${zoneId}`, | ||||
|               status: zoneStatus as any, | ||||
|               verificationStatus: 'pending', | ||||
|               nameservers: nameServers, | ||||
|               autoRenew: true, | ||||
|               cloudflareZoneId: zoneId, | ||||
|               activationState: 'available', | ||||
|               syncSource: 'cloudflare', | ||||
|               lastSyncAt: now, | ||||
|             } as any); | ||||
|             created++; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         await execution?.setMetric('created', created); | ||||
|         await execution?.setMetric('updated', updated); | ||||
|         await execution?.addLog(`Cloudflare sync done: ${created} created, ${updated} updated`, 'success'); | ||||
|         return { created, updated, totalZones: zones.length }; | ||||
|       } catch (error) { | ||||
|         await execution?.addLog(`Cloudflare sync error: ${error.message}`, 'error'); | ||||
|         throw error; | ||||
|       } | ||||
|     }, | ||||
|   }); | ||||
|  | ||||
|   taskManager.registerTask('cloudflare-domain-sync', cfDomainSync, { | ||||
|     description: 'Import and update domains from Cloudflare zones', | ||||
|     category: 'system', | ||||
|     schedule: '0 3 * * *', // Daily at 3 AM | ||||
|     enabled: true, | ||||
|   }); | ||||
|  | ||||
|   // DNS Sync Task | ||||
|   const dnsSync = new plugins.taskbuffer.Task({ | ||||
|     name: 'dns-sync', | ||||
| @@ -79,8 +159,10 @@ export function createPredefinedTasks(taskManager: CloudlyTaskManager) { | ||||
|           return; | ||||
|         } | ||||
|          | ||||
|         // Get all domains | ||||
|         const domains = await taskManager.cloudlyRef.domainManager.CDomain.getInstances({}); | ||||
|         // Get all domains (only activated ones are considered for renewal) | ||||
|         const domains = await taskManager.cloudlyRef.domainManager.CDomain.getInstances({ | ||||
|           'data.activationState': 'activated', | ||||
|         } as any); | ||||
|         await execution?.setMetric('totalDomains', domains.length); | ||||
|          | ||||
|         let renewedCount = 0; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user