mirror of
https://gh.wpcy.net/https://github.com/CaptainCore/captaincore-manager.git
synced 2026-04-26 10:02:16 +08:00
1281 lines
No EOL
59 KiB
PHP
1281 lines
No EOL
59 KiB
PHP
<?php
|
|
|
|
namespace CaptainCore;
|
|
|
|
class Domain {
|
|
|
|
protected $domain_id = "";
|
|
|
|
public function __construct( $domain_id = "" ) {
|
|
$this->domain_id = $domain_id;
|
|
}
|
|
|
|
public function accounts() {
|
|
|
|
$accountdomain = new AccountDomain();
|
|
$response = [];
|
|
|
|
// Fetch current records
|
|
$current_account_ids = array_column ( $accountdomain->where( [ "domain_id" => $this->domain_id ] ), "account_id" );
|
|
foreach ( $current_account_ids as $current_account_id ) {
|
|
// Get the account details
|
|
$account = \CaptainCore\Accounts::get( $current_account_id );
|
|
|
|
// Ensure the account exists before adding it to the response
|
|
if ( $account ) {
|
|
$response[] =[
|
|
"account_id" => $current_account_id,
|
|
"name" => $account->name
|
|
];
|
|
}
|
|
}
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
public function insert_accounts( $account_ids = [] ) {
|
|
|
|
$accountdomain = new AccountDomain();
|
|
|
|
foreach( $account_ids as $account_id ) {
|
|
|
|
// Fetch current records
|
|
$lookup = $accountdomain->where( [ "domain_id" => $this->domain_id, "account_id" => $account_id ] );
|
|
|
|
// Add new record
|
|
if ( count( $lookup ) == 0 ) {
|
|
$accountdomain->insert( [ "domain_id" => $this->domain_id, "account_id" => $account_id ] );
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public function assign_accounts( $account_ids = [] ) {
|
|
|
|
$accountdomain = new AccountDomain();
|
|
|
|
// Fetch current records
|
|
$current_account_ids = array_column ( $accountdomain->where( [ "domain_id" => $this->domain_id ] ), "account_id" );
|
|
|
|
// Removed current records not found new records.
|
|
foreach ( array_diff( $current_account_ids, $account_ids ) as $account_id ) {
|
|
$records = $accountdomain->where( [ "domain_id" => $this->domain_id, "account_id" => $account_id ] );
|
|
foreach ( $records as $record ) {
|
|
$accountdomain->delete( $record->account_domain_id );
|
|
}
|
|
}
|
|
|
|
// Add new records
|
|
foreach ( array_diff( $account_ids, $current_account_ids ) as $account_id ) {
|
|
$accountdomain->insert( [ "domain_id" => $this->domain_id, "account_id" => $account_id ] );
|
|
}
|
|
|
|
}
|
|
|
|
public function fetch_remote_id( $link_existing = false ) {
|
|
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
$response = null;
|
|
$remote_id = null;
|
|
|
|
// Load domains from transient
|
|
$constellix_all_domains = get_transient( 'constellix_all_domains' );
|
|
|
|
// If empty then update transient with large remote call
|
|
if ( empty( $constellix_all_domains ) ) {
|
|
|
|
$constellix_all_domains = Remote\Constellix::get( 'domains' );
|
|
|
|
// Save the API response so we don't have to call again until tomorrow.
|
|
set_transient( 'constellix_all_domains', $constellix_all_domains, HOUR_IN_SECONDS );
|
|
|
|
}
|
|
|
|
// Search API for domain ID
|
|
if ( ! empty( $constellix_all_domains->data ) ) {
|
|
foreach ( $constellix_all_domains->data as $item ) {
|
|
if ( $domain->name == $item->name ) {
|
|
$remote_id = $item->id;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Generate a new domain zone and add the new domain
|
|
if ( empty( $remote_id ) ) {
|
|
$arguments = [ 'name' => $domain->name ];
|
|
if ( defined( 'CAPTAINCORE_CONSTELLIX_VANITY_ID' ) && defined( 'CAPTAINCORE_CONSTELLIX_SOA_NAME' ) ) {
|
|
$arguments['vanityNameserver'] = CAPTAINCORE_CONSTELLIX_VANITY_ID;
|
|
$arguments['soa'] = [
|
|
"primaryNameserver" => CAPTAINCORE_CONSTELLIX_SOA_NAME,
|
|
"ttl" => "86400",
|
|
"refresh" => "43200",
|
|
"retry" => "3600",
|
|
"expire" => "1209600",
|
|
"negCache" => "180",
|
|
];
|
|
}
|
|
$response = Remote\Constellix::post( 'domains', $arguments );
|
|
if ( ! empty( $response->data ) ) {
|
|
$remote_id = $response->data->id;
|
|
}
|
|
|
|
// Check if domain already exists error and admin wants to link to it
|
|
if ( ! empty( $response->errors ) && $link_existing ) {
|
|
foreach ( $response->errors as $error ) {
|
|
// Check for "Domain with name X already exists, Domain Id: Y" error
|
|
if ( preg_match( '/Domain with name .+ already exists, Domain Id: (\d+)/', $error, $matches ) ) {
|
|
$remote_id = intval( $matches[1] );
|
|
// Clear the transient so next lookup will find this domain
|
|
delete_transient( 'constellix_all_domains' );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Only return errors if we still don't have a remote_id
|
|
if ( $response && ! empty( $response->errors ) && empty( $remote_id ) ) {
|
|
return [ "errors" => $response->errors ];
|
|
}
|
|
|
|
if ( ! empty( $remote_id ) ) {
|
|
( new Domains )->update( [ "remote_id" => $remote_id ], [ "domain_id" => $this->domain_id ] );
|
|
}
|
|
|
|
return $remote_id;
|
|
}
|
|
|
|
public function fetch() {
|
|
$domain = Domains::get( $this->domain_id );
|
|
$details = empty( $domain->details ) ? (object) [] : json_decode( $domain->details );
|
|
unset( $details->provider_cache );
|
|
return [
|
|
"provider" => self::fetch_remote(),
|
|
"accounts" => self::accounts(),
|
|
"provider_id" => $domain->provider_id,
|
|
"connected_sites" => self::connected_sites(),
|
|
"details" => $details,
|
|
];
|
|
}
|
|
|
|
public function clear_provider_cache() {
|
|
$domain = Domains::get( $this->domain_id );
|
|
$details = empty( $domain->details ) ? (object) [] : json_decode( $domain->details );
|
|
unset( $details->provider_cache );
|
|
( new Domains )->update( [ "details" => json_encode( $details ) ], [ "domain_id" => $this->domain_id ] );
|
|
}
|
|
|
|
public function connected_sites() {
|
|
$domain = Domains::get( $this->domain_id );
|
|
$details = empty( $domain->details ) ? (object) [] : json_decode( $domain->details );
|
|
|
|
// New logic starts here
|
|
$domain_accounts = self::accounts();
|
|
$connected_sites = [];
|
|
$seen_site_ids = []; // Use this to get unique site IDs first.
|
|
|
|
if ( ! empty( $domain_accounts ) ) {
|
|
foreach ( $domain_accounts as $account ) {
|
|
$account_id = $account['account_id'];
|
|
// Use admin 'true' flag to ensure Account class can fetch sites
|
|
// `sites()` returns array of [ 'site_id' => ..., 'name' => ... ]
|
|
$account_sites = ( new \CaptainCore\Account( $account_id, true ) )->sites();
|
|
|
|
if ( ! empty( $account_sites ) ) {
|
|
foreach ( $account_sites as $site ) {
|
|
// Ensure site list is unique
|
|
if ( ! isset( $seen_site_ids[ $site['site_id'] ] ) ) {
|
|
$seen_site_ids[ $site['site_id'] ] = $site['name'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now, loop through the unique site IDs and get their environments
|
|
if ( ! empty( $seen_site_ids ) ) {
|
|
foreach ( $seen_site_ids as $site_id => $site_name ) {
|
|
// Fetch environments for this site
|
|
$environments = ( new \CaptainCore\Environments )->where( [ "site_id" => $site_id ] );
|
|
|
|
if ( ! empty( $environments ) ) {
|
|
foreach($environments as $env) {
|
|
// Add an entry for each environment
|
|
$connected_sites[] = [
|
|
"id" => $site_id, // Match JS 'site.id'
|
|
"name" => $site_name,
|
|
"environment" => $env->environment,
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sort the results: Primary by name (ASC), Secondary by environment (DESC - so Prod comes before Stage)
|
|
if ( ! empty( $connected_sites ) ) {
|
|
$names = array_column( $connected_sites, 'name' );
|
|
$envs = array_column( $connected_sites, 'environment' );
|
|
// Sort by name ASC, then environment DESC
|
|
array_multisort( $names, SORT_ASC, $envs, SORT_ASC, $connected_sites );
|
|
}
|
|
|
|
return $connected_sites;
|
|
}
|
|
|
|
public function fetch_remote() {
|
|
$domain = Domains::get( $this->domain_id );
|
|
if ( empty( $domain->provider_id ) ) {
|
|
return [ "errors" => [ "No remote domain found." ] ];
|
|
}
|
|
$provider = Providers::get( $domain->provider_id );
|
|
if ( $provider->provider == "hoverdotcom" ) {
|
|
|
|
if ( empty( get_transient( 'captaincore_hovercom_auth' ) ) ) {
|
|
( new Domains )->provider_login();
|
|
}
|
|
$auth = get_transient( 'captaincore_hovercom_auth' );
|
|
$args = [
|
|
'headers' => [
|
|
'Cookie' => 'hoverauth=' . $auth
|
|
]
|
|
];
|
|
|
|
$response = wp_remote_get( "https://www.hover.com/api/control_panel/domains/{$domain->name}", $args );
|
|
if ( is_wp_error( $response ) ) {
|
|
return json_decode( $response->get_error_message() );
|
|
} else {
|
|
$decoded = json_decode( $response['body'] );
|
|
if ( empty( $decoded->domain ) ) {
|
|
return [ "errors" => [ "Unable to fetch domain info from Hover.com" ] ];
|
|
}
|
|
$response = $decoded->domain;
|
|
$nameservers = [];
|
|
foreach( $response->nameservers as $nameserver ) {
|
|
$nameservers[] = [ "value" => $nameserver ];
|
|
}
|
|
$domain = [
|
|
"domain" => $response->name,
|
|
"nameservers" => $nameservers,
|
|
"contacts" => [
|
|
"owner" => $response->owner,
|
|
"admin" => $response->admin,
|
|
"billing" => $response->billing,
|
|
"tech" => $response->tech,
|
|
],
|
|
"locked" => $response->locked,
|
|
"whois_privacy" => $response->whois_privacy,
|
|
"status" => $response->status,
|
|
];
|
|
return $domain;
|
|
}
|
|
}
|
|
|
|
if ( $provider->provider == "spaceship" ) {
|
|
// Check for cached provider data (10-minute TTL)
|
|
$details = empty( $domain->details ) ? (object) [] : json_decode( $domain->details );
|
|
if ( ! empty( $details->provider_cache ) && ( time() - $details->provider_cache->cached_at ) < 600 ) {
|
|
return (array) $details->provider_cache->data;
|
|
}
|
|
|
|
$response = \CaptainCore\Remote\Spaceship::get( "domains/{$domain->name}" );
|
|
if ( empty( $response ) || empty( $response->contacts ) ) {
|
|
// Fall back to stale cache on error
|
|
if ( ! empty( $details->provider_cache->data ) ) {
|
|
return (array) $details->provider_cache->data;
|
|
}
|
|
return [ "errors" => [ "Remote domain details not found." ] ];
|
|
}
|
|
$owner = \CaptainCore\Remote\Spaceship::get( "contacts/{$response->contacts->registrant}" );
|
|
$admin = $response->contacts->registrant == $response->contacts->admin ? $owner : \CaptainCore\Remote\Spaceship::get( "contacts/{$response->contacts->admin}" );
|
|
$billing = $response->contacts->registrant == $response->contacts->billing ? $owner : \CaptainCore\Remote\Spaceship::get( "contacts/{$response->contacts->billing}" );
|
|
$tech = $response->contacts->registrant == $response->contacts->tech ? $owner : \CaptainCore\Remote\Spaceship::get( "contacts/{$response->contacts->tech}" );
|
|
$owner->first_name = $owner->firstName ?? '';
|
|
$owner->last_name = $owner->lastName ?? '';
|
|
$owner->org_name = $owner->organization ?? '';
|
|
$owner->state = $owner->stateProvince ?? '';
|
|
$owner->postal_code = $owner->postalCode ?? '';
|
|
$admin->first_name = $admin->firstName ?? '';
|
|
$admin->last_name = $admin->lastName ?? '';
|
|
$admin->org_name = $admin->organization ?? '';
|
|
$admin->state = $admin->stateProvince ?? '';
|
|
$admin->postal_code = $admin->postalCode ?? '';
|
|
$billing->first_name = $billing->firstName ?? '';
|
|
$billing->last_name = $billing->lastName ?? '';
|
|
$billing->org_name = $billing->organization ?? '';
|
|
$billing->state = $billing->stateProvince ?? '';
|
|
$billing->postal_code = $billing->postalCode ?? '';
|
|
$tech->first_name = $tech->firstName ?? '';
|
|
$tech->last_name = $tech->lastName ?? '';
|
|
$tech->org_name = $tech->organization ?? '';
|
|
$tech->state = $tech->stateProvince ?? '';
|
|
$tech->postal_code = $tech->postalCode ?? '';
|
|
$result = [
|
|
"domain" => empty( $response->name ) ? "" : $response->name,
|
|
"nameservers" => empty( $response->nameservers->hosts ) ? [] : array_map(function ($host) { return ["value" => $host]; }, $response->nameservers->hosts),
|
|
"contacts" => [
|
|
"owner" => $owner,
|
|
"admin" => $admin,
|
|
"billing" => $billing,
|
|
"tech" => $tech,
|
|
],
|
|
"locked" => empty( $response->eppStatuses ) ? "off" : "on",
|
|
"whois_privacy" => $response->privacyProtection->level == "high" ? "on" : "off",
|
|
"status" => $response->lifecycleStatus,
|
|
];
|
|
unset( $result['contacts']["owner"]->firstName );
|
|
unset( $result['contacts']["owner"]->lastName );
|
|
unset( $result['contacts']["owner"]->organization );
|
|
unset( $result['contacts']["owner"]->stateProvince );
|
|
unset( $result['contacts']["owner"]->postalCode );
|
|
unset( $result['contacts']["admin"]->firstName );
|
|
unset( $result['contacts']["admin"]->lastName );
|
|
unset( $result['contacts']["admin"]->organization );
|
|
unset( $result['contacts']["admin"]->stateProvince );
|
|
unset( $result['contacts']["admin"]->postalCode );
|
|
unset( $result['contacts']["billing"]->firstName );
|
|
unset( $result['contacts']["billing"]->lastName );
|
|
unset( $result['contacts']["billing"]->organization );
|
|
unset( $result['contacts']["billing"]->stateProvince );
|
|
|
|
// Cache the result
|
|
$details->provider_cache = [ "data" => $result, "cached_at" => time() ];
|
|
( new Domains )->update( [ "details" => json_encode( $details ) ], [ "domain_id" => $this->domain_id ] );
|
|
|
|
return $result;
|
|
}
|
|
|
|
}
|
|
|
|
public function activate_email_forwarding( $overwrite_mx = false ) {
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
$details = empty( $domain->details ) ? (object) [] : json_decode( $domain->details );
|
|
|
|
// Check if already active (using mailgun_forwarding_id)
|
|
if ( ! empty( $details->mailgun_forwarding_id ) ) {
|
|
return new \WP_Error( 'already_active', 'Email forwarding is already active for this domain.' );
|
|
}
|
|
|
|
// 1. Check for DNS conflicts before proceeding
|
|
$constellix_domain = ( new Domains )->get( $this->domain_id );
|
|
$at_mx_records = [];
|
|
$existing_txt_records = [];
|
|
$has_existing_at_mx = false;
|
|
|
|
if ( ! empty( $constellix_domain->remote_id ) ) {
|
|
|
|
$all_records_response = \CaptainCore\Remote\Constellix::get( "domains/{$constellix_domain->remote_id}/records" );
|
|
|
|
if ( is_object( $all_records_response ) && isset( $all_records_response->data ) && is_array( $all_records_response->data ) ) {
|
|
foreach ( $all_records_response->data as $record ) {
|
|
if ( $record->type === 'MX' && $record->name === "" ) {
|
|
$at_mx_records[] = $record;
|
|
}
|
|
// Index existing TXT records by name for later lookup
|
|
if ( $record->type === 'TXT' ) {
|
|
$existing_txt_records[ $record->name ] = $record;
|
|
}
|
|
}
|
|
}
|
|
|
|
$has_existing_at_mx = ( count( $at_mx_records ) > 0 );
|
|
|
|
if ( $has_existing_at_mx && ! $overwrite_mx ) {
|
|
return new \WP_Error( 'mx_conflict', 'Existing MX records found. Please confirm to overwrite.', [ 'status' => 409 ] );
|
|
}
|
|
}
|
|
|
|
// 2. Check if domain already exists in Mailgun, or create it
|
|
$mailgun_domain = \CaptainCore\Remote\Mailgun::get( "v4/domains/{$domain->name}" );
|
|
|
|
if ( ! empty( $mailgun_domain->message ) && $mailgun_domain->message == "Domain not found" ) {
|
|
// Create domain in Mailgun for receiving
|
|
$mailgun_domain = \CaptainCore\Remote\Mailgun::post( "v4/domains", [ 'name' => $domain->name ] );
|
|
}
|
|
|
|
// Check for errors from Mailgun API
|
|
if ( ! empty( $mailgun_domain->errors ) ) {
|
|
return new \WP_Error( 'api_error', 'Mailgun API error: ' . json_encode( $mailgun_domain->errors ) );
|
|
}
|
|
|
|
// Handle Mailgun response - both GET and POST return domain info nested under 'domain' key
|
|
// GET /v4/domains/{name} returns: { "domain": { "name": "...", "id": "..." }, "receiving_dns_records": [...], ... }
|
|
// POST /v4/domains returns: { "domain": { "name": "...", "id": "..." }, "receiving_dns_records": [...], ... }
|
|
if ( ! empty( $mailgun_domain->domain ) ) {
|
|
$mailgun_domain_info = $mailgun_domain->domain;
|
|
} else {
|
|
error_log( 'CaptainCore: Unexpected Mailgun response for ' . $domain->name . ': ' . json_encode( $mailgun_domain ) );
|
|
return new \WP_Error( 'api_error', 'Failed to create or retrieve domain on Mailgun.' );
|
|
}
|
|
|
|
// 3. Apply DNS changes (if managed via Constellix)
|
|
if ( ! empty( $constellix_domain->remote_id ) ) {
|
|
|
|
// Add MX records for receiving (from Mailgun's response)
|
|
if ( ! empty( $mailgun_domain->receiving_dns_records ) ) {
|
|
$mx_records = [];
|
|
foreach ( $mailgun_domain->receiving_dns_records as $record ) {
|
|
// Add all MX records from Mailgun (don't skip based on valid status)
|
|
if ( $record->record_type === 'MX' ) {
|
|
$mx_records[] = [
|
|
'server' => $record->value . '.',
|
|
'priority' => $record->priority ?? 10,
|
|
'enabled' => true,
|
|
];
|
|
}
|
|
}
|
|
if ( ! empty( $mx_records ) ) {
|
|
$formatted_mx_data = self::_format_dns_record_for_api( 'mx', '', $mx_records, 3600 );
|
|
|
|
if ( $has_existing_at_mx && $overwrite_mx ) {
|
|
// Update existing MX record using PUT (use the first record's ID)
|
|
$existing_mx_id = $at_mx_records[0]->id;
|
|
$mx_dns_response = \CaptainCore\Remote\Constellix::put( "domains/{$constellix_domain->remote_id}/records/{$existing_mx_id}", $formatted_mx_data );
|
|
if ( ! empty( $mx_dns_response->errors ) ) {
|
|
error_log( 'CaptainCore: Failed to update Mailgun MX records for ' . $domain->name . ': ' . json_encode( $mx_dns_response->errors ) );
|
|
}
|
|
} elseif ( ! $has_existing_at_mx ) {
|
|
// Create new MX record using POST
|
|
$mx_dns_response = \CaptainCore\Remote\Constellix::post( "domains/{$constellix_domain->remote_id}/records", $formatted_mx_data );
|
|
if ( ! empty( $mx_dns_response->errors ) ) {
|
|
error_log( 'CaptainCore: Failed to add Mailgun MX records for ' . $domain->name . ': ' . json_encode( $mx_dns_response->errors ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add TXT and CNAME records for sending/verification (from Mailgun's response)
|
|
if ( ! empty( $mailgun_domain->sending_dns_records ) ) {
|
|
foreach ( $mailgun_domain->sending_dns_records as $record ) {
|
|
$record_name = str_replace( ".{$domain->name}", "", rtrim( $record->name, '.' ) );
|
|
// If name equals the domain itself, use empty string for root
|
|
if ( $record_name === $domain->name ) {
|
|
$record_name = '';
|
|
}
|
|
|
|
if ( $record->record_type === 'TXT' && $record->valid !== 'valid' ) {
|
|
// Check if a TXT record with this name already exists
|
|
if ( isset( $existing_txt_records[ $record_name ] ) ) {
|
|
// Append to existing TXT record using PUT
|
|
$existing_record = $existing_txt_records[ $record_name ];
|
|
$existing_values = $existing_record->value ?? [];
|
|
|
|
// Add the new Mailgun value to existing values
|
|
$new_values = [];
|
|
foreach ( $existing_values as $existing_value ) {
|
|
$new_values[] = [
|
|
'value' => $existing_value->value,
|
|
'enabled' => $existing_value->enabled ?? true,
|
|
];
|
|
}
|
|
$new_values[] = [ 'value' => $record->value, 'enabled' => true ];
|
|
|
|
$txt_data = self::_format_dns_record_for_api( 'txt', $record_name, $new_values, $existing_record->ttl ?? 3600 );
|
|
$response = \CaptainCore\Remote\Constellix::put( "domains/{$constellix_domain->remote_id}/records/{$existing_record->id}", $txt_data );
|
|
if ( ! empty( $response->errors ) ) {
|
|
error_log( 'CaptainCore: Failed to update TXT record for ' . $domain->name . ': ' . json_encode( $response->errors ) );
|
|
}
|
|
} else {
|
|
// Create new TXT record using POST
|
|
$txt_data = self::_format_dns_record_for_api( 'txt', $record_name, [
|
|
[ 'value' => $record->value, 'enabled' => true ]
|
|
], 3600 );
|
|
$response = \CaptainCore\Remote\Constellix::post( "domains/{$constellix_domain->remote_id}/records", $txt_data );
|
|
if ( ! empty( $response->errors ) ) {
|
|
error_log( 'CaptainCore: Failed to add Mailgun TXT record for ' . $domain->name . ': ' . json_encode( $response->errors ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( $record->record_type === 'CNAME' && $record->valid !== 'valid' ) {
|
|
$cname_data = self::_format_dns_record_for_api( 'cname', $record_name, [
|
|
[ 'value' => $record->value . '.', 'enabled' => true ]
|
|
], 3600 );
|
|
$response = \CaptainCore\Remote\Constellix::post( "domains/{$constellix_domain->remote_id}/records", $cname_data );
|
|
if ( ! empty( $response->errors ) ) {
|
|
error_log( 'CaptainCore: Failed to add Mailgun CNAME record for ' . $domain->name . ': ' . json_encode( $response->errors ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 4. Trigger Mailgun domain verification
|
|
\CaptainCore\Remote\Mailgun::put( "v4/domains/{$domain->name}/verify" );
|
|
|
|
// 5. Schedule a follow-up verification in 60 seconds
|
|
wp_schedule_single_event( time() + 60, 'schedule_mailgun_verify', [ $domain->name ] );
|
|
|
|
// 6. Save the Mailgun forwarding ID to domain details
|
|
$details->mailgun_forwarding_id = $mailgun_domain_info->id ?? $domain->name;
|
|
( new Domains )->update( [ "details" => json_encode( $details ) ], [ "domain_id" => $this->domain_id ] );
|
|
$domain_account_ids = array_column( ( new AccountDomain() )->where( [ "domain_id" => $this->domain_id ] ), "account_id" );
|
|
ActivityLog::log( 'created', 'email_forward', $this->domain_id, $domain->name, "Activated email forwarding for {$domain->name}", [], $domain_account_ids[0] ?? null );
|
|
|
|
// Return a response object for the frontend
|
|
return (object) [
|
|
'id' => $details->mailgun_forwarding_id,
|
|
'name' => $domain->name,
|
|
'mailgun_domain' => $mailgun_domain_info,
|
|
'has_mx_record' => true,
|
|
'forwarding_active' => true,
|
|
];
|
|
}
|
|
|
|
public function get_email_forwards() {
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
if ( empty( $domain->name ) ) {
|
|
return new \WP_Error( 'no_domain', 'Domain not found.' );
|
|
}
|
|
|
|
// Get all routes from Mailgun
|
|
$routes_response = \CaptainCore\Remote\Mailgun::get( "v3/routes", [ 'limit' => 1000 ] );
|
|
|
|
// Check for errors
|
|
if ( ! empty( $routes_response->errors ) ) {
|
|
return new \WP_Error( 'mailgun_error', 'Error fetching routes from Mailgun.', [ 'details' => $routes_response->errors ] );
|
|
}
|
|
|
|
if ( empty( $routes_response->items ) ) {
|
|
return [];
|
|
}
|
|
|
|
// Filter routes that match this domain and transform to alias format
|
|
$aliases = [];
|
|
$domain_pattern = '/@' . preg_quote( $domain->name, '/' ) . '(["\']|\))/i';
|
|
|
|
foreach ( $routes_response->items as $route ) {
|
|
// Check if this route's expression matches our domain
|
|
if ( ! empty( $route->expression ) && preg_match( $domain_pattern, $route->expression ) ) {
|
|
$alias = self::_mailgun_route_to_alias( $route, $domain->name );
|
|
if ( $alias ) {
|
|
$aliases[] = $alias;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $aliases;
|
|
}
|
|
|
|
public function add_email_forward( $alias_input ) {
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
if ( empty( $domain->name ) ) {
|
|
return new \WP_Error( 'no_domain', 'Domain not found.' );
|
|
}
|
|
|
|
$alias_input = (object) $alias_input;
|
|
|
|
// Build the Mailgun route expression
|
|
$alias_name = $alias_input->name ?? '';
|
|
|
|
if ( $alias_name === '*' || $alias_name === '' ) {
|
|
// Catch-all alias
|
|
$expression = 'match_recipient(".*@' . $domain->name . '")';
|
|
} else {
|
|
// Specific alias
|
|
$expression = 'match_recipient("' . $alias_name . '@' . $domain->name . '")';
|
|
}
|
|
|
|
// Build the forward actions
|
|
$actions = [];
|
|
$recipients = $alias_input->recipients ?? [];
|
|
if ( is_string( $recipients ) ) {
|
|
$recipients = array_map( 'trim', explode( ',', $recipients ) );
|
|
}
|
|
|
|
foreach ( $recipients as $recipient ) {
|
|
$recipient_email = is_object( $recipient ) ? $recipient->address : $recipient;
|
|
$actions[] = 'forward("' . $recipient_email . '")';
|
|
}
|
|
$actions[] = 'stop()';
|
|
|
|
// Determine priority (catch-all should be lower priority = higher number)
|
|
$priority = ( $alias_name === '*' || $alias_name === '' ) ? 100 : 0;
|
|
|
|
// Create the route in Mailgun
|
|
$route_data = [
|
|
'priority' => $priority,
|
|
'description' => "Email forward: {$alias_name}@{$domain->name}",
|
|
'expression' => $expression,
|
|
'action' => $actions,
|
|
];
|
|
|
|
$response = \CaptainCore\Remote\Mailgun::post( "v3/routes", $route_data );
|
|
|
|
if ( empty( $response->route ) && empty( $response->id ) ) {
|
|
return new \WP_Error( 'mailgun_error', 'Failed to create route in Mailgun.', [ 'details' => $response ] );
|
|
}
|
|
|
|
// Transform response to alias format for compatibility
|
|
return self::_mailgun_route_to_alias( $response->route ?? $response, $domain->name );
|
|
}
|
|
|
|
public function update_email_forward( $route_id, $alias_input ) {
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
if ( empty( $domain->name ) ) {
|
|
return new \WP_Error( 'no_domain', 'Domain not found.' );
|
|
}
|
|
|
|
$alias_input = (object) $alias_input;
|
|
|
|
// Build update data
|
|
$update_data = [];
|
|
|
|
// If name is being updated, rebuild the expression
|
|
if ( isset( $alias_input->name ) ) {
|
|
$alias_name = $alias_input->name;
|
|
if ( $alias_name === '*' || $alias_name === '' ) {
|
|
$update_data['expression'] = 'match_recipient(".*@' . $domain->name . '")';
|
|
$update_data['priority'] = 100;
|
|
} else {
|
|
$update_data['expression'] = 'match_recipient("' . $alias_name . '@' . $domain->name . '")';
|
|
$update_data['priority'] = 0;
|
|
}
|
|
$update_data['description'] = "Email forward: {$alias_name}@{$domain->name}";
|
|
}
|
|
|
|
// If recipients are being updated, rebuild actions
|
|
if ( isset( $alias_input->recipients ) ) {
|
|
$actions = [];
|
|
$recipients = $alias_input->recipients;
|
|
if ( is_string( $recipients ) ) {
|
|
$recipients = array_map( 'trim', explode( ',', $recipients ) );
|
|
}
|
|
|
|
foreach ( $recipients as $recipient ) {
|
|
$recipient_email = is_object( $recipient ) ? $recipient->address : $recipient;
|
|
$actions[] = 'forward("' . $recipient_email . '")';
|
|
}
|
|
$actions[] = 'stop()';
|
|
$update_data['action'] = $actions;
|
|
}
|
|
|
|
if ( empty( $update_data ) ) {
|
|
return new \WP_Error( 'no_changes', 'No changes provided.' );
|
|
}
|
|
|
|
$response = \CaptainCore\Remote\Mailgun::put( "v3/routes/{$route_id}", $update_data );
|
|
|
|
if ( empty( $response->id ) && empty( $response->message ) ) {
|
|
return new \WP_Error( 'mailgun_error', 'Failed to update route in Mailgun.', [ 'details' => $response ] );
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
public function delete_email_forward( $route_id ) {
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
if ( empty( $domain->name ) ) {
|
|
return new \WP_Error( 'no_domain', 'Domain not found.' );
|
|
}
|
|
|
|
$response = \CaptainCore\Remote\Mailgun::delete( "v3/routes/{$route_id}" );
|
|
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* Converts a Mailgun route object to the alias format used by the frontend.
|
|
* This maintains compatibility with the existing UI.
|
|
*
|
|
* @param object $route The Mailgun route object.
|
|
* @param string $domain_name The domain name for context.
|
|
* @return object|null The alias object or null if not a valid forward route.
|
|
*/
|
|
private static function _mailgun_route_to_alias( $route, $domain_name ) {
|
|
if ( empty( $route ) ) {
|
|
return null;
|
|
}
|
|
|
|
// Extract alias name from expression
|
|
// Expression format: match_recipient("alias@domain.com") or match_recipient(".*@domain.com")
|
|
$alias_name = '';
|
|
if ( preg_match( '/match_recipient\(["\'](.+)@' . preg_quote( $domain_name, '/' ) . '["\']\)/', $route->expression, $matches ) ) {
|
|
$alias_name = $matches[1];
|
|
if ( $alias_name === '.*' ) {
|
|
$alias_name = '*'; // Convert regex catch-all to simple asterisk
|
|
}
|
|
}
|
|
|
|
// Extract recipients from actions
|
|
// Action format: ["forward(\"target@email.com\")", "stop()"]
|
|
$recipients = [];
|
|
$actions = is_array( $route->actions ) ? $route->actions : [ $route->actions ];
|
|
foreach ( $actions as $action ) {
|
|
if ( preg_match( '/forward\(["\'](.+?)["\']\)/', $action, $matches ) ) {
|
|
$recipients[] = $matches[1]; // Return simple email strings for frontend compatibility
|
|
}
|
|
}
|
|
|
|
return (object) [
|
|
'id' => $route->id,
|
|
'name' => $alias_name,
|
|
'recipients' => $recipients,
|
|
'description' => $route->description ?? '',
|
|
'created_at' => $route->created_at ?? '',
|
|
// Additional fields for compatibility
|
|
'domain' => $domain_name,
|
|
'expression' => $route->expression ?? '',
|
|
'priority' => $route->priority ?? 0,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Formats DNS record data for the Constellix API.
|
|
* (Internal helper copied from captaincore.php)
|
|
*/
|
|
private static function _format_dns_record_for_api( $record_type, $record_name, $record_value, $record_ttl ) {
|
|
$record_type = strtolower( $record_type );
|
|
$post_data = [
|
|
'name' => $record_name,
|
|
'type' => $record_type,
|
|
'ttl' => $record_ttl,
|
|
];
|
|
|
|
if ( in_array( $record_type, [ 'a', 'aaaa', 'aname', 'cname', 'txt', 'spf' ] ) ) {
|
|
$records = [];
|
|
foreach ( (array) $record_value as $record ) {
|
|
$record_obj = (object) $record;
|
|
$records[] = [
|
|
'value' => $record_obj->value,
|
|
'enabled' => $record_obj->enabled ?? true,
|
|
];
|
|
}
|
|
$post_data['value'] = $records;
|
|
} elseif ( $record_type == 'mx' ) {
|
|
$mx_records = [];
|
|
foreach ( (array) $record_value as $mx_record ) {
|
|
$mx_record_obj = (object) $mx_record;
|
|
$mx_records[] = [
|
|
'server' => $mx_record_obj->server,
|
|
'priority' => $mx_record_obj->priority,
|
|
'enabled' => $mx_record_obj->enabled ?? true, // Preserve enabled state
|
|
];
|
|
}
|
|
$post_data['value'] = $mx_records;
|
|
} elseif ( $record_type == 'srv' ) {
|
|
$srv_records = [];
|
|
foreach ( (array) $record_value as $srv_record ) {
|
|
$srv_record_obj = (object) $srv_record;
|
|
$srv_records[] = [
|
|
'host' => $srv_record_obj->host,
|
|
'priority' => $srv_record_obj->priority,
|
|
'weight' => $srv_record_obj->weight,
|
|
'port' => $srv_record_obj->port,
|
|
'enabled' => $srv_record_obj->enabled ?? true, // Preserve enabled state
|
|
];
|
|
}
|
|
$post_data['value'] = $srv_records;
|
|
} elseif ( $record_type == 'http' ) {
|
|
$url = is_object($record_value) ? $record_value->url : $record_value;
|
|
$post_data['value'] = [
|
|
'hard' => true,
|
|
'url' => $url,
|
|
'redirectType' => '301',
|
|
];
|
|
} else {
|
|
$post_data['value'] = $record_value;
|
|
}
|
|
|
|
return $post_data;
|
|
}
|
|
|
|
public function auth_code() {
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
if ( empty( $domain->provider_id ) ) {
|
|
return [ "errors" => [ "No remote domain found." ] ];
|
|
}
|
|
$provider = Providers::get( $domain->provider_id );
|
|
$domain_account_ids = array_column( ( new AccountDomain() )->where( [ "domain_id" => $this->domain_id ] ), "account_id" );
|
|
ActivityLog::log( 'executed', 'domain', $this->domain_id, $domain->name, "Retrieved auth code for {$domain->name}", [], $domain_account_ids[0] ?? null );
|
|
if ( $provider->provider == "hoverdotcom" ) {
|
|
if ( empty( get_transient( 'captaincore_hovercom_auth' ) ) ) {
|
|
( new Domains )->provider_login();
|
|
}
|
|
$auth = get_transient( 'captaincore_hovercom_auth' );
|
|
$args = [
|
|
'headers' => [
|
|
'Cookie' => 'hoverauth=' . $auth
|
|
]
|
|
];
|
|
|
|
$response = wp_remote_get( "https://www.hover.com/api/domains/{$domain->name}/auth_code", $args );
|
|
if ( is_wp_error( $response ) ) {
|
|
return json_decode( $response->get_error_message() );
|
|
}
|
|
$response = json_decode( $response['body'] );
|
|
if ( empty( $response->auth_code ) ) {
|
|
return "";
|
|
}
|
|
return $response->auth_code;
|
|
}
|
|
if ( $provider->provider == "spaceship" ) {
|
|
return \CaptainCore\Remote\Spaceship::get( "domains/{$domain->name}/transfer/auth-code" )->authCode;
|
|
}
|
|
}
|
|
|
|
public function lock() {
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
if ( empty( $domain->provider_id ) ) {
|
|
return [ "errors" => [ "No remote domain found." ] ];
|
|
}
|
|
$provider = Providers::get( $domain->provider_id );
|
|
$domain_account_ids = array_column( ( new AccountDomain() )->where( [ "domain_id" => $this->domain_id ] ), "account_id" );
|
|
ActivityLog::log( 'locked', 'domain', $this->domain_id, $domain->name, "Locked domain {$domain->name}", [], $domain_account_ids[0] ?? null );
|
|
if ( $provider->provider == "hoverdotcom" ) {
|
|
if ( empty( get_transient( 'captaincore_hovercom_auth' ) ) ) {
|
|
( new Domains )->provider_login();
|
|
}
|
|
$auth = get_transient( 'captaincore_hovercom_auth' );
|
|
$data = [
|
|
'timeout' => 45,
|
|
'headers' => [
|
|
'Content-Type' => 'application/json; charset=utf-8',
|
|
'Cookie' => 'hoverauth=' . $auth
|
|
],
|
|
'body' => json_encode( [
|
|
"field" => "locked",
|
|
'value' => true
|
|
] ),
|
|
'method' => 'PUT',
|
|
'data_format' => 'body',
|
|
];
|
|
|
|
$response = wp_remote_request( "https://www.hover.com/api/control_panel/domains/domain-{$domain->name}", $data );
|
|
echo json_encode( $response );
|
|
if ( is_wp_error( $response ) ) {
|
|
return json_decode( $response->get_error_message() );
|
|
} else {
|
|
return json_decode( $response['body'] );
|
|
}
|
|
}
|
|
if ( $provider->provider == "spaceship" ) {
|
|
$result = \CaptainCore\Remote\Spaceship::put( "domains/{$domain->name}/transfer/lock", [ "isLocked" => true ] );
|
|
$this->clear_provider_cache();
|
|
return $result;
|
|
}
|
|
}
|
|
|
|
public function unlock() {
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
if ( empty( $domain->provider_id ) ) {
|
|
return [ "errors" => [ "No remote domain found." ] ];
|
|
}
|
|
$provider = Providers::get( $domain->provider_id );
|
|
$domain_account_ids = array_column( ( new AccountDomain() )->where( [ "domain_id" => $this->domain_id ] ), "account_id" );
|
|
ActivityLog::log( 'unlocked', 'domain', $this->domain_id, $domain->name, "Unlocked domain {$domain->name}", [], $domain_account_ids[0] ?? null );
|
|
if ( $provider->provider == "hoverdotcom" ) {
|
|
if ( empty( get_transient( 'captaincore_hovercom_auth' ) ) ) {
|
|
( new Domains )->provider_login();
|
|
}
|
|
$auth = get_transient( 'captaincore_hovercom_auth' );
|
|
$data = [
|
|
'timeout' => 45,
|
|
'headers' => [
|
|
'Content-Type' => 'application/json; charset=utf-8',
|
|
'Cookie' => 'hoverauth=' . $auth
|
|
],
|
|
'body' => json_encode( [
|
|
"field" => "locked",
|
|
'value' => false
|
|
] ),
|
|
'method' => 'PUT',
|
|
'data_format' => 'body',
|
|
];
|
|
|
|
$response = wp_remote_request( "https://www.hover.com/api/control_panel/domains/domain-{$domain->name}", $data );
|
|
|
|
if ( is_wp_error( $response ) ) {
|
|
return json_decode( $response->get_error_message() );
|
|
} else {
|
|
return json_decode( $response['body'] );
|
|
}
|
|
}
|
|
if ( $provider->provider == "spaceship" ) {
|
|
$result = \CaptainCore\Remote\Spaceship::put( "domains/{$domain->name}/transfer/lock", [ "isLocked" => false ] );
|
|
$this->clear_provider_cache();
|
|
return $result;
|
|
}
|
|
}
|
|
|
|
public function privacy_on() {
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
if ( empty( $domain->provider_id ) ) {
|
|
return [ "errors" => [ "No remote domain found." ] ];
|
|
}
|
|
$provider = Providers::get( $domain->provider_id );
|
|
$domain_account_ids = array_column( ( new AccountDomain() )->where( [ "domain_id" => $this->domain_id ] ), "account_id" );
|
|
ActivityLog::log( 'enabled', 'domain', $this->domain_id, $domain->name, "Enabled WHOIS privacy for {$domain->name}", [], $domain_account_ids[0] ?? null );
|
|
if ( $provider->provider == "hoverdotcom" ) {
|
|
if ( empty( get_transient( 'captaincore_hovercom_auth' ) ) ) {
|
|
( new Domains )->provider_login();
|
|
}
|
|
$auth = get_transient( 'captaincore_hovercom_auth' );
|
|
$data = [
|
|
'timeout' => 45,
|
|
'headers' => [
|
|
'Content-Type' => 'application/json; charset=utf-8',
|
|
'Cookie' => 'hoverauth=' . $auth
|
|
],
|
|
'body' => json_encode( [
|
|
"field" => "whois_privacy",
|
|
'value' => true
|
|
] ),
|
|
'method' => 'PUT',
|
|
'data_format' => 'body',
|
|
];
|
|
|
|
$response = wp_remote_request( "https://www.hover.com/api/control_panel/domains/domain-{$domain->name}", $data );
|
|
echo json_encode( $response );
|
|
if ( is_wp_error( $response ) ) {
|
|
return json_decode( $response->get_error_message() );
|
|
}
|
|
return json_decode( $response['body'] );
|
|
}
|
|
if ( $provider->provider == "spaceship" ) {
|
|
$result = \CaptainCore\Remote\Spaceship::put( "domains/{$domain->name}/privacy/preference", [ "privacyLevel" => "high", "userConsent" => true ] );
|
|
$this->clear_provider_cache();
|
|
return $result;
|
|
}
|
|
}
|
|
|
|
public function privacy_off() {
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
if ( empty( $domain->provider_id ) ) {
|
|
return [ "errors" => [ "No remote domain found." ] ];
|
|
}
|
|
$provider = Providers::get( $domain->provider_id );
|
|
$domain_account_ids = array_column( ( new AccountDomain() )->where( [ "domain_id" => $this->domain_id ] ), "account_id" );
|
|
ActivityLog::log( 'disabled', 'domain', $this->domain_id, $domain->name, "Disabled WHOIS privacy for {$domain->name}", [], $domain_account_ids[0] ?? null );
|
|
if ( $provider->provider == "hoverdotcom" ) {
|
|
if ( empty( get_transient( 'captaincore_hovercom_auth' ) ) ) {
|
|
( new Domains )->provider_login();
|
|
}
|
|
$auth = get_transient( 'captaincore_hovercom_auth' );
|
|
$data = [
|
|
'timeout' => 45,
|
|
'headers' => [
|
|
'Content-Type' => 'application/json; charset=utf-8',
|
|
'Cookie' => 'hoverauth=' . $auth
|
|
],
|
|
'body' => json_encode( [
|
|
"field" => "whois_privacy",
|
|
'value' => false
|
|
] ),
|
|
'method' => 'PUT',
|
|
'data_format' => 'body',
|
|
];
|
|
|
|
$response = wp_remote_request( "https://www.hover.com/api/control_panel/domains/domain-{$domain->name}", $data );
|
|
echo json_encode( $response );
|
|
if ( is_wp_error( $response ) ) {
|
|
return json_decode( $response->get_error_message() );
|
|
} else {
|
|
return json_decode( $response['body'] );
|
|
}
|
|
}
|
|
if ( $provider->provider == "spaceship" ) {
|
|
$result = \CaptainCore\Remote\Spaceship::put( "domains/{$domain->name}/privacy/preference", [ "privacyLevel" => "public", "userConsent" => true ] );
|
|
$this->clear_provider_cache();
|
|
return $result;
|
|
}
|
|
}
|
|
|
|
public function renew_off() {
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
if ( empty( $domain->provider_id ) ) {
|
|
return [ "errors" => [ "No remote domain found." ] ];
|
|
}
|
|
if ( empty( get_transient( 'captaincore_hovercom_auth' ) ) ) {
|
|
( new Domains )->provider_login();
|
|
}
|
|
$auth = get_transient( 'captaincore_hovercom_auth' );
|
|
$data = [
|
|
'timeout' => 45,
|
|
'headers' => [
|
|
'Content-Type' => 'application/json; charset=utf-8',
|
|
'Cookie' => 'hoverauth=' . $auth
|
|
],
|
|
'body' => json_encode( [
|
|
"field" => "autorenew",
|
|
'value' => false
|
|
] ),
|
|
'method' => 'PUT',
|
|
'data_format' => 'body',
|
|
];
|
|
|
|
$response = wp_remote_request( "https://www.hover.com/api/control_panel/domains/domain-{$domain->name}", $data );
|
|
echo json_encode( $response );
|
|
if ( is_wp_error( $response ) ) {
|
|
return json_decode( $response->get_error_message() );
|
|
} else {
|
|
return json_decode( $response['body'] );
|
|
}
|
|
}
|
|
|
|
public function set_contacts( $contacts = [] ) {
|
|
$domain = Domains::get( $this->domain_id );
|
|
$contacts = (object) $contacts;
|
|
if ( empty( $domain->provider_id ) ) {
|
|
return [ "errors" => [ "No remote domain found." ] ];
|
|
}
|
|
$provider = Providers::get( $domain->provider_id );
|
|
if ( $provider->provider == "hoverdotcom" ) {
|
|
if ( empty( get_transient( 'captaincore_hovercom_auth' ) ) ) {
|
|
( new Domains )->provider_login();
|
|
}
|
|
$auth = get_transient( 'captaincore_hovercom_auth' );
|
|
$data = [
|
|
'timeout' => 45,
|
|
'headers' => [
|
|
'Content-Type' => 'application/json; charset=utf-8',
|
|
'Cookie' => 'hoverauth=' . $auth
|
|
],
|
|
'body' => json_encode( [
|
|
"id" => "domain-{$domain->name}",
|
|
"contacts" => [
|
|
"nolock" => true,
|
|
"owner" => $contacts->owner,
|
|
"admin" => $contacts->admin,
|
|
"tech" => $contacts->tech,
|
|
"billing" => $contacts->billing,
|
|
|
|
]
|
|
] ),
|
|
'method' => 'PUT',
|
|
'data_format' => 'body',
|
|
];
|
|
|
|
$response = wp_remote_request( "https://www.hover.com/api/control_panel/domains/set_contacts", $data );
|
|
if ( is_wp_error( $response ) ) {
|
|
return json_decode( $response->get_error_message() );
|
|
}
|
|
$response = json_decode( $response['body'] );
|
|
if ( ! empty( $response->error ) ) {
|
|
return [ "error" => "There was a problem updating the contact info. Check the formatting and try again." ];
|
|
}
|
|
if ( $response->succeeded == "true" ) {
|
|
return [ "response" => "Contacts have been updated." ];
|
|
}
|
|
}
|
|
if ( $provider->provider == "spaceship" ) {
|
|
$changed = false;
|
|
$response = \CaptainCore\Remote\Spaceship::get( "domains/{$domain->name}" );
|
|
$owner = \CaptainCore\Remote\Spaceship::get( "contacts/{$response->contacts->registrant}" );
|
|
$admin = $response->contacts->admin == $response->contacts->registrant ? $owner : \CaptainCore\Remote\Spaceship::get( "contacts/{$response->contacts->admin}" );
|
|
$billing = $response->contacts->billing == $response->contacts->registrant ? $owner : \CaptainCore\Remote\Spaceship::get( "contacts/{$response->contacts->billing}" );
|
|
$tech = $response->contacts->tech == $response->contacts->registrant ? $owner : \CaptainCore\Remote\Spaceship::get( "contacts/{$response->contacts->tech}" );
|
|
foreach (['owner', 'admin', 'tech', 'billing'] as $record) {
|
|
if (isset($contacts->$record)) {
|
|
$new_contact = $contacts->$record;
|
|
$existing_contact = ${$record};
|
|
// Skip if no changes made
|
|
if ( $existing_contact->firstName == $new_contact->first_name && $existing_contact->lastName == $new_contact->last_name && $existing_contact->email == $new_contact->email && $existing_contact->phone == $new_contact->phone &&
|
|
$existing_contact->organization == $new_contact->org_name && $existing_contact->address1 == $new_contact->address1 && $existing_contact->address2 == $new_contact->address2 && $existing_contact->stateProvince == $new_contact->state &&
|
|
$existing_contact->postalCode == $new_contact->postal_code && $existing_contact->city == $new_contact->city && $existing_contact->country == $new_contact->country ) {
|
|
continue;
|
|
}
|
|
$changed = true;
|
|
$updated_contact = [
|
|
"firstName" => $new_contact->first_name,
|
|
"lastName" => $new_contact->last_name,
|
|
"organization" => $new_contact->org_name,
|
|
"email" => $new_contact->email,
|
|
"address1" => $new_contact->address1,
|
|
"address2" => $new_contact->address2,
|
|
"city" => $new_contact->city,
|
|
"country" => $new_contact->country,
|
|
"stateProvince" => $new_contact->state,
|
|
"postalCode" => $new_contact->postal_code,
|
|
"phone" => $new_contact->phone
|
|
];
|
|
$response_contact = \CaptainCore\Remote\Spaceship::put( "contacts", $updated_contact );
|
|
$response->contacts->{$record} = $response_contact->contactId;
|
|
}
|
|
}
|
|
if ( ! $changed ) {
|
|
return [ "response" => "No changes found." ];
|
|
}
|
|
$results = \CaptainCore\Remote\Spaceship::put( "domains/{$domain->name}/contacts", [
|
|
"registrant" => $response->contacts->registrant,
|
|
"admin" => $response->contacts->admin,
|
|
"tech" => $response->contacts->tech,
|
|
"billing" => $repsonse->contacts->billing
|
|
] );
|
|
if ( ! empty( $results->data ) ) {
|
|
return [ "error" => "There was a problem updating the contact info. Check the formatting and try again." . json_encode( $results->data ) ];
|
|
}
|
|
$this->clear_provider_cache();
|
|
return [ "response" => "Contacts have been updated.". json_encode( $results ) ];
|
|
}
|
|
}
|
|
|
|
public function set_nameservers( $nameservers = [] ) {
|
|
$domain = ( new Domains )->get( $this->domain_id );
|
|
if ( empty( $domain->provider_id ) ) {
|
|
return [ "errors" => [ "No remote domain found." ] ];
|
|
}
|
|
$provider = Providers::get( $domain->provider_id );
|
|
$domain_account_ids = array_column( ( new AccountDomain() )->where( [ "domain_id" => $this->domain_id ] ), "account_id" );
|
|
ActivityLog::log( 'updated', 'domain', $this->domain_id, $domain->name, "Updated nameservers for {$domain->name}", [ 'nameservers' => $nameservers ], $domain_account_ids[0] ?? null );
|
|
if ( $provider->provider == "hoverdotcom" ) {
|
|
if ( empty( get_transient( 'captaincore_hovercom_auth' ) ) ) {
|
|
( new Domains )->provider_login();
|
|
}
|
|
$auth = get_transient( 'captaincore_hovercom_auth' );
|
|
$data = [
|
|
'timeout' => 45,
|
|
'headers' => [
|
|
'Content-Type' => 'application/json; charset=utf-8',
|
|
'Cookie' => 'hoverauth=' . $auth
|
|
],
|
|
'body' => json_encode( [
|
|
"field" => "nameservers",
|
|
'value' => $nameservers
|
|
] ),
|
|
'method' => 'PUT',
|
|
'data_format' => 'body',
|
|
];
|
|
|
|
$response = wp_remote_request( "https://www.hover.com/api/control_panel/domains/domain-{$domain->name}", $data );
|
|
if ( is_wp_error( $response ) ) {
|
|
return json_decode( $response->get_error_message() );
|
|
}
|
|
$response = json_decode( $response['body'] );
|
|
if ( ! empty( $response->error ) ) {
|
|
return [ "error" => "There was a problem updating nameservers. Check formatting and try again." ];
|
|
}
|
|
if ( $response->succeeded == "true" ) {
|
|
return [ "response" => "Nameservers have been updated." ];
|
|
}
|
|
if ( $response->succeeded == "false" ) {
|
|
return [ "response" => $response->errors ];
|
|
}
|
|
}
|
|
if ( $provider->provider == "spaceship" ) {
|
|
$response = \CaptainCore\Remote\Spaceship::put( "domains/{$domain->name}/nameservers", [ "provider" => "custom", "hosts" => $nameservers ] );
|
|
if ( empty( $response->hosts ) || ! empty( $response->data ) ) {
|
|
$detail = $response->detail ?? '';
|
|
$data = ! empty( $response->data ) ? json_encode( $response->data ) : '';
|
|
return [ "error" => "There was a problem updating nameservers. {$detail} {$data}" ];
|
|
}
|
|
$this->clear_provider_cache();
|
|
return [ "response" => "Nameservers have been updated." ];
|
|
}
|
|
}
|
|
|
|
public static function zone( $domain_id ) {
|
|
$domain = ( new Domains )->get( $domain_id );
|
|
$domain_info = Remote\Constellix::get( "domains/$domain->remote_id" );
|
|
$records = Remote\Constellix::get( "domains/$domain->remote_id/records?perPage=100" );
|
|
$steps = ceil( $records->meta->pagination->total / 100 );
|
|
for ($i = 1; $i < $steps; $i++) {
|
|
$page = $i + 1;
|
|
$additional_records = Remote\Constellix::get( "domains/$domain->remote_id/records?page=$page&perPage=100" );
|
|
$records->data = array_merge($records->data, $additional_records->data);
|
|
}
|
|
$zone = new \Badcow\DNS\Zone( $domain->name .'.');
|
|
$zone->setDefaultTtl(3600);
|
|
$zone_record = new \Badcow\DNS\ResourceRecord;
|
|
$zone_record->setName( "@" );
|
|
$zone_record->setClass( "IN" );
|
|
$zone_record->setRdata( \Badcow\DNS\Rdata\Factory::Soa(
|
|
$domain_info->data->soa->primaryNameserver,
|
|
$domain_info->data->soa->email,
|
|
$domain_info->data->soa->serial,
|
|
$domain_info->data->soa->refresh,
|
|
$domain_info->data->soa->retry,
|
|
$domain_info->data->soa->expire,
|
|
$domain_info->data->soa->negativeCache
|
|
));
|
|
$zone->addResourceRecord($zone_record);
|
|
foreach( $domain_info->data->nameservers as $nameserver ) {
|
|
$zone_record = new \Badcow\DNS\ResourceRecord;
|
|
$zone_record->setName( "@" );
|
|
$zone_record->setClass( "IN" );
|
|
$zone_record->setRdata( \Badcow\DNS\Rdata\Factory::Ns( $nameserver . "." ) );
|
|
$zone->addResourceRecord($zone_record);
|
|
}
|
|
foreach( $records->data as $record ) {
|
|
if ( empty( $record->name ) ) {
|
|
$record->name = "@";
|
|
}
|
|
if ( $record->type == "A" ) {
|
|
foreach( $record->value as $value ) {
|
|
$zone_record = new \Badcow\DNS\ResourceRecord;
|
|
$zone_record->setName( $record->name );
|
|
$zone_record->setRdata( \Badcow\DNS\Rdata\Factory::A( $value->value ));
|
|
$zone->addResourceRecord($zone_record);
|
|
}
|
|
}
|
|
if ( $record->type == "AAAA" ) {
|
|
foreach( $record->value as $value ) {
|
|
$zone_record = new \Badcow\DNS\ResourceRecord;
|
|
$zone_record->setName( $record->name );
|
|
$zone_record->setRdata( \Badcow\DNS\Rdata\Factory::Aaaa( $value->value ));
|
|
$zone->addResourceRecord($zone_record);
|
|
}
|
|
}
|
|
if ( $record->type == "CNAME" ) {
|
|
foreach( $record->value as $value ) {
|
|
$zone_record = new \Badcow\DNS\ResourceRecord;
|
|
$zone_record->setName( $record->name );
|
|
$zone_record->setRdata( \Badcow\DNS\Rdata\Factory::Cname( $value->value ));
|
|
$zone->addResourceRecord($zone_record);
|
|
}
|
|
}
|
|
if ( $record->type == "MX" ) {
|
|
foreach( $record->value as $value ) {
|
|
$zone_record = new \Badcow\DNS\ResourceRecord;
|
|
$zone_record->setName( $record->name );
|
|
$zone_record->setRdata( \Badcow\DNS\Rdata\Factory::Mx( $value->priority, $value->server ));
|
|
$zone->addResourceRecord($zone_record);
|
|
}
|
|
}
|
|
if ( $record->type == "SRV" ) {
|
|
foreach( $record->value as $value ) {
|
|
$zone_record = new \Badcow\DNS\ResourceRecord;
|
|
$zone_record->setName( $record->name );
|
|
$zone_record->setRdata( \Badcow\DNS\Rdata\Factory::Srv( $value->priority, $value->weight, $value->port, $value->host ));
|
|
$zone->addResourceRecord($zone_record);
|
|
}
|
|
}
|
|
if ( $record->type == "TXT" ) {
|
|
foreach( $record->value as $value ) {
|
|
$zone_record = new \Badcow\DNS\ResourceRecord;
|
|
$zone_record->setName( $record->name );
|
|
$zone_record->setClass('IN');
|
|
$zone_record->setRdata( \Badcow\DNS\Rdata\Factory::Txt(trim($value->value,'"'), 0, 200));
|
|
$zone->addResourceRecord($zone_record);
|
|
}
|
|
}
|
|
}
|
|
|
|
$builder = new \Badcow\DNS\AlignedBuilder();
|
|
$builder->addRdataFormatter('TXT', '\CaptainCore\Domain::specialTxtFormatter' );
|
|
$builder->build($zone);
|
|
return $builder->build($zone);
|
|
}
|
|
|
|
public static function specialTxtFormatter(\Badcow\DNS\Rdata\TXT $rdata, int $padding): string {
|
|
//If the text length is less than or equal to 50 characters, just return it unaltered.
|
|
if (strlen($rdata->getText()) <= 500) {
|
|
return sprintf('"%s"', addcslashes($rdata->getText(), '"\\'));
|
|
}
|
|
|
|
$returnVal = "(\n";
|
|
$chunks = str_split($rdata->getText(), 500);
|
|
foreach ($chunks as $chunk) {
|
|
$returnVal .= str_repeat(' ', $padding).
|
|
sprintf('"%s"', addcslashes($chunk, '"\\')).
|
|
"\n";
|
|
}
|
|
$returnVal .= str_repeat(' ', $padding) . ")";
|
|
|
|
return $returnVal;
|
|
}
|
|
|
|
} |