From 379f20590e3492dcd888857ace67076a96d83c50 Mon Sep 17 00:00:00 2001 From: Deon George Date: Thu, 4 Aug 2022 20:45:31 +1000 Subject: [PATCH] Initial release with Customer and Domain --- composer.json | 22 ++++ src/API.php | 224 +++++++++++++++++++++++++++++++++++++++ src/Models/Customer.php | 32 ++++++ src/Models/Domain.php | 65 ++++++++++++ src/Response/Base.php | 214 +++++++++++++++++++++++++++++++++++++ src/Response/Generic.php | 11 ++ 6 files changed, 568 insertions(+) create mode 100644 composer.json create mode 100644 src/API.php create mode 100644 src/Models/Customer.php create mode 100644 src/Models/Domain.php create mode 100644 src/Response/Base.php create mode 100644 src/Response/Generic.php diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..bdbe114 --- /dev/null +++ b/composer.json @@ -0,0 +1,22 @@ +{ + "name": "leenooks/dreamscape", + "description": "Dreamscape API", + "keywords": ["laravel","leenooks","dreamscape"], + "authors": [ + { + "name": "Deon George", + "email": "deon@leenooks.net" + } + ], + "require": { + "jenssegers/model": "^1.5" + }, + "require-dev": { + }, + "autoload": { + "psr-4": { + "Dreamscape\\": "src" + } + }, + "minimum-stability": "dev" +} diff --git a/src/API.php b/src/API.php new file mode 100644 index 0000000..67a1d55 --- /dev/null +++ b/src/API.php @@ -0,0 +1,224 @@ +url = (config('app.env') == 'local' && ! $tryprod) ? 'https://reseller-api.sandbox.ds.network' : 'https://reseller-api.ds.network'; + $this->key = $key; + + Log::debug(sprintf('%s:Dreamscape API for id [%s]',static::LOGKEY,$id)); + } + + /** + * Call the API + * + * @param string $path + * @param array $parameters + * @return object|array + * @throws \Exception + */ + private function execute(string $path,array $parameters=[]) + { + $url = sprintf('%s/%s',$this->url,$path); + $request_id = md5(uniqid().microtime(true)); + $signature = md5($request_id.$this->key); + $method = Arr::get($parameters,'method','GET'); + + if ($parameters) + Arr::forget($parameters,'method'); + + // If we are passed an array, we'll do a normal post. + switch ($method) { + case 'GET': + $request = $this->prepareRequest( + $url, + $parameters, + [ + 'accept: application/json', + 'Api-Request-Id: '.$request_id, + 'Api-Signature: '.$signature, + ] + ); + break; + + case 'POST': + $request = $this->prepareRequestPost( + $url, + $parameters, + [ + 'accept: application/json', + 'Api-Request-Id: '.$request_id, + 'Api-Signature: '.$signature, + ] + ); + break; + + case 'PUT': + $request = $this->prepareRequestPut( + $url, + $parameters, + [ + 'accept: application/json', + 'Api-Request-Id: '.$request_id, + 'Api-Signature: '.$signature, + ] + ); + break; + + default: + throw new \Exception(sprintf('Unknown method: %s',$method)); + } + + $key = md5($path.serialize($parameters)); + + //Cache::forget($key); + $result = Cache::remember($key,self::CACHE_TIME,function() use ($request,$url) { + try { + $response = curl_exec($request); + + switch($x=curl_getinfo($request,CURLINFO_HTTP_CODE)) { + case 400: + case 404: + dump([$xx=curl_getinfo($request),'response'=>$response]); + + throw new \Exception(sprintf('CURL exec returned %d: %s (%s)',$x,curl_error($request),serialize($xx))); + } + + curl_close($request); + return json_decode($response); + + } catch (\Exception $e) { + dump(['error'=>$e->getMessage()]); + Log::error(sprintf('%s:Got an error while posting to [%s] (%s)',static::LOGKEY,$url,$e->getMessage()),['m'=>__METHOD__]); + + curl_close($request); + throw new \Exception($e->getMessage()); + } + }); + + return $result; + } + + /** + * Get a list of our clients + * + * @param array $parameters + * @return Generic + * @throws \Exception + */ + public function getCustomers(array $parameters=[]): Generic + { + Log::debug(sprintf('%s:Get a list of customers',static::LOGKEY)); + $key = 'customers'; + + $fetchall = FALSE; + if (Arr::get($parameters,'fetchall')) { + Arr::forget($parameters,['fetchall']); + $parameters['limit'] = self::MAX_LIMIT; + $parameters['page'] = 1; + + $fetchall = TRUE; + } + + $o = new Generic($this->execute($key,$parameters),$key); + + return $fetchall ? $this->fetchall($o,$key,$parameters) : $o; + } + + private function fetchall(Base $o,string $path,array $parameters): Base + { + while ($o->hasMore()) { + $parameters['page']++; + + $o->merge($this->execute($path,$parameters)); + } + + return $o; + } + + /** + * Get a list of our clients domains + * + * @param array $parameters + * @return Generic + * @throws \Exception + */ + public function getDomains(array $parameters=[]): Generic + { + Log::debug(sprintf('%s:Get a list of domains',static::LOGKEY)); + + return new Generic($this->execute('domains',$parameters),'domains'); + } + + /** + * Get a list of our available product types + * + * @return Generic + * @throws \Exception + */ + public function getProductTypes(): Generic + { + Log::debug(sprintf('%s:Get a list of product types',static::LOGKEY)); + + return new Generic($this->execute('products/types')); + } + + /** + * Setup the API call + * + * @param $url + * @param array $parameters + * @param array $headers + * @return resource + */ + private function prepareRequest($url,array $parameters=[],array $headers=[]) + { + $request = curl_init(); + + curl_setopt($request,CURLOPT_URL,$url.($parameters ? '?'.http_build_query($parameters) : '')); + curl_setopt($request,CURLOPT_RETURNTRANSFER,TRUE); + if ($headers) + curl_setopt($request,CURLOPT_HTTPHEADER,$headers); + curl_setopt($request,CURLINFO_HEADER_OUT,TRUE); + curl_setopt($request,CURLOPT_SSL_VERIFYPEER,FALSE); + + return $request; + } + + private function prepareRequestPost($url,$parameters='',$headers=[]) + { + $request = $this->prepareRequest($url,[],$headers); + curl_setopt($request,CURLOPT_POST,TRUE); + curl_setopt($request,CURLOPT_POSTFIELDS,json_encode($parameters)); + + return $request; + } + + private function prepareRequestPut($url,$parameters='',$headers=[]) + { + $request = $this->prepareRequest($url,[],$headers); + //curl_setopt($request,CURLOPT_PUT,TRUE); + curl_setopt($request,CURLOPT_CUSTOMREQUEST,'PUT'); + curl_setopt($request,CURLOPT_POSTFIELDS,json_encode($parameters)); + + return $request; + } +} \ No newline at end of file diff --git a/src/Models/Customer.php b/src/Models/Customer.php new file mode 100644 index 0000000..b8eb98a --- /dev/null +++ b/src/Models/Customer.php @@ -0,0 +1,32 @@ + 5249071 + "status_id" => 1 + "username" => "graytech" + "first_name" => "Deon" + "last_name" => "George" + "address" => "48B Celia Street" + "city" => "Bentleigh East" + "country" => "AU" + "state" => "VIC" + "post_code" => "3165" + "country_code" => 61 + "phone" => "354101135" + "mobile" => null + "email" => "deon..@..t.au" + "currency" => "AUD" + "account_type" => "business" + "business_name" => "Graytech Hosting Pty Ltd" + "business_number_type" => "ABN" + "business_number" => "49106229476" + "date_added" => "2013-05-21T19:43:06+00:00" + */ + +final class Customer extends Model +{ +} \ No newline at end of file diff --git a/src/Models/Domain.php b/src/Models/Domain.php new file mode 100644 index 0000000..da514d5 --- /dev/null +++ b/src/Models/Domain.php @@ -0,0 +1,65 @@ + 20756501 + "domain_name" => "graytech.net.au" + "auth_key" => "" + "status_id" => 2 + "period" => 24 + "start_date" => "2021-07-19T06:18:38+00:00" + "expiry_date" => "2023-09-22T00:00:00+00:00" + "customer_id" => 5249071 + "registrant_id" => 22203773 + "admin_contact_id" => 5249071 + "billing_contact_id" => 5249071 + "tech_contact_id" => 5249071 + "name_servers" => array:2 [ + 0 => {#1109 + +"host": "arch.ns.cloudflare.com" + +"ip": "173.245.59.68,2803:f800:50::6ca2:c144" + } + 1 => {#1110 + +"host": "brianna.ns.cloudflare.com" + +"ip": "173.245.58.245,2a06:98c1:50::ac40:20f5" + } + ] + "is_locked" => false + "privacy" => false + "eligibility_data" => array:7 [ + 0 => {#1111 + +"name": "business_type" + +"value": "Company" + } + 1 => {#1112 + +"name": "business_name" + +"value": null + } + 2 => {#1113 + +"name": "business_number_type" + +"value": "ACN" + } + 3 => {#1114 + +"name": "business_number" + +"value": "106 229 476" + } + 4 => {#1115 + +"name": "trading_name" + +"value": "Graytech Hosting Pty Ltd" + } + 5 => {#1116 + +"name": "trading_number_type" + +"value": "ACN" + } + 6 => {#1117 + +"name": "trading_number" + +"value": "106 229 476" + } + */ + +final class Domain extends Model +{ +} \ No newline at end of file diff --git a/src/Response/Base.php b/src/Response/Base.php new file mode 100644 index 0000000..e3f6b9f --- /dev/null +++ b/src/Response/Base.php @@ -0,0 +1,214 @@ +_data = $this->data($response,$type); + $this->_status = $response->status; + $this->_pagination = $response->pagination; + $this->_type = $type; + + // This is only for child classes + if (get_class($this) == Base::class) { + Log::debug(sprintf('%s:Dreamscape RESPONSE Initialised [%s]',static::LOGKEY,get_class($this)),['m'=>__METHOD__]); + + if (App::environment() == 'dev') + file_put_contents('/tmp/response',print_r($this,TRUE),FILE_APPEND); + } + } + + /* ABSTRACT */ + + /** + * When we json_encode this object, this is the data that will be returned + */ + public function jsonSerialize(): mixed + { + return $this->_data ?: new \stdClass; + } + + public function current(): mixed + { + return $this->_data[$this->counter]; + } + + public function next(): void + { + $this->counter++; + } + + public function key(): mixed + { + return $this->counter; + } + + public function valid(): bool + { + return isset($this->_data[$this->counter]); + } + + public function rewind(): void + { + $this->counter = 0; + } + + public function offsetExists(mixed $offset): bool + { + return $this->has($offset); + } + + public function offsetGet(mixed $offset): mixed + { + return $this->_data->get($offset); + } + + public function offsetSet(mixed $offset, mixed $value): void + { + throw new \Exception('Method not implemented: '.__METHOD__); + } + + public function offsetUnset(mixed $offset): void + { + $this->_data->forget($offset); + + // Rekey the collection + $this->_data = $this->_data->values(); + + // Reset the counter if we have deleted a value before it + if ($offset < $this->counter) + $this->counter--; + } + + public function count(): int + { + return count($this->_data); + } + + /* METHODS */ + + /** + * Convert our response into a collection of the appropriate model + * + * @param object $response + * @param string $type + * @return Collection + * @throws \Exception + */ + private function data(object $response,string $type): Collection + { + switch ($type) { + case 'customers': + $data = collect(Customer::hydrate($response->data)); + break; + + case 'domains': + $data = collect(Domain::hydrate($response->data)); + break; + + default: throw new \Exception('Unknown object type: '.$this->_type); + } + + return $data; + } + + /** + * Determine if there are more values to obtain + * + * @return bool + */ + public function hasMore(): bool + { + return $this->_status && ($this->count() < $this->totalItems()); + } + + /** + * Merge more values to the result + * + * @param object $response + * @return void + * @throws \Exception + */ + public function merge(object $response): void + { + $this->_data = $this->_data->merge($this->data($response,$this->_type)); + } + + /** + * Return the current resultset page number + * + * @return int + */ + public function page(): int + { + return $this->_pagination->current_page; + } + + /** + * Search for an item in the result + * + * @param string $key + * @param mixed $value + * @return mixed + */ + public function search(string $key, mixed $value): mixed + { + return $this->_data->search(function($item) use ($key,$value) { return $item->{$key} == $value; }); + } + + /** + * Return the result status + * + * @return bool + */ + public function status(): bool + { + return $this->_status; + } + + /** + * Return the total items available + * + * @return int + */ + public function totalItems(): int + { + return $this->_pagination->total_items; + } +} \ No newline at end of file diff --git a/src/Response/Generic.php b/src/Response/Generic.php new file mode 100644 index 0000000..3e5d371 --- /dev/null +++ b/src/Response/Generic.php @@ -0,0 +1,11 @@ +