Initial implementation
This commit is contained in:
commit
bcbde6359a
21
composer.json
Normal file
21
composer.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "leenooks/trello",
|
||||||
|
"description": "Trello API",
|
||||||
|
"keywords": ["laravel","leenooks","trello"],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Deon George",
|
||||||
|
"email": "deon@leenooks.net"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Trello\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimum-stability": "dev"
|
||||||
|
}
|
294
src/API.php
Normal file
294
src/API.php
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello;
|
||||||
|
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Trello\Models\{Board,BoardList,Card,CustomField,Token};
|
||||||
|
use Trello\Models\CustomFields\{ListList,Options\Option};
|
||||||
|
use Trello\Response\Generic;
|
||||||
|
|
||||||
|
final class API
|
||||||
|
{
|
||||||
|
private const LOGKEY = 'API';
|
||||||
|
private const VERSION = 1;
|
||||||
|
private const CACHE_TIME = 600;
|
||||||
|
private const URL = 'https://api.trello.com';
|
||||||
|
|
||||||
|
// Our trello token to use
|
||||||
|
private $_token;
|
||||||
|
|
||||||
|
public function __construct(Token $o)
|
||||||
|
{
|
||||||
|
$this->_token = $o;
|
||||||
|
|
||||||
|
Log::debug(sprintf('%s:Trello API with token [%s]',static::LOGKEY,$this->_token ? $this->_token->token_hidden() : NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createCard(Card $card): Card
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('%s:Create Card [%s] on list [%s]',static::LOGKEY,$card->name,$card->idList));
|
||||||
|
|
||||||
|
return (new Card)->forceFill((array)$this->execute('cards',array_merge($card->toArray(),['method'=>'POST']))) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createCustomField(Board $board,string $name,string $type): CustomField
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('%s:Create CustomField [%s] in Boards [%s]',static::LOGKEY,$name,$board->id));
|
||||||
|
if (! in_array($type,['checkbox','list','number','text','date']))
|
||||||
|
throw new \Exception('Invalid type: '.$type);
|
||||||
|
|
||||||
|
// Invalidate any cache
|
||||||
|
Cache::forget(md5(sprintf('boards/%s/customFields',$board->id).serialize([])));
|
||||||
|
|
||||||
|
return CustomField::factory($this->execute('customFields',[
|
||||||
|
'name'=>$name,
|
||||||
|
'type'=>$type,
|
||||||
|
'idModel'=>$board->id,
|
||||||
|
'display_cardFront'=>'true',
|
||||||
|
'modelType'=>'board',
|
||||||
|
'method'=>'POST'
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createCustomFieldOptions(ListList $field,Collection $options): ListList
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('%s:Create CustomField Options to [%s] (%s)',static::LOGKEY,$field->name,$options->pluck('value.text')->join('|')));
|
||||||
|
|
||||||
|
// Invalidate any cache
|
||||||
|
Cache::forget(md5(sprintf('boards/%s/customFields',$field->idModel).serialize([])));
|
||||||
|
|
||||||
|
foreach ($options as $option) {
|
||||||
|
Log::debug(sprintf('%s: Adding (%s)',static::LOGKEY,Arr::get($option,'value.text')));
|
||||||
|
|
||||||
|
$field->addOption((new Option)->forceFill((array)$this->execute(
|
||||||
|
sprintf('customFields/%s/options',$field->id),
|
||||||
|
array_merge(
|
||||||
|
$option,
|
||||||
|
['method'=>'POST']
|
||||||
|
))));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $field;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a list on a board
|
||||||
|
*
|
||||||
|
* @param Board $board
|
||||||
|
* @param string $name
|
||||||
|
* @return BoardList
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function createList(Board $board,string $name): BoardList
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('%s:Create List [%s] in Boards [%s]',static::LOGKEY,$name,$board->id));
|
||||||
|
|
||||||
|
// Invalidate any cache
|
||||||
|
Cache::forget(md5(sprintf('boards/%s/lists',$board->id).serialize([])));
|
||||||
|
|
||||||
|
return (new BoardList)->forceFill((array)$this->execute('lists',['name'=>$name,'idBoard'=>$board->id,'method'=>'POST']))->syncOriginal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the Slack API
|
||||||
|
*
|
||||||
|
* @param string $path // @todo this should really be called $path, since it isnt the HTTP method
|
||||||
|
* @param array $parameters
|
||||||
|
* @return object|array
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
private function execute(string $path,array $parameters=[])
|
||||||
|
{
|
||||||
|
$url = sprintf('%s/%d/%s',self::URL,self::VERSION,$path);
|
||||||
|
$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,
|
||||||
|
[
|
||||||
|
'Content-Type: application/json; charset=utf-8',
|
||||||
|
sprintf('Authorization: OAuth oauth_consumer_key="%s", oauth_token="%s"',$this->_token->key,$this->_token->token),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'POST':
|
||||||
|
$request = $this->prepareRequestPost(
|
||||||
|
$url,
|
||||||
|
$parameters,
|
||||||
|
[
|
||||||
|
'Content-Type: application/json; charset=utf-8',
|
||||||
|
sprintf('Authorization: OAuth oauth_consumer_key="%s", oauth_token="%s"',$this->_token->key,$this->_token->token),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'PUT':
|
||||||
|
$request = $this->prepareRequestPut(
|
||||||
|
$url,
|
||||||
|
$parameters,
|
||||||
|
[
|
||||||
|
'Content-Type: application/json; charset=utf-8',
|
||||||
|
sprintf('Authorization: OAuth oauth_consumer_key="%s", oauth_token="%s"',$this->_token->key,$this->_token->token),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBoards(): Collection
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('%s:Get Boards',static::LOGKEY));
|
||||||
|
|
||||||
|
return Board::hydrate($this->execute('members/me/boards'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCard(string $id): Card
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('%s:Get Card [%s]',static::LOGKEY,$id));
|
||||||
|
|
||||||
|
return (new Card)->forceFill((array)$this->execute(sprintf('cards/%s?%s',$id,http_build_query(['all','customFieldItems'=>'true']))))->syncOriginal();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCustomFields(Board $board): Collection
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('%s:Get CustomFields from [%s]',static::LOGKEY,$board->id));
|
||||||
|
|
||||||
|
$result = collect();
|
||||||
|
foreach ($this->execute(sprintf('boards/%s/customFields',$board->id)) as $cf)
|
||||||
|
$result->push(CustomField::factory($cf));
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of Cards for a Board
|
||||||
|
*
|
||||||
|
* @param Board $board
|
||||||
|
* @return Collection
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function getCards(Board $board): Collection
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('%s:Get Board Cards [%s]',static::LOGKEY,$board->id));
|
||||||
|
|
||||||
|
return Card::hydrate($this->execute(sprintf('boards/%s/cards',$board->id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLists(Board $board): Collection
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('%s:Get Board Lists [%s]',static::LOGKEY,$board->id));
|
||||||
|
|
||||||
|
return BoardList::hydrate($this->execute(sprintf('boards/%s/lists',$board->id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
curl_setopt($request,CURLOPT_HTTPGET,TRUE);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a card's value
|
||||||
|
*
|
||||||
|
* @param Card $card
|
||||||
|
* @param CustomField $cf
|
||||||
|
* @param string $value
|
||||||
|
* @return Generic
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function setFieldValue(Card $card,CustomField $cf,array $value)
|
||||||
|
{
|
||||||
|
if (! $card->id)
|
||||||
|
throw new \Exception('Card doesnt have an id?');
|
||||||
|
|
||||||
|
$x = $this->execute(sprintf('card/%s/customField/%s/item',$card->id,$cf->id),array_merge($value,['method'=>'PUT']));
|
||||||
|
|
||||||
|
return new Generic((array)$x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateCard(Card $card): Card
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('%s:Update Card [%s] on list [%s]',static::LOGKEY,$card->name,$card->idList));
|
||||||
|
|
||||||
|
$x = $this->execute(sprintf('cards/%s',$card->id),array_merge($card->getDirty(),['method'=>'PUT']));
|
||||||
|
|
||||||
|
return (new Card)->forceFill((array)$this->execute(sprintf('cards/%s',$card->id),array_merge($card->getDirty(),['method'=>'PUT'])));
|
||||||
|
}
|
||||||
|
}
|
7
src/Exceptions/TrelloException.php
Normal file
7
src/Exceptions/TrelloException.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Exceptions;
|
||||||
|
|
||||||
|
class TrelloException extends \Exception
|
||||||
|
{
|
||||||
|
}
|
142
src/Models/Board.php
Normal file
142
src/Models/Board.php
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Trello\API;
|
||||||
|
use Trello\Models\CustomFields\ListList;
|
||||||
|
|
||||||
|
final class Board extends Model
|
||||||
|
{
|
||||||
|
protected $keyType = 'string';
|
||||||
|
protected const LOGKEY = 'MTB';
|
||||||
|
|
||||||
|
public Collection $customfields;
|
||||||
|
private API $api;
|
||||||
|
public ?BoardList $newopslist = NULL;
|
||||||
|
public const newopslist = 'New Ops';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the API to store/retrieve values
|
||||||
|
*
|
||||||
|
* @return API
|
||||||
|
* @todo This should be kept private, and we should call functions to retrieve the items we are interested in
|
||||||
|
*/
|
||||||
|
public function api(): API
|
||||||
|
{
|
||||||
|
return $this->api;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a specific custom field
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return CustomField
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function customField(string $name): ?CustomField
|
||||||
|
{
|
||||||
|
return $this->customFields()->filter(function($item) use ($name) { return $item->name == $name;})->pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get this boards custom fields.
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function customFields(): Collection
|
||||||
|
{
|
||||||
|
if (! $this->customfields->count()) {
|
||||||
|
$cf = $this->api->getCustomFields($this);
|
||||||
|
|
||||||
|
// Check all our customFields are of the types we need:
|
||||||
|
foreach ($cf as $key => $field) {
|
||||||
|
if ($x=config('trello.customfields.'.$field->name)) {
|
||||||
|
|
||||||
|
if ($field instanceof $x) {
|
||||||
|
dump(['m'=>__METHOD__,'EXISTS','x'=>$x,'field'=>$field,'listlsit'=>$field instanceof ListList]);
|
||||||
|
|
||||||
|
// If it is a list item, we need to check that the list has all the options
|
||||||
|
if ($field instanceof ListList) {
|
||||||
|
if (! $field->hasAllOptions()) {
|
||||||
|
$this->api->createCustomFieldOptions($field,collect($field->missingOptions())->transform(function($item) { return ['pos'=>'bottom','value'=>['text'=>$item]]; }));
|
||||||
|
//dd(['m'=>__METHOD__,'has failed?'=>collect($field->missingOptions())->transform(function($item,$key) { return ['pos'=>$key,'value'=>['text'=>$item]]; }),'x'=>$x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log::error(sprintf('%s:Field [%s] is not of the right type [%s] (%s)',self::LOGKEY,$field->name,$field->type,$x));
|
||||||
|
|
||||||
|
throw new \Exception(sprintf('Invalid field type: %s (%s), should be [%s]',$field->name,get_class($field),$x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not one of our fields
|
||||||
|
} else {
|
||||||
|
Log::debug(sprintf('%s:Ignoring custom field [%s]',self::LOGKEY,$field->name));
|
||||||
|
|
||||||
|
$cf->forget($key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any missing fields we need to create.
|
||||||
|
foreach (collect(config('trello.customfields'))->filter(function($item,$key) use ($cf) { return $cf->pluck('attributes.name')->search($key) === FALSE; }) as $key => $field) {
|
||||||
|
Log::debug(sprintf('%s:Creating field [%s] (%s)',self::LOGKEY,$key,$field));
|
||||||
|
|
||||||
|
$o = new $field(new \stdClass);
|
||||||
|
dump(['o'=>$o]);
|
||||||
|
$cf->push($x=$this->api->createCustomField($this,$key,$o->trello_type));
|
||||||
|
//dd(['M'=>__METHOD__,'addkey'=>$key,'addfield'=>$field,'x'=>$x]);
|
||||||
|
|
||||||
|
// If it is a list, we'll need to create our options too
|
||||||
|
if ($x instanceof ListList) {
|
||||||
|
$this->api->createCustomFieldOptions($x,collect($x->missingOptions())->transform(function($item) { return ['pos'=>'bottom','value'=>['text'=>$item]]; }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->customfields = $cf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->customfields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the list that we use to create new cards in
|
||||||
|
*
|
||||||
|
* @return BoardList
|
||||||
|
*/
|
||||||
|
public function listNewOps(): BoardList
|
||||||
|
{
|
||||||
|
if (! $this->newopslist) {
|
||||||
|
// Find our "New Opps" List in Trello
|
||||||
|
$newoplist = $this->api
|
||||||
|
->getLists($this)
|
||||||
|
->filter(function($item) { return $item->name == self::newopslist; });
|
||||||
|
|
||||||
|
// If list doesnt exist, we'll create it.
|
||||||
|
if (! $newoplist->count()) {
|
||||||
|
//$newoplist = $api->createList($b,$newopslist);
|
||||||
|
dd([__METHOD__=>$newoplist,'todo'=>'create this']);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$this->newoplist = $newoplist->pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newoplist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record the API that this board is stored/retrieved with
|
||||||
|
*
|
||||||
|
* @param API $api
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setAPI(API $api): void
|
||||||
|
{
|
||||||
|
$this->api = $api;
|
||||||
|
$this->customfields = collect();
|
||||||
|
}
|
||||||
|
}
|
10
src/Models/BoardList.php
Normal file
10
src/Models/BoardList.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
final class BoardList extends Model
|
||||||
|
{
|
||||||
|
protected $keyType = 'string';
|
||||||
|
}
|
58
src/Models/Card.php
Normal file
58
src/Models/Card.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
use App\Trello\Models\CustomFields\{Action,SalesStage};
|
||||||
|
|
||||||
|
final class Card extends Model
|
||||||
|
{
|
||||||
|
protected $keyType = 'string';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get this card's custom field value.
|
||||||
|
*
|
||||||
|
* @param CustomField $o
|
||||||
|
* @return object|null
|
||||||
|
*/
|
||||||
|
public function getCustomFieldValue(CustomField $o): ?object
|
||||||
|
{
|
||||||
|
return collect($this->customFieldItems)->filter(function($item) use ($o) { return $item->idCustomField == $o->id; })->pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if this card should be ignored.
|
||||||
|
*
|
||||||
|
* @param Board $b
|
||||||
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function shouldIgnore(Board $b): bool
|
||||||
|
{
|
||||||
|
// Check Stages
|
||||||
|
$cf = $b->customField('Stage');
|
||||||
|
$y = '';
|
||||||
|
|
||||||
|
if (($x=$this->getCustomFieldValue($cf)) && (! in_array($y=$cf->value($x),SalesStage::options))) {
|
||||||
|
Log::info(sprintf('Card [%s] Stage value is not one of ours [%s]',$this->id,$y));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
Log::debug(sprintf('Card [%s] Stage value is [%s]',$this->id,$y ?: 'Not Set'));
|
||||||
|
|
||||||
|
// Check Actions
|
||||||
|
$cf = $b->customField('Action');
|
||||||
|
$y = '';
|
||||||
|
|
||||||
|
if (($x=$this->getCustomFieldValue($cf)) && (! in_array($y=$cf->value($x),Action::options)) || ($y === 'Ignore')) {
|
||||||
|
Log::info(sprintf('Card [%s] Action value is not one of ours [%s]',$this->id,$y));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
Log::debug(sprintf('Card [%s] Action value is [%s]',$this->id,$y ?: 'Not Set'));
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
68
src/Models/CustomField.php
Normal file
68
src/Models/CustomField.php
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Models;
|
||||||
|
|
||||||
|
use Trello\Models\CustomFields\{Base,Checkbox,Date,ListList,Number,Text};
|
||||||
|
|
||||||
|
abstract class CustomField extends Base
|
||||||
|
{
|
||||||
|
protected $keyType = 'string';
|
||||||
|
private const LOGKEY = 'TCF';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the data into a CustomField Object
|
||||||
|
*
|
||||||
|
* @param object $data
|
||||||
|
* @return mixed|Checkbox|Date|ListList|Number|Text
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function factory(object $data) {
|
||||||
|
// See if the field name is one we have configured
|
||||||
|
if (collect(config('trello.customfields'))->has($x=object_get($data,'name'))) {
|
||||||
|
$xx = config('trello.customfields.'.$x);
|
||||||
|
$o = new $xx($data);
|
||||||
|
|
||||||
|
if ($o->trello_type !== ($y=object_get($data,'type')))
|
||||||
|
throw new \Exception(sprintf('%s:! ERROR - Custom field [%s] (%s) is not the right type [%s]',self::LOGKEY,$x,$o->trello_type,$y));
|
||||||
|
|
||||||
|
return $o;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($x=object_get($data,'type')) {
|
||||||
|
case 'checkbox':
|
||||||
|
return new Checkbox($data);
|
||||||
|
|
||||||
|
case 'date':
|
||||||
|
return new Date($data);
|
||||||
|
|
||||||
|
case 'list':
|
||||||
|
return new ListList($data);
|
||||||
|
|
||||||
|
case 'number':
|
||||||
|
return new Number($data);
|
||||||
|
|
||||||
|
case 'text':
|
||||||
|
return new Text($data);
|
||||||
|
|
||||||
|
default:
|
||||||
|
dump($data);
|
||||||
|
throw new \Exception('Unknown data type: '.$x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a customfield's value
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
abstract public function set(string $value): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a customfield's value
|
||||||
|
*
|
||||||
|
* @param object $key
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
abstract public function value(object $key): ?string;
|
||||||
|
}
|
28
src/Models/CustomFields/Base.php
Normal file
28
src/Models/CustomFields/Base.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Models\CustomFields;
|
||||||
|
|
||||||
|
abstract class Base
|
||||||
|
{
|
||||||
|
public object $attributes;
|
||||||
|
public const options = NULL;
|
||||||
|
|
||||||
|
public function __construct(object $attributes)
|
||||||
|
{
|
||||||
|
$this->attributes = $attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($key)
|
||||||
|
{
|
||||||
|
switch ($key) {
|
||||||
|
case 'trello_type':
|
||||||
|
return object_get($this->attributes,'type');
|
||||||
|
|
||||||
|
case 'type':
|
||||||
|
return get_class($this);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return object_get($this->attributes,$key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
src/Models/CustomFields/Checkbox.php
Normal file
22
src/Models/CustomFields/Checkbox.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Models\CustomFields;
|
||||||
|
|
||||||
|
use Trello\Models\CustomField;
|
||||||
|
|
||||||
|
class Checkbox extends CustomField
|
||||||
|
{
|
||||||
|
/* ABSTRACT METHODS */
|
||||||
|
|
||||||
|
public function set(string $value): array
|
||||||
|
{
|
||||||
|
// @todo TO TEST
|
||||||
|
return ['value'=>['checked'=>$value ? 'true' : 'false']];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function value(object $key): ?string
|
||||||
|
{
|
||||||
|
// @todo TO TEST
|
||||||
|
return (string)$key->value->checked;
|
||||||
|
}
|
||||||
|
}
|
23
src/Models/CustomFields/Date.php
Normal file
23
src/Models/CustomFields/Date.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Models\CustomFields;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Trello\Models\CustomField;
|
||||||
|
|
||||||
|
class Date extends CustomField
|
||||||
|
{
|
||||||
|
/* ABSTRACT METHODS */
|
||||||
|
|
||||||
|
public function set(string $value): array
|
||||||
|
{
|
||||||
|
// @todo TO TEST
|
||||||
|
return ['value'=>['date'=>Carbon::createFromTimeString($value)->toISOString()]];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function value(object $key): ?string
|
||||||
|
{
|
||||||
|
// @todo TO TEST
|
||||||
|
return $key->value->date;
|
||||||
|
}
|
||||||
|
}
|
70
src/Models/CustomFields/ListList.php
Normal file
70
src/Models/CustomFields/ListList.php
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Models\CustomFields;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Trello\Models\CustomField;
|
||||||
|
use Trello\Models\CustomFields\Options\Option;
|
||||||
|
|
||||||
|
class ListList extends CustomField
|
||||||
|
{
|
||||||
|
public Collection $options;
|
||||||
|
|
||||||
|
public function __construct(object $attributes)
|
||||||
|
{
|
||||||
|
parent::__construct($attributes);
|
||||||
|
|
||||||
|
$this->options = collect();
|
||||||
|
|
||||||
|
foreach (object_get($attributes,'options',[]) as $option)
|
||||||
|
$this->addOption((new Option)->forceFill((array)$option)->syncOriginal());
|
||||||
|
|
||||||
|
unset($this->attributes->options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ABSTRACT METHODS */
|
||||||
|
|
||||||
|
public function set(string $value): array
|
||||||
|
{
|
||||||
|
return ['idValue'=>$this->id($value)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value, given a customfield key
|
||||||
|
*
|
||||||
|
* @param object $key
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function value(object $key): ?string
|
||||||
|
{
|
||||||
|
return ($x=$this->options->filter(function($item) use ($key) { return $item->id == $key->idValue; })->pop()) ? $x->value->text : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* METHODS */
|
||||||
|
|
||||||
|
public function addOption(Option $option): void
|
||||||
|
{
|
||||||
|
$this->options->push($option);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure our list has all the option values
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasAllOptions(): bool
|
||||||
|
{
|
||||||
|
return $this->missingOptions()->count() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function id(string $name): ?string
|
||||||
|
{
|
||||||
|
return ($x=$this->options->filter(function($item) use ($name) { return $item->name == $name; })->pop()) ? $x->id : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function missingOptions(): Collection
|
||||||
|
{
|
||||||
|
return collect(static::options)->diff($this->options->pluck('name'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
20
src/Models/CustomFields/Number.php
Normal file
20
src/Models/CustomFields/Number.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Models\CustomFields;
|
||||||
|
|
||||||
|
use Trello\Models\CustomField;
|
||||||
|
|
||||||
|
class Number extends CustomField
|
||||||
|
{
|
||||||
|
/* ABSTRACT METHODS */
|
||||||
|
|
||||||
|
public function set(string $value): array
|
||||||
|
{
|
||||||
|
return ['value'=>['number'=>$value]];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function value(object $key): ?string
|
||||||
|
{
|
||||||
|
return (string)$key->value->number;
|
||||||
|
}
|
||||||
|
}
|
16
src/Models/CustomFields/Options/Option.php
Normal file
16
src/Models/CustomFields/Options/Option.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Models\CustomFields\Options;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
|
class Option extends Model
|
||||||
|
{
|
||||||
|
protected $keyType = 'string';
|
||||||
|
|
||||||
|
public function getNameAttribute(): ?string
|
||||||
|
{
|
||||||
|
return ($x=Arr::get($this->attributes,'value')) ? $x->text : NULL;
|
||||||
|
}
|
||||||
|
}
|
20
src/Models/CustomFields/Text.php
Normal file
20
src/Models/CustomFields/Text.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Models\CustomFields;
|
||||||
|
|
||||||
|
use Trello\Models\CustomField;
|
||||||
|
|
||||||
|
class Text extends CustomField
|
||||||
|
{
|
||||||
|
/* ABSTRACT METHODS */
|
||||||
|
|
||||||
|
public function set(string $value): array
|
||||||
|
{
|
||||||
|
return ['value'=>['text'=>$value]];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function value(object $key): ?string
|
||||||
|
{
|
||||||
|
return $key->value->text;
|
||||||
|
}
|
||||||
|
}
|
20
src/Models/Token.php
Normal file
20
src/Models/Token.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Models;
|
||||||
|
|
||||||
|
final class Token
|
||||||
|
{
|
||||||
|
public string $key;
|
||||||
|
public string $token;
|
||||||
|
|
||||||
|
public function __construct(string $key,string $token)
|
||||||
|
{
|
||||||
|
$this->key = $key;
|
||||||
|
$this->token = $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function token_hidden(): string
|
||||||
|
{
|
||||||
|
return '...'.substr($this->token,-5);
|
||||||
|
}
|
||||||
|
}
|
60
src/Response/Base.php
Normal file
60
src/Response/Base.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Response;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This parent class handles responses received from Trello
|
||||||
|
*
|
||||||
|
* @note: This class is used for events not specifically created.
|
||||||
|
*/
|
||||||
|
class Base implements \JsonSerializable
|
||||||
|
{
|
||||||
|
protected const LOGKEY = 'RB-';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Constructor Setup
|
||||||
|
*
|
||||||
|
* @param object $response
|
||||||
|
*/
|
||||||
|
public function __construct(array $response)
|
||||||
|
{
|
||||||
|
$this->_data = $response;
|
||||||
|
|
||||||
|
// This is only for child classes
|
||||||
|
if (get_class($this) == Base::class) {
|
||||||
|
Log::debug(sprintf('%s:Trello 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable getting values for keys in the response
|
||||||
|
*
|
||||||
|
* @note: This method is limited to certain values to ensure integrity reasons
|
||||||
|
* @note: Classes should return:
|
||||||
|
* + channel_id,
|
||||||
|
* + team_id,
|
||||||
|
* + ts,
|
||||||
|
* + user_id
|
||||||
|
*/
|
||||||
|
public function __get($key)
|
||||||
|
{
|
||||||
|
switch ($key) {
|
||||||
|
case 'id':
|
||||||
|
return object_get($this->_data,$key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When we json_encode this object, this is the data that will be returned
|
||||||
|
*/
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
return $this->_data ? $this->_data : new \stdClass;
|
||||||
|
}
|
||||||
|
}
|
11
src/Response/Generic.php
Normal file
11
src/Response/Generic.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Trello\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a Generic Slack Response to API calls
|
||||||
|
*/
|
||||||
|
class Generic extends Base
|
||||||
|
{
|
||||||
|
protected const LOGKEY = 'RGE';
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user