diff --git a/app/Events/SubdomainWasRemoved.php b/app/Events/SubdomainWasRemoved.php new file mode 100644 index 000000000000..ef0a1a2a969c --- /dev/null +++ b/app/Events/SubdomainWasRemoved.php @@ -0,0 +1,21 @@ +account = $account; + } +} diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index 84b5e436d375..124c0bf0a393 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Events\SubdomainWasRemoved; use App\Events\SubdomainWasUpdated; use App\Events\UserSettingsChanged; use App\Events\UserSignedUp; @@ -809,18 +810,27 @@ class AccountController extends BaseController } } + + (bool) $fireUpdateSubdomainEvent = false; + if ($account->subdomain !== $request->subdomain) { - event(new SubdomainWasUpdated($account)); + $fireUpdateSubdomainEvent = true; + event(new SubdomainWasRemoved($account)); } $account->fill($request->all()); $account->client_view_css = $request->client_view_css; - $account->subdomain = $request->subdomain; + $account->subdomain = $request->subdomain; $account->iframe_url = $request->iframe_url; $account->save(); + if ($fireUpdateSubdomainEvent) { + event(new SubdomainWasUpdated($account)); + } + + return redirect('settings/' . ACCOUNT_CLIENT_PORTAL) - ->with('message', trans('texts.updated_settings')); + ->with('message', trans('texts.updated_settings')); } /** @@ -837,7 +847,7 @@ class AccountController extends BaseController $settings->save(); return redirect('settings/' . ACCOUNT_EMAIL_SETTINGS) - ->with('message', trans('texts.updated_settings')); + ->with('message', trans('texts.updated_settings')); } /** @@ -992,8 +1002,8 @@ class AccountController extends BaseController } if (! $account->share_counter - && $account->invoice_number_prefix == $account->quote_number_prefix - && $account->invoice_number_pattern == $account->quote_number_pattern) { + && $account->invoice_number_prefix == $account->quote_number_prefix + && $account->invoice_number_pattern == $account->quote_number_pattern) { Session::flash('error', trans('texts.invalid_counter')); return Redirect::to('settings/'.ACCOUNT_INVOICE_SETTINGS)->withInput(); @@ -1296,8 +1306,8 @@ class AccountController extends BaseController } $email = User::withTrashed()->where('email', '=', $email) - ->where('id', '<>', $user->registered ? 0 : $user->id) - ->first(); + ->where('id', '<>', $user->registered ? 0 : $user->id) + ->first(); if ($email) { return 'taken'; @@ -1505,8 +1515,8 @@ class AccountController extends BaseController { $template = Input::get('template'); $invitation = \App\Models\Invitation::scope() - ->with('invoice.client.contacts') - ->first(); + ->with('invoice.client.contacts') + ->first(); if (! $invitation) { return trans('texts.create_invoice_for_sample'); diff --git a/app/Listeners/DNSListener.php b/app/Listeners/DNSListener.php index 83d6253a74a4..33126f86520a 100644 --- a/app/Listeners/DNSListener.php +++ b/app/Listeners/DNSListener.php @@ -2,6 +2,7 @@ namespace App\Listeners; +use App\Events\SubdomainWasRemoved; use App\Events\SubdomainWasUpdated; use App\Ninja\DNS\Cloudflare; @@ -19,4 +20,11 @@ class DNSListener if(env("CLOUDFLARE_DNS_ENABLED")) Cloudflare::addDNSRecord($event->account); } + + public function removeDNSRecord(SubdomainWasRemoved $event) + { + if(env("CLOUDFLARE_DNS_ENABLED")) + Cloudflare::removeDNSRecord($event->account); + } + } diff --git a/app/Ninja/DNS/Cloudflare.php b/app/Ninja/DNS/Cloudflare.php index 5bdabf9e5912..3c6f31327399 100644 --- a/app/Ninja/DNS/Cloudflare.php +++ b/app/Ninja/DNS/Cloudflare.php @@ -18,31 +18,16 @@ class Cloudflare if($account->subdomain != "") { - $curl = curl_init(); $jsonEncodedData = json_encode(['type' => 'A', 'name' => $account->subdomain, 'content' => env('CLOUDFLARE_TARGET_IP_ADDRESS', ''), 'proxied' => true]); - $opts = [ - CURLOPT_URL => 'https://api.cloudflare.com/client/v4/zones/' . $zone . '/dns_records', - CURLOPT_RETURNTRANSFER => true, - CURLOPT_CUSTOMREQUEST => 'POST', - CURLOPT_POST => 1, - CURLOPT_POSTFIELDS => $jsonEncodedData, - CURLOPT_HTTPHEADER => ['Content-Type: application/json', - 'Content-Length: ' . strlen($jsonEncodedData), - 'X-Auth-Email: ' . env('CLOUDFLARE_EMAIL', ''), - 'X-Auth-Key: ' . env('CLOUDFLARE_API_KEY', '') - ], - ]; + $requestType = 'POST'; - curl_setopt_array($curl, $opts); + $url = 'https://api.cloudflare.com/client/v4/zones/' . $zone . '/dns_records'; - $result = curl_exec($curl); - $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + $response = self::curlCloudFlare($requestType, $url, $jsonEncodedData); - curl_close($curl); - - if ($status != 200) - Utils::logError('unable to update subdomain ' . $account->subdomain . ' @ Cloudflare - ' . $result); + if ($response['status'] != 200) + Utils::logError('Unable to update subdomain ' . $account->subdomain . ' @ Cloudflare - ' . $response['result']['result']); } @@ -51,5 +36,96 @@ class Cloudflare } + public static function removeDNSRecord(Account $account) { + + $zones = json_decode(env('CLOUDFLARE_ZONE_IDS',''), true); + + foreach($zones as $zone) + { + + if($account->subdomain != "") + { + + $dnsRecordId = self::getDNSRecord($zone, $account->subdomain); + + $jsonEncodedData = json_encode([]); + + $requestType = 'DELETE'; + + $url = 'https://api.cloudflare.com/client/v4/zones/' . $zone . '/dns_records/'. $dnsRecordId .''; + + $response = self::curlCloudFlare($requestType, $url, $jsonEncodedData); + + if ($response['status'] != 200) + Utils::logError('Unable to delete subdomain ' . $account->subdomain . ' @ Cloudflare - ' . $response['result']['result']); + + } + + } + + } + + public static function getDNSRecord($zone, $aRecord) + { + //harvest the zone_name + $url = 'https://api.cloudflare.com/client/v4/zones/'. $zone .'/dns_records?type=A&per_page=1'; + + $requestType = 'GET'; + + $jsonEncodedData = json_encode([]); + + $response = self::curlCloudFlare($requestType, $url, $jsonEncodedData); + + if ($response['status'] != 200) + Utils::logError('Unable to get the zone name for ' . $aRecord . ' @ Cloudflare - ' . $response['result']['result']); + + $zoneName = $response['result']['result'][0]['zone_name']; + + //get the A record + $url = 'https://api.cloudflare.com/client/v4/zones/'. $zone .'/dns_records?type=A&name='. $aRecord .'.'. $zoneName .' '; + + $response = self::curlCloudFlare($requestType, $url, $jsonEncodedData); + + if ($response['status'] != 200) + Utils::logError('Unable to get the record ID for ' . $aRecord . ' @ Cloudflare - ' . $response['result']['result']); + + return $response['result']['result'][0]['id']; + + } + + private static function curlCloudFlare($requestType, $url, $jsonEncodedData) + { + + $curl = curl_init(); + + $opts = [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => $requestType, + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => $jsonEncodedData, + CURLOPT_HTTPHEADER => ['Content-Type: application/json', + 'Content-Length: ' . strlen($jsonEncodedData), + 'X-Auth-Email: ' . env('CLOUDFLARE_EMAIL', ''), + 'X-Auth-Key: ' . env('CLOUDFLARE_API_KEY', '') + ], + ]; + + curl_setopt_array($curl, $opts); + + $result = curl_exec($curl); + + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + + $data['status'] = $status; + + $data['result'] = \json_decode($result, true); + + curl_close($curl); + + return $data; + + } + } \ No newline at end of file diff --git a/app/Ninja/Transformers/ProjectTransformer.php b/app/Ninja/Transformers/ProjectTransformer.php index dbff6390a40a..ad049b183727 100644 --- a/app/Ninja/Transformers/ProjectTransformer.php +++ b/app/Ninja/Transformers/ProjectTransformer.php @@ -17,6 +17,9 @@ class ProjectTransformer extends EntityTransformer * @SWG\Property(property="archived_at", type="integer", example=1451160233, readOnly=true) * @SWG\Property(property="is_deleted", type="boolean", example=false, readOnly=true) * @SWG\Property(property="task_rate", type="number", format="float", example=10) + * @SWG\Property(property="due_date", type="string", format="date", example="2016-01-01") + * @SWG\Property(property="private_notes", type="string", format="Sample notes", example=10) + * @SWG\Property(property="budgeted_hours", type="number", format="float", example=10) */ public function transform(Project $project) { @@ -28,6 +31,9 @@ class ProjectTransformer extends EntityTransformer 'archived_at' => $this->getTimestamp($project->deleted_at), 'is_deleted' => (bool) $project->is_deleted, 'task_rate' => (float) $project->task_rate, + 'due_date' => $project->due_date, + 'private_notes' => $project->private_notes, + 'budgeted_hours' => (float) $project->budgeted_hours, ]); } } diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 3f9723c93358..5a501e891df9 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -225,9 +225,14 @@ class EventServiceProvider extends ServiceProvider 'App\Listeners\InvoiceListener@jobFailed' ], - //DNS + //DNS Add A record to Cloudflare 'App\Events\SubdomainWasUpdated' => [ 'App\Listeners\DNSListener@addDNSRecord' + ], + + //DNS Remove A record from Cloudflare + 'App\Events\SubdomainWasRemoved' => [ + 'App\Listeners\DNSListener@removeDNSRecord' ] /*