Initial release with Customer and Domain

This commit is contained in:
Deon George 2022-08-04 20:45:31 +10:00
commit 379f20590e
6 changed files with 568 additions and 0 deletions

22
composer.json Normal file
View File

@ -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"
}

224
src/API.php Normal file
View File

@ -0,0 +1,224 @@
<?php
namespace Dreamscape;
use Dreamscape\Response\Base;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Dreamscape\Response\Generic;
final class API
{
private const LOGKEY = 'API';
private const CACHE_TIME = 60*60*12;
private const MAX_LIMIT = 100;
// Our reseller details
private string $key;
private string $url;
public function __construct(string $id,string $key,bool $tryprod=FALSE)
{
$this->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;
}
}

32
src/Models/Customer.php Normal file
View File

@ -0,0 +1,32 @@
<?php
namespace Dreamscape\Models;
use Jenssegers\Model\Model;
/*
"id" => 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
{
}

65
src/Models/Domain.php Normal file
View File

@ -0,0 +1,65 @@
<?php
namespace Dreamscape\Models;
use Jenssegers\Model\Model;
/*
"id" => 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
{
}

214
src/Response/Base.php Normal file
View File

@ -0,0 +1,214 @@
<?php
namespace Dreamscape\Response;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Log;
use Dreamscape\Models\{Customer,Domain};
/**
* This parent class handles responses received from Trello
*
* @note: This class is used for events not specifically created.
*/
abstract class Base implements \JsonSerializable, \Countable, \ArrayAccess, \Iterator
{
protected const LOGKEY = 'RB-';
protected Collection $_data;
protected bool $_status;
protected object $_pagination;
protected ?string $_type;
private ?int $counter = NULL;
protected const TYPES = [
'customers',
'domains',
];
/**
* Default Constructor Setup
*
* @param object $response
* @param string $type
* @throws \Exception
*/
public function __construct(object $response,string $type)
{
if (! in_array($type,self::TYPES))
throw new \Exception('Unknown data type: '.$type);
$this->_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;
}
}

11
src/Response/Generic.php Normal file
View File

@ -0,0 +1,11 @@
<?php
namespace Dreamscape\Response;
/**
* This is a Generic Dreamscape Response to API calls
*/
class Generic extends Base
{
protected const LOGKEY = 'RGD';
}