From a9c1d643a05e7ccca51197ca79cdea262f46ac55 Mon Sep 17 00:00:00 2001 From: bmilesp Date: Fri, 19 Jul 2013 15:07:10 -0400 Subject: [PATCH 01/11] added support for multiple logins per api domain --- Config/Schema/schema.php | 1 + Controller/Component/OauthComponent.php | 26 ++++++++++++++++-------- Model/Behavior/OAuthConsumerBehavior.php | 23 +++++++++++++++++---- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Config/Schema/schema.php b/Config/Schema/schema.php index 5834c5a..8eb54ee 100644 --- a/Config/Schema/schema.php +++ b/Config/Schema/schema.php @@ -17,6 +17,7 @@ public function after($event = array()) { 'refresh_token' => array('type' => 'text', 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 'token_secret' => array('type' => 'text', 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 'expires_in' => array('type' => 'string', 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), + 'api_domain' => array('type' => 'string', 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 'indexes' => array( 'PRIMARY' => array('column' => 'id', 'unique' => 1), 'user_id' => array('column' => array('user_id', 'api'), 'unique' => 1) diff --git a/Controller/Component/OauthComponent.php b/Controller/Component/OauthComponent.php index b0f38ad..351dd01 100644 --- a/Controller/Component/OauthComponent.php +++ b/Controller/Component/OauthComponent.php @@ -63,6 +63,16 @@ protected function _checkAuthFailure(Controller $controller) { function getOauthUri($apiName, $path, $extra = array()) { if (Configure::check('Copula.' . $apiName . '.Auth')) { $config = Configure::read('Copula.' . $apiName . '.Auth'); + + if(!empty($config['callback']) && is_array($config['callback'])){ + $config['callback'] = Router::url($config['callback']); + } + + //if a domain is passed into the options, override the default + if(!empty($extra['api_domain'])){ + $config['host'] = $extra['api_domain']; + } + if ($config['authMethod'] == 'OAuth') { return $config['scheme'] . '://' . $config['host'] . '/' . $config[$path]; } elseif ($config['authMethod'] == 'OAuthV2') { @@ -158,7 +168,7 @@ function getOauthRequestToken($apiName, $requestOptions = array()) { * @param string $apiName * @throws CakeException */ - function callback($apiName) { + function callback($apiName, $api_domain = null) { $method = $this->getOauthMethod($apiName); if ($method == 'OAuthV2') { $code = $this->controller->request->query('code'); @@ -167,9 +177,9 @@ function callback($apiName) { } $accessToken = $this->getAccessTokenV2($apiName, $code); if (!empty($accessToken)) { - return $this->_afterRequest($accessToken, $apiName, $method); + return $this->_afterRequest($accessToken, $apiName, $method, $api_domain); } else { - throw new CakeException(__('Could not get OAuthV2 Access Token from %s', $apiName)); + throw new CakeException(__('Could not get OAuthV2 Access Token from %s or Token already exists', $apiName)); } } elseif ($method == 'OAuth') { $verifier = $this->controller->request->query('oauth_verifier'); @@ -190,8 +200,8 @@ function callback($apiName) { } } - protected function _afterRequest(array $accessToken, $apiName, $version) { - if ($this->store($accessToken, $apiName, $version)) { + protected function _afterRequest(array $accessToken, $apiName, $version, $api_domain = null) { + if ($this->store($accessToken, $apiName, $version, $api_domain)) { if ($this->Session->check('Oauth.redirect')) { $redirect = $this->Session->read('Oauth.redirect'); $this->Session->delete('Oauth.redirect'); @@ -200,7 +210,7 @@ protected function _afterRequest(array $accessToken, $apiName, $version) { return $accessToken; } } else { - throw new CakeException(__('Could not store access token for API %s', $apiName)); + throw new CakeException(__('Could not store access token for API %s Possibly already in db', $apiName)); } } @@ -210,11 +220,11 @@ protected function _afterRequest(array $accessToken, $apiName, $version) { * @param string|array $accessToken * @param string $tokenSecret */ - public function store(array $accessToken, $apiName, $version) { + public function store(array $accessToken, $apiName, $version, $api_domain = null) { $storageMethod = (empty($this->controller->Apis[$apiName]['store'])) ? 'Db' : ucfirst($this->controller->Apis[$apiName]['store']); $Store = ClassRegistry::init('Copula.TokenStore' . $storageMethod); if ($Store instanceof TokenStoreInterface) { - return $Store->saveToken($accessToken, $apiName, AuthComponent::user('id'), $version); + return $Store->saveToken($accessToken, $apiName, AuthComponent::user('id'), $version, $api_domain); } else { throw new CakeException(__('Storage Method: %s not supported.', $storageMethod)); } diff --git a/Model/Behavior/OAuthConsumerBehavior.php b/Model/Behavior/OAuthConsumerBehavior.php index b89e030..88aa704 100644 --- a/Model/Behavior/OAuthConsumerBehavior.php +++ b/Model/Behavior/OAuthConsumerBehavior.php @@ -13,7 +13,8 @@ public function setup(\Model $model, $config = array()) { $this->config[$model->alias] = array_merge( $this->config[$model->alias], (array) $config); if ($this->config[$model->alias]['autoFetch'] === true) { - $this->authorize($model, AuthComponent::user('id')); + $authId = (!empty($config['user_id']))? $config['user_id'] : AuthComponent::user('id'); + $this->authorize($model, $authId); } } @@ -24,14 +25,16 @@ public function setup(\Model $model, $config = array()) { * @param TokenStoreInterface $Store * @return boolean */ - function authorize(\Model $model, $userId, TokenStoreInterface $Store = null, $apiName = null) { + function authorize(\Model $model, $userId, TokenStoreInterface $Store = null, $apiName = null, $apiDomain = null) { + if (empty($Store)) { $Store = ClassRegistry::init('Copula.TokenStoreDb'); } if (empty($apiName)) { $apiName = $model->useDbConfig; } - $token = $Store->getToken($userId, $apiName); + + $token = $Store->getToken($userId, $apiName, $apiDomain); if (!empty($token)) { ConnectionManager::getDataSource($model->useDbConfig)->setConfig($token); return TRUE; @@ -48,7 +51,8 @@ function authorize(\Model $model, $userId, TokenStoreInterface $Store = null, $a * @return void * @author Ceeram */ - public function setDbConfig(\Model $model, $source = null, $useTable = null) { + public function setDbConfig(\Model $model, $source = null, $useTable = null, $api_domain = null, $userId = null, TokenStoreInterface $Store = null) { + $datasource = $model->getDataSource(); if (method_exists($datasource, 'flushMethodCache')) { $datasource->flushMethodCache(); @@ -59,6 +63,17 @@ public function setDbConfig(\Model $model, $source = null, $useTable = null) { if ($useTable !== null) { $this->setSource($useTable); } + if($api_domain){ + if (empty($Store)) { + $Store = ClassRegistry::init('Copula.TokenStoreDb'); + } + $token = $Store->getToken($userId, $apiName, $api_domain); + if (!empty($token)) { + $model->getDataSource($model->useDbConfig)->setConfig($token); + } else { + throw new CakeException(__('Could not get access token for Api %s', $model->useDbConfig)); + } + } } else { if (!empty($this->config[$model->alias]['default'])) { $this->setDataSource($this->config[$model->alias]['default']['useDbConfig']); From 934a720e5ea40a78fcccc0987e3330b90f1cea2a Mon Sep 17 00:00:00 2001 From: bmilesp Date: Fri, 19 Jul 2013 15:34:30 -0400 Subject: [PATCH 02/11] added tolkenized path support, added Cake-ified ruturn data ( $response[Modelname] format) --- Model/Datasource/ApisSource.php | 102 ++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 17 deletions(-) diff --git a/Model/Datasource/ApisSource.php b/Model/Datasource/ApisSource.php index 559a7db..d820e69 100644 --- a/Model/Datasource/ApisSource.php +++ b/Model/Datasource/ApisSource.php @@ -141,7 +141,10 @@ protected function _buildRequest($apiName, $type = 'read', $request = array()) { $this->setConfig($host); } $request['method'] = $this->restMap[$type]; - $request['uri']['host'] = $this->config['host']; + if(!empty($request['uri']['host'])){ + $request['uri']['host'] = $this->config['host']; + } + $request['auth'] = $this->_getAuth($this->config['authMethod'], $apiName); if (!empty($this->config['scheme'])) { $request['uri']['scheme'] = $this->config['scheme']; @@ -195,8 +198,45 @@ public function request(Model $model) { $this->logQuery($Http); $model->response = $this->afterRequest($model, $Http->response); - - return $model->response; + $data = $this->cakeModelFormat($model); + return $data; + } + +/** + * formats response into a standard CakePHP formatted array based on useTable var + * @param \Model $model + * @return array + * + */ + + public function cakeModelFormat(Model $model){ + $modelKeyName = null; + + if(empty($model->response[$model->useTable])){ + if(empty($model->response[Inflector::singularize($model->useTable)])){ + if(!empty($model->response)){ + $modelKeyName = Inflector::singularize($model->useTable); + $model->response = array($modelKeyName => $model->response); + }else{ + return array(); + } + }else{ + $modelKeyName = Inflector::singularize($model->useTable); + + } + }else{ + $modelKeyName = $model->useTable; + } + + $data = array(); + if(!empty($model->response[$modelKeyName][0])){ + foreach($model->response[$modelKeyName] as $key=>$record){ + $data[$key][Inflector::classify($model->useTable)] = $record; + } + }else{ + $data[0][Inflector::classify($model->useTable)] = $model->response[$modelKeyName]; + } + return $data; } /** @@ -259,7 +299,13 @@ protected function _getAuth($method, $apiName) { $auth = null; break; } - return array_filter($auth); + + $filtered = null; + if(!empty($auth)){ + array_filter($auth); + $filtered = $auth; + } + return $filtered; } /** @@ -333,7 +379,8 @@ protected function _scanMap($action, $section, $fields = array()) { throw new CakeException(__('Section %s not found in Copula Driver Configuration Map - ', $section) . get_class($this), 500); } else { $element = Hash::extract($map, $section); - $path = $required = $optional = null; + $path = null; + $required = $optional = array(); extract($element); if (array_intersect($fields, $required) == $required) { return compact('path', 'required', 'optional'); @@ -376,6 +423,19 @@ public function afterRequest(Model &$model, HttpSocketResponse &$response) { return $this->decode($response); } } + +/** + * build a path based on request method + * + * made to be overriadable by specific apis so that urls that require a primary key id as + * a url param (site.name/34534534/?), rather than a traditional param (?item_id=432323523) + * you can parse the query here. + * + * + */ + protected function _buildPath(Model $model, $request_type = 'read', $path = null, $conditions = array(), $authMethod = 'Oauth'){ + return $path; + } /** * Uses standard find conditions. Use find('all', $params). @@ -385,7 +445,7 @@ public function afterRequest(Model &$model, HttpSocketResponse &$response) { * @return mixed * @access public */ - public function read(Model $model, $queryData = array()) { + public function read(Model $model, $queryData = array(), $recursive = null) { if (!empty($queryData['fields']) && $queryData['fields'] == 'COUNT') { return array(array(array('count' => 1))); } @@ -394,10 +454,13 @@ public function read(Model $model, $queryData = array()) { $scan = $this->_scanMap('read', $model->useTable, array_keys($queryData['conditions'])); $required = $optional = array(); extract($scan); - $model->request['uri']['path'] = $path; - $conditions = array_intersect_key($queryData['conditions'], array_flip(array_merge($required, $optional))); - $model->request['uri']['query'] = $this->_buildQuery($conditions); - return $this->request($model); + + //$conditions = array_intersect(array_keys($queryData['conditions']), array_merge($required, $optional)); + $model->request['uri']['path'] = $this->_buildPath($model, 'read', $path, $queryData['conditions']); + + $model->request['uri']['query'] = $this->_buildQuery($queryData['conditions'],$this->config['escape']); + $data = $this->request($model); + return $data; } /** @@ -408,12 +471,17 @@ public function read(Model $model, $queryData = array()) { * @param array $values Unused */ public function create(Model $model, $fields = null, $values = null) { + $model->request = $this->_buildRequest($model->useDbConfig, 'create'); $scan = $this->_scanMap('create', $model->useTable, $fields); extract($scan); - $model->request['uri']['path'] = $path; - $model->request['body'] = $this->_buildQuery(array_combine($fields, $values), $this->config['escape']); - return $this->request($model); + $model->request['uri']['path'] = $this->_buildPath($model, 'create', $path); + $model->request['body'] = $this->_buildQuery(array_combine($fields, $values), $this->config['escape'], 'create'); + $data = $this->request($model); + if(!empty($data[Inflector::classify($model->useTable)][$model->primaryKey])){ + $model->id = $data[Inflector::classify($model->useTable)][$model->primaryKey]; + } + return $data; } /** @@ -427,8 +495,8 @@ public function update(Model $model, $fields = null, $values = null, $conditions $model->request = $this->_buildRequest($model->useDbConfig, 'update'); $scan = $this->_scanMap('update', $model->useTable, $fields); extract($scan); - $model->request['uri']['path'] = $path; - $model->request['body'] = $this->_buildQuery(array_combine($fields, $values), $this->config['escape']); + $model->request['uri']['path'] = $this->_buildPath($model, 'update', $path); + $model->request['body'] = $this->_buildQuery(array_combine($fields, $values), $this->config['escape'], 'update'); return $this->request($model); } @@ -442,8 +510,8 @@ public function delete(Model $model, $conditions = null) { $model->request = $this->_buildRequest($model->useDbConfig, 'delete'); $scan = $this->_scanMap('delete', $model->useTable, array_keys($conditions)); extract($scan); - $model->request['uri']['path'] = $path; - $model->request['body'] = $this->_buildQuery($conditions, $this->config['escape']); + $model->request['uri']['path'] = $this->_buildPath($model, 'delete', $path);; + $model->request['body'] = $this->_buildQuery($conditions, $this->config['escape'], 'delete'); return $this->request($model); } From c3476d182435058f0a7835b6fe3e6030a828965c Mon Sep 17 00:00:00 2001 From: bmilesp Date: Fri, 19 Jul 2013 15:35:55 -0400 Subject: [PATCH 03/11] PathTokenSource.php as extended APisource.php for tokenized path support --- Model/Datasource/PathTokenSource.php | 54 ++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Model/Datasource/PathTokenSource.php diff --git a/Model/Datasource/PathTokenSource.php b/Model/Datasource/PathTokenSource.php new file mode 100644 index 0000000..19ef084 --- /dev/null +++ b/Model/Datasource/PathTokenSource.php @@ -0,0 +1,54 @@ +} to a path and an optional or required + * + * also can create an array for a path to change paths based on 'one' or 'many' results: + * + * eg: + * 'customers' => array( + 'path' => array( + 'one' => 'api/1.0/customer/{id}', + 'many' => 'api/customers' + ), + 'optional' => array('id') + ), + * + */ + + protected function _buildPath(Model $model, $request_type = 'read', $path = null, $conditions = array(), $authMethod = 'Oauth'){ + $token = null; + + + //need to add in a foreach loop for multiple token replacement: + + if(!empty($this->map[$request_type][$model->useTable]['optional'][0])){ + $token = $this->map[$request_type][$model->useTable]['optional'][0]; + } + + if(!empty($this->map[$request_type][$model->useTable]['required'][0])){ + $token = $this->map[$request_type][$model->useTable]['required'][0]; + } + + $value = ''; + $selectedPath = is_array($path)? $path['many'] : $path; + + if((!empty($conditions[$token]))){ + $selectedPath = is_array($path)? $path['one'] : $path; + $value = $conditions[$token]; + unset($conditions[$token]); + } + if($request_type == 'update'){ + $value = $model->data[$model->name][$token]; + } + + $path = str_replace('{'.$token.'}', $value, $selectedPath); + + return $path; + } + +} + From 6623c5a69d5e2e316585d8aa39334f04fa76e3d3 Mon Sep 17 00:00:00 2001 From: bmilesp Date: Fri, 19 Jul 2013 15:40:09 -0400 Subject: [PATCH 04/11] added support for multiple logins per api domain in tokenStoreDb.php --- Model/TokenStoreDb.php | 64 +++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/Model/TokenStoreDb.php b/Model/TokenStoreDb.php index ce285c8..dfdf4cf 100755 --- a/Model/TokenStoreDb.php +++ b/Model/TokenStoreDb.php @@ -31,26 +31,54 @@ public function __construct($id = false, $table = null, $ds = null) { ) ), 'api' => array( - 'alphaNumeric' => array( - 'rule' => 'alphaNumeric', - 'message' => __('API names must be alphanumeric. In point of fact they should probably be camelcased singular.') - ) - ) + 'alphaNumeric' => array( + 'rule' => 'alphaNumeric', + 'message' => __('API names must be alphanumeric. In point of fact they should probably be camelcased singular.') + ) + ), + 'api_domain' => array( + 'multiUnique' => array( + 'rule' => 'multiUnique', + 'message' => __('This domain is already entered in') + ) + ) ); parent::__construct($id, $table, $ds); } + function multiUnique(){ + $exists = $this->find('first', array( + 'conditions' => array( + 'user_id' => $this->data[$this->alias]['user_id'], + 'api' => $this->data[$this->alias]['api'], + 'api_domain' => $this->data[$this->alias]['api_domain'], + ) + )); + if(!empty($exists)){ + return false; + } + return true; + } + /** * @param string $user_id the associated user id * @param string $apiName the name of an API to search for + * @param string $api_domain the name of an API domain to search for, useful + * if you have multiple domains for one APL * @return array token data */ - function getToken($user_id, $apiName) { + function getToken($user_id, $apiName, $api_domain = null) { + $conditions = array( + 'user_id' => $user_id, + 'api' => $apiName + ); + + if (!empty($api_domain)){ + $conditions['api_domain'] = $api_domain; + } $result = $this->find('first', array( - 'conditions' => array( - 'user_id' => $user_id, - 'api' => $apiName - ))); + 'conditions' => $conditions + )); $result = (empty($result)) ? $result : $result[$this->alias]; return $result; } @@ -68,7 +96,7 @@ function checkToken($user_id, $apiName) { * @param array $access_token * @param string $apiName */ - function saveToken(array $access_token, $apiName, $user_id, $version) { + function saveToken(array $access_token, $apiName, $user_id, $version, $api_domain = null) { $this->data = array( 'user_id' => $user_id, 'api' => $apiName @@ -76,12 +104,15 @@ function saveToken(array $access_token, $apiName, $user_id, $version) { if ($version == 'OAuth' || $version == '1.0') { $this->data['access_token'] = $access_token['oauth_token']; $this->data['token_secret'] = $access_token['oauth_token_secret']; + $this->data['api_domain'] = !empty($api_domain)?: null; } elseif ($version == 'OAuthV2' || $version == '2.0') { $this->data['access_token'] = $access_token['access_token']; - $this->data['refresh_token'] = $access_token['refresh_token']; - $this->data['expires_in'] = $access_token['expires_in']; + $this->data['refresh_token'] = !empty($access_token['refresh_token'])?: null; + $this->data['expires_in'] = !empty($access_token['expires_in'])?: null; + $this->data['api_domain'] = !empty($api_domain)? $api_domain: null; } - return $this->save($this->data); + $s = $this->save($this->data); + return $s; } /** @@ -90,11 +121,12 @@ function saveToken(array $access_token, $apiName, $user_id, $version) { * @return boolean */ function beforeSave($options = array()) { - if (!$this->isUnique(array('api', 'user_id'), false)) { + if (!$this->isUnique(array('api', 'user_id','api_domain'), false)) { $existing = $this->find('all', array( 'conditions' => array( 'user_id' => $this->data[$this->alias]['user_id'], - 'api' => $this->data[$this->alias]['api'] + 'api' => $this->data[$this->alias]['api'], + 'api_domain' => $this->data[$this->alias]['api_domain'] ), 'callbacks' => 'before' )); From 9a1cec5065900af6e0e99eb14dcd8af1b70747be Mon Sep 17 00:00:00 2001 From: bmilesp Date: Fri, 19 Jul 2013 15:42:11 -0400 Subject: [PATCH 05/11] updated readme.md and integration.md ; --- Integration.md | 4 ++-- README.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Integration.md b/Integration.md index 92bd192..527c7e3 100644 --- a/Integration.md +++ b/Integration.md @@ -89,7 +89,7 @@ For the purposes of this document, the hosts configuration file is assumed to be ```php 'OAuthV2', 'scheme' => 'https', 'authorize' => 'o/oauth2/auth', @@ -99,7 +99,7 @@ For the purposes of this document, the hosts configuration file is assumed to be 'callback' => 'https://example.com/oauth2callback/' ); - $config['Copula']['cloudprint']['Api'] = array( + $config['Copula']['cloudprint']['path']['Api'] = array( 'host' => 'www.google.com/cloudprint', 'authMethod' => 'OAuthV2' ); diff --git a/README.md b/README.md index 4d4e6c7..1505ea5 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Copula is, in itself, not very useful, and primarily aimed at developers. * Supports both OAuth and OAuth v2 * Access tokens can be stored in the session, or persisted in your database * Integrates with CakePHP's built-in Authorization features +* Multiple login/sub-domain functionality In addition, Copula is well-tested, and working towards 100% code coverage. From 9812229c4884e2c569d76e7a3abf882687c10a74 Mon Sep 17 00:00:00 2001 From: bmilesp Date: Fri, 19 Jul 2013 15:54:29 -0400 Subject: [PATCH 06/11] updated readme.md added multiple domain feature --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1505ea5..ef8249a 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Copula is, in itself, not very useful, and primarily aimed at developers. * Supports both OAuth and OAuth v2 * Access tokens can be stored in the session, or persisted in your database * Integrates with CakePHP's built-in Authorization features -* Multiple login/sub-domain functionality +* Multiple login/sub-domain functionality - with this you can store multiple domains for a single api type (eg: multiple shopify stores) In addition, Copula is well-tested, and working towards 100% code coverage. From f520a4f1557834c2f5491df5e3781fdeed6e2f25 Mon Sep 17 00:00:00 2001 From: bmilesp Date: Fri, 19 Jul 2013 16:27:46 -0400 Subject: [PATCH 07/11] added samdbox_domain to tokens table --- Config/Schema/schema.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Config/Schema/schema.php b/Config/Schema/schema.php index 8eb54ee..a20f25a 100644 --- a/Config/Schema/schema.php +++ b/Config/Schema/schema.php @@ -18,6 +18,7 @@ public function after($event = array()) { 'token_secret' => array('type' => 'text', 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 'expires_in' => array('type' => 'string', 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 'api_domain' => array('type' => 'string', 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), + 'sandbox_domain' => array('type' => 'string', 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 'indexes' => array( 'PRIMARY' => array('column' => 'id', 'unique' => 1), 'user_id' => array('column' => array('user_id', 'api'), 'unique' => 1) From 836c97346ab2fded5d8ad22d2deb91460e9e2adf Mon Sep 17 00:00:00 2001 From: bmilesp Date: Mon, 22 Jul 2013 10:44:08 -0400 Subject: [PATCH 08/11] added a column for organization grouping, for multiple users all using the same api keys --- Config/Schema/schema.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Config/Schema/schema.php b/Config/Schema/schema.php index a20f25a..729f0f8 100644 --- a/Config/Schema/schema.php +++ b/Config/Schema/schema.php @@ -11,6 +11,7 @@ public function after($event = array()) { public $tokens = array( 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'), 'user_id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'index'), + 'organization_id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'index'), 'api' => array('type' => 'string', 'null' => false, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 'access_token' => array('type' => 'text', 'null' => false, 'default' => null, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'), 'modified' => array('type' => 'datetime', 'null' => true, 'default' => null), From 7ce02ecd8464cd33b6b560ce233e9370f1717eae Mon Sep 17 00:00:00 2001 From: bmilesp Date: Mon, 22 Jul 2013 18:15:09 -0400 Subject: [PATCH 09/11] make override compatable with Cakephp 2.4, !empty catches on unrequired login password posts for linkpoint --- Model/Datasource/ApisSource.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Model/Datasource/ApisSource.php b/Model/Datasource/ApisSource.php index d820e69..55db474 100644 --- a/Model/Datasource/ApisSource.php +++ b/Model/Datasource/ApisSource.php @@ -79,6 +79,7 @@ class ApisSource extends DataSource { * @return \HttpSocketOauth|\HttpSocket */ public function getHttpObject($authMethod, $url = null) { + switch ($authMethod) { case 'OAuth': case 'OAuthV2': @@ -96,7 +97,7 @@ public function getHttpObject($authMethod, $url = null) { * @param \Model $model * @return mixed */ - public function describe(\Model $model) { + public function describe($model) { if (!empty($model->schema)) { $schema = $model->schema; } elseif (!empty($this->_schema[$model->name])) { @@ -188,12 +189,11 @@ public function request(Model $model) { if (method_exists($this, 'beforeRequest')) { $model->request = $this->beforeRequest($model); } - + $Http = $this->getHttpObject($this->config['authMethod']); $t = microtime(true); - $Http->request($model->request); - + $this->took = round((microtime(true) - $t) * 1000, 0); $this->logQuery($Http); @@ -273,8 +273,8 @@ protected function _getAuth($method, $apiName) { $auth = array( 'method' => 'Basic', - 'login' => $this->config['login'], - 'password' => $this->config['password'] + 'login' => !empty($this->config['login'])? $this->config['login'] : null, + 'password' => !empty($this->config['password'])? $this->config['password'] : null, ); break; case 'OAuth': @@ -471,7 +471,6 @@ public function read(Model $model, $queryData = array(), $recursive = null) { * @param array $values Unused */ public function create(Model $model, $fields = null, $values = null) { - $model->request = $this->_buildRequest($model->useDbConfig, 'create'); $scan = $this->_scanMap('create', $model->useTable, $fields); extract($scan); From 69a65117ac066af4fb4cd6ab84c975531fb0f98c Mon Sep 17 00:00:00 2001 From: bmilesp Date: Tue, 23 Jul 2013 10:50:43 -0400 Subject: [PATCH 10/11] modified cakeFormat for use after decoding, added arguments to decode function for manual content type application --- Model/Datasource/ApisSource.php | 44 +++++++++++++++++---------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/Model/Datasource/ApisSource.php b/Model/Datasource/ApisSource.php index 55db474..1901e0a 100644 --- a/Model/Datasource/ApisSource.php +++ b/Model/Datasource/ApisSource.php @@ -198,8 +198,8 @@ public function request(Model $model) { $this->logQuery($Http); $model->response = $this->afterRequest($model, $Http->response); - $data = $this->cakeModelFormat($model); - return $data; + + return $model->response; } /** @@ -209,32 +209,31 @@ public function request(Model $model) { * */ - public function cakeModelFormat(Model $model){ + public function cakeModelFormat(Model $model, $body = null){ $modelKeyName = null; - if(empty($model->response[$model->useTable])){ - if(empty($model->response[Inflector::singularize($model->useTable)])){ - if(!empty($model->response)){ - $modelKeyName = Inflector::singularize($model->useTable); - $model->response = array($modelKeyName => $model->response); + if(empty($body[$model->useTable])){ + if(empty($body[Inflector::singularize($model->useTable)])){ + if(!empty($body)){ + $modelKeyName = $model->alias; + $body = array($modelKeyName => $body); }else{ return array(); } }else{ - $modelKeyName = Inflector::singularize($model->useTable); + $modelKeyName = $model->alias; } }else{ - $modelKeyName = $model->useTable; + $modelKeyName = $model->alias; } - $data = array(); - if(!empty($model->response[$modelKeyName][0])){ - foreach($model->response[$modelKeyName] as $key=>$record){ - $data[$key][Inflector::classify($model->useTable)] = $record; + if(!empty($body[$modelKeyName][0]) && is_array($body[$modelKeyName][0])){ + foreach($body[$modelKeyName] as $key=>$record){ + $data[$key][$modelKeyName] = $record; } }else{ - $data[0][Inflector::classify($model->useTable)] = $model->response[$modelKeyName]; + $data[0][$modelKeyName] = $body[$model->useTable]; } return $data; } @@ -315,12 +314,14 @@ protected function _getAuth($method, $apiName) { * @return array $response * @author Dean Sofer */ - public function decode(\HttpSocketResponse $response) { + public function decode(\HttpSocketResponse $response, Model $model, $contentType = null) { // Get content type header - $contentType = explode(';', $response->getHeader('Content-Type')); - + if($contentType == null){ + $contentType = explode(';', $response->getHeader('Content-Type')); + $contentType = $contentType[0]; + }; // Decode response according to content type - switch ($contentType[0]) { + switch ($contentType) { case 'application/xml': case 'application/atom+xml': case 'application/rss+xml': @@ -343,6 +344,7 @@ public function decode(\HttpSocketResponse $response) { $return = $response->body(); break; } + $return = $this->cakeModelFormat($model, $return); return $return; } @@ -415,12 +417,12 @@ public function beforeRequest(Model $model) { return $model->request; } - public function afterRequest(Model &$model, HttpSocketResponse &$response) { + public function afterRequest(Model &$model, HttpSocketResponse &$response, $contentType = null) { if (!$response->isOk()) { $model->onError(); return false; } else { - return $this->decode($response); + return $this->decode($response, $model, $contentType); } } From c53181182a12e13fd774155176f8440851b68f95 Mon Sep 17 00:00:00 2001 From: bmilesp Date: Tue, 23 Jul 2013 13:40:41 -0400 Subject: [PATCH 11/11] modified cakeFormat for use after decoding, added arguments to decode function for manual content type application --- Model/Datasource/ApisSource.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Model/Datasource/ApisSource.php b/Model/Datasource/ApisSource.php index 1901e0a..2e85260 100644 --- a/Model/Datasource/ApisSource.php +++ b/Model/Datasource/ApisSource.php @@ -198,7 +198,6 @@ public function request(Model $model) { $this->logQuery($Http); $model->response = $this->afterRequest($model, $Http->response); - return $model->response; } @@ -233,7 +232,7 @@ public function cakeModelFormat(Model $model, $body = null){ $data[$key][$modelKeyName] = $record; } }else{ - $data[0][$modelKeyName] = $body[$model->useTable]; + $data[$modelKeyName] = $body[$model->useTable]; } return $data; }