You've already forked laravel-connect
First commit
This commit is contained in:
264
src/Connect.php
Normal file
264
src/Connect.php
Normal file
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
|
||||
namespace Bluesquare\Connect;
|
||||
|
||||
use Bluesquare\Connect\Traits\HasConnectSync;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
class Connect
|
||||
{
|
||||
protected $app;
|
||||
protected $synchronized = [];
|
||||
|
||||
public function __construct(array $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
// User config
|
||||
|
||||
public function setSynchronized($models)
|
||||
{
|
||||
$this->synchronized = [];
|
||||
|
||||
foreach ($models as $model)
|
||||
{
|
||||
if (!in_array(HasConnectSync::class, class_uses($model)))
|
||||
throw new ConnectException("$model does not implement HasConnectSync trait.");
|
||||
|
||||
$class = explode('\\', $model);
|
||||
$resource = $model::$connectResource ?? end($class);
|
||||
|
||||
$this->synchronized[$resource] = $model;
|
||||
}
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
/**
|
||||
* @param $method
|
||||
* @param $uri
|
||||
* @param null $data
|
||||
* @return \Psr\Http\Message\StreamInterface
|
||||
* @throws ConnectException
|
||||
*/
|
||||
public function request($method, $uri, $data = null, $auth = true): StreamInterface
|
||||
{
|
||||
$url = config('bconnect.url') ?? 'https://connect.bluesquare.io';
|
||||
$url = $url . '/' . trim($uri, '/');
|
||||
|
||||
$client = new Client();
|
||||
|
||||
$config = [
|
||||
'headers' => [
|
||||
'Accept' => 'application/json'
|
||||
]
|
||||
];
|
||||
|
||||
if ($auth === true) {
|
||||
$config['Authorization'] = 'Bearer ' . $this->getAccessToken();
|
||||
}
|
||||
elseif ($auth !== false) {
|
||||
$config['Authorization'] = 'Bearer ' . $auth;
|
||||
}
|
||||
|
||||
if (!is_null($data)) {
|
||||
$config['form_params'] = $data;
|
||||
}
|
||||
|
||||
try {
|
||||
return json_decode(
|
||||
$client->request($method, $url, $config)->getBody(),
|
||||
true
|
||||
);
|
||||
|
||||
} catch(\Exception $e) {
|
||||
$this->deleteAccessToken();
|
||||
throw new ConnectException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// OAuth (user)
|
||||
|
||||
public function redirect($state = null)
|
||||
{
|
||||
if (is_null($state))
|
||||
$state = Str::random();
|
||||
|
||||
$states = session()->get('connect_states');
|
||||
if (!is_array($states))
|
||||
$states = [];
|
||||
$states[] = $state;
|
||||
session()->put('connect_states', $states);
|
||||
|
||||
$query = http_build_query([
|
||||
'client_id' => config('bconnect.client_id'),
|
||||
'scope' => config('bconnect.scopes'),
|
||||
'redirect_uri' => config('bconnect.redirect'),
|
||||
'response_type' => 'code',
|
||||
'state' => $state
|
||||
]);
|
||||
|
||||
$url = config('bconnect.url') . '/oauth/authorize?' . $query;
|
||||
return redirect()->to($url);
|
||||
}
|
||||
|
||||
public function loginFromCallback(Request $request)
|
||||
{
|
||||
// State check
|
||||
|
||||
if (!session()->has('connect_states'))
|
||||
abort(403, "Session expired");
|
||||
|
||||
$states = session()->get('connect_states');
|
||||
|
||||
if (!is_array($states))
|
||||
abort(403, "Session expired");
|
||||
|
||||
if (!$request->has('state') || !in_array($request->state, $states))
|
||||
abort(403, "Invalid state");
|
||||
|
||||
unset($states[array_search($request->state, $states)]);
|
||||
|
||||
session()->put('connect_states', $states);
|
||||
|
||||
// Code check
|
||||
|
||||
if (!$request->has('code'))
|
||||
abort(403, "Missing authorization code");
|
||||
|
||||
$code = $request->code;
|
||||
|
||||
// Access token
|
||||
|
||||
$data = $this->request('post', 'oauth/token', [
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => config('bconnect.client_id'),
|
||||
'client_secret' => config('bconnect.client_secret'),
|
||||
'scope' => config('bconnect.user_scopes'),
|
||||
'authorization_code' => $code
|
||||
], false);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
// OAuth (client)
|
||||
|
||||
public function getAccessToken()
|
||||
{
|
||||
$access_token = cache()->get('bconnect.access_token');
|
||||
$access_token_expiration = cache()->get('bconnect.access_token_expiration');
|
||||
|
||||
if ($access_token && $access_token_expiration > time() + 60) {
|
||||
return $access_token;
|
||||
}
|
||||
|
||||
$data = $this->request('post', '/oauth/token', [
|
||||
'grant_type' => 'client_credentials',
|
||||
'client_id' => config('bconnect.client_id'),
|
||||
'client_secret' => config('bconnect.client_secret'),
|
||||
'scope' => config('bconnect.client_scopes')
|
||||
], false);
|
||||
|
||||
cache()->set('bconnect.access_token', $data['access_token']);
|
||||
cache()->set('bconnect.access_token_expiration', time() + $data['expires_in']);
|
||||
|
||||
return $data['access_token'];
|
||||
}
|
||||
|
||||
public function deleteAccessToken()
|
||||
{
|
||||
cache()->delete('bconnect.access_token');
|
||||
cache()->delete('bconnect.access_token_expiration');
|
||||
}
|
||||
|
||||
// Webhooks handler
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
public function handleWebhook(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'connectEventType' => 'required|in:created,updated,deleted',
|
||||
'connectResourceType' => 'required',
|
||||
'connectResourceTable' => 'required',
|
||||
'connectResourceData' => 'required|array',
|
||||
'connectResourceData.id' => 'required'
|
||||
]);
|
||||
|
||||
if (!array_key_exists($data['connectResourceType'], $this->synchronized))
|
||||
return false;
|
||||
|
||||
$model = $this->synchronized[$data['connectResourceType']];
|
||||
$method = $this->getEventMethod($data['connectEventType']);
|
||||
$data = $data['connectResourceData'];
|
||||
$model::$method($data['id'], $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Resources endpoints
|
||||
|
||||
public function getAll($resourceType)
|
||||
{
|
||||
return $this->request('get', "api/resources/$resourceType");
|
||||
}
|
||||
|
||||
public function get($resourceType, $resourceId)
|
||||
{
|
||||
return $this->request('get', "api/resources/$resourceType/$resourceId");
|
||||
}
|
||||
|
||||
// Resources sync
|
||||
|
||||
public function syncAll($resourceTypes = null)
|
||||
{
|
||||
$resourceTypes = $resourceTypes ?? $this->synchronized;
|
||||
|
||||
foreach ($resourceTypes as $resourceType)
|
||||
{
|
||||
if (!array_key_exists($resourceType, $this->synchronized))
|
||||
throw new ConnectException("Resource $resourceType not declared as synchronized.");
|
||||
|
||||
$resources = $this->getAll($resourceType);
|
||||
$model = $this->synchronized[$resourceType];
|
||||
$identifiers = [];
|
||||
|
||||
foreach ($resources as $data)
|
||||
{
|
||||
$identifiers[] = intval($data['id']);
|
||||
$this->sync($resourceType, $data['id'], $data);
|
||||
}
|
||||
|
||||
foreach ($model::all() as $item)
|
||||
{
|
||||
if (!in_array(intval($item->id), $identifiers))
|
||||
$item->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function sync($resourceType, $resourceId, $resourceData = null)
|
||||
{
|
||||
if (is_null($resourceData)) {
|
||||
$resourceData = $this->get($resourceType, $resourceId);
|
||||
}
|
||||
|
||||
$model = $this->synchronized[$resourceType];
|
||||
$item = $model::find($resourceId);
|
||||
$method = $this->getEventMethod($item ? 'updated' : 'created');
|
||||
$model::$method($resourceId, $resourceData);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
protected function getEventMethod($event)
|
||||
{
|
||||
return 'onConnectResource' . ucfirst($event);
|
||||
}
|
||||
}
|
||||
5
src/ConnectException.php
Normal file
5
src/ConnectException.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Bluesquare\Connect;
|
||||
|
||||
class ConnectException extends \Exception {}
|
||||
37
src/ConnectServiceProvider.php
Normal file
37
src/ConnectServiceProvider.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Bluesquare\Connect;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class ConnectServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->mergeConfigFrom(
|
||||
__DIR__ . '/../config/bconnect.php',
|
||||
'bmail'
|
||||
);
|
||||
|
||||
$this->app->singleton(Connect::class, function ($app) {
|
||||
return new Connect($app);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->publishes([
|
||||
__DIR__ . '/../config/bconnect.php' => config_path('bconnect.php')
|
||||
], 'config');
|
||||
}
|
||||
}
|
||||
34
src/traits/HasConnectSync.php
Normal file
34
src/traits/HasConnectSync.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Bluesquare\Connect\Traits;
|
||||
|
||||
trait HasConnectSync
|
||||
{
|
||||
abstract function fill($data);
|
||||
abstract function save();
|
||||
abstract function delete();
|
||||
|
||||
public static $connectResource;
|
||||
|
||||
public static function onConnectResourceCreated($id, $data)
|
||||
{
|
||||
$record = new self;
|
||||
$record->fill($data);
|
||||
$record->save();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function onConnectResourceUpdated($id, $data)
|
||||
{
|
||||
$record = self::find($id) ?? new self;
|
||||
$record->fill($data);
|
||||
$record->save();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function onConnectResourceDeleted($id, $data)
|
||||
{
|
||||
$record = self::find($id);
|
||||
return $record ? $record->delete() : false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user