From 2d69e74fffc0a0201e33d362533f814b14cc6341 Mon Sep 17 00:00:00 2001 From: Russ P Date: Thu, 20 Jan 2011 00:20:15 -0500 Subject: [PATCH 001/112] Moved request headers to an argument of _sendRequest; Added JSON content header only to patch requests; Added key-less demo application to this package for functional testing --- aweber_api/oauth_application.php | 9 ++-- demo.php | 80 ++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 demo.php diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index b2c74f2..3f546c9 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -448,7 +448,7 @@ protected function patch($url, $oauth, $data) { $handle = curl_init($url); curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'PATCH'); curl_setopt($handle, CURLOPT_POSTFIELDS, json_encode($data)); - $resp = $this->_sendRequest($handle); + $resp = $this->_sendRequest($handle, array('Expect:', 'Content-Type: application/json')); return $resp; } @@ -509,14 +509,15 @@ public function buildData($data) { * _sendRequest * * Actually makes a request. - * @param mixed $handle + * @param mixed $handle Curl handle + * @param array $headers Additional headers needed for request * @access private * @return void */ - private function _sendRequest($handle) { + private function _sendRequest($handle, $headers = array('Expect:')) { curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); curl_setopt($handle, CURLOPT_HEADER, true); - curl_setopt($handle, CURLOPT_HTTPHEADER, array('Expect:', 'Content-Type: application/json')); + curl_setopt($handle, CURLOPT_HTTPHEADER, $headers); curl_setopt($handle, CURLOPT_USERAGENT, $this->userAgent); curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($handle, CURLOPT_VERBOSE, FALSE); diff --git a/demo.php b/demo.php new file mode 100644 index 0000000..5611b2d --- /dev/null +++ b/demo.php @@ -0,0 +1,80 @@ +key; +$consumerSecret = $data->secret; +$aweber = new AWeberAPI($consumerKey, $consumerSecret); + +if (empty($_COOKIE['accessToken'])) { + if (empty($_GET['oauth_token'])) { + $callbackUrl = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; + list($requestToken, $requestTokenSecret) = $aweber->getRequestToken($callbackUrl); + setcookie('requestTokenSecret', $requestTokenSecret); + setcookie('callbackUrl', $callbackUrl); + header("Location: {$aweber->getAuthorizeUrl()}"); + exit(); + } + + $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; + $aweber->user->requestToken = $_GET['oauth_token']; + $aweber->user->verifier = $_GET['oauth_verifier']; + list($accessToken, $accessTokenSecret) = $aweber->getAccessToken(); + setcookie('accessToken', $accessToken); + setcookie('accessTokenSecret', $accessTokenSecret); + header('Location: '.$_COOKIE['callbackUrl']); + exit(); +} +$account = $aweber->getAccount($_COOKIE['accessToken'], $_COOKIE['accessTokenSecret']); +?> + + + + AWeber Test Application + + +lists as $offset => $list) { +?> +

List: name; ?>

+

id; ?>

+ + + + + + + +subscribers as $sub) { + if ($count++ > 10) break; +?> + + + + + + + +
IdNameEmailStatus
id; ?>name; ?>email; ?>status; ?>
+ + + + From 75752efcc1a91e6dbb34c542b70b0b0f813756c1 Mon Sep 17 00:00:00 2001 From: "Edward F. Long, Jr" Date: Tue, 15 Mar 2011 09:38:22 -0400 Subject: [PATCH 002/112] added move resource functionality to entries, refactored test harness, updated json fixtures --- aweber_api/aweber_api.php | 6 +- aweber_api/aweber_entry.php | 30 +++++- aweber_api/oauth_application.php | 21 ++++- data.json | 6 ++ demo.php | 80 ---------------- simpletest | 1 + tests/all_tests.php | 1 + tests/aweber_api.test.php | 15 +-- tests/aweber_collection.test.php | 6 +- tests/aweber_entry.test.php | 93 ++++++++++++++++--- tests/data/account.json | 1 - tests/data/accounts.json | 9 -- tests/data/accounts/1.json | 1 + tests/data/accounts/page1.json | 1 + tests/data/accounts/webForms.json | 1 + .../campaigns.json => campaigns/303449.json} | 2 +- tests/data/lists/303449.json | 2 +- tests/data/lists/303450.json | 1 - tests/data/lists/505454.json | 1 + tests/data/lists/page1.json | 1 + tests/data/lists/page2.json | 1 + tests/data/{lists.json => lists/page3.json} | 0 tests/data/lists_page2.json | 1 - tests/data/subscribers/1.json | 2 +- tests/data/subscribers/2.json | 1 + tests/data/subscribers/3.json | 1 + tests/data/subscribers/find.json | 1 + tests/data/subscribers/page1.json | 1 + tests/data/web_forms.json | 1 - tests/mock_adapter.php | 44 ++++++--- 30 files changed, 192 insertions(+), 140 deletions(-) create mode 100644 data.json delete mode 100644 demo.php create mode 120000 simpletest delete mode 100644 tests/data/account.json delete mode 100644 tests/data/accounts.json create mode 100644 tests/data/accounts/1.json create mode 100644 tests/data/accounts/page1.json create mode 100644 tests/data/accounts/webForms.json rename tests/data/{lists/303449/campaigns.json => campaigns/303449.json} (50%) delete mode 100644 tests/data/lists/303450.json create mode 100644 tests/data/lists/505454.json create mode 100644 tests/data/lists/page1.json create mode 100644 tests/data/lists/page2.json rename tests/data/{lists.json => lists/page3.json} (100%) delete mode 100644 tests/data/lists_page2.json create mode 100644 tests/data/subscribers/2.json create mode 100644 tests/data/subscribers/3.json create mode 100644 tests/data/subscribers/find.json create mode 100644 tests/data/subscribers/page1.json delete mode 100644 tests/data/web_forms.json diff --git a/aweber_api/aweber_api.php b/aweber_api/aweber_api.php index ae7c99c..ddc0ebd 100644 --- a/aweber_api/aweber_api.php +++ b/aweber_api/aweber_api.php @@ -20,7 +20,7 @@ class AWeberServiceProvider implements OAuthServiceProvider { /** * @var String Location for API calls */ - public $baseUri = 'https://api.aweber.com/1.0'; + public $baseUri = 'http://apistage1.colo.lair:12011/1.0'; /** * @var String Location to request an access token @@ -42,6 +42,10 @@ public function getBaseUri() { return $this->baseUri; } + public function removeBaseUri($url) { + return str_replace($this->getBaseUri(), '', $url); + } + public function getAccessTokenUrl() { return $this->accessTokenUrl; } diff --git a/aweber_api/aweber_entry.php b/aweber_api/aweber_entry.php index f4c769a..36515ef 100644 --- a/aweber_api/aweber_entry.php +++ b/aweber_api/aweber_entry.php @@ -6,7 +6,6 @@ class AWeberEntry extends AWeberResponse { * @var array Holds list of data keys that are not publicly accessible */ protected $_privateData = array( - 'self_link', 'resource_type_link', 'http_etag', ); @@ -78,6 +77,35 @@ public function delete() { return false; } + /** + * move + * + * Invoke the API method to MOVE an entry resource to a different List. + * + * Note: Not all entry resources are eligible to be moved, please + * refer to the AWeber API Reference Documentation at + * https://labs.aweber.com/docs/reference/1.0 for more + * details on which entry resources may be moved and if there + * are any requirements for moving that resource. + * + * @access public + * @param AWeberEntry(List) List to move Resource (this) too. + * @return mixed AWeberEntry(Resource) Resource created on List ($list) + * or False if resource was not created. + */ + public function move($list) { + # Move Resource + $params = array('ws.op' => 'move', 'list_link' => $list->self_link); + $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers')); + if ($data['Status-Code'] !== '201') { + return false; + } + + # Return new Resource + $url = $data['Location']; + $resource_data = $this->adapter->request('GET', $url); + return new AWeberEntry($resource_data, $url, $this->adapter); + } /** * save diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 3f546c9..ad5b452 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -104,13 +104,20 @@ public function __construct($parentApp = false) { * @return void */ public function request($method, $uri, $data = array(), $options = array()) { + $uri = $this->app->removeBaseUri($uri); $url = $this->app->getBaseUri() . $uri; + $response = $this->makeRequest($method, $url, $data); if (!$response) { throw new AWeberResponseError($uri); } - if (!empty($options['return']) && $options['return'] == 'status') { - return $response->headers['Status-Code']; + if (!empty($options['return'])) { + if ($options['return'] == 'status') { + return $response->headers['Status-Code']; + } + if ($options['return'] == 'headers') { + return $response->headers; + } } $data = json_decode($response->body, true); if (empty($options['allow_empty']) && empty($data)) { @@ -427,9 +434,13 @@ public function makeRequest($method, $url, $data=array()) { } else { $resp = $this->get($url, $oauth, $data); } - if ($this->debug) print_r($oauth); - if ($this->debug) echo " --> Status: {$resp->headers['Status-Code']}\n"; - if ($this->debug) echo " --> Body: {$resp->body}"; + if ($this->debug) { + echo "
";
+            print_r($oauth);
+            echo " --> Status: {$resp->headers['Status-Code']}\n";
+            echo " --> Body: {$resp->body}";
+            echo "
"; + } return $resp; } diff --git a/data.json b/data.json new file mode 100644 index 0000000..2a2ad70 --- /dev/null +++ b/data.json @@ -0,0 +1,6 @@ +{ + "consumer_key" : "Ak3JWfqDPsLwcROAmS3nMb8k", + "consumer_secret" : "6SiLPb8AAK7OO1x2KnldhUaJhBGqIQHAf3jURRcg", + "access_token_key" : "AgzedRRXUeuxv6FJK21Oto7G", + "access_token_secret" : "XIvR68ERd6nzoIi5MPEqctKd0K2JjGBupMIxslpy" +} diff --git a/demo.php b/demo.php deleted file mode 100644 index 5611b2d..0000000 --- a/demo.php +++ /dev/null @@ -1,80 +0,0 @@ -key; -$consumerSecret = $data->secret; -$aweber = new AWeberAPI($consumerKey, $consumerSecret); - -if (empty($_COOKIE['accessToken'])) { - if (empty($_GET['oauth_token'])) { - $callbackUrl = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; - list($requestToken, $requestTokenSecret) = $aweber->getRequestToken($callbackUrl); - setcookie('requestTokenSecret', $requestTokenSecret); - setcookie('callbackUrl', $callbackUrl); - header("Location: {$aweber->getAuthorizeUrl()}"); - exit(); - } - - $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; - $aweber->user->requestToken = $_GET['oauth_token']; - $aweber->user->verifier = $_GET['oauth_verifier']; - list($accessToken, $accessTokenSecret) = $aweber->getAccessToken(); - setcookie('accessToken', $accessToken); - setcookie('accessTokenSecret', $accessTokenSecret); - header('Location: '.$_COOKIE['callbackUrl']); - exit(); -} -$account = $aweber->getAccount($_COOKIE['accessToken'], $_COOKIE['accessTokenSecret']); -?> - - - - AWeber Test Application - - -lists as $offset => $list) { -?> -

List: name; ?>

-

id; ?>

- - - - - - - -subscribers as $sub) { - if ($count++ > 10) break; -?> - - - - - - - -
IdNameEmailStatus
id; ?>name; ?>email; ?>status; ?>
- - - - diff --git a/simpletest b/simpletest new file mode 120000 index 0000000..5b9b03a --- /dev/null +++ b/simpletest @@ -0,0 +1 @@ +../simpletest \ No newline at end of file diff --git a/tests/all_tests.php b/tests/all_tests.php index 94b132a..23c7ace 100644 --- a/tests/all_tests.php +++ b/tests/all_tests.php @@ -15,6 +15,7 @@ $test->addTestCase(new TestAWeberEntry()); $test->addTestCase(new TestAWeberAccountEntry()); $test->addTestCase(new TestAWeberSubscriberEntry()); +$test->addTestCase(new TestAWeberMoveEntry()); $test->run(new TextReporter()); ?> diff --git a/tests/aweber_api.test.php b/tests/aweber_api.test.php index de53745..9508751 100644 --- a/tests/aweber_api.test.php +++ b/tests/aweber_api.test.php @@ -54,13 +54,14 @@ public function test_should_raise_exception_if_auth_fails() { MockData::$oauth = true; } - public function test_should_return_null_after_authorization() { - $this->aweber->setAdapter($this->adapter); - $account = $this->aweber->getAccount($this->user['token'], - $this->user['secret']); - $list = $account->lists->getById(123456); - $this->assertTrue(empty($list)); - } +# is this test a valid test? +# public function test_should_return_null_after_authorization() { +# $this->aweber->setAdapter($this->adapter); +# $account = $this->aweber->getAccount($this->user['token'], +# $this->user['secret']); +# $list = $account->lists->getById(123456); +# $this->assertTrue(empty($list)); +# } /** * getAccount should load an AWeberEntry based on a single account diff --git a/tests/aweber_collection.test.php b/tests/aweber_collection.test.php index 3c7613d..cdadc30 100644 --- a/tests/aweber_collection.test.php +++ b/tests/aweber_collection.test.php @@ -8,7 +8,7 @@ class TestAWeberCollection extends UnitTestCase { */ public function setUp() { $this->adapter = new MockOAuthAdapter(); - $this->collection = new AWeberCollection(MockData::load('lists'), '/accounts/1/lists', $this->adapter); + $this->collection = new AWeberCollection(MockData::load('lists/page3'), '/accounts/1/lists', $this->adapter); } /** @@ -66,11 +66,11 @@ public function testShouldLazilyLoadAdditionalPages() { $this->assertTrue(empty($this->adapter->requestsMade)); $entry = $this->collection[20]; - $this->assertEqual($entry->id, 50000002); + $this->assertEqual($entry->id, 1364473); $this->assertEqual(count($this->adapter->requestsMade), 1); $entry = $this->collection[21]; - $this->assertEqual($entry->id, 406860); + $this->assertEqual($entry->id, 1211626); $this->assertEqual(count($this->adapter->requestsMade), 1); } diff --git a/tests/aweber_entry.test.php b/tests/aweber_entry.test.php index f4db6e6..8f72bb4 100644 --- a/tests/aweber_entry.test.php +++ b/tests/aweber_entry.test.php @@ -89,6 +89,7 @@ public function testAttrs() { array( 'id' => 303449, 'name' => 'default303449', + 'self_link' => 'https://api.aweber.com/1.0/accounts/1/lists/303449', 'campaigns' => 'collection', 'subscribers' => 'collection', 'web_forms' => 'collection', @@ -138,7 +139,7 @@ public function testSet() { } /** - * Should make a request when a save is made. + * Should Color a request when a save is made. */ public function testSave() { $this->entry->name = 'mynewlistname'; @@ -153,7 +154,7 @@ public function testSave() { } public function testSaveFailed() { - $url = '/accounts/1/lists/303450'; + $url = '/accounts/1/lists/505454'; $data = $this->adapter->request('GET', $url); $entry = new AWeberEntry($data, $url, $this->adapter); $entry->name = 'foobarbaz'; @@ -163,7 +164,7 @@ public function testSaveFailed() { /** * Should keep track of whether or not this entry is "dirty". It should - * not make save calls if it hasn't been altered since the last successful + * not Color save calls if it hasn't been altered since the last successful * load / save operation. */ public function testShouldMaintainDirtiness() { @@ -210,7 +211,7 @@ public function testShouldReturnArray() { } public function testShouldHaveCorrectCountOfEntries() { - $this->assertEqual(sizeOf($this->data), 23); + $this->assertEqual(sizeOf($this->data), 181); } public function testShouldHaveEntries() { @@ -221,7 +222,7 @@ public function testShouldHaveEntries() { public function testShouldHaveFullURL() { foreach($this->data as $entry) { - $this->assertTrue(preg_match('/^\/accounts\/1\/lists\/[0-9]*\/web_forms\/[0-9]*$/', $entry->url)); + $this->assertTrue(preg_match('/^https:\/\/api\.aweber\.com\/1\.0\/accounts\/1\/lists\/[0-9]*\/web_forms\/[0-9]*$/', $entry->url)); } } } @@ -231,7 +232,7 @@ class TestAWeberSubscriberEntry extends UnitTestCase { public function setUp() { $this->adapter = new MockOAuthAdapter(); $this->adapter->app = new AWeberServiceProvider(); - $url = '/accounts/1/lists/1/subscribers/1'; + $url = '/accounts/1/lists/303449/subscribers/1'; $data = $this->adapter->request('GET', $url); $this->entry = new AWeberEntry($data, $url, $this->adapter); } @@ -246,18 +247,18 @@ public function testHasCustomFields() { } public function testCanReadCustomFields() { - $this->assertEqual($this->entry->custom_fields['Make'], 'Honda'); - $this->assertEqual($this->entry->custom_fields['Model'], 'Civic'); + $this->assertEqual($this->entry->custom_fields['Color'], 'blue'); + $this->assertEqual($this->entry->custom_fields['Walruses'], '32'); } public function testCanUpdateCustomFields() { - $this->entry->custom_fields['Make'] = 'Jeep'; - $this->entry->custom_fields['Model'] = 'Cherokee'; - $this->assertEqual($this->entry->custom_fields['Make'], 'Jeep'); + $this->entry->custom_fields['Color'] = 'Jeep'; + $this->entry->custom_fields['Walruses'] = 'Cherokee'; + $this->assertEqual($this->entry->custom_fields['Color'], 'Jeep'); } public function testCanViewSizeOfCustomFields() { - $this->assertEqual(sizeOf($this->entry->custom_fields), 4); + $this->assertEqual(sizeOf($this->entry->custom_fields), 6); } public function testCanIterateOverCustomFields() { @@ -270,12 +271,76 @@ public function testCanIterateOverCustomFields() { public function testShouldBeUpdatable() { $this->adapter->clearRequests(); - $this->entry->custom_fields['Make'] = 'Jeep'; + $this->entry->custom_fields['Color'] = 'Jeep'; $this->entry->save(); $data = $this->adapter->requestsMade[0]['data']; - $this->assertEqual($data['custom_fields']['Make'], 'Jeep'); + $this->assertEqual($data['custom_fields']['Color'], 'Jeep'); } +} + + +class TestAWeberMoveEntry extends UnitTestCase { + + public function setUp() { + $this->adapter = new MockOAuthAdapter(); + $this->adapter->app = new AWeberServiceProvider(); + + # Get Subscriber + $url = '/accounts/1/lists/303449/subscribers/1'; + $data = $this->adapter->request('GET', $url); + $this->subscriber = new AWeberEntry($data, $url, $this->adapter); + $url = '/accounts/1/lists/303449/subscribers/2'; + $data = $this->adapter->request('GET', $url); + $this->unsubscribed = new AWeberEntry($data, $url, $this->adapter); + + # Different List + $url = '/accounts/1/lists/505454'; + $data = $this->adapter->request('GET', $url); + $this->different_list = new AWeberEntry($data, $url, $this->adapter); + } + + /** + * Move Succeeded + */ + public function testMove_Success() { + $this->adapter->clearRequests(); + $resp = $this->subscriber->move($this->different_list); + + $this->assertEqual(sizeOf($this->adapter->requestsMade), 2); + + $req = $this->adapter->requestsMade[0]; + $this->assertEqual($req['method'], 'POST'); + $this->assertEqual($req['uri'], $this->subscriber->url); + $this->assertEqual($req['data'], array( + 'ws.op' => 'move', + 'list_link' => $this->different_list->self_link)); + + $req = $this->adapter->requestsMade[1]; + $this->assertEqual($req['method'], 'GET'); + $this->assertEqual($req['uri'], '/accounts/1/lists/505454/subscribers/3'); + } + + /** + * Move Failed + */ + public function testMove_Failure() { + + $this->adapter->clearRequests(); + $resp = $this->unsubscribed->move($this->different_list); + + $this->assertEqual(sizeOf($this->adapter->requestsMade), 1); + + $req = $this->adapter->requestsMade[0]; + $this->assertEqual($req['method'], 'POST'); + $this->assertEqual($req['uri'], $this->unsubscribed->url); + $this->assertEqual($req['data'], array( + 'ws.op' => 'move', + 'list_link' => $this->different_list->self_link)); + + $this->assertFalse($resp); + return; + } } diff --git a/tests/data/account.json b/tests/data/account.json deleted file mode 100644 index 4782e1e..0000000 --- a/tests/data/account.json +++ /dev/null @@ -1 +0,0 @@ -{"http_etag": "\"5ae3075ce7c9b1869ce83bf2a7d67da376af0031-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "lists_collection_link": "https://api.aweber.com/1.0/accounts/326084/lists", "self_link": "https://api.aweber.com/1.0/accounts/326084", "resource_type_link": "https://api.aweber.com/1.0/#account", "id": 326084, "integrations_collection_link": "https://api.aweber.com/1.0/accounts/326084/integrations"} diff --git a/tests/data/accounts.json b/tests/data/accounts.json deleted file mode 100644 index 0e0edc4..0000000 --- a/tests/data/accounts.json +++ /dev/null @@ -1,9 +0,0 @@ -{"total_size": 1, "start": 0, "next_collection_link": -"http://api.apitest.lab:81/0.1/accounts?ws.start=20&ws.size=20", "entries": -[{"http_etag": -"\"c70dfb07dc67c9dd6a8bc01130acf68d1fbf035f-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", -"vendor_accounts_collection_link": -"http://api.apitest.lab:81/0.1/accounts/910/vendor_accounts", -"lists_collection_link": "http://api.apitest.lab:81/0.1/accounts/910/lists", -"self_link": "http://api.apitest.lab:81/0.1/accounts/910", -"resource_type_link": "http://api.apitest.lab:81/0.1/#account", "id": 910}], "resource_type_link" : "http://api.apitest.lab:81/0.1/#accounts"} diff --git a/tests/data/accounts/1.json b/tests/data/accounts/1.json new file mode 100644 index 0000000..0082f80 --- /dev/null +++ b/tests/data/accounts/1.json @@ -0,0 +1 @@ +{"http_etag": "\"356a192b7913b04c54574d18c28d46e6395428ab-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "lists_collection_link": "https://api.aweber.com/1.0/accounts/1/lists", "self_link": "https://api.aweber.com/1.0/accounts/1", "resource_type_link": "https://api.aweber.com/1.0/#account", "id": 1, "integrations_collection_link": "https://api.aweber.com/1.0/accounts/1/integrations"} \ No newline at end of file diff --git a/tests/data/accounts/page1.json b/tests/data/accounts/page1.json new file mode 100644 index 0000000..9ded1aa --- /dev/null +++ b/tests/data/accounts/page1.json @@ -0,0 +1 @@ +{"total_size": 1, "start": 0, "resource_type_link": "https://api.aweber.com/1.0/#accounts", "entries": [{"http_etag": "\"356a192b7913b04c54574d18c28d46e6395428ab-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "lists_collection_link": "https://api.aweber.com/1.0/accounts/1/lists", "self_link": "https://api.aweber.com/1.0/accounts/1", "resource_type_link": "https://api.aweber.com/1.0/#account", "id": 1, "integrations_collection_link": "https://api.aweber.com/1.0/accounts/1/integrations"}]} \ No newline at end of file diff --git a/tests/data/accounts/webForms.json b/tests/data/accounts/webForms.json new file mode 100644 index 0000000..fe2b354 --- /dev/null +++ b/tests/data/accounts/webForms.json @@ -0,0 +1 @@ +[{"conversion_percentage": 50.0, "unique_conversion_percentage": 100.0, "name": "My Web Form", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 1, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/web_forms/2144687381", "http_etag": "\"51be85d7b77486eb3a5dc2c3f63d09a012a33926-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 2, "type": "styled", "id": 2144687381}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/web_forms/973076791", "http_etag": "\"0e82edd46ca9875726804d94453ede91f6744bbd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 973076791}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Gray Chicklet", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms/568620", "http_etag": "\"2b308ba9dff0d01fd6a06ae5e52b9c11ba520f39-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "popover", "id": 568620}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New Form 285188834", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms/285188834", "http_etag": "\"a085ac40b9623b018feecd53b139c50dbf01273d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 285188834}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms/855354709", "http_etag": "\"95152961c46929db4ec7b4d0255dd3307f57ae2b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 855354709}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms/934237153", "http_etag": "\"99e202c1f0a8f788a9f721ce50e64ec4d75ee100-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 934237153}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms/976364442", "http_etag": "\"42b90e264d78ef869caa3dfb8749e5c59829fa74-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 976364442}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms/1264487494", "http_etag": "\"24ccbe40ec8662d44a50d32016bfe82d9f083efa-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1264487494}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Gray Chicklet", "total_unique_displays": 5, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms/1462846225", "http_etag": "\"43f4a8a0acba4d5cb29cdbef880208ef1d49e7eb-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 11, "type": "popover", "id": 1462846225}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms/1468487959", "http_etag": "\"6ad3154c3a4c9e482b3bd0501c7add80e44a67fc-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1468487959}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms/1711941830", "http_etag": "\"3f03507b50cadc29e8fd8688f0ccfb321b848f7c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1711941830}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms/1744135098", "http_etag": "\"b89e8365f2071a8d6377bf574064629999c88ffe-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1744135098}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms/1814628241", "http_etag": "\"988a78522511150ab99b27337b2f16e1254948c0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1814628241}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms/1857915969", "http_etag": "\"353329e0cf32e566d5d0afe326b292c8be355445-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1857915969}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Powered by form.", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1348696/web_forms/1366711934", "http_etag": "\"c48fdfe8e3d6368e350e5c987e1efb40c790f502-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 1366711934}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "schnazzy!", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1196881/web_forms/473922196", "http_etag": "\"8834f0be4c6c74d50149dab04c5ba5eb14022865-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 473922196}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Pasta Marco Email Newsletter", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1183956/web_forms/1018037681", "http_etag": "\"42cf0269831bb5d0dce403fef1d10c11dbcc4c4f-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1018037681}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1182241/web_forms/785375409", "http_etag": "\"5b4471873fe7aba40bdb8b8fec13ce542c845def-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 785375409}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 4", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1115098/web_forms/1788673120", "http_etag": "\"288e20fb5d8c8976fa611835a9d76a6ec42aa13f-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1788673120}, {"conversion_percentage": 200.0, "unique_conversion_percentage": 200.0, "name": "Musical Form", "total_unique_displays": 2, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 4, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1115098/web_forms/2065783495", "http_etag": "\"84ce57743da233d23be8c9caab68d2731ffeb6a1-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 2, "type": "styled", "id": 2065783495}, {"conversion_percentage": 17.142857142857142, "unique_conversion_percentage": 92.307692307692307, "name": "My Web Form", "total_unique_displays": 13, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 12, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1115098/web_forms/1864285919", "http_etag": "\"8db2aeff14913fa247c03c4116cc23b3f40cacfd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 70, "type": "styled", "id": 1864285919}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 3", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1115098/web_forms/1757005029", "http_etag": "\"00dd6eac3d88fd75e7d501168c00ba5c0a02777c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1757005029}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1111742/web_forms/10301239", "http_etag": "\"ef222211d3f7ae8721156ae961851322ee1e8513-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 10301239}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Break it", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1111742/web_forms/77889986", "http_etag": "\"7d38647664420bcbd2e8bce394d6c72bbe06407a-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 77889986}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Archive Link Test", "total_unique_displays": 6, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/443852033", "http_etag": "\"e3348e5c31160f2beaa1c80fec8d83f8dce8af60-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 8, "type": "styled", "id": 443852033}, {"conversion_percentage": 60.0, "unique_conversion_percentage": 75.0, "name": "My Child Form", "total_unique_displays": 4, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 3, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/443345799", "http_etag": "\"4890501b056cfc914de815b747f8118243ff5ddc-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 5, "type": "styled", "id": 443345799}, {"conversion_percentage": 9.0909090909090917, "unique_conversion_percentage": 12.5, "name": "My Parent Form", "total_unique_displays": 8, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 1, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/373395245", "http_etag": "\"3f587348fdc61e30f9a23bb279d3a1ae4ca25e86-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 11, "type": "styled", "id": 373395245}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 10", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/328144509", "http_etag": "\"f96fea01b595a370fb0d570e7258948fcd07fac1-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 328144509}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 9, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/321196417", "http_etag": "\"499663dbd0e5ed40fb85b8326e793e63f5e27004-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 16, "type": "styled", "id": 321196417}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 2", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/1722348849", "http_etag": "\"18fa000c3f56edc9ed5015b0d49ce7808b60cdd0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1722348849}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 4", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/1671541208", "http_etag": "\"2540db27ff371fd077b4b857fe84f3ed9be1b412-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1671541208}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 8", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/1412438117", "http_etag": "\"19d23a82f864c6b6a1217e3f542db0d948edecb9-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1412438117}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 7", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/1194725294", "http_etag": "\"1ab43dcf494d60a4df4df3b8f71c72cd11028c2f-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 1194725294}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 10", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/888558240", "http_etag": "\"bcad5e2525fe6d4920a0c29c4860f85df7848d1e-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 888558240}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 5", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/612488428", "http_etag": "\"154deedf37af57c9c3b69617a0f55df42dd3799e-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 612488428}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 3", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/596395782", "http_etag": "\"6f185c76b236366b494201ca6c311b69cb2abee5-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 2, "type": "styled", "id": 596395782}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 6", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/5432097", "http_etag": "\"e1d9a53731237d367e916fd02ca52f272f585468-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 5432097}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 9", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/52577210", "http_etag": "\"65fbdeba9c2ff7433b612c5453a350e4ff7c9adb-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 52577210}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 10", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_forms/180387219", "http_etag": "\"5b6421896e5eb441b4872ccef1334482e40e72ef-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 180387219}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 80, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1095782/web_forms/1131664280", "http_etag": "\"8dbfa1b2af790cab7624be54cd266e928c30bde0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 80, "type": "styled", "id": 1131664280}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 2", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1095782/web_forms/1661398130", "http_etag": "\"556986c22e508739394965abd76250a6b3df947b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 1661398130}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 2, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1072793/web_forms/1641279744", "http_etag": "\"b52a6bdbcf30b4a545fac08ca8560f7d99c4d4bc-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 2, "type": "styled", "id": 1641279744}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1054014/web_forms/231994029", "http_etag": "\"a0172692184320c2cbd4ff72a9a4e487ea383c62-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 231994029}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "legacy form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1054014/web_forms/562064899", "http_etag": "\"1c811aa0623413179239fbc9de98616d3609be6f-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 562064899}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1046404/web_forms/496819835", "http_etag": "\"fb3b65ae7c76fc45228d2a81d4b6947ec40ab8c5-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 496819835}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": null, "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/964600/web_forms/5519300", "http_etag": "\"aa48417c41d1e7be17a42ce51d5938731c72b0c0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 5519300}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": null, "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/964600/web_forms/73641902", "http_etag": "\"7eecaa30a6053e077c6c1826e6511a5c92032e02-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 73641902}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Legacy Form Backup", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/964600/web_forms/302910027", "http_etag": "\"c9571c60fd36b7074ce4bcde7742409f37284055-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "popup", "id": 302910027}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Legacy Form Backup Backup", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/964600/web_forms/387792437", "http_etag": "\"850db01ebc1293291a0a67028c320a955046bd2b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "popup", "id": 387792437}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": null, "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/964600/web_forms/593064148", "http_etag": "\"433f04376492b78dc70b0fa2dcf80962ce4ba6e4-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 593064148}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New Form 627390460", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/964600/web_forms/627390460", "http_etag": "\"2fd9aff7b96ca46c052e32158bddfb7b5d588b9e-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 627390460}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": null, "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/964600/web_forms/968066808", "http_etag": "\"13fc8fe97cf9cedab7e1e7b77a202e8383c8a2ba-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 968066808}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 2", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/964600/web_forms/1023998893", "http_etag": "\"d046fe1331102a3558398ae3c5f98dbf13a01cd4-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1023998893}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Legacy Form Backup", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/964600/web_forms/1170809790", "http_etag": "\"dc108596d4582ba8309d8ef4fc8405e0199c85bb-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1170809790}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Legacy Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/964600/web_forms/1529784343", "http_etag": "\"f970afd79c9442dc0879b0a87bc7f7fe0058bd72-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1529784343}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/964600/web_forms/1860899944", "http_etag": "\"5183c37a84b6ba1e29477c22b16d4f8359da7af7-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1860899944}, {"conversion_percentage": 2.1459227467811157, "unique_conversion_percentage": 5.4945054945054945, "name": "Template Test-Suite", "total_unique_displays": 91, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 5, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/964600/web_forms/2051923412", "http_etag": "\"ca8c6849fcb786a6f05d2111f4a8dbf8642dd944-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 233, "type": "styled", "id": 2051923412}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/955380/web_forms/82242439", "http_etag": "\"0f60646aff234b5ec8f0e3fdd792476e885908ca-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 82242439}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": null, "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/955380/web_forms/724627", "http_etag": "\"bdb5ae4d0e0bfb6ef8c253f7cef7b9bb1abe1f3c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 724627}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": null, "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/955380/web_forms/587198783", "http_etag": "\"681134ebbd0912ebafc57126c78dd964a4d56125-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 587198783}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": null, "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/955380/web_forms/1617266080", "http_etag": "\"e6e3b97b7785439f60411f7461b1a2889db1cc24-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1617266080}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/942197/web_forms/1163987878", "http_etag": "\"2980675adbcbcd672fd280d6fd05f23623bfa63a-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1163987878}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New Form 542539955", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/910041/web_forms/542539955", "http_etag": "\"676a6ebc322f40c810f97b8352d6466535ac057d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 542539955}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New Form 257213584", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/257213584", "http_etag": "\"747b22256c036faebdd02f958bef2ff3ff8fb83e-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 257213584}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 10", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/357037756", "http_etag": "\"827c8d4bb584291f9f11058c578ed807ac9156dc-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 357037756}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 3", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/400478268", "http_etag": "\"54e36cc52f8010cea33dc75a62dc563229c89827-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 400478268}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "make it rain", "total_unique_displays": 29, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/508718125", "http_etag": "\"2c5aefc3d8d01f39e6a3baab3a7785a7042e867b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 29, "type": "styled", "id": 508718125}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 6", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/689069504", "http_etag": "\"15a5ed08906a5cb727b69e49580ff2057d512d15-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 689069504}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New Form 691528162", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/691528162", "http_etag": "\"714aaccc3411c474a171c4fe5e7606ec2dc11bc3-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 691528162}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New Form 699871790", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/699871790", "http_etag": "\"35710365e496c5d4426f016e9ccf6ef42d245e10-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 699871790}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New Form 748189901", "total_unique_displays": 7, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/748189901", "http_etag": "\"0b7bbdb9bde8ccfc28fd98848714a023761f64da-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 21, "type": "styled", "id": 748189901}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "bobs form", "total_unique_displays": 11, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/894036012", "http_etag": "\"77e86e5863f9119c72ed3af7967c92ff7f37bf3e-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 122, "type": "styled", "id": 894036012}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 5", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/1276182016", "http_etag": "\"ea9cf905e5f8b7dac791daf1ab2a707ceb4466f4-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1276182016}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 4", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/1288238087", "http_etag": "\"e334666d7fd23428442fda765c497aa9d35fc5f1-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 4, "type": "styled", "id": 1288238087}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 6sdafas", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/1437665117", "http_etag": "\"d6e57f5621fdaa1ae98468320dc3f16c03893145-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1437665117}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/1457026934", "http_etag": "\"87c8c668744826e68cb3c028a36d24944b9f635f-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1457026934}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 8", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/1531760318", "http_etag": "\"29d28dc30b201895beac81321ceae9b46ce388dd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1531760318}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New Form 1595765870", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/1595765870", "http_etag": "\"a0699a235db9cffeb796dd12240a36d0c7ebbd94-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1595765870}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 10", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/1842848697", "http_etag": "\"8dafd61b38bc24f55dba2a1278507ece17fcadab-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 1842848697}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "testPreview", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/1853297168", "http_etag": "\"9aed1ef77223300ad4cc722ef2154b856d8d7917-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1853297168}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New Form 1861519652", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/1861519652", "http_etag": "\"eb3dd259cf4859f85b917fcd77499f34d3299550-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 1861519652}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": null, "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/1898374275", "http_etag": "\"10975370ab291307ea2448ffb2dcb348427dba90-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1898374275}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 2", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/1906787848", "http_etag": "\"82380044d5196a56e38a1fbd66f598fbec0dc7f3-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1906787848}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 7", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/2067391571", "http_etag": "\"750d5f8b28d3a1b55aff90c9493d49fe33bfbbc7-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 2067391571}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New Form 2107913849", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 1, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/900776/web_forms/2107913849", "http_etag": "\"b074b956a1b5c53c32987de9b5019d14314a0779-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 2107913849}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "my form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/878564/web_forms/851265514", "http_etag": "\"d19ba57bc9d865dcc33c541c4d4cb2770734c900-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 851265514}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "my form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/878564/web_forms/1141219796", "http_etag": "\"b150d0c0bdab6cfb026f3c13defd05b7fc23b33d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1141219796}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "foobar", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/878564/web_forms/1966182491", "http_etag": "\"1187e370af50fe9cd20185467ad641f62e831557-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1966182491}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "foobar Backup", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/878564/web_forms/2018090923", "http_etag": "\"ebb84c017a46c29b232e67fb066ec758007b9732-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "popup", "id": 2018090923}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Green Test Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/878564/web_forms/2047149891", "http_etag": "\"c00d650d89cbeb6d41743871ab2e97eb814dad6c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 2047149891}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "fug testing", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/823131/web_forms/332065738", "http_etag": "\"301f32f63bfee00f23bec5654d2276adb476567c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "inline", "id": 332065738}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/823123/web_forms/2116787913", "http_etag": "\"386078a203d4fa3703a1cc89fc58851b3c521b44-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 2116787913}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "fug testing", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/823119/web_forms/507248900", "http_etag": "\"e89c96894f627a53709fb3737fb315297b109145-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 507248900}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "fug testing", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/823118/web_forms/1350820648", "http_etag": "\"4a06eb62ade5c8d033f25ab8f8f41f725956b32a-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1350820648}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "fug testing", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/823112/web_forms/1448685995", "http_etag": "\"9784fcd2ca5688e6a01cbd5e53e276485632a7f2-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1448685995}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 2", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/808784/web_forms/676161441", "http_etag": "\"4bb89cc242764e2e2e349c65817010af42f766c5-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 676161441}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/808784/web_forms/1867865991", "http_etag": "\"72820806d8c09b2b422b6d0befbfd656ea930468-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 1867865991}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "test webform", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/808115/web_forms/159068296", "http_etag": "\"6efc88cc8c361b96302bc78962c7d5125ae68860-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 159068296}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "test webform", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/808108/web_forms/511191625", "http_etag": "\"ebeb6c885a61041a63114f40499c7dcca7613efc-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 511191625}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Original Legacy Form", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/800953/web_forms/1036959601", "http_etag": "\"ddadd210cf3084cb94397df01a8b5154e2d2eaa8-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 11, "type": "lightbox", "id": 1036959601}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Legacy Form Upgraded", "total_unique_displays": 3, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/800953/web_forms/1963249447", "http_etag": "\"4c2ec6baae3b3b2001fc0bc69b80cf08716776c3-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 14, "type": "styled", "id": 1963249447}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Legacy Form Manually Corrected", "total_unique_displays": 3, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/800953/web_forms/1971575092", "http_etag": "\"7bb9be77ce645de9c18603120e0fdab59483a2b7-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 16, "type": "styled", "id": 1971575092}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/784481/web_forms/1947156267", "http_etag": "\"697940ccd24b035c748b16a07a2f497a445bcfbd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1947156267}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "test WF", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/779069/web_forms/45835009", "http_etag": "\"a9027d07999bc8d350a0b0445d74eb7dca1f3087-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "inline", "id": 45835009}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/779069/web_forms/170475442", "http_etag": "\"f5a5c7dfb9f4c40cd0e4f31028f6286a967a8793-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 170475442}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": null, "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/779069/web_forms/1873861809", "http_etag": "\"b05aebe1c77e313b802a7a72dea4ef10b1a99b69-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1873861809}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "asdf", "total_unique_displays": 2, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/772516/web_forms/347588065", "http_etag": "\"f9247bb31da775793fa02fbda06a581d0d4867db-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 3, "type": "styled", "id": 347588065}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Test", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/772516/web_forms/809624501", "http_etag": "\"b6392dc21b1fdf05314ddb8bcd73a0fda1261c39-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "lightbox", "id": 809624501}, {"conversion_percentage": 33.333333333333336, "unique_conversion_percentage": 100.0, "name": "No name", "total_unique_displays": 2, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 2, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/772516/web_forms/965010836", "http_etag": "\"789f3178f8c6c53cb740ad1513362f4ae9121c82-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 6, "type": "inline", "id": 965010836}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/772516/web_forms/1881580465", "http_etag": "\"430f381402cf43d9713a94569d7bd628bc639900-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1881580465}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "blank form", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/771506/web_forms/348189412", "http_etag": "\"bc717b77dc727ad07d062fefb097310d46624e1e-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 6, "type": "styled", "id": 348189412}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Basic Blue", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/770825/web_forms/1905753533", "http_etag": "\"e136db41d3979245208bb3a9190df713fd3a94eb-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1905753533}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "my form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/770663/web_forms/892847888", "http_etag": "\"c21643f4205d0b7ccf19856698dd7f596b06b4de-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "popover", "id": 892847888}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "asdfasdfasdf", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/759844/web_forms/1634379617", "http_etag": "\"3ef2b680996eee89fb124b72a11a7b5ec179b05c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1634379617}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/745346/web_forms/1355512330", "http_etag": "\"33ce7a5a93ae01cfb3bab274d15d4ab9586d503c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1355512330}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "BuckForm", "total_unique_displays": 3, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/726604/web_forms/129150770", "http_etag": "\"c4e771b9c731cc7fe96a885f098f2babd07fb2b0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 3, "type": "styled", "id": 129150770}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Test Form Pop-over", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/726604/web_forms/244808226", "http_etag": "\"9cd06fce487d66079a29d0ab9b0933ae99dc9d60-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "popover", "id": 244808226}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Test Form Lightbox", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/726604/web_forms/599599630", "http_etag": "\"e210d12f66ff1f4054730e6f8a8d32ffc53ec791-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "lightbox", "id": 599599630}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Test Form in-Line", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/726604/web_forms/941072015", "http_etag": "\"f3ff01cbaf709af60034c220caec07259b2495c6-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 941072015}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Test Form Pop-up", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/726604/web_forms/1197965158", "http_etag": "\"3040656b7ebb09ebb0b3dfaecbc63cecaf8f61d3-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "popup", "id": 1197965158}, {"conversion_percentage": 181.81818181818181, "unique_conversion_percentage": 500.0, "name": "Test", "total_unique_displays": 4, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 20, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/724283/web_forms/2132673208", "http_etag": "\"2865cc41208c645c092def7f4b66198ad318d471-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 11, "type": "inline", "id": 2132673208}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "asdfsdf", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/702861/web_forms/566873591", "http_etag": "\"b743e7f1ee262682df8e964a59629ed1a49dabeb-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 566873591}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Unique Display Test", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/694079/web_forms/858281535", "http_etag": "\"952ed00ff7c8e881112a7020756e0965a63c3e80-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 29, "type": "inline", "id": 858281535}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Unique Display Test 2", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/694079/web_forms/1042012891", "http_etag": "\"b8800085d83e6ae0e977bb14775bca9c6f396682-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "inline", "id": 1042012891}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Pop Over", "total_unique_displays": 2, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/694079/web_forms/1191578413", "http_etag": "\"203340cbd71e53bb7e3008237d4225e8efbb6bb6-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 3, "type": "popover", "id": 1191578413}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 3, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/694079/web_forms/1217730325", "http_etag": "\"9fe092f1a19002b793f7dbb59aa86ddeb9ef9d00-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 4, "type": "lightbox", "id": 1217730325}, {"conversion_percentage": 9.0909090909090917, "unique_conversion_percentage": 200.0, "name": "My Homepage Form", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 2, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/694079/web_forms/1868326525", "http_etag": "\"50147fd094bb1d44d65629c5cc15403aa14b7839-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 22, "type": "inline", "id": 1868326525}, {"conversion_percentage": 50.0, "unique_conversion_percentage": 133.33333333333334, "name": "Test", "total_unique_displays": 9, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 12, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/660719/web_forms/402369361", "http_etag": "\"e2c71e4ae648e0ce3155f5d14271cf620b68a44a-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 24, "type": "inline", "id": 402369361}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "DonkeyNews", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/565324/web_forms/1764155127", "http_etag": "\"8678cd52a779bd1d40fb73bc0fd12a460363ceba-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1764155127}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "test form preview", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/565324/web_forms/2049171912", "http_etag": "\"238b79a4cd7e44b3ee9a32907a2418aeeec4c397-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "lightbox", "id": 2049171912}, {"conversion_percentage": 200.0, "unique_conversion_percentage": 200.0, "name": "My Web Form", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 2, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/480650/web_forms/119940622", "http_etag": "\"37995d85ec1de48a1750f683991157bbd5bca79d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 119940622}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Jeff Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/385081/web_forms/532991540", "http_etag": "\"c04ba8dece428df59ff3a068983a503f115ac4fa-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "popover", "id": 532991540}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Web Form Pop-over Slide Top", "total_unique_displays": 4, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/76455409", "http_etag": "\"6fd18ad018087d4ae916d285fa1f3993f161db64-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 12, "type": "popover", "id": 76455409}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Web Form Exit Pop-up", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/189792168", "http_etag": "\"e9ba1dbdb9d954736cfb4013f8303ce899480592-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "exitpopup", "id": 189792168}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "new form555", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/583286931", "http_etag": "\"722a29bbc87313b8d6a19974a78aa6e2ec529263-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 583286931}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Web Form Inline", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/667692730", "http_etag": "\"e83dcc8db81b7969c80299e6fc10c6fcb8aa11b7-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 4, "type": "inline", "id": 667692730}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "new form555", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/686888629", "http_etag": "\"d842c1ab0719cd2471acbe2a4314877bcb6bf595-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 686888629}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Web Form Pop-up", "total_unique_displays": 2, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/928196725", "http_etag": "\"1ef0d2dad8640ba7e7908dadd8dfeb044e734ea7-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 11, "type": "popup", "id": 928196725}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "new form555", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/954331622", "http_etag": "\"c1b8ad8c63cbe5d4945849594c877b49a2a5b110-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 954331622}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "new form555", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/971982735", "http_etag": "\"41b121aed9cd74bafc11f2987cded6a8c7c8bfbb-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 971982735}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Web Form Pop-over Pop", "total_unique_displays": 2, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/1170541731", "http_etag": "\"55734955aad86bd99fd1d5c12f6a4695cb5fcfbf-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 24, "type": "popover", "id": 1170541731}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Web Form Pop-under", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/1288554194", "http_etag": "\"b99d5a5b09e2f5323a5732ab7d960163f840033f-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 5, "type": "popunder", "id": 1288554194}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "new form555", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/1652536477", "http_etag": "\"7889ac919a1c1b449a5bfad675353ef5b9d6a855-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1652536477}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Web Form Pop-over Slide Left", "total_unique_displays": 5, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/1770309189", "http_etag": "\"db01cd46be00bc149c4f89f2bc11aa4e8f3966bb-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 16, "type": "popover", "id": 1770309189}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "new form555", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/2008449116", "http_etag": "\"328804463b0810cc7417156ad8166f17023e03bd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 2008449116}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Web Form Pop-over Fade", "total_unique_displays": 4, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_forms/2135024251", "http_etag": "\"957b4bc0a9880932e0cf014fa7c3c07a6360250d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 9, "type": "popover", "id": 2135024251}, {"conversion_percentage": 4.2553191489361701, "unique_conversion_percentage": 66.666666666666671, "name": "Tom's Form", "total_unique_displays": 3, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 2, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1/web_forms/585613330", "http_etag": "\"0c42e3d0fe9212482f6c94c65c66c56f6ed6934e-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 47, "type": "styled", "id": 585613330}, {"conversion_percentage": 1.9230769230769231, "unique_conversion_percentage": 2.2222222222222223, "name": "Test Blog Subscriber Form Backup", "total_unique_displays": 45, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 1, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1/web_forms/605946693", "http_etag": "\"dfe03cb014315b1566b89e944f6373158da7004e-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 52, "type": "inline", "id": 605946693}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1/web_forms/694992833", "http_etag": "\"a2fbae430508601a559025cc79f5c2f18f10efc8-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 694992833}, {"conversion_percentage": 1.2820512820512822, "unique_conversion_percentage": 4.0816326530612246, "name": "Test Blog Subscriber Form", "total_unique_displays": 49, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 2, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1/web_forms/736998890", "http_etag": "\"61d90b4154d2f68bd4be44bfebcb0b9b999f32a9-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 156, "type": "styled", "id": 736998890}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 2", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1/web_forms/1588279671", "http_etag": "\"1e7eae8a399ebeffeccdb98dba74c5cf67ae3b87-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1588279671}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "test", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/320972/web_forms/293943", "http_etag": "\"584bee990092c9f819279178aff904647e137455-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "popup", "id": 293943}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "No name", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/320972/web_forms/400702746", "http_etag": "\"1e86361303464a7f5b4545c18bee759e3b791fd1-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "inline", "id": 400702746}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "aweberrdb form", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/385835/web_forms/1083972136", "http_etag": "\"e17ff3aec6197e19d7923fc25ab97c1b6c17f7ee-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "popover", "id": 1083972136}, {"conversion_percentage": 16.666666666666668, "unique_conversion_percentage": 50.0, "name": "Pop-over", "total_unique_displays": 2, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 1, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/385834/web_forms/224832412", "http_etag": "\"05baaf169d94747e620118394e215f375abed729-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 6, "type": "popover", "id": 224832412}, {"conversion_percentage": 16.666666666666668, "unique_conversion_percentage": 100.0, "name": "Pop-up", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 1, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/385834/web_forms/521818981", "http_etag": "\"05c7b2fc3c6d2ada26ddec1b74cc5959c3a3036b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 6, "type": "popup", "id": 521818981}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Bite Me", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/385837/web_forms/97718346", "http_etag": "\"b6b47c8182f15c97fa686df109839dde9d9b54b0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 97718346}, {"conversion_percentage": 250.0, "unique_conversion_percentage": 250.0, "name": "My Web Form2", "total_unique_displays": 2, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 5, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/web_forms/909085126", "http_etag": "\"b8371416aae5af865c7da9954d69e2aaae4df2b4-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 2, "type": "styled", "id": 909085126}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "test_lb", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/web_forms/634275", "http_etag": "\"32d1c3aa21d7173910f4164ecb68aa03a2a6b9c4-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "lightbox", "id": 634275}, {"conversion_percentage": 250.0, "unique_conversion_percentage": 250.0, "name": "My Web Form", "total_unique_displays": 2, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 5, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/web_forms/1618399024", "http_etag": "\"7b3321ecf419e04e65c935981e82c038142cafe7-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 2, "type": "styled", "id": 1618399024}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "sdfgsdfgsdfgsdfg", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/web_forms/1739189983", "http_etag": "\"35154bc8fbaac55c33bbe63ceacdb43299e911c9-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 1739189983}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "test_lb", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/web_forms/1749436464", "http_etag": "\"93a493fe6ab0b4e773a10c9c681f9bf7d23814f4-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "lightbox", "id": 1749436464}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 3", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/web_forms/1167592969", "http_etag": "\"de51ce5f38b0e4231e2c574a9f7be77050beab65-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1167592969}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My First Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 1, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/327293/web_forms/2074646586", "http_etag": "\"399cc498f917fbda4d38a33adc7c311aea2373a0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 2074646586}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Stage 2 Web Form", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/1507672263", "http_etag": "\"d9378933b5b5cc9c30e6ac8605397c95dcb79015-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1507672263}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 3", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/1911952229", "http_etag": "\"740e66434631228ac7e9ec39e518f0b78615b6eb-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 1911952229}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Exit Popup - display every visit", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/132181207", "http_etag": "\"277bd4a125e5df089f770a2990090ef075be9851-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "exitpopup", "id": 132181207}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Test Light", "total_unique_displays": 13, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/208918171", "http_etag": "\"0847e45063225af0afdf9db639dad1ce55f45172-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 34, "type": "lightbox", "id": 208918171}, {"conversion_percentage": 2.8571428571428572, "unique_conversion_percentage": 14.285714285714286, "name": "In-Line Test", "total_unique_displays": 7, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 1, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/513600765", "http_etag": "\"ba9ec9ba99dd12cdab2c77cf4a581567d1c428e5-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 35, "type": "inline", "id": 513600765}, {"conversion_percentage": 59.574468085106382, "unique_conversion_percentage": 133.33333333333334, "name": "Popup - display every visit", "total_unique_displays": 21, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 28, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/647191251", "http_etag": "\"eb86f399609ba3bcac47328e2c371e36088513dc-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 47, "type": "popup", "id": 647191251}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "LightboxTest", "total_unique_displays": 12, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/961241624", "http_etag": "\"74ec0becd9e2cd53f7952e680695362fd2c1e0dc-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 73, "type": "styled", "id": 961241624}, {"conversion_percentage": 33.333333333333336, "unique_conversion_percentage": 50.0, "name": "Popunder - display every visit", "total_unique_displays": 8, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 4, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/1749423022", "http_etag": "\"eabdab5a1722c124ba3ed2a75c37cbf275ca31b9-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 12, "type": "popunder", "id": 1749423022}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/1921154277", "http_etag": "\"dab71e6152ce104125b6f40762294bb09309e5c6-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 1921154277}, {"conversion_percentage": 20.0, "unique_conversion_percentage": 100.0, "name": "Popover - display every visit", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 1, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/1939327572", "http_etag": "\"f290d56d439512e483d384768912e6de2a43b92b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 5, "type": "popover", "id": 1939327572}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Test Light (legacy upgraded.)", "total_unique_displays": 10, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/2046878551", "http_etag": "\"de897ef50aea8fd3300919e3375f22ecdd381708-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 31, "type": "styled", "id": 2046878551}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 2", "total_unique_displays": 4, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/2047103930", "http_etag": "\"5f9a8844dd3a501988cf9045c23c050838a3bf6e-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 9, "type": "styled", "id": 2047103930}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 4", "total_unique_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/164297012", "http_etag": "\"5e3c3b5d1d836e6a74cc6dc3e4fab268b4f731a2-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "type": "styled", "id": 164297012}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 5", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/1642576831", "http_etag": "\"3a9765ef32d2575b4212d89952e5835393a1a094-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1642576831}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 6", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/1733075440", "http_etag": "\"584f653571423fc4d2de45a964410aa4a5fd8cb7-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "styled", "id": 1733075440}, {"conversion_percentage": 150.0, "unique_conversion_percentage": 150.0, "name": "Character Test", "total_unique_displays": 2, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 3, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_forms/783905838", "http_etag": "\"6600295b6ac82ad4c898d0d29b1ce6b2291f3328-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 2, "type": "styled", "id": 783905838}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "test", "total_unique_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/487061/web_forms/801072576", "http_etag": "\"85fe08eda612b9ca19c0781da1d1c69e510b6d7c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "type": "inline", "id": 801072576}] \ No newline at end of file diff --git a/tests/data/lists/303449/campaigns.json b/tests/data/campaigns/303449.json similarity index 50% rename from tests/data/lists/303449/campaigns.json rename to tests/data/campaigns/303449.json index 1ff9a96..2115171 100644 --- a/tests/data/lists/303449/campaigns.json +++ b/tests/data/campaigns/303449.json @@ -1 +1 @@ -{"total_size": 0, "start": null, "entries": [], "resource_type_link" : "http://api.apitest.lab:81/0.1/#campaign-page-resource"} +{"total_size": 0, "start": null, "entries": [], "resource_type_link" : "https://api.aweber.com/1.0/#campaign-page-resource"} diff --git a/tests/data/lists/303449.json b/tests/data/lists/303449.json index 582192b..0f2a4c0 100644 --- a/tests/data/lists/303449.json +++ b/tests/data/lists/303449.json @@ -1 +1 @@ -{"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/303449/campaigns", "name": "default303449", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/303449/subscribers", "id": 303449, "http_etag": "\"5ba07c4b65dd1f6d245a7fd0dada5ea65b0f054d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/303449", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/303449/web_forms"} +{"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/campaigns", "name": "default303449", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers", "id": 303449, "http_etag": "\"5ba07c4b65dd1f6d245a7fd0dada5ea65b0f054d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449", "resource_type_link": "https://api.aweber.com/1.0/#list", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/web_forms"} diff --git a/tests/data/lists/303450.json b/tests/data/lists/303450.json deleted file mode 100644 index 582192b..0000000 --- a/tests/data/lists/303450.json +++ /dev/null @@ -1 +0,0 @@ -{"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/303449/campaigns", "name": "default303449", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/303449/subscribers", "id": 303449, "http_etag": "\"5ba07c4b65dd1f6d245a7fd0dada5ea65b0f054d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/303449", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/303449/web_forms"} diff --git a/tests/data/lists/505454.json b/tests/data/lists/505454.json new file mode 100644 index 0000000..bf8b249 --- /dev/null +++ b/tests/data/lists/505454.json @@ -0,0 +1 @@ +{"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/505454/campaigns", "name": "default505454", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/505454/subscribers", "id": 505454, "http_etag": "\"5gaffc4b65dd1f6d245a7fd4acda5ea65b0f054d-ca5feee2baecb6febfca8af55eded1ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/505454", "resource_type_link": "https://api.aweber.com/1.0/#list", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/505454/web_forms"} diff --git a/tests/data/lists/page1.json b/tests/data/lists/page1.json new file mode 100644 index 0000000..9c3be4e --- /dev/null +++ b/tests/data/lists/page1.json @@ -0,0 +1 @@ +{"total_size": 24, "start": 0, "resource_type_link": "https://api.aweber.com/1.0/#list-page-resource", "next_collection_link": "http://api.aweber.com/1.0/accounts/1/lists?ws.start=20&ws.size=20", "entries": [{"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533/campaigns", "name": "dailydrseuss1", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533/web_forms", "http_etag": "\"547d7402c7f528a2dbefeffa85eb973b13ed002f-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701533}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501/campaigns", "name": "default1701501", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501/web_forms", "http_etag": "\"710e976cbede7ee0befc9a78bbb079b67a1e8a22-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701501}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500/campaigns", "name": "default1701500", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500/web_forms", "http_etag": "\"9bb23b65ff2f1c755ba07691c8896114aea79303-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701500}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498/campaigns", "name": "default1701498", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498/web_forms", "http_etag": "\"e483a56588e762a709329a75f02b98ba25a744c0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701498}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497/campaigns", "name": "default1701497", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497/web_forms", "http_etag": "\"98fb0fa002a470133ef1cc2074064f25523f8351-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701497}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494/campaigns", "name": "default1701494", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494/web_forms", "http_etag": "\"2c1cd24fac1d6fbee9585007f16c3506ae0691be-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701494}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492/campaigns", "name": "default1701492", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492/web_forms", "http_etag": "\"15a50d4956d93ec26da11bf8411289c445b91b83-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701492}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491/campaigns", "name": "default1701491", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491/web_forms", "http_etag": "\"61a6028d19143623ccac12151640a84a21f20836-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701491}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489/campaigns", "name": "default1701489", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489/web_forms", "http_etag": "\"227bd84ee1763f3b46a3c37309a84b024a2c6c86-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701489}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487/campaigns", "name": "default1701487", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487/web_forms", "http_etag": "\"12edfe9548eaaf794d26606454f666f2525cce34-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701487}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486/campaigns", "name": "default1701486", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486/web_forms", "http_etag": "\"d8dca7c18825db31e24aa1ddaf51cdd8c6d74abd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701486}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482/campaigns", "name": "default1701482", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482/web_forms", "http_etag": "\"63a30a5a3b92aa45667efc7b7cba1df230883394-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701482}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/campaigns", "name": "test-stevee01", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/web_forms", "http_etag": "\"a27c0c9651a6309547835e18bb2920a44eb43ccc-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1694928}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832/campaigns", "name": "elong_api", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832/web_forms", "http_etag": "\"21e28bffb390cb82d069dd923cf99f5d9164b5fe-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1683832}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482/campaigns", "name": "default1673482", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482/web_forms", "http_etag": "\"10009452dfe8d4f6a77215a22d83735bdad5a5f6-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1673482}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018/campaigns", "name": "default1553018", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018/web_forms", "http_etag": "\"4ab41e60d14ea138a4522b3d2896942b7335c13c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1553018}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685/campaigns", "name": "default1550685", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685/web_forms", "http_etag": "\"685c00e3983add5e4efb5ca3bc7294e247f6e9fe-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1550685}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679/campaigns", "name": "default1550679", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679/web_forms", "http_etag": "\"0aaa38a50287df08ccb74c7f13fca8679aab688a-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1550679}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694/campaigns", "name": "default1482694", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694/web_forms", "http_etag": "\"fa5b88866c12617f4a74276b226bf8973a45cf73-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1482694}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/campaigns", "name": "jrodneyotest", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/web_forms", "http_etag": "\"e6edf11299299d16e7c848a3d42a52bba63daacd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1424745}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/campaigns", "name": "default1364473", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/web_forms", "http_etag": "\"dd77357a87c343b20234254438ae7094aeff2b3d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1364473}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/campaigns", "name": "tk-unlimited", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/web_forms", "http_etag": "\"cfd8bbcad976f5271368a5b3e646ea364efcd9e0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1211626}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/campaigns", "name": "devteamtest_2", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms", "http_etag": "\"d78abf7131f250f0929a6558f000b8760e76155b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 307014}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/campaigns", "name": "default1205629", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/web_forms", "http_etag": "\"f98f71baf8860d3522b4e88cb0acccabebaa9369-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1205629}]} diff --git a/tests/data/lists/page2.json b/tests/data/lists/page2.json new file mode 100644 index 0000000..5a4e9ce --- /dev/null +++ b/tests/data/lists/page2.json @@ -0,0 +1 @@ +{"total_size": 24, "prev_collection_link": "http://api.aweber.com/1.0/accounts/1/lists?ws.start=0&ws.size=20", "start": 20, "entries": [{"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/campaigns", "name": "default1364473", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/web_forms", "http_etag": "\"dd77357a87c343b20234254438ae7094aeff2b3d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1364473}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/campaigns", "name": "tk-unlimited", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/web_forms", "http_etag": "\"cfd8bbcad976f5271368a5b3e646ea364efcd9e0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1211626}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/campaigns", "name": "devteamtest_2", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms", "http_etag": "\"d78abf7131f250f0929a6558f000b8760e76155b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 307014}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/campaigns", "name": "default1205629", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/web_forms", "http_etag": "\"f98f71baf8860d3522b4e88cb0acccabebaa9369-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1205629}], "resource_type_link": "https://api.aweber.com/1.0/#list-page-resource"} diff --git a/tests/data/lists.json b/tests/data/lists/page3.json similarity index 100% rename from tests/data/lists.json rename to tests/data/lists/page3.json diff --git a/tests/data/lists_page2.json b/tests/data/lists_page2.json deleted file mode 100644 index 2bf6446..0000000 --- a/tests/data/lists_page2.json +++ /dev/null @@ -1 +0,0 @@ -{"total_size": 24, "start": 20, "prev_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists?ws.start=0&ws.size=20", "entries": [{"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/50000002/campaigns", "name": "one_two_test", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/50000002/subscribers", "id": 50000002, "http_etag": "\"daeb57124532aac221374522cb6c07754e71ba21-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/50000002", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/50000002/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/406860/campaigns", "name": "devteamtest", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/406860/subscribers", "id": 406860, "http_etag": "\"db00e81c0187d524ac56a254636664e14e90184b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/406860", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/406860/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/50000054/campaigns", "name": "furedesign_test", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/50000054/subscribers", "id": 50000054, "http_etag": "\"d082409a783f7f4f955cca186e17eb39d4b28045-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/50000054", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/50000054/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/327293/campaigns", "name": "anewtestlist1", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/327293/subscribers", "id": 327293, "http_etag": "\"99057bd859740bc8cb946dac3bf6d44a3bcc5a72-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/327293", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/327293/web_forms"}], "resource_type_link" : "http://api.apitest.lab:81/0.1/#list-page-resource"} diff --git a/tests/data/subscribers/1.json b/tests/data/subscribers/1.json index 60d19de..ca977d9 100644 --- a/tests/data/subscribers/1.json +++ b/tests/data/subscribers/1.json @@ -1 +1 @@ -{"subscription_url": null, "postal_code": "19006", "id": 1, "custom_fields": {"Trim": "EX", "Make": "Honda", "Model": "Civic", "Year": "2007"}, "last_followup_sent_link": "http://api.aweber.com/1.0/accounts/1/lists/1/campaigns/f2", "city": "Huntingdon Valley", "http_etag": "\"f3cd054da8ee5fcc8fd62765f1248a3e286a1e98-5452a183e6c35a9d38607ef778eba4fbf56db21e\"", "ad_tracking": "asasdffasdfasff", "dma_code": 143, "last_followup_message_number_sent": 1, "last_followup_sent_at": null, "misc_notes": null, "latitude": 23.23, "is_verified": false, "email": "joe@example.com", "status": "unsubscribed", "area_code": 267, "unsubscribed_at": "2010-12-16 20:57:51.178863-05:00", "self_link": "http://api.aweber.com/1.0/accounts/1/lists/1/subscribers/1", "ip_address": null, "name": "Joe Jones", "subscription_method": "email", "resource_type_link": "http://api.aweber.com/1.0/#subscriber", "region": "North America", "longitude": 70.340000000000003, "verified_at": "2010-12-17 01:57:51.178816", "subscribed_at": "2010-12-16 20:57:51.178856-05:00", "country": "USA"} +{"subscription_url": "https://www.aweber.com/users/leads/add", "name": "Joe Jones", "postal_code": "14450", "id": 50205517, "custom_fields": {"what is my quest": "", "Color": "blue", "COLOR": "", "asdfasdf": "", "test": "", "Walruses": "32"}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/campaigns/f3548399", "city": "Fairport", "http_etag": "\"e60b496d99539173e3d994dbe41e8efd5154c42b-139949b906d1ffef2d531c166eed3152968d3bc8\"", "ad_tracking": "testing", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2010-01-29 00:10:57.617606-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/subscribers/50205517", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2010-01-15 09:25:53", "subscribed_at": "2010-01-15 09:21:39-05:00"} diff --git a/tests/data/subscribers/2.json b/tests/data/subscribers/2.json new file mode 100644 index 0000000..1ef1276 --- /dev/null +++ b/tests/data/subscribers/2.json @@ -0,0 +1 @@ +{"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 52628638, "custom_fields": {"what is my quest": null, "Color": null, "COLOR": null, "asdfasdf": null, "test": null, "Walruses": null}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/campaigns/f3548399", "city": "Fairport", "http_etag": "\"f82f8c9121f8eb4a5f5c492b7be8d6a0a08c3d00-84189fc55bac463725b58eaa1e0011242c4f8993\"", "ad_tracking": "control panel", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2011-03-01 00:48:35.529460-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/subscribers/52628638", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2011-02-15 11:50:27", "subscribed_at": "2011-02-15 11:49:55-05:00"} \ No newline at end of file diff --git a/tests/data/subscribers/3.json b/tests/data/subscribers/3.json new file mode 100644 index 0000000..76fa5e5 --- /dev/null +++ b/tests/data/subscribers/3.json @@ -0,0 +1 @@ +{"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 52629234, "custom_fields": {"what is my quest": null, "Color": null, "COLOR": null, "asdfasdf": null, "test": null, "Walruses": null}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/campaigns/f3548399", "city": "Fairport", "http_etag": "\"f6a629a0a3994371c9d93ca2ab799295280669a9-3ad4b6214f0137033f4cca61d710063030611f48\"", "ad_tracking": "control panel", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2011-03-02 14:47:22.797206-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/subscribers/52629234", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2011-02-15 13:37:23", "subscribed_at": "2011-02-15 13:27:28-05:00"} \ No newline at end of file diff --git a/tests/data/subscribers/find.json b/tests/data/subscribers/find.json new file mode 100644 index 0000000..533beb8 --- /dev/null +++ b/tests/data/subscribers/find.json @@ -0,0 +1 @@ +{"total_size": 1, "start": 0, "resource_type_link": "https://api.aweber.com/1.0/#subscriber-page-resource", "entries": [{"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 50205517, "custom_fields": {"what is my quest": "", "Color": "blue", "COLOR": "", "asdfasdf": "", "test": "", "Walruses": ""}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/campaigns/f3548399", "city": "Fairport", "http_etag": "\"e60b496d99539173e3d994dbe41e8efd5154c42b-139949b906d1ffef2d531c166eed3152968d3bc8\"", "ad_tracking": "testing", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2010-01-29 00:10:57.617606-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/50205517", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2010-01-15 09:25:53", "subscribed_at": "2010-01-15 09:21:39-05:00"}]} diff --git a/tests/data/subscribers/page1.json b/tests/data/subscribers/page1.json new file mode 100644 index 0000000..27e7ccf --- /dev/null +++ b/tests/data/subscribers/page1.json @@ -0,0 +1 @@ +{"total_size": 5, "start": 0, "resource_type_link": "https://api.aweber.com/1.0/#subscriber-page-resource", "entries": [{"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 50205517, "custom_fields": {"what is my quest": "", "Color": "blue", "COLOR": "", "asdfasdf": "", "test": "", "Walruses": ""}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/campaigns/f3548399", "city": "Fairport", "http_etag": "\"e60b496d99539173e3d994dbe41e8efd5154c42b-139949b906d1ffef2d531c166eed3152968d3bc8\"", "ad_tracking": "testing", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2010-01-29 00:10:57.617606-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/50205517", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2010-01-15 09:25:53", "subscribed_at": "2010-01-15 09:21:39-05:00"}, {"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 52628638, "custom_fields": {"what is my quest": null, "Color": null, "COLOR": null, "asdfasdf": null, "test": null, "Walruses": null}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/campaigns/f3548399", "city": "Fairport", "http_etag": "\"f82f8c9121f8eb4a5f5c492b7be8d6a0a08c3d00-84189fc55bac463725b58eaa1e0011242c4f8993\"", "ad_tracking": "control panel", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2011-03-01 00:48:35.529460-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/52628638", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2011-02-15 11:50:27", "subscribed_at": "2011-02-15 11:49:55-05:00"}, {"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 52629234, "custom_fields": {"what is my quest": null, "Color": null, "COLOR": null, "asdfasdf": null, "test": null, "Walruses": null}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/campaigns/f3548399", "city": "Fairport", "http_etag": "\"f6a629a0a3994371c9d93ca2ab799295280669a9-3ad4b6214f0137033f4cca61d710063030611f48\"", "ad_tracking": "control panel", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2011-03-02 14:47:22.797206-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/52629234", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2011-02-15 13:37:23", "subscribed_at": "2011-02-15 13:27:28-05:00"}, {"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 52736751, "custom_fields": {"what is my quest": null, "Color": "5", "COLOR": "1", "asdfasdf": null, "test": "1", "Walruses": "1"}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/campaigns/f3548390", "city": "Fairport", "http_etag": "\"960ea4ccfa09531a7ed474bf698e3945857546be-dad6f6913eb8b9484b3b2aa01fd938637a100736\"", "ad_tracking": "control panel", "dma_code": 538, "last_followup_message_number_sent": 1, "last_followup_sent_at": "2011-03-04 08:47:07.194842-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/52736751", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "unsubscribed", "unsubscribed_at": "2011-03-07 15:48:32.409082-05:00", "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2011-03-04 08:35:49", "subscribed_at": "2011-03-03 17:11:07-05:00"}, {"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 52754436, "custom_fields": {"what is my quest": null, "Color": null, "COLOR": null, "asdfasdf": null, "test": null, "Walruses": null}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/campaigns/f3548390", "city": "Fairport", "http_etag": "\"e79a7a8f1f41947b6155243d8e4c9b1d3e1c7f82-8772003459a8b72fa59301e9e68bfc73b9a53c36\"", "ad_tracking": "control panel", "dma_code": 538, "last_followup_message_number_sent": 1, "last_followup_sent_at": "2011-03-08 15:52:02.979758-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/52754436", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "unsubscribed", "unsubscribed_at": "2011-03-09 10:27:43.752801-05:00", "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2011-03-08 15:50:39", "subscribed_at": "2011-03-08 15:49:26-05:00"}]} diff --git a/tests/data/web_forms.json b/tests/data/web_forms.json deleted file mode 100644 index 24635f0..0000000 --- a/tests/data/web_forms.json +++ /dev/null @@ -1 +0,0 @@ -[{"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 0, "type": "styled", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1192556/web_forms/1733464505", "http_etag": "\"81c5932ffaf2418e6547f3db29ff430f83c9ad79-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 1733464505}, {"conversion_percentage": 33.333333333333329, "unique_conversion_percentage": 100.0, "name": "My Web Form", "total_unique_displays": 1, "type": "styled", "is_active": true, "total_submissions": 1, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1121402/web_forms/1369283626", "http_etag": "\"29ac5759b22c6d92eec850b40f2e270e42b8f6fd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 3, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 1369283626}, {"conversion_percentage": 0.11641443538998836, "unique_conversion_percentage": 0.26515151515151519, "name": "Home page, sidebar", "total_unique_displays": 2640, "type": "styled", "is_active": true, "total_submissions": 7, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1093432/web_forms/356827526", "http_etag": "\"d131de42f8375408f277ccee852edec27fbf8321-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 6013, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 356827526}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": null, "total_unique_displays": 0, "type": "styled", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/771601/web_forms/131500557", "http_etag": "\"1288c4078b1f5a78197f267b9b0e3079320aa015-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 131500557}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Testing", "total_unique_displays": 0, "type": "inline", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/771601/web_forms/180597630", "http_etag": "\"9e0dc548e60eecde94661e53f06380f411118e70-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 180597630}, {"conversion_percentage": 33.333333333333329, "unique_conversion_percentage": 50.0, "name": "fdsdfsdfdfs", "total_unique_displays": 2, "type": "styled", "is_active": true, "total_submissions": 1, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/771601/web_forms/270024008", "http_etag": "\"50d20937bcc6ae716543f3da492d71302f7ba5da-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 3, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 270024008}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 0, "type": "styled", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/771601/web_forms/721555577", "http_etag": "\"82b4eb089fd0b6a0b157bda1373115d146feb59b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 721555577}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": null, "total_unique_displays": 0, "type": "styled", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/771601/web_forms/1070664099", "http_etag": "\"76e920f4b1d7ee7763b1f41a59a243a8187aba99-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 1070664099}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": null, "total_unique_displays": 0, "type": "styled", "is_active": true, "total_submissions": 1, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/771601/web_forms/2013603311", "http_etag": "\"b6691478c2334176f9c0a0065e729e5511258aa5-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 2013603311}, {"conversion_percentage": 1.1469142545057347, "unique_conversion_percentage": 3.9585296889726673, "name": "website", "total_unique_displays": 1061, "type": "inline", "is_active": true, "total_submissions": 42, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/771601/web_forms/1077762960", "http_etag": "\"4037f3d1f0c29bb19a3a5d92d13e7f0d96dd3bb1-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 3662, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 1077762960}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "blarhg", "total_unique_displays": 1, "type": "inline", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/798061/web_forms/668327018", "http_etag": "\"36e02decd31624698c6753a7f6f8b246017ca6f2-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 5, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 668327018}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New Form 785164876", "total_unique_displays": 0, "type": "styled", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/798061/web_forms/785164876", "http_etag": "\"99ad3b309fd7caa39cdc74a57093199166847ddb-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 785164876}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "barf", "total_unique_displays": 1, "type": "popover", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/798061/web_forms/1437187399", "http_etag": "\"83222600a0690071080e876fdf0d62c948ae0807-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 1437187399}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Old ass legacy stinky form", "total_unique_displays": 0, "type": "lightbox", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/853318/web_forms/1126276203", "http_etag": "\"c8b7aad2c71683c23296ca4469e125fa3af67fee-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 1126276203}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form 2", "total_unique_displays": 0, "type": "styled", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/853318/web_forms/1222053368", "http_etag": "\"4372b1ea1703db57e6f588d777244c903815c10b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 1222053368}, {"conversion_percentage": 400.0, "unique_conversion_percentage": 400.0, "name": "Sample", "total_unique_displays": 1, "type": "styled", "is_active": true, "total_submissions": 4, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/853318/web_forms/1653200290", "http_etag": "\"552639ecbb958d98848a020ab38abce5f805db00-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 1653200290}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New Form 1900114264", "total_unique_displays": 0, "type": "styled", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/853318/web_forms/1900114264", "http_etag": "\"ccb02527c3b7060d649ff8b611ccd4531d46cc85-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 1900114264}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Form popup", "total_unique_displays": 0, "type": "inline", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/853318/web_forms/1938455405", "http_etag": "\"29e56cc073fdf5e9d5dcdcbef5ef9f4adcd0b98e-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 1938455405}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "My Web Form", "total_unique_displays": 0, "type": "styled", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/853318/web_forms/2082623301", "http_etag": "\"3023b1ad6b3e0fbc52129deb5a55ce1effd56bef-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 2082623301}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Sign up for free newsletter", "total_unique_displays": 1, "type": "inline", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/853404/web_forms/1276584893", "http_etag": "\"a8ab161350d7e0d244913ff848f301c7ba66029e-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 1, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 1276584893}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "New styled form", "total_unique_displays": 1, "type": "styled", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/853399/web_forms/992299989", "http_etag": "\"669b36b1c356151329743774bff0edd1bd5a2877-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 3, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 992299989}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Existing Styled form", "total_unique_displays": 0, "type": "styled", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/853399/web_forms/1716841568", "http_etag": "\"013c2ffd669a6dff74db540bcaaaebc2494ef682-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 1716841568}, {"conversion_percentage": 0.0, "unique_conversion_percentage": 0.0, "name": "Legacy form", "total_unique_displays": 0, "type": "styled", "is_active": true, "total_submissions": 0, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/853399/web_forms/2120561755", "http_etag": "\"c58a76526d5614ae99fac801207b18851b8f6284-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "total_displays": 0, "resource_type_link": "https://api.aweber.com/1.0/#web_form", "id": 2120561755}] diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php index 6811426..91f57f5 100644 --- a/tests/mock_adapter.php +++ b/tests/mock_adapter.php @@ -4,19 +4,22 @@ class MockOAuthAdapter extends OAuthApplication { public $requestsMade = array(); + # TODO: make this consistant protected $requests = array( 'GET' => array( - '/accounts' => 'accounts', - '/accounts/1' => 'account', - '/accounts/1/lists' => 'lists', - '/accounts/1?ws.op=getWebForms' => 'web_forms', - '/accounts/910/lists' => 'lists', - '/accounts/1/lists?ws.size=20&ws.start=20' => 'lists_page2', + # the new way + '/accounts' => 'accounts/page1', + '/accounts/1' => 'accounts/1', + '/accounts/1?ws.op=getWebForms' => 'accounts/webForms', + '/accounts/1/lists' => 'lists/page1', + '/accounts/1/lists?ws.size=20&ws.start=20' => 'lists/page2', '/accounts/1/lists/303449' => 'lists/303449', - '/accounts/1/lists/303450' => 'lists/303450', - '/accounts/910/lists/123456' => 'error', - '/accounts/1/lists/303449/campaigns' => 'lists/303449/campaigns', - '/accounts/1/lists/1/subscribers/1' => 'subscribers/1', + '/accounts/1/lists/505454' => 'lists/505454', + '/accounts/1/lists/303449/campaigns' => 'campaigns/303449', + '/accounts/1/lists/303449/subscribers' => 'subscribers/page1', + '/accounts/1/lists/303449/subscribers/1' => 'subscribers/1', + '/accounts/1/lists/303449/subscribers/2' => 'subscribers/2', + '/accounts/1/lists/505454/subscribers/3' => 'subscribers/3', ), 'DELETE' => array( '/accounts/1/lists/303449' => '200', @@ -25,7 +28,16 @@ class MockOAuthAdapter extends OAuthApplication { 'PATCH' => array( '/accounts/1/lists/303449' => '209', '/accounts/1/lists/303450' => '404', - '/accounts/1/lists/1/subscribers/1' => '209', + '/accounts/1/lists/303449/subscribers/1' => '209', + ), + 'POST' => array( + '/accounts/1/lists/303449/subscribers/1' => Array( + 'Status-Code' => '201', + 'Location' => '/accounts/1/lists/505454/subscribers/3', + ), + '/accounts/1/lists/303449/subscribers/2' => Array( + 'Status-Code' => '400', + ), ) ); @@ -45,8 +57,14 @@ public function request($method, $uri, $data=array(), $options=array()) { $uri = $uri.'?'. http_build_query($data); } $this->addRequest($method, $uri, $data); - if (!empty($options['return']) && $options['return'] == 'status') { - return $this->requests[$method][$uri]; + + if (!empty($options['return'])) { + if ($options['return'] == 'status') { + return $this->requests[$method][$uri]; + } + if ($options['return'] == 'headers') { + return $this->requests[$method][$uri]; + } } $data = MockData::load($this->requests[$method][$uri]); $this->parseAsError($data); From 46545141468e49778a7f19da47daa7e42e73c28f Mon Sep 17 00:00:00 2001 From: "Edward F. Long, Jr" Date: Tue, 15 Mar 2011 09:50:38 -0400 Subject: [PATCH 003/112] fixed basename --- aweber_api/aweber_api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aweber_api/aweber_api.php b/aweber_api/aweber_api.php index ddc0ebd..1eaf1c3 100644 --- a/aweber_api/aweber_api.php +++ b/aweber_api/aweber_api.php @@ -20,7 +20,7 @@ class AWeberServiceProvider implements OAuthServiceProvider { /** * @var String Location for API calls */ - public $baseUri = 'http://apistage1.colo.lair:12011/1.0'; + public $baseUri = 'https://api.aweber.com/1.0'; /** * @var String Location to request an access token From a85ab51f2d24492b3981cb898b94bc8bb3756064 Mon Sep 17 00:00:00 2001 From: "Edward F. Long, Jr" Date: Tue, 15 Mar 2011 13:03:11 -0400 Subject: [PATCH 004/112] added find operation for collections. --- aweber_api/aweber_collection.php | 36 +++++++++++++++++++++ data.json | 6 ---- aweber_api/demo.php => demo.php | 0 simpletest | 1 - tests/all_tests.php | 1 + tests/aweber_collection.test.php | 47 ++++++++++++++++++++++++++++ tests/aweber_entry.test.php | 2 +- tests/data/subscribers/find.json | 2 +- tests/data/subscribers/find_tsl.json | 1 + tests/mock_adapter.php | 3 ++ tests/mock_data.php | 9 +++++- 11 files changed, 98 insertions(+), 10 deletions(-) delete mode 100644 data.json rename aweber_api/demo.php => demo.php (100%) delete mode 120000 simpletest create mode 100644 tests/data/subscribers/find_tsl.json diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index 3029d5a..18734e8 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -30,6 +30,42 @@ public function getById($id) { } } + + /** + * find + * + * Invoke the API 'find' operation on a collection to return a subset + * of that collection. Not all collections support the 'find' operation. + * refer to https://labs.aweber.com/docs/reference/1.0 for more information. + * + * @param mixed $search_data Associative array of key/value pairs used as search filters + * * refer to https://labs.aweber.com/docs/reference/1.0 for a + * complete list of valid search filters. + * * filtering on attributes that require additional permissions to + * display requires an app authorized with those additional permissions. + * @access public + * @return mixed AWeberCollection if the 'find' operation is successful + * otherwise, null if the 'find' operation is not successful + */ + public function find($search_data) { + # invoke find operation + $params = array_merge($search_data, array('ws.op' => 'find')); + try { + $data = $this->adapter->request('GET', $this->url, $params); + } catch (AWeberException $e) { + return false; + } + + # get total size + $ts_params = array_merge($params, array('ws.show' => 'total_size')); + $total_size = $this->adapter->request('GET', $this->url, $ts_params); + + # return collection + $data['total_size'] = $total_size; + $url = $this->url . '?'. http_build_query($params); + return new AWeberCollection($data, $url, $this->adapter); + } + /** * _getPageParams * diff --git a/data.json b/data.json deleted file mode 100644 index 2a2ad70..0000000 --- a/data.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "consumer_key" : "Ak3JWfqDPsLwcROAmS3nMb8k", - "consumer_secret" : "6SiLPb8AAK7OO1x2KnldhUaJhBGqIQHAf3jURRcg", - "access_token_key" : "AgzedRRXUeuxv6FJK21Oto7G", - "access_token_secret" : "XIvR68ERd6nzoIi5MPEqctKd0K2JjGBupMIxslpy" -} diff --git a/aweber_api/demo.php b/demo.php similarity index 100% rename from aweber_api/demo.php rename to demo.php diff --git a/simpletest b/simpletest deleted file mode 120000 index 5b9b03a..0000000 --- a/simpletest +++ /dev/null @@ -1 +0,0 @@ -../simpletest \ No newline at end of file diff --git a/tests/all_tests.php b/tests/all_tests.php index 23c7ace..3cccd0d 100644 --- a/tests/all_tests.php +++ b/tests/all_tests.php @@ -12,6 +12,7 @@ $test->addTestCase(new TestAWeberAPI()); $test->addTestCase(new OAuthAppliationTest()); $test->addTestCase(new TestAWeberCollection()); +$test->addTestCase(new TestAWeberCollectionFind()); $test->addTestCase(new TestAWeberEntry()); $test->addTestCase(new TestAWeberAccountEntry()); $test->addTestCase(new TestAWeberSubscriberEntry()); diff --git a/tests/aweber_collection.test.php b/tests/aweber_collection.test.php index cdadc30..d241829 100644 --- a/tests/aweber_collection.test.php +++ b/tests/aweber_collection.test.php @@ -1,5 +1,52 @@ adapter = new MockOAuthAdapter(); + $this->adapter->app = new AWeberServiceProvider(); + $this->subscribers = $this->_getCollection('/accounts/1/lists/303449/subscribers'); + $this->lists = $this->_getCollection('/accounts/1/lists'); + $this->adapter->clearRequests(); + } + + /** + * Return AWeberCollection + */ + public function _getCollection($url) { + $data = $this->adapter->request('GET', $url); + return new AWeberCollection($data, $url, $this->adapter); + } + + /** + * Find Returns Entries + */ + public function testFind_ReturnsEntries() { + + $found_subscribers = $this->subscribers->find(array('email' => 'someone@example.com')); + + # Asserts on the API request + $expected_url = $this->subscribers->url . '?email=someone%40example.com&ws.op=find'; + $this->assertEqual(sizeOf($this->adapter->requestsMade), 2); + $req = $this->adapter->requestsMade[0]; + $this->assertEqual($req['method'], 'GET'); + $this->assertEqual($req['uri'], $expected_url); + + $req = $this->adapter->requestsMade[1]; + $this->assertEqual($req['method'], 'GET'); + $this->assertEqual($req['uri'], $expected_url . "&ws.show=total_size"); + + # Asserts on the returned data + $this->assertTrue(is_a($found_subscribers, 'AWeberCollection')); + $this->assertEqual($this->adapter, $found_subscribers->adapter); + #$this->assertEqual($found_subscribers->url, $expected_url); + #echo "
";
+        #print_r($found_subscribers);
+        $this->assertEqual($found_subscribers->total_size, 1);
+     }
+}
+
+
 class TestAWeberCollection extends UnitTestCase {
 
     /**
diff --git a/tests/aweber_entry.test.php b/tests/aweber_entry.test.php
index 8f72bb4..096cfe5 100644
--- a/tests/aweber_entry.test.php
+++ b/tests/aweber_entry.test.php
@@ -222,7 +222,7 @@ public function testShouldHaveEntries() {
 
     public function testShouldHaveFullURL() {
         foreach($this->data as $entry) {
-            $this->assertTrue(preg_match('/^https:\/\/api\.aweber\.com\/1\.0\/accounts\/1\/lists\/[0-9]*\/web_forms\/[0-9]*$/', $entry->url));
+            $this->assertTrue(preg_match('/^\/accounts\/1\/lists\/[0-9]*\/web_forms\/[0-9]*$/', $entry->url));
         }
     }
 }
diff --git a/tests/data/subscribers/find.json b/tests/data/subscribers/find.json
index 533beb8..d9ee9f2 100644
--- a/tests/data/subscribers/find.json
+++ b/tests/data/subscribers/find.json
@@ -1 +1 @@
-{"total_size": 1, "start": 0, "resource_type_link": "https://api.aweber.com/1.0/#subscriber-page-resource", "entries": [{"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 50205517, "custom_fields": {"what is my quest": "", "Color": "blue", "COLOR": "", "asdfasdf": "", "test": "", "Walruses": ""}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/campaigns/f3548399", "city": "Fairport", "http_etag": "\"e60b496d99539173e3d994dbe41e8efd5154c42b-139949b906d1ffef2d531c166eed3152968d3bc8\"", "ad_tracking": "testing", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2010-01-29 00:10:57.617606-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/50205517", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2010-01-15 09:25:53", "subscribed_at": "2010-01-15 09:21:39-05:00"}]}
+{"total_size_link": "/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.op=find&ws.show=total_size", "start": 0, "resource_type_link": "https://api.aweber.com/1.0/#subscriber-page-resource", "entries": [{"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 50205517, "custom_fields": {"what is my quest": "", "Color": "blue", "COLOR": "", "asdfasdf": "", "test": "", "Walruses": ""}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/campaigns/f3548399", "city": "Fairport", "http_etag": "\"e60b496d99539173e3d994dbe41e8efd5154c42b-139949b906d1ffef2d531c166eed3152968d3bc8\"", "ad_tracking": "testing", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2010-01-29 00:10:57.617606-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/50205517", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2010-01-15 09:25:53", "subscribed_at": "2010-01-15 09:21:39-05:00"}]}
diff --git a/tests/data/subscribers/find_tsl.json b/tests/data/subscribers/find_tsl.json
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/data/subscribers/find_tsl.json
@@ -0,0 +1 @@
+1
diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php
index 91f57f5..11a3c65 100644
--- a/tests/mock_adapter.php
+++ b/tests/mock_adapter.php
@@ -20,6 +20,8 @@ class MockOAuthAdapter extends OAuthApplication {
             '/accounts/1/lists/303449/subscribers/1'   => 'subscribers/1',
             '/accounts/1/lists/303449/subscribers/2'   => 'subscribers/2',
             '/accounts/1/lists/505454/subscribers/3'   => 'subscribers/3',
+            '/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.op=find' => 'subscribers/find',
+            '/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.op=find&ws.show=total_size' => 'subscribers/find_tsl',
         ),
         'DELETE' => array(
             '/accounts/1/lists/303449'                 => '200',
@@ -66,6 +68,7 @@ public function request($method, $uri, $data=array(), $options=array()) {
                 return $this->requests[$method][$uri];
             }
         }
+
         $data = MockData::load($this->requests[$method][$uri]);
         $this->parseAsError($data);
         return $data;
diff --git a/tests/mock_data.php b/tests/mock_data.php
index f0d6336..63bf701 100644
--- a/tests/mock_data.php
+++ b/tests/mock_data.php
@@ -9,6 +9,13 @@ public static function load($resource) {
         if (!MockData::$host) return '';
         if (!MockData::$oauth) $resource = 'error';
         $dir = dirname(__FILE__);
-        return json_decode(file_get_contents($dir."/data/{$resource}.json"), true);
+
+        $data = file_get_contents($dir."/data/{$resource}.json");
+        $json_data = json_decode($data, true);
+        if($json_data == null) {
+            # used for total_size_links
+            return intval($data);
+        }
+        return $json_data;
     }
 }

From 07758c6cb47504db314c3c7efdb9a0e900d6bf86 Mon Sep 17 00:00:00 2001
From: "Edward F. Long, Jr" 
Date: Tue, 15 Mar 2011 15:35:05 -0400
Subject: [PATCH 005/112] removed commented out code from tests

---
 tests/aweber_collection.test.php | 4 +---
 tests/aweber_entry.test.php      | 1 +
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/tests/aweber_collection.test.php b/tests/aweber_collection.test.php
index d241829..95cda77 100644
--- a/tests/aweber_collection.test.php
+++ b/tests/aweber_collection.test.php
@@ -39,9 +39,7 @@ public function testFind_ReturnsEntries() {
         # Asserts on the returned data
         $this->assertTrue(is_a($found_subscribers, 'AWeberCollection'));
         $this->assertEqual($this->adapter, $found_subscribers->adapter);
-        #$this->assertEqual($found_subscribers->url, $expected_url);
-        #echo "
";
-        #print_r($found_subscribers);
+        $this->assertEqual($found_subscribers->url, $expected_url);
         $this->assertEqual($found_subscribers->total_size, 1);
      }
 }
diff --git a/tests/aweber_entry.test.php b/tests/aweber_entry.test.php
index 096cfe5..99fa164 100644
--- a/tests/aweber_entry.test.php
+++ b/tests/aweber_entry.test.php
@@ -289,6 +289,7 @@ public function setUp() {
          $url = '/accounts/1/lists/303449/subscribers/1';
          $data = $this->adapter->request('GET', $url);
          $this->subscriber = new AWeberEntry($data, $url, $this->adapter);
+
          $url = '/accounts/1/lists/303449/subscribers/2';
          $data = $this->adapter->request('GET', $url);
          $this->unsubscribed = new AWeberEntry($data, $url, $this->adapter);

From fc2ae2353fc9ef032450d326fa4f98a0207cb80e Mon Sep 17 00:00:00 2001
From: "Edward F. Long, Jr" 
Date: Tue, 29 Mar 2011 16:03:26 -0400
Subject: [PATCH 006/112] added support for custom_fields collection along with
 the ability to create resources.

---
 aweber_api/aweber_api.php            |  2 +-
 aweber_api/aweber_collection.php     | 30 +++++++++++++++++++++++
 tests/all_tests.php                  |  1 +
 tests/aweber_collection.test.php     | 36 ++++++++++++++++++++++++++++
 tests/aweber_entry.test.php          | 13 +++++-----
 tests/data/custom_fields/1.json      |  1 +
 tests/data/custom_fields/2.json      |  1 +
 tests/data/custom_fields/303449.json |  1 +
 tests/mock_adapter.php               |  7 ++++++
 9 files changed, 85 insertions(+), 7 deletions(-)
 create mode 100644 tests/data/custom_fields/1.json
 create mode 100644 tests/data/custom_fields/2.json
 create mode 100644 tests/data/custom_fields/303449.json

diff --git a/aweber_api/aweber_api.php b/aweber_api/aweber_api.php
index 1eaf1c3..4e2e501 100644
--- a/aweber_api/aweber_api.php
+++ b/aweber_api/aweber_api.php
@@ -84,7 +84,7 @@ class AWeberAPIBase {
         'broadcast_campaign'   => array('links', 'messages'),
         'followup_campaign'    => array('links', 'messages'),
         'link'                 => array('clicks'),
-        'list'                 => array('campaigns', 'subscribers',
+        'list'                 => array('campaigns', 'custom_fields', 'subscribers',
                                         'web_forms', 'web_form_split_tests'),
         'web_form'             => array(),
         'web_form_split_test'  => array('components'),
diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php
index 18734e8..d41dfa9 100644
--- a/aweber_api/aweber_collection.php
+++ b/aweber_api/aweber_collection.php
@@ -31,6 +31,36 @@ public function getById($id) {
     }
 
 
+    /**
+     * create
+     *
+     * Invoke the API method to CREATE a new entry resource.
+     *
+     * Note: Not all entry resources are eligible to be created, please
+     *       refer to the AWeber API Reference Documentation at
+     *       https://labs.aweber.com/docs/reference/1.0 for more
+     *       details on which entry resources may be created and what
+     *       attributes are required for creating resources.
+     *
+     * @access public
+     * @param params mixed  associtative array of key/value pairs.
+     * @return mixed AWeberEntry(Resource) The new resource created
+     *                                     or False if resource was not created.
+     */
+    public function create($kv_pairs) {
+        # Create Resource
+        $params = array_merge(array('ws.op' => 'create'), $kv_pairs);
+        $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers'));
+        if ($data['Status-Code']  !==  '201') {
+            return false;
+        }
+
+        # Return new Resource
+        $url = $data['Location'];
+        $resource_data = $this->adapter->request('GET', $url);
+        return new AWeberEntry($resource_data, $url, $this->adapter);
+    }
+
     /**
      * find
      *
diff --git a/tests/all_tests.php b/tests/all_tests.php
index 3cccd0d..d9ec971 100644
--- a/tests/all_tests.php
+++ b/tests/all_tests.php
@@ -14,6 +14,7 @@
 $test->addTestCase(new TestAWeberCollection());
 $test->addTestCase(new TestAWeberCollectionFind());
 $test->addTestCase(new TestAWeberEntry());
+$test->addTestCase(new TestAWeberCreateEntry());
 $test->addTestCase(new TestAWeberAccountEntry());
 $test->addTestCase(new TestAWeberSubscriberEntry());
 $test->addTestCase(new TestAWeberMoveEntry());
diff --git a/tests/aweber_collection.test.php b/tests/aweber_collection.test.php
index 95cda77..5766faa 100644
--- a/tests/aweber_collection.test.php
+++ b/tests/aweber_collection.test.php
@@ -44,6 +44,42 @@ public function testFind_ReturnsEntries() {
      }
 }
 
+class TestAWeberCreateEntry extends UnitTestCase {
+
+    public function setUp() {
+        $this->adapter = new MockOAuthAdapter();
+        $this->adapter->app = new AWeberServiceProvider();
+
+         # Get CustomFields
+         $url = '/accounts/1/lists/303449/custom_fields';
+         $data = $this->adapter->request('GET', $url);
+         $this->custom_fields = new AWeberCollection($data, $url, $this->adapter);
+
+    }
+
+    /**
+     * Create Succeeded
+     */
+    public function testCreate_Success() {
+
+         $this->adapter->clearRequests();
+         $resp = $this->custom_fields->create(array('name' => 'AwesomeField'));
+
+
+         $this->assertEqual(sizeOf($this->adapter->requestsMade), 2);
+
+         $req = $this->adapter->requestsMade[0];
+         $this->assertEqual($req['method'], 'POST');
+         $this->assertEqual($req['uri'], $this->custom_fields->url);
+         $this->assertEqual($req['data'], array(
+             'ws.op' => 'create',
+             'name' => 'AwesomeField'));
+
+         $req = $this->adapter->requestsMade[1];
+         $this->assertEqual($req['method'], 'GET');
+         $this->assertEqual($req['uri'], '/accounts/1/lists/303449/custom_fields/2');
+     }
+}
 
 class TestAWeberCollection extends UnitTestCase {
 
diff --git a/tests/aweber_entry.test.php b/tests/aweber_entry.test.php
index 99fa164..695a246 100644
--- a/tests/aweber_entry.test.php
+++ b/tests/aweber_entry.test.php
@@ -87,12 +87,13 @@ public function testShouldThrowExceptionIfNotImplemented() {
     public function testAttrs() {
         $this->assertEqual($this->entry->attrs(),
             array(
-                'id'          => 303449,
-                'name'        => 'default303449',
-                'self_link'   => 'https://api.aweber.com/1.0/accounts/1/lists/303449',
-                'campaigns'   => 'collection',
-                'subscribers' => 'collection',
-                'web_forms'   => 'collection',
+                'id'                   => 303449,
+                'name'                 => 'default303449',
+                'self_link'            => 'https://api.aweber.com/1.0/accounts/1/lists/303449',
+                'campaigns'            => 'collection',
+                'subscribers'          => 'collection',
+                'web_forms'            => 'collection',
+                'custom_fields'        => 'collection',
                 'web_form_split_tests' => 'collection',
             )
         );
diff --git a/tests/data/custom_fields/1.json b/tests/data/custom_fields/1.json
new file mode 100644
index 0000000..edd92fd
--- /dev/null
+++ b/tests/data/custom_fields/1.json
@@ -0,0 +1 @@
+{"name": "Favorite Color", "is_subscriber_updateable": true, "https_etag": "\"356a192b7913b04c54574d18c28d46e6395428ab-cf46a99b7a9ec9059c21044110a3528be7b0a5de\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/1", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 1}
\ No newline at end of file
diff --git a/tests/data/custom_fields/2.json b/tests/data/custom_fields/2.json
new file mode 100644
index 0000000..01b0713
--- /dev/null
+++ b/tests/data/custom_fields/2.json
@@ -0,0 +1 @@
+{"name": "COLOR", "is_subscriber_updateable": true, "https_etag": "\"da4b9237bacccdf19c0760cab7aec4a8359010b0-94bc2de8c0247784c42763ddb76e2b05405199d8\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/2", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 2}
\ No newline at end of file
diff --git a/tests/data/custom_fields/303449.json b/tests/data/custom_fields/303449.json
new file mode 100644
index 0000000..83d51d0
--- /dev/null
+++ b/tests/data/custom_fields/303449.json
@@ -0,0 +1 @@
+{"total_size": 25, "start": 0, "resource_type_link": "https://api.aweber.com/1.0/#custom_field-page-resource", "entries": [{"name": "Favorite Color", "is_subscriber_updateable": true, "https_etag": "\"356a192b7913b04c54574d18c28d46e6395428ab-cf46a99b7a9ec9059c21044110a3528be7b0a5de\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/1", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 1}, {"name": "COLOR", "is_subscriber_updateable": true, "https_etag": "\"da4b9237bacccdf19c0760cab7aec4a8359010b0-94bc2de8c0247784c42763ddb76e2b05405199d8\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/2", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 2}, {"name": "Walruses", "is_subscriber_updateable": false, "https_etag": "\"77de68daecd823babbb58edb1c8e14d7106e83bb-8cf140eeac0798552baaf7727b75087a2a1c0b4b\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/3", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 3}, {"name": "test", "is_subscriber_updateable": false, "https_etag": "\"1b6453892473a467d07372d45eb05abc2031647a-515a2e84687be77dfd27567617d2cbbdd45a8898\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/4", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 4}, {"name": "MyAwesomeCustomField", "is_subscriber_updateable": true, "https_etag": "\"ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4-2b4f2b8465b462fc6b6dfc3cec6ea068a03c4f4f\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/5", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 5}, {"name": "what is my quest", "is_subscriber_updateable": true, "https_etag": "\"c1dfd96eea8cc2b62785275bca38ac261256e278-ca36c26645bb470234ec4a9011fbf709c11bb7bc\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/6", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 6}, {"name": "What do i Seek", "is_subscriber_updateable": true, "https_etag": "\"902ba3cda1883801594b6e1b452790cc53948fda-0cd181dcc074c11cd3a9e9a53f867b7410606f62\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/7", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 7}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"fe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/8", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 8}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"0ade7c2cf97f75d009975f4d720d1fa6c19f4897-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/9", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 9}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"b1d5781111d84f7b3fe45a0852e59758cd7a87e5-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/10", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 10}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"17ba0791499db908433b80f37c5fbc89b870084b-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/11", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 11}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"7b52009b64fd0a2a49e6d8a939753077792b0554-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/12", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 12}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"bd307a3ec329e10a2cff8fb87480823da114f8f4-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/13", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 13}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"fa35e192121eabf3dabf9f5ea6abdbcbc107ac3b-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/14", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 14}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"f1abd670358e036c31296e66b3b66c382ac00812-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/15", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 15}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"1574bddb75c78a6fd2251d61e2993b5146201319-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/16", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 16}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"0716d9708d321ffb6a00818614779e779925365c-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/17", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 17}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"9e6a55b6b4563e652a23be9d623ca5055c356940-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/18", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 18}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"b3f0c7f6bb763af1be91d9e74eabfeb199dc1f1f-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/19", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 19}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"91032ad7bbcb6cf72875e8e8207dcfba80173f7c-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/20", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 20}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"472b07b9fcf2c2451e8781e944bf5f77cd8457c8-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/21", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 21}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"12c6fc06c99a462375eeb3f43dfd832b08ca9e17-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/22", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 22}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"d435a6cdd786300dff204ee7c2ef942d3e9034e2-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/23", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 23}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"4d134bc072212ace2df385dae143139da74ec0ef-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/24", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 24}, {"name": null, "is_subscriber_updateable": false, "https_etag": "\"f6e1126cedebf23e1463aee73f9df08783640400-f8cbecaf9f2b0d467aebe3909b23a65d1e7c7a82\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/custom_fields/25", "resource_type_link": "https://api.aweber.com/1.0/#custom_field", "id": 25}]}
\ No newline at end of file
diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php
index 11a3c65..c7ac1a3 100644
--- a/tests/mock_adapter.php
+++ b/tests/mock_adapter.php
@@ -16,6 +16,9 @@ class MockOAuthAdapter extends OAuthApplication {
             '/accounts/1/lists/303449'                 => 'lists/303449',
             '/accounts/1/lists/505454'                 => 'lists/505454',
             '/accounts/1/lists/303449/campaigns'       => 'campaigns/303449',
+            '/accounts/1/lists/303449/custom_fields'   => 'custom_fields/303449',
+            '/accounts/1/lists/303449/custom_fields/1' => 'custom_fields/1',
+            '/accounts/1/lists/303449/custom_fields/2' => 'custom_fields/2',
             '/accounts/1/lists/303449/subscribers'     => 'subscribers/page1',
             '/accounts/1/lists/303449/subscribers/1'   => 'subscribers/1',
             '/accounts/1/lists/303449/subscribers/2'   => 'subscribers/2',
@@ -33,6 +36,10 @@ class MockOAuthAdapter extends OAuthApplication {
             '/accounts/1/lists/303449/subscribers/1'   => '209',
         ),
         'POST' => array(
+            '/accounts/1/lists/303449/custom_fields' => Array(
+                'Status-Code' => '201',
+                'Location' => '/accounts/1/lists/303449/custom_fields/2',
+            ),
             '/accounts/1/lists/303449/subscribers/1' => Array(
                 'Status-Code' => '201',
                 'Location' => '/accounts/1/lists/505454/subscribers/3',

From a57f5912635a0dd008857254c05121a7b6f217bb Mon Sep 17 00:00:00 2001
From: Russell Posluszny 
Date: Wed, 30 Mar 2011 17:00:35 -0400
Subject: [PATCH 007/112] Added license

---
 LICENSE | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 LICENSE

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..bc5dae0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2010-2011, AWeber Communications Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the AWeber Communications Inc. nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+

From 4944a89e9a5dc6d930d4245838b9ba9c87fe27c3 Mon Sep 17 00:00:00 2001
From: Russ P 
Date: Wed, 30 Mar 2011 17:07:33 -0400
Subject: [PATCH 008/112] Updated LICENSE

---
 LICENSE | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/LICENSE b/LICENSE
index bc5dae0..6af074d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2010-2011, AWeber Communications Inc.
+Copyright (c) 2010-2011, AWeber Communications, Inc.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -8,7 +8,7 @@ modification, are permitted provided that the following conditions are met:
     * Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
-    * Neither the name of the AWeber Communications Inc. nor the
+    * Neither the name of AWeber Communications, Inc. nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.
 

From 3810bc8507934a6065b14ef89136533d323886cc Mon Sep 17 00:00:00 2001
From: "Edward F. Long, Jr" 
Date: Fri, 1 Apr 2011 09:43:39 -0400
Subject: [PATCH 009/112] updated license agreement

---
 LICENSE | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LICENSE b/LICENSE
index 6af074d..8665904 100644
--- a/LICENSE
+++ b/LICENSE
@@ -15,7 +15,7 @@ modification, are permitted provided that the following conditions are met:
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
+DISCLAIMED. IN NO EVENT SHALL AWEBER COMMUNICATIONS, INC. BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND

From 5c7312d4c8b792b00f380806f21f6936610da8f7 Mon Sep 17 00:00:00 2001
From: Boris Valerstein 
Date: Wed, 6 Apr 2011 14:48:23 -0400
Subject: [PATCH 010/112] fixed bug where find fails, in case of no matches

---
 aweber_api/aweber_collection.php         |  2 +-
 demo.php                                 |  7 +++---
 tests/aweber_collection.test.php         | 28 +++++++++++++++++++++++-
 tests/data/subscribers/nonexist.json     |  1 +
 tests/data/subscribers/nonexist_tsl.json |  1 +
 tests/mock_adapter.php                   |  5 +++++
 6 files changed, 38 insertions(+), 6 deletions(-)
 create mode 100644 tests/data/subscribers/nonexist.json
 create mode 100644 tests/data/subscribers/nonexist_tsl.json

diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php
index d41dfa9..8674aa4 100644
--- a/aweber_api/aweber_collection.php
+++ b/aweber_api/aweber_collection.php
@@ -88,7 +88,7 @@ public function find($search_data) {
 
         # get total size
         $ts_params = array_merge($params, array('ws.show' => 'total_size'));
-        $total_size = $this->adapter->request('GET', $this->url, $ts_params);
+        $total_size = $this->adapter->request('GET', $this->url, $ts_params, array('allow_empty' => 'true'));
 
         # return collection
         $data['total_size'] = $total_size;
diff --git a/demo.php b/demo.php
index 1516c18..fc56dc0 100644
--- a/demo.php
+++ b/demo.php
@@ -1,9 +1,9 @@
 adapter->debug = true;
 $account = $aweber->getAccount($_COOKIE['accessToken'], $_COOKIE['accessTokenSecret']);
-$account->loadFromUrl('/accounts/326084?ws.op=getWebForms');
 ?>
 
 
diff --git a/tests/aweber_collection.test.php b/tests/aweber_collection.test.php
index 5766faa..f0481ee 100644
--- a/tests/aweber_collection.test.php
+++ b/tests/aweber_collection.test.php
@@ -19,7 +19,7 @@ public function _getCollection($url) {
      }
 
      /**
-      * Find Returns Entries
+      * Find That Returns Entries
       */
      public function testFind_ReturnsEntries() {
 
@@ -42,6 +42,32 @@ public function testFind_ReturnsEntries() {
         $this->assertEqual($found_subscribers->url, $expected_url);
         $this->assertEqual($found_subscribers->total_size, 1);
      }
+
+    /**
+      * Find That Does Not Return Entries
+      */
+     public function testFindDoesNot_ReturnsEntries() {
+
+        $found_subscribers = $this->subscribers->find(array('email' => 'nonexist@example.com'));
+
+        # Asserts on the API request
+        $expected_url = $this->subscribers->url . '?email=nonexist%40example.com&ws.op=find';
+        $this->assertEqual(sizeOf($this->adapter->requestsMade), 2);
+        $req = $this->adapter->requestsMade[0];
+        $this->assertEqual($req['method'], 'GET');
+        $this->assertEqual($req['uri'], $expected_url);
+
+        $req = $this->adapter->requestsMade[1];
+        $this->assertEqual($req['method'], 'GET');
+        $this->assertEqual($req['uri'], $expected_url . "&ws.show=total_size");
+
+        # Asserts on the returned data
+        $this->assertTrue(is_a($found_subscribers, 'AWeberCollection'));
+        $this->assertEqual($this->adapter, $found_subscribers->adapter);
+        $this->assertEqual($found_subscribers->url, $expected_url);
+        $this->assertEqual($found_subscribers->total_size, 0);
+     }
+
 }
 
 class TestAWeberCreateEntry extends UnitTestCase {
diff --git a/tests/data/subscribers/nonexist.json b/tests/data/subscribers/nonexist.json
new file mode 100644
index 0000000..4861035
--- /dev/null
+++ b/tests/data/subscribers/nonexist.json
@@ -0,0 +1 @@
+{"total_size_link": "/accounts/1/lists/303449/subscribers?email=nonexist%40example.com&ws.op=find&ws.show=total_size", "start": 0, "resource_type_link": "https://api.aweber.com/1.0/#subscriber-page-resource", "entries": []}
diff --git a/tests/data/subscribers/nonexist_tsl.json b/tests/data/subscribers/nonexist_tsl.json
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/data/subscribers/nonexist_tsl.json
@@ -0,0 +1 @@
+0
diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php
index c7ac1a3..64c29cf 100644
--- a/tests/mock_adapter.php
+++ b/tests/mock_adapter.php
@@ -25,6 +25,8 @@ class MockOAuthAdapter extends OAuthApplication {
             '/accounts/1/lists/505454/subscribers/3'   => 'subscribers/3',
             '/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.op=find' => 'subscribers/find',
             '/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.op=find&ws.show=total_size' => 'subscribers/find_tsl',
+            '/accounts/1/lists/303449/subscribers?email=nonexist%40example.com&ws.op=find' => 'subscribers/nonexist',
+            '/accounts/1/lists/303449/subscribers?email=nonexist%40example.com&ws.op=find&ws.show=total_size' => 'subscribers/nonexist_tsl',
         ),
         'DELETE' => array(
             '/accounts/1/lists/303449'                 => '200',
@@ -77,6 +79,9 @@ public function request($method, $uri, $data=array(), $options=array()) {
         }
 
         $data = MockData::load($this->requests[$method][$uri]);
+        if (empty($options['allow_empty']) && empty($data)) {
+            throw new AWeberResponseError($uri);
+        }
         $this->parseAsError($data);
         return $data;
     }

From 4ee10b1eca2d9e804c4e519349324790ba2396be Mon Sep 17 00:00:00 2001
From: "Edward F. Long, Jr" 
Date: Mon, 18 Apr 2011 12:41:01 -0400
Subject: [PATCH 011/112] fixed bug in the collection->find method

---
 aweber_api/aweber_collection.php | 5 ++---
 tests/aweber_collection.test.php | 4 ++--
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php
index 8674aa4..a511187 100644
--- a/aweber_api/aweber_collection.php
+++ b/aweber_api/aweber_collection.php
@@ -89,11 +89,10 @@ public function find($search_data) {
         # get total size
         $ts_params = array_merge($params, array('ws.show' => 'total_size'));
         $total_size = $this->adapter->request('GET', $this->url, $ts_params, array('allow_empty' => 'true'));
+        $data['total_size'] = $total_size;
 
         # return collection
-        $data['total_size'] = $total_size;
-        $url = $this->url . '?'. http_build_query($params);
-        return new AWeberCollection($data, $url, $this->adapter);
+        return $this->readResponse($data, $this->url);
     }
 
     /**
diff --git a/tests/aweber_collection.test.php b/tests/aweber_collection.test.php
index f0481ee..25de98e 100644
--- a/tests/aweber_collection.test.php
+++ b/tests/aweber_collection.test.php
@@ -39,7 +39,7 @@ public function testFind_ReturnsEntries() {
         # Asserts on the returned data
         $this->assertTrue(is_a($found_subscribers, 'AWeberCollection'));
         $this->assertEqual($this->adapter, $found_subscribers->adapter);
-        $this->assertEqual($found_subscribers->url, $expected_url);
+        $this->assertEqual($found_subscribers->url, $this->subscribers->url);
         $this->assertEqual($found_subscribers->total_size, 1);
      }
 
@@ -64,7 +64,7 @@ public function testFindDoesNot_ReturnsEntries() {
         # Asserts on the returned data
         $this->assertTrue(is_a($found_subscribers, 'AWeberCollection'));
         $this->assertEqual($this->adapter, $found_subscribers->adapter);
-        $this->assertEqual($found_subscribers->url, $expected_url);
+        $this->assertEqual($found_subscribers->url, $this->subscribers->url);
         $this->assertEqual($found_subscribers->total_size, 0);
      }
 

From 84ab65eb1ef5ceffd50cd54beb47075a117f6d11 Mon Sep 17 00:00:00 2001
From: Boris Valerstein 
Date: Wed, 8 Jun 2011 09:33:21 -0400
Subject: [PATCH 012/112] Added findSubscribers

---
 aweber_api/aweber_entry.php | 26 ++++++++++++
 tests/all_tests.php         |  5 ++-
 tests/aweber_entry.test.php | 79 ++++++++++++++++++++++++++++++-------
 tests/mock_adapter.php      |  3 ++
 4 files changed, 96 insertions(+), 17 deletions(-)

diff --git a/aweber_api/aweber_entry.php b/aweber_api/aweber_entry.php
index 36515ef..98ea389 100644
--- a/aweber_api/aweber_entry.php
+++ b/aweber_api/aweber_entry.php
@@ -174,6 +174,32 @@ public function __set($key, $value) {
         }
     }
 
+    /**
+     * findSubscribers
+     *
+     * Looks through all lists for subscribers
+     * that match the given filter
+     * @access public
+     * @return AWeberCollection
+     */
+    public function findSubscribers($search_data) {
+        $this->_methodFor(array('account'));
+        $params = array_merge($search_data, array('ws.op' => 'findSubscribers'));
+        try {
+            $data = $this->adapter->request('GET', $this->url, $params);
+        } catch (AWeberException $e) {
+            return false;
+        }
+
+        $ts_params = array_merge($params, array('ws.show' => 'total_size'));
+        $total_size = $this->adapter->request('GET', $this->url, $ts_params, array('allow_empty' => 'true'));
+
+        # return collection
+        $data['total_size'] = $total_size;
+        $url = $this->url . '?'. http_build_query($params);
+        return new AWeberCollection($data, $url, $this->adapter);
+    }
+
     /**
      * getWebForms
      *
diff --git a/tests/all_tests.php b/tests/all_tests.php
index d9ec971..75540d7 100644
--- a/tests/all_tests.php
+++ b/tests/all_tests.php
@@ -16,8 +16,9 @@
 $test->addTestCase(new TestAWeberEntry());
 $test->addTestCase(new TestAWeberCreateEntry());
 $test->addTestCase(new TestAWeberAccountEntry());
+$test->addTestCase(new TestAccountGetWebForms());
+$test->addTestCase(new TestAccountGetWebFormSplitTests());
+$test->addTestCase(new TestAccountFindSubscribers());
 $test->addTestCase(new TestAWeberSubscriberEntry());
 $test->addTestCase(new TestAWeberMoveEntry());
 $test->run(new TextReporter());
-
-?>
diff --git a/tests/aweber_entry.test.php b/tests/aweber_entry.test.php
index 695a246..d9ced48 100644
--- a/tests/aweber_entry.test.php
+++ b/tests/aweber_entry.test.php
@@ -182,6 +182,17 @@ public function testShouldMaintainDirtiness() {
 
 }
 
+class AccountTestCase extends UnitTestCase {
+
+    public function setUp() {
+        $this->adapter = new MockOAuthAdapter();
+        $this->adapter->app = new AWeberServiceProvider();
+        $url = '/accounts/1';
+        $data = $this->adapter->request('GET', $url);
+        $this->entry = new AWeberEntry($data, $url, $this->adapter);
+    }
+}
+
 /**
  * TestAWeberAccountEntry
  *
@@ -192,42 +203,81 @@ public function testShouldMaintainDirtiness() {
  * @package 
  * @version $id$
  */
-class TestAWeberAccountEntry extends UnitTestCase {
-
-    public function setUp() {
-        $this->adapter = new MockOAuthAdapter();
-        $this->adapter->app = new AWeberServiceProvider();
-        $url = '/accounts/1';
-        $data = $this->adapter->request('GET', $url);
-        $this->entry = new AWeberEntry($data, $url, $this->adapter);
-        $this->data = $this->entry->getWebForms();
-    }
+class TestAWeberAccountEntry extends AccountTestCase {
 
     public function testIsAccount() {
         $this->assertEqual($this->entry->type, 'account');
     }
+}
+
+class TestAccountGetWebForms extends AccountTestCase {
+
+    public function setUp() {
+        parent::setUp();
+        $this->forms = $this->entry->getWebForms();
+    }
 
     public function testShouldReturnArray() {
-        $this->assertTrue(is_array($this->data));
+        $this->assertTrue(is_array($this->forms));
     }
 
     public function testShouldHaveCorrectCountOfEntries() {
-        $this->assertEqual(sizeOf($this->data), 181);
+        $this->assertEqual(sizeOf($this->forms), 181);
     }
 
     public function testShouldHaveEntries() {
-        foreach($this->data as $entry) {
+        foreach($this->forms as $entry) {
             $this->assertTrue(is_a($entry, 'AWeberEntry'));
         }
     }
 
     public function testShouldHaveFullURL() {
-        foreach($this->data as $entry) {
+        foreach($this->forms as $entry) {
             $this->assertTrue(preg_match('/^\/accounts\/1\/lists\/[0-9]*\/web_forms\/[0-9]*$/', $entry->url));
         }
     }
 }
 
+class TestAccountGetWebFormSplitTests extends AccountTestCase {
+
+    public function setUp() {
+        parent::setUp();
+        $this->forms = $this->entry->getWebFormSplitTests();
+    }
+
+    public function testShouldReturnArray() {
+        $this->assertTrue(is_array($this->forms));
+    }
+
+    public function testShouldHaveCorrectCountOfEntries() {
+        $this->assertEqual(sizeOf($this->forms), 10);
+    }
+
+    public function testShouldHaveEntries() {
+        foreach($this->forms as $entry) {
+            $this->assertTrue(is_a($entry, 'AWeberEntry'));
+        }
+    }
+
+    public function testShouldHaveFullURL() {
+        foreach($this->forms as $entry) {
+            $this->assertTrue(preg_match('/^\/accounts\/1\/lists\/[0-9]*\/web_form_split_tests\/[0-9]*$/', $entry->url));
+        }
+    }
+}
+
+class TestAccountFindSubscribers extends AccountTestCase {
+
+    public function testShouldSupportFindSubscribersMethod() {
+        $subscribers = $this->entry->findSubscribers(array('email' => 'joe@example.com'));
+
+        $this->assertTrue(is_a($subscribers, 'AWeberCollection'));
+        $this->assertEqual(count($subscribers), 1);
+        $this->assertEqual($subscribers->data['entries'][0]['self_link'],
+                           'https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/1');
+    }
+}
+
 class TestAWeberSubscriberEntry extends UnitTestCase {
 
     public function setUp() {
@@ -279,7 +329,6 @@ public function testShouldBeUpdatable() {
     }
 }
 
-
 class TestAWeberMoveEntry extends UnitTestCase {
 
     public function setUp() {
diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php
index 64c29cf..f3e8cd0 100644
--- a/tests/mock_adapter.php
+++ b/tests/mock_adapter.php
@@ -10,7 +10,10 @@ class MockOAuthAdapter extends OAuthApplication {
             # the new way
             '/accounts'                                => 'accounts/page1',
             '/accounts/1'                              => 'accounts/1',
+            '/accounts/1?email=joe%40example.com&ws.op=findSubscribers' => 'accounts/findSubscribers',
+            '/accounts/1?email=joe%40example.com&ws.op=findSubscribers&ws.show=total_size' => 'accounts/findSubscribers_ts',
             '/accounts/1?ws.op=getWebForms'            => 'accounts/webForms',
+            '/accounts/1?ws.op=getWebFormSplitTests'   => 'accounts/webFormSplitTests',
             '/accounts/1/lists'                        => 'lists/page1',
             '/accounts/1/lists?ws.size=20&ws.start=20' => 'lists/page2',
             '/accounts/1/lists/303449'                 => 'lists/303449',

From d79b28b8576cfa9c1cce89c4abc3c20ffac22df6 Mon Sep 17 00:00:00 2001
From: Boris Valerstein 
Date: Wed, 8 Jun 2011 15:25:31 -0400
Subject: [PATCH 013/112] Added getParentEntry

---
 aweber_api/aweber_collection.php | 20 +++++++++++++++++++
 aweber_api/aweber_entry.php      | 25 +++++++++++++++++++++--
 tests/all_tests.php              |  2 ++
 tests/aweber_collection.test.php | 32 +++++++++++++++++++++++++++++-
 tests/aweber_entry.test.php      | 34 +++++++++++++++++++++++++++++++-
 tests/mock_data.php              |  7 ++++++-
 6 files changed, 115 insertions(+), 5 deletions(-)

diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php
index 8674aa4..77b0ef5 100644
--- a/aweber_api/aweber_collection.php
+++ b/aweber_api/aweber_collection.php
@@ -96,6 +96,26 @@ public function find($search_data) {
         return new AWeberCollection($data, $url, $this->adapter);
     }
 
+    /** getParentEntry
+     *
+     * Gets an entry's parent entry
+     * Returns NULL if no parent entry
+     */
+    public function getParentEntry(){
+        $url_parts = split('/', $this->url);
+        $size = count($url_parts);
+
+        #Remove collection id and slash from end of url
+        $url = substr($this->url, 0, -strlen($url_parts[$size-1])-1);
+
+        try {
+            $data = $this->adapter->request('GET', $url);
+            return new AWeberEntry($data, $url, $this->adapter);
+        } catch (Exception $e) {
+            return NULL;
+        }
+    }
+
     /**
      * _getPageParams
      *
diff --git a/aweber_api/aweber_entry.php b/aweber_api/aweber_entry.php
index 98ea389..c7902cb 100644
--- a/aweber_api/aweber_entry.php
+++ b/aweber_api/aweber_entry.php
@@ -200,6 +200,29 @@ public function findSubscribers($search_data) {
         return new AWeberCollection($data, $url, $this->adapter);
     }
 
+    /** getParentEntry
+     *
+     * Gets an entry's parent entry
+     * Returns NULL if no parent entry
+     */
+    public function getParentEntry(){
+        $url_parts = split('/', $this->url);
+        $size = count($url_parts);
+
+        #Remove entry id and slash from end of url
+        $url = substr($this->url, 0, -strlen($url_parts[$size-1])-1);
+
+        #Remove collection name and slash from end of url
+        $url = substr($url, 0, -strlen($url_parts[$size-2])-1);
+
+        try {
+            $data = $this->adapter->request('GET', $url);
+            return new AWeberEntry($data, $url, $this->adapter);
+        } catch (Exception $e) {
+            return NULL;
+        }
+    }
+
     /**
      * getWebForms
      *
@@ -306,5 +329,3 @@ protected function _isChildCollection($value) {
     }
 
 }
-
-?>
diff --git a/tests/all_tests.php b/tests/all_tests.php
index 75540d7..9f9b9a1 100644
--- a/tests/all_tests.php
+++ b/tests/all_tests.php
@@ -21,4 +21,6 @@
 $test->addTestCase(new TestAccountFindSubscribers());
 $test->addTestCase(new TestAWeberSubscriberEntry());
 $test->addTestCase(new TestAWeberMoveEntry());
+$test->addTestCase(new TestGettingEntryParentEntry());
+$test->addTestCase(new TestGettingCollectionParentEntry());
 $test->run(new TextReporter());
diff --git a/tests/aweber_collection.test.php b/tests/aweber_collection.test.php
index f0481ee..6511175 100644
--- a/tests/aweber_collection.test.php
+++ b/tests/aweber_collection.test.php
@@ -229,6 +229,36 @@ public function testShouldAllowCountOperations() {
 
 }
 
+class TestGettingCollectionParentEntry extends UnitTestCase {
 
+    public function setUp() {
+        $this->adapter = new MockOAuthAdapter();
+        $this->adapter->app = new AWeberServiceProvider();
+        $url = '/accounts/1/lists';
+        $data = $this->adapter->request('GET', $url);
+        $this->lists = new AWeberCollection($data, $url, $this->adapter);
+        $url = '/accounts';
+        $data = $this->adapter->request('GET', $url);
+        $this->accounts = new AWeberCollection($data, $url, $this->adapter);
+        $url = '/accounts/1/lists/303449/custom_fields';
+        $data = $this->adapter->request('GET', $url);
+        $this->customFields = new AWeberCollection($data, $url, $this->adapter);
+    }
+
+    public function testListsParentShouldBeAccount() {
+        $entry = $this->lists->getParentEntry();
+        $this->assertTrue(is_a($entry, 'AWeberEntry'));
+        $this->assertEqual($entry->type, 'account');
+    }
+
+    public function testCustomFieldsParentShouldBeList() {
+        $entry = $this->customFields->getParentEntry();
+        $this->assertTrue(is_a($entry, 'AWeberEntry'));
+        $this->assertEqual($entry->type, 'list');
+    }
 
-?>
+    public function testAccountsParentShouldBeNULL() {
+        $entry = $this->accounts->getParentEntry();
+        $this->assertEqual($entry, NULL);
+    }
+}
diff --git a/tests/aweber_entry.test.php b/tests/aweber_entry.test.php
index d9ced48..56b2c30 100644
--- a/tests/aweber_entry.test.php
+++ b/tests/aweber_entry.test.php
@@ -392,6 +392,38 @@ public function testMove_Failure() {
          $this->assertFalse($resp);
          return;
     }
-
 }
 
+class TestGettingEntryParentEntry extends UnitTestCase {
+
+    public function setUp() {
+        $this->adapter = new MockOAuthAdapter();
+        $this->adapter->app = new AWeberServiceProvider();
+        $url = '/accounts/1/lists/303449';
+        $data = $this->adapter->request('GET', $url);
+        $this->list = new AWeberEntry($data, $url, $this->adapter);
+        $url = '/accounts/1';
+        $data = $this->adapter->request('GET', $url);
+        $this->account = new AWeberEntry($data, $url, $this->adapter);
+        $url = '/accounts/1/lists/303449/custom_fields/1';
+        $data = $this->adapter->request('GET', $url);
+        $this->customField = new AWeberEntry($data, $url, $this->adapter);
+    }
+
+    public function testListParentShouldBeAccount() {
+        $entry = $this->list->getParentEntry();
+        $this->assertTrue(is_a($entry, 'AWeberEntry'));
+        $this->assertEqual($entry->type, 'account');
+    }
+
+    public function testCustomFieldParentShouldBeList() {
+        $entry = $this->customField->getParentEntry();
+        $this->assertTrue(is_a($entry, 'AWeberEntry'));
+        $this->assertEqual($entry->type, 'list');
+    }
+
+    public function testAccountParentShouldBeNULL() {
+        $entry = $this->account->getParentEntry();
+        $this->assertEqual($entry, NULL);
+    }
+}
diff --git a/tests/mock_data.php b/tests/mock_data.php
index 63bf701..fcfc752 100644
--- a/tests/mock_data.php
+++ b/tests/mock_data.php
@@ -10,7 +10,12 @@ public static function load($resource) {
         if (!MockData::$oauth) $resource = 'error';
         $dir = dirname(__FILE__);
 
-        $data = file_get_contents($dir."/data/{$resource}.json");
+        if(file_exists($dir."/data/{$resource}.json")) {
+            $data = file_get_contents($dir."/data/{$resource}.json");
+        }
+        else {
+            $data = NULL;
+        }
         $json_data = json_decode($data, true);
         if($json_data == null) {
             # used for total_size_links

From 102be0d0be3af8ef539e8f7d8e329741ed5d287e Mon Sep 17 00:00:00 2001
From: "Edward F. Long, Jr" 
Date: Thu, 25 Aug 2011 14:24:10 -0400
Subject: [PATCH 014/112] added missing fixtures to fix broken tests.

---
 .gitignore                                  | 2 ++
 tests/aweber_entry.test.php                 | 1 -
 tests/data/accounts/findSubscribers.json    | 1 +
 tests/data/accounts/findSubscribers_ts.json | 1 +
 tests/data/accounts/webFormSplitTests.json  | 1 +
 5 files changed, 5 insertions(+), 1 deletion(-)
 create mode 100644 .gitignore
 create mode 100644 tests/data/accounts/findSubscribers.json
 create mode 100644 tests/data/accounts/findSubscribers_ts.json
 create mode 100644 tests/data/accounts/webFormSplitTests.json

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..db71f9b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.svn
+*.swp
diff --git a/tests/aweber_entry.test.php b/tests/aweber_entry.test.php
index 56b2c30..743692f 100644
--- a/tests/aweber_entry.test.php
+++ b/tests/aweber_entry.test.php
@@ -270,7 +270,6 @@ class TestAccountFindSubscribers extends AccountTestCase {
 
     public function testShouldSupportFindSubscribersMethod() {
         $subscribers = $this->entry->findSubscribers(array('email' => 'joe@example.com'));
-
         $this->assertTrue(is_a($subscribers, 'AWeberCollection'));
         $this->assertEqual(count($subscribers), 1);
         $this->assertEqual($subscribers->data['entries'][0]['self_link'],
diff --git a/tests/data/accounts/findSubscribers.json b/tests/data/accounts/findSubscribers.json
new file mode 100644
index 0000000..cf80f2d
--- /dev/null
+++ b/tests/data/accounts/findSubscribers.json
@@ -0,0 +1 @@
+{"start": 0, "total_size_link": "https://api.aweber.com/1.0/accounts/1?email=joe%40example.com&ws.op=findSubscribers&ws.show=total_size", "entries": [{"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 52629234, "custom_fields": {"NewCustomField": "really awesome", "YourCustomField": "NewValue"}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/campaigns/f3548399", "city": "Fairport", "http_etag": "\"223a06015fdd0daaef1b561aee4f10176513e346-075619e34cfd24154382b5a53939132945e96ce3\"", "ad_tracking": "control panel", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2011-03-02 14:47:22.797206-05:00", "misc_notes": "", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/1", "is_verified": true, "email": "joe@example.com", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "unsubscribe_method": null, "ip_address": "192.168.10.10", "name": "Joe User", "subscription_method": "signup form", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2011-02-15 13:37:23", "subscribed_at": "2011-02-15 13:27:28-05:00", "country": "United States"}]}
diff --git a/tests/data/accounts/findSubscribers_ts.json b/tests/data/accounts/findSubscribers_ts.json
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/data/accounts/findSubscribers_ts.json
@@ -0,0 +1 @@
+1
diff --git a/tests/data/accounts/webFormSplitTests.json b/tests/data/accounts/webFormSplitTests.json
new file mode 100644
index 0000000..f362390
--- /dev/null
+++ b/tests/data/accounts/webFormSplitTests.json
@@ -0,0 +1 @@
+[{"javascript_source_link": "http://forms.aweber.com/form/40/split_1855537940.js", "name": "Split test test", "components_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1115098/web_form_split_tests/1855537940/components", "is_active": true, "http_etag": "\"b233a000ec4c29e928c514a253a15684a410fa4e-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1115098/web_form_split_tests/1855537940", "resource_type_link": "https://api.aweber.com/1.0/#web_form_split_test", "id": 1855537940}, {"javascript_source_link": "http://forms.aweber.com/form/13/split_1532806713.js", "name": "boristest", "components_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_form_split_tests/1532806713/components", "is_active": true, "http_etag": "\"84edfbf4844a7a322bc379038974c0ce9871c1cd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_form_split_tests/1532806713", "resource_type_link": "https://api.aweber.com/1.0/#web_form_split_test", "id": 1532806713}, {"javascript_source_link": "http://forms.aweber.com/form/77/split_534926677.js", "name": "dsdf", "components_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_form_split_tests/534926677/components", "is_active": true, "http_etag": "\"3b72341343ae33364cbb88255b27faa0502eeaa4-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1108070/web_form_split_tests/534926677", "resource_type_link": "https://api.aweber.com/1.0/#web_form_split_test", "id": 534926677}, {"javascript_source_link": "http://forms.aweber.com/form/75/split_728276575.js", "name": "Split test 1", "components_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/772516/web_form_split_tests/728276575/components", "is_active": true, "http_etag": "\"178f16c2c921b30ea27b1f367005873c6de01c3b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/772516/web_form_split_tests/728276575", "resource_type_link": "https://api.aweber.com/1.0/#web_form_split_test", "id": 728276575}, {"javascript_source_link": "http://forms.aweber.com/form/48/split_1607797548.js", "name": "Split Test", "components_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/772516/web_form_split_tests/1607797548/components", "is_active": true, "http_etag": "\"67201f06d0d014c17dcde6b0a272535f6e569e79-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/772516/web_form_split_tests/1607797548", "resource_type_link": "https://api.aweber.com/1.0/#web_form_split_test", "id": 1607797548}, {"javascript_source_link": "http://forms.aweber.com/form/26/split_1252500526.js", "name": "Default", "components_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_form_split_tests/1252500526/components", "is_active": true, "http_etag": "\"3516cfad8b8d86f837c3c96a80537437fd774423-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/226186/web_form_split_tests/1252500526", "resource_type_link": "https://api.aweber.com/1.0/#web_form_split_test", "id": 1252500526}, {"javascript_source_link": "http://forms.aweber.com/form/35/split_917592535.js", "name": "sdfsdf", "components_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/web_form_split_tests/917592535/components", "is_active": true, "http_etag": "\"aa9292397447f3a0a75a377c258112d8c0533f2f-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/web_form_split_tests/917592535", "resource_type_link": "https://api.aweber.com/1.0/#web_form_split_test", "id": 917592535}, {"javascript_source_link": "http://forms.aweber.com/form/44/split_1012223044.js", "name": "My splittest", "components_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_form_split_tests/1012223044/components", "is_active": true, "http_etag": "\"a69aca22c1f557260d2e977974400ded9830d288-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_form_split_tests/1012223044", "resource_type_link": "https://api.aweber.com/1.0/#web_form_split_test", "id": 1012223044}, {"javascript_source_link": "http://forms.aweber.com/form/72/split_1470252472.js", "name": "Split Test", "components_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_form_split_tests/1470252472/components", "is_active": true, "http_etag": "\"32123e40a437467f56cbc2d937196af63521b106-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_form_split_tests/1470252472", "resource_type_link": "https://api.aweber.com/1.0/#web_form_split_test", "id": 1470252472}, {"javascript_source_link": "http://forms.aweber.com/form/63/split_612763163.js", "name": "Popover/Inline Split", "components_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_form_split_tests/612763163/components", "is_active": true, "http_etag": "\"527d810ab00669964ab634395cded77c12af7a9c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/406860/web_form_split_tests/612763163", "resource_type_link": "https://api.aweber.com/1.0/#web_form_split_test", "id": 612763163}]

From 66f30b24890bd0968f3d4b64d6096d3ffe83f4f5 Mon Sep 17 00:00:00 2001
From: "Edward F. Long, Jr" 
Date: Thu, 25 Aug 2011 16:37:12 -0400
Subject: [PATCH 015/112] modified the client library to raise exceptions when
 an api request results in an error.

---
 README                           | 50 +++++++++++++++++++++++++++++++-
 aweber_api/aweber_api.php        |  8 ++---
 aweber_api/aweber_collection.php | 36 ++++++-----------------
 aweber_api/aweber_entry.php      | 13 ++-------
 aweber_api/exceptions.php        | 28 ++++++++++++++++++
 aweber_api/oauth_application.php |  9 ++++--
 tests/data/error.json            |  2 +-
 7 files changed, 98 insertions(+), 48 deletions(-)

diff --git a/README b/README
index d6ab588..fbaf957 100644
--- a/README
+++ b/README
@@ -3,5 +3,53 @@ AWeber API PHP Library
 
 PHP library for easily integrating with the AWeber API.
 
-For complete documentation:
+Changelog:
+----------
+
+2011-08-25: v1.1.0
+ * Modified client library to raise an APIException on any API errors (HTTP status >= 400)
+
+
+Basic Usage:
+------------
+Refer to demo.php to see a working example of how to authenticate an app and query the API.
+
+For more complete documentation please refer to:
 https://labs.aweber.com/docs/php-library-walkthrough
+
+
+Handling Errors:
+----------------
+Sometimes errors happen and your application should handle them appropriately.
+Whenever an API error occurs an APIException will be raised with a detailed 
+error message and documentation link to explain whats wrong.
+
+You should wrap any calls to the API in a try/except block.
+
+Common Errors:
+ * Resource not found (404 error)
+ * Your application has been rate limited (403 error)
+ * Bad request (400 error)
+ * API Temporarily unavailable (503 error)
+
+Refer to https://labs.aweber.com/docs/troubleshooting for the complete list
+
+Example Below:
+
+getAccount($accessKey, $accessSecret);
+
+try {
+    $resource = $account->loadFromUrl('/accounts/idontexist');
+} catch (APIException $exc) {
+    print "
  • $exc->type on $exc->url, refer to $exc->message for more info ...
    "; +} + +?> diff --git a/aweber_api/aweber_api.php b/aweber_api/aweber_api.php index 4e2e501..385dea7 100644 --- a/aweber_api/aweber_api.php +++ b/aweber_api/aweber_api.php @@ -101,12 +101,8 @@ class AWeberAPIBase { * @return AWeberEntry or AWeberCollection */ public function loadFromUrl($url) { - try { - $data = $this->adapter->request('GET', $url); - return $this->readResponse($data, $url); - } catch (AWeberException $e) { - return null; - } + $data = $this->adapter->request('GET', $url); + return $this->readResponse($data, $url); } protected function _cleanUrl($url) { diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index 559cfd8..b4c73ff 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -22,12 +22,8 @@ class AWeberCollection extends AWeberResponse implements ArrayAccess, Iterator, * @return AWeberEntry */ public function getById($id) { - try { - $data = $this->adapter->request('GET', "{$this->url}/{$id}"); - return $this->_makeEntry($data, $id, "{$this->url}/{$id}"); - } catch (AWeberException $e) { - return null; - } + $data = $this->adapter->request('GET', "{$this->url}/{$id}"); + return $this->_makeEntry($data, $id, "{$this->url}/{$id}"); } @@ -44,16 +40,12 @@ public function getById($id) { * * @access public * @param params mixed associtative array of key/value pairs. - * @return mixed AWeberEntry(Resource) The new resource created - * or False if resource was not created. + * @return AWeberEntry(Resource) The new resource created */ public function create($kv_pairs) { # Create Resource $params = array_merge(array('ws.op' => 'create'), $kv_pairs); $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers')); - if ($data['Status-Code'] !== '201') { - return false; - } # Return new Resource $url = $data['Location']; @@ -74,17 +66,12 @@ public function create($kv_pairs) { * * filtering on attributes that require additional permissions to * display requires an app authorized with those additional permissions. * @access public - * @return mixed AWeberCollection if the 'find' operation is successful - * otherwise, null if the 'find' operation is not successful + * @return AWeberCollection */ public function find($search_data) { # invoke find operation $params = array_merge($search_data, array('ws.op' => 'find')); - try { - $data = $this->adapter->request('GET', $this->url, $params); - } catch (AWeberException $e) { - return false; - } + $data = $this->adapter->request('GET', $this->url, $params); # get total size $ts_params = array_merge($params, array('ws.show' => 'total_size')); @@ -187,20 +174,15 @@ protected function _calculatePageSize() { * @access protected * @return void */ - protected function _loadPageForOffset($offset, $attempt=1) { + protected function _loadPageForOffset($offset) { $this->_calculatePageSize(); $start = round($offset / $this->pageSize) * $this->pageSize; $params = $this->_getPageParams($start, $this->pageSize); // Loading page - try { - $data = $this->adapter->request('GET', $this->url, $params); - $this->adapter->debug = false; - } - catch (Exception $e) { - if ($attempt < 3) $this->_loadPageForOffset($offset, ++$attempt); - return; - } + $data = $this->adapter->request('GET', $this->url, $params); + $this->adapter->debug = false; + $rekeyed = array(); foreach ($data['entries'] as $key => $entry) { $rekeyed[$key+$data['start']] = $entry; diff --git a/aweber_api/aweber_entry.php b/aweber_api/aweber_entry.php index c7902cb..d90f569 100644 --- a/aweber_api/aweber_entry.php +++ b/aweber_api/aweber_entry.php @@ -185,11 +185,7 @@ public function __set($key, $value) { public function findSubscribers($search_data) { $this->_methodFor(array('account')); $params = array_merge($search_data, array('ws.op' => 'findSubscribers')); - try { - $data = $this->adapter->request('GET', $this->url, $params); - } catch (AWeberException $e) { - return false; - } + $data = $this->adapter->request('GET', $this->url, $params); $ts_params = array_merge($params, array('ws.show' => 'total_size')); $total_size = $this->adapter->request('GET', $this->url, $ts_params, array('allow_empty' => 'true')); @@ -299,12 +295,7 @@ protected function _methodFor($entryTypes) { protected function _getCollection($value) { if (empty($this->_collections[$value])) { $url = "{$this->url}/{$value}"; - try { - $data = $this->adapter->request('GET', $url); - } - catch (Exception $e) { - $data = array('entries' => array(), 'total_size' => 0, 'start' => 0); - } + $data = $this->adapter->request('GET', $url); $this->_collections[$value] = new AWeberCollection($data, $url, $this->adapter); } return $this->_collections[$value]; diff --git a/aweber_api/exceptions.php b/aweber_api/exceptions.php index 954bc45..c556b6c 100644 --- a/aweber_api/exceptions.php +++ b/aweber_api/exceptions.php @@ -2,6 +2,34 @@ class AWeberException extends Exception { } +/** + * Thrown when the API returns an error. (HTTP status >= 400) + * + * + * @uses AWeberException + * @package + * @version $id$ + */ +class APIException extends AWeberException { + + public $type; + public $status; + public $message; + public $documentation_url; + public $url; + + public function __construct($error, $url) { #type, $status, $message, $documentation_url) { + + // record specific details of the API exception for processing + $this->url = $url; + $this->type = $error['type']; + $this->status = $error['status']; + $this->message = $error['message']; + $this->documentation_url = $error['documentation_url']; + + parent::__construct($this->message); + } +} /** * Thrown when attempting to use a resource that is not implemented. diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index ad5b452..c122cfe 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -106,11 +106,17 @@ public function __construct($parentApp = false) { public function request($method, $uri, $data = array(), $options = array()) { $uri = $this->app->removeBaseUri($uri); $url = $this->app->getBaseUri() . $uri; - $response = $this->makeRequest($method, $url, $data); + if (!$response) { throw new AWeberResponseError($uri); } + + if($response->headers['Status-Code'] >= 400) { + $data = json_decode($response->body, true); + throw new APIException($data['error'], $url); + } + if (!empty($options['return'])) { if ($options['return'] == 'status') { return $response->headers['Status-Code']; @@ -168,7 +174,6 @@ public function getAccessToken() { return array($data['oauth_token'], $data['oauth_token_secret']); } - /** * parseAsError * diff --git a/tests/data/error.json b/tests/data/error.json index bb8eb9b..623bc5f 100644 --- a/tests/data/error.json +++ b/tests/data/error.json @@ -1 +1 @@ -{"error": {"message": "Missing required parameter 'oauth_consumer_key'.", "type": "MissingRequiredOAuthParameterError"}} +{"error": {"message": "Simulated Exception", "type": "BadRequestError"}} From 273a7f77d83869d7911bf99a3909cce5de67176c Mon Sep 17 00:00:00 2001 From: "Edward F. Long, Jr" Date: Thu, 25 Aug 2011 16:37:39 -0400 Subject: [PATCH 016/112] fixed typo in demo.php --- demo.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/demo.php b/demo.php index fc56dc0..9841c7e 100644 --- a/demo.php +++ b/demo.php @@ -4,6 +4,7 @@ // NEVER SHARE OR DISTRIBUTE YOUR APPLICATIONS'S KEYS! $consumerKey = "************************"; $consumerSecret = "*********************************"; + $aweber = new AWeberAPI($consumerKey, $consumerSecret); if (empty($_COOKIE['accessToken'])) { @@ -25,8 +26,12 @@ header('Location: '.$_COOKIE['callbackUrl']); exit(); } -$aweber->adapter->debug = true; + +# set this to true to view the actual api request and response +$aweber->adapter->debug = false; + $account = $aweber->getAccount($_COOKIE['accessToken'], $_COOKIE['accessTokenSecret']); + ?> @@ -51,7 +56,7 @@ ?> subject; ?> - sent_date)); ?> + sent_at)); ?>
    • Opened: total_opens; ?>
    • Sent: total_sent; ?>
    • From c2233192f50071858b421b8e66e36a6ad06350e6 Mon Sep 17 00:00:00 2001 From: "Edward F. Long, Jr" Date: Mon, 29 Aug 2011 12:01:00 -0400 Subject: [PATCH 017/112] updated tests to only mock the actual request and not the request processing methods for better test coverage. modified fixtures. --- aweber_api/aweber_collection.php | 2 +- aweber_api/aweber_entry.php | 13 +--- aweber_api/oauth_application.php | 3 + tests/all_tests.php | 2 +- tests/aweber_api.test.php | 42 +++++------ tests/aweber_api_test.php | 93 ----------------------- tests/aweber_collection.test.php | 33 +++++---- tests/aweber_entry.test.php | 68 ++++++++--------- tests/data/lists/page1.json | 2 +- tests/data/lists/page2.json | 2 +- tests/data/lists/page3.json | 1 - tests/mock_adapter.php | 123 ++++++++++++++----------------- tests/mock_data.php | 18 +++-- tests/oauth_application.test.php | 2 +- 14 files changed, 146 insertions(+), 258 deletions(-) delete mode 100644 tests/aweber_api_test.php delete mode 100644 tests/data/lists/page3.json diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index b4c73ff..63d3ddd 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -75,7 +75,7 @@ public function find($search_data) { # get total size $ts_params = array_merge($params, array('ws.show' => 'total_size')); - $total_size = $this->adapter->request('GET', $this->url, $ts_params, array('allow_empty' => 'true')); + $total_size = $this->adapter->request('GET', $this->url, $ts_params, array('return' => 'integer')); $data['total_size'] = $total_size; # return collection diff --git a/aweber_api/aweber_entry.php b/aweber_api/aweber_entry.php index d90f569..f3d3db9 100644 --- a/aweber_api/aweber_entry.php +++ b/aweber_api/aweber_entry.php @@ -72,9 +72,8 @@ protected function _type() { * if the delete request failed. */ public function delete() { - $status = $this->adapter->request('DELETE', $this->url, array(), array('return' => 'status')); - if (substr($status, 0, 2) == '20') return true; - return false; + $this->adapter->request('DELETE', $this->url, array(), array('return' => 'status')); + return true; } /** @@ -97,9 +96,6 @@ public function move($list) { # Move Resource $params = array('ws.op' => 'move', 'list_link' => $list->self_link); $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers')); - if ($data['Status-Code'] !== '201') { - return false; - } # Return new Resource $url = $data['Location']; @@ -117,9 +113,6 @@ public function move($list) { public function save() { if (!empty($this->_localDiff)) { $data = $this->adapter->request('PATCH', $this->url, $this->_localDiff, array('return' => 'status')); - if (substr($data, 0, 2) !== '20') { - return false; - } } $this->_localDiff = array(); return true; @@ -188,7 +181,7 @@ public function findSubscribers($search_data) { $data = $this->adapter->request('GET', $this->url, $params); $ts_params = array_merge($params, array('ws.show' => 'total_size')); - $total_size = $this->adapter->request('GET', $this->url, $ts_params, array('allow_empty' => 'true')); + $total_size = $this->adapter->request('GET', $this->url, $ts_params, array('return' => 'integer')); # return collection $data['total_size'] = $total_size; diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index c122cfe..cd52b26 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -124,6 +124,9 @@ public function request($method, $uri, $data = array(), $options = array()) { if ($options['return'] == 'headers') { return $response->headers; } + if ($options['return'] == 'integer') { + return intval($response->body); + } } $data = json_decode($response->body, true); if (empty($options['allow_empty']) && empty($data)) { diff --git a/tests/all_tests.php b/tests/all_tests.php index 9f9b9a1..45e848f 100644 --- a/tests/all_tests.php +++ b/tests/all_tests.php @@ -10,7 +10,7 @@ $test = &new GroupTest('All tests'); $test->addTestCase(new TestAWeberAPI()); -$test->addTestCase(new OAuthAppliationTest()); +$test->addTestCase(new TestOAuthAppliation()); $test->addTestCase(new TestAWeberCollection()); $test->addTestCase(new TestAWeberCollectionFind()); $test->addTestCase(new TestAWeberEntry()); diff --git a/tests/aweber_api.test.php b/tests/aweber_api.test.php index 9508751..9543501 100644 --- a/tests/aweber_api.test.php +++ b/tests/aweber_api.test.php @@ -1,9 +1,16 @@ adapter = new MockOAuthAdapter(); + $this->adapter = get_mock_adapter(); $this->app = array( 'key' => 'RogsGzUw3QAK6cPSI24u', 'secret' => '1eaHAFJnEklS8qSBvitvSO6OCkaU4QyHU3AOE1rw', @@ -15,18 +22,14 @@ public function setUp() { 'token' => 'lc0UcVJdlpNyVVMLzeZWZZGb61pEnlhBdHGg9usF', 'secret' => 'VMus5FW1TyX7N24xaOyc0VsylGBHC6rAomq3LM67', ); - } /** * App keys given at construction should be maintained internally */ public function test_should_contain_app_keys() { - $this->assertEqual($this->aweber->consumerKey, - $this->app['key']); - $this->assertEqual($this->aweber->consumerSecret, - $this->app['secret']); - + $this->assertEqual($this->aweber->consumerKey, $this->app['key']); + $this->assertEqual($this->aweber->consumerSecret, $this->app['secret']); } /** @@ -44,24 +47,19 @@ public function test_should_raise_exception_if_auth_fails() { MockData::$oauth = false; $this->aweber->setAdapter($this->adapter); try { - $account = $this->aweber->getAccount($this->user['token'], - $this->user['secret']); + $account = $this->aweber->getAccount($this->user['token'], $this->user['secret']); $this->assertTrue(false, 'This should not run due to an exception'); } - catch (Exception $e) { - $this->assertTrue(is_a($e, 'Exception')); - } + catch (Exception $e) { } MockData::$oauth = true; } -# is this test a valid test? -# public function test_should_return_null_after_authorization() { -# $this->aweber->setAdapter($this->adapter); -# $account = $this->aweber->getAccount($this->user['token'], -# $this->user['secret']); -# $list = $account->lists->getById(123456); -# $this->assertTrue(empty($list)); -# } + public function test_should_work_after_authorization() { + $this->aweber->setAdapter($this->adapter); + $account = $this->aweber->getAccount($this->user['token'], $this->user['secret']); + $list = $account->lists->getById(303449); + $this->assertEqual($list->id, 303449); + } /** * getAccount should load an AWeberEntry based on a single account @@ -69,8 +67,8 @@ public function test_should_raise_exception_if_auth_fails() { */ public function test_getAccount() { $this->aweber->setAdapter($this->adapter); - $account = $this->aweber->getAccount($this->user['token'], - $this->user['secret']); + $account = $this->aweber->getAccount($this->user['token'], $this->user['secret']); + $this->assertNotNull($account); $this->assertTrue(is_a($account, 'AWeberResponse')); $this->assertTrue(is_a($account, 'AWeberEntry')); diff --git a/tests/aweber_api_test.php b/tests/aweber_api_test.php deleted file mode 100644 index de53745..0000000 --- a/tests/aweber_api_test.php +++ /dev/null @@ -1,93 +0,0 @@ -adapter = new MockOAuthAdapter(); - $this->app = array( - 'key' => 'RogsGzUw3QAK6cPSI24u', - 'secret' => '1eaHAFJnEklS8qSBvitvSO6OCkaU4QyHU3AOE1rw', - ); - $this->aweber = new AWeberAPI($this->app['key'], - $this->app['secret']); - - $this->user = array( - 'token' => 'lc0UcVJdlpNyVVMLzeZWZZGb61pEnlhBdHGg9usF', - 'secret' => 'VMus5FW1TyX7N24xaOyc0VsylGBHC6rAomq3LM67', - ); - - } - - /** - * App keys given at construction should be maintained internally - */ - public function test_should_contain_app_keys() { - $this->assertEqual($this->aweber->consumerKey, - $this->app['key']); - $this->assertEqual($this->aweber->consumerSecret, - $this->app['secret']); - - } - - /** - * OAuther adapter object should be allowed to be switched out - */ - public function test_should_allow_setting_oauth_adapter() { - $this->aweber->setAdapter($this->adapter); - $this->assertEqual($this->aweber->adapter, $this->adapter); - } - - /** - * When authorization fails, an exception is raised - */ - public function test_should_raise_exception_if_auth_fails() { - MockData::$oauth = false; - $this->aweber->setAdapter($this->adapter); - try { - $account = $this->aweber->getAccount($this->user['token'], - $this->user['secret']); - $this->assertTrue(false, 'This should not run due to an exception'); - } - catch (Exception $e) { - $this->assertTrue(is_a($e, 'Exception')); - } - MockData::$oauth = true; - } - - public function test_should_return_null_after_authorization() { - $this->aweber->setAdapter($this->adapter); - $account = $this->aweber->getAccount($this->user['token'], - $this->user['secret']); - $list = $account->lists->getById(123456); - $this->assertTrue(empty($list)); - } - - /** - * getAccount should load an AWeberEntry based on a single account - * for the authorized user - */ - public function test_getAccount() { - $this->aweber->setAdapter($this->adapter); - $account = $this->aweber->getAccount($this->user['token'], - $this->user['secret']); - $this->assertNotNull($account); - $this->assertTrue(is_a($account, 'AWeberResponse')); - $this->assertTrue(is_a($account, 'AWeberEntry')); - } - - /** - * Load from URL should take a relative URL and return the correct - * object based on that request. Allows skipping around the tree - * based on URLs, not just walking it. - */ - public function test_loadFromUrl() { - $this->aweber->setAdapter($this->adapter); - $list = $this->aweber->loadFromUrl('/accounts/1/lists/303449'); - - $this->assertTrue(is_a($list, 'AWeberEntry')); - $this->assertEqual($list->type, 'list'); - $this->assertEqual($list->id, '303449'); - } - -} -?> diff --git a/tests/aweber_collection.test.php b/tests/aweber_collection.test.php index bf8fccf..2a1c503 100644 --- a/tests/aweber_collection.test.php +++ b/tests/aweber_collection.test.php @@ -3,8 +3,7 @@ class TestAWeberCollectionFind extends UnitTestCase { public function setUp() { - $this->adapter = new MockOAuthAdapter(); - $this->adapter->app = new AWeberServiceProvider(); + $this->adapter = get_mock_adapter(); $this->subscribers = $this->_getCollection('/accounts/1/lists/303449/subscribers'); $this->lists = $this->_getCollection('/accounts/1/lists'); $this->adapter->clearRequests(); @@ -73,13 +72,12 @@ public function testFindDoesNot_ReturnsEntries() { class TestAWeberCreateEntry extends UnitTestCase { public function setUp() { - $this->adapter = new MockOAuthAdapter(); - $this->adapter->app = new AWeberServiceProvider(); + $this->adapter = get_mock_adapter(); - # Get CustomFields - $url = '/accounts/1/lists/303449/custom_fields'; - $data = $this->adapter->request('GET', $url); - $this->custom_fields = new AWeberCollection($data, $url, $this->adapter); + # Get CustomFields + $url = '/accounts/1/lists/303449/custom_fields'; + $data = $this->adapter->request('GET', $url); + $this->custom_fields = new AWeberCollection($data, $url, $this->adapter); } @@ -114,8 +112,10 @@ class TestAWeberCollection extends UnitTestCase { * data for requests, and creates a new collection. */ public function setUp() { - $this->adapter = new MockOAuthAdapter(); - $this->collection = new AWeberCollection(MockData::load('lists/page3'), '/accounts/1/lists', $this->adapter); + $this->adapter = get_mock_adapter(); + $this->url = '/accounts/1/lists'; + $data = $this->adapter->request('GET', $this->url); + $this->collection = new AWeberCollection($data, $this->url, $this->adapter); } /** @@ -129,7 +129,7 @@ public function testShouldHaveTotalSize() { * Should have the URL used to generate this collection */ public function testShouldHaveURL() { - $this->assertEqual($this->collection->url, '/accounts/1/lists'); + $this->assertEqual($this->collection->url, $this->url); } /** @@ -147,7 +147,7 @@ public function testShouldAccessEntiresAsArray() { $entry = $this->collection[0]; $this->assertTrue(is_a($entry, 'AWeberResponse')); $this->assertTrue(is_a($entry, 'AWeberEntry')); - $this->assertEqual($entry->id, 251847); + $this->assertEqual($entry->id, 1701533); } public function testShouldKnowItsCollectionType() { @@ -167,9 +167,11 @@ public function testShouldNotAccessEntriesOutOfRange() { */ public function testShouldLazilyLoadAdditionalPages() { $this->adapter->clearRequests(); + + $this->assertEqual(sizeof($this->collection->data['entries']), 20); $entry = $this->collection[19]; - $this->assertEqual($entry->id, 50000003); + $this->assertEqual($entry->id, 1424745); $this->assertTrue(empty($this->adapter->requestsMade)); $entry = $this->collection[20]; @@ -207,6 +209,7 @@ public function testShouldAllowIteration() { public function testShouldAllowGetById() { $id = 303449; $name = 'default303449'; + $this->adapter->clearRequests(); $entry = $this->collection->getById($id); $this->assertEqual($entry->id, $id); @@ -214,6 +217,7 @@ public function testShouldAllowGetById() { $this->assertTrue(is_a($entry, 'AWeberEntry')); $this->assertEqual(count($this->adapter->requestsMade), 1); + $this->assertEqual($this->adapter->requestsMade[0]['uri'], '/accounts/1/lists/303449'); } @@ -232,8 +236,7 @@ public function testShouldAllowCountOperations() { class TestGettingCollectionParentEntry extends UnitTestCase { public function setUp() { - $this->adapter = new MockOAuthAdapter(); - $this->adapter->app = new AWeberServiceProvider(); + $this->adapter = get_mock_adapter(); $url = '/accounts/1/lists'; $data = $this->adapter->request('GET', $url); $this->lists = new AWeberCollection($data, $url, $this->adapter); diff --git a/tests/aweber_entry.test.php b/tests/aweber_entry.test.php index 743692f..43e0c50 100644 --- a/tests/aweber_entry.test.php +++ b/tests/aweber_entry.test.php @@ -1,5 +1,11 @@ adapter = new MockOAuthAdapter(); - + $this->adapter = get_mock_adapter(); $url = '/accounts/1/lists/303449'; $data = $this->adapter->request('GET', $url); $this->entry = new AWeberEntry($data, $url, $this->adapter); @@ -70,14 +75,8 @@ public function testShouldProvidedCollections() { */ public function testShouldThrowExceptionIfNotImplemented() { $this->adapter->clearRequests(); - try { - $obj = $this->entry->something_not_implemented; - $this->assertFalse(true, "This should not get called due to exception raising."); - } - catch (Exception $e) { - $this->assertTrue(is_a($e, 'AWeberException')); - $this->assertTrue(is_a($e, 'AWeberResourceNotImplemented')); - } + $this->expectException(AWeberResourceNotImplemented); + $obj = $this->entry->something_not_implemented; $this->assertEqual(count($this->adapter->requestsMade), 0); } @@ -121,9 +120,8 @@ public function testFailedDelete() { $data = $this->adapter->request('GET', $url); $entry = new AWeberEntry($data, $url, $this->adapter); - // Can't delete account - $resp = $entry->delete(); - $this->assertIdentical($resp, false); + $this->expectException(APIException, "SimulatedException"); + $entry->delete(); } /** @@ -159,13 +157,13 @@ public function testSaveFailed() { $data = $this->adapter->request('GET', $url); $entry = new AWeberEntry($data, $url, $this->adapter); $entry->name = 'foobarbaz'; + $this->expectException(APIException, "SimulatedException"); $resp = $entry->save(); - $this->assertIdentical($resp, false); } /** * Should keep track of whether or not this entry is "dirty". It should - * not Color save calls if it hasn't been altered since the last successful + * not issue save calls if it hasn't been altered since the last successful * load / save operation. */ public function testShouldMaintainDirtiness() { @@ -185,8 +183,7 @@ public function testShouldMaintainDirtiness() { class AccountTestCase extends UnitTestCase { public function setUp() { - $this->adapter = new MockOAuthAdapter(); - $this->adapter->app = new AWeberServiceProvider(); + $this->adapter = get_mock_adapter(); $url = '/accounts/1'; $data = $this->adapter->request('GET', $url); $this->entry = new AWeberEntry($data, $url, $this->adapter); @@ -280,8 +277,7 @@ public function testShouldSupportFindSubscribersMethod() { class TestAWeberSubscriberEntry extends UnitTestCase { public function setUp() { - $this->adapter = new MockOAuthAdapter(); - $this->adapter->app = new AWeberServiceProvider(); + $this->adapter = get_mock_adapter(); $url = '/accounts/1/lists/303449/subscribers/1'; $data = $this->adapter->request('GET', $url); $this->entry = new AWeberEntry($data, $url, $this->adapter); @@ -331,22 +327,21 @@ public function testShouldBeUpdatable() { class TestAWeberMoveEntry extends UnitTestCase { public function setUp() { - $this->adapter = new MockOAuthAdapter(); - $this->adapter->app = new AWeberServiceProvider(); + $this->adapter = get_mock_adapter(); - # Get Subscriber - $url = '/accounts/1/lists/303449/subscribers/1'; - $data = $this->adapter->request('GET', $url); - $this->subscriber = new AWeberEntry($data, $url, $this->adapter); + # Get Subscriber + $url = '/accounts/1/lists/303449/subscribers/1'; + $data = $this->adapter->request('GET', $url); + $this->subscriber = new AWeberEntry($data, $url, $this->adapter); - $url = '/accounts/1/lists/303449/subscribers/2'; - $data = $this->adapter->request('GET', $url); - $this->unsubscribed = new AWeberEntry($data, $url, $this->adapter); + $url = '/accounts/1/lists/303449/subscribers/2'; + $data = $this->adapter->request('GET', $url); + $this->unsubscribed = new AWeberEntry($data, $url, $this->adapter); - # Different List - $url = '/accounts/1/lists/505454'; - $data = $this->adapter->request('GET', $url); - $this->different_list = new AWeberEntry($data, $url, $this->adapter); + # Different List + $url = '/accounts/1/lists/505454'; + $data = $this->adapter->request('GET', $url); + $this->different_list = new AWeberEntry($data, $url, $this->adapter); } /** @@ -377,8 +372,8 @@ public function testMove_Success() { public function testMove_Failure() { $this->adapter->clearRequests(); - $resp = $this->unsubscribed->move($this->different_list); - + $this->expectException(APIException, "SimulatedException"); + $this->unsubscribed->move($this->different_list); $this->assertEqual(sizeOf($this->adapter->requestsMade), 1); $req = $this->adapter->requestsMade[0]; @@ -387,8 +382,6 @@ public function testMove_Failure() { $this->assertEqual($req['data'], array( 'ws.op' => 'move', 'list_link' => $this->different_list->self_link)); - - $this->assertFalse($resp); return; } } @@ -396,8 +389,7 @@ public function testMove_Failure() { class TestGettingEntryParentEntry extends UnitTestCase { public function setUp() { - $this->adapter = new MockOAuthAdapter(); - $this->adapter->app = new AWeberServiceProvider(); + $this->adapter = get_mock_adapter(); $url = '/accounts/1/lists/303449'; $data = $this->adapter->request('GET', $url); $this->list = new AWeberEntry($data, $url, $this->adapter); diff --git a/tests/data/lists/page1.json b/tests/data/lists/page1.json index 9c3be4e..ff6b830 100644 --- a/tests/data/lists/page1.json +++ b/tests/data/lists/page1.json @@ -1 +1 @@ -{"total_size": 24, "start": 0, "resource_type_link": "https://api.aweber.com/1.0/#list-page-resource", "next_collection_link": "http://api.aweber.com/1.0/accounts/1/lists?ws.start=20&ws.size=20", "entries": [{"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533/campaigns", "name": "dailydrseuss1", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533/web_forms", "http_etag": "\"547d7402c7f528a2dbefeffa85eb973b13ed002f-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701533}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501/campaigns", "name": "default1701501", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501/web_forms", "http_etag": "\"710e976cbede7ee0befc9a78bbb079b67a1e8a22-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701501}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500/campaigns", "name": "default1701500", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500/web_forms", "http_etag": "\"9bb23b65ff2f1c755ba07691c8896114aea79303-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701500}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498/campaigns", "name": "default1701498", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498/web_forms", "http_etag": "\"e483a56588e762a709329a75f02b98ba25a744c0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701498}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497/campaigns", "name": "default1701497", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497/web_forms", "http_etag": "\"98fb0fa002a470133ef1cc2074064f25523f8351-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701497}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494/campaigns", "name": "default1701494", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494/web_forms", "http_etag": "\"2c1cd24fac1d6fbee9585007f16c3506ae0691be-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701494}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492/campaigns", "name": "default1701492", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492/web_forms", "http_etag": "\"15a50d4956d93ec26da11bf8411289c445b91b83-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701492}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491/campaigns", "name": "default1701491", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491/web_forms", "http_etag": "\"61a6028d19143623ccac12151640a84a21f20836-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701491}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489/campaigns", "name": "default1701489", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489/web_forms", "http_etag": "\"227bd84ee1763f3b46a3c37309a84b024a2c6c86-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701489}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487/campaigns", "name": "default1701487", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487/web_forms", "http_etag": "\"12edfe9548eaaf794d26606454f666f2525cce34-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701487}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486/campaigns", "name": "default1701486", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486/web_forms", "http_etag": "\"d8dca7c18825db31e24aa1ddaf51cdd8c6d74abd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701486}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482/campaigns", "name": "default1701482", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482/web_forms", "http_etag": "\"63a30a5a3b92aa45667efc7b7cba1df230883394-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701482}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/campaigns", "name": "test-stevee01", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/web_forms", "http_etag": "\"a27c0c9651a6309547835e18bb2920a44eb43ccc-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1694928}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832/campaigns", "name": "elong_api", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832/web_forms", "http_etag": "\"21e28bffb390cb82d069dd923cf99f5d9164b5fe-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1683832}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482/campaigns", "name": "default1673482", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482/web_forms", "http_etag": "\"10009452dfe8d4f6a77215a22d83735bdad5a5f6-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1673482}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018/campaigns", "name": "default1553018", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018/web_forms", "http_etag": "\"4ab41e60d14ea138a4522b3d2896942b7335c13c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1553018}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685/campaigns", "name": "default1550685", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685/web_forms", "http_etag": "\"685c00e3983add5e4efb5ca3bc7294e247f6e9fe-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1550685}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679/campaigns", "name": "default1550679", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679/web_forms", "http_etag": "\"0aaa38a50287df08ccb74c7f13fca8679aab688a-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1550679}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694/campaigns", "name": "default1482694", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694/web_forms", "http_etag": "\"fa5b88866c12617f4a74276b226bf8973a45cf73-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1482694}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/campaigns", "name": "jrodneyotest", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/web_forms", "http_etag": "\"e6edf11299299d16e7c848a3d42a52bba63daacd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1424745}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/campaigns", "name": "default1364473", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/web_forms", "http_etag": "\"dd77357a87c343b20234254438ae7094aeff2b3d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1364473}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/campaigns", "name": "tk-unlimited", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/web_forms", "http_etag": "\"cfd8bbcad976f5271368a5b3e646ea364efcd9e0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1211626}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/campaigns", "name": "devteamtest_2", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms", "http_etag": "\"d78abf7131f250f0929a6558f000b8760e76155b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 307014}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/campaigns", "name": "default1205629", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/web_forms", "http_etag": "\"f98f71baf8860d3522b4e88cb0acccabebaa9369-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1205629}]} +{"total_size": 24, "start": 0, "resource_type_link": "https://api.aweber.com/1.0/#list-page-resource", "next_collection_link": "https://api.aweber.com/1.0/accounts/1/lists?ws.start=20&ws.size=20", "entries": [{"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533/campaigns", "name": "dailydrseuss1", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533/web_forms", "http_etag": "\"547d7402c7f528a2dbefeffa85eb973b13ed002f-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701533", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701533}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501/campaigns", "name": "default1701501", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501/web_forms", "http_etag": "\"710e976cbede7ee0befc9a78bbb079b67a1e8a22-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701501", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701501}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500/campaigns", "name": "default1701500", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500/web_forms", "http_etag": "\"9bb23b65ff2f1c755ba07691c8896114aea79303-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701500", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701500}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498/campaigns", "name": "default1701498", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498/web_forms", "http_etag": "\"e483a56588e762a709329a75f02b98ba25a744c0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701498", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701498}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497/campaigns", "name": "default1701497", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497/web_forms", "http_etag": "\"98fb0fa002a470133ef1cc2074064f25523f8351-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701497", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701497}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494/campaigns", "name": "default1701494", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494/web_forms", "http_etag": "\"2c1cd24fac1d6fbee9585007f16c3506ae0691be-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701494", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701494}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492/campaigns", "name": "default1701492", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492/web_forms", "http_etag": "\"15a50d4956d93ec26da11bf8411289c445b91b83-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701492", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701492}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491/campaigns", "name": "default1701491", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491/web_forms", "http_etag": "\"61a6028d19143623ccac12151640a84a21f20836-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701491", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701491}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489/campaigns", "name": "default1701489", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489/web_forms", "http_etag": "\"227bd84ee1763f3b46a3c37309a84b024a2c6c86-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701489", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701489}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487/campaigns", "name": "default1701487", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487/web_forms", "http_etag": "\"12edfe9548eaaf794d26606454f666f2525cce34-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701487", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701487}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486/campaigns", "name": "default1701486", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486/web_forms", "http_etag": "\"d8dca7c18825db31e24aa1ddaf51cdd8c6d74abd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701486", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701486}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482/campaigns", "name": "default1701482", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482/web_forms", "http_etag": "\"63a30a5a3b92aa45667efc7b7cba1df230883394-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1701482", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1701482}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/campaigns", "name": "test-stevee01", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928/web_forms", "http_etag": "\"a27c0c9651a6309547835e18bb2920a44eb43ccc-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1694928", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1694928}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832/campaigns", "name": "elong_api", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832/web_forms", "http_etag": "\"21e28bffb390cb82d069dd923cf99f5d9164b5fe-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1683832", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1683832}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482/campaigns", "name": "default1673482", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482/web_forms", "http_etag": "\"10009452dfe8d4f6a77215a22d83735bdad5a5f6-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1673482", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1673482}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018/campaigns", "name": "default1553018", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018/web_forms", "http_etag": "\"4ab41e60d14ea138a4522b3d2896942b7335c13c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1553018", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1553018}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685/campaigns", "name": "default1550685", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685/web_forms", "http_etag": "\"685c00e3983add5e4efb5ca3bc7294e247f6e9fe-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1550685", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1550685}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679/campaigns", "name": "default1550679", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679/web_forms", "http_etag": "\"0aaa38a50287df08ccb74c7f13fca8679aab688a-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1550679", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1550679}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694/campaigns", "name": "default1482694", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694/web_forms", "http_etag": "\"fa5b88866c12617f4a74276b226bf8973a45cf73-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1482694", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1482694}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/campaigns", "name": "jrodneyotest", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745/web_forms", "http_etag": "\"e6edf11299299d16e7c848a3d42a52bba63daacd-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1424745", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1424745}]} diff --git a/tests/data/lists/page2.json b/tests/data/lists/page2.json index 5a4e9ce..26cd3ff 100644 --- a/tests/data/lists/page2.json +++ b/tests/data/lists/page2.json @@ -1 +1 @@ -{"total_size": 24, "prev_collection_link": "http://api.aweber.com/1.0/accounts/1/lists?ws.start=0&ws.size=20", "start": 20, "entries": [{"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/campaigns", "name": "default1364473", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/web_forms", "http_etag": "\"dd77357a87c343b20234254438ae7094aeff2b3d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1364473}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/campaigns", "name": "tk-unlimited", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/web_forms", "http_etag": "\"cfd8bbcad976f5271368a5b3e646ea364efcd9e0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1211626}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/campaigns", "name": "devteamtest_2", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms", "http_etag": "\"d78abf7131f250f0929a6558f000b8760e76155b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 307014}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/campaigns", "name": "default1205629", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/web_forms", "http_etag": "\"f98f71baf8860d3522b4e88cb0acccabebaa9369-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1205629}], "resource_type_link": "https://api.aweber.com/1.0/#list-page-resource"} +{"total_size": 24, "prev_collection_link": "https://api.aweber.com/1.0/accounts/1/lists?ws.start=0&ws.size=20", "start": 20, "entries": [{"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/campaigns", "name": "default1364473", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473/web_forms", "http_etag": "\"dd77357a87c343b20234254438ae7094aeff2b3d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1364473", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1364473}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/campaigns", "name": "tk-unlimited", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626/web_forms", "http_etag": "\"cfd8bbcad976f5271368a5b3e646ea364efcd9e0-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1211626", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1211626}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/campaigns", "name": "devteamtest_2", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/307014/web_forms", "http_etag": "\"d78abf7131f250f0929a6558f000b8760e76155b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/307014", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 307014}, {"campaigns_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/campaigns", "name": "default1205629", "web_form_split_tests_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/web_form_split_tests", "subscribers_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/subscribers", "web_forms_collection_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629/web_forms", "http_etag": "\"f98f71baf8860d3522b4e88cb0acccabebaa9369-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/1205629", "resource_type_link": "https://api.aweber.com/1.0/#list", "id": 1205629}], "resource_type_link": "https://api.aweber.com/1.0/#list-page-resource"} diff --git a/tests/data/lists/page3.json b/tests/data/lists/page3.json deleted file mode 100644 index fc113ef..0000000 --- a/tests/data/lists/page3.json +++ /dev/null @@ -1 +0,0 @@ -{"total_size": 24, "start": 0, "next_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists?ws.start=20&ws.size=20", "entries": [{"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251847/campaigns", "name": "default251847", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251847/subscribers", "id": 251847, "http_etag": "\"dac7041022b8d1b9690fbc0a34121a19c0461781-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251847", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251847/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251846/campaigns", "name": "default251846", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251846/subscribers", "id": 251846, "http_etag": "\"acefbf9202cfd5d156006591fa0222b7e4f735d2-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251846", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251846/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251845/campaigns", "name": "default251845", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251845/subscribers", "id": 251845, "http_etag": "\"a2845b27890ae073977798afe229933c00b6604a-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251845", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251845/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251843/campaigns", "name": "default251843", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251843/subscribers", "id": 251843, "http_etag": "\"80ef114161f2e417ce3da2a5ae0f45e1f9e2a17d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251843", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251843/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/312802/campaigns", "name": "anewtestlist", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/312802/subscribers", "id": 312802, "http_etag": "\"b4408834c0f13761cc2f4b90784e1faee5b8d084-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/312802", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/312802/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251848/campaigns", "name": "testmc", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251848/subscribers", "id": 251848, "http_etag": "\"be0d61f3d6cbf34819f74e994b1ffa2c96ed7bb3-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251848", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251848/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/303449/campaigns", "name": "default303449", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/303449/subscribers", "id": 303449, "http_etag": "\"5ba07c4b65dd1f6d245a7fd0dada5ea65b0f054d-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/303449", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/303449/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/305162/campaigns", "name": "herewego12", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/305162/subscribers", "id": 305162, "http_etag": "\"03a0ec4e9f52a0a1a99a8d4a83ef6587eed9a6b8-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/305162", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/305162/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/226186/campaigns", "name": "test-list777", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/226186/subscribers", "id": 226186, "http_etag": "\"e51bc0351083caca2a811a97937225605e80113c-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/226186", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/226186/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251844/campaigns", "name": "default251844", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251844/subscribers", "id": 251844, "http_etag": "\"fd2ed44b31f0b07b1c3e1d8cc094c152e83b2dc5-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251844", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/251844/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/1/campaigns", "name": "test-list2fff", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/1/subscribers", "id": 1, "http_etag": "\"a2e27930058f806c597e52b9f069284cff575588-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/1", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/1/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/301413/campaigns", "name": "test-list1d", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/301413/subscribers", "id": 301413, "http_etag": "\"6a4f25e78b120a99951beae31f3d9491f19d6719-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/301413", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/301413/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/320972/campaigns", "name": "superbenk", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/320972/subscribers", "id": 320972, "http_etag": "\"cd895b82944e86aefd492949d8b7d923d7d28778-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/320972", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/320972/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363010/campaigns", "name": "default363010", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363010/subscribers", "id": 363010, "http_etag": "\"4b095ec0243d40ab613096d8d3f96a609fdd27d5-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363010", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363010/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/307014/campaigns", "name": "devteamtest_2", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/307014/subscribers", "id": 307014, "http_etag": "\"d78abf7131f250f0929a6558f000b8760e76155b-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/307014", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/307014/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/305164/campaigns", "name": "homer_simpson", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/305164/subscribers", "id": 305164, "http_etag": "\"568306713e4d297e2f40948e63f240b1798fc3d8-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/305164", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/305164/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363013/campaigns", "name": "default363013", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363013/subscribers", "id": 363013, "http_etag": "\"4eee1ea48164b794be3891422d0ddbede8c26ecc-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363013", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363013/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363014/campaigns", "name": "default363014", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363014/subscribers", "id": 363014, "http_etag": "\"511a9e0afca20511da481093d1742ce1d3a791bf-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363014", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363014/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363009/campaigns", "name": "super", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363009/subscribers", "id": 363009, "http_etag": "\"570519a927e3bf6a13499bff4c10339ed8572216-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363009", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/363009/web_forms"}, {"campaigns_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/50000003/campaigns", "name": "default50000003", "subscribers_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/50000003/subscribers", "id": 50000003, "http_etag": "\"0f1b51f3c1fa3f61fe29a7783312371cc4f42149-ca5feee2b7fbb6febfca8af5541541ea960aaedb\"", "self_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/50000003", "resource_type_link": "http://api.apitest.lab:81/0.1/#list", "web_forms_collection_link": "http://api.apitest.lab:81/0.1/accounts/1/lists/50000003/web_forms"}], "resource_type_link" : "http://api.apitest.lab:81/0.1/#list-page-resource"} diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php index f3e8cd0..ce85b3d 100644 --- a/tests/mock_adapter.php +++ b/tests/mock_adapter.php @@ -1,60 +1,44 @@ array( - # the new way - '/accounts' => 'accounts/page1', - '/accounts/1' => 'accounts/1', - '/accounts/1?email=joe%40example.com&ws.op=findSubscribers' => 'accounts/findSubscribers', - '/accounts/1?email=joe%40example.com&ws.op=findSubscribers&ws.show=total_size' => 'accounts/findSubscribers_ts', - '/accounts/1?ws.op=getWebForms' => 'accounts/webForms', - '/accounts/1?ws.op=getWebFormSplitTests' => 'accounts/webFormSplitTests', - '/accounts/1/lists' => 'lists/page1', - '/accounts/1/lists?ws.size=20&ws.start=20' => 'lists/page2', - '/accounts/1/lists/303449' => 'lists/303449', - '/accounts/1/lists/505454' => 'lists/505454', - '/accounts/1/lists/303449/campaigns' => 'campaigns/303449', - '/accounts/1/lists/303449/custom_fields' => 'custom_fields/303449', - '/accounts/1/lists/303449/custom_fields/1' => 'custom_fields/1', - '/accounts/1/lists/303449/custom_fields/2' => 'custom_fields/2', - '/accounts/1/lists/303449/subscribers' => 'subscribers/page1', - '/accounts/1/lists/303449/subscribers/1' => 'subscribers/1', - '/accounts/1/lists/303449/subscribers/2' => 'subscribers/2', - '/accounts/1/lists/505454/subscribers/3' => 'subscribers/3', - '/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.op=find' => 'subscribers/find', - '/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.op=find&ws.show=total_size' => 'subscribers/find_tsl', - '/accounts/1/lists/303449/subscribers?email=nonexist%40example.com&ws.op=find' => 'subscribers/nonexist', - '/accounts/1/lists/303449/subscribers?email=nonexist%40example.com&ws.op=find&ws.show=total_size' => 'subscribers/nonexist_tsl', - ), - 'DELETE' => array( - '/accounts/1/lists/303449' => '200', - '/accounts/1' => '404', - ), - 'PATCH' => array( - '/accounts/1/lists/303449' => '209', - '/accounts/1/lists/303450' => '404', - '/accounts/1/lists/303449/subscribers/1' => '209', - ), - 'POST' => array( - '/accounts/1/lists/303449/custom_fields' => Array( - 'Status-Code' => '201', - 'Location' => '/accounts/1/lists/303449/custom_fields/2', - ), - '/accounts/1/lists/303449/subscribers/1' => Array( - 'Status-Code' => '201', - 'Location' => '/accounts/1/lists/505454/subscribers/3', - ), - '/accounts/1/lists/303449/subscribers/2' => Array( - 'Status-Code' => '400', - ), - ) - ); - public function addRequest($method, $uri, $data) { $this->requestsMade[] = array( 'method' => $method, @@ -66,29 +50,32 @@ public function clearRequests() { $this->requestsMade = array(); } - public function request($method, $uri, $data=array(), $options=array()) { + public function makeRequest($method, $url, $data=array()) { + global $map; + + # append params to url (for fixtures) + $uri = str_replace($this->app->baseUri, '', $url); if ($method == 'GET' && !empty($data)) { $uri = $uri.'?'. http_build_query($data); } + + # extract response map parameters + $status = $map[$method][$uri][0]; + $resource = $map[$method][$uri][1]; + + # record the request $this->addRequest($method, $uri, $data); - if (!empty($options['return'])) { - if ($options['return'] == 'status') { - return $this->requests[$method][$uri]; - } - if ($options['return'] == 'headers') { - return $this->requests[$method][$uri]; - } - } + # load response from fixture and return data + $mock_data = MockData::load($resource); + $headers = array(); + $headers['Status-Code'] = $status; - $data = MockData::load($this->requests[$method][$uri]); - if (empty($options['allow_empty']) && empty($data)) { - throw new AWeberResponseError($uri); + if($status == 201) { + $headers['Location'] = $resource; } - $this->parseAsError($data); - return $data; - } + $mock_data->headers = $headers; + return $mock_data; + } } - - diff --git a/tests/mock_data.php b/tests/mock_data.php index fcfc752..baaf50f 100644 --- a/tests/mock_data.php +++ b/tests/mock_data.php @@ -1,5 +1,13 @@ body = $data; + return $mock_data; } } diff --git a/tests/oauth_application.test.php b/tests/oauth_application.test.php index 0747da9..61c5482 100644 --- a/tests/oauth_application.test.php +++ b/tests/oauth_application.test.php @@ -3,7 +3,7 @@ class Object {} } -class OAuthAppliationTest extends UnitTestCase { +class TestOAuthAppliation extends UnitTestCase { public function setUp() { $this->oauth = new OAuthApplication($parentApp); From da4984a781a98b098d182cc1be5493cd86378fb2 Mon Sep 17 00:00:00 2001 From: "Edward F. Long, Jr" Date: Mon, 29 Aug 2011 12:22:24 -0400 Subject: [PATCH 018/112] renamed APIException to AWeberAPIException --- README | 10 ++++++---- aweber_api/exceptions.php | 2 +- aweber_api/oauth_application.php | 2 +- tests/aweber_entry.test.php | 6 +++--- tests/data/error.json | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/README b/README index fbaf957..fec70cc 100644 --- a/README +++ b/README @@ -6,8 +6,10 @@ PHP library for easily integrating with the AWeber API. Changelog: ---------- -2011-08-25: v1.1.0 - * Modified client library to raise an APIException on any API errors (HTTP status >= 400) +2011-08-29: v1.1.0 + * Modified client library to raise an AWeberAPIException on any API errors (HTTP status >= 400) + * Refactored tests for better code coverage + * Refactored move and create methods to return the resource or raise an AWeberAPIException on error. Basic Usage: @@ -21,7 +23,7 @@ https://labs.aweber.com/docs/php-library-walkthrough Handling Errors: ---------------- Sometimes errors happen and your application should handle them appropriately. -Whenever an API error occurs an APIException will be raised with a detailed +Whenever an API error occurs an AWeberAPIException will be raised with a detailed error message and documentation link to explain whats wrong. You should wrap any calls to the API in a try/except block. @@ -48,7 +50,7 @@ $account = $aweber->getAccount($accessKey, $accessSecret); try { $resource = $account->loadFromUrl('/accounts/idontexist'); -} catch (APIException $exc) { +} catch (AWeberAPIException $exc) { print "
    • $exc->type on $exc->url, refer to $exc->message for more info ...
      "; } diff --git a/aweber_api/exceptions.php b/aweber_api/exceptions.php index c556b6c..2b95232 100644 --- a/aweber_api/exceptions.php +++ b/aweber_api/exceptions.php @@ -10,7 +10,7 @@ class AWeberException extends Exception { } * @package * @version $id$ */ -class APIException extends AWeberException { +class AWeberAPIException extends AWeberException { public $type; public $status; diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index cd52b26..0c5f635 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -114,7 +114,7 @@ public function request($method, $uri, $data = array(), $options = array()) { if($response->headers['Status-Code'] >= 400) { $data = json_decode($response->body, true); - throw new APIException($data['error'], $url); + throw new AWeberAPIException($data['error'], $url); } if (!empty($options['return'])) { diff --git a/tests/aweber_entry.test.php b/tests/aweber_entry.test.php index 43e0c50..a80b1bd 100644 --- a/tests/aweber_entry.test.php +++ b/tests/aweber_entry.test.php @@ -120,7 +120,7 @@ public function testFailedDelete() { $data = $this->adapter->request('GET', $url); $entry = new AWeberEntry($data, $url, $this->adapter); - $this->expectException(APIException, "SimulatedException"); + $this->expectException(AWeberAPIException, "SimulatedException"); $entry->delete(); } @@ -157,7 +157,7 @@ public function testSaveFailed() { $data = $this->adapter->request('GET', $url); $entry = new AWeberEntry($data, $url, $this->adapter); $entry->name = 'foobarbaz'; - $this->expectException(APIException, "SimulatedException"); + $this->expectException(AWeberAPIException, "SimulatedException"); $resp = $entry->save(); } @@ -372,7 +372,7 @@ public function testMove_Success() { public function testMove_Failure() { $this->adapter->clearRequests(); - $this->expectException(APIException, "SimulatedException"); + $this->expectException(AWeberAPIException, "SimulatedException"); $this->unsubscribed->move($this->different_list); $this->assertEqual(sizeOf($this->adapter->requestsMade), 1); diff --git a/tests/data/error.json b/tests/data/error.json index 623bc5f..2d48c22 100644 --- a/tests/data/error.json +++ b/tests/data/error.json @@ -1 +1 @@ -{"error": {"message": "Simulated Exception", "type": "BadRequestError"}} +{"error": {"message": "Simulated Exception", "type": "BadRequestError", "documentation_url": "https://labs.aweber.com/docs/troubleshooting#badrequesterror"}} From c97e169894bf4d77607d5e1e932e1f074e7477f4 Mon Sep 17 00:00:00 2001 From: "Edward F. Long, Jr" Date: Mon, 29 Aug 2011 12:44:31 -0400 Subject: [PATCH 019/112] added getActivity method to the Subscriber Entry. --- README | 2 +- aweber_api/aweber_entry.php | 21 +++++++++++++++++++++ tests/aweber_entry.test.php | 6 ++++++ tests/data/subscribers/activity.json | 1 + tests/data/subscribers/activity_ts.json | 1 + tests/mock_adapter.php | 2 ++ 6 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/data/subscribers/activity.json create mode 100644 tests/data/subscribers/activity_ts.json diff --git a/README b/README index fec70cc..aaf7f1b 100644 --- a/README +++ b/README @@ -10,7 +10,7 @@ Changelog: * Modified client library to raise an AWeberAPIException on any API errors (HTTP status >= 400) * Refactored tests for better code coverage * Refactored move and create methods to return the resource or raise an AWeberAPIException on error. - + * added getActivity method to a subscriber entry. Basic Usage: ------------ diff --git a/aweber_api/aweber_entry.php b/aweber_api/aweber_entry.php index f3d3db9..580fa0e 100644 --- a/aweber_api/aweber_entry.php +++ b/aweber_api/aweber_entry.php @@ -189,6 +189,27 @@ public function findSubscribers($search_data) { return new AWeberCollection($data, $url, $this->adapter); } + /** + * getActivity + * + * Returns analytics activity for a given subscriber + * @access public + * @return AWeberCollection + */ + public function getActivity() { + $this->_methodFor(array('subscriber')); + $params = array('ws.op' => 'getActivity'); + $data = $this->adapter->request('GET', $this->url, $params); + + $ts_params = array_merge($params, array('ws.show' => 'total_size')); + $total_size = $this->adapter->request('GET', $this->url, $ts_params, array('return' => 'integer')); + + # return collection + $data['total_size'] = $total_size; + $url = $this->url . '?'. http_build_query($params); + return new AWeberCollection($data, $url, $this->adapter); + } + /** getParentEntry * * Gets an entry's parent entry diff --git a/tests/aweber_entry.test.php b/tests/aweber_entry.test.php index a80b1bd..be77ea2 100644 --- a/tests/aweber_entry.test.php +++ b/tests/aweber_entry.test.php @@ -322,6 +322,12 @@ public function testShouldBeUpdatable() { $data = $this->adapter->requestsMade[0]['data']; $this->assertEqual($data['custom_fields']['Color'], 'Jeep'); } + + public function testShouldSupportGetActivity() { + $activity = $this->entry->getActivity(); + $this->assertTrue(is_a($activity, 'AWeberCollection')); + $this->assertEqual($activity->total_size, 1); + } } class TestAWeberMoveEntry extends UnitTestCase { diff --git a/tests/data/subscribers/activity.json b/tests/data/subscribers/activity.json new file mode 100644 index 0000000..2b70602 --- /dev/null +++ b/tests/data/subscribers/activity.json @@ -0,0 +1 @@ +{"start": 0, "total_size_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/1?ws.op=getActivity&ws.op=total_size", "entries": [{"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 52629234, "custom_fields": {"NewCustomField": "really awesome", "YourCustomField": "NewValue"}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/496562/campaigns/f3548399", "city": "Fairport", "http_etag": "\"223a06015fdd0daaef1b561aee4f10176513e346-075619e34cfd24154382b5a53939132945e96ce3\"", "ad_tracking": "control panel", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2011-03-02 14:47:22.797206-05:00", "misc_notes": "", "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/1", "is_verified": true, "email": "joe@example.com", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "unsubscribe_method": null, "ip_address": "192.168.10.10", "name": "Joe User", "subscription_method": "signup form", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2011-02-15 13:37:23", "subscribed_at": "2011-02-15 13:27:28-05:00", "country": "United States"}]} diff --git a/tests/data/subscribers/activity_ts.json b/tests/data/subscribers/activity_ts.json new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/data/subscribers/activity_ts.json @@ -0,0 +1 @@ +1 diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php index ce85b3d..47849db 100644 --- a/tests/mock_adapter.php +++ b/tests/mock_adapter.php @@ -14,6 +14,8 @@ $map['GET' ]['/accounts/1/lists/303449/custom_fields/2' ] = array(200, 'custom_fields/2'); $map['GET' ]['/accounts/1/lists/303449/subscribers' ] = array(200, 'subscribers/page1'); $map['GET' ]['/accounts/1/lists/303449/subscribers/1' ] = array(200, 'subscribers/1'); +$map['GET' ]['/accounts/1/lists/303449/subscribers/1?ws.op=getActivity' ] = array(200, 'subscribers/activity'); +$map['GET' ]['/accounts/1/lists/303449/subscribers/1?ws.op=getActivity&ws.show=total_size' ] = array(200, 'subscribers/activity_ts'); $map['GET' ]['/accounts/1/lists/303449/subscribers/2' ] = array(200, 'subscribers/2'); $map['GET' ]['/accounts/1/lists/303449/subscribers?email=nonexist%40example.com&ws.op=find&ws.show=total_size'] = array(200, 'subscribers/nonexist_tsl'); $map['GET' ]['/accounts/1/lists/303449/subscribers?email=nonexist%40example.com&ws.op=find' ] = array(200, 'subscribers/nonexist'); From 67f6fe599c8742c00fcf8cb911e437fadfa0abda Mon Sep 17 00:00:00 2001 From: "Edward F. Long, Jr" Date: Mon, 29 Aug 2011 15:42:13 -0400 Subject: [PATCH 020/112] code review changes. --- README | 4 ++-- aweber_api/aweber_collection.php | 1 + aweber_api/exceptions.php | 3 +-- tests/aweber_api.test.php | 7 ------- tests/aweber_entry.test.php | 6 ------ tests/mock_adapter.php | 10 +++++++++- 6 files changed, 13 insertions(+), 18 deletions(-) diff --git a/README b/README index aaf7f1b..3852537 100644 --- a/README +++ b/README @@ -10,7 +10,7 @@ Changelog: * Modified client library to raise an AWeberAPIException on any API errors (HTTP status >= 400) * Refactored tests for better code coverage * Refactored move and create methods to return the resource or raise an AWeberAPIException on error. - * added getActivity method to a subscriber entry. + * Added getActivity method to a subscriber entry. Basic Usage: ------------ @@ -24,7 +24,7 @@ Handling Errors: ---------------- Sometimes errors happen and your application should handle them appropriately. Whenever an API error occurs an AWeberAPIException will be raised with a detailed -error message and documentation link to explain whats wrong. +error message and documentation link to explain what's wrong. You should wrap any calls to the API in a try/except block. diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index 63d3ddd..171fdf5 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -46,6 +46,7 @@ public function create($kv_pairs) { # Create Resource $params = array_merge(array('ws.op' => 'create'), $kv_pairs); $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers')); + $this->_entries = array(); # Return new Resource $url = $data['Location']; diff --git a/aweber_api/exceptions.php b/aweber_api/exceptions.php index 2b95232..96acb41 100644 --- a/aweber_api/exceptions.php +++ b/aweber_api/exceptions.php @@ -18,8 +18,7 @@ class AWeberAPIException extends AWeberException { public $documentation_url; public $url; - public function __construct($error, $url) { #type, $status, $message, $documentation_url) { - + public function __construct($error, $url) { // record specific details of the API exception for processing $this->url = $url; $this->type = $error['type']; diff --git a/tests/aweber_api.test.php b/tests/aweber_api.test.php index 9543501..f85a394 100644 --- a/tests/aweber_api.test.php +++ b/tests/aweber_api.test.php @@ -1,12 +1,5 @@ Date: Thu, 8 Sep 2011 10:56:38 -0400 Subject: [PATCH 021/112] added automatic json serialization to GET and POST data when arrays are passed. --- aweber_api/oauth_application.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 0c5f635..37215de 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -106,6 +106,16 @@ public function __construct($parentApp = false) { public function request($method, $uri, $data = array(), $options = array()) { $uri = $this->app->removeBaseUri($uri); $url = $this->app->getBaseUri() . $uri; + + # WARNING: non-primative items in data must be json serialized. + if ($method == 'POST' or $method == 'GET') { + foreach ($data as $key => $value) { + if (is_array($value)) { + $data[$key] = json_encode($value); + } + } + } + $response = $this->makeRequest($method, $url, $data); if (!$response) { From c6c59df52d680b96cad826e9b7431ac08f1bfa13 Mon Sep 17 00:00:00 2001 From: Boris Valerstein Date: Tue, 27 Sep 2011 11:25:02 -0400 Subject: [PATCH 022/112] Added duplicate client library check --- aweber_api/aweber.php | 292 ++++++++++++++++++++++++++++++++++++++ aweber_api/aweber_api.php | 292 +------------------------------------- 2 files changed, 296 insertions(+), 288 deletions(-) create mode 100644 aweber_api/aweber.php diff --git a/aweber_api/aweber.php b/aweber_api/aweber.php new file mode 100644 index 0000000..385dea7 --- /dev/null +++ b/aweber_api/aweber.php @@ -0,0 +1,292 @@ +baseUri; + } + + public function removeBaseUri($url) { + return str_replace($this->getBaseUri(), '', $url); + } + + public function getAccessTokenUrl() { + return $this->accessTokenUrl; + } + + public function getAuthorizeUrl() { + return $this->authorizeUrl; + } + + public function getRequestTokenUrl() { + return $this->requestTokenUrl; + } + + public function getAuthTokenFromUrl() { return ''; } + public function getUserData() { return ''; } + +} + +/** + * AWeberAPIBase + * + * Base object that all AWeberAPI objects inherit from. Allows specific pieces + * of functionality to be shared across any object in the API, such as the + * ability to introspect the collections map. + * + * @package + * @version $id$ + */ +class AWeberAPIBase { + + /** + * Maintains data about what children collections a given object type + * contains. + */ + static protected $_collectionMap = array( + 'account' => array('lists', 'integrations'), + 'broadcast_campaign' => array('links', 'messages'), + 'followup_campaign' => array('links', 'messages'), + 'link' => array('clicks'), + 'list' => array('campaigns', 'custom_fields', 'subscribers', + 'web_forms', 'web_form_split_tests'), + 'web_form' => array(), + 'web_form_split_test' => array('components'), + ); + + /** + * loadFromUrl + * + * Creates an object, either collection or entry, based on the given + * URL. + * + * @param mixed $url URL for this request + * @access public + * @return AWeberEntry or AWeberCollection + */ + public function loadFromUrl($url) { + $data = $this->adapter->request('GET', $url); + return $this->readResponse($data, $url); + } + + protected function _cleanUrl($url) { + return str_replace($this->adapter->app->getBaseUri(), '', $url); + } + + /** + * readResponse + * + * Interprets a response, and creates the appropriate object from it. + * @param mixed $response Data returned from a request to the AWeberAPI + * @param mixed $url URL that this data was requested from + * @access protected + * @return mixed + */ + protected function readResponse($response, $url) { + $this->adapter->parseAsError($response); + if (!empty($response['id'])) { + return new AWeberEntry($response, $url, $this->adapter); + } else if (isset($response['entries'])) { + return new AWeberCollection($response, $url, $this->adapter); + } + return false; + } +} + +/** + * AWeberAPI + * + * Creates a connection to the AWeberAPI for a given consumer application. + * This is generally the starting point for this library. Instances can be + * created directly with consumerKey and consumerSecret. + * @uses AWeberAPIBase + * @package + * @version $id$ + */ +class AWeberAPI extends AWeberAPIBase { + + /** + * @var String Consumer Key + */ + public $consumerKey = false; + + /** + * @var String Consumer Secret + */ + public $consumerSecret = false; + + /** + * @var Object - Populated in setAdapter() + */ + public $adapter = false; + + /** + * Uses the app's authorization code to fetch an access token + * + * @param String Authorization code from authorize app page + */ + public static function getDataFromAweberID($string) { + list($consumerKey, $consumerSecret, $requestToken, $tokenSecret, $verifier) = AWeberAPI::_parseAweberID($string); + + if (!$verifier) { + return null; + } + $aweber = new AweberAPI($consumerKey, $consumerSecret); + $aweber->adapter->user->requestToken = $requestToken; + $aweber->adapter->user->tokenSecret = $tokenSecret; + $aweber->adapter->user->verifier = $verifier; + list($accessToken, $accessSecret) = $aweber->getAccessToken(); + return array($consumerKey, $consumerSecret, $accessToken, $accessSecret); + } + + protected static function _parseAWeberID($string) { + $values = split('\|', $string); + if (count($values) < 5) { + return null; + } + return array_slice($values, 0, 5); + } + + /** + * Sets the consumer key and secret for the API object. The + * key and secret are listed in the My Apps page in the labs.aweber.com + * Control Panel OR, in the case of distributed apps, will be returned + * from the getDataFromAweberID() function + * + * @param String Consumer Key + * @param String Consumer Secret + * @return null + */ + public function __construct($key, $secret) { + // Load key / secret + $this->consumerKey = $key; + $this->consumerSecret = $secret; + + $this->setAdapter(); + } + + /** + * Returns the authorize URL by appending the request + * token to the end of the Authorize URI, if it exists + * + * @return string The Authorization URL + */ + public function getAuthorizeUrl() { + $requestToken = $this->user->requestToken; + return (empty($requestToken)) ? + $this->adapter->app->getAuthorizeUrl() + : + $this->adapter->app->getAuthorizeUrl() . "?oauth_token={$this->user->requestToken}"; + } + + /** + * Sets the adapter for use with the API + */ + public function setAdapter($adapter=null) { + if (empty($adapter)) { + $serviceProvider = new AWeberServiceProvider(); + $adapter = new OAuthApplication($serviceProvider); + $adapter->consumerKey = $this->consumerKey; + $adapter->consumerSecret = $this->consumerSecret; + } + $this->adapter = $adapter; + } + + /** + * Fetches account data for the associated account + * + * @param String Access Token (Only optional/cached if you called getAccessToken() earlier + * on the same page) + * @param String Access Token Secret (Only optional/cached if you called getAccessToken() earlier + * on the same page) + * @return Object AWeberCollection Object with the requested + * account data + */ + public function getAccount($token=false, $secret=false) { + if ($token && $secret) { + $user = new OAuthUser(); + $user->accessToken = $token; + $user->tokenSecret = $secret; + $this->adapter->user = $user; + } + + $body = $this->adapter->request('GET', '/accounts'); + $accounts = $this->readResponse($body, '/accounts'); + return $accounts[0]; + } + + /** + * PHP Automagic + */ + public function __get($item) { + if ($item == 'user') return $this->adapter->user; + trigger_error("Could not find \"{$item}\""); + } + + /** + * Request a request token from AWeber and associate the + * provided $callbackUrl with the new token + * @param String The URL where users should be redirected + * once they authorize your app + * @return Array Contains the request token as the first item + * and the request token secret as the second item of the array + */ + public function getRequestToken($callbackUrl) { + $requestToken = $this->adapter->getRequestToken($callbackUrl); + return array($requestToken, $this->user->tokenSecret); + } + + /** + * Request an access token using the request tokens stored in the + * current user object. You would want to first set the request tokens + * on the user before calling this function via: + * + * $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; + * $aweber->user->requestToken = $_GET['oauth_token']; + * $aweber->user->verifier = $_GET['oauth_verifier']; + * + * @return Array Contains the access token as the first item + * and the access token secret as the second item of the array + */ + public function getAccessToken() { + return $this->adapter->getAccessToken(); + } +} + +?> diff --git a/aweber_api/aweber_api.php b/aweber_api/aweber_api.php index 385dea7..201de64 100644 --- a/aweber_api/aweber_api.php +++ b/aweber_api/aweber_api.php @@ -1,292 +1,8 @@ baseUri; - } - - public function removeBaseUri($url) { - return str_replace($this->getBaseUri(), '', $url); - } - - public function getAccessTokenUrl() { - return $this->accessTokenUrl; - } - - public function getAuthorizeUrl() { - return $this->authorizeUrl; - } - - public function getRequestTokenUrl() { - return $this->requestTokenUrl; - } - - public function getAuthTokenFromUrl() { return ''; } - public function getUserData() { return ''; } +if (class_exists('AWeberAPI')) { + trigger_error("Duplicate: Another AWeberAPI client library is already in scope.", E_USER_WARNING); } - -/** - * AWeberAPIBase - * - * Base object that all AWeberAPI objects inherit from. Allows specific pieces - * of functionality to be shared across any object in the API, such as the - * ability to introspect the collections map. - * - * @package - * @version $id$ - */ -class AWeberAPIBase { - - /** - * Maintains data about what children collections a given object type - * contains. - */ - static protected $_collectionMap = array( - 'account' => array('lists', 'integrations'), - 'broadcast_campaign' => array('links', 'messages'), - 'followup_campaign' => array('links', 'messages'), - 'link' => array('clicks'), - 'list' => array('campaigns', 'custom_fields', 'subscribers', - 'web_forms', 'web_form_split_tests'), - 'web_form' => array(), - 'web_form_split_test' => array('components'), - ); - - /** - * loadFromUrl - * - * Creates an object, either collection or entry, based on the given - * URL. - * - * @param mixed $url URL for this request - * @access public - * @return AWeberEntry or AWeberCollection - */ - public function loadFromUrl($url) { - $data = $this->adapter->request('GET', $url); - return $this->readResponse($data, $url); - } - - protected function _cleanUrl($url) { - return str_replace($this->adapter->app->getBaseUri(), '', $url); - } - - /** - * readResponse - * - * Interprets a response, and creates the appropriate object from it. - * @param mixed $response Data returned from a request to the AWeberAPI - * @param mixed $url URL that this data was requested from - * @access protected - * @return mixed - */ - protected function readResponse($response, $url) { - $this->adapter->parseAsError($response); - if (!empty($response['id'])) { - return new AWeberEntry($response, $url, $this->adapter); - } else if (isset($response['entries'])) { - return new AWeberCollection($response, $url, $this->adapter); - } - return false; - } +else { + require_once('aweber.php'); } - -/** - * AWeberAPI - * - * Creates a connection to the AWeberAPI for a given consumer application. - * This is generally the starting point for this library. Instances can be - * created directly with consumerKey and consumerSecret. - * @uses AWeberAPIBase - * @package - * @version $id$ - */ -class AWeberAPI extends AWeberAPIBase { - - /** - * @var String Consumer Key - */ - public $consumerKey = false; - - /** - * @var String Consumer Secret - */ - public $consumerSecret = false; - - /** - * @var Object - Populated in setAdapter() - */ - public $adapter = false; - - /** - * Uses the app's authorization code to fetch an access token - * - * @param String Authorization code from authorize app page - */ - public static function getDataFromAweberID($string) { - list($consumerKey, $consumerSecret, $requestToken, $tokenSecret, $verifier) = AWeberAPI::_parseAweberID($string); - - if (!$verifier) { - return null; - } - $aweber = new AweberAPI($consumerKey, $consumerSecret); - $aweber->adapter->user->requestToken = $requestToken; - $aweber->adapter->user->tokenSecret = $tokenSecret; - $aweber->adapter->user->verifier = $verifier; - list($accessToken, $accessSecret) = $aweber->getAccessToken(); - return array($consumerKey, $consumerSecret, $accessToken, $accessSecret); - } - - protected static function _parseAWeberID($string) { - $values = split('\|', $string); - if (count($values) < 5) { - return null; - } - return array_slice($values, 0, 5); - } - - /** - * Sets the consumer key and secret for the API object. The - * key and secret are listed in the My Apps page in the labs.aweber.com - * Control Panel OR, in the case of distributed apps, will be returned - * from the getDataFromAweberID() function - * - * @param String Consumer Key - * @param String Consumer Secret - * @return null - */ - public function __construct($key, $secret) { - // Load key / secret - $this->consumerKey = $key; - $this->consumerSecret = $secret; - - $this->setAdapter(); - } - - /** - * Returns the authorize URL by appending the request - * token to the end of the Authorize URI, if it exists - * - * @return string The Authorization URL - */ - public function getAuthorizeUrl() { - $requestToken = $this->user->requestToken; - return (empty($requestToken)) ? - $this->adapter->app->getAuthorizeUrl() - : - $this->adapter->app->getAuthorizeUrl() . "?oauth_token={$this->user->requestToken}"; - } - - /** - * Sets the adapter for use with the API - */ - public function setAdapter($adapter=null) { - if (empty($adapter)) { - $serviceProvider = new AWeberServiceProvider(); - $adapter = new OAuthApplication($serviceProvider); - $adapter->consumerKey = $this->consumerKey; - $adapter->consumerSecret = $this->consumerSecret; - } - $this->adapter = $adapter; - } - - /** - * Fetches account data for the associated account - * - * @param String Access Token (Only optional/cached if you called getAccessToken() earlier - * on the same page) - * @param String Access Token Secret (Only optional/cached if you called getAccessToken() earlier - * on the same page) - * @return Object AWeberCollection Object with the requested - * account data - */ - public function getAccount($token=false, $secret=false) { - if ($token && $secret) { - $user = new OAuthUser(); - $user->accessToken = $token; - $user->tokenSecret = $secret; - $this->adapter->user = $user; - } - - $body = $this->adapter->request('GET', '/accounts'); - $accounts = $this->readResponse($body, '/accounts'); - return $accounts[0]; - } - - /** - * PHP Automagic - */ - public function __get($item) { - if ($item == 'user') return $this->adapter->user; - trigger_error("Could not find \"{$item}\""); - } - - /** - * Request a request token from AWeber and associate the - * provided $callbackUrl with the new token - * @param String The URL where users should be redirected - * once they authorize your app - * @return Array Contains the request token as the first item - * and the request token secret as the second item of the array - */ - public function getRequestToken($callbackUrl) { - $requestToken = $this->adapter->getRequestToken($callbackUrl); - return array($requestToken, $this->user->tokenSecret); - } - - /** - * Request an access token using the request tokens stored in the - * current user object. You would want to first set the request tokens - * on the user before calling this function via: - * - * $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; - * $aweber->user->requestToken = $_GET['oauth_token']; - * $aweber->user->verifier = $_GET['oauth_verifier']; - * - * @return Array Contains the access token as the first item - * and the access token secret as the second item of the array - */ - public function getAccessToken() { - return $this->adapter->getAccessToken(); - } -} - -?> From 205f7332f31cfc302aeebfeefdc4240ec44addc0 Mon Sep 17 00:00:00 2001 From: Boris Valerstein Date: Tue, 27 Sep 2011 11:27:50 -0400 Subject: [PATCH 023/112] Revert "Added duplicate client library check" This reverts commit c6c59df52d680b96cad826e9b7431ac08f1bfa13. --- aweber_api/aweber.php | 292 -------------------------------------- aweber_api/aweber_api.php | 292 +++++++++++++++++++++++++++++++++++++- 2 files changed, 288 insertions(+), 296 deletions(-) delete mode 100644 aweber_api/aweber.php diff --git a/aweber_api/aweber.php b/aweber_api/aweber.php deleted file mode 100644 index 385dea7..0000000 --- a/aweber_api/aweber.php +++ /dev/null @@ -1,292 +0,0 @@ -baseUri; - } - - public function removeBaseUri($url) { - return str_replace($this->getBaseUri(), '', $url); - } - - public function getAccessTokenUrl() { - return $this->accessTokenUrl; - } - - public function getAuthorizeUrl() { - return $this->authorizeUrl; - } - - public function getRequestTokenUrl() { - return $this->requestTokenUrl; - } - - public function getAuthTokenFromUrl() { return ''; } - public function getUserData() { return ''; } - -} - -/** - * AWeberAPIBase - * - * Base object that all AWeberAPI objects inherit from. Allows specific pieces - * of functionality to be shared across any object in the API, such as the - * ability to introspect the collections map. - * - * @package - * @version $id$ - */ -class AWeberAPIBase { - - /** - * Maintains data about what children collections a given object type - * contains. - */ - static protected $_collectionMap = array( - 'account' => array('lists', 'integrations'), - 'broadcast_campaign' => array('links', 'messages'), - 'followup_campaign' => array('links', 'messages'), - 'link' => array('clicks'), - 'list' => array('campaigns', 'custom_fields', 'subscribers', - 'web_forms', 'web_form_split_tests'), - 'web_form' => array(), - 'web_form_split_test' => array('components'), - ); - - /** - * loadFromUrl - * - * Creates an object, either collection or entry, based on the given - * URL. - * - * @param mixed $url URL for this request - * @access public - * @return AWeberEntry or AWeberCollection - */ - public function loadFromUrl($url) { - $data = $this->adapter->request('GET', $url); - return $this->readResponse($data, $url); - } - - protected function _cleanUrl($url) { - return str_replace($this->adapter->app->getBaseUri(), '', $url); - } - - /** - * readResponse - * - * Interprets a response, and creates the appropriate object from it. - * @param mixed $response Data returned from a request to the AWeberAPI - * @param mixed $url URL that this data was requested from - * @access protected - * @return mixed - */ - protected function readResponse($response, $url) { - $this->adapter->parseAsError($response); - if (!empty($response['id'])) { - return new AWeberEntry($response, $url, $this->adapter); - } else if (isset($response['entries'])) { - return new AWeberCollection($response, $url, $this->adapter); - } - return false; - } -} - -/** - * AWeberAPI - * - * Creates a connection to the AWeberAPI for a given consumer application. - * This is generally the starting point for this library. Instances can be - * created directly with consumerKey and consumerSecret. - * @uses AWeberAPIBase - * @package - * @version $id$ - */ -class AWeberAPI extends AWeberAPIBase { - - /** - * @var String Consumer Key - */ - public $consumerKey = false; - - /** - * @var String Consumer Secret - */ - public $consumerSecret = false; - - /** - * @var Object - Populated in setAdapter() - */ - public $adapter = false; - - /** - * Uses the app's authorization code to fetch an access token - * - * @param String Authorization code from authorize app page - */ - public static function getDataFromAweberID($string) { - list($consumerKey, $consumerSecret, $requestToken, $tokenSecret, $verifier) = AWeberAPI::_parseAweberID($string); - - if (!$verifier) { - return null; - } - $aweber = new AweberAPI($consumerKey, $consumerSecret); - $aweber->adapter->user->requestToken = $requestToken; - $aweber->adapter->user->tokenSecret = $tokenSecret; - $aweber->adapter->user->verifier = $verifier; - list($accessToken, $accessSecret) = $aweber->getAccessToken(); - return array($consumerKey, $consumerSecret, $accessToken, $accessSecret); - } - - protected static function _parseAWeberID($string) { - $values = split('\|', $string); - if (count($values) < 5) { - return null; - } - return array_slice($values, 0, 5); - } - - /** - * Sets the consumer key and secret for the API object. The - * key and secret are listed in the My Apps page in the labs.aweber.com - * Control Panel OR, in the case of distributed apps, will be returned - * from the getDataFromAweberID() function - * - * @param String Consumer Key - * @param String Consumer Secret - * @return null - */ - public function __construct($key, $secret) { - // Load key / secret - $this->consumerKey = $key; - $this->consumerSecret = $secret; - - $this->setAdapter(); - } - - /** - * Returns the authorize URL by appending the request - * token to the end of the Authorize URI, if it exists - * - * @return string The Authorization URL - */ - public function getAuthorizeUrl() { - $requestToken = $this->user->requestToken; - return (empty($requestToken)) ? - $this->adapter->app->getAuthorizeUrl() - : - $this->adapter->app->getAuthorizeUrl() . "?oauth_token={$this->user->requestToken}"; - } - - /** - * Sets the adapter for use with the API - */ - public function setAdapter($adapter=null) { - if (empty($adapter)) { - $serviceProvider = new AWeberServiceProvider(); - $adapter = new OAuthApplication($serviceProvider); - $adapter->consumerKey = $this->consumerKey; - $adapter->consumerSecret = $this->consumerSecret; - } - $this->adapter = $adapter; - } - - /** - * Fetches account data for the associated account - * - * @param String Access Token (Only optional/cached if you called getAccessToken() earlier - * on the same page) - * @param String Access Token Secret (Only optional/cached if you called getAccessToken() earlier - * on the same page) - * @return Object AWeberCollection Object with the requested - * account data - */ - public function getAccount($token=false, $secret=false) { - if ($token && $secret) { - $user = new OAuthUser(); - $user->accessToken = $token; - $user->tokenSecret = $secret; - $this->adapter->user = $user; - } - - $body = $this->adapter->request('GET', '/accounts'); - $accounts = $this->readResponse($body, '/accounts'); - return $accounts[0]; - } - - /** - * PHP Automagic - */ - public function __get($item) { - if ($item == 'user') return $this->adapter->user; - trigger_error("Could not find \"{$item}\""); - } - - /** - * Request a request token from AWeber and associate the - * provided $callbackUrl with the new token - * @param String The URL where users should be redirected - * once they authorize your app - * @return Array Contains the request token as the first item - * and the request token secret as the second item of the array - */ - public function getRequestToken($callbackUrl) { - $requestToken = $this->adapter->getRequestToken($callbackUrl); - return array($requestToken, $this->user->tokenSecret); - } - - /** - * Request an access token using the request tokens stored in the - * current user object. You would want to first set the request tokens - * on the user before calling this function via: - * - * $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; - * $aweber->user->requestToken = $_GET['oauth_token']; - * $aweber->user->verifier = $_GET['oauth_verifier']; - * - * @return Array Contains the access token as the first item - * and the access token secret as the second item of the array - */ - public function getAccessToken() { - return $this->adapter->getAccessToken(); - } -} - -?> diff --git a/aweber_api/aweber_api.php b/aweber_api/aweber_api.php index 201de64..385dea7 100644 --- a/aweber_api/aweber_api.php +++ b/aweber_api/aweber_api.php @@ -1,8 +1,292 @@ baseUri; + } + + public function removeBaseUri($url) { + return str_replace($this->getBaseUri(), '', $url); + } + + public function getAccessTokenUrl() { + return $this->accessTokenUrl; + } + + public function getAuthorizeUrl() { + return $this->authorizeUrl; + } + + public function getRequestTokenUrl() { + return $this->requestTokenUrl; + } + + public function getAuthTokenFromUrl() { return ''; } + public function getUserData() { return ''; } -if (class_exists('AWeberAPI')) { - trigger_error("Duplicate: Another AWeberAPI client library is already in scope.", E_USER_WARNING); } -else { - require_once('aweber.php'); + +/** + * AWeberAPIBase + * + * Base object that all AWeberAPI objects inherit from. Allows specific pieces + * of functionality to be shared across any object in the API, such as the + * ability to introspect the collections map. + * + * @package + * @version $id$ + */ +class AWeberAPIBase { + + /** + * Maintains data about what children collections a given object type + * contains. + */ + static protected $_collectionMap = array( + 'account' => array('lists', 'integrations'), + 'broadcast_campaign' => array('links', 'messages'), + 'followup_campaign' => array('links', 'messages'), + 'link' => array('clicks'), + 'list' => array('campaigns', 'custom_fields', 'subscribers', + 'web_forms', 'web_form_split_tests'), + 'web_form' => array(), + 'web_form_split_test' => array('components'), + ); + + /** + * loadFromUrl + * + * Creates an object, either collection or entry, based on the given + * URL. + * + * @param mixed $url URL for this request + * @access public + * @return AWeberEntry or AWeberCollection + */ + public function loadFromUrl($url) { + $data = $this->adapter->request('GET', $url); + return $this->readResponse($data, $url); + } + + protected function _cleanUrl($url) { + return str_replace($this->adapter->app->getBaseUri(), '', $url); + } + + /** + * readResponse + * + * Interprets a response, and creates the appropriate object from it. + * @param mixed $response Data returned from a request to the AWeberAPI + * @param mixed $url URL that this data was requested from + * @access protected + * @return mixed + */ + protected function readResponse($response, $url) { + $this->adapter->parseAsError($response); + if (!empty($response['id'])) { + return new AWeberEntry($response, $url, $this->adapter); + } else if (isset($response['entries'])) { + return new AWeberCollection($response, $url, $this->adapter); + } + return false; + } } + +/** + * AWeberAPI + * + * Creates a connection to the AWeberAPI for a given consumer application. + * This is generally the starting point for this library. Instances can be + * created directly with consumerKey and consumerSecret. + * @uses AWeberAPIBase + * @package + * @version $id$ + */ +class AWeberAPI extends AWeberAPIBase { + + /** + * @var String Consumer Key + */ + public $consumerKey = false; + + /** + * @var String Consumer Secret + */ + public $consumerSecret = false; + + /** + * @var Object - Populated in setAdapter() + */ + public $adapter = false; + + /** + * Uses the app's authorization code to fetch an access token + * + * @param String Authorization code from authorize app page + */ + public static function getDataFromAweberID($string) { + list($consumerKey, $consumerSecret, $requestToken, $tokenSecret, $verifier) = AWeberAPI::_parseAweberID($string); + + if (!$verifier) { + return null; + } + $aweber = new AweberAPI($consumerKey, $consumerSecret); + $aweber->adapter->user->requestToken = $requestToken; + $aweber->adapter->user->tokenSecret = $tokenSecret; + $aweber->adapter->user->verifier = $verifier; + list($accessToken, $accessSecret) = $aweber->getAccessToken(); + return array($consumerKey, $consumerSecret, $accessToken, $accessSecret); + } + + protected static function _parseAWeberID($string) { + $values = split('\|', $string); + if (count($values) < 5) { + return null; + } + return array_slice($values, 0, 5); + } + + /** + * Sets the consumer key and secret for the API object. The + * key and secret are listed in the My Apps page in the labs.aweber.com + * Control Panel OR, in the case of distributed apps, will be returned + * from the getDataFromAweberID() function + * + * @param String Consumer Key + * @param String Consumer Secret + * @return null + */ + public function __construct($key, $secret) { + // Load key / secret + $this->consumerKey = $key; + $this->consumerSecret = $secret; + + $this->setAdapter(); + } + + /** + * Returns the authorize URL by appending the request + * token to the end of the Authorize URI, if it exists + * + * @return string The Authorization URL + */ + public function getAuthorizeUrl() { + $requestToken = $this->user->requestToken; + return (empty($requestToken)) ? + $this->adapter->app->getAuthorizeUrl() + : + $this->adapter->app->getAuthorizeUrl() . "?oauth_token={$this->user->requestToken}"; + } + + /** + * Sets the adapter for use with the API + */ + public function setAdapter($adapter=null) { + if (empty($adapter)) { + $serviceProvider = new AWeberServiceProvider(); + $adapter = new OAuthApplication($serviceProvider); + $adapter->consumerKey = $this->consumerKey; + $adapter->consumerSecret = $this->consumerSecret; + } + $this->adapter = $adapter; + } + + /** + * Fetches account data for the associated account + * + * @param String Access Token (Only optional/cached if you called getAccessToken() earlier + * on the same page) + * @param String Access Token Secret (Only optional/cached if you called getAccessToken() earlier + * on the same page) + * @return Object AWeberCollection Object with the requested + * account data + */ + public function getAccount($token=false, $secret=false) { + if ($token && $secret) { + $user = new OAuthUser(); + $user->accessToken = $token; + $user->tokenSecret = $secret; + $this->adapter->user = $user; + } + + $body = $this->adapter->request('GET', '/accounts'); + $accounts = $this->readResponse($body, '/accounts'); + return $accounts[0]; + } + + /** + * PHP Automagic + */ + public function __get($item) { + if ($item == 'user') return $this->adapter->user; + trigger_error("Could not find \"{$item}\""); + } + + /** + * Request a request token from AWeber and associate the + * provided $callbackUrl with the new token + * @param String The URL where users should be redirected + * once they authorize your app + * @return Array Contains the request token as the first item + * and the request token secret as the second item of the array + */ + public function getRequestToken($callbackUrl) { + $requestToken = $this->adapter->getRequestToken($callbackUrl); + return array($requestToken, $this->user->tokenSecret); + } + + /** + * Request an access token using the request tokens stored in the + * current user object. You would want to first set the request tokens + * on the user before calling this function via: + * + * $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; + * $aweber->user->requestToken = $_GET['oauth_token']; + * $aweber->user->verifier = $_GET['oauth_verifier']; + * + * @return Array Contains the access token as the first item + * and the access token secret as the second item of the array + */ + public function getAccessToken() { + return $this->adapter->getAccessToken(); + } +} + +?> From f7d8b6749327078c0d8c9d0c1d5ed4c200bb6a12 Mon Sep 17 00:00:00 2001 From: Boris Valerstein Date: Tue, 27 Sep 2011 11:28:24 -0400 Subject: [PATCH 024/112] Revert "Revert "Added duplicate client library check"" This reverts commit 205f7332f31cfc302aeebfeefdc4240ec44addc0. --- aweber_api/aweber.php | 292 ++++++++++++++++++++++++++++++++++++++ aweber_api/aweber_api.php | 292 +------------------------------------- 2 files changed, 296 insertions(+), 288 deletions(-) create mode 100644 aweber_api/aweber.php diff --git a/aweber_api/aweber.php b/aweber_api/aweber.php new file mode 100644 index 0000000..385dea7 --- /dev/null +++ b/aweber_api/aweber.php @@ -0,0 +1,292 @@ +baseUri; + } + + public function removeBaseUri($url) { + return str_replace($this->getBaseUri(), '', $url); + } + + public function getAccessTokenUrl() { + return $this->accessTokenUrl; + } + + public function getAuthorizeUrl() { + return $this->authorizeUrl; + } + + public function getRequestTokenUrl() { + return $this->requestTokenUrl; + } + + public function getAuthTokenFromUrl() { return ''; } + public function getUserData() { return ''; } + +} + +/** + * AWeberAPIBase + * + * Base object that all AWeberAPI objects inherit from. Allows specific pieces + * of functionality to be shared across any object in the API, such as the + * ability to introspect the collections map. + * + * @package + * @version $id$ + */ +class AWeberAPIBase { + + /** + * Maintains data about what children collections a given object type + * contains. + */ + static protected $_collectionMap = array( + 'account' => array('lists', 'integrations'), + 'broadcast_campaign' => array('links', 'messages'), + 'followup_campaign' => array('links', 'messages'), + 'link' => array('clicks'), + 'list' => array('campaigns', 'custom_fields', 'subscribers', + 'web_forms', 'web_form_split_tests'), + 'web_form' => array(), + 'web_form_split_test' => array('components'), + ); + + /** + * loadFromUrl + * + * Creates an object, either collection or entry, based on the given + * URL. + * + * @param mixed $url URL for this request + * @access public + * @return AWeberEntry or AWeberCollection + */ + public function loadFromUrl($url) { + $data = $this->adapter->request('GET', $url); + return $this->readResponse($data, $url); + } + + protected function _cleanUrl($url) { + return str_replace($this->adapter->app->getBaseUri(), '', $url); + } + + /** + * readResponse + * + * Interprets a response, and creates the appropriate object from it. + * @param mixed $response Data returned from a request to the AWeberAPI + * @param mixed $url URL that this data was requested from + * @access protected + * @return mixed + */ + protected function readResponse($response, $url) { + $this->adapter->parseAsError($response); + if (!empty($response['id'])) { + return new AWeberEntry($response, $url, $this->adapter); + } else if (isset($response['entries'])) { + return new AWeberCollection($response, $url, $this->adapter); + } + return false; + } +} + +/** + * AWeberAPI + * + * Creates a connection to the AWeberAPI for a given consumer application. + * This is generally the starting point for this library. Instances can be + * created directly with consumerKey and consumerSecret. + * @uses AWeberAPIBase + * @package + * @version $id$ + */ +class AWeberAPI extends AWeberAPIBase { + + /** + * @var String Consumer Key + */ + public $consumerKey = false; + + /** + * @var String Consumer Secret + */ + public $consumerSecret = false; + + /** + * @var Object - Populated in setAdapter() + */ + public $adapter = false; + + /** + * Uses the app's authorization code to fetch an access token + * + * @param String Authorization code from authorize app page + */ + public static function getDataFromAweberID($string) { + list($consumerKey, $consumerSecret, $requestToken, $tokenSecret, $verifier) = AWeberAPI::_parseAweberID($string); + + if (!$verifier) { + return null; + } + $aweber = new AweberAPI($consumerKey, $consumerSecret); + $aweber->adapter->user->requestToken = $requestToken; + $aweber->adapter->user->tokenSecret = $tokenSecret; + $aweber->adapter->user->verifier = $verifier; + list($accessToken, $accessSecret) = $aweber->getAccessToken(); + return array($consumerKey, $consumerSecret, $accessToken, $accessSecret); + } + + protected static function _parseAWeberID($string) { + $values = split('\|', $string); + if (count($values) < 5) { + return null; + } + return array_slice($values, 0, 5); + } + + /** + * Sets the consumer key and secret for the API object. The + * key and secret are listed in the My Apps page in the labs.aweber.com + * Control Panel OR, in the case of distributed apps, will be returned + * from the getDataFromAweberID() function + * + * @param String Consumer Key + * @param String Consumer Secret + * @return null + */ + public function __construct($key, $secret) { + // Load key / secret + $this->consumerKey = $key; + $this->consumerSecret = $secret; + + $this->setAdapter(); + } + + /** + * Returns the authorize URL by appending the request + * token to the end of the Authorize URI, if it exists + * + * @return string The Authorization URL + */ + public function getAuthorizeUrl() { + $requestToken = $this->user->requestToken; + return (empty($requestToken)) ? + $this->adapter->app->getAuthorizeUrl() + : + $this->adapter->app->getAuthorizeUrl() . "?oauth_token={$this->user->requestToken}"; + } + + /** + * Sets the adapter for use with the API + */ + public function setAdapter($adapter=null) { + if (empty($adapter)) { + $serviceProvider = new AWeberServiceProvider(); + $adapter = new OAuthApplication($serviceProvider); + $adapter->consumerKey = $this->consumerKey; + $adapter->consumerSecret = $this->consumerSecret; + } + $this->adapter = $adapter; + } + + /** + * Fetches account data for the associated account + * + * @param String Access Token (Only optional/cached if you called getAccessToken() earlier + * on the same page) + * @param String Access Token Secret (Only optional/cached if you called getAccessToken() earlier + * on the same page) + * @return Object AWeberCollection Object with the requested + * account data + */ + public function getAccount($token=false, $secret=false) { + if ($token && $secret) { + $user = new OAuthUser(); + $user->accessToken = $token; + $user->tokenSecret = $secret; + $this->adapter->user = $user; + } + + $body = $this->adapter->request('GET', '/accounts'); + $accounts = $this->readResponse($body, '/accounts'); + return $accounts[0]; + } + + /** + * PHP Automagic + */ + public function __get($item) { + if ($item == 'user') return $this->adapter->user; + trigger_error("Could not find \"{$item}\""); + } + + /** + * Request a request token from AWeber and associate the + * provided $callbackUrl with the new token + * @param String The URL where users should be redirected + * once they authorize your app + * @return Array Contains the request token as the first item + * and the request token secret as the second item of the array + */ + public function getRequestToken($callbackUrl) { + $requestToken = $this->adapter->getRequestToken($callbackUrl); + return array($requestToken, $this->user->tokenSecret); + } + + /** + * Request an access token using the request tokens stored in the + * current user object. You would want to first set the request tokens + * on the user before calling this function via: + * + * $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; + * $aweber->user->requestToken = $_GET['oauth_token']; + * $aweber->user->verifier = $_GET['oauth_verifier']; + * + * @return Array Contains the access token as the first item + * and the access token secret as the second item of the array + */ + public function getAccessToken() { + return $this->adapter->getAccessToken(); + } +} + +?> diff --git a/aweber_api/aweber_api.php b/aweber_api/aweber_api.php index 385dea7..201de64 100644 --- a/aweber_api/aweber_api.php +++ b/aweber_api/aweber_api.php @@ -1,292 +1,8 @@ baseUri; - } - - public function removeBaseUri($url) { - return str_replace($this->getBaseUri(), '', $url); - } - - public function getAccessTokenUrl() { - return $this->accessTokenUrl; - } - - public function getAuthorizeUrl() { - return $this->authorizeUrl; - } - - public function getRequestTokenUrl() { - return $this->requestTokenUrl; - } - - public function getAuthTokenFromUrl() { return ''; } - public function getUserData() { return ''; } +if (class_exists('AWeberAPI')) { + trigger_error("Duplicate: Another AWeberAPI client library is already in scope.", E_USER_WARNING); } - -/** - * AWeberAPIBase - * - * Base object that all AWeberAPI objects inherit from. Allows specific pieces - * of functionality to be shared across any object in the API, such as the - * ability to introspect the collections map. - * - * @package - * @version $id$ - */ -class AWeberAPIBase { - - /** - * Maintains data about what children collections a given object type - * contains. - */ - static protected $_collectionMap = array( - 'account' => array('lists', 'integrations'), - 'broadcast_campaign' => array('links', 'messages'), - 'followup_campaign' => array('links', 'messages'), - 'link' => array('clicks'), - 'list' => array('campaigns', 'custom_fields', 'subscribers', - 'web_forms', 'web_form_split_tests'), - 'web_form' => array(), - 'web_form_split_test' => array('components'), - ); - - /** - * loadFromUrl - * - * Creates an object, either collection or entry, based on the given - * URL. - * - * @param mixed $url URL for this request - * @access public - * @return AWeberEntry or AWeberCollection - */ - public function loadFromUrl($url) { - $data = $this->adapter->request('GET', $url); - return $this->readResponse($data, $url); - } - - protected function _cleanUrl($url) { - return str_replace($this->adapter->app->getBaseUri(), '', $url); - } - - /** - * readResponse - * - * Interprets a response, and creates the appropriate object from it. - * @param mixed $response Data returned from a request to the AWeberAPI - * @param mixed $url URL that this data was requested from - * @access protected - * @return mixed - */ - protected function readResponse($response, $url) { - $this->adapter->parseAsError($response); - if (!empty($response['id'])) { - return new AWeberEntry($response, $url, $this->adapter); - } else if (isset($response['entries'])) { - return new AWeberCollection($response, $url, $this->adapter); - } - return false; - } +else { + require_once('aweber.php'); } - -/** - * AWeberAPI - * - * Creates a connection to the AWeberAPI for a given consumer application. - * This is generally the starting point for this library. Instances can be - * created directly with consumerKey and consumerSecret. - * @uses AWeberAPIBase - * @package - * @version $id$ - */ -class AWeberAPI extends AWeberAPIBase { - - /** - * @var String Consumer Key - */ - public $consumerKey = false; - - /** - * @var String Consumer Secret - */ - public $consumerSecret = false; - - /** - * @var Object - Populated in setAdapter() - */ - public $adapter = false; - - /** - * Uses the app's authorization code to fetch an access token - * - * @param String Authorization code from authorize app page - */ - public static function getDataFromAweberID($string) { - list($consumerKey, $consumerSecret, $requestToken, $tokenSecret, $verifier) = AWeberAPI::_parseAweberID($string); - - if (!$verifier) { - return null; - } - $aweber = new AweberAPI($consumerKey, $consumerSecret); - $aweber->adapter->user->requestToken = $requestToken; - $aweber->adapter->user->tokenSecret = $tokenSecret; - $aweber->adapter->user->verifier = $verifier; - list($accessToken, $accessSecret) = $aweber->getAccessToken(); - return array($consumerKey, $consumerSecret, $accessToken, $accessSecret); - } - - protected static function _parseAWeberID($string) { - $values = split('\|', $string); - if (count($values) < 5) { - return null; - } - return array_slice($values, 0, 5); - } - - /** - * Sets the consumer key and secret for the API object. The - * key and secret are listed in the My Apps page in the labs.aweber.com - * Control Panel OR, in the case of distributed apps, will be returned - * from the getDataFromAweberID() function - * - * @param String Consumer Key - * @param String Consumer Secret - * @return null - */ - public function __construct($key, $secret) { - // Load key / secret - $this->consumerKey = $key; - $this->consumerSecret = $secret; - - $this->setAdapter(); - } - - /** - * Returns the authorize URL by appending the request - * token to the end of the Authorize URI, if it exists - * - * @return string The Authorization URL - */ - public function getAuthorizeUrl() { - $requestToken = $this->user->requestToken; - return (empty($requestToken)) ? - $this->adapter->app->getAuthorizeUrl() - : - $this->adapter->app->getAuthorizeUrl() . "?oauth_token={$this->user->requestToken}"; - } - - /** - * Sets the adapter for use with the API - */ - public function setAdapter($adapter=null) { - if (empty($adapter)) { - $serviceProvider = new AWeberServiceProvider(); - $adapter = new OAuthApplication($serviceProvider); - $adapter->consumerKey = $this->consumerKey; - $adapter->consumerSecret = $this->consumerSecret; - } - $this->adapter = $adapter; - } - - /** - * Fetches account data for the associated account - * - * @param String Access Token (Only optional/cached if you called getAccessToken() earlier - * on the same page) - * @param String Access Token Secret (Only optional/cached if you called getAccessToken() earlier - * on the same page) - * @return Object AWeberCollection Object with the requested - * account data - */ - public function getAccount($token=false, $secret=false) { - if ($token && $secret) { - $user = new OAuthUser(); - $user->accessToken = $token; - $user->tokenSecret = $secret; - $this->adapter->user = $user; - } - - $body = $this->adapter->request('GET', '/accounts'); - $accounts = $this->readResponse($body, '/accounts'); - return $accounts[0]; - } - - /** - * PHP Automagic - */ - public function __get($item) { - if ($item == 'user') return $this->adapter->user; - trigger_error("Could not find \"{$item}\""); - } - - /** - * Request a request token from AWeber and associate the - * provided $callbackUrl with the new token - * @param String The URL where users should be redirected - * once they authorize your app - * @return Array Contains the request token as the first item - * and the request token secret as the second item of the array - */ - public function getRequestToken($callbackUrl) { - $requestToken = $this->adapter->getRequestToken($callbackUrl); - return array($requestToken, $this->user->tokenSecret); - } - - /** - * Request an access token using the request tokens stored in the - * current user object. You would want to first set the request tokens - * on the user before calling this function via: - * - * $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; - * $aweber->user->requestToken = $_GET['oauth_token']; - * $aweber->user->verifier = $_GET['oauth_verifier']; - * - * @return Array Contains the access token as the first item - * and the access token secret as the second item of the array - */ - public function getAccessToken() { - return $this->adapter->getAccessToken(); - } -} - -?> From f993488fc2188b0b0599dfc5d488b450c7e588fe Mon Sep 17 00:00:00 2001 From: Boris Valerstein Date: Tue, 27 Sep 2011 11:31:52 -0400 Subject: [PATCH 025/112] Revert "Revert "Revert "Added duplicate client library check""" This reverts commit f7d8b6749327078c0d8c9d0c1d5ed4c200bb6a12. --- aweber_api/aweber.php | 292 -------------------------------------- aweber_api/aweber_api.php | 292 +++++++++++++++++++++++++++++++++++++- 2 files changed, 288 insertions(+), 296 deletions(-) delete mode 100644 aweber_api/aweber.php diff --git a/aweber_api/aweber.php b/aweber_api/aweber.php deleted file mode 100644 index 385dea7..0000000 --- a/aweber_api/aweber.php +++ /dev/null @@ -1,292 +0,0 @@ -baseUri; - } - - public function removeBaseUri($url) { - return str_replace($this->getBaseUri(), '', $url); - } - - public function getAccessTokenUrl() { - return $this->accessTokenUrl; - } - - public function getAuthorizeUrl() { - return $this->authorizeUrl; - } - - public function getRequestTokenUrl() { - return $this->requestTokenUrl; - } - - public function getAuthTokenFromUrl() { return ''; } - public function getUserData() { return ''; } - -} - -/** - * AWeberAPIBase - * - * Base object that all AWeberAPI objects inherit from. Allows specific pieces - * of functionality to be shared across any object in the API, such as the - * ability to introspect the collections map. - * - * @package - * @version $id$ - */ -class AWeberAPIBase { - - /** - * Maintains data about what children collections a given object type - * contains. - */ - static protected $_collectionMap = array( - 'account' => array('lists', 'integrations'), - 'broadcast_campaign' => array('links', 'messages'), - 'followup_campaign' => array('links', 'messages'), - 'link' => array('clicks'), - 'list' => array('campaigns', 'custom_fields', 'subscribers', - 'web_forms', 'web_form_split_tests'), - 'web_form' => array(), - 'web_form_split_test' => array('components'), - ); - - /** - * loadFromUrl - * - * Creates an object, either collection or entry, based on the given - * URL. - * - * @param mixed $url URL for this request - * @access public - * @return AWeberEntry or AWeberCollection - */ - public function loadFromUrl($url) { - $data = $this->adapter->request('GET', $url); - return $this->readResponse($data, $url); - } - - protected function _cleanUrl($url) { - return str_replace($this->adapter->app->getBaseUri(), '', $url); - } - - /** - * readResponse - * - * Interprets a response, and creates the appropriate object from it. - * @param mixed $response Data returned from a request to the AWeberAPI - * @param mixed $url URL that this data was requested from - * @access protected - * @return mixed - */ - protected function readResponse($response, $url) { - $this->adapter->parseAsError($response); - if (!empty($response['id'])) { - return new AWeberEntry($response, $url, $this->adapter); - } else if (isset($response['entries'])) { - return new AWeberCollection($response, $url, $this->adapter); - } - return false; - } -} - -/** - * AWeberAPI - * - * Creates a connection to the AWeberAPI for a given consumer application. - * This is generally the starting point for this library. Instances can be - * created directly with consumerKey and consumerSecret. - * @uses AWeberAPIBase - * @package - * @version $id$ - */ -class AWeberAPI extends AWeberAPIBase { - - /** - * @var String Consumer Key - */ - public $consumerKey = false; - - /** - * @var String Consumer Secret - */ - public $consumerSecret = false; - - /** - * @var Object - Populated in setAdapter() - */ - public $adapter = false; - - /** - * Uses the app's authorization code to fetch an access token - * - * @param String Authorization code from authorize app page - */ - public static function getDataFromAweberID($string) { - list($consumerKey, $consumerSecret, $requestToken, $tokenSecret, $verifier) = AWeberAPI::_parseAweberID($string); - - if (!$verifier) { - return null; - } - $aweber = new AweberAPI($consumerKey, $consumerSecret); - $aweber->adapter->user->requestToken = $requestToken; - $aweber->adapter->user->tokenSecret = $tokenSecret; - $aweber->adapter->user->verifier = $verifier; - list($accessToken, $accessSecret) = $aweber->getAccessToken(); - return array($consumerKey, $consumerSecret, $accessToken, $accessSecret); - } - - protected static function _parseAWeberID($string) { - $values = split('\|', $string); - if (count($values) < 5) { - return null; - } - return array_slice($values, 0, 5); - } - - /** - * Sets the consumer key and secret for the API object. The - * key and secret are listed in the My Apps page in the labs.aweber.com - * Control Panel OR, in the case of distributed apps, will be returned - * from the getDataFromAweberID() function - * - * @param String Consumer Key - * @param String Consumer Secret - * @return null - */ - public function __construct($key, $secret) { - // Load key / secret - $this->consumerKey = $key; - $this->consumerSecret = $secret; - - $this->setAdapter(); - } - - /** - * Returns the authorize URL by appending the request - * token to the end of the Authorize URI, if it exists - * - * @return string The Authorization URL - */ - public function getAuthorizeUrl() { - $requestToken = $this->user->requestToken; - return (empty($requestToken)) ? - $this->adapter->app->getAuthorizeUrl() - : - $this->adapter->app->getAuthorizeUrl() . "?oauth_token={$this->user->requestToken}"; - } - - /** - * Sets the adapter for use with the API - */ - public function setAdapter($adapter=null) { - if (empty($adapter)) { - $serviceProvider = new AWeberServiceProvider(); - $adapter = new OAuthApplication($serviceProvider); - $adapter->consumerKey = $this->consumerKey; - $adapter->consumerSecret = $this->consumerSecret; - } - $this->adapter = $adapter; - } - - /** - * Fetches account data for the associated account - * - * @param String Access Token (Only optional/cached if you called getAccessToken() earlier - * on the same page) - * @param String Access Token Secret (Only optional/cached if you called getAccessToken() earlier - * on the same page) - * @return Object AWeberCollection Object with the requested - * account data - */ - public function getAccount($token=false, $secret=false) { - if ($token && $secret) { - $user = new OAuthUser(); - $user->accessToken = $token; - $user->tokenSecret = $secret; - $this->adapter->user = $user; - } - - $body = $this->adapter->request('GET', '/accounts'); - $accounts = $this->readResponse($body, '/accounts'); - return $accounts[0]; - } - - /** - * PHP Automagic - */ - public function __get($item) { - if ($item == 'user') return $this->adapter->user; - trigger_error("Could not find \"{$item}\""); - } - - /** - * Request a request token from AWeber and associate the - * provided $callbackUrl with the new token - * @param String The URL where users should be redirected - * once they authorize your app - * @return Array Contains the request token as the first item - * and the request token secret as the second item of the array - */ - public function getRequestToken($callbackUrl) { - $requestToken = $this->adapter->getRequestToken($callbackUrl); - return array($requestToken, $this->user->tokenSecret); - } - - /** - * Request an access token using the request tokens stored in the - * current user object. You would want to first set the request tokens - * on the user before calling this function via: - * - * $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; - * $aweber->user->requestToken = $_GET['oauth_token']; - * $aweber->user->verifier = $_GET['oauth_verifier']; - * - * @return Array Contains the access token as the first item - * and the access token secret as the second item of the array - */ - public function getAccessToken() { - return $this->adapter->getAccessToken(); - } -} - -?> diff --git a/aweber_api/aweber_api.php b/aweber_api/aweber_api.php index 201de64..385dea7 100644 --- a/aweber_api/aweber_api.php +++ b/aweber_api/aweber_api.php @@ -1,8 +1,292 @@ baseUri; + } + + public function removeBaseUri($url) { + return str_replace($this->getBaseUri(), '', $url); + } + + public function getAccessTokenUrl() { + return $this->accessTokenUrl; + } + + public function getAuthorizeUrl() { + return $this->authorizeUrl; + } + + public function getRequestTokenUrl() { + return $this->requestTokenUrl; + } + + public function getAuthTokenFromUrl() { return ''; } + public function getUserData() { return ''; } -if (class_exists('AWeberAPI')) { - trigger_error("Duplicate: Another AWeberAPI client library is already in scope.", E_USER_WARNING); } -else { - require_once('aweber.php'); + +/** + * AWeberAPIBase + * + * Base object that all AWeberAPI objects inherit from. Allows specific pieces + * of functionality to be shared across any object in the API, such as the + * ability to introspect the collections map. + * + * @package + * @version $id$ + */ +class AWeberAPIBase { + + /** + * Maintains data about what children collections a given object type + * contains. + */ + static protected $_collectionMap = array( + 'account' => array('lists', 'integrations'), + 'broadcast_campaign' => array('links', 'messages'), + 'followup_campaign' => array('links', 'messages'), + 'link' => array('clicks'), + 'list' => array('campaigns', 'custom_fields', 'subscribers', + 'web_forms', 'web_form_split_tests'), + 'web_form' => array(), + 'web_form_split_test' => array('components'), + ); + + /** + * loadFromUrl + * + * Creates an object, either collection or entry, based on the given + * URL. + * + * @param mixed $url URL for this request + * @access public + * @return AWeberEntry or AWeberCollection + */ + public function loadFromUrl($url) { + $data = $this->adapter->request('GET', $url); + return $this->readResponse($data, $url); + } + + protected function _cleanUrl($url) { + return str_replace($this->adapter->app->getBaseUri(), '', $url); + } + + /** + * readResponse + * + * Interprets a response, and creates the appropriate object from it. + * @param mixed $response Data returned from a request to the AWeberAPI + * @param mixed $url URL that this data was requested from + * @access protected + * @return mixed + */ + protected function readResponse($response, $url) { + $this->adapter->parseAsError($response); + if (!empty($response['id'])) { + return new AWeberEntry($response, $url, $this->adapter); + } else if (isset($response['entries'])) { + return new AWeberCollection($response, $url, $this->adapter); + } + return false; + } } + +/** + * AWeberAPI + * + * Creates a connection to the AWeberAPI for a given consumer application. + * This is generally the starting point for this library. Instances can be + * created directly with consumerKey and consumerSecret. + * @uses AWeberAPIBase + * @package + * @version $id$ + */ +class AWeberAPI extends AWeberAPIBase { + + /** + * @var String Consumer Key + */ + public $consumerKey = false; + + /** + * @var String Consumer Secret + */ + public $consumerSecret = false; + + /** + * @var Object - Populated in setAdapter() + */ + public $adapter = false; + + /** + * Uses the app's authorization code to fetch an access token + * + * @param String Authorization code from authorize app page + */ + public static function getDataFromAweberID($string) { + list($consumerKey, $consumerSecret, $requestToken, $tokenSecret, $verifier) = AWeberAPI::_parseAweberID($string); + + if (!$verifier) { + return null; + } + $aweber = new AweberAPI($consumerKey, $consumerSecret); + $aweber->adapter->user->requestToken = $requestToken; + $aweber->adapter->user->tokenSecret = $tokenSecret; + $aweber->adapter->user->verifier = $verifier; + list($accessToken, $accessSecret) = $aweber->getAccessToken(); + return array($consumerKey, $consumerSecret, $accessToken, $accessSecret); + } + + protected static function _parseAWeberID($string) { + $values = split('\|', $string); + if (count($values) < 5) { + return null; + } + return array_slice($values, 0, 5); + } + + /** + * Sets the consumer key and secret for the API object. The + * key and secret are listed in the My Apps page in the labs.aweber.com + * Control Panel OR, in the case of distributed apps, will be returned + * from the getDataFromAweberID() function + * + * @param String Consumer Key + * @param String Consumer Secret + * @return null + */ + public function __construct($key, $secret) { + // Load key / secret + $this->consumerKey = $key; + $this->consumerSecret = $secret; + + $this->setAdapter(); + } + + /** + * Returns the authorize URL by appending the request + * token to the end of the Authorize URI, if it exists + * + * @return string The Authorization URL + */ + public function getAuthorizeUrl() { + $requestToken = $this->user->requestToken; + return (empty($requestToken)) ? + $this->adapter->app->getAuthorizeUrl() + : + $this->adapter->app->getAuthorizeUrl() . "?oauth_token={$this->user->requestToken}"; + } + + /** + * Sets the adapter for use with the API + */ + public function setAdapter($adapter=null) { + if (empty($adapter)) { + $serviceProvider = new AWeberServiceProvider(); + $adapter = new OAuthApplication($serviceProvider); + $adapter->consumerKey = $this->consumerKey; + $adapter->consumerSecret = $this->consumerSecret; + } + $this->adapter = $adapter; + } + + /** + * Fetches account data for the associated account + * + * @param String Access Token (Only optional/cached if you called getAccessToken() earlier + * on the same page) + * @param String Access Token Secret (Only optional/cached if you called getAccessToken() earlier + * on the same page) + * @return Object AWeberCollection Object with the requested + * account data + */ + public function getAccount($token=false, $secret=false) { + if ($token && $secret) { + $user = new OAuthUser(); + $user->accessToken = $token; + $user->tokenSecret = $secret; + $this->adapter->user = $user; + } + + $body = $this->adapter->request('GET', '/accounts'); + $accounts = $this->readResponse($body, '/accounts'); + return $accounts[0]; + } + + /** + * PHP Automagic + */ + public function __get($item) { + if ($item == 'user') return $this->adapter->user; + trigger_error("Could not find \"{$item}\""); + } + + /** + * Request a request token from AWeber and associate the + * provided $callbackUrl with the new token + * @param String The URL where users should be redirected + * once they authorize your app + * @return Array Contains the request token as the first item + * and the request token secret as the second item of the array + */ + public function getRequestToken($callbackUrl) { + $requestToken = $this->adapter->getRequestToken($callbackUrl); + return array($requestToken, $this->user->tokenSecret); + } + + /** + * Request an access token using the request tokens stored in the + * current user object. You would want to first set the request tokens + * on the user before calling this function via: + * + * $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; + * $aweber->user->requestToken = $_GET['oauth_token']; + * $aweber->user->verifier = $_GET['oauth_verifier']; + * + * @return Array Contains the access token as the first item + * and the access token secret as the second item of the array + */ + public function getAccessToken() { + return $this->adapter->getAccessToken(); + } +} + +?> From b331a54c80da3fad68e9e56cde85970837f152e0 Mon Sep 17 00:00:00 2001 From: "Edward F. Long, Jr" Date: Mon, 10 Oct 2011 13:49:31 -0400 Subject: [PATCH 026/112] added duplicate client library detection with tests. updated changelog. --- README | 2 + aweber_api/aweber.php | 292 +++++++++++++++++++++++++++++++++++ aweber_api/aweber_api.php | 292 +---------------------------------- tests/all_tests.php | 2 + tests/multi_version.test.php | 35 +++++ 5 files changed, 335 insertions(+), 288 deletions(-) create mode 100644 aweber_api/aweber.php create mode 100644 tests/multi_version.test.php diff --git a/README b/README index 3852537..d270de0 100644 --- a/README +++ b/README @@ -5,6 +5,8 @@ PHP library for easily integrating with the AWeber API. Changelog: ---------- +2011-10-10: v1.1.1 + * Raise an E_USER_WARNING instead of a fatal error if multiple instances of the client library are installed. 2011-08-29: v1.1.0 * Modified client library to raise an AWeberAPIException on any API errors (HTTP status >= 400) diff --git a/aweber_api/aweber.php b/aweber_api/aweber.php new file mode 100644 index 0000000..385dea7 --- /dev/null +++ b/aweber_api/aweber.php @@ -0,0 +1,292 @@ +baseUri; + } + + public function removeBaseUri($url) { + return str_replace($this->getBaseUri(), '', $url); + } + + public function getAccessTokenUrl() { + return $this->accessTokenUrl; + } + + public function getAuthorizeUrl() { + return $this->authorizeUrl; + } + + public function getRequestTokenUrl() { + return $this->requestTokenUrl; + } + + public function getAuthTokenFromUrl() { return ''; } + public function getUserData() { return ''; } + +} + +/** + * AWeberAPIBase + * + * Base object that all AWeberAPI objects inherit from. Allows specific pieces + * of functionality to be shared across any object in the API, such as the + * ability to introspect the collections map. + * + * @package + * @version $id$ + */ +class AWeberAPIBase { + + /** + * Maintains data about what children collections a given object type + * contains. + */ + static protected $_collectionMap = array( + 'account' => array('lists', 'integrations'), + 'broadcast_campaign' => array('links', 'messages'), + 'followup_campaign' => array('links', 'messages'), + 'link' => array('clicks'), + 'list' => array('campaigns', 'custom_fields', 'subscribers', + 'web_forms', 'web_form_split_tests'), + 'web_form' => array(), + 'web_form_split_test' => array('components'), + ); + + /** + * loadFromUrl + * + * Creates an object, either collection or entry, based on the given + * URL. + * + * @param mixed $url URL for this request + * @access public + * @return AWeberEntry or AWeberCollection + */ + public function loadFromUrl($url) { + $data = $this->adapter->request('GET', $url); + return $this->readResponse($data, $url); + } + + protected function _cleanUrl($url) { + return str_replace($this->adapter->app->getBaseUri(), '', $url); + } + + /** + * readResponse + * + * Interprets a response, and creates the appropriate object from it. + * @param mixed $response Data returned from a request to the AWeberAPI + * @param mixed $url URL that this data was requested from + * @access protected + * @return mixed + */ + protected function readResponse($response, $url) { + $this->adapter->parseAsError($response); + if (!empty($response['id'])) { + return new AWeberEntry($response, $url, $this->adapter); + } else if (isset($response['entries'])) { + return new AWeberCollection($response, $url, $this->adapter); + } + return false; + } +} + +/** + * AWeberAPI + * + * Creates a connection to the AWeberAPI for a given consumer application. + * This is generally the starting point for this library. Instances can be + * created directly with consumerKey and consumerSecret. + * @uses AWeberAPIBase + * @package + * @version $id$ + */ +class AWeberAPI extends AWeberAPIBase { + + /** + * @var String Consumer Key + */ + public $consumerKey = false; + + /** + * @var String Consumer Secret + */ + public $consumerSecret = false; + + /** + * @var Object - Populated in setAdapter() + */ + public $adapter = false; + + /** + * Uses the app's authorization code to fetch an access token + * + * @param String Authorization code from authorize app page + */ + public static function getDataFromAweberID($string) { + list($consumerKey, $consumerSecret, $requestToken, $tokenSecret, $verifier) = AWeberAPI::_parseAweberID($string); + + if (!$verifier) { + return null; + } + $aweber = new AweberAPI($consumerKey, $consumerSecret); + $aweber->adapter->user->requestToken = $requestToken; + $aweber->adapter->user->tokenSecret = $tokenSecret; + $aweber->adapter->user->verifier = $verifier; + list($accessToken, $accessSecret) = $aweber->getAccessToken(); + return array($consumerKey, $consumerSecret, $accessToken, $accessSecret); + } + + protected static function _parseAWeberID($string) { + $values = split('\|', $string); + if (count($values) < 5) { + return null; + } + return array_slice($values, 0, 5); + } + + /** + * Sets the consumer key and secret for the API object. The + * key and secret are listed in the My Apps page in the labs.aweber.com + * Control Panel OR, in the case of distributed apps, will be returned + * from the getDataFromAweberID() function + * + * @param String Consumer Key + * @param String Consumer Secret + * @return null + */ + public function __construct($key, $secret) { + // Load key / secret + $this->consumerKey = $key; + $this->consumerSecret = $secret; + + $this->setAdapter(); + } + + /** + * Returns the authorize URL by appending the request + * token to the end of the Authorize URI, if it exists + * + * @return string The Authorization URL + */ + public function getAuthorizeUrl() { + $requestToken = $this->user->requestToken; + return (empty($requestToken)) ? + $this->adapter->app->getAuthorizeUrl() + : + $this->adapter->app->getAuthorizeUrl() . "?oauth_token={$this->user->requestToken}"; + } + + /** + * Sets the adapter for use with the API + */ + public function setAdapter($adapter=null) { + if (empty($adapter)) { + $serviceProvider = new AWeberServiceProvider(); + $adapter = new OAuthApplication($serviceProvider); + $adapter->consumerKey = $this->consumerKey; + $adapter->consumerSecret = $this->consumerSecret; + } + $this->adapter = $adapter; + } + + /** + * Fetches account data for the associated account + * + * @param String Access Token (Only optional/cached if you called getAccessToken() earlier + * on the same page) + * @param String Access Token Secret (Only optional/cached if you called getAccessToken() earlier + * on the same page) + * @return Object AWeberCollection Object with the requested + * account data + */ + public function getAccount($token=false, $secret=false) { + if ($token && $secret) { + $user = new OAuthUser(); + $user->accessToken = $token; + $user->tokenSecret = $secret; + $this->adapter->user = $user; + } + + $body = $this->adapter->request('GET', '/accounts'); + $accounts = $this->readResponse($body, '/accounts'); + return $accounts[0]; + } + + /** + * PHP Automagic + */ + public function __get($item) { + if ($item == 'user') return $this->adapter->user; + trigger_error("Could not find \"{$item}\""); + } + + /** + * Request a request token from AWeber and associate the + * provided $callbackUrl with the new token + * @param String The URL where users should be redirected + * once they authorize your app + * @return Array Contains the request token as the first item + * and the request token secret as the second item of the array + */ + public function getRequestToken($callbackUrl) { + $requestToken = $this->adapter->getRequestToken($callbackUrl); + return array($requestToken, $this->user->tokenSecret); + } + + /** + * Request an access token using the request tokens stored in the + * current user object. You would want to first set the request tokens + * on the user before calling this function via: + * + * $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; + * $aweber->user->requestToken = $_GET['oauth_token']; + * $aweber->user->verifier = $_GET['oauth_verifier']; + * + * @return Array Contains the access token as the first item + * and the access token secret as the second item of the array + */ + public function getAccessToken() { + return $this->adapter->getAccessToken(); + } +} + +?> diff --git a/aweber_api/aweber_api.php b/aweber_api/aweber_api.php index 385dea7..201de64 100644 --- a/aweber_api/aweber_api.php +++ b/aweber_api/aweber_api.php @@ -1,292 +1,8 @@ baseUri; - } - - public function removeBaseUri($url) { - return str_replace($this->getBaseUri(), '', $url); - } - - public function getAccessTokenUrl() { - return $this->accessTokenUrl; - } - - public function getAuthorizeUrl() { - return $this->authorizeUrl; - } - - public function getRequestTokenUrl() { - return $this->requestTokenUrl; - } - - public function getAuthTokenFromUrl() { return ''; } - public function getUserData() { return ''; } +if (class_exists('AWeberAPI')) { + trigger_error("Duplicate: Another AWeberAPI client library is already in scope.", E_USER_WARNING); } - -/** - * AWeberAPIBase - * - * Base object that all AWeberAPI objects inherit from. Allows specific pieces - * of functionality to be shared across any object in the API, such as the - * ability to introspect the collections map. - * - * @package - * @version $id$ - */ -class AWeberAPIBase { - - /** - * Maintains data about what children collections a given object type - * contains. - */ - static protected $_collectionMap = array( - 'account' => array('lists', 'integrations'), - 'broadcast_campaign' => array('links', 'messages'), - 'followup_campaign' => array('links', 'messages'), - 'link' => array('clicks'), - 'list' => array('campaigns', 'custom_fields', 'subscribers', - 'web_forms', 'web_form_split_tests'), - 'web_form' => array(), - 'web_form_split_test' => array('components'), - ); - - /** - * loadFromUrl - * - * Creates an object, either collection or entry, based on the given - * URL. - * - * @param mixed $url URL for this request - * @access public - * @return AWeberEntry or AWeberCollection - */ - public function loadFromUrl($url) { - $data = $this->adapter->request('GET', $url); - return $this->readResponse($data, $url); - } - - protected function _cleanUrl($url) { - return str_replace($this->adapter->app->getBaseUri(), '', $url); - } - - /** - * readResponse - * - * Interprets a response, and creates the appropriate object from it. - * @param mixed $response Data returned from a request to the AWeberAPI - * @param mixed $url URL that this data was requested from - * @access protected - * @return mixed - */ - protected function readResponse($response, $url) { - $this->adapter->parseAsError($response); - if (!empty($response['id'])) { - return new AWeberEntry($response, $url, $this->adapter); - } else if (isset($response['entries'])) { - return new AWeberCollection($response, $url, $this->adapter); - } - return false; - } +else { + require_once('aweber.php'); } - -/** - * AWeberAPI - * - * Creates a connection to the AWeberAPI for a given consumer application. - * This is generally the starting point for this library. Instances can be - * created directly with consumerKey and consumerSecret. - * @uses AWeberAPIBase - * @package - * @version $id$ - */ -class AWeberAPI extends AWeberAPIBase { - - /** - * @var String Consumer Key - */ - public $consumerKey = false; - - /** - * @var String Consumer Secret - */ - public $consumerSecret = false; - - /** - * @var Object - Populated in setAdapter() - */ - public $adapter = false; - - /** - * Uses the app's authorization code to fetch an access token - * - * @param String Authorization code from authorize app page - */ - public static function getDataFromAweberID($string) { - list($consumerKey, $consumerSecret, $requestToken, $tokenSecret, $verifier) = AWeberAPI::_parseAweberID($string); - - if (!$verifier) { - return null; - } - $aweber = new AweberAPI($consumerKey, $consumerSecret); - $aweber->adapter->user->requestToken = $requestToken; - $aweber->adapter->user->tokenSecret = $tokenSecret; - $aweber->adapter->user->verifier = $verifier; - list($accessToken, $accessSecret) = $aweber->getAccessToken(); - return array($consumerKey, $consumerSecret, $accessToken, $accessSecret); - } - - protected static function _parseAWeberID($string) { - $values = split('\|', $string); - if (count($values) < 5) { - return null; - } - return array_slice($values, 0, 5); - } - - /** - * Sets the consumer key and secret for the API object. The - * key and secret are listed in the My Apps page in the labs.aweber.com - * Control Panel OR, in the case of distributed apps, will be returned - * from the getDataFromAweberID() function - * - * @param String Consumer Key - * @param String Consumer Secret - * @return null - */ - public function __construct($key, $secret) { - // Load key / secret - $this->consumerKey = $key; - $this->consumerSecret = $secret; - - $this->setAdapter(); - } - - /** - * Returns the authorize URL by appending the request - * token to the end of the Authorize URI, if it exists - * - * @return string The Authorization URL - */ - public function getAuthorizeUrl() { - $requestToken = $this->user->requestToken; - return (empty($requestToken)) ? - $this->adapter->app->getAuthorizeUrl() - : - $this->adapter->app->getAuthorizeUrl() . "?oauth_token={$this->user->requestToken}"; - } - - /** - * Sets the adapter for use with the API - */ - public function setAdapter($adapter=null) { - if (empty($adapter)) { - $serviceProvider = new AWeberServiceProvider(); - $adapter = new OAuthApplication($serviceProvider); - $adapter->consumerKey = $this->consumerKey; - $adapter->consumerSecret = $this->consumerSecret; - } - $this->adapter = $adapter; - } - - /** - * Fetches account data for the associated account - * - * @param String Access Token (Only optional/cached if you called getAccessToken() earlier - * on the same page) - * @param String Access Token Secret (Only optional/cached if you called getAccessToken() earlier - * on the same page) - * @return Object AWeberCollection Object with the requested - * account data - */ - public function getAccount($token=false, $secret=false) { - if ($token && $secret) { - $user = new OAuthUser(); - $user->accessToken = $token; - $user->tokenSecret = $secret; - $this->adapter->user = $user; - } - - $body = $this->adapter->request('GET', '/accounts'); - $accounts = $this->readResponse($body, '/accounts'); - return $accounts[0]; - } - - /** - * PHP Automagic - */ - public function __get($item) { - if ($item == 'user') return $this->adapter->user; - trigger_error("Could not find \"{$item}\""); - } - - /** - * Request a request token from AWeber and associate the - * provided $callbackUrl with the new token - * @param String The URL where users should be redirected - * once they authorize your app - * @return Array Contains the request token as the first item - * and the request token secret as the second item of the array - */ - public function getRequestToken($callbackUrl) { - $requestToken = $this->adapter->getRequestToken($callbackUrl); - return array($requestToken, $this->user->tokenSecret); - } - - /** - * Request an access token using the request tokens stored in the - * current user object. You would want to first set the request tokens - * on the user before calling this function via: - * - * $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; - * $aweber->user->requestToken = $_GET['oauth_token']; - * $aweber->user->verifier = $_GET['oauth_verifier']; - * - * @return Array Contains the access token as the first item - * and the access token secret as the second item of the array - */ - public function getAccessToken() { - return $this->adapter->getAccessToken(); - } -} - -?> diff --git a/tests/all_tests.php b/tests/all_tests.php index 45e848f..46988f0 100644 --- a/tests/all_tests.php +++ b/tests/all_tests.php @@ -7,10 +7,12 @@ require_once('oauth_application.test.php'); require_once('aweber_collection.test.php'); require_once('aweber_entry.test.php'); +require_once('multi_version.test.php'); $test = &new GroupTest('All tests'); $test->addTestCase(new TestAWeberAPI()); $test->addTestCase(new TestOAuthAppliation()); +$test->addTestCase(new TestMultipleInstalledVersions()); $test->addTestCase(new TestAWeberCollection()); $test->addTestCase(new TestAWeberCollectionFind()); $test->addTestCase(new TestAWeberEntry()); diff --git a/tests/multi_version.test.php b/tests/multi_version.test.php new file mode 100644 index 0000000..f8a5aa1 --- /dev/null +++ b/tests/multi_version.test.php @@ -0,0 +1,35 @@ + $type, 'msg' => $msg)); +} + + +class TestMultipleInstalledVersions extends UnitTestCase { + + public function setUp() { + global $errors; + $errors = array(); + } + + /** + * tests that multiple includes would raise a E_USER_WARNING + */ + public function test_multiple_includes() { + global $errors; + set_error_handler("myErrorHandler"); + include("../aweber_api/aweber_api.php"); + restore_error_handler(); + + $this->assertEqual(count($errors), 1); + $this->assertEqual($errors[0]['type'], E_USER_WARNING); + $this->assertEqual($errors[0]['msg'], 'Duplicate: Another AWeberAPI client library is already in scope.'); + } +} +?> From 8c47cb2264fcda30862273864e40f11bfa2762b6 Mon Sep 17 00:00:00 2001 From: "Edward F. Long, Jr" Date: Fri, 23 Dec 2011 11:56:34 -0500 Subject: [PATCH 027/112] modified AWeberCollection to use the self_link of the AWeberEntry resource contained in a collection as its url instead of attempting to derive it. --- README | 3 +++ aweber_api/aweber_collection.php | 14 +++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/README b/README index d270de0..c6226f3 100644 --- a/README +++ b/README @@ -5,6 +5,9 @@ PHP library for easily integrating with the AWeber API. Changelog: ---------- +2011-12-23: v1.1.2 + * Fixed a bug in the AWeberCollection class to properly set the URL of entries found in collections. + 2011-10-10: v1.1.1 * Raise an E_USER_WARNING instead of a fatal error if multiple instances of the client library are installed. diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index 171fdf5..e1609e6 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -214,7 +214,7 @@ protected function _getEntry($offset) { * _makeEntry * * Creates an entry object from the given entry data. Optionally can take - * the id and URL of the entry, though that data can be infered from the + * the id AND URL of the entry, though that data can be infered from the * context in which _makeEntry is being called. * * @param mixed $data Array of data returned from an API request for @@ -224,17 +224,17 @@ protected function _getEntry($offset) { * @access protected * @return void */ - protected function _makeEntry($data, $id = false, $url= false) { - if (!$id) { - $id = $data['id']; - } - if (!$url) { + protected function _makeEntry($data, $id = false, $url = false) { + if ((!$url) or (!$id)) { + // if either the url or id is omitted, grab the url from the + // self_link of the resource + $url = $this->adapter->app->removeBaseUri($data['self_link']); + } else { $url = "{$this->url}/{$id}"; } return new AWeberEntry($data, $url, $this->adapter); } - /** * ArrayAccess interface methods * From a86d75e68ececec3324b3ee65c5e07d83f051c69 Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Tue, 3 Apr 2012 14:37:24 -0400 Subject: [PATCH 028/112] Add build directory and config files for build targets. build.xml contains the ant targets to be run by developers and jenkins. build directory contains the logs and config files for the various build target utilities. --- build.xml | 150 ++++++++++++++++++++++++++++++++++++++++++++++ build/phpcs.xml | 5 ++ build/phpmd.xml | 25 ++++++++ build/phpunit.xml | 14 +++++ 4 files changed, 194 insertions(+) create mode 100644 build.xml create mode 100644 build/phpcs.xml create mode 100644 build/phpmd.xml create mode 100644 build/phpunit.xml diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..f3b34d7 --- /dev/null +++ b/build.xml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/phpcs.xml b/build/phpcs.xml new file mode 100644 index 0000000..77ff2c8 --- /dev/null +++ b/build/phpcs.xml @@ -0,0 +1,5 @@ + + + A custom coding standard. + + diff --git a/build/phpmd.xml b/build/phpmd.xml new file mode 100644 index 0000000..2ad0db5 --- /dev/null +++ b/build/phpmd.xml @@ -0,0 +1,25 @@ + + + + My custom rule set that checks my code... + + + + + + + + + + + + + + + diff --git a/build/phpunit.xml b/build/phpunit.xml new file mode 100644 index 0000000..6674622 --- /dev/null +++ b/build/phpunit.xml @@ -0,0 +1,14 @@ + + + + + + + + + tests/ + + + From d9e44c7c865d2e52b04cb39c8d664d771763e185 Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Tue, 3 Apr 2012 14:54:33 -0400 Subject: [PATCH 029/112] Rename test files to conform to phpunit format. --- tests/{aweber_api.test.php => AWeberAPITest.php} | 0 tests/{aweber_collection.test.php => AWeberCollectionTest.php} | 0 tests/{aweber_entry.test.php => AWeberEntryTest.php} | 0 tests/{multi_version.test.php => MultiVersionTest.php} | 2 +- tests/{oauth_application.test.php => OAuthApplicationTest.php} | 0 5 files changed, 1 insertion(+), 1 deletion(-) rename tests/{aweber_api.test.php => AWeberAPITest.php} (100%) rename tests/{aweber_collection.test.php => AWeberCollectionTest.php} (100%) rename tests/{aweber_entry.test.php => AWeberEntryTest.php} (100%) rename tests/{multi_version.test.php => MultiVersionTest.php} (94%) rename tests/{oauth_application.test.php => OAuthApplicationTest.php} (100%) diff --git a/tests/aweber_api.test.php b/tests/AWeberAPITest.php similarity index 100% rename from tests/aweber_api.test.php rename to tests/AWeberAPITest.php diff --git a/tests/aweber_collection.test.php b/tests/AWeberCollectionTest.php similarity index 100% rename from tests/aweber_collection.test.php rename to tests/AWeberCollectionTest.php diff --git a/tests/aweber_entry.test.php b/tests/AWeberEntryTest.php similarity index 100% rename from tests/aweber_entry.test.php rename to tests/AWeberEntryTest.php diff --git a/tests/multi_version.test.php b/tests/MultiVersionTest.php similarity index 94% rename from tests/multi_version.test.php rename to tests/MultiVersionTest.php index f8a5aa1..514070a 100644 --- a/tests/multi_version.test.php +++ b/tests/MultiVersionTest.php @@ -24,7 +24,7 @@ public function setUp() { public function test_multiple_includes() { global $errors; set_error_handler("myErrorHandler"); - include("../aweber_api/aweber_api.php"); + include("aweber_api/aweber_api.php"); restore_error_handler(); $this->assertEqual(count($errors), 1); diff --git a/tests/oauth_application.test.php b/tests/OAuthApplicationTest.php similarity index 100% rename from tests/oauth_application.test.php rename to tests/OAuthApplicationTest.php From 2aed94ab4647dd7773115a190de45776d721274f Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Tue, 3 Apr 2012 15:13:58 -0400 Subject: [PATCH 030/112] Add mock_data dependency to mock_adapter. --- tests/mock_adapter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php index 876e049..8bc1634 100644 --- a/tests/mock_adapter.php +++ b/tests/mock_adapter.php @@ -1,4 +1,5 @@ Date: Tue, 3 Apr 2012 15:15:16 -0400 Subject: [PATCH 031/112] Get AWeberAPITest passing. Replace assertEqual with assertEquals. Add dependencies to AWeberAPITest --- tests/AWeberAPITest.php | 16 ++--- tests/AWeberCollectionTest.php | 100 +++++++++++++++--------------- tests/AWeberEntryTest.php | 108 ++++++++++++++++----------------- tests/MultiVersionTest.php | 8 +-- tests/OAuthApplicationTest.php | 36 +++++------ 5 files changed, 135 insertions(+), 133 deletions(-) diff --git a/tests/AWeberAPITest.php b/tests/AWeberAPITest.php index f85a394..15ec63d 100644 --- a/tests/AWeberAPITest.php +++ b/tests/AWeberAPITest.php @@ -1,6 +1,8 @@ adapter = get_mock_adapter(); @@ -21,8 +23,8 @@ public function setUp() { * App keys given at construction should be maintained internally */ public function test_should_contain_app_keys() { - $this->assertEqual($this->aweber->consumerKey, $this->app['key']); - $this->assertEqual($this->aweber->consumerSecret, $this->app['secret']); + $this->assertEquals($this->aweber->consumerKey, $this->app['key']); + $this->assertEquals($this->aweber->consumerSecret, $this->app['secret']); } /** @@ -30,7 +32,7 @@ public function test_should_contain_app_keys() { */ public function test_should_allow_setting_oauth_adapter() { $this->aweber->setAdapter($this->adapter); - $this->assertEqual($this->aweber->adapter, $this->adapter); + $this->assertEquals($this->aweber->adapter, $this->adapter); } /** @@ -51,7 +53,7 @@ public function test_should_work_after_authorization() { $this->aweber->setAdapter($this->adapter); $account = $this->aweber->getAccount($this->user['token'], $this->user['secret']); $list = $account->lists->getById(303449); - $this->assertEqual($list->id, 303449); + $this->assertEquals($list->id, 303449); } /** @@ -77,8 +79,8 @@ public function test_loadFromUrl() { $list = $this->aweber->loadFromUrl('/accounts/1/lists/303449'); $this->assertTrue(is_a($list, 'AWeberEntry')); - $this->assertEqual($list->type, 'list'); - $this->assertEqual($list->id, '303449'); + $this->assertEquals($list->type, 'list'); + $this->assertEquals($list->id, '303449'); } } diff --git a/tests/AWeberCollectionTest.php b/tests/AWeberCollectionTest.php index 2a1c503..c1d92ac 100644 --- a/tests/AWeberCollectionTest.php +++ b/tests/AWeberCollectionTest.php @@ -1,6 +1,6 @@ adapter = get_mock_adapter(); @@ -26,20 +26,20 @@ public function testFind_ReturnsEntries() { # Asserts on the API request $expected_url = $this->subscribers->url . '?email=someone%40example.com&ws.op=find'; - $this->assertEqual(sizeOf($this->adapter->requestsMade), 2); + $this->assertEquals(sizeOf($this->adapter->requestsMade), 2); $req = $this->adapter->requestsMade[0]; - $this->assertEqual($req['method'], 'GET'); - $this->assertEqual($req['uri'], $expected_url); + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], $expected_url); $req = $this->adapter->requestsMade[1]; - $this->assertEqual($req['method'], 'GET'); - $this->assertEqual($req['uri'], $expected_url . "&ws.show=total_size"); + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], $expected_url . "&ws.show=total_size"); # Asserts on the returned data $this->assertTrue(is_a($found_subscribers, 'AWeberCollection')); - $this->assertEqual($this->adapter, $found_subscribers->adapter); - $this->assertEqual($found_subscribers->url, $this->subscribers->url); - $this->assertEqual($found_subscribers->total_size, 1); + $this->assertEquals($this->adapter, $found_subscribers->adapter); + $this->assertEquals($found_subscribers->url, $this->subscribers->url); + $this->assertEquals($found_subscribers->total_size, 1); } /** @@ -51,25 +51,25 @@ public function testFindDoesNot_ReturnsEntries() { # Asserts on the API request $expected_url = $this->subscribers->url . '?email=nonexist%40example.com&ws.op=find'; - $this->assertEqual(sizeOf($this->adapter->requestsMade), 2); + $this->assertEquals(sizeOf($this->adapter->requestsMade), 2); $req = $this->adapter->requestsMade[0]; - $this->assertEqual($req['method'], 'GET'); - $this->assertEqual($req['uri'], $expected_url); + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], $expected_url); $req = $this->adapter->requestsMade[1]; - $this->assertEqual($req['method'], 'GET'); - $this->assertEqual($req['uri'], $expected_url . "&ws.show=total_size"); + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], $expected_url . "&ws.show=total_size"); # Asserts on the returned data $this->assertTrue(is_a($found_subscribers, 'AWeberCollection')); - $this->assertEqual($this->adapter, $found_subscribers->adapter); - $this->assertEqual($found_subscribers->url, $this->subscribers->url); - $this->assertEqual($found_subscribers->total_size, 0); + $this->assertEquals($this->adapter, $found_subscribers->adapter); + $this->assertEquals($found_subscribers->url, $this->subscribers->url); + $this->assertEquals($found_subscribers->total_size, 0); } } -class TestAWeberCreateEntry extends UnitTestCase { +class TestAWeberCreateEntry extends PHPUnit_Framework_TestCase { public function setUp() { $this->adapter = get_mock_adapter(); @@ -90,22 +90,22 @@ public function testCreate_Success() { $resp = $this->custom_fields->create(array('name' => 'AwesomeField')); - $this->assertEqual(sizeOf($this->adapter->requestsMade), 2); + $this->assertEquals(sizeOf($this->adapter->requestsMade), 2); $req = $this->adapter->requestsMade[0]; - $this->assertEqual($req['method'], 'POST'); - $this->assertEqual($req['uri'], $this->custom_fields->url); - $this->assertEqual($req['data'], array( + $this->assertEquals($req['method'], 'POST'); + $this->assertEquals($req['uri'], $this->custom_fields->url); + $this->assertEquals($req['data'], array( 'ws.op' => 'create', 'name' => 'AwesomeField')); $req = $this->adapter->requestsMade[1]; - $this->assertEqual($req['method'], 'GET'); - $this->assertEqual($req['uri'], '/accounts/1/lists/303449/custom_fields/2'); + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], '/accounts/1/lists/303449/custom_fields/2'); } } -class TestAWeberCollection extends UnitTestCase { +class TestAWeberCollection extends PHPUnit_Framework_TestCase { /** * Run before each test. Sets up mock adapter, which uses fixture @@ -122,14 +122,14 @@ public function setUp() { * Should have the total size available. */ public function testShouldHaveTotalSize() { - $this->assertEqual($this->collection->total_size, 24); + $this->assertEquals($this->collection->total_size, 24); } /** - * Should have the URL used to generate this collection + * Should have the URL used to generate this collection */ public function testShouldHaveURL() { - $this->assertEqual($this->collection->url, $this->url); + $this->assertEquals($this->collection->url, $this->url); } /** @@ -147,11 +147,11 @@ public function testShouldAccessEntiresAsArray() { $entry = $this->collection[0]; $this->assertTrue(is_a($entry, 'AWeberResponse')); $this->assertTrue(is_a($entry, 'AWeberEntry')); - $this->assertEqual($entry->id, 1701533); + $this->assertEquals($entry->id, 1701533); } public function testShouldKnowItsCollectionType() { - $this->assertEqual($this->collection->type, 'lists'); + $this->assertEquals($this->collection->type, 'lists'); } /** @@ -167,20 +167,20 @@ public function testShouldNotAccessEntriesOutOfRange() { */ public function testShouldLazilyLoadAdditionalPages() { $this->adapter->clearRequests(); - - $this->assertEqual(sizeof($this->collection->data['entries']), 20); + + $this->assertEquals(sizeof($this->collection->data['entries']), 20); $entry = $this->collection[19]; - $this->assertEqual($entry->id, 1424745); + $this->assertEquals($entry->id, 1424745); $this->assertTrue(empty($this->adapter->requestsMade)); $entry = $this->collection[20]; - $this->assertEqual($entry->id, 1364473); - $this->assertEqual(count($this->adapter->requestsMade), 1); + $this->assertEquals($entry->id, 1364473); + $this->assertEquals(count($this->adapter->requestsMade), 1); $entry = $this->collection[21]; - $this->assertEqual($entry->id, 1211626); - $this->assertEqual(count($this->adapter->requestsMade), 1); + $this->assertEquals($entry->id, 1211626); + $this->assertEquals(count($this->adapter->requestsMade), 1); } /** @@ -197,10 +197,10 @@ public function testShouldBeAnIterator() { public function testShouldAllowIteration() { $count = 0; foreach ($this->collection as $index => $entry) { - $this->assertEqual($index, $count); + $this->assertEquals($index, $count); $count++; } - $this->assertEqual($count, $this->collection->total_size); + $this->assertEquals($count, $this->collection->total_size); } /** @@ -212,28 +212,28 @@ public function testShouldAllowGetById() { $this->adapter->clearRequests(); $entry = $this->collection->getById($id); - $this->assertEqual($entry->id, $id); - $this->assertEqual($entry->name, $name); + $this->assertEquals($entry->id, $id); + $this->assertEquals($entry->name, $name); $this->assertTrue(is_a($entry, 'AWeberEntry')); - $this->assertEqual(count($this->adapter->requestsMade), 1); + $this->assertEquals(count($this->adapter->requestsMade), 1); - $this->assertEqual($this->adapter->requestsMade[0]['uri'], + $this->assertEquals($this->adapter->requestsMade[0]['uri'], '/accounts/1/lists/303449'); } /** - * Should implement the countable interface, allowing count() and sizeOf() + * Should implement the countable interface, allowing count() and sizeOf() * functions to work properly */ public function testShouldAllowCountOperations() { - $this->assertEqual(count($this->collection), $this->collection->total_size); - $this->assertEqual(sizeOf($this->collection), $this->collection->total_size); + $this->assertEquals(count($this->collection), $this->collection->total_size); + $this->assertEquals(sizeOf($this->collection), $this->collection->total_size); } } -class TestGettingCollectionParentEntry extends UnitTestCase { +class TestGettingCollectionParentEntry extends PHPUnit_Framework_TestCase { public function setUp() { $this->adapter = get_mock_adapter(); @@ -251,17 +251,17 @@ public function setUp() { public function testListsParentShouldBeAccount() { $entry = $this->lists->getParentEntry(); $this->assertTrue(is_a($entry, 'AWeberEntry')); - $this->assertEqual($entry->type, 'account'); + $this->assertEquals($entry->type, 'account'); } public function testCustomFieldsParentShouldBeList() { $entry = $this->customFields->getParentEntry(); $this->assertTrue(is_a($entry, 'AWeberEntry')); - $this->assertEqual($entry->type, 'list'); + $this->assertEquals($entry->type, 'list'); } public function testAccountsParentShouldBeNULL() { $entry = $this->accounts->getParentEntry(); - $this->assertEqual($entry, NULL); + $this->assertEquals($entry, NULL); } } diff --git a/tests/AWeberEntryTest.php b/tests/AWeberEntryTest.php index fb08ad3..9f0e292 100644 --- a/tests/AWeberEntryTest.php +++ b/tests/AWeberEntryTest.php @@ -1,7 +1,7 @@ assertEqual($this->entry->id, 303449); + $this->assertEquals($this->entry->id, 303449); } /** * Should be able to access name (or any property unique to the response) */ public function testShouldBeAbleToAccessName() { - $this->assertEqual($this->entry->name, 'default303449'); + $this->assertEquals($this->entry->name, 'default303449'); } /** * Should be able to discern its type based on its data */ public function testShouldKnowItsType() { - $this->assertEqual($this->entry->type, 'list'); + $this->assertEquals($this->entry->type, 'list'); } /** * When access properties it does not have, but are known sub collections, - * it will request for it and return the new collection object. + * it will request for it and return the new collection object. */ public function testShouldProvidedCollections() { $this->adapter->clearRequests(); $campaigns = $this->entry->campaigns; $this->assertTrue(is_a($campaigns, 'AWeberCollection')); - $this->assertEqual(count($this->adapter->requestsMade), 1); - $this->assertEqual($this->adapter->requestsMade[0]['uri'], + $this->assertEquals(count($this->adapter->requestsMade), 1); + $this->assertEquals($this->adapter->requestsMade[0]['uri'], '/accounts/1/lists/303449/campaigns'); } @@ -71,14 +71,14 @@ public function testShouldThrowExceptionIfNotImplemented() { $this->adapter->clearRequests(); $this->expectException(AWeberResourceNotImplemented); $obj = $this->entry->something_not_implemented; - $this->assertEqual(count($this->adapter->requestsMade), 0); + $this->assertEquals(count($this->adapter->requestsMade), 0); } /** * Should return the name of all attributes and collections in this entry */ public function testAttrs() { - $this->assertEqual($this->entry->attrs(), + $this->assertEquals($this->entry->attrs(), array( 'id' => 303449, 'name' => 'default303449', @@ -100,9 +100,9 @@ public function testDelete() { $this->adapter->clearRequests(); $resp = $this->entry->delete(); $this->assertIdentical($resp, true); - $this->assertEqual(sizeOf($this->adapter->requestsMade), 1); - $this->assertEqual($this->adapter->requestsMade[0]['method'], 'DELETE'); - $this->assertEqual($this->adapter->requestsMade[0]['uri'], $this->entry->url); + $this->assertEquals(sizeOf($this->adapter->requestsMade), 1); + $this->assertEquals($this->adapter->requestsMade[0]['method'], 'DELETE'); + $this->assertEquals($this->adapter->requestsMade[0]['uri'], $this->entry->url); } /** @@ -121,14 +121,14 @@ public function testFailedDelete() { /** * Should be able to change a property in an entry's data array directly on * the object, and have that change propogate to its data array - * + * */ public function testSet() { $this->assertNotEqual($this->entry->name, 'mynewlistname'); $this->assertNotEqual($this->entry->data['name'], 'mynewlistname'); $this->entry->name = 'mynewlistname'; - $this->assertEqual($this->entry->name, 'mynewlistname'); - $this->assertEqual($this->entry->data['name'], 'mynewlistname'); + $this->assertEquals($this->entry->name, 'mynewlistname'); + $this->assertEquals($this->entry->data['name'], 'mynewlistname'); } /** @@ -138,11 +138,11 @@ public function testSave() { $this->entry->name = 'mynewlistname'; $this->adapter->clearRequests(); $resp = $this->entry->save(); - $this->assertEqual(sizeOf($this->adapter->requestsMade), 1); + $this->assertEquals(sizeOf($this->adapter->requestsMade), 1); $req = $this->adapter->requestsMade[0]; - $this->assertEqual($req['method'], 'PATCH'); - $this->assertEqual($req['uri'], $this->entry->url); - $this->assertEqual($req['data'], array('name' => 'mynewlistname')); + $this->assertEquals($req['method'], 'PATCH'); + $this->assertEquals($req['uri'], $this->entry->url); + $this->assertEquals($req['data'], array('name' => 'mynewlistname')); $this->assertIdentical($resp, true); } @@ -163,18 +163,18 @@ public function testSaveFailed() { public function testShouldMaintainDirtiness() { $this->adapter->clearRequests(); $resp = $this->entry->save(); - $this->assertEqual(sizeOf($this->adapter->requestsMade), 0); + $this->assertEquals(sizeOf($this->adapter->requestsMade), 0); $this->entry->name = 'mynewlistname'; $resp = $this->entry->save(); - $this->assertEqual(sizeOf($this->adapter->requestsMade), 1); + $this->assertEquals(sizeOf($this->adapter->requestsMade), 1); $resp = $this->entry->save(); - $this->assertEqual(sizeOf($this->adapter->requestsMade), 1); + $this->assertEquals(sizeOf($this->adapter->requestsMade), 1); } } -class AccountTestCase extends UnitTestCase { +class AccountTestCase extends PHPUnit_Framework_TestCase { public function setUp() { $this->adapter = get_mock_adapter(); @@ -190,14 +190,14 @@ public function setUp() { * Account entries have a handful of special named operations. This asserts * that they behave as expected. * - * @uses UnitTestCase - * @package + * @uses PHPUnit_Framework_TestCase + * @package * @version $id$ */ class TestAWeberAccountEntry extends AccountTestCase { public function testIsAccount() { - $this->assertEqual($this->entry->type, 'account'); + $this->assertEquals($this->entry->type, 'account'); } } @@ -213,7 +213,7 @@ public function testShouldReturnArray() { } public function testShouldHaveCorrectCountOfEntries() { - $this->assertEqual(sizeOf($this->forms), 181); + $this->assertEquals(sizeOf($this->forms), 181); } public function testShouldHaveEntries() { @@ -241,7 +241,7 @@ public function testShouldReturnArray() { } public function testShouldHaveCorrectCountOfEntries() { - $this->assertEqual(sizeOf($this->forms), 10); + $this->assertEquals(sizeOf($this->forms), 10); } public function testShouldHaveEntries() { @@ -262,13 +262,13 @@ class TestAccountFindSubscribers extends AccountTestCase { public function testShouldSupportFindSubscribersMethod() { $subscribers = $this->entry->findSubscribers(array('email' => 'joe@example.com')); $this->assertTrue(is_a($subscribers, 'AWeberCollection')); - $this->assertEqual(count($subscribers), 1); - $this->assertEqual($subscribers->data['entries'][0]['self_link'], + $this->assertEquals(count($subscribers), 1); + $this->assertEquals($subscribers->data['entries'][0]['self_link'], 'https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/1'); } } -class TestAWeberSubscriberEntry extends UnitTestCase { +class TestAWeberSubscriberEntry extends PHPUnit_Framework_TestCase { public function setUp() { $this->adapter = get_mock_adapter(); @@ -278,7 +278,7 @@ public function setUp() { } public function testIsSubscriber() { - $this->assertEqual($this->entry->type, 'subscriber'); + $this->assertEquals($this->entry->type, 'subscriber'); } public function testHasCustomFields() { @@ -287,18 +287,18 @@ public function testHasCustomFields() { } public function testCanReadCustomFields() { - $this->assertEqual($this->entry->custom_fields['Color'], 'blue'); - $this->assertEqual($this->entry->custom_fields['Walruses'], '32'); + $this->assertEquals($this->entry->custom_fields['Color'], 'blue'); + $this->assertEquals($this->entry->custom_fields['Walruses'], '32'); } public function testCanUpdateCustomFields() { $this->entry->custom_fields['Color'] = 'Jeep'; $this->entry->custom_fields['Walruses'] = 'Cherokee'; - $this->assertEqual($this->entry->custom_fields['Color'], 'Jeep'); + $this->assertEquals($this->entry->custom_fields['Color'], 'Jeep'); } public function testCanViewSizeOfCustomFields() { - $this->assertEqual(sizeOf($this->entry->custom_fields), 6); + $this->assertEquals(sizeOf($this->entry->custom_fields), 6); } public function testCanIterateOverCustomFields() { @@ -306,7 +306,7 @@ public function testCanIterateOverCustomFields() { foreach ($this->entry->custom_fields as $field => $value) { $count++; } - $this->assertEqual($count, sizeOf($this->entry->custom_fields)); + $this->assertEquals($count, sizeOf($this->entry->custom_fields)); } public function testShouldBeUpdatable() { @@ -314,17 +314,17 @@ public function testShouldBeUpdatable() { $this->entry->custom_fields['Color'] = 'Jeep'; $this->entry->save(); $data = $this->adapter->requestsMade[0]['data']; - $this->assertEqual($data['custom_fields']['Color'], 'Jeep'); + $this->assertEquals($data['custom_fields']['Color'], 'Jeep'); } public function testShouldSupportGetActivity() { $activity = $this->entry->getActivity(); $this->assertTrue(is_a($activity, 'AWeberCollection')); - $this->assertEqual($activity->total_size, 1); + $this->assertEquals($activity->total_size, 1); } } -class TestAWeberMoveEntry extends UnitTestCase { +class TestAWeberMoveEntry extends PHPUnit_Framework_TestCase { public function setUp() { $this->adapter = get_mock_adapter(); @@ -352,18 +352,18 @@ public function testMove_Success() { $this->adapter->clearRequests(); $resp = $this->subscriber->move($this->different_list); - $this->assertEqual(sizeOf($this->adapter->requestsMade), 2); + $this->assertEquals(sizeOf($this->adapter->requestsMade), 2); $req = $this->adapter->requestsMade[0]; - $this->assertEqual($req['method'], 'POST'); - $this->assertEqual($req['uri'], $this->subscriber->url); - $this->assertEqual($req['data'], array( + $this->assertEquals($req['method'], 'POST'); + $this->assertEquals($req['uri'], $this->subscriber->url); + $this->assertEquals($req['data'], array( 'ws.op' => 'move', 'list_link' => $this->different_list->self_link)); $req = $this->adapter->requestsMade[1]; - $this->assertEqual($req['method'], 'GET'); - $this->assertEqual($req['uri'], '/accounts/1/lists/505454/subscribers/3'); + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], '/accounts/1/lists/505454/subscribers/3'); } /** @@ -374,19 +374,19 @@ public function testMove_Failure() { $this->adapter->clearRequests(); $this->expectException(AWeberAPIException, "SimulatedException"); $this->unsubscribed->move($this->different_list); - $this->assertEqual(sizeOf($this->adapter->requestsMade), 1); + $this->assertEquals(sizeOf($this->adapter->requestsMade), 1); $req = $this->adapter->requestsMade[0]; - $this->assertEqual($req['method'], 'POST'); - $this->assertEqual($req['uri'], $this->unsubscribed->url); - $this->assertEqual($req['data'], array( + $this->assertEquals($req['method'], 'POST'); + $this->assertEquals($req['uri'], $this->unsubscribed->url); + $this->assertEquals($req['data'], array( 'ws.op' => 'move', 'list_link' => $this->different_list->self_link)); return; } } -class TestGettingEntryParentEntry extends UnitTestCase { +class TestGettingEntryParentEntry extends PHPUnit_Framework_TestCase { public function setUp() { $this->adapter = get_mock_adapter(); @@ -404,17 +404,17 @@ public function setUp() { public function testListParentShouldBeAccount() { $entry = $this->list->getParentEntry(); $this->assertTrue(is_a($entry, 'AWeberEntry')); - $this->assertEqual($entry->type, 'account'); + $this->assertEquals($entry->type, 'account'); } public function testCustomFieldParentShouldBeList() { $entry = $this->customField->getParentEntry(); $this->assertTrue(is_a($entry, 'AWeberEntry')); - $this->assertEqual($entry->type, 'list'); + $this->assertEquals($entry->type, 'list'); } public function testAccountParentShouldBeNULL() { $entry = $this->account->getParentEntry(); - $this->assertEqual($entry, NULL); + $this->assertEquals($entry, NULL); } } diff --git a/tests/MultiVersionTest.php b/tests/MultiVersionTest.php index 514070a..a4c9ef2 100644 --- a/tests/MultiVersionTest.php +++ b/tests/MultiVersionTest.php @@ -11,7 +11,7 @@ function myErrorHandler($type, $msg, $errfile, $errline) { } -class TestMultipleInstalledVersions extends UnitTestCase { +class TestMultipleInstalledVersions extends PHPUnit_Framework_TestCase { public function setUp() { global $errors; @@ -27,9 +27,9 @@ public function test_multiple_includes() { include("aweber_api/aweber_api.php"); restore_error_handler(); - $this->assertEqual(count($errors), 1); - $this->assertEqual($errors[0]['type'], E_USER_WARNING); - $this->assertEqual($errors[0]['msg'], 'Duplicate: Another AWeberAPI client library is already in scope.'); + $this->assertEquals(count($errors), 1); + $this->assertEquals($errors[0]['type'], E_USER_WARNING); + $this->assertEquals($errors[0]['msg'], 'Duplicate: Another AWeberAPI client library is already in scope.'); } } ?> diff --git a/tests/OAuthApplicationTest.php b/tests/OAuthApplicationTest.php index 61c5482..c7f2b5d 100644 --- a/tests/OAuthApplicationTest.php +++ b/tests/OAuthApplicationTest.php @@ -3,7 +3,7 @@ class Object {} } -class TestOAuthAppliation extends UnitTestCase { +class TestOAuthAppliation extends PHPUnit_Framework_TestCase { public function setUp() { $this->oauth = new OAuthApplication($parentApp); @@ -35,7 +35,7 @@ public function testAddGetParams() { 'keyB' => 'yet another value', ); - $this->assertEqual( + $this->assertEquals( 'keyA=Some%20Value&keyB=yet%20another%20value&keyC=some%20other%20value', $this->oauth->buildData($data)); } @@ -101,7 +101,7 @@ public function testCreateSignatureUniqueness() { $sigKey = 'gdgdfet4gdffgd4etgr'; // Random string as well $signature = $this->oauth->createSignature($sigBase, $sigKey); $signature2 = $this->oauth->createSignature($sigBase, $sigKey); - $this->assertEqual($signature, $signature2, 'Signatures with same parameters are identical.'); + $this->assertEquals($signature, $signature2, 'Signatures with same parameters are identical.'); $sigKey = $sigKey.'1'; $sig3 = $this->oauth->createSignature($sigBase, $sigKey); @@ -118,11 +118,11 @@ public function testCreateSignatureUniqueness() { */ public function testGetVersion() { $version = $this->oauth->version; - $this->assertEqual($version, '1.0', 'Default version is 1.0'); + $this->assertEquals($version, '1.0', 'Default version is 1.0'); } /** - * testOAuthUser + * testOAuthUser * * Tests the the OAuthUser class exists and has all its necessary data * @access public @@ -157,7 +157,7 @@ protected function generateOAuthUser() { return array($user, $data); } - + /** * testCreatSignatureKey * @@ -170,12 +170,12 @@ public function testCreatSignatureKey() { $this->oauth->user = $user; $sigKey = $this->oauth->createSignatureKey(); - $this->assertEqual('CONSUMERSECRET&abcdefg', $sigKey); //, 'Signature key generated matches'); + $this->assertEquals('CONSUMERSECRET&abcdefg', $sigKey); //, 'Signature key generated matches'); } /** - * testGetOAuthRequestData - * + * testGetOAuthRequestData + * * @access public * @return void */ @@ -217,8 +217,8 @@ public function generateRequestData() { public function testMergeOAuthData() { list($mergeData, $requestData) = $this->generateRequestData(); - $this->assertEqual($mergeData['key1'], $requestData['key1']); - $this->assertEqual($mergeData['oauth_consumer_key'], $this->oauth->consumerKey); + $this->assertEquals($mergeData['key1'], $requestData['key1']); + $this->assertEquals($mergeData['oauth_consumer_key'], $this->oauth->consumerKey); } public function testCreateSignatureBase() { @@ -239,15 +239,15 @@ public function testSignRequest() { $signedData = $this->oauth->signRequest($method, $url, $data); foreach ($data as $key => $val) { - $this->assertEqual($signedData[$key], $val, 'Signed data has correct value for "'.$key.'"'); + $this->assertEquals($signedData[$key], $val, 'Signed data has correct value for "'.$key.'"'); } $this->assertTrue(!empty($signedData['oauth_signature'])); } /** - * testPrepareRequest - * + * testPrepareRequest + * * @access public * @return void */ @@ -258,7 +258,7 @@ public function testPrepareRequest() { $signedData = $this->oauth->prepareRequest($method, $url, $requestData); - // Test that a nonce and timestamp was generated, then remove the one from our base data so that we + // Test that a nonce and timestamp was generated, then remove the one from our base data so that we // don't try to compare the two. They should still be different. $this->assertTrue(!empty($signedData['oauth_nonce']), 'Verify nonce was generated'); $this->assertTrue(!empty($signedData['oauth_timestamp']), 'Verify nonce was generated'); @@ -266,15 +266,15 @@ public function testPrepareRequest() { unset($data['oauth_timestamp']); foreach ($data as $key => $val) { - $this->assertEqual($signedData[$key], $val, 'Signed data has correct value for "'.$key.'"'); + $this->assertEquals($signedData[$key], $val, 'Signed data has correct value for "'.$key.'"'); } $this->assertTrue(!empty($signedData['oauth_signature'])); } /** - * testParseResponse - * + * testParseResponse + * * @access public * @return void */ From 27eba6be2704072805f07899033ae5e98081d69a Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Tue, 3 Apr 2012 15:54:19 -0400 Subject: [PATCH 032/112] Break out TestAWeberCollectionFind class from AWeberCollectionTest file. --- tests/AWeberCollectionFindTest.php | 72 ++++++++++++++++++++++++++++++ tests/AWeberCollectionTest.php | 71 +---------------------------- 2 files changed, 74 insertions(+), 69 deletions(-) create mode 100644 tests/AWeberCollectionFindTest.php diff --git a/tests/AWeberCollectionFindTest.php b/tests/AWeberCollectionFindTest.php new file mode 100644 index 0000000..c526d34 --- /dev/null +++ b/tests/AWeberCollectionFindTest.php @@ -0,0 +1,72 @@ +adapter = get_mock_adapter(); + $this->subscribers = $this->_getCollection('/accounts/1/lists/303449/subscribers'); + $this->lists = $this->_getCollection('/accounts/1/lists'); + $this->adapter->clearRequests(); + } + + /** + * Return AWeberCollection + */ + public function _getCollection($url) { + $data = $this->adapter->request('GET', $url); + return new AWeberCollection($data, $url, $this->adapter); + } + + /** + * Find That Returns Entries + */ + public function testFind_ReturnsEntries() { + + $found_subscribers = $this->subscribers->find(array('email' => 'someone@example.com')); + + # Asserts on the API request + $expected_url = $this->subscribers->url . '?email=someone%40example.com&ws.op=find'; + $this->assertEquals(sizeOf($this->adapter->requestsMade), 2); + $req = $this->adapter->requestsMade[0]; + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], $expected_url); + + $req = $this->adapter->requestsMade[1]; + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], $expected_url . "&ws.show=total_size"); + + # Asserts on the returned data + $this->assertTrue(is_a($found_subscribers, 'AWeberCollection')); + $this->assertEquals($this->adapter, $found_subscribers->adapter); + $this->assertEquals($found_subscribers->url, $this->subscribers->url); + $this->assertEquals($found_subscribers->total_size, 1); + } + + /** + * Find That Does Not Return Entries + */ + public function testFindDoesNot_ReturnsEntries() { + + $found_subscribers = $this->subscribers->find(array('email' => 'nonexist@example.com')); + + # Asserts on the API request + $expected_url = $this->subscribers->url . '?email=nonexist%40example.com&ws.op=find'; + $this->assertEquals(sizeOf($this->adapter->requestsMade), 2); + $req = $this->adapter->requestsMade[0]; + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], $expected_url); + + $req = $this->adapter->requestsMade[1]; + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], $expected_url . "&ws.show=total_size"); + + # Asserts on the returned data + $this->assertTrue(is_a($found_subscribers, 'AWeberCollection')); + $this->assertEquals($this->adapter, $found_subscribers->adapter); + $this->assertEquals($found_subscribers->url, $this->subscribers->url); + $this->assertEquals($found_subscribers->total_size, 0); + } + +} diff --git a/tests/AWeberCollectionTest.php b/tests/AWeberCollectionTest.php index c1d92ac..e71936e 100644 --- a/tests/AWeberCollectionTest.php +++ b/tests/AWeberCollectionTest.php @@ -1,73 +1,6 @@ adapter = get_mock_adapter(); - $this->subscribers = $this->_getCollection('/accounts/1/lists/303449/subscribers'); - $this->lists = $this->_getCollection('/accounts/1/lists'); - $this->adapter->clearRequests(); - } - - /** - * Return AWeberCollection - */ - public function _getCollection($url) { - $data = $this->adapter->request('GET', $url); - return new AWeberCollection($data, $url, $this->adapter); - } - - /** - * Find That Returns Entries - */ - public function testFind_ReturnsEntries() { - - $found_subscribers = $this->subscribers->find(array('email' => 'someone@example.com')); - - # Asserts on the API request - $expected_url = $this->subscribers->url . '?email=someone%40example.com&ws.op=find'; - $this->assertEquals(sizeOf($this->adapter->requestsMade), 2); - $req = $this->adapter->requestsMade[0]; - $this->assertEquals($req['method'], 'GET'); - $this->assertEquals($req['uri'], $expected_url); - - $req = $this->adapter->requestsMade[1]; - $this->assertEquals($req['method'], 'GET'); - $this->assertEquals($req['uri'], $expected_url . "&ws.show=total_size"); - - # Asserts on the returned data - $this->assertTrue(is_a($found_subscribers, 'AWeberCollection')); - $this->assertEquals($this->adapter, $found_subscribers->adapter); - $this->assertEquals($found_subscribers->url, $this->subscribers->url); - $this->assertEquals($found_subscribers->total_size, 1); - } - - /** - * Find That Does Not Return Entries - */ - public function testFindDoesNot_ReturnsEntries() { - - $found_subscribers = $this->subscribers->find(array('email' => 'nonexist@example.com')); - - # Asserts on the API request - $expected_url = $this->subscribers->url . '?email=nonexist%40example.com&ws.op=find'; - $this->assertEquals(sizeOf($this->adapter->requestsMade), 2); - $req = $this->adapter->requestsMade[0]; - $this->assertEquals($req['method'], 'GET'); - $this->assertEquals($req['uri'], $expected_url); - - $req = $this->adapter->requestsMade[1]; - $this->assertEquals($req['method'], 'GET'); - $this->assertEquals($req['uri'], $expected_url . "&ws.show=total_size"); - - # Asserts on the returned data - $this->assertTrue(is_a($found_subscribers, 'AWeberCollection')); - $this->assertEquals($this->adapter, $found_subscribers->adapter); - $this->assertEquals($found_subscribers->url, $this->subscribers->url); - $this->assertEquals($found_subscribers->total_size, 0); - } - -} +require_once('aweber_api/aweber_api.php'); +require_once('mock_adapter.php'); class TestAWeberCreateEntry extends PHPUnit_Framework_TestCase { From d452c5c10dd28f8295f3ce45347d002b183dad3a Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Tue, 3 Apr 2012 15:57:15 -0400 Subject: [PATCH 033/112] Break out TestAWeberCreateEntry class into AWeberCreateEntryTest file. --- tests/AWeberCollectionTest.php | 36 ------------------------------ tests/AWeberCreateEntryTest.php | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 36 deletions(-) create mode 100644 tests/AWeberCreateEntryTest.php diff --git a/tests/AWeberCollectionTest.php b/tests/AWeberCollectionTest.php index e71936e..92b3cbe 100644 --- a/tests/AWeberCollectionTest.php +++ b/tests/AWeberCollectionTest.php @@ -2,42 +2,6 @@ require_once('aweber_api/aweber_api.php'); require_once('mock_adapter.php'); -class TestAWeberCreateEntry extends PHPUnit_Framework_TestCase { - - public function setUp() { - $this->adapter = get_mock_adapter(); - - # Get CustomFields - $url = '/accounts/1/lists/303449/custom_fields'; - $data = $this->adapter->request('GET', $url); - $this->custom_fields = new AWeberCollection($data, $url, $this->adapter); - - } - - /** - * Create Succeeded - */ - public function testCreate_Success() { - - $this->adapter->clearRequests(); - $resp = $this->custom_fields->create(array('name' => 'AwesomeField')); - - - $this->assertEquals(sizeOf($this->adapter->requestsMade), 2); - - $req = $this->adapter->requestsMade[0]; - $this->assertEquals($req['method'], 'POST'); - $this->assertEquals($req['uri'], $this->custom_fields->url); - $this->assertEquals($req['data'], array( - 'ws.op' => 'create', - 'name' => 'AwesomeField')); - - $req = $this->adapter->requestsMade[1]; - $this->assertEquals($req['method'], 'GET'); - $this->assertEquals($req['uri'], '/accounts/1/lists/303449/custom_fields/2'); - } -} - class TestAWeberCollection extends PHPUnit_Framework_TestCase { /** diff --git a/tests/AWeberCreateEntryTest.php b/tests/AWeberCreateEntryTest.php new file mode 100644 index 0000000..144279d --- /dev/null +++ b/tests/AWeberCreateEntryTest.php @@ -0,0 +1,39 @@ +adapter = get_mock_adapter(); + + # Get CustomFields + $url = '/accounts/1/lists/303449/custom_fields'; + $data = $this->adapter->request('GET', $url); + $this->custom_fields = new AWeberCollection($data, $url, $this->adapter); + + } + + /** + * Create Succeeded + */ + public function testCreate_Success() { + + $this->adapter->clearRequests(); + $resp = $this->custom_fields->create(array('name' => 'AwesomeField')); + + + $this->assertEquals(sizeOf($this->adapter->requestsMade), 2); + + $req = $this->adapter->requestsMade[0]; + $this->assertEquals($req['method'], 'POST'); + $this->assertEquals($req['uri'], $this->custom_fields->url); + $this->assertEquals($req['data'], array( + 'ws.op' => 'create', + 'name' => 'AwesomeField')); + + $req = $this->adapter->requestsMade[1]; + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], '/accounts/1/lists/303449/custom_fields/2'); + } +} From 968367990344987f827b9e1b658b8c1c7cd81437 Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Tue, 3 Apr 2012 16:02:13 -0400 Subject: [PATCH 034/112] Break out TestAWeberCollectionParentEntry into AWeberCollectionParentEntryTest file. --- tests/AWeberCollectionParentEntryTest.php | 36 +++++++++++++++++++++++ tests/AWeberCollectionTest.php | 33 --------------------- 2 files changed, 36 insertions(+), 33 deletions(-) create mode 100644 tests/AWeberCollectionParentEntryTest.php diff --git a/tests/AWeberCollectionParentEntryTest.php b/tests/AWeberCollectionParentEntryTest.php new file mode 100644 index 0000000..7730d96 --- /dev/null +++ b/tests/AWeberCollectionParentEntryTest.php @@ -0,0 +1,36 @@ +adapter = get_mock_adapter(); + $url = '/accounts/1/lists'; + $data = $this->adapter->request('GET', $url); + $this->lists = new AWeberCollection($data, $url, $this->adapter); + $url = '/accounts'; + $data = $this->adapter->request('GET', $url); + $this->accounts = new AWeberCollection($data, $url, $this->adapter); + $url = '/accounts/1/lists/303449/custom_fields'; + $data = $this->adapter->request('GET', $url); + $this->customFields = new AWeberCollection($data, $url, $this->adapter); + } + + public function testListsParentShouldBeAccount() { + $entry = $this->lists->getParentEntry(); + $this->assertTrue(is_a($entry, 'AWeberEntry')); + $this->assertEquals($entry->type, 'account'); + } + + public function testCustomFieldsParentShouldBeList() { + $entry = $this->customFields->getParentEntry(); + $this->assertTrue(is_a($entry, 'AWeberEntry')); + $this->assertEquals($entry->type, 'list'); + } + + public function testAccountsParentShouldBeNULL() { + $entry = $this->accounts->getParentEntry(); + $this->assertEquals($entry, NULL); + } +} diff --git a/tests/AWeberCollectionTest.php b/tests/AWeberCollectionTest.php index 92b3cbe..dd2718d 100644 --- a/tests/AWeberCollectionTest.php +++ b/tests/AWeberCollectionTest.php @@ -129,36 +129,3 @@ public function testShouldAllowCountOperations() { } } - -class TestGettingCollectionParentEntry extends PHPUnit_Framework_TestCase { - - public function setUp() { - $this->adapter = get_mock_adapter(); - $url = '/accounts/1/lists'; - $data = $this->adapter->request('GET', $url); - $this->lists = new AWeberCollection($data, $url, $this->adapter); - $url = '/accounts'; - $data = $this->adapter->request('GET', $url); - $this->accounts = new AWeberCollection($data, $url, $this->adapter); - $url = '/accounts/1/lists/303449/custom_fields'; - $data = $this->adapter->request('GET', $url); - $this->customFields = new AWeberCollection($data, $url, $this->adapter); - } - - public function testListsParentShouldBeAccount() { - $entry = $this->lists->getParentEntry(); - $this->assertTrue(is_a($entry, 'AWeberEntry')); - $this->assertEquals($entry->type, 'account'); - } - - public function testCustomFieldsParentShouldBeList() { - $entry = $this->customFields->getParentEntry(); - $this->assertTrue(is_a($entry, 'AWeberEntry')); - $this->assertEquals($entry->type, 'list'); - } - - public function testAccountsParentShouldBeNULL() { - $entry = $this->accounts->getParentEntry(); - $this->assertEquals($entry, NULL); - } -} From ac2d5133abefe4607dc11a39ad1578ebdb7ee5dd Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Tue, 3 Apr 2012 16:36:20 -0400 Subject: [PATCH 035/112] Convert OAuthApplication tests to phpunit. --- tests/OAuthApplicationTest.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/OAuthApplicationTest.php b/tests/OAuthApplicationTest.php index c7f2b5d..057a00c 100644 --- a/tests/OAuthApplicationTest.php +++ b/tests/OAuthApplicationTest.php @@ -1,4 +1,6 @@ oauth = new OAuthApplication($parentApp); $this->oauth->consumerSecret = 'CONSUMERSECRET'; $this->oauth->consumerKey = 'consumer_key'; @@ -84,7 +87,7 @@ public function testCreateSignature() { $sigBase = '342refd435gdfxw354xfbw364fdg'; // Random string $sigKey = 'gdgdfet4gdffgd4etgr'; // Random string as well $signature = $this->oauth->createSignature($sigBase, $sigKey); - $this->assertTrue($signature, 'Returns a valid signature'); + $this->assertNotEmpty($signature, 'Returns a valid signature'); $this->assertTrue(strpos($signature, $sigBase) === false, 'Signature does not contain base'); $this->assertTrue(strpos($signature, $sigKey) === false, 'Signature does not contain key'); } @@ -105,7 +108,7 @@ public function testCreateSignatureUniqueness() { $sigKey = $sigKey.'1'; $sig3 = $this->oauth->createSignature($sigBase, $sigKey); - $this->assertNotEqual($signature, $sig3, 'Changing key creates different signature'); + $this->assertNotEquals($signature, $sig3, 'Changing key creates different signature'); } @@ -199,7 +202,7 @@ public function testGetOAuthRequestData() { ksort($data); ksort($tempData); - $this->assertIdentical($data, $tempData, 'Aside from timestamp and nonce, the rest should be identical'); + $this->assertSame($data, $tempData, 'Aside from timestamp and nonce, the rest should be identical'); } public function generateRequestData() { @@ -227,7 +230,7 @@ public function testCreateSignatureBase() { $url = 'http://www.someservice.com/chicken-nuggets'; $baseString = $this->oauth->createSignatureBase($method, $url, $mergeData); - $this->assertTrue($baseString); + $this->assertNotEmpty($baseString); $this->assertTrue(strpos($baseString, $method) !== false); $this->assertTrue(strpos($baseString, urlencode($url))!== false); } @@ -287,8 +290,7 @@ public function testParseResponse() { 'oauth_token_secret' => 'GRRa1E7MMm526nql1hETKHMu2BvAXpvHaCu332TPAJ4', 'oauth_callback_confirmed' => 'true', ); - $this->assertIdentical($data, $dataShouldBe, 'Data is parsed correctly.'); + $this->assertSame($data, $dataShouldBe, 'Data is parsed correctly.'); } } -?> From be742a4478e887920d14011672130a100c9e37c7 Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Tue, 3 Apr 2012 16:37:51 -0400 Subject: [PATCH 036/112] Fix phpunit.xml config. --- build/phpunit.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/phpunit.xml b/build/phpunit.xml index 6674622..84f7b37 100644 --- a/build/phpunit.xml +++ b/build/phpunit.xml @@ -8,7 +8,7 @@ - tests/ + ../tests/ From 12ea57e44725b4afd3c67b5941915e98a9ef11d8 Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Thu, 5 Apr 2012 14:38:05 -0400 Subject: [PATCH 037/112] Convert AWeberEntryTest to use PHPUnit. --- aweber_api/exceptions.php | 2 +- tests/AWeberEntryTest.php | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/aweber_api/exceptions.php b/aweber_api/exceptions.php index 96acb41..5e24d89 100644 --- a/aweber_api/exceptions.php +++ b/aweber_api/exceptions.php @@ -22,7 +22,7 @@ public function __construct($error, $url) { // record specific details of the API exception for processing $this->url = $url; $this->type = $error['type']; - $this->status = $error['status']; + $this->status = array_key_exists('status', $error) ? $error['status'] : ''; $this->message = $error['message']; $this->documentation_url = $error['documentation_url']; diff --git a/tests/AWeberEntryTest.php b/tests/AWeberEntryTest.php index 9f0e292..e191d17 100644 --- a/tests/AWeberEntryTest.php +++ b/tests/AWeberEntryTest.php @@ -1,5 +1,6 @@ adapter->clearRequests(); - $this->expectException(AWeberResourceNotImplemented); + $this->setExpectedException('AWeberResourceNotImplemented'); $obj = $this->entry->something_not_implemented; $this->assertEquals(count($this->adapter->requestsMade), 0); } @@ -99,7 +100,7 @@ public function testAttrs() { public function testDelete() { $this->adapter->clearRequests(); $resp = $this->entry->delete(); - $this->assertIdentical($resp, true); + $this->assertSame($resp, true); $this->assertEquals(sizeOf($this->adapter->requestsMade), 1); $this->assertEquals($this->adapter->requestsMade[0]['method'], 'DELETE'); $this->assertEquals($this->adapter->requestsMade[0]['uri'], $this->entry->url); @@ -114,7 +115,7 @@ public function testFailedDelete() { $data = $this->adapter->request('GET', $url); $entry = new AWeberEntry($data, $url, $this->adapter); - $this->expectException(AWeberAPIException, "SimulatedException"); + $this->setExpectedException('AWeberAPIException', 'Simulated Exception'); $entry->delete(); } @@ -124,8 +125,8 @@ public function testFailedDelete() { * */ public function testSet() { - $this->assertNotEqual($this->entry->name, 'mynewlistname'); - $this->assertNotEqual($this->entry->data['name'], 'mynewlistname'); + $this->assertNotEquals($this->entry->name, 'mynewlistname'); + $this->assertNotEquals($this->entry->data['name'], 'mynewlistname'); $this->entry->name = 'mynewlistname'; $this->assertEquals($this->entry->name, 'mynewlistname'); $this->assertEquals($this->entry->data['name'], 'mynewlistname'); @@ -143,7 +144,7 @@ public function testSave() { $this->assertEquals($req['method'], 'PATCH'); $this->assertEquals($req['uri'], $this->entry->url); $this->assertEquals($req['data'], array('name' => 'mynewlistname')); - $this->assertIdentical($resp, true); + $this->assertSame($resp, true); } public function testSaveFailed() { @@ -151,7 +152,7 @@ public function testSaveFailed() { $data = $this->adapter->request('GET', $url); $entry = new AWeberEntry($data, $url, $this->adapter); $entry->name = 'foobarbaz'; - $this->expectException(AWeberAPIException, "SimulatedException"); + $this->setExpectedException('AWeberAPIException', 'Simulated Exception'); $resp = $entry->save(); } @@ -174,7 +175,7 @@ public function testShouldMaintainDirtiness() { } -class AccountTestCase extends PHPUnit_Framework_TestCase { +abstract class AccountTestCase extends PHPUnit_Framework_TestCase { public function setUp() { $this->adapter = get_mock_adapter(); @@ -224,7 +225,7 @@ public function testShouldHaveEntries() { public function testShouldHaveFullURL() { foreach($this->forms as $entry) { - $this->assertTrue(preg_match('/^\/accounts\/1\/lists\/[0-9]*\/web_forms\/[0-9]*$/', $entry->url)); + $this->assertEquals(preg_match('/^\/accounts\/1\/lists\/[0-9]*\/web_forms\/[0-9]*$/', $entry->url), 1); } } } @@ -252,7 +253,7 @@ public function testShouldHaveEntries() { public function testShouldHaveFullURL() { foreach($this->forms as $entry) { - $this->assertTrue(preg_match('/^\/accounts\/1\/lists\/[0-9]*\/web_form_split_tests\/[0-9]*$/', $entry->url)); + $this->assertEquals(preg_match('/^\/accounts\/1\/lists\/[0-9]*\/web_form_split_tests\/[0-9]*$/', $entry->url), 1); } } } @@ -372,7 +373,7 @@ public function testMove_Success() { public function testMove_Failure() { $this->adapter->clearRequests(); - $this->expectException(AWeberAPIException, "SimulatedException"); + $this->setExpectedException('AWeberAPIException', 'Simulated Exception'); $this->unsubscribed->move($this->different_list); $this->assertEquals(sizeOf($this->adapter->requestsMade), 1); From 6c7b54a688eda0b880f1a510b693459331f78178 Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Fri, 6 Apr 2012 21:54:52 -0400 Subject: [PATCH 038/112] Add .md extension to README so it gets parsed by github. --- README => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README => README.md (100%) diff --git a/README b/README.md similarity index 100% rename from README rename to README.md From b8a91fc4b812a37d9cabf268bc785a2018d273d2 Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Mon, 9 Apr 2012 10:06:39 -0400 Subject: [PATCH 039/112] Remove files used to run tests using simpletest. --- tests/all_tests.php | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 tests/all_tests.php diff --git a/tests/all_tests.php b/tests/all_tests.php deleted file mode 100644 index 46988f0..0000000 --- a/tests/all_tests.php +++ /dev/null @@ -1,28 +0,0 @@ -addTestCase(new TestAWeberAPI()); -$test->addTestCase(new TestOAuthAppliation()); -$test->addTestCase(new TestMultipleInstalledVersions()); -$test->addTestCase(new TestAWeberCollection()); -$test->addTestCase(new TestAWeberCollectionFind()); -$test->addTestCase(new TestAWeberEntry()); -$test->addTestCase(new TestAWeberCreateEntry()); -$test->addTestCase(new TestAWeberAccountEntry()); -$test->addTestCase(new TestAccountGetWebForms()); -$test->addTestCase(new TestAccountGetWebFormSplitTests()); -$test->addTestCase(new TestAccountFindSubscribers()); -$test->addTestCase(new TestAWeberSubscriberEntry()); -$test->addTestCase(new TestAWeberMoveEntry()); -$test->addTestCase(new TestGettingEntryParentEntry()); -$test->addTestCase(new TestGettingCollectionParentEntry()); -$test->run(new TextReporter()); From e4365bd29d47fc035ceb980c4ccb16f23d53501c Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Mon, 9 Apr 2012 10:07:37 -0400 Subject: [PATCH 040/112] Fix phpunit logging configuration. --- build/phpunit.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/phpunit.xml b/build/phpunit.xml index 84f7b37..3a05bd0 100644 --- a/build/phpunit.xml +++ b/build/phpunit.xml @@ -1,10 +1,10 @@ - - - + + From f721e3e48345c9cc0591c05acb80b6c224157b50 Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Mon, 9 Apr 2012 14:20:42 -0400 Subject: [PATCH 041/112] Add testing information to README. --- README.md | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c6226f3..e1b8c98 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,15 @@ PHP library for easily integrating with the AWeber API. Changelog: ---------- 2011-12-23: v1.1.2 + * Fixed a bug in the AWeberCollection class to properly set the URL of entries found in collections. 2011-10-10: v1.1.1 + * Raise an E_USER_WARNING instead of a fatal error if multiple instances of the client library are installed. 2011-08-29: v1.1.0 + * Modified client library to raise an AWeberAPIException on any API errors (HTTP status >= 400) * Refactored tests for better code coverage * Refactored move and create methods to return the resource or raise an AWeberAPIException on error. @@ -28,12 +31,13 @@ https://labs.aweber.com/docs/php-library-walkthrough Handling Errors: ---------------- Sometimes errors happen and your application should handle them appropriately. -Whenever an API error occurs an AWeberAPIException will be raised with a detailed +Whenever an API error occurs an AWeberAPIException will be raised with a detailed error message and documentation link to explain what's wrong. You should wrap any calls to the API in a try/except block. Common Errors: + * Resource not found (404 error) * Your application has been rate limited (403 error) * Bad request (400 error) @@ -43,20 +47,35 @@ Refer to https://labs.aweber.com/docs/troubleshooting for the complete list Example Below: -getAccount($accessKey, $accessSecret); + + try { + $resource = $account->loadFromUrl('/accounts/idontexist'); + } catch (AWeberAPIException $exc) { + print "
    • $exc->type on $exc->url, refer to $exc->message for more info ...
      "; + } + ?> -$consumerKey = '***'; -$consumerSecret = '***'; -$accessKey = '***'; -$accessSecret = '***'; +Running Tests: +-------------- +Testing the PHP api library requires installation of a few utilities. -$aweber = new AWeberAPI($consumerKey, $consumerSecret); -$account = $aweber->getAccount($accessKey, $accessSecret); + * [Apache Ant](http://ant.apache.org/) - Used to run the build + targets in the build.xml file. + * [PHP PEAR](http://pear.php.net/manual/en/installation.getting.php) + - Used to install utilities for testing and code metrics. + * [PHP QA Tools](http://pear.phpqatools.org/) - Collection of PHP + testing tools. -try { - $resource = $account->loadFromUrl('/accounts/idontexist'); -} catch (AWeberAPIException $exc) { - print "
    • $exc->type on $exc->url, refer to $exc->message for more info ...
      "; -} +Once the above requirements are installed, run the tests from the base +directory using the command: `ant phpunit`. -?> +To run the entire suite of checks and tests, run: `ant`. From f6b26ab9b7b6803978e826dba3168b52abfe493e Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Wed, 11 Apr 2012 16:32:56 -0400 Subject: [PATCH 042/112] Address comment in pull request regarding installation of the tools needed to run the tests. --- README.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e1b8c98..846a2fa 100644 --- a/README.md +++ b/README.md @@ -68,12 +68,30 @@ Running Tests: -------------- Testing the PHP api library requires installation of a few utilities. - * [Apache Ant](http://ant.apache.org/) - Used to run the build - targets in the build.xml file. + * [Apache Ant](http://ant.apache.org/) + - Used to run the build targets in the build.xml file. + - Get the latest version. + * Setup `/etc/php.ini` configuration file. + - Make sure `include_path` contains the correct directories.(`/usr/lib/php` on MacOS) + - Set `date.timezone` to your local timezone. * [PHP PEAR](http://pear.php.net/manual/en/installation.getting.php) - Used to install utilities for testing and code metrics. - * [PHP QA Tools](http://pear.phpqatools.org/) - Collection of PHP - testing tools. + - Upgrade to the latest version using `sudo pear upgrade pear`. + * [PHP QA Tools](http://pear.phpqatools.org/) + - Collection of PHP testing tools. + - The following commands were needed to install: + + sudo pear channel-discover pear.phpqatools.org + + sudo pear install phpqatools/phpqatools + + - If it fails due to missing channels, manually add the missing channels: + + sudo pear channel-discover pear.phpunit.de + sudo pear channel-discover pear.pdepend.org + sudo pear channel-discover pear.phpmd.org + sudo pear channel-discover components.ez.no + sudo pear channel-discover pear.symfony-project.com Once the above requirements are installed, run the tests from the base directory using the command: `ant phpunit`. From 7c00b6b287d50fc6768c4d64f89958eb9e7ce15a Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Thu, 12 Apr 2012 09:27:54 -0400 Subject: [PATCH 043/112] More edits related to the comments. --- README.md | 68 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 846a2fa..3812aa5 100644 --- a/README.md +++ b/README.md @@ -47,52 +47,54 @@ Refer to https://labs.aweber.com/docs/troubleshooting for the complete list Example Below: - getAccount($accessKey, $accessSecret); +$aweber = new AWeberAPI($consumerKey, $consumerSecret); +$account = $aweber->getAccount($accessKey, $accessSecret); - try { - $resource = $account->loadFromUrl('/accounts/idontexist'); - } catch (AWeberAPIException $exc) { - print "
    • $exc->type on $exc->url, refer to $exc->message for more info ...
      "; - } - ?> +try { + $resource = $account->loadFromUrl('/accounts/idontexist'); +} catch (AWeberAPIException $exc) { + print "
    • $exc->type on $exc->url, refer to $exc->message for more info ...
      "; +} +?> +``` Running Tests: -------------- Testing the PHP api library requires installation of a few utilities. - * [Apache Ant](http://ant.apache.org/) - - Used to run the build targets in the build.xml file. - - Get the latest version. - * Setup `/etc/php.ini` configuration file. - - Make sure `include_path` contains the correct directories.(`/usr/lib/php` on MacOS) - - Set `date.timezone` to your local timezone. - * [PHP PEAR](http://pear.php.net/manual/en/installation.getting.php) - - Used to install utilities for testing and code metrics. - - Upgrade to the latest version using `sudo pear upgrade pear`. - * [PHP QA Tools](http://pear.phpqatools.org/) - - Collection of PHP testing tools. - - The following commands were needed to install: +### Requirements ### +[Apache Ant](http://ant.apache.org/) is used to run the build targets in the build.xml file. Get the latest version. - sudo pear channel-discover pear.phpqatools.org +Setup `/etc/php.ini` configuration file. Make sure `include_path` contains the correct directories.(`/usr/lib/php` on MacOS) Set `date.timezone` to your local timezone. - sudo pear install phpqatools/phpqatools +[PHP PEAR](http://pear.php.net/manual/en/installation.getting.php) is used to install utilities for testing and code metrics. Upgrade to the latest version using `sudo pear upgrade pear`. - - If it fails due to missing channels, manually add the missing channels: +[PHP QA Tools](http://pear.phpqatools.org/) contain a collection of PHP testing tools. The following commands were needed to install: - sudo pear channel-discover pear.phpunit.de - sudo pear channel-discover pear.pdepend.org - sudo pear channel-discover pear.phpmd.org - sudo pear channel-discover components.ez.no - sudo pear channel-discover pear.symfony-project.com +```bash +sudo pear channel-discover pear.phpqatools.org +sudo pear install phpqatools/phpqatools +``` +If installing PHP QA Tools fails due to missing channels, manually add the missing channels: + +```bash +sudo pear channel-discover pear.phpunit.de +sudo pear channel-discover pear.pdepend.org +sudo pear channel-discover pear.phpmd.org +sudo pear channel-discover components.ez.no +sudo pear channel-discover pear.symfony-project.com +``` + +### Execute Tests ### Once the above requirements are installed, run the tests from the base directory using the command: `ant phpunit`. From 9eb6676a8230b621a83b4f3e9cd2f51bfe0fa5c1 Mon Sep 17 00:00:00 2001 From: "Edward F Long, Jr" Date: Wed, 18 Apr 2012 08:24:37 -0400 Subject: [PATCH 044/112] split: removed deprecated function used explode instead of split --- aweber_api/aweber.php | 2 +- aweber_api/aweber_collection.php | 2 +- aweber_api/aweber_entry.php | 2 +- aweber_api/oauth_application.php | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aweber_api/aweber.php b/aweber_api/aweber.php index 385dea7..cad360f 100644 --- a/aweber_api/aweber.php +++ b/aweber_api/aweber.php @@ -176,7 +176,7 @@ public static function getDataFromAweberID($string) { } protected static function _parseAWeberID($string) { - $values = split('\|', $string); + $values = explode('|', $string); if (count($values) < 5) { return null; } diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index e1609e6..0becab3 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -89,7 +89,7 @@ public function find($search_data) { * Returns NULL if no parent entry */ public function getParentEntry(){ - $url_parts = split('/', $this->url); + $url_parts = explode('/', $this->url); $size = count($url_parts); #Remove collection id and slash from end of url diff --git a/aweber_api/aweber_entry.php b/aweber_api/aweber_entry.php index 580fa0e..c89c578 100644 --- a/aweber_api/aweber_entry.php +++ b/aweber_api/aweber_entry.php @@ -216,7 +216,7 @@ public function getActivity() { * Returns NULL if no parent entry */ public function getParentEntry(){ - $url_parts = split('/', $this->url); + $url_parts = explode('/', $this->url); $size = count($url_parts); #Remove entry id and slash from end of url diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 37215de..8808272 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -378,10 +378,10 @@ public function createSignatureBase($method, $url, $data) { $method = $this->encode(strtoupper($method)); $query = parse_url($url, PHP_URL_QUERY); if ($query) { - $url = array_shift(split('\?', $url, 2)); - $items = split('&', $query); + $url = array_shift(explode('?', $url, 2)); + $items = explode('&', $query); foreach ($items as $item) { - list($key, $value) = split('=', $item); + list($key, $value) = explode('=', $item); $data[$key] = $value; } } From 016d5d420ff08c9ddcaa8c4d00556dbe8bda4972 Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Thu, 19 Apr 2012 15:39:48 -0400 Subject: [PATCH 045/112] Enable phpdoc ant target. --- build.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.xml b/build.xml index f3b34d7..0069afe 100644 --- a/build.xml +++ b/build.xml @@ -2,8 +2,8 @@ - + + depends="prepare,lint,phploc,pdepend,phpmd-ci,phpcs-ci,phpcpd,phpdoc,phpunit,phpcb"/> @@ -18,7 +18,7 @@ - + From 89eb6504150f62292cbb734afd4d0aef77516c10 Mon Sep 17 00:00:00 2001 From: "Edward F Long, Jr" Date: Thu, 19 Apr 2012 15:49:20 -0400 Subject: [PATCH 046/112] readme: bump version --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 3812aa5..818240e 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,10 @@ PHP library for easily integrating with the AWeber API. Changelog: ---------- +2012-04-18: v1.1.3 + + * Removed usage of deprecated split function. + 2011-12-23: v1.1.2 * Fixed a bug in the AWeberCollection class to properly set the URL of entries found in collections. From dd5865386fc0280c3eaa18ef101e5cc7bde67c99 Mon Sep 17 00:00:00 2001 From: Jason Schadel Date: Thu, 19 Apr 2012 16:02:16 -0400 Subject: [PATCH 047/112] Fix broken build.xml file. --- build.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/build.xml b/build.xml index 0069afe..3abaa40 100644 --- a/build.xml +++ b/build.xml @@ -2,7 +2,6 @@ --> depends="prepare,lint,phploc,pdepend,phpmd-ci,phpcs-ci,phpcpd,phpdoc,phpunit,phpcb"/> Date: Thu, 19 Apr 2012 16:06:27 -0400 Subject: [PATCH 048/112] Add missing commands needed to properly setup the user environment for running the tests. --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3812aa5..63806f5 100644 --- a/README.md +++ b/README.md @@ -75,11 +75,15 @@ Testing the PHP api library requires installation of a few utilities. Setup `/etc/php.ini` configuration file. Make sure `include_path` contains the correct directories.(`/usr/lib/php` on MacOS) Set `date.timezone` to your local timezone. -[PHP PEAR](http://pear.php.net/manual/en/installation.getting.php) is used to install utilities for testing and code metrics. Upgrade to the latest version using `sudo pear upgrade pear`. +[PHP PEAR](http://pear.php.net/manual/en/installation.getting.php) is +used to install utilities for testing and code metrics. Upgrade to the +latest version using `sudo pear upgrade pear`. [PHP QA Tools](http://pear.phpqatools.org/) contain a collection of PHP testing tools. The following commands were needed to install: ```bash +sudo pear upgrade +sudo pear config-set auto_discover 1 sudo pear channel-discover pear.phpqatools.org sudo pear install phpqatools/phpqatools ``` From da5f431d78f5333a2bb39b666e7fd20bde27d1dd Mon Sep 17 00:00:00 2001 From: "Edward F Long, Jr" Date: Tue, 8 May 2012 09:56:38 -0400 Subject: [PATCH 049/112] errors: make error messages more helpful Some API Developers have reported AWeberOAuthDataMissing exceptions when using the demo.php script. This error message is not helpful as the typical cause for this exception is an invalid consumer key or secret. The client library has been refactored to always raise an AWeberAPIException when a 40x/50x http status code is returned. This exception will clearly indicate the error for troubleshooting. --- README.md | 64 ++++++++++++++++++++------------ aweber_api/oauth_application.php | 25 ++++++++----- tests/mock_adapter.php | 15 +++++++- 3 files changed, 70 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 6f50c06..fd143b4 100644 --- a/README.md +++ b/README.md @@ -3,26 +3,6 @@ AWeber API PHP Library PHP library for easily integrating with the AWeber API. -Changelog: ----------- -2012-04-18: v1.1.3 - - * Removed usage of deprecated split function. - -2011-12-23: v1.1.2 - - * Fixed a bug in the AWeberCollection class to properly set the URL of entries found in collections. - -2011-10-10: v1.1.1 - - * Raise an E_USER_WARNING instead of a fatal error if multiple instances of the client library are installed. - -2011-08-29: v1.1.0 - - * Modified client library to raise an AWeberAPIException on any API errors (HTTP status >= 400) - * Refactored tests for better code coverage - * Refactored move and create methods to return the resource or raise an AWeberAPIException on error. - * Added getActivity method to a subscriber entry. Basic Usage: ------------ @@ -36,15 +16,15 @@ Handling Errors: ---------------- Sometimes errors happen and your application should handle them appropriately. Whenever an API error occurs an AWeberAPIException will be raised with a detailed -error message and documentation link to explain what's wrong. +error message and documentation link to explain what is wrong. You should wrap any calls to the API in a try/except block. Common Errors: - - * Resource not found (404 error) - * Your application has been rate limited (403 error) * Bad request (400 error) + * Your application is not authorized (401 error) + * Your application has been rate limited (403 error) + * Resource not found (404 error) * API Temporarily unavailable (503 error) Refer to https://labs.aweber.com/docs/troubleshooting for the complete list @@ -70,6 +50,42 @@ try { ?> ``` + +Changelog: +---------- +2012-05-08: v1.1.4 +``` + Some API Developers have reported AWeberOAuthDataMissing exceptions when using the demo.php script. + This error message is not helpful as the typical cause for this exception is an invalid consumer key or secret. + + The client library has been refactored to always raise an AWeberAPIException when a 40x/50x http status code + response is returned. This exception will clearly indicate the cause of the error for easier troubleshooting. +``` + * Refactored makeRequest to always raise an AWeberAPIException when a 40x or 50x status is returned. + * Refactored makeRequest to indicate transient networking or firewall connectivity issues. + * Refactored mock adaptor makeRequest for testing to behave the same way as the real makeRequest does. + +2012-04-18: v1.1.3 + + * Removed usage of deprecated split function. + +2011-12-23: v1.1.2 + + * Fixed a bug in the AWeberCollection class to properly set the URL of entries found in collections. + +2011-10-10: v1.1.1 + + * Raise an E_USER_WARNING instead of a fatal error if multiple instances of the client library are installed. + +2011-08-29: v1.1.0 + + * Modified client library to raise an AWeberAPIException on any API errors (HTTP status >= 400) + * Refactored tests for better code coverage + * Refactored move and create methods to return the resource or raise an AWeberAPIException on error. + * Added getActivity method to a subscriber entry. + + + Running Tests: -------------- Testing the PHP api library requires installation of a few utilities. diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 8808272..f56a81a 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -118,15 +118,6 @@ public function request($method, $uri, $data = array(), $options = array()) { $response = $this->makeRequest($method, $url, $data); - if (!$response) { - throw new AWeberResponseError($uri); - } - - if($response->headers['Status-Code'] >= 400) { - $data = json_decode($response->body, true); - throw new AWeberAPIException($data['error'], $url); - } - if (!empty($options['return'])) { if ($options['return'] == 'status') { return $response->headers['Status-Code']; @@ -452,6 +443,8 @@ public function makeRequest($method, $url, $data=array()) { } else { $resp = $this->get($url, $oauth, $data); } + + // enable debug output if ($this->debug) { echo "
      ";
                   print_r($oauth);
      @@ -459,6 +452,20 @@ public function makeRequest($method, $url, $data=array()) {
                   echo " --> Body: {$resp->body}";
                   echo "
      "; } + + if (!$resp) { + $msg = 'Unable to connect to the AWeber API. Please ensure that CURL is enabled and your '; + $msg .= 'firewall allows outbound SSL requests from your web server.'; + $error = array('message' => $msg, 'type' => 'APIUnreachableError', + 'documentation_url' => 'https://labs.aweber.com/docs/troubleshooting'); + throw new AWeberAPIException($error, $url); + } + + if($resp->headers['Status-Code'] >= 400) { + $data = json_decode($resp->body, true); + throw new AWeberAPIException($data['error'], $url); + } + return $resp; } diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php index 8bc1634..363ab8e 100644 --- a/tests/mock_adapter.php +++ b/tests/mock_adapter.php @@ -8,7 +8,6 @@ function get_mock_adapter() { } $map = array(); - $map['DELETE']['/accounts/1' ] = array(403, 'error'); $map['DELETE']['/accounts/1/lists/303449' ] = array(200, null); @@ -79,6 +78,15 @@ public function makeRequest($method, $url, $data=array()) { # load response from fixture and return data $mock_data = MockData::load($resource); + + if (!$mock_data) { + $msg = 'Unable to connect to the AWeber API. Please ensure that CURL is enabled and your '; + $msg .= 'firewall allows outbound SSL requests from your web server.'; + $error = array('message' => $msg, 'type' => 'APIUnreachableError', + 'documentation_url' => 'https://labs.aweber.com/docs/troubleshooting'); + throw new AWeberAPIException($error, $url); + } + $headers = array(); $headers['Status-Code'] = $status; @@ -87,6 +95,11 @@ public function makeRequest($method, $url, $data=array()) { } $mock_data->headers = $headers; + if($headers['Status-Code'] >= 400) { + $data = json_decode($mock_data->body, true); + throw new AWeberAPIException($data['error'], $url); + + } return $mock_data; } } From 17ad619816df1e344ef839586d5b91b57273a1f7 Mon Sep 17 00:00:00 2001 From: "Edward F Long, Jr" Date: Tue, 8 May 2012 13:13:36 -0400 Subject: [PATCH 050/112] readme: added more docs added more docs to the README file --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fd143b4..8d54294 100644 --- a/README.md +++ b/README.md @@ -51,16 +51,22 @@ try { ``` +Accessing personally identifiable subscriber data +------------------------------------------------- +In order to view or update the email, name, misc_notes, and ip_address fields of a subscriber, your app must +specifically request access to subscriber data. Refer to our documentation at +https://labs.aweber.com/docs/permissions for more information on how to be able to access personally identifiable +subscriber information. + + Changelog: ---------- 2012-05-08: v1.1.4 -``` Some API Developers have reported AWeberOAuthDataMissing exceptions when using the demo.php script. This error message is not helpful as the typical cause for this exception is an invalid consumer key or secret. The client library has been refactored to always raise an AWeberAPIException when a 40x/50x http status code response is returned. This exception will clearly indicate the cause of the error for easier troubleshooting. -``` * Refactored makeRequest to always raise an AWeberAPIException when a 40x or 50x status is returned. * Refactored makeRequest to indicate transient networking or firewall connectivity issues. * Refactored mock adaptor makeRequest for testing to behave the same way as the real makeRequest does. From f7412c378ed6177fbabb47b531d4ad0d0577332a Mon Sep 17 00:00:00 2001 From: "Edward F Long, Jr" Date: Thu, 5 Jul 2012 09:35:51 -0400 Subject: [PATCH 051/112] utf8_encode: prevent notice when patching changed logic of handling api requests to remove an unnecessary call to encode that results in a notice being raised when issuing a PATCH request with values that are arrays. --- README.md | 3 +++ aweber_api/oauth_application.php | 34 +++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8d54294..9f81c1b 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ subscriber information. Changelog: ---------- +2012-07-05: v1.1.5 + * Fixed a bug were a utf8_encode notice was raised when updating subscriber custom field values. + 2012-05-08: v1.1.4 Some API Developers have reported AWeberOAuthDataMissing exceptions when using the demo.php script. This error message is not helpful as the typical cause for this exception is an invalid consumer key or secret. diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index f56a81a..9cbf833 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -107,7 +107,7 @@ public function request($method, $uri, $data = array(), $options = array()) { $uri = $this->app->removeBaseUri($uri); $url = $this->app->getBaseUri() . $uri; - # WARNING: non-primative items in data must be json serialized. + # WARNING: non-primative items in data must be json serialized in GET and POST. if ($method == 'POST' or $method == 'GET') { foreach ($data as $key => $value) { if (is_array($value)) { @@ -431,17 +431,29 @@ public function signRequest($method, $url, $data) { * @return void */ public function makeRequest($method, $url, $data=array()) { - $oauth = $this->prepareRequest($method, $url, $data); + if ($this->debug) echo "\n** {$method}: $url\n"; - if (strtoupper($method) == 'POST') { - $resp = $this->post($url, $oauth); - } else if (strtoupper($method) == 'DELETE') { - $resp = $this->delete($url, $oauth); - } else if (strtoupper($method) == 'PATCH') { - $oauth = $this->prepareRequest($method, $url, array()); - $resp = $this->patch($url, $oauth, $data); - } else { - $resp = $this->get($url, $oauth, $data); + + switch (strtoupper($method)) { + case 'POST': + $oauth = $this->prepareRequest($method, $url, $data); + $resp = $this->post($url, $oauth); + break; + + case 'GET': + $oauth = $this->prepareRequest($method, $url, $data); + $resp = $this->get($url, $oauth, $data); + break; + + case 'DELETE': + $oauth = $this->prepareRequest($method, $url, $data); + $resp = $this->delete($url, $oauth); + break; + + case 'PATCH': + $oauth = $this->prepareRequest($method, $url, array()); + $resp = $this->patch($url, $oauth, $data); + break; } // enable debug output From 967ef2c15fb2777eb6794439d5c1495492fe6ba4 Mon Sep 17 00:00:00 2001 From: Ethan McCreadie Date: Tue, 14 Aug 2012 14:15:11 -0400 Subject: [PATCH 052/112] readme: Include TravisCI status link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f81c1b..fab74d2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -AWeber API PHP Library +AWeber API PHP Library [![Build Status](https://secure.travis-ci.org/aweber/AWeber-API-PHP-Library.png)](http://travis-ci.org/aweber/AWeber-API-PHP-Library) ====================== PHP library for easily integrating with the AWeber API. From d6db9bd65e09ea2fea72b37e2edbd81113e839b6 Mon Sep 17 00:00:00 2001 From: Ethan McCreadie Date: Tue, 14 Aug 2012 14:37:09 -0400 Subject: [PATCH 053/112] travisci: Add .yml file --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..3507c23 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +language: php + +php: + - 5.3 + - 5.4 + +script: phpunit --configuration build/phpunit.xml From 732fd870357aeda9cbdce4a414d0c89ac6ae6d38 Mon Sep 17 00:00:00 2001 From: Ethan McCreadie Date: Wed, 15 Aug 2012 10:49:40 -0400 Subject: [PATCH 054/112] travis: Use consolidated notification email --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3507c23..f04ab82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,8 @@ php: - 5.4 script: phpunit --configuration build/phpunit.xml + +notifications: + email: + recipients: + - travisci@aweber.com From bdec39bd6e1ec01d5db17bead4b6f636a3dae162 Mon Sep 17 00:00:00 2001 From: "Edward F Long, Jr" Date: Wed, 19 Sep 2012 14:56:49 -0400 Subject: [PATCH 055/112] fix update on fields with initially null values fix updates on fields with initially null values. we were using isset() instead of array_key_exists() replace usage of isset with array_key_exists --- README.md | 4 ++++ aweber_api/aweber.php | 2 +- aweber_api/aweber_collection.php | 2 +- aweber_api/aweber_entry.php | 2 +- aweber_api/aweber_response.php | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fab74d2..593640b 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,10 @@ subscriber information. Changelog: ---------- +2012-09-19: v1.1.6 + * Fixed a bug that prevented resource attributes from being saved when the initial value of the resource attribute was null. + * used array_key_exists instead of isset for evaluation of associative arrays. Requires PHP >= 4.0.7 + 2012-07-05: v1.1.5 * Fixed a bug were a utf8_encode notice was raised when updating subscriber custom field values. diff --git a/aweber_api/aweber.php b/aweber_api/aweber.php index cad360f..792dc89 100644 --- a/aweber_api/aweber.php +++ b/aweber_api/aweber.php @@ -122,7 +122,7 @@ protected function readResponse($response, $url) { $this->adapter->parseAsError($response); if (!empty($response['id'])) { return new AWeberEntry($response, $url, $this->adapter); - } else if (isset($response['entries'])) { + } else if (array_key_exists('entries', $response)) { return new AWeberCollection($response, $url, $this->adapter); } return false; diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index 0becab3..9f65f19 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -151,7 +151,7 @@ protected function _type() { * @return integer */ protected function _calculatePageSize() { - if (isset($this->data['next_collection_link'])) { + if (array_key_exists('next_collection_link', $this->data)) { $url = $this->data['next_collection_link']; $urlParts = parse_url($url); if (empty($urlParts['query'])) return $this->pageSize; diff --git a/aweber_api/aweber_entry.php b/aweber_api/aweber_entry.php index c89c578..3492f38 100644 --- a/aweber_api/aweber_entry.php +++ b/aweber_api/aweber_entry.php @@ -159,7 +159,7 @@ public function __get($value) { * @access public */ public function __set($key, $value) { - if (isset($this->data[$key])) { + if (array_key_exists($key, $this->data)) { $this->_localDiff[$key] = $value; return $this->data[$key] = $value; } else { diff --git a/aweber_api/aweber_response.php b/aweber_api/aweber_response.php index a688e3f..5d021a2 100644 --- a/aweber_api/aweber_response.php +++ b/aweber_api/aweber_response.php @@ -62,7 +62,7 @@ public function __get($value) { if (in_array($value, $this->_privateData)) { return null; } - if (isset($this->data[$value])) { + if (array_key_exists($value, $this->data)) { return $this->data[$value]; } if ($value == 'type') return $this->_type(); From a7d3039bff1f72758e4d7bbc42d6b11ca5e94628 Mon Sep 17 00:00:00 2001 From: chrismcguire Date: Mon, 8 Oct 2012 10:18:22 -0300 Subject: [PATCH 056/112] Travis CI image now uses latest master build. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 593640b..a5567f8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -AWeber API PHP Library [![Build Status](https://secure.travis-ci.org/aweber/AWeber-API-PHP-Library.png)](http://travis-ci.org/aweber/AWeber-API-PHP-Library) +AWeber API PHP Library [![Build Status](https://secure.travis-ci.org/aweber/AWeber-API-PHP-Library.png?branch=master)](http://travis-ci.org/aweber/AWeber-API-PHP-Library) ====================== PHP library for easily integrating with the AWeber API. From 47f0b9fa047a4898a9c7335c34ae529983b8d56f Mon Sep 17 00:00:00 2001 From: Mike Druger Date: Fri, 7 Dec 2012 11:31:24 -0500 Subject: [PATCH 057/112] Move Subscriber: added last followup message number sent added last followup message number sent. --- aweber_api/aweber_entry.php | 11 +++++++++-- tests/AWeberEntryTest.php | 27 ++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/aweber_api/aweber_entry.php b/aweber_api/aweber_entry.php index 3492f38..c98e64b 100644 --- a/aweber_api/aweber_entry.php +++ b/aweber_api/aweber_entry.php @@ -92,9 +92,16 @@ public function delete() { * @return mixed AWeberEntry(Resource) Resource created on List ($list) * or False if resource was not created. */ - public function move($list) { + public function move($list, $last_followup_message_number_sent=NULL) { # Move Resource - $params = array('ws.op' => 'move', 'list_link' => $list->self_link); + $params = array( + 'ws.op' => 'move', + 'list_link' => $list->self_link + ); + if (isset($last_followup_message_number_sent)) { + $params['last_followup_message_number_sent'] = $last_followup_message_number_sent; + } + $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers')); # Return new Resource diff --git a/tests/AWeberEntryTest.php b/tests/AWeberEntryTest.php index e191d17..3a73791 100644 --- a/tests/AWeberEntryTest.php +++ b/tests/AWeberEntryTest.php @@ -384,7 +384,32 @@ public function testMove_Failure() { 'ws.op' => 'move', 'list_link' => $this->different_list->self_link)); return; - } + } + + /** + * Move with LastMessageSentNumber Succeeded + */ + public function testMoveWLastMessageNumberSent_Success() { + $this->last_followup_message_number_sent = 1; + + $this->adapter->clearRequests(); + $resp = $this->subscriber->move($this->different_list, $this->last_followup_message_number_sent); + + $this->assertEquals(sizeOf($this->adapter->requestsMade), 2); + + $req = $this->adapter->requestsMade[0]; + $this->assertEquals($req['method'], 'POST'); + $this->assertEquals($req['uri'], $this->subscriber->url); + $this->assertEquals($req['data'], array( + 'ws.op' => 'move', + 'list_link' => $this->different_list->self_link, + 'last_followup_message_number_sent' => $this->last_followup_message_number_sent)); + + $req = $this->adapter->requestsMade[1]; + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], '/accounts/1/lists/505454/subscribers/3'); + } + } class TestGettingEntryParentEntry extends PHPUnit_Framework_TestCase { From 7e79beec6ca8c759f695c676b203b8dab470de59 Mon Sep 17 00:00:00 2001 From: Mike Druger Date: Mon, 10 Dec 2012 14:28:55 -0500 Subject: [PATCH 058/112] Version Bump version bump --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index a5567f8..09ce6a6 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,10 @@ subscriber information. Changelog: ---------- +2012-12-10: v1.1.7 + * Added a parameter to the Move Subscriber method for last followup message number sent. + * to support version 1.0.16 of the API. See https://labs.aweber.com/docs/changelog + 2012-09-19: v1.1.6 * Fixed a bug that prevented resource attributes from being saved when the initial value of the resource attribute was null. * used array_key_exists instead of isset for evaluation of associative arrays. Requires PHP >= 4.0.7 From 05efa07b64b57a45eaa353c47beb0239220ccf16 Mon Sep 17 00:00:00 2001 From: Mike Druger Date: Thu, 13 Dec 2012 11:26:15 -0500 Subject: [PATCH 059/112] oauth request: return 0 as response err handle the 0 response to an empty set. --- .gitignore | 10 +++++++++- README.md | 3 +++ aweber_api/oauth_application.php | 5 +++-- tests/OAuthApplicationTest.php | 9 +++++++++ tests/data/empty.json | 1 + tests/mock_adapter.php | 2 +- 6 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 tests/data/empty.json diff --git a/.gitignore b/.gitignore index db71f9b..9f6aea2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,10 @@ -*.svn +.DS_Store +Icon? +Thumbs.db +ehthumbs.db +*.bak +*.swm +*.swn +*.swo *.swp +*~ diff --git a/README.md b/README.md index 09ce6a6..3de0c75 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ subscriber information. Changelog: ---------- +2012-12-13: v1.1.8 + * Fixed a bug that resulted in Exceptions being raised when using collections when the collection size is zero. + 2012-12-10: v1.1.7 * Added a parameter to the Move Subscriber method for last followup message number sent. * to support version 1.0.16 of the API. See https://labs.aweber.com/docs/changelog diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 9cbf833..417b1f9 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -117,7 +117,6 @@ public function request($method, $uri, $data = array(), $options = array()) { } $response = $this->makeRequest($method, $url, $data); - if (!empty($options['return'])) { if ($options['return'] == 'status') { return $response->headers['Status-Code']; @@ -129,8 +128,10 @@ public function request($method, $uri, $data = array(), $options = array()) { return intval($response->body); } } + $data = json_decode($response->body, true); - if (empty($options['allow_empty']) && empty($data)) { + + if (empty($options['allow_empty']) && !isset($data)) { throw new AWeberResponseError($uri); } return $data; diff --git a/tests/OAuthApplicationTest.php b/tests/OAuthApplicationTest.php index 057a00c..a59151f 100644 --- a/tests/OAuthApplicationTest.php +++ b/tests/OAuthApplicationTest.php @@ -1,5 +1,6 @@ assertSame($data, $dataShouldBe, 'Data is parsed correctly.'); } + public function testRequestReturnValueIsZeroNotInJSONFormat(){ + $this->adapter = get_mock_adapter(); + $url = '/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.show=total_size'; + $data = $this->adapter->request('GET', $url); + $this->assertTrue(isset($data)); + $this->assertEquals($data,0); + } + } diff --git a/tests/data/empty.json b/tests/data/empty.json new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/tests/data/empty.json @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php index 363ab8e..e41c7b2 100644 --- a/tests/mock_adapter.php +++ b/tests/mock_adapter.php @@ -35,6 +35,7 @@ function get_mock_adapter() { $map['GET' ]['/accounts/1?email=joe%40example.com&ws.op=findSubscribers' ] = array(200, 'accounts/findSubscribers'); $map['GET' ]['/accounts/1?ws.op=getWebFormSplitTests' ] = array(200, 'accounts/webFormSplitTests'); $map['GET' ]['/accounts/1?ws.op=getWebForms' ] = array(200, 'accounts/webForms'); +$map['GET' ]['/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.show=total_size' ] = array(200, 'empty'); $map['PATCH' ]['/accounts/1/lists/303449' ] = array(209, 'lists/303449'); $map['PATCH' ]['/accounts/1/lists/303449/subscribers/1' ] = array(209, 'subscribers/1'); @@ -78,7 +79,6 @@ public function makeRequest($method, $url, $data=array()) { # load response from fixture and return data $mock_data = MockData::load($resource); - if (!$mock_data) { $msg = 'Unable to connect to the AWeber API. Please ensure that CURL is enabled and your '; $msg .= 'firewall allows outbound SSL requests from your web server.'; From 1d42a2a4e3a88f721523e22526f992064c4fc5dc Mon Sep 17 00:00:00 2001 From: "Edward F Long, Jr" Date: Thu, 3 Jan 2013 10:52:39 -0500 Subject: [PATCH 060/112] license: happy new year updated copyright information in license --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 8665904..c1ea705 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2010-2011, AWeber Communications, Inc. +Copyright (c) 2010-2013, AWeber Communications, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without From 2522844ebac905087fa76ccfc145503308f55e67 Mon Sep 17 00:00:00 2001 From: "Edward F Long, Jr" Date: Thu, 3 Jan 2013 10:53:29 -0500 Subject: [PATCH 061/112] public api upgrade: support version 1.0.17 --- README.md | 3 +++ aweber_api/aweber.php | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3de0c75..a67f667 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ subscriber information. Changelog: ---------- +2013-01-03: v1.1.9 + * Updated client library to support 1.0.17 of the API. (Broadcast Statistics) + 2012-12-13: v1.1.8 * Fixed a bug that resulted in Exceptions being raised when using collections when the collection size is zero. diff --git a/aweber_api/aweber.php b/aweber_api/aweber.php index 792dc89..49f0611 100644 --- a/aweber_api/aweber.php +++ b/aweber_api/aweber.php @@ -81,8 +81,8 @@ class AWeberAPIBase { */ static protected $_collectionMap = array( 'account' => array('lists', 'integrations'), - 'broadcast_campaign' => array('links', 'messages'), - 'followup_campaign' => array('links', 'messages'), + 'broadcast_campaign' => array('links', 'messages', 'stats'), + 'followup_campaign' => array('links', 'messages', 'stats'), 'link' => array('clicks'), 'list' => array('campaigns', 'custom_fields', 'subscribers', 'web_forms', 'web_form_split_tests'), From 28a8ba9b85db4d5c7ee1fc44d6645e01d4cf6619 Mon Sep 17 00:00:00 2001 From: "Edward F Long, Jr" Date: Thu, 7 Feb 2013 11:23:00 -0500 Subject: [PATCH 062/112] oauth_adapter.php: add curl errors to exceptions. add curl error to exception message for APIUnreachableError to allow for quicker troubleshooting of curl issues --- README.md | 3 +++ aweber_api/oauth_application.php | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a67f667..88a0286 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ subscriber information. Changelog: ---------- +2013-02-07: v1.1.10 + * Updated APIUnreachableException to provide more diagnostic data. + 2013-01-03: v1.1.9 * Updated client library to support 1.0.17 of the API. (Broadcast Statistics) diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 417b1f9..34a770d 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -467,8 +467,7 @@ public function makeRequest($method, $url, $data=array()) { } if (!$resp) { - $msg = 'Unable to connect to the AWeber API. Please ensure that CURL is enabled and your '; - $msg .= 'firewall allows outbound SSL requests from your web server.'; + $msg = 'Unable to connect to the AWeber API. (' . $this->error . ')'; $error = array('message' => $msg, 'type' => 'APIUnreachableError', 'documentation_url' => 'https://labs.aweber.com/docs/troubleshooting'); throw new AWeberAPIException($error, $url); From bb6a987bb879502f007cf8c4c0d7b10bd4cc1483 Mon Sep 17 00:00:00 2001 From: Mike Druger Date: Wed, 24 Apr 2013 13:58:58 -0400 Subject: [PATCH 063/112] find subscriber: fixed pagination error pagination error on find subscriber --- README.md | 15 ++ aweber_api/aweber_collection.php | 290 ++++++++++------------ tests/AWeberCollectionTest.php | 69 +++++ tests/data/subscribers/find_1of2.json | 1 + tests/data/subscribers/find_1of2_tsl.json | 1 + tests/data/subscribers/find_2of2.json | 1 + tests/mock_adapter.php | 8 +- 7 files changed, 224 insertions(+), 161 deletions(-) create mode 100644 tests/data/subscribers/find_1of2.json create mode 100644 tests/data/subscribers/find_1of2_tsl.json create mode 100644 tests/data/subscribers/find_2of2.json diff --git a/README.md b/README.md index 88a0286..e3b36dc 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,21 @@ subscriber information. Changelog: ---------- +2013-04-25: v1.1.11 + * Fixed a bug in the Collection Find Subscriber method where fetching the next page in the collection had not + included the previous search parameters. + + * We've changed how we store collection data internally in AWeberCollection objects to + reduce the amount of memory required for large collections. + + To lower memory usage, the AWeberCollection only stores a single page of entries + as you iterate thru the collection. + + - foreach and sequential array indexing operations now require less memory. + + - Random access of array elements by indexes will fetch pages of the collection + from the API on demand if the collection data is not already in memory. + 2013-02-07: v1.1.10 * Updated APIUnreachableException to provide more diagnostic data. diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index 9f65f19..2250a86 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -2,7 +2,43 @@ class AWeberCollection extends AWeberResponse implements ArrayAccess, Iterator, Countable { protected $pageSize = 100; - protected $_entries = array(); + protected $pageStart = 0; + + protected function _updatePageSize() { + + # grab the url, or prev and next url and pull ws.size from it + $url = $this->url; + if (array_key_exists('next_collection_link', $this->data)) { + $url = $this->data['next_collection_link']; + + } elseif (array_key_exists('prev_collection_link', $this->data)) { + $url = $this->data['prev_collection_link']; + } + + # scan querystring for ws_size + $url_parts = parse_url($url); + + # we have a query string + if (array_key_exists('query', $url_parts)) { + parse_str($url_parts['query'], $params); + + # we have a ws_size + if (array_key_exists('ws_size', $params)) { + + # set pageSize + $this->pageSize = $params['ws_size']; + return; + } + } + + # we dont have one, just count the # of entries + $this->pageSize = count($this->data['entries']); + } + + public function __construct($response, $url, $adapter) { + parent::__construct($response, $url, $adapter); + $this->_updatePageSize(); + } /** * @var array Holds list of keys that are not publicly accessible @@ -23,9 +59,44 @@ class AWeberCollection extends AWeberResponse implements ArrayAccess, Iterator, */ public function getById($id) { $data = $this->adapter->request('GET', "{$this->url}/{$id}"); - return $this->_makeEntry($data, $id, "{$this->url}/{$id}"); + $url = "{$this->url}/{$id}"; + return new AWeberEntry($data, $url, $this->adapter); } + /** getParentEntry + * + * Gets an entry's parent entry + * Returns NULL if no parent entry + */ + public function getParentEntry(){ + $url_parts = explode('/', $this->url); + $size = count($url_parts); + + # Remove collection id and slash from end of url + $url = substr($this->url, 0, -strlen($url_parts[$size-1])-1); + + try { + $data = $this->adapter->request('GET', $url); + return new AWeberEntry($data, $url, $this->adapter); + } catch (Exception $e) { + return NULL; + } + } + + /** + * _type + * + * Interpret what type of resources are held in this collection by + * analyzing the URL + * + * @access protected + * @return void + */ + protected function _type() { + $urlParts = explode('/', $this->url); + $type = array_pop($urlParts); + return $type; + } /** * create @@ -46,7 +117,6 @@ public function create($kv_pairs) { # Create Resource $params = array_merge(array('ws.op' => 'create'), $kv_pairs); $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers')); - $this->_entries = array(); # Return new Resource $url = $data['Location']; @@ -83,187 +153,88 @@ public function find($search_data) { return $this->readResponse($data, $this->url); } - /** getParentEntry + /* + * ArrayAccess Functions * - * Gets an entry's parent entry - * Returns NULL if no parent entry + * Allows this object to be accessed via bracket notation (ie $obj[$x]) + * http://php.net/manual/en/class.arrayaccess.php */ - public function getParentEntry(){ - $url_parts = explode('/', $this->url); - $size = count($url_parts); - #Remove collection id and slash from end of url - $url = substr($this->url, 0, -strlen($url_parts[$size-1])-1); + public function offsetSet($offset, $value) {} + public function offsetUnset($offset) {} + public function offsetExists($offset) { - try { - $data = $this->adapter->request('GET', $url); - return new AWeberEntry($data, $url, $this->adapter); - } catch (Exception $e) { - return NULL; + if ($offset >=0 && $offset < $this->total_size) { + return true; } + return false; } + protected function _fetchCollectionData($offset) { - /** - * _getPageParams - * - * Returns an array of GET params used to set the page of a collection - * request - * @param int $start Which entry offset should this page start on? - * @param int $size How many entries should be included in this page? - * @access protected - * @return void - */ - protected function _getPageParams($start=0, $size=20) { - if ($start > 0) { - $params = array( - 'ws.start' => $start, - 'ws.size' => $size, - ); - ksort($params); - } else { - $params = array(); + # we dont have a next page, we're done + if (!array_key_exists('next_collection_link', $this->data)) { + return null; } - return $params; - } - /** - * _type - * - * Interpret what type of resources are held in this collection by - * analyzing the URL - * - * @access protected - * @return void - */ - protected function _type() { - $urlParts = explode('/', $this->url); - $type = array_pop($urlParts); - return $type; - } + # snag query string args from collection + $parsed = parse_url($this->data['next_collection_link']); - /** - * _calculatePageSize - * - * Calculates the page size of this collection based on the data in the - * next and prev links. - * - * @access protected - * @return integer - */ - protected function _calculatePageSize() { - if (array_key_exists('next_collection_link', $this->data)) { - $url = $this->data['next_collection_link']; - $urlParts = parse_url($url); - if (empty($urlParts['query'])) return $this->pageSize; - $query = array(); - parse_str($urlParts['query'], $query); - if (empty($query['ws_size'])) return $this->pageSize; - $this->pageSize = $query['ws_size']; + # parse the query string to get params + $pairs = explode('&', $parsed['query']); + foreach ($pairs as $pair) { + list($key, $val) = explode('=', $pair); + $params[$key] = $val; } - return $this->pageSize; - } - /** - * _loadPageForOffset - * - * Makes a request for an additional page of entries, based on the given - * offset. Calculates the start / size of the page needed to get that - * offset, requests for it, and then merges the data into it internal - * collection of entry data. - * - * @param mixed $offset The offset requested, 0 to total_size-1 - * @access protected - * @return void - */ - protected function _loadPageForOffset($offset) { - $this->_calculatePageSize(); - $start = round($offset / $this->pageSize) * $this->pageSize; - $params = $this->_getPageParams($start, $this->pageSize); + # calculate new args + $limit = $params['ws.size']; + $pagination_offset = intval($offset / $limit) * $limit; + $params['ws.start'] = $pagination_offset; - // Loading page + # fetch data $data = $this->adapter->request('GET', $this->url, $params); - $this->adapter->debug = false; + $this->pageStart = $params['ws.start']; + $this->pageSize = $params['ws.size']; - $rekeyed = array(); - foreach ($data['entries'] as $key => $entry) { - $rekeyed[$key+$data['start']] = $entry; - } - $this->data['entries'] = array_merge($this->data['entries'], $rekeyed); - } + $collection_data = array('entries', 'next_collection_link', 'prev_collection_link', 'ws.start'); - /** - * _getEntry - * - * Makes sure that entry offset's page is loaded, then returns it. Returns - * null if the entry can't be loaded, even after requesting the needed - * page. - * - * @param mixed $offset Offset being requested. - * @access protected - * @return void - */ - protected function _getEntry($offset) { - if (empty($this->data['entries'][$offset])) { - $this->_loadPageForOffset($offset); + foreach ($collection_data as $item) { + if (!array_key_exists($item, $this->data)) { + continue; + } + if (!array_key_exists($item, $data)) { + continue; + } + $this->data[$item] = $data[$item]; } - return (empty($this->data['entries'][$offset]))? null : - $this->data['entries'][$offset]; } - /** - * _makeEntry - * - * Creates an entry object from the given entry data. Optionally can take - * the id AND URL of the entry, though that data can be infered from the - * context in which _makeEntry is being called. - * - * @param mixed $data Array of data returned from an API request for - * entry, or as part of the entries array in this collection. - * @param mixed $id ID of the entry. (Optional) - * @param mixed $url URL used to retrieve this entry (Optional) - * @access protected - * @return void - */ - protected function _makeEntry($data, $id = false, $url = false) { - if ((!$url) or (!$id)) { - // if either the url or id is omitted, grab the url from the - // self_link of the resource - $url = $this->adapter->app->removeBaseUri($data['self_link']); - } else { - $url = "{$this->url}/{$id}"; + public function offsetGet($offset) { + + if (!$this->offsetExists($offset)) { + return null; } - return new AWeberEntry($data, $url, $this->adapter); - } - /** - * ArrayAccess interface methods - * - * Allows this object to be accessed via bracket notation (ie $obj[$x]) - * http://php.net/manual/en/class.arrayaccess.php - */ - public function offsetSet($offset, $value) { } - public function offsetUnset($offset) {} - public function offsetExists($offset) { - if ($offset >=0 && $offset < $this->total_size) { - return true; + $limit = $this->pageSize; + $pagination_offset = intval($offset / $limit) * $limit; + + # load collection page if needed + if ($pagination_offset !== $this->pageStart) { + $this->_fetchCollectionData($offset); } - return false; - } - public function offsetGet($offset) { - if (!$this->offsetExists($offset)) return null; - if (!empty($this->_entries[$offset])) return $this->_entries[$offset]; - $this->_entries[$offset] = $this->_makeEntry($this->_getEntry($offset)); - return $this->_entries[$offset]; + $entry = $this->data['entries'][$offset - $pagination_offset]; + + # we have an entry, cast it to an AWeberEntry and return it + $entry_url = $this->adapter->app->removeBaseUri($entry['self_link']); + return new AWeberEntry($entry, $entry_url, $this->adapter); } - /** - * Iterator interface methods - * - * Provides iterator functionality. - * http://php.net/manual/en/class.iterator.php + /* + * Iterator */ protected $_iterationKey = 0; + public function current() { return $this->offsetGet($this->_iterationKey); } @@ -284,14 +255,13 @@ public function valid() { return $this->offsetExists($this->key()); } - /** + /* * Countable interface methods - * * Allows PHP's count() and sizeOf() functions to act on this object * http://www.php.net/manual/en/class.countable.php */ + public function count() { return $this->total_size; } - } diff --git a/tests/AWeberCollectionTest.php b/tests/AWeberCollectionTest.php index dd2718d..44ca90c 100644 --- a/tests/AWeberCollectionTest.php +++ b/tests/AWeberCollectionTest.php @@ -2,6 +2,75 @@ require_once('aweber_api/aweber_api.php'); require_once('mock_adapter.php'); + +class TestFindCollection extends PHPUnit_Framework_TestCase { + + public function setUp() { + $url = '/accounts/1/lists/303449/subscribers'; + $this->adapter = get_mock_adapter(); + $this->subscribers = new AWeberCollection( + $this->adapter->request('GET', $url), + $url, + $this->adapter); + $this->adapter->clearRequests(); + $this->params = array('status' => 'unsubscribed', 'ws.size' => 1, 'ws.start' => 0); + $this->found = $this->subscribers->find($this->params); + } + + /** + * The find method makes two requests, one for the collection, and the other to get total_size. + */ + public function testShouldInitiallyMake2APIRequests() { + $this->assertEquals(count($this->adapter->requestsMade), 2); + } + + /** + * The first of two requests, verify the url to get the collection. + */ + public function testShouldRequestCollectionPageFirst() { + #$this->subscribers->find($this->params); + $uri = $this->adapter->requestsMade[0]['uri']; + $this->assertEquals($uri, '/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=0&ws.op=find'); + } + + /** + * The second of two requests, verify the url to get the total size. + */ + public function testShouldRequestTotalSizePageSecond() { + $uri = $this->adapter->requestsMade[1]['uri']; + $this->assertEquals($uri, '/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=0&ws.op=find&ws.show=total_size'); + } + + /** + * Pagination: An additional fetch is made when there is a next_collection_link included + */ + public function testShouldFetchDataforDataNotPreviouslyLoaded() { + $this->adapter->clearRequests(); + $subscriber = $this->found[1]; + $this->assertEquals(count($this->adapter->requestsMade), 1); + } + + /** + * Pagination: the first of two requests for the next fetch. Verify the url to get the next collection. + */ + public function testShouldRequestCorrectCollectionPage() { + $this->adapter->clearRequests(); + $subscriber = $this->found[1]; + $uri = $this->adapter->requestsMade[0]['uri']; + $this->assertEquals($uri, '/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=1&ws.op=find'); + } + + /** + * Pagination: the second of two requests for the next fetch. Verify the url to get the total size of the next collection. + */ + public function testShouldFetchCorrectDataOnSecondPage() { + $this->adapter->clearRequests(); + $subscriber = $this->found[1]; + $this->assertEquals($subscriber->data['self_link'], 'https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/50205518'); + } +} + + class TestAWeberCollection extends PHPUnit_Framework_TestCase { /** diff --git a/tests/data/subscribers/find_1of2.json b/tests/data/subscribers/find_1of2.json new file mode 100644 index 0000000..f869d73 --- /dev/null +++ b/tests/data/subscribers/find_1of2.json @@ -0,0 +1 @@ +{"next_collection_link": "/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=1&ws.op=find", "total_size_link": "/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=1&ws.op=find&ws.show=total_size", "start": 0, "resource_type_link": "https://api.aweber.com/1.0/#subscriber-page-resource", "entries": [{"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 50205517, "custom_fields": {"what is my quest": "", "Color": "blue", "COLOR": "", "asdfasdf": "", "test": "", "Walruses": ""}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/campaigns/f3548399", "city": "Davenport", "http_etag": "\"e60b496d99539173e3d994dbe41e8efd5154c42b-139949b906d1ffef2d531c166eed3152968d3bc8\"", "ad_tracking": "testing", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2010-01-29 00:10:57.617606-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/50205517", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2010-01-15 09:25:53", "subscribed_at": "2010-01-15 09:21:39-05:00"}]} diff --git a/tests/data/subscribers/find_1of2_tsl.json b/tests/data/subscribers/find_1of2_tsl.json new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/tests/data/subscribers/find_1of2_tsl.json @@ -0,0 +1 @@ +2 diff --git a/tests/data/subscribers/find_2of2.json b/tests/data/subscribers/find_2of2.json new file mode 100644 index 0000000..4377a84 --- /dev/null +++ b/tests/data/subscribers/find_2of2.json @@ -0,0 +1 @@ +{"prev_collection_link": "/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=0&ws.op=find", "total_size_link": "/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=1&ws.op=find&ws.show=total_size", "start": 0, "resource_type_link": "https://api.aweber.com/1.0/#subscriber-page-resource", "entries": [{"subscription_url": "https://www.aweber.com/users/leads/add", "postal_code": "14450", "id": 50205517, "custom_fields": {"what is my quest": "", "Color": "blue", "COLOR": "", "asdfasdf": "", "test": "", "Walruses": ""}, "last_followup_sent_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/campaigns/f3548399", "city": "Davenport", "http_etag": "\"e60b496d99539173e3d994dbe41e8efd5154c42b-139949b906d1ffef2d531c166eed3152968d3bc8\"", "ad_tracking": "testing", "dma_code": 538, "last_followup_message_number_sent": 3, "last_followup_sent_at": "2010-01-29 00:10:57.617606-05:00", "is_verified": true, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/50205518", "resource_type_link": "https://api.aweber.com/1.0/#subscriber", "status": "subscribed", "unsubscribed_at": null, "area_code": 585, "latitude": 43.100499999999997, "subscription_method": "signup form", "country": "United States", "region": "NY", "longitude": -77.426000000000002, "verified_at": "2010-01-15 09:25:53", "subscribed_at": "2010-01-15 09:21:39-05:00"}]} diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php index e41c7b2..174c812 100644 --- a/tests/mock_adapter.php +++ b/tests/mock_adapter.php @@ -30,13 +30,18 @@ function get_mock_adapter() { $map['GET' ]['/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.op=find' ] = array(200, 'subscribers/find'); $map['GET' ]['/accounts/1/lists/505454' ] = array(200, 'lists/505454'); $map['GET' ]['/accounts/1/lists/505454/subscribers/3' ] = array(200, 'subscribers/3'); -$map['GET' ]['/accounts/1/lists?ws.size=20&ws.start=20' ] = array(200, 'lists/page2'); +$map['GET' ]['/accounts/1/lists?ws.start=20&ws.size=20' ] = array(200, 'lists/page2'); $map['GET' ]['/accounts/1?email=joe%40example.com&ws.op=findSubscribers&ws.show=total_size' ] = array(200, 'accounts/findSubscribers_ts'); $map['GET' ]['/accounts/1?email=joe%40example.com&ws.op=findSubscribers' ] = array(200, 'accounts/findSubscribers'); $map['GET' ]['/accounts/1?ws.op=getWebFormSplitTests' ] = array(200, 'accounts/webFormSplitTests'); $map['GET' ]['/accounts/1?ws.op=getWebForms' ] = array(200, 'accounts/webForms'); $map['GET' ]['/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.show=total_size' ] = array(200, 'empty'); +# collection pagination tests +$map['GET' ]['/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=0&ws.op=find' ] = array(200, 'subscribers/find_1of2'); +$map['GET' ]['/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=1&ws.op=find' ] = array(200, 'subscribers/find_2of2'); +$map['GET' ]['/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=0&ws.op=find&ws.show=total_size'] = array(200, 'subscribers/find_1of2_tsl'); + $map['PATCH' ]['/accounts/1/lists/303449' ] = array(209, 'lists/303449'); $map['PATCH' ]['/accounts/1/lists/303449/subscribers/1' ] = array(209, 'subscribers/1'); $map['PATCH' ]['/accounts/1/lists/505454' ] = array(404, 'error'); @@ -71,6 +76,7 @@ public function makeRequest($method, $url, $data=array()) { } # extract response map parameters + # $status = $map[$method][$uri][0]; $resource = $map[$method][$uri][1]; From d90179f3090f57340ddff1e568d0d82176667e2d Mon Sep 17 00:00:00 2001 From: Dan Grosso Date: Mon, 1 Jul 2013 16:00:41 -0400 Subject: [PATCH 064/112] omit query string adapter->request() url --- aweber_api/aweber_collection.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index 2250a86..83ef8e1 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -192,7 +192,8 @@ protected function _fetchCollectionData($offset) { $params['ws.start'] = $pagination_offset; # fetch data - $data = $this->adapter->request('GET', $this->url, $params); + list($relative_url, $query_string) = explode('?', $this->url); + $data = $this->adapter->request('GET', $relative_url, $params); $this->pageStart = $params['ws.start']; $this->pageSize = $params['ws.size']; From 397327521ced84a11f3ba62dce582e71d77a2dc2 Mon Sep 17 00:00:00 2001 From: Dan Grosso Date: Tue, 2 Jul 2013 15:46:16 -0400 Subject: [PATCH 065/112] fixed undefined index issue with list --- aweber_api/aweber_collection.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index 83ef8e1..196da7f 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -191,9 +191,9 @@ protected function _fetchCollectionData($offset) { $pagination_offset = intval($offset / $limit) * $limit; $params['ws.start'] = $pagination_offset; - # fetch data - list($relative_url, $query_string) = explode('?', $this->url); - $data = $this->adapter->request('GET', $relative_url, $params); + # fetch data, exclude query string + $url_parts = explode('?', $this->url); + $data = $this->adapter->request('GET', $url_parts[0], $params); $this->pageStart = $params['ws.start']; $this->pageSize = $params['ws.size']; From c886658e2d5ffee83dd12ee9f60b2e586f3dfc75 Mon Sep 17 00:00:00 2001 From: Brian Korty Date: Mon, 23 Dec 2013 10:50:06 -0500 Subject: [PATCH 066/112] ABSTRACT CURL LIBRARY INTO OBJECT FOR BETTER UNIT TESTING Write a wrapper class around the standard cURL library so that it can easily be replaced in oauth_application.php for unit testing. Create an interface called CurlInterface and implement a concrete implementation of CurlInterface called CurlObject. Instantiate CurlObject data member in OAuthApplication. Modify OAuthApplication methods to call CurlObject methods instead of cURL methods directly. Add some unit tests for OAuthApplication->makeRequest() to verify that CurlObject is being invoked properly. Add an additional unit test to verify that + character is correctly URL encoded in SignatureBase. See Jira PA-60. --- aweber_api/curl_object.php | 105 +++++++++++++++++++++++++++++++ aweber_api/oauth_application.php | 47 +++++++------- tests/OAuthApplicationTest.php | 57 +++++++++++++++++ 3 files changed, 188 insertions(+), 21 deletions(-) create mode 100644 aweber_api/curl_object.php diff --git a/aweber_api/curl_object.php b/aweber_api/curl_object.php new file mode 100644 index 0000000..0f06867 --- /dev/null +++ b/aweber_api/curl_object.php @@ -0,0 +1,105 @@ + \ No newline at end of file diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 34a770d..bcd1668 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -1,4 +1,5 @@ app = $parentApp; } $this->user = new OAuthUser(); + $this->curl = new CurlObject(); } /** @@ -227,7 +231,7 @@ protected function requiredFromResponse($data, $requiredFields) { */ protected function get($url, $data) { $url = $this->_addParametersToUrl($url, $data); - $handle = curl_init($url); + $handle = $this->curl->init($url); $resp = $this->_sendRequest($handle); return $resp; } @@ -488,14 +492,14 @@ public function makeRequest($method, $url, $data=array()) { * * @param mixed $url URL where we are making the request to * @param mixed $data Data that is used to make the request - * @access private + * @access protected * @return void */ protected function patch($url, $oauth, $data) { $url = $this->_addParametersToUrl($url, $oauth); - $handle = curl_init($url); - curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'PATCH'); - curl_setopt($handle, CURLOPT_POSTFIELDS, json_encode($data)); + $handle = $this->curl->init($url); + $this->curl->setopt($handle, CURLOPT_CUSTOMREQUEST, 'PATCH'); + $this->curl->setopt($handle, CURLOPT_POSTFIELDS, json_encode($data)); $resp = $this->_sendRequest($handle, array('Expect:', 'Content-Type: application/json')); return $resp; } @@ -507,14 +511,14 @@ protected function patch($url, $oauth, $data) { * * @param mixed $url URL where we are making the request to * @param mixed $data Data that is used to make the request - * @access private + * @access protected * @return void */ protected function post($url, $oauth) { - $handle = curl_init($url); + $handle = $this->curl->init($url); $postData = $this->buildData($oauth); - curl_setopt($handle, CURLOPT_POST, true); - curl_setopt($handle, CURLOPT_POSTFIELDS, $postData); + $this->curl->setopt($handle, CURLOPT_POST, true); + $this->curl->setopt($handle, CURLOPT_POSTFIELDS, $postData); $resp = $this->_sendRequest($handle); return $resp; } @@ -530,8 +534,8 @@ protected function post($url, $oauth) { */ protected function delete($url, $data) { $url = $this->_addParametersToUrl($url, $data); - $handle = curl_init($url); - curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'DELETE'); + $handle = $this->curl->init($url); + $this->curl->setopt($handle, CURLOPT_CUSTOMREQUEST, 'DELETE'); $resp = $this->_sendRequest($handle); return $resp; } @@ -563,19 +567,20 @@ public function buildData($data) { * @return void */ private function _sendRequest($handle, $headers = array('Expect:')) { - curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); - curl_setopt($handle, CURLOPT_HEADER, true); - curl_setopt($handle, CURLOPT_HTTPHEADER, $headers); - curl_setopt($handle, CURLOPT_USERAGENT, $this->userAgent); - curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); - curl_setopt($handle, CURLOPT_VERBOSE, FALSE); - curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 10); - curl_setopt($handle, CURLOPT_TIMEOUT, 90); - $resp = curl_exec($handle); + $this->curl->setopt($handle, CURLOPT_RETURNTRANSFER, true); + $this->curl->setopt($handle, CURLOPT_HEADER, true); + $this->curl->setopt($handle, CURLOPT_HTTPHEADER, $headers); + $this->curl->setopt($handle, CURLOPT_USERAGENT, $this->userAgent); + $this->curl->setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); + $this->curl->setopt($handle, CURLOPT_VERBOSE, FALSE); + $this->curl->setopt($handle, CURLOPT_CONNECTTIMEOUT, 10); + $this->curl->setopt($handle, CURLOPT_TIMEOUT, 90); + $resp = $this->curl->execute($handle); if ($resp) { return new CurlResponse($resp); } - $this->error = curl_errno($handle).' - '.curl_error($handle); + $this->error = $this->curl->errno($handle) . ' - ' . + $this->curl->error($handle); return false; } diff --git a/tests/OAuthApplicationTest.php b/tests/OAuthApplicationTest.php index a59151f..601d386 100644 --- a/tests/OAuthApplicationTest.php +++ b/tests/OAuthApplicationTest.php @@ -1,5 +1,6 @@ oauth = new OAuthApplication($parentApp); @@ -235,6 +239,20 @@ public function testCreateSignatureBase() { $this->assertTrue(strpos($baseString, $method) !== false); $this->assertTrue(strpos($baseString, urlencode($url))!== false); } + + /** + * A plus sign in a query param is treated as a plug sign whereas a plus + * sign in a POST body is treated as a space character. + */ + public function testCreateSignatureBaseEscapeParamWithPlus() { + list($mergeData, $requestData) = $this->generateRequestData(); + $method = 'GET'; + $url = 'http://www.somewhere.com/chicken?email=iluvchkn+10@somewhere.com'; + $encodedPlus = '%252B'; + + $baseString = $this->oauth->createSignatureBase($method, $url, $mergeData); + $this->assertTrue(strpos($baseString, $encodedPlus)!==FALSE); + } public function testSignRequest() { list($data, $requestData) = $this->generateRequestData(); @@ -302,4 +320,43 @@ public function testRequestReturnValueIsZeroNotInJSONFormat(){ $this->assertEquals($data,0); } + public function testMakeRequestGet() { + $stub = $this->getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($this->stubrsp)); + $this->oauth->curl = $stub; + $rsp = $this->oauth->makeRequest("GET", 'http://www.example.com/fakeresource'); + $this->assertEquals($rsp, "{data:fake}"); + } + + public function testMakeRequestPost() { + $stub = $this->getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($this->stubrsp)); + $this->oauth->curl = $stub; + $rsp = $this->oauth->makeRequest("POST", 'http://www.example.com/fakeresource'); + $this->assertEquals($rsp, "{data:fake}"); + } + + public function testMakeRequestPut() { + $stub = $this->getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($this->stubrsp)); + $this->oauth->curl = $stub; + $rsp = $this->oauth->makeRequest("PATCH", 'http://www.example.com/fakeresource'); + $this->assertEquals($rsp, "{data:fake}"); + } + + public function testMakeRequestDelete() { + $stub = $this->getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($this->stubrsp)); + $this->oauth->curl = $stub; + $rsp = $this->oauth->makeRequest("DELETE", 'http://www.example.com/fakeresource'); + $this->assertEquals($rsp, "{data:fake}"); + } } From 03e98245593ba9bc193dc1cc4c26e8af9ff35d48 Mon Sep 17 00:00:00 2001 From: Brian Korty Date: Mon, 23 Dec 2013 13:36:21 -0500 Subject: [PATCH 067/112] FIX SPACING PROBLEMS CAUSED BY MIX OF TABS AND SPACES Replace tab characters with spaces for files modified with last commit so that code indentation is consistent in all editors. --- aweber_api/curl_object.php | 54 ++++++++-------- aweber_api/oauth_application.php | 4 +- tests/OAuthApplicationTest.php | 106 +++++++++++++++---------------- 3 files changed, 82 insertions(+), 82 deletions(-) diff --git a/aweber_api/curl_object.php b/aweber_api/curl_object.php index 0f06867..a4dac3e 100644 --- a/aweber_api/curl_object.php +++ b/aweber_api/curl_object.php @@ -22,7 +22,7 @@ interface CurlInterface { * @access public * @return the error number or 0 if no error occured. */ - public function errno($ch); + public function errno($ch); /** * error @@ -32,7 +32,7 @@ public function errno($ch); * @access public * @return the error messge or '' if no error occured. */ - public function error($ch); + public function error($ch); /** * execute @@ -42,7 +42,7 @@ public function error($ch); * @access public * @return TRUE on success, FALSE on failure. */ - public function execute($ch); + public function execute($ch); /** * init @@ -52,19 +52,19 @@ public function execute($ch); * @access public * @return cURL handle on success, FALSE on failure. */ - public function init($url); + public function init($url); /** * setopt * * Encapsulates curl_setopt - Set an option for cURL transfer. * @param resource $ch - A cURL handle returned by init. - * @param int $opt - The CURLOPT to set. - * @param mixed $value - The value to set. + * @param int $opt - The CURLOPT to set. + * @param mixed $value - The value to set. * @access public * @return True on success, FALSE on failure. */ - public function setopt ($ch , $option , $value); + public function setopt ($ch , $option , $value); } @@ -79,27 +79,27 @@ public function setopt ($ch , $option , $value); */ class CurlObject implements CurlInterface { - public function errno($ch) { - return curl_errno($ch); - } - - public function error($ch) { - return curl_error($ch); - } - - public function execute($ch) { - return curl_exec($ch); - } - - public function init($url) { - return curl_init($url); - } - - public function setopt ($ch , $option , $value) { - return curl_setopt($ch, $option, $value); - } + public function errno($ch) { + return curl_errno($ch); + } + + public function error($ch) { + return curl_error($ch); + } + public function execute($ch) { + return curl_exec($ch); + } + + public function init($url) { + return curl_init($url); + } + + public function setopt ($ch , $option , $value) { + return curl_setopt($ch, $option, $value); + } + } -?> \ No newline at end of file +?> diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index bcd1668..b86261c 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -66,7 +66,7 @@ class OAuthApplication implements AWeberOAuthAdapter { public $signatureMethod = 'HMAC-SHA1'; public $version = '1.0'; - public $curl = false; + public $curl = false; /** * @var OAuthUser User currently interacting with the service provider @@ -93,7 +93,7 @@ public function __construct($parentApp = false) { $this->app = $parentApp; } $this->user = new OAuthUser(); - $this->curl = new CurlObject(); + $this->curl = new CurlObject(); } /** diff --git a/tests/OAuthApplicationTest.php b/tests/OAuthApplicationTest.php index 601d386..ed30003 100644 --- a/tests/OAuthApplicationTest.php +++ b/tests/OAuthApplicationTest.php @@ -10,7 +10,7 @@ class Object {} class TestOAuthAppliation extends PHPUnit_Framework_TestCase { public $stubrsp = - "HTTP/1.1 200 Ok\r\nDate: Fri, 20 Dec 2013 21:23:38 GMT\r\nContent-Type: application/json\r\n\r\n{data:fake}"; + "HTTP/1.1 200 Ok\r\nDate: Fri, 20 Dec 2013 21:23:38 GMT\r\nContent-Type: application/json\r\n\r\n{data:fake}"; public function setUp() { $parentApp = false; @@ -240,20 +240,20 @@ public function testCreateSignatureBase() { $this->assertTrue(strpos($baseString, urlencode($url))!== false); } - /** - * A plus sign in a query param is treated as a plug sign whereas a plus - * sign in a POST body is treated as a space character. - */ - public function testCreateSignatureBaseEscapeParamWithPlus() { - list($mergeData, $requestData) = $this->generateRequestData(); - $method = 'GET'; - $url = 'http://www.somewhere.com/chicken?email=iluvchkn+10@somewhere.com'; - $encodedPlus = '%252B'; - - $baseString = $this->oauth->createSignatureBase($method, $url, $mergeData); - $this->assertTrue(strpos($baseString, $encodedPlus)!==FALSE); - } + /** + * A plus sign in a query param is treated as a plug sign whereas a plus + * sign in a POST body is treated as a space character. + */ + public function testCreateSignatureBaseEscapeParamWithPlus() { + list($mergeData, $requestData) = $this->generateRequestData(); + $method = 'GET'; + $url = 'http://www.somewhere.com/chicken?email=iluvchkn+10@somewhere.com'; + $encodedPlus = '%252B'; + $baseString = $this->oauth->createSignatureBase($method, $url, $mergeData); + $this->assertTrue(strpos($baseString, $encodedPlus)!==FALSE); + } + public function testSignRequest() { list($data, $requestData) = $this->generateRequestData(); $method = 'GET'; @@ -320,43 +320,43 @@ public function testRequestReturnValueIsZeroNotInJSONFormat(){ $this->assertEquals($data,0); } - public function testMakeRequestGet() { - $stub = $this->getMock('CurlObject'); - $stub->expects($this->any()) - ->method('execute') - ->will($this->returnValue($this->stubrsp)); - $this->oauth->curl = $stub; - $rsp = $this->oauth->makeRequest("GET", 'http://www.example.com/fakeresource'); - $this->assertEquals($rsp, "{data:fake}"); - } - - public function testMakeRequestPost() { - $stub = $this->getMock('CurlObject'); - $stub->expects($this->any()) - ->method('execute') - ->will($this->returnValue($this->stubrsp)); - $this->oauth->curl = $stub; - $rsp = $this->oauth->makeRequest("POST", 'http://www.example.com/fakeresource'); - $this->assertEquals($rsp, "{data:fake}"); - } - - public function testMakeRequestPut() { - $stub = $this->getMock('CurlObject'); - $stub->expects($this->any()) - ->method('execute') - ->will($this->returnValue($this->stubrsp)); - $this->oauth->curl = $stub; - $rsp = $this->oauth->makeRequest("PATCH", 'http://www.example.com/fakeresource'); - $this->assertEquals($rsp, "{data:fake}"); - } - - public function testMakeRequestDelete() { - $stub = $this->getMock('CurlObject'); - $stub->expects($this->any()) - ->method('execute') - ->will($this->returnValue($this->stubrsp)); - $this->oauth->curl = $stub; - $rsp = $this->oauth->makeRequest("DELETE", 'http://www.example.com/fakeresource'); - $this->assertEquals($rsp, "{data:fake}"); - } + public function testMakeRequestGet() { + $stub = $this->getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($this->stubrsp)); + $this->oauth->curl = $stub; + $rsp = $this->oauth->makeRequest("GET", 'http://www.example.com/fakeresource'); + $this->assertEquals($rsp, "{data:fake}"); + } + + public function testMakeRequestPost() { + $stub = $this->getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($this->stubrsp)); + $this->oauth->curl = $stub; + $rsp = $this->oauth->makeRequest("POST", 'http://www.example.com/fakeresource'); + $this->assertEquals($rsp, "{data:fake}"); + } + + public function testMakeRequestPut() { + $stub = $this->getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($this->stubrsp)); + $this->oauth->curl = $stub; + $rsp = $this->oauth->makeRequest("PATCH", 'http://www.example.com/fakeresource'); + $this->assertEquals($rsp, "{data:fake}"); + } + + public function testMakeRequestDelete() { + $stub = $this->getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($this->stubrsp)); + $this->oauth->curl = $stub; + $rsp = $this->oauth->makeRequest("DELETE", 'http://www.example.com/fakeresource'); + $this->assertEquals($rsp, "{data:fake}"); + } } From 6401d027dbb2b7224017a7d04f700cc86553fac5 Mon Sep 17 00:00:00 2001 From: Brian Korty Date: Thu, 26 Dec 2013 12:53:32 -0500 Subject: [PATCH 068/112] Fix handling of reserved chars when generating oauth signatures Clearly define how reserved characters are to be encoded in calls to OAuthApplication->makeRequest. Treat reserved characters as though they are URL encoded when they are passed in as query params to the URL. Treat reserved characters as though they are not URL encoded when passed in as an entry in a data array. Generate unit tests to prove that the signature is being generated correctly. --- aweber_api/oauth_application.php | 9 +- tests/OAuthApplicationTest.php | 146 +++++++++++++++++++++++++++++-- 2 files changed, 146 insertions(+), 9 deletions(-) diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index b86261c..1c44f30 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -378,7 +378,7 @@ public function createSignatureBase($method, $url, $data) { $items = explode('&', $query); foreach ($items as $item) { list($key, $value) = explode('=', $item); - $data[$key] = $value; + $data[rawurldecode($key)] = rawurldecode($value); } } $url = $this->encode($url); @@ -429,16 +429,17 @@ public function signRequest($method, $url, $data) { * makeRequest * * Public facing function to make a request + * * @param mixed $method - * @param mixed $url - * @param mixed $data + * @param mixed $url - Reserved characters in query params MUST be escaped + * @param mixed $data - Reserved characters in values MUST NOT be escaped * @access public * @return void */ public function makeRequest($method, $url, $data=array()) { if ($this->debug) echo "\n** {$method}: $url\n"; - + switch (strtoupper($method)) { case 'POST': $oauth = $this->prepareRequest($method, $url, $data); diff --git a/tests/OAuthApplicationTest.php b/tests/OAuthApplicationTest.php index ed30003..1fae70b 100644 --- a/tests/OAuthApplicationTest.php +++ b/tests/OAuthApplicationTest.php @@ -7,7 +7,21 @@ class Object {} } -class TestOAuthAppliation extends PHPUnit_Framework_TestCase { +class PatchedOAuthApplication extends OAuthApplication { + + public $signatureBase = false; + + public function createSignature($sigBase, $sigKey) { + $this->signatureBase = $sigBase; + switch ($this->signatureMethod) { + case 'HMAC-SHA1': + default: + return base64_encode(hash_hmac('sha1', $sigBase, $sigKey, true)); + } + } +} + +class TestOAuthApplication extends PHPUnit_Framework_TestCase { public $stubrsp = "HTTP/1.1 200 Ok\r\nDate: Fri, 20 Dec 2013 21:23:38 GMT\r\nContent-Type: application/json\r\n\r\n{data:fake}"; @@ -326,7 +340,8 @@ public function testMakeRequestGet() { ->method('execute') ->will($this->returnValue($this->stubrsp)); $this->oauth->curl = $stub; - $rsp = $this->oauth->makeRequest("GET", 'http://www.example.com/fakeresource'); + $rsp = $this->oauth->makeRequest("GET", + 'http://www.example.com/fakeresource'); $this->assertEquals($rsp, "{data:fake}"); } @@ -336,7 +351,8 @@ public function testMakeRequestPost() { ->method('execute') ->will($this->returnValue($this->stubrsp)); $this->oauth->curl = $stub; - $rsp = $this->oauth->makeRequest("POST", 'http://www.example.com/fakeresource'); + $rsp = $this->oauth->makeRequest("POST", + 'http://www.example.com/fakeresource'); $this->assertEquals($rsp, "{data:fake}"); } @@ -346,7 +362,8 @@ public function testMakeRequestPut() { ->method('execute') ->will($this->returnValue($this->stubrsp)); $this->oauth->curl = $stub; - $rsp = $this->oauth->makeRequest("PATCH", 'http://www.example.com/fakeresource'); + $rsp = $this->oauth->makeRequest("PATCH", + 'http://www.example.com/fakeresource'); $this->assertEquals($rsp, "{data:fake}"); } @@ -356,7 +373,126 @@ public function testMakeRequestDelete() { ->method('execute') ->will($this->returnValue($this->stubrsp)); $this->oauth->curl = $stub; - $rsp = $this->oauth->makeRequest("DELETE", 'http://www.example.com/fakeresource'); + $rsp = $this->oauth->makeRequest("DELETE", + 'http://www.example.com/fakeresource'); $this->assertEquals($rsp, "{data:fake}"); } + + /** + * testMakeRequestContainsReservedCharInUrl + * + * Test request behavior as it relates to reserved chars in URL. + * + * This test verifies that escaped characters in the URL query + * params are handled correctly when generating the oauth + * signature base. For this specific test, an escaped plus + * sign needs to show up as %252B in the signature, not as + * %25252B + * + * @access public + * @return void + */ + public function testMakeRequestContainsReservedCharInUrl() { + $parentApp = false; + $patchedoauth = new PatchedOAuthApplication($parentApp); + $patchedoauth->consumerSecret = 'CONSUMERSECRET'; + $patchedoauth->consumerKey = 'consumer_key'; + + $stub = $this->getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($this->stubrsp)); + $patchedoauth->curl = $stub; + $rsp = $patchedoauth->makeRequest("GET", + 'http://www.example.com/fake?email=noone%2B@sp.com'); + $this->assertRegExp('/.+(\%252B).+/', $patchedoauth->signatureBase); + } + + /** + * testMakeRequestContainsSeperatorInUrl + * + * Test request behavior as it relates to separaters in URL. + * + * This test verifies that a non-sepator equals sign in the URL + * query params is handled correctly when generating the oauth + * signature base. For this specific test, an escaped plus + * sign needs to show up as %253D in the signature, not as + * %25253D + * + * @access public + * @return void + */ + public function testMakeRequestContainsSeparatorInUrl() { + $parentApp = false; + $patchedoauth = new PatchedOAuthApplication($parentApp); + $patchedoauth->consumerSecret = 'CONSUMERSECRET'; + $patchedoauth->consumerKey = 'consumer_key'; + + $stub = $this->getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($this->stubrsp)); + $patchedoauth->curl = $stub; + $rsp = $patchedoauth->makeRequest("GET", + 'http://www.example.com/fake?email=noone%3D@sp.com'); + $this->assertRegExp('/.+(\%253D).+/', $patchedoauth->signatureBase); + } + + /** + * testMakeRequestContainsReservedCharInData + * + * Test request behavior as it relates to reserved chars in data. + * + * This test verifies that reserved characters in the data array + * are handled correctly when generating the oauth signature base. + * For this specific test, a plus sign needs to show up as %252B + * in the signature, not as + or %25252B + * + * @access public + * @return void + */ + public function testMakeRequestContainsReservedCharInData() { + $parentApp = false; + $patchedoauth = new PatchedOAuthApplication($parentApp); + $patchedoauth->consumerSecret = 'CONSUMERSECRET'; + $patchedoauth->consumerKey = 'consumer_key'; + + $stub = $this->getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($this->stubrsp)); + $patchedoauth->curl = $stub; + $rsp = $patchedoauth->makeRequest("GET", 'http://www.example.com/fake', + array('email' => 'noone+1@sp.com')); + $this->assertRegExp('/.+(\%252B).+/', $patchedoauth->signatureBase); + } + + /** + * testMakeRequestContainsSeperatorInData + * + * Test request behavior as it relates to separators in data array. + * + * This test verifies that a non-separator equals sign in the data + * array is handled correctly when generating the oauth signature base. + * For this specific test, an equals sign needs to show up as %253D + * in the signature, not as %25253D + * + * @access public + * @return void + */ + public function testMakeRequestContainsSeparatorInData() { + $parentApp = false; + $patchedoauth = new PatchedOAuthApplication($parentApp); + $patchedoauth->consumerSecret = 'CONSUMERSECRET'; + $patchedoauth->consumerKey = 'consumer_key'; + + $stub = $this->getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($this->stubrsp)); + $patchedoauth->curl = $stub; + $rsp = $patchedoauth->makeRequest("GET", 'http://www.example.com/fake', + array('email' => 'noone=1@sp.com')); + $this->assertRegExp('/.+(\%253D).+/', $patchedoauth->signatureBase); + } } From 1b5aad6ba6e0330fc8a15ed35914f4451677bbc9 Mon Sep 17 00:00:00 2001 From: Brian Korty Date: Thu, 26 Dec 2013 16:37:35 -0500 Subject: [PATCH 069/112] Address Typos in Comments Fix the typos in comments that were pointed out in code review. --- aweber_api/curl_object.php | 8 +++----- tests/OAuthApplicationTest.php | 18 ++++++++++++------ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/aweber_api/curl_object.php b/aweber_api/curl_object.php index a4dac3e..39783ed 100644 --- a/aweber_api/curl_object.php +++ b/aweber_api/curl_object.php @@ -1,9 +1,9 @@ diff --git a/tests/OAuthApplicationTest.php b/tests/OAuthApplicationTest.php index 1fae70b..ef91e01 100644 --- a/tests/OAuthApplicationTest.php +++ b/tests/OAuthApplicationTest.php @@ -255,13 +255,19 @@ public function testCreateSignatureBase() { } /** - * A plus sign in a query param is treated as a plug sign whereas a plus - * sign in a POST body is treated as a space character. + * testCreateSignatureBaseEscapeParamWithPlus + * + * Test that reserved characters escaped in the URL query params are preserved + * correctly in the signature base. In this case, a %2B (plus) should be + * converted into a %252B in the signature base. + * + * @access public + * @return void */ public function testCreateSignatureBaseEscapeParamWithPlus() { list($mergeData, $requestData) = $this->generateRequestData(); $method = 'GET'; - $url = 'http://www.somewhere.com/chicken?email=iluvchkn+10@somewhere.com'; + $url = 'http://www.somewhere.com/chicken?email=iluvchkn%2B10@somewhere.com'; $encodedPlus = '%252B'; $baseString = $this->oauth->createSignatureBase($method, $url, $mergeData); @@ -413,10 +419,10 @@ public function testMakeRequestContainsReservedCharInUrl() { * * Test request behavior as it relates to separaters in URL. * - * This test verifies that a non-sepator equals sign in the URL + * This test verifies that a non-seperator equals sign in the URL * query params is handled correctly when generating the oauth - * signature base. For this specific test, an escaped plus - * sign needs to show up as %253D in the signature, not as + * signature base. For this specific test, an escaped equals + * character needs to show up as %253D in the signature, not as * %25253D * * @access public From 29475b545eafa13d965c65e52bca96fc06e82acf Mon Sep 17 00:00:00 2001 From: Brian Korty Date: Tue, 31 Dec 2013 11:04:03 -0500 Subject: [PATCH 070/112] Add Unit Tests for Collection Create Method Add unit tests for Collection create method to ensure that changes in the OAuthApplication module related to escaping reserved characters do not have unintended side effects in the AWeberCollections module. --- tests/AWeberCreateEntryTest.php | 126 +++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 2 deletions(-) diff --git a/tests/AWeberCreateEntryTest.php b/tests/AWeberCreateEntryTest.php index 144279d..b3c07cd 100644 --- a/tests/AWeberCreateEntryTest.php +++ b/tests/AWeberCreateEntryTest.php @@ -2,6 +2,12 @@ require_once('aweber_api/aweber_api.php'); require_once('mock_adapter.php'); +/** + * Unit Tests for Creating Collection Entries + * + * This class contains a set of unit tests verifying the + * functionality related to creating an entry in a collection. + */ class TestAWeberCreateEntry extends PHPUnit_Framework_TestCase { public function setUp() { @@ -15,9 +21,14 @@ public function setUp() { } /** - * Create Succeeded + * Create Success + * + * A unit test of a successful call to the Collection create method. + * Testing is limited to the Collection module; the OAuthAdapater + * module that handles the communications with the AWeber Public + * API Web Service is stubbed out. */ - public function testCreate_Success() { + public function testCreateSuccess() { $this->adapter->clearRequests(); $resp = $this->custom_fields->create(array('name' => 'AwesomeField')); @@ -36,4 +47,115 @@ public function testCreate_Success() { $this->assertEquals($req['method'], 'GET'); $this->assertEquals($req['uri'], '/accounts/1/lists/303449/custom_fields/2'); } + + /** + * Create Success With Adapter + * + * A unit test of a successful call to the Collection create method. + * Testing covers calls to the OAuthAdapter module, though the actual call + * to the Public API is mocked. + * + * Verifies that a Custom Field with the specified name is returned in the + * response. + * + * Note! The actual Web Service responses contain additional headers and + * response attributes that are not currently relevant to these tests. + */ + public function testCreateSuccessWithAdapter() { + + // Define the fake AWeber API responses. + $getCollectionRsp = +<<getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->onConsecutiveCalls($postCustomFieldRsp, + $getCustomFieldRsp)); + $aweber->adapter->curl = $stub; + + // Create an empty custom field collection to work on. + $url = "/accounts/12345/lists/67890/custom_fields"; + $data = json_decode($getCollectionRsp, true); + $custom_fields = new AWeberCollection($data, $url, $aweber->adapter); + + // Finally the actual unit test. Create the new custom field + $rsp = $custom_fields->create(array('name' => 'Field With Spaces')); + $this->assertEquals($rsp->data['name'],'Field With Spaces'); + } + + /** + * Create Failure With Adapter + * + * A unit test of a failed call to the Collection create method. + * Testing covers calls to the OAuthAdapter module, though the actual call + * to the Public API is mocked. + * + * Verifies that an AWeberAPIException is thrown as a result of a + * disallowed character. + * + * Note! The actual Web Service responses contain additional headers and + * response attributes that are not currently relevant to these tests. + */ + public function testCreateFailureWithAdapter() { + + // Define the fake AWeber API responses. + $getCollectionRsp = +<<getMock('CurlObject'); + $stub->expects($this->any()) + ->method('execute') + ->will($this->returnValue($postCustomFieldRsp)); + $aweber->adapter->curl = $stub; + + // Create an empty custom field collection to work on. + $url = "/accounts/12345/lists/67890/custom_fields"; + $data = json_decode($getCollectionRsp, true); + $custom_fields = new AWeberCollection($data, $url, $aweber->adapter); + + // Create the new custom field + try { + $rsp = $custom_fields->create(array('name' => 'Field With Spaces')); + } + + // Finally the actual unit test. Verify that the create fails. + catch (AWeberAPIException $expected){ + $this->assertEquals($expected->status, 400); + return; + } + $this->fail('An AWeberResponseError was not raised'); + } } From 1f249cd74d2eacd353b8e906c56532bf1b1baeb9 Mon Sep 17 00:00:00 2001 From: Brian Korty Date: Tue, 31 Dec 2013 13:51:20 -0500 Subject: [PATCH 071/112] Change custom field name in test Change the name of the custom field being created in the unit test testCreateFailureWithAdaptor from 'Field With Spaces' to 'Field+With+Plus+Chars' because the original name is a valid custom field name. --- tests/AWeberCreateEntryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/AWeberCreateEntryTest.php b/tests/AWeberCreateEntryTest.php index b3c07cd..2a0b95f 100644 --- a/tests/AWeberCreateEntryTest.php +++ b/tests/AWeberCreateEntryTest.php @@ -148,7 +148,7 @@ public function testCreateFailureWithAdapter() { // Create the new custom field try { - $rsp = $custom_fields->create(array('name' => 'Field With Spaces')); + $rsp = $custom_fields->create(array('name' => 'Field+With+Plus+Chars')); } // Finally the actual unit test. Verify that the create fails. From 43f15134bc49b92a3a6a743aee124f901f13cc31 Mon Sep 17 00:00:00 2001 From: Brian Korty Date: Tue, 31 Dec 2013 15:19:04 -0500 Subject: [PATCH 072/112] Fix unsafe array operation. Fix unsafe array operation inOAuthApplication->createSignatureBase flagged by Travis: Only variables should be passed by reference. Store the output of explode in a temporary variable and pass that variable into array_shift. --- aweber_api/oauth_application.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 1c44f30..3b53a92 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -374,7 +374,8 @@ public function createSignatureBase($method, $url, $data) { $method = $this->encode(strtoupper($method)); $query = parse_url($url, PHP_URL_QUERY); if ($query) { - $url = array_shift(explode('?', $url, 2)); + $parts = explode('?', $url, 2); + $url = array_shift($parts); $items = explode('&', $query); foreach ($items as $item) { list($key, $value) = explode('=', $item); From a697b76539da01063c2c6ad2c634e58e16ff40a5 Mon Sep 17 00:00:00 2001 From: John Brodie Date: Tue, 4 Feb 2014 15:49:52 -0500 Subject: [PATCH 073/112] composer: Add composer.json Add a composer file so we can upload the client library to Packagist. --- composer.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 composer.json diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..8118249 --- /dev/null +++ b/composer.json @@ -0,0 +1,20 @@ +{ + "name": "aweber/aweber", + "description": "The official AWeber API client library.", + "homepage": "https://www.aweber.com", + "license": "GPL-2.0", + "keywords": ["email", "api", "client"], + "support": { + "email": "api@aweber.com", + "source": "https://github.com/aweber/AWeber-API-PHP-Library", + "issues": "https://github.com/aweber/AWeber-API-PHP-Library" + }, + "require": { + "php": ">=5.0.0" + }, + "autoload": { + "psr-4": { + "": "aweber_api/" + } + } +} From 45c5e6b5f836ce429395bbb84524eeea103db4e7 Mon Sep 17 00:00:00 2001 From: John Brodie Date: Tue, 4 Feb 2014 16:08:56 -0500 Subject: [PATCH 074/112] Remove php requirement --- composer.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/composer.json b/composer.json index 8118249..97ba36f 100644 --- a/composer.json +++ b/composer.json @@ -9,9 +9,6 @@ "source": "https://github.com/aweber/AWeber-API-PHP-Library", "issues": "https://github.com/aweber/AWeber-API-PHP-Library" }, - "require": { - "php": ">=5.0.0" - }, "autoload": { "psr-4": { "": "aweber_api/" From 887e9ca9ea836368ebd8de96a73ac9aba8c747d4 Mon Sep 17 00:00:00 2001 From: John Brodie Date: Wed, 5 Feb 2014 09:42:39 -0500 Subject: [PATCH 075/112] Bump version --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e3b36dc..4121015 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ subscriber information. Changelog: ---------- +2014-02-05: v1.1.12 + * Add composer file. + 2013-04-25: v1.1.11 * Fixed a bug in the Collection Find Subscriber method where fetching the next page in the collection had not included the previous search parameters. From 540b2c4cc3b0e5140ba18a21afb20db23ed9c7df Mon Sep 17 00:00:00 2001 From: Will Fitch Date: Thu, 6 Feb 2014 12:01:10 -0500 Subject: [PATCH 076/112] Revert "Merge pull request #36 from aweber/add-composer-json" This reverts commit 6c2e3c04306b03e748b51058dbb0160fea16ddc6, reversing changes made to 1815ec881d8794c53c5db9c8636aa7f161591b83. --- composer.json | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 composer.json diff --git a/composer.json b/composer.json deleted file mode 100644 index 97ba36f..0000000 --- a/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "aweber/aweber", - "description": "The official AWeber API client library.", - "homepage": "https://www.aweber.com", - "license": "GPL-2.0", - "keywords": ["email", "api", "client"], - "support": { - "email": "api@aweber.com", - "source": "https://github.com/aweber/AWeber-API-PHP-Library", - "issues": "https://github.com/aweber/AWeber-API-PHP-Library" - }, - "autoload": { - "psr-4": { - "": "aweber_api/" - } - } -} From 860ef8d598d24ace7354b41a48dc9d7dfc8a39d6 Mon Sep 17 00:00:00 2001 From: Will Fitch Date: Thu, 6 Feb 2014 12:01:49 -0500 Subject: [PATCH 077/112] Revert "Merge pull request #37 from aweber/bump-version" This reverts commit c139021dfa6445945b242bdb1e58e6b0233f4863, reversing changes made to 6c2e3c04306b03e748b51058dbb0160fea16ddc6. --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 4121015..e3b36dc 100644 --- a/README.md +++ b/README.md @@ -61,9 +61,6 @@ subscriber information. Changelog: ---------- -2014-02-05: v1.1.12 - * Add composer file. - 2013-04-25: v1.1.11 * Fixed a bug in the Collection Find Subscriber method where fetching the next page in the collection had not included the previous search parameters. From bfbd13e9252bf72b40bbcb35ef67ebc651b4f867 Mon Sep 17 00:00:00 2001 From: Amber Heilman Date: Tue, 17 Feb 2015 15:39:21 -0500 Subject: [PATCH 078/112] oauth_app.py: remove double encoding --- aweber_api/oauth_application.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 3b53a92..29e580d 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -310,7 +310,7 @@ public function createSignature($sigBase, $sigKey) { * @return void Encoded data */ protected function encode($data) { - return rawurlencode(utf8_encode($data)); + return rawurlencode($data); } /** @@ -384,6 +384,7 @@ public function createSignatureBase($method, $url, $data) { } $url = $this->encode($url); $data = $this->encode($this->collapseDataForSignature($data)); + return $method.'&'.$url.'&'.$data; } From 7e0798793718c8e033bd1c80f8eb79425c8e1ebf Mon Sep 17 00:00:00 2001 From: Amber Heilman Date: Tue, 17 Feb 2015 17:17:55 -0500 Subject: [PATCH 079/112] bump to 1.1.13 --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e3b36dc..42d2d5e 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ subscriber information. Changelog: ---------- +2015-02-17: v1.1.13 + * Remove double encoding in requests to support utf-8 + 2013-04-25: v1.1.11 * Fixed a bug in the Collection Find Subscriber method where fetching the next page in the collection had not included the previous search parameters. From 4089a99d47dce0d5689178a7c96a9eb8c7b56bcd Mon Sep 17 00:00:00 2001 From: Amber Heilman Date: Thu, 19 Feb 2015 11:38:16 -0500 Subject: [PATCH 080/112] Revert "Revert "Merge pull request #36 from aweber/add-composer-json"" This reverts commit 540b2c4cc3b0e5140ba18a21afb20db23ed9c7df. --- composer.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 composer.json diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..97ba36f --- /dev/null +++ b/composer.json @@ -0,0 +1,17 @@ +{ + "name": "aweber/aweber", + "description": "The official AWeber API client library.", + "homepage": "https://www.aweber.com", + "license": "GPL-2.0", + "keywords": ["email", "api", "client"], + "support": { + "email": "api@aweber.com", + "source": "https://github.com/aweber/AWeber-API-PHP-Library", + "issues": "https://github.com/aweber/AWeber-API-PHP-Library" + }, + "autoload": { + "psr-4": { + "": "aweber_api/" + } + } +} From 4749c8dc197cc0f024fd2634c28037fa80261816 Mon Sep 17 00:00:00 2001 From: Amber Heilman Date: Thu, 19 Feb 2015 11:39:14 -0500 Subject: [PATCH 081/112] Revert "Revert "Merge pull request #37 from aweber/bump-version"" This reverts commit 860ef8d598d24ace7354b41a48dc9d7dfc8a39d6. Conflicts: README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 42d2d5e..d747989 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,9 @@ Changelog: 2015-02-17: v1.1.13 * Remove double encoding in requests to support utf-8 +2014-02-05: v1.1.12 + * Add composer file. + 2013-04-25: v1.1.11 * Fixed a bug in the Collection Find Subscriber method where fetching the next page in the collection had not included the previous search parameters. From 5cd1fabcd9a27a7a177a705761aeb34a08ca8d36 Mon Sep 17 00:00:00 2001 From: Dan Piston Date: Tue, 8 Nov 2016 10:25:19 -0500 Subject: [PATCH 082/112] Added response for Broadcast entry --- aweber_api/aweber.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aweber_api/aweber.php b/aweber_api/aweber.php index 49f0611..7fcca54 100644 --- a/aweber_api/aweber.php +++ b/aweber_api/aweber.php @@ -120,7 +120,7 @@ protected function _cleanUrl($url) { */ protected function readResponse($response, $url) { $this->adapter->parseAsError($response); - if (!empty($response['id'])) { + if (!empty($response['id']) || !empty($response['broadcast_id'])) { return new AWeberEntry($response, $url, $this->adapter); } else if (array_key_exists('entries', $response)) { return new AWeberCollection($response, $url, $this->adapter); From 875e06cd21e42be5d3357cc03570afa12053f1a6 Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Tue, 8 Nov 2016 11:30:59 -0500 Subject: [PATCH 083/112] Set broadcast type --- aweber_api/aweber_entry.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/aweber_api/aweber_entry.php b/aweber_api/aweber_entry.php index c98e64b..b74051b 100644 --- a/aweber_api/aweber_entry.php +++ b/aweber_api/aweber_entry.php @@ -54,10 +54,14 @@ public function attrs() { */ protected function _type() { if (empty($this->type)) { - $typeLink = $this->data['resource_type_link']; - if (empty($typeLink)) return null; - list($url, $type) = explode('#', $typeLink); - $this->type = $type; + if (!empty($this->data['resource_type_link'])) { + list($url, $type) = explode('#', $this->data['resource_type_link']); + $this->type = $type; + } elseif (!empty($this->data['broadcast_id'])) { + $this->type = 'broadcast'; + } else { + return null; + } } return $this->type; } From 6ad5d285869c9e616ffeb09bd824add5d7080924 Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Tue, 8 Nov 2016 11:31:17 -0500 Subject: [PATCH 084/112] Broadcast entry tests --- tests/AWeberAPITest.php | 13 +++++++++++++ tests/data/broadcasts/1337.json | 1 + tests/mock_adapter.php | 1 + 3 files changed, 15 insertions(+) create mode 100644 tests/data/broadcasts/1337.json diff --git a/tests/AWeberAPITest.php b/tests/AWeberAPITest.php index 15ec63d..6d4c4cc 100644 --- a/tests/AWeberAPITest.php +++ b/tests/AWeberAPITest.php @@ -83,5 +83,18 @@ public function test_loadFromUrl() { $this->assertEquals($list->id, '303449'); } + /** + * Load from URL should take a relative URL and return the correct + * object based on that request. Allows skipping around the tree + * based on URLs, not just walking it. + */ + public function test_loadFromUrl_broadcast() { + $this->aweber->setAdapter($this->adapter); + $list = $this->aweber->loadFromUrl('/accounts/1/lists/303449/broadcasts/1337'); + + $this->assertTrue(is_a($list, 'AWeberEntry')); + $this->assertEquals($list->type, 'broadcast'); + $this->assertEquals($list->broadcast_id, '1337'); + } } ?> diff --git a/tests/data/broadcasts/1337.json b/tests/data/broadcasts/1337.json new file mode 100644 index 0000000..3f6ebeb --- /dev/null +++ b/tests/data/broadcasts/1337.json @@ -0,0 +1 @@ +{"archive_url": "http://archive.aweber.com/awlist303449/JowqO", "sent_at": "2016-11-07T09:55:10.132392-05:00", "facebook_integration": null, "self_link": "https://api.aweber.com/1.0/accounts/1/lists/303449/broadcasts/33873982", "is_archived": true, "stats": {"num_undeliv": null, "unique_clicks": 0, "unique_opens": 0, "num_emailed": 1, "num_complaints": 0}, "status": "sent", "scheduled_for": "2016-11-07T09:55:01.871213-05:00", "twitter_integration": null, "exclude_lists": [], "click_tracking_enabled": true, "notify_on_send": true, "body_html": "Hi there!", "body_text": "Hi there!", "subject": "bork links", "has_customized_body_text": false, "created_at": "2016-11-07T14:53:13", "segment_name": "All Subscribers", "include_lists": [], "links": [{"rel": "list_archive_rss_url", "href": "http://archive.aweber.com/awlist303449.rss"}, {"rel": "list_archive_url", "href": "http://archive.aweber.com/awlist303449"}], "broadcast_id": 1337} diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php index 174c812..3a87a8e 100644 --- a/tests/mock_adapter.php +++ b/tests/mock_adapter.php @@ -36,6 +36,7 @@ function get_mock_adapter() { $map['GET' ]['/accounts/1?ws.op=getWebFormSplitTests' ] = array(200, 'accounts/webFormSplitTests'); $map['GET' ]['/accounts/1?ws.op=getWebForms' ] = array(200, 'accounts/webForms'); $map['GET' ]['/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.show=total_size' ] = array(200, 'empty'); +$map['GET' ]['/accounts/1/lists/303449/broadcasts/1337' ] = array(200, 'broadcasts/1337'); # collection pagination tests $map['GET' ]['/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=0&ws.op=find' ] = array(200, 'subscribers/find_1of2'); From bd5d0143b01831f14ce2b6b44eaffb0f50a59085 Mon Sep 17 00:00:00 2001 From: stevee Date: Wed, 9 Nov 2016 10:41:51 -0500 Subject: [PATCH 085/112] Bump Version to v1.1.15 --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index d747989..be57171 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ subscriber information. Changelog: ---------- +2016-11-09: v1.1.15 + * Create AWeberEntry for Broadcast Entry endpoint + 2015-02-17: v1.1.13 * Remove double encoding in requests to support utf-8 From f5e5904f0d7a31998242f79912ba981a12db43b0 Mon Sep 17 00:00:00 2001 From: Brett Santore Date: Mon, 14 Nov 2016 14:55:41 -0500 Subject: [PATCH 086/112] Ignore development directories --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 9f6aea2..5b06d79 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ ehthumbs.db *.swo *.swp *~ +/vendor +/.idea From e29e84469321e49bc83d24f9acc7e7d6130e57bd Mon Sep 17 00:00:00 2001 From: Brett Santore Date: Mon, 14 Nov 2016 17:04:41 -0500 Subject: [PATCH 087/112] add composer dependencies for ant --- .gitignore | 5 + build.xml | 299 ++++++++++++++++++++++++++------------------------ composer.json | 44 +++++--- 3 files changed, 188 insertions(+), 160 deletions(-) diff --git a/.gitignore b/.gitignore index 9f6aea2..4089a0a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,8 @@ ehthumbs.db *.swo *.swp *~ +cache.properties +build +!build/phpcs.xml +!build/phpmd.xml +!build/phpunit.xml diff --git a/build.xml b/build.xml index 3abaa40..54705e7 100644 --- a/build.xml +++ b/build.xml @@ -1,149 +1,156 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/composer.json b/composer.json index 97ba36f..d0931cf 100644 --- a/composer.json +++ b/composer.json @@ -1,17 +1,33 @@ { - "name": "aweber/aweber", - "description": "The official AWeber API client library.", - "homepage": "https://www.aweber.com", - "license": "GPL-2.0", - "keywords": ["email", "api", "client"], - "support": { - "email": "api@aweber.com", - "source": "https://github.com/aweber/AWeber-API-PHP-Library", - "issues": "https://github.com/aweber/AWeber-API-PHP-Library" - }, - "autoload": { - "psr-4": { - "": "aweber_api/" - } + "name": "aweber/aweber", + "description": "The official AWeber API client library.", + "homepage": "https://www.aweber.com", + "license": "GPL-2.0", + "keywords": [ + "email", + "api", + "client" + ], + "support": { + "email": "api@aweber.com", + "source": "https://github.com/aweber/AWeber-API-PHP-Library", + "issues": "https://github.com/aweber/AWeber-API-PHP-Library" + }, + "autoload": { + "psr-4": { + "": "aweber_api/" } + }, + "require-dev": { + "phpdocumentor/phpdocumentor": "^2.9", + "pdepend/pdepend": "^2.2", + "phpmd/phpmd": "^2.4", + "bamboohr/phpcs": "^0.1.4", + "sebastian/phpcpd": "^2.0", + "phploc/phploc": "^3.0", + "squizlabs/php_codesniffer": "^2.7", + "php-di/phpdoc-reader": "^2.0", + "mayflower/php-codebrowser": "^1.1", + "phpunit/phpunit": "^5.6" + } } From c7481f13737122ce32b515f07b478ef506132255 Mon Sep 17 00:00:00 2001 From: Brett Santore Date: Mon, 14 Nov 2016 17:14:36 -0500 Subject: [PATCH 088/112] update test documentation --- README.md | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index be57171..09c7775 100644 --- a/README.md +++ b/README.md @@ -145,31 +145,9 @@ Testing the PHP api library requires installation of a few utilities. Setup `/etc/php.ini` configuration file. Make sure `include_path` contains the correct directories.(`/usr/lib/php` on MacOS) Set `date.timezone` to your local timezone. -[PHP PEAR](http://pear.php.net/manual/en/installation.getting.php) is -used to install utilities for testing and code metrics. Upgrade to the -latest version using `sudo pear upgrade pear`. - -[PHP QA Tools](http://pear.phpqatools.org/) contain a collection of PHP testing tools. The following commands were needed to install: - -```bash -sudo pear upgrade -sudo pear config-set auto_discover 1 -sudo pear channel-discover pear.phpqatools.org -sudo pear install phpqatools/phpqatools -``` - -If installing PHP QA Tools fails due to missing channels, manually add the missing channels: - -```bash -sudo pear channel-discover pear.phpunit.de -sudo pear channel-discover pear.pdepend.org -sudo pear channel-discover pear.phpmd.org -sudo pear channel-discover components.ez.no -sudo pear channel-discover pear.symfony-project.com -``` - ### Execute Tests ### -Once the above requirements are installed, run the tests from the base -directory using the command: `ant phpunit`. +Once the above requirements are installed, make sure to run `composer install`, this will ensure all the test dependencies are installed. + +Run the tests from the base directory using the command: `ant`. -To run the entire suite of checks and tests, run: `ant`. +Individual test can be run by specifying ant targets: `ant phpunit`, `ant phpcs`. From c155e7d147abd499210cd3f454e3968f14e61eb6 Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Fri, 16 Dec 2016 14:48:09 -0500 Subject: [PATCH 089/112] autoload with classmap --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index d0931cf..99bec3f 100644 --- a/composer.json +++ b/composer.json @@ -14,9 +14,9 @@ "issues": "https://github.com/aweber/AWeber-API-PHP-Library" }, "autoload": { - "psr-4": { - "": "aweber_api/" - } + "classmap": [ + "aweber_api/" + ] }, "require-dev": { "phpdocumentor/phpdocumentor": "^2.9", From e81acfef1d9df65c11ca6cc347561d142de5a9b0 Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Fri, 16 Dec 2016 14:49:15 -0500 Subject: [PATCH 090/112] composer.lock in .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2fb67bb..120e0e9 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ cache.properties build !build/phpcs.xml !build/phpmd.xml -!build/phpunit.xml \ No newline at end of file +!build/phpunit.xml +/composer.lock From 4d41408c39dcd969262decbe436b4245e00b03ec Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Mon, 21 Aug 2017 13:15:40 -0400 Subject: [PATCH 091/112] Modifying methods to allow for headers to be passed in the request. This is to fix the issue with UTF-8 characters. Adding asserts to verify that the 'Content-Type' is properly set on the methods. --- aweber_api/aweber_collection.php | 6 ++-- aweber_api/aweber_entry.php | 18 +++++----- aweber_api/oauth_application.php | 55 ++++++++++++++++-------------- tests/AWeberCollectionFindTest.php | 4 +++ tests/AWeberCreateEntryTest.php | 2 ++ tests/AWeberEntryTest.php | 4 +++ tests/mock_adapter.php | 9 ++--- 7 files changed, 57 insertions(+), 41 deletions(-) diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index 196da7f..26c0bc5 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -86,7 +86,7 @@ public function getParentEntry(){ /** * _type * - * Interpret what type of resources are held in this collection by + * Interpret what type of resources are held in this collection by * analyzing the URL * * @access protected @@ -116,7 +116,7 @@ protected function _type() { public function create($kv_pairs) { # Create Resource $params = array_merge(array('ws.op' => 'create'), $kv_pairs); - $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers')); + $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers'), array('Content-Type: application/json')); # Return new Resource $url = $data['Location']; @@ -137,7 +137,7 @@ public function create($kv_pairs) { * * filtering on attributes that require additional permissions to * display requires an app authorized with those additional permissions. * @access public - * @return AWeberCollection + * @return AWeberCollection */ public function find($search_data) { # invoke find operation diff --git a/aweber_api/aweber_entry.php b/aweber_api/aweber_entry.php index b74051b..1b01984 100644 --- a/aweber_api/aweber_entry.php +++ b/aweber_api/aweber_entry.php @@ -46,9 +46,9 @@ public function attrs() { } /** - * _type + * _type * - * Used to pull the name of this resource from its resource_type_link + * Used to pull the name of this resource from its resource_type_link * @access protected * @return String */ @@ -123,7 +123,7 @@ public function move($list, $last_followup_message_number_sent=NULL) { */ public function save() { if (!empty($this->_localDiff)) { - $data = $this->adapter->request('PATCH', $this->url, $this->_localDiff, array('return' => 'status')); + $data = $this->adapter->request('PATCH', $this->url, $this->_localDiff, array('return' => 'status'), array('Content-Type: application/json')); } $this->_localDiff = array(); return true; @@ -133,10 +133,10 @@ public function save() { /** * __get * - * Used to look up items in data, and special properties like type and + * Used to look up items in data, and special properties like type and * child collections dynamically. * - * @param String $value Attribute being accessed + * @param String $value Attribute being accessed * @access public * @throws AWeberResourceNotImplemented * @return mixed @@ -276,11 +276,11 @@ public function getWebFormSplitTests() { /** * _parseNamedOperation * - * Turns a dumb array of json into an array of Entries. This is NOT + * Turns a dumb array of json into an array of Entries. This is NOT * a collection, but simply an array of entries, as returned from a * named operation. * - * @param array $data + * @param array $data * @access protected * @return array */ @@ -288,7 +288,7 @@ protected function _parseNamedOperation($data) { $results = array(); foreach($data as $entryData) { $results[] = new AWeberEntry($entryData, str_replace($this->adapter->app->getBaseUri(), '', - $entryData['self_link']), $this->adapter); + $entryData['self_link']), $this->adapter); } return $results; } @@ -308,7 +308,7 @@ protected function _methodFor($entryTypes) { } /** - * _getCollection + * _getCollection * * Returns the AWeberCollection object representing the given * collection name, relative to this entry. diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 29e580d..8e8f885 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -107,7 +107,7 @@ public function __construct($parentApp = false) { * @access public * @return void */ - public function request($method, $uri, $data = array(), $options = array()) { + public function request($method, $uri, $data = array(), $options = array(), $headers = array()) { $uri = $this->app->removeBaseUri($uri); $url = $this->app->getBaseUri() . $uri; @@ -120,7 +120,7 @@ public function request($method, $uri, $data = array(), $options = array()) { } } - $response = $this->makeRequest($method, $url, $data); + $response = $this->makeRequest($method, $url, $data, $headers); if (!empty($options['return'])) { if ($options['return'] == 'status') { return $response->headers['Status-Code']; @@ -226,22 +226,23 @@ protected function requiredFromResponse($data, $requiredFields) { * Make a get request. Used to exchange user tokens with serice provider. * @param mixed $url URL to make a get request from. * @param array $data Data for the request. + * @param mixed $headers Headers for the request * @access protected * @return void */ - protected function get($url, $data) { + protected function get($url, $data, $headers) { $url = $this->_addParametersToUrl($url, $data); $handle = $this->curl->init($url); - $resp = $this->_sendRequest($handle); + $resp = $this->_sendRequest($handle, $headers); return $resp; } /** * _addParametersToUrl * - * Adds the parameters in associative array $data to the + * Adds the parameters in associative array $data to the * given URL - * @param String $url URL + * @param String $url URL * @param array $data Parameters to be added as a query string to * the URL provided * @access protected @@ -431,36 +432,36 @@ public function signRequest($method, $url, $data) { * makeRequest * * Public facing function to make a request - * + * * @param mixed $method * @param mixed $url - Reserved characters in query params MUST be escaped * @param mixed $data - Reserved characters in values MUST NOT be escaped * @access public * @return void */ - public function makeRequest($method, $url, $data=array()) { + public function makeRequest($method, $url, $data=array(), $headers=array()) { if ($this->debug) echo "\n** {$method}: $url\n"; - + switch (strtoupper($method)) { case 'POST': $oauth = $this->prepareRequest($method, $url, $data); - $resp = $this->post($url, $oauth); + $resp = $this->post($url, $oauth, $data, $headers); break; case 'GET': $oauth = $this->prepareRequest($method, $url, $data); - $resp = $this->get($url, $oauth, $data); + $resp = $this->get($url, $oauth, $data, $headers); break; case 'DELETE': $oauth = $this->prepareRequest($method, $url, $data); - $resp = $this->delete($url, $oauth); + $resp = $this->delete($url, $oauth, $headers); break; case 'PATCH': $oauth = $this->prepareRequest($method, $url, array()); - $resp = $this->patch($url, $oauth, $data); + $resp = $this->patch($url, $oauth, $data, $headers); break; } @@ -493,17 +494,18 @@ public function makeRequest($method, $url, $data=array()) { * * Prepare an OAuth put method. * - * @param mixed $url URL where we are making the request to - * @param mixed $data Data that is used to make the request + * @param mixed $url URL where we are making the request to + * @param mixed $data Data that is used to make the request + * @param mixed $headers Headers for the request * @access protected * @return void */ - protected function patch($url, $oauth, $data) { + protected function patch($url, $oauth, $data, $headers) { $url = $this->_addParametersToUrl($url, $oauth); $handle = $this->curl->init($url); $this->curl->setopt($handle, CURLOPT_CUSTOMREQUEST, 'PATCH'); $this->curl->setopt($handle, CURLOPT_POSTFIELDS, json_encode($data)); - $resp = $this->_sendRequest($handle, array('Expect:', 'Content-Type: application/json')); + $resp = $this->_sendRequest($handle, $headers); return $resp; } @@ -512,17 +514,19 @@ protected function patch($url, $oauth, $data) { * * Prepare an OAuth post method. * - * @param mixed $url URL where we are making the request to - * @param mixed $data Data that is used to make the request + * @param mixed $url URL where we are making the request to + * @param mixed $data Data that is used to make the request + * @param mixed $headers Headers for the request * @access protected * @return void */ - protected function post($url, $oauth) { + protected function post($url, $oauth, $data, $headers = array()) { + $url = $this->_addParametersToUrl($url, $oauth); $handle = $this->curl->init($url); - $postData = $this->buildData($oauth); $this->curl->setopt($handle, CURLOPT_POST, true); + $postData = in_array("Content-Type: application/json", $headers) ? json_encode($data) : $this->buildData($data); $this->curl->setopt($handle, CURLOPT_POSTFIELDS, $postData); - $resp = $this->_sendRequest($handle); + $resp = $this->_sendRequest($handle, $headers); return $resp; } @@ -532,14 +536,15 @@ protected function post($url, $oauth) { * Makes a DELETE request * @param mixed $url URL where we are making the request to * @param mixed $data Data that is used in the request + * @param mixed $headers Headers for the request * @access protected * @return void */ - protected function delete($url, $data) { + protected function delete($url, $data, $headers = array()) { $url = $this->_addParametersToUrl($url, $data); $handle = $this->curl->init($url); $this->curl->setopt($handle, CURLOPT_CUSTOMREQUEST, 'DELETE'); - $resp = $this->_sendRequest($handle); + $resp = $this->_sendRequest($handle, $headers); return $resp; } @@ -569,7 +574,7 @@ public function buildData($data) { * @access private * @return void */ - private function _sendRequest($handle, $headers = array('Expect:')) { + private function _sendRequest($handle, $headers = array()) { $this->curl->setopt($handle, CURLOPT_RETURNTRANSFER, true); $this->curl->setopt($handle, CURLOPT_HEADER, true); $this->curl->setopt($handle, CURLOPT_HTTPHEADER, $headers); diff --git a/tests/AWeberCollectionFindTest.php b/tests/AWeberCollectionFindTest.php index c526d34..9cc62fb 100644 --- a/tests/AWeberCollectionFindTest.php +++ b/tests/AWeberCollectionFindTest.php @@ -32,10 +32,12 @@ public function testFind_ReturnsEntries() { $req = $this->adapter->requestsMade[0]; $this->assertEquals($req['method'], 'GET'); $this->assertEquals($req['uri'], $expected_url); + $this->assertEmpty($req['headers'], "Find request shouldn't have a Content-Type header"); $req = $this->adapter->requestsMade[1]; $this->assertEquals($req['method'], 'GET'); $this->assertEquals($req['uri'], $expected_url . "&ws.show=total_size"); + $this->assertEmpty($req['headers'], "Find request shouldn't have a Content-Type header"); # Asserts on the returned data $this->assertTrue(is_a($found_subscribers, 'AWeberCollection')); @@ -57,10 +59,12 @@ public function testFindDoesNot_ReturnsEntries() { $req = $this->adapter->requestsMade[0]; $this->assertEquals($req['method'], 'GET'); $this->assertEquals($req['uri'], $expected_url); + $this->assertEmpty($req['headers'], "Find request shouldn't have a Content-Type header"); $req = $this->adapter->requestsMade[1]; $this->assertEquals($req['method'], 'GET'); $this->assertEquals($req['uri'], $expected_url . "&ws.show=total_size"); + $this->assertEmpty($req['headers'], "Find request shouldn't have a Content-Type header"); # Asserts on the returned data $this->assertTrue(is_a($found_subscribers, 'AWeberCollection')); diff --git a/tests/AWeberCreateEntryTest.php b/tests/AWeberCreateEntryTest.php index 2a0b95f..aa10909 100644 --- a/tests/AWeberCreateEntryTest.php +++ b/tests/AWeberCreateEntryTest.php @@ -42,10 +42,12 @@ public function testCreateSuccess() { $this->assertEquals($req['data'], array( 'ws.op' => 'create', 'name' => 'AwesomeField')); + $this->assertEquals(array('Content-Type: application/json'), $req['headers'], "Create request should have a Content-Type header"); $req = $this->adapter->requestsMade[1]; $this->assertEquals($req['method'], 'GET'); $this->assertEquals($req['uri'], '/accounts/1/lists/303449/custom_fields/2'); + $this->assertEmpty($req['headers'], "Get Custom fields request shouldn't have a Content-Type header"); } /** diff --git a/tests/AWeberEntryTest.php b/tests/AWeberEntryTest.php index 3a73791..29fdb48 100644 --- a/tests/AWeberEntryTest.php +++ b/tests/AWeberEntryTest.php @@ -104,6 +104,7 @@ public function testDelete() { $this->assertEquals(sizeOf($this->adapter->requestsMade), 1); $this->assertEquals($this->adapter->requestsMade[0]['method'], 'DELETE'); $this->assertEquals($this->adapter->requestsMade[0]['uri'], $this->entry->url); + $this->assertEmpty($this->adapter->requestsMade[0]['headers'], "Delete request shouldn't have a Content-Type header"); } /** @@ -144,6 +145,7 @@ public function testSave() { $this->assertEquals($req['method'], 'PATCH'); $this->assertEquals($req['uri'], $this->entry->url); $this->assertEquals($req['data'], array('name' => 'mynewlistname')); + $this->assertEquals(array('Content-Type: application/json'), $req['headers'], "Save request should have a Content-Type header"); $this->assertSame($resp, true); } @@ -361,6 +363,7 @@ public function testMove_Success() { $this->assertEquals($req['data'], array( 'ws.op' => 'move', 'list_link' => $this->different_list->self_link)); + $this->assertEmpty($req['headers'], "Move request shouldn't have a Content-Type header"); $req = $this->adapter->requestsMade[1]; $this->assertEquals($req['method'], 'GET'); @@ -404,6 +407,7 @@ public function testMoveWLastMessageNumberSent_Success() { 'ws.op' => 'move', 'list_link' => $this->different_list->self_link, 'last_followup_message_number_sent' => $this->last_followup_message_number_sent)); + $this->assertEmpty($req['headers'], "Move request shouldn't have a Content-Type header"); $req = $this->adapter->requestsMade[1]; $this->assertEquals($req['method'], 'GET'); diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php index 3a87a8e..ebb7639 100644 --- a/tests/mock_adapter.php +++ b/tests/mock_adapter.php @@ -56,18 +56,19 @@ class MockOAuthAdapter extends OAuthApplication { public $requestsMade = array(); - public function addRequest($method, $uri, $data) { + public function addRequest($method, $uri, $data, $headers) { $this->requestsMade[] = array( 'method' => $method, 'uri' => $uri, - 'data' => $data); + 'data' => $data, + 'headers' => $headers); } public function clearRequests() { $this->requestsMade = array(); } - public function makeRequest($method, $url, $data=array()) { + public function makeRequest($method, $url, $data=array(), $headers=array()) { global $map; # append params to url (for fixtures) @@ -82,7 +83,7 @@ public function makeRequest($method, $url, $data=array()) { $resource = $map[$method][$uri][1]; # record the request - $this->addRequest($method, $uri, $data); + $this->addRequest($method, $uri, $data, $headers); # load response from fixture and return data $mock_data = MockData::load($resource); From 42a250d437b57f279bdd491ad59aa582f3496692 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Mon, 21 Aug 2017 13:21:44 -0400 Subject: [PATCH 092/112] Bumping version and updating README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 09c7775..75b5882 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ subscriber information. Changelog: ---------- +2016-11-09: v1.1.16 + * Fixing UTF-8 issues on creates + 2016-11-09: v1.1.15 * Create AWeberEntry for Broadcast Entry endpoint From f46031f274d041a704ee78bf9886a3ee57a06e66 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Wed, 23 Aug 2017 10:36:29 -0400 Subject: [PATCH 093/112] Updating README.md with correct dates and missing version --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 75b5882..402b27b 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,11 @@ subscriber information. Changelog: ---------- -2016-11-09: v1.1.16 +2017-08-21: v1.1.17 * Fixing UTF-8 issues on creates + +2016-12-16: v1.1.16 + * Composer autoload with classmap 2016-11-09: v1.1.15 * Create AWeberEntry for Broadcast Entry endpoint From e82483bebfa12ab721382307464ad59fc1d0049f Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Thu, 24 Aug 2017 09:00:16 -0400 Subject: [PATCH 094/112] Adding the proper phpdocs to the request method --- aweber_api/oauth_application.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 8e8f885..5d2c0ba 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -104,8 +104,10 @@ public function __construct($parentApp = false) { * @param mixed $uri * @param array $data * @param array $options + * @param array $headers * @access public * @return void + * @throws AWeberResponseError */ public function request($method, $uri, $data = array(), $options = array(), $headers = array()) { $uri = $this->app->removeBaseUri($uri); From a1d5d4b0880654229e6194f2ea1f4623a990d17c Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Thu, 24 Aug 2017 14:46:30 -0400 Subject: [PATCH 095/112] Making interface match implementation. Adding userAgent method to calculate the User-Agent header. --- aweber_api/oauth_adapter.php | 2 +- aweber_api/oauth_application.php | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/aweber_api/oauth_adapter.php b/aweber_api/oauth_adapter.php index a6b698a..0b9d454 100644 --- a/aweber_api/oauth_adapter.php +++ b/aweber_api/oauth_adapter.php @@ -2,7 +2,7 @@ interface AWeberOAuthAdapter { - public function request($method, $uri, $data = array()); + public function request($method, $uri, $data = array(), $options = array(), $headers = array()); public function getRequestToken($callbackUrl=false); } diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 5d2c0ba..4276a02 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -57,14 +57,17 @@ public function getUserData(); class OAuthApplication implements AWeberOAuthAdapter { public $debug = false; - public $userAgent = 'AWeber OAuth Consumer Application 1.0 - https://labs.aweber.com/'; + public $userAgentTitle = "AWeber-PHP-CL/"; public $format = false; public $requiresTokenSecret = true; public $signatureMethod = 'HMAC-SHA1'; - public $version = '1.0'; + + public $clientVersion = '1.1.17'; + + public $oAuthVersion = '1.0'; public $curl = false; @@ -344,7 +347,7 @@ public function getOAuthRequestData() { return array( 'oauth_token' => $token, 'oauth_consumer_key' => $this->consumerKey, - 'oauth_version' => $this->version, + 'oauth_version' => $this->oAuthVersion, 'oauth_timestamp' => $ts, 'oauth_signature_method' => $this->signatureMethod, 'oauth_nonce' => $nonce); @@ -580,7 +583,7 @@ private function _sendRequest($handle, $headers = array()) { $this->curl->setopt($handle, CURLOPT_RETURNTRANSFER, true); $this->curl->setopt($handle, CURLOPT_HEADER, true); $this->curl->setopt($handle, CURLOPT_HTTPHEADER, $headers); - $this->curl->setopt($handle, CURLOPT_USERAGENT, $this->userAgent); + $this->curl->setopt($handle, CURLOPT_USERAGENT, $this->userAgent()); $this->curl->setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); $this->curl->setopt($handle, CURLOPT_VERBOSE, FALSE); $this->curl->setopt($handle, CURLOPT_CONNECTTIMEOUT, 10); @@ -635,6 +638,17 @@ public function parseResponse($resp) { return $data; } + /** + * userAgent + * + * Generates the user agent for the cURL command + * + * @return string + */ + protected function userAgent() { + return $this->userAgentTitle . $this->clientVersion . ' PHP/' . PHP_VERSION . ' ' . php_uname('m') . '-' . strtolower(php_uname('s')) . '-'. php_uname('r'); + } + } /** From 325d125e01659620ae1dcd78786e64e20a46eca6 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Thu, 24 Aug 2017 14:56:54 -0400 Subject: [PATCH 096/112] Fixing broken unit test on the OAuth version number --- tests/OAuthApplicationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/OAuthApplicationTest.php b/tests/OAuthApplicationTest.php index ef91e01..b62bef0 100644 --- a/tests/OAuthApplicationTest.php +++ b/tests/OAuthApplicationTest.php @@ -139,7 +139,7 @@ public function testCreateSignatureUniqueness() { * @return void */ public function testGetVersion() { - $version = $this->oauth->version; + $version = $this->oauth->oAuthVersion; $this->assertEquals($version, '1.0', 'Default version is 1.0'); } From ea480664f25a89b3dc16c4022a8b3b325d20ab28 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Sat, 2 Sep 2017 09:59:47 -0400 Subject: [PATCH 097/112] - Fixing issue with nested objects in the create call - Replacing deprecated getMock() with createMock() - Fixing PHPDocs - Updating the version --- README.md | 3 ++ aweber_api/oauth_application.php | 22 ++++++++----- tests/AWeberCollectionTest.php | 54 ++++++++++++++++++++++++++++++++ tests/AWeberCreateEntryTest.php | 4 +-- tests/AWeberEntryTest.php | 22 ++++++++++++- tests/OAuthApplicationTest.php | 16 +++++----- tests/mock_adapter.php | 6 ++++ 7 files changed, 108 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 402b27b..2ebcfd5 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ subscriber information. Changelog: ---------- +2017-09-02: v1.1.18 + * Fixing issues on the formatting of nested objects on 'application/json' requests + 2017-08-21: v1.1.17 * Fixing UTF-8 issues on creates diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 4276a02..bd8d449 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -65,7 +65,7 @@ class OAuthApplication implements AWeberOAuthAdapter { public $signatureMethod = 'HMAC-SHA1'; - public $clientVersion = '1.1.17'; + public $clientVersion = '1.1.18'; public $oAuthVersion = '1.0'; @@ -86,7 +86,8 @@ class OAuthApplication implements AWeberOAuthAdapter { * * Create a new OAuthApplication, based on an OAuthServiceProvider * @access public - * @return void + * @param bool $parentApp + * @throws Exception */ public function __construct($parentApp = false) { if ($parentApp) { @@ -116,8 +117,8 @@ public function request($method, $uri, $data = array(), $options = array(), $hea $uri = $this->app->removeBaseUri($uri); $url = $this->app->getBaseUri() . $uri; - # WARNING: non-primative items in data must be json serialized in GET and POST. - if ($method == 'POST' or $method == 'GET') { + # WARNING: If not being sent as json, non-primative items in data must be json serialized in GET and POST. + if ( (!in_array("Content-Type: application/json", $headers) and $method == 'POST') or $method == 'GET' ) { foreach ($data as $key => $value) { if (is_array($value)) { $data[$key] = json_encode($value); @@ -171,6 +172,7 @@ public function getRequestToken($callbackUrl=false) { * * @access public * @return void + * @throws AWeberOAuthDataMissing */ public function getAccessToken() { $resp = $this->makeRequest('POST', $this->app->getAccessTokenUrl(), @@ -212,10 +214,11 @@ public function parseAsError($response) { * Enforce that all the fields in requiredFields are present and not * empty in data. If a required field is empty, throw an exception. * - * @param mixed $data Array of data - * @param mixed $requiredFields Array of required field names. - * @access protected + * @param mixed $data Array of data + * @param mixed $requiredFields Array of required field names. * @return void + * @throws AWeberOAuthDataMissing + * @access protected */ protected function requiredFromResponse($data, $requiredFields) { foreach ($requiredFields as $field) { @@ -441,8 +444,11 @@ public function signRequest($method, $url, $data) { * @param mixed $method * @param mixed $url - Reserved characters in query params MUST be escaped * @param mixed $data - Reserved characters in values MUST NOT be escaped + * @param mixed $headers - Reserved characters in values MUST NOT be escaped * @access public * @return void + * + * @throws AWeberAPIException */ public function makeRequest($method, $url, $data=array(), $headers=array()) { @@ -450,7 +456,7 @@ public function makeRequest($method, $url, $data=array(), $headers=array()) { switch (strtoupper($method)) { case 'POST': - $oauth = $this->prepareRequest($method, $url, $data); + $oauth = $this->prepareRequest($method, $url, in_array("Content-Type: application/json", $headers) ? array() : $data); $resp = $this->post($url, $oauth, $data, $headers); break; diff --git a/tests/AWeberCollectionTest.php b/tests/AWeberCollectionTest.php index 44ca90c..40bb01b 100644 --- a/tests/AWeberCollectionTest.php +++ b/tests/AWeberCollectionTest.php @@ -17,6 +17,60 @@ public function setUp() { $this->found = $this->subscribers->find($this->params); } + /** + * Test to ensure that the nested objects, such as "custom_fields", are formatted correctly for GET request. The + * nested objects should be a JSON encoded string. + */ + public function testFormatOfGetData() { + $findParams = array('custom_fields' => array('test' => 'test')); + $expectedFindData = array('ws.op' => 'find', 'custom_fields' => '{"test":"test"}'); + + $this->adapter->clearRequests(); + + $resp = $this->subscribers->find($findParams); + + $req = $this->adapter->requestsMade[0]; + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['data'], $expectedFindData); + $this->assertEmpty($req['headers'], "Find request shouldn't have a Content-Type header"); + } + + /** + * Checks that the nested objects, such as "custom_fields", are formatted correctly. The "create" method + * is a POST with Content-Type of 'application/json'. The data should be formatted as JSON. + */ + public function testFormatOfPostData() { + + $createParams = array( + 'email' => 'test@example.com', + 'ip_address' => '127.0.0.1', + 'name' => 'John Doe', + 'custom_fields' => array( + 'custom' => 'test' + ) + ); + + $expectedCreateParams = array( + 'ws.op' => 'create', + 'email' => 'test@example.com', + 'ip_address' => '127.0.0.1', + 'name' => 'John Doe', + 'custom_fields' => array( + 'custom' => 'test' + ) + ); + + $this->adapter->clearRequests(); + + $resp = $this->subscribers->create($createParams); + + $req = $this->adapter->requestsMade[0]; + $this->assertEquals($req['method'], 'POST'); + $this->assertEquals($req['data'], $expectedCreateParams); + $this->assertEquals(array('Content-Type: application/json'), $req['headers'], "Create request should have a Content-Type header"); + + } + /** * The find method makes two requests, one for the collection, and the other to get total_size. */ diff --git a/tests/AWeberCreateEntryTest.php b/tests/AWeberCreateEntryTest.php index aa10909..9f51510 100644 --- a/tests/AWeberCreateEntryTest.php +++ b/tests/AWeberCreateEntryTest.php @@ -88,7 +88,7 @@ public function testCreateSuccessWithAdapter() { $aweber = new AWeberAPI($consumerKey, $consumerSecret); // Set up the cURL Stub - $stub = $this->getMock('CurlObject'); + $stub = $this->createMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->onConsecutiveCalls($postCustomFieldRsp, @@ -137,7 +137,7 @@ public function testCreateFailureWithAdapter() { $aweber = new AWeberAPI($consumerKey, $consumerSecret); // Set up the cURL Stub - $stub = $this->getMock('CurlObject'); + $stub = $this->createMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($postCustomFieldRsp)); diff --git a/tests/AWeberEntryTest.php b/tests/AWeberEntryTest.php index 29fdb48..473dabe 100644 --- a/tests/AWeberEntryTest.php +++ b/tests/AWeberEntryTest.php @@ -269,6 +269,26 @@ public function testShouldSupportFindSubscribersMethod() { $this->assertEquals($subscribers->data['entries'][0]['self_link'], 'https://api.aweber.com/1.0/accounts/1/lists/303449/subscribers/1'); } + + /** + * Test to ensure that the nested objects, such as "custom_fields", are formatted correctly for GET request. The + * nested objects should be a JSON encoded string. + */ + public function testShouldFormatFindSubscribersParameters() { + + $findSubscribersParameters = array('email' => 'joe@example.com', 'custom_fields' => array('test' => 'test')); + $expectedFindSubscribersParameters = array('email' => 'joe@example.com', 'custom_fields' => '{"test":"test"}', 'ws.op' => 'findSubscribers'); + + $subscribers = $this->entry->findSubscribers($findSubscribersParameters); + + $req = $this->adapter->requestsMade[1]; + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['data'], $expectedFindSubscribersParameters, "Request data should be formatted properly."); + + print_r($req['data']); + + } + } class TestAWeberSubscriberEntry extends PHPUnit_Framework_TestCase { @@ -363,7 +383,7 @@ public function testMove_Success() { $this->assertEquals($req['data'], array( 'ws.op' => 'move', 'list_link' => $this->different_list->self_link)); - $this->assertEmpty($req['headers'], "Move request shouldn't have a Content-Type header"); + $this->assertEmpty($req['headers'], "Move request shouldn't have a Content-Type header"); $req = $this->adapter->requestsMade[1]; $this->assertEquals($req['method'], 'GET'); diff --git a/tests/OAuthApplicationTest.php b/tests/OAuthApplicationTest.php index b62bef0..3e972af 100644 --- a/tests/OAuthApplicationTest.php +++ b/tests/OAuthApplicationTest.php @@ -341,7 +341,7 @@ public function testRequestReturnValueIsZeroNotInJSONFormat(){ } public function testMakeRequestGet() { - $stub = $this->getMock('CurlObject'); + $stub = $this->createMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -352,7 +352,7 @@ public function testMakeRequestGet() { } public function testMakeRequestPost() { - $stub = $this->getMock('CurlObject'); + $stub = $this->createMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -363,7 +363,7 @@ public function testMakeRequestPost() { } public function testMakeRequestPut() { - $stub = $this->getMock('CurlObject'); + $stub = $this->createMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -374,7 +374,7 @@ public function testMakeRequestPut() { } public function testMakeRequestDelete() { - $stub = $this->getMock('CurlObject'); + $stub = $this->createMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -404,7 +404,7 @@ public function testMakeRequestContainsReservedCharInUrl() { $patchedoauth->consumerSecret = 'CONSUMERSECRET'; $patchedoauth->consumerKey = 'consumer_key'; - $stub = $this->getMock('CurlObject'); + $stub = $this->createMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -434,7 +434,7 @@ public function testMakeRequestContainsSeparatorInUrl() { $patchedoauth->consumerSecret = 'CONSUMERSECRET'; $patchedoauth->consumerKey = 'consumer_key'; - $stub = $this->getMock('CurlObject'); + $stub = $this->createMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -463,7 +463,7 @@ public function testMakeRequestContainsReservedCharInData() { $patchedoauth->consumerSecret = 'CONSUMERSECRET'; $patchedoauth->consumerKey = 'consumer_key'; - $stub = $this->getMock('CurlObject'); + $stub = $this->createMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -492,7 +492,7 @@ public function testMakeRequestContainsSeparatorInData() { $patchedoauth->consumerSecret = 'CONSUMERSECRET'; $patchedoauth->consumerKey = 'consumer_key'; - $stub = $this->getMock('CurlObject'); + $stub = $this->createMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php index ebb7639..2304ac9 100644 --- a/tests/mock_adapter.php +++ b/tests/mock_adapter.php @@ -51,6 +51,12 @@ function get_mock_adapter() { $map['POST' ]['/accounts/1/lists/303449/subscribers/1' ] = array(201, '/accounts/1/lists/505454/subscribers/3'); $map['POST' ]['/accounts/1/lists/303449/subscribers/2' ] = array(400, 'error'); +# Entity Body formatting +$map['POST' ]['/accounts/1/lists/303449/subscribers' ] = array(201, '/accounts/1/lists/505454/subscribers/3'); +$map['GET' ]['/accounts/1?email=joe%40example.com&custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=findSubscribers&ws.show=total_size' ] = array(200, 'accounts/findSubscribers_ts'); +$map['GET' ]['/accounts/1?email=joe%40example.com&custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=findSubscribers' ] = array(200, 'accounts/findSubscribers'); +$map['GET' ]['/accounts/1/lists/303449/subscribers?custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=find' ] = array(200, 'subscribers/find_1of2'); +$map['GET' ]['/accounts/1/lists/303449/subscribers?custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=find&ws.show=total_size' ] = array(200, 'subscribers/find_1of2_tsl'); class MockOAuthAdapter extends OAuthApplication { From 9b2804397aa01fa4f3420334122f99b625ae5523 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Tue, 5 Sep 2017 09:45:06 -0400 Subject: [PATCH 098/112] - Fixing improper headers being sent with GET requests --- aweber_api/oauth_application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index bd8d449..694e926 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -462,7 +462,7 @@ public function makeRequest($method, $url, $data=array(), $headers=array()) { case 'GET': $oauth = $this->prepareRequest($method, $url, $data); - $resp = $this->get($url, $oauth, $data, $headers); + $resp = $this->get($url, $oauth, $headers); break; case 'DELETE': From 25ad1e8053a712c26b0b95500241482d4c899d28 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Tue, 5 Sep 2017 13:19:14 -0400 Subject: [PATCH 099/112] - Adding check for custom fields to not encode as JSON, as request fails not form encoded --- aweber_api/aweber_collection.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index 26c0bc5..fbbd244 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -116,7 +116,8 @@ protected function _type() { public function create($kv_pairs) { # Create Resource $params = array_merge(array('ws.op' => 'create'), $kv_pairs); - $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers'), array('Content-Type: application/json')); + $headers = strstr($this->url,'custom_fields') ? array() : array('Content-Type: application/json'); + $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers'), $headers); # Return new Resource $url = $data['Location']; From 46d9b8772c50e92dc6f939c155364ca9a0ce4c33 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Tue, 5 Sep 2017 13:22:51 -0400 Subject: [PATCH 100/112] Updating README.md file --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 2ebcfd5..014f58b 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,9 @@ Changelog: ---------- 2017-09-02: v1.1.18 * Fixing issues on the formatting of nested objects on 'application/json' requests + * Fixing issue with extra data being sent in header. + * Fixing issue to allow the creation of custom fields to be sent as form encoded. + * Updating the deprecated getMock method to createMock. 2017-08-21: v1.1.17 * Fixing UTF-8 issues on creates From 96156e2f4bc0a1eaee57640a7c63dbf1bf082895 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Tue, 5 Sep 2017 14:00:05 -0400 Subject: [PATCH 101/112] Adding test to check the encoding of the request to create subscriber and custom fields, since they use the same method, but different encodings. --- tests/AWeberCreateEntryTest.php | 42 +++++++++++++++++++++++++++++---- tests/AWeberEntryTest.php | 2 -- tests/mock_adapter.php | 3 ++- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/tests/AWeberCreateEntryTest.php b/tests/AWeberCreateEntryTest.php index 9f51510..367d886 100644 --- a/tests/AWeberCreateEntryTest.php +++ b/tests/AWeberCreateEntryTest.php @@ -18,17 +18,22 @@ public function setUp() { $data = $this->adapter->request('GET', $url); $this->custom_fields = new AWeberCollection($data, $url, $this->adapter); + $subscribers_url = '/accounts/1/lists/303449/subscribers'; + $this->subscribers = new AWeberCollection( + $this->adapter->request('GET', $subscribers_url), + $subscribers_url, + $this->adapter); } /** - * Create Success + * Create Custom Field Success * * A unit test of a successful call to the Collection create method. * Testing is limited to the Collection module; the OAuthAdapater * module that handles the communications with the AWeber Public * API Web Service is stubbed out. */ - public function testCreateSuccess() { + public function testCreateCustomFieldSuccess() { $this->adapter->clearRequests(); $resp = $this->custom_fields->create(array('name' => 'AwesomeField')); @@ -42,14 +47,43 @@ public function testCreateSuccess() { $this->assertEquals($req['data'], array( 'ws.op' => 'create', 'name' => 'AwesomeField')); - $this->assertEquals(array('Content-Type: application/json'), $req['headers'], "Create request should have a Content-Type header"); + $this->assertEmpty($req['headers'], "Custom Field create request should have a Content-Type header"); $req = $this->adapter->requestsMade[1]; $this->assertEquals($req['method'], 'GET'); $this->assertEquals($req['uri'], '/accounts/1/lists/303449/custom_fields/2'); $this->assertEmpty($req['headers'], "Get Custom fields request shouldn't have a Content-Type header"); } - + + /** + * Create Success + * + * A unit test of a successful call to the Collection create method. + * Testing is limited to the Collection module; the OAuthAdapater + * module that handles the communications with the AWeber Public + * API Web Service is stubbed out. + */ + public function testCreateSubscriberSuccess() { + + $this->adapter->clearRequests(); + $resp = $this->subscribers->create(array('email' => 'test@test.com')); + + + $this->assertEquals(sizeOf($this->adapter->requestsMade), 2); + + $req = $this->adapter->requestsMade[0]; + $this->assertEquals($req['method'], 'POST'); + $this->assertEquals($req['data'], array( + 'ws.op' => 'create', + 'email' => 'test@test.com')); + $this->assertEquals(array('Content-Type: application/json'), $req['headers'], "Create request should have a Content-Type header"); + + $req = $this->adapter->requestsMade[1]; + $this->assertEquals($req['method'], 'GET'); + $this->assertEquals($req['uri'], '/accounts/1/lists/303449/subscribers/3'); + $this->assertEmpty($req['headers'], "Get subscriber request shouldn't have a Content-Type header"); + } + /** * Create Success With Adapter * diff --git a/tests/AWeberEntryTest.php b/tests/AWeberEntryTest.php index 473dabe..20dcbe2 100644 --- a/tests/AWeberEntryTest.php +++ b/tests/AWeberEntryTest.php @@ -285,8 +285,6 @@ public function testShouldFormatFindSubscribersParameters() { $this->assertEquals($req['method'], 'GET'); $this->assertEquals($req['data'], $expectedFindSubscribersParameters, "Request data should be formatted properly."); - print_r($req['data']); - } } diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php index 2304ac9..4ea94e5 100644 --- a/tests/mock_adapter.php +++ b/tests/mock_adapter.php @@ -30,6 +30,7 @@ function get_mock_adapter() { $map['GET' ]['/accounts/1/lists/303449/subscribers?email=someone%40example.com&ws.op=find' ] = array(200, 'subscribers/find'); $map['GET' ]['/accounts/1/lists/505454' ] = array(200, 'lists/505454'); $map['GET' ]['/accounts/1/lists/505454/subscribers/3' ] = array(200, 'subscribers/3'); +$map['GET' ]['/accounts/1/lists/303449/subscribers/3' ] = array(200, 'subscribers/3'); $map['GET' ]['/accounts/1/lists?ws.start=20&ws.size=20' ] = array(200, 'lists/page2'); $map['GET' ]['/accounts/1?email=joe%40example.com&ws.op=findSubscribers&ws.show=total_size' ] = array(200, 'accounts/findSubscribers_ts'); $map['GET' ]['/accounts/1?email=joe%40example.com&ws.op=findSubscribers' ] = array(200, 'accounts/findSubscribers'); @@ -52,7 +53,7 @@ function get_mock_adapter() { $map['POST' ]['/accounts/1/lists/303449/subscribers/2' ] = array(400, 'error'); # Entity Body formatting -$map['POST' ]['/accounts/1/lists/303449/subscribers' ] = array(201, '/accounts/1/lists/505454/subscribers/3'); +$map['POST' ]['/accounts/1/lists/303449/subscribers' ] = array(201, '/accounts/1/lists/303449/subscribers/3'); $map['GET' ]['/accounts/1?email=joe%40example.com&custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=findSubscribers&ws.show=total_size' ] = array(200, 'accounts/findSubscribers_ts'); $map['GET' ]['/accounts/1?email=joe%40example.com&custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=findSubscribers' ] = array(200, 'accounts/findSubscribers'); $map['GET' ]['/accounts/1/lists/303449/subscribers?custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=find' ] = array(200, 'subscribers/find_1of2'); From 88c442353c832a307ca480a97f92dbc21e4491dc Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Tue, 5 Sep 2017 14:37:56 -0400 Subject: [PATCH 102/112] Updating travis.yml file to update the composer dependencies --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f04ab82..2cbb18c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ php: - 5.3 - 5.4 +install: composer install --dev script: phpunit --configuration build/phpunit.xml notifications: From 872f776a624906b6f8d16d580eef9f2866dfc261 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Tue, 5 Sep 2017 15:40:00 -0400 Subject: [PATCH 103/112] Reverting the upgrade to createMock method as it creates issue with the build. The build fails because it can't find the method. Tried to update the libraries, but certain libraries have issues with the version of PHP. --- .travis.yml | 1 - tests/AWeberCreateEntryTest.php | 4 ++-- tests/OAuthApplicationTest.php | 16 ++++++++-------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2cbb18c..f04ab82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ php: - 5.3 - 5.4 -install: composer install --dev script: phpunit --configuration build/phpunit.xml notifications: diff --git a/tests/AWeberCreateEntryTest.php b/tests/AWeberCreateEntryTest.php index 367d886..77165ff 100644 --- a/tests/AWeberCreateEntryTest.php +++ b/tests/AWeberCreateEntryTest.php @@ -122,7 +122,7 @@ public function testCreateSuccessWithAdapter() { $aweber = new AWeberAPI($consumerKey, $consumerSecret); // Set up the cURL Stub - $stub = $this->createMock('CurlObject'); + $stub = $this->getMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->onConsecutiveCalls($postCustomFieldRsp, @@ -171,7 +171,7 @@ public function testCreateFailureWithAdapter() { $aweber = new AWeberAPI($consumerKey, $consumerSecret); // Set up the cURL Stub - $stub = $this->createMock('CurlObject'); + $stub = $this->getMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($postCustomFieldRsp)); diff --git a/tests/OAuthApplicationTest.php b/tests/OAuthApplicationTest.php index 3e972af..b62bef0 100644 --- a/tests/OAuthApplicationTest.php +++ b/tests/OAuthApplicationTest.php @@ -341,7 +341,7 @@ public function testRequestReturnValueIsZeroNotInJSONFormat(){ } public function testMakeRequestGet() { - $stub = $this->createMock('CurlObject'); + $stub = $this->getMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -352,7 +352,7 @@ public function testMakeRequestGet() { } public function testMakeRequestPost() { - $stub = $this->createMock('CurlObject'); + $stub = $this->getMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -363,7 +363,7 @@ public function testMakeRequestPost() { } public function testMakeRequestPut() { - $stub = $this->createMock('CurlObject'); + $stub = $this->getMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -374,7 +374,7 @@ public function testMakeRequestPut() { } public function testMakeRequestDelete() { - $stub = $this->createMock('CurlObject'); + $stub = $this->getMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -404,7 +404,7 @@ public function testMakeRequestContainsReservedCharInUrl() { $patchedoauth->consumerSecret = 'CONSUMERSECRET'; $patchedoauth->consumerKey = 'consumer_key'; - $stub = $this->createMock('CurlObject'); + $stub = $this->getMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -434,7 +434,7 @@ public function testMakeRequestContainsSeparatorInUrl() { $patchedoauth->consumerSecret = 'CONSUMERSECRET'; $patchedoauth->consumerKey = 'consumer_key'; - $stub = $this->createMock('CurlObject'); + $stub = $this->getMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -463,7 +463,7 @@ public function testMakeRequestContainsReservedCharInData() { $patchedoauth->consumerSecret = 'CONSUMERSECRET'; $patchedoauth->consumerKey = 'consumer_key'; - $stub = $this->createMock('CurlObject'); + $stub = $this->getMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); @@ -492,7 +492,7 @@ public function testMakeRequestContainsSeparatorInData() { $patchedoauth->consumerSecret = 'CONSUMERSECRET'; $patchedoauth->consumerKey = 'consumer_key'; - $stub = $this->createMock('CurlObject'); + $stub = $this->getMock('CurlObject'); $stub->expects($this->any()) ->method('execute') ->will($this->returnValue($this->stubrsp)); From 105d9b7386e5530c53db39871c8af5c68a79be28 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Tue, 5 Sep 2017 15:59:14 -0400 Subject: [PATCH 104/112] Updating travis configuration to get the PHP 5.3 build --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f04ab82..623139a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: php +sudo: required php: - 5.3 - 5.4 From 91623911f678a8b51e8938f82dd4893d2d3f1482 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Fri, 8 Sep 2017 15:33:00 -0400 Subject: [PATCH 105/112] Refactoring the code to perform the ContentType check once and make it more readable Using the _type to check the 'custom_fields' endpoint Fixing test to handle the reordering of how the request URL and Bosy are built Removing the PHP 5.3 build from Travis as it has been sunset from Travis CI (will do the 5.3 builds internally) --- .travis.yml | 1 - aweber_api/aweber_collection.php | 2 +- aweber_api/oauth_application.php | 111 +++++++++++++++++++------------ tests/AWeberCollectionTest.php | 10 +-- tests/AWeberCreateEntryTest.php | 2 +- tests/AWeberEntryTest.php | 8 +-- tests/mock_adapter.php | 38 +++++++---- 7 files changed, 104 insertions(+), 68 deletions(-) diff --git a/.travis.yml b/.travis.yml index 623139a..f3b6214 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: php sudo: required php: - - 5.3 - 5.4 script: phpunit --configuration build/phpunit.xml diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index fbbd244..0ce6fed 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -116,7 +116,7 @@ protected function _type() { public function create($kv_pairs) { # Create Resource $params = array_merge(array('ws.op' => 'create'), $kv_pairs); - $headers = strstr($this->url,'custom_fields') ? array() : array('Content-Type: application/json'); + $headers = $this->_type() == 'custom_fields' ? array() : array('Content-Type: application/json'); $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers'), $headers); # Return new Resource diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 694e926..49544f0 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -117,14 +117,6 @@ public function request($method, $uri, $data = array(), $options = array(), $hea $uri = $this->app->removeBaseUri($uri); $url = $this->app->getBaseUri() . $uri; - # WARNING: If not being sent as json, non-primative items in data must be json serialized in GET and POST. - if ( (!in_array("Content-Type: application/json", $headers) and $method == 'POST') or $method == 'GET' ) { - foreach ($data as $key => $value) { - if (is_array($value)) { - $data[$key] = json_encode($value); - } - } - } $response = $this->makeRequest($method, $url, $data, $headers); if (!empty($options['return'])) { @@ -232,14 +224,14 @@ protected function requiredFromResponse($data, $requiredFields) { * get * * Make a get request. Used to exchange user tokens with serice provider. - * @param mixed $url URL to make a get request from. - * @param array $data Data for the request. - * @param mixed $headers Headers for the request + * @param mixed $url URL to make a get request from. + * @param String $url_params URL parameter string + * @param mixed $headers Headers for the request * @access protected * @return void */ - protected function get($url, $data, $headers) { - $url = $this->_addParametersToUrl($url, $data); + protected function get($url, $url_params, $headers = array()) { + $url = $this->_addParametersToUrl($url, $url_params); $handle = $this->curl->init($url); $resp = $this->_sendRequest($handle, $headers); return $resp; @@ -251,7 +243,7 @@ protected function get($url, $data, $headers) { * Adds the parameters in associative array $data to the * given URL * @param String $url URL - * @param array $data Parameters to be added as a query string to + * @param String $data Parameters to be added as a query string to * the URL provided * @access protected * @return void @@ -259,9 +251,9 @@ protected function get($url, $data, $headers) { protected function _addParametersToUrl($url, $data) { if (!empty($data)) { if (strpos($url, '?') === false) { - $url .= '?'.$this->buildData($data); + $url .= '?' . $data; } else { - $url .= '&'.$this->buildData($data); + $url .= '&' . $data; } } return $url; @@ -454,25 +446,23 @@ public function makeRequest($method, $url, $data=array(), $headers=array()) { if ($this->debug) echo "\n** {$method}: $url\n"; + list($url_params, $request_body) = $this->formatRequestData($method, $url, $data, $headers); + switch (strtoupper($method)) { case 'POST': - $oauth = $this->prepareRequest($method, $url, in_array("Content-Type: application/json", $headers) ? array() : $data); - $resp = $this->post($url, $oauth, $data, $headers); + $resp = $this->post($url, $url_params, $request_body, $headers); break; case 'GET': - $oauth = $this->prepareRequest($method, $url, $data); - $resp = $this->get($url, $oauth, $headers); + $resp = $this->get($url, $url_params, $headers); break; case 'DELETE': - $oauth = $this->prepareRequest($method, $url, $data); - $resp = $this->delete($url, $oauth, $headers); + $resp = $this->delete($url, $url_params, $headers); break; case 'PATCH': - $oauth = $this->prepareRequest($method, $url, array()); - $resp = $this->patch($url, $oauth, $data, $headers); + $resp = $this->patch($url, $url_params, $request_body, $headers); break; } @@ -501,21 +491,22 @@ public function makeRequest($method, $url, $data=array(), $headers=array()) { } /** - * put + * patch * - * Prepare an OAuth put method. + * Prepare an OAuth patch method. * - * @param mixed $url URL where we are making the request to - * @param mixed $data Data that is used to make the request - * @param mixed $headers Headers for the request + * @param mixed $url URL where we are making the request to + * @param mixed $url_params URL parameter string + * @param mixed $post_field Data that is used to make the request + * @param mixed $headers Headers for the request * @access protected * @return void */ - protected function patch($url, $oauth, $data, $headers) { - $url = $this->_addParametersToUrl($url, $oauth); + protected function patch($url, $url_params, $post_field, $headers = array()) { + $url = $this->_addParametersToUrl($url, $url_params); $handle = $this->curl->init($url); $this->curl->setopt($handle, CURLOPT_CUSTOMREQUEST, 'PATCH'); - $this->curl->setopt($handle, CURLOPT_POSTFIELDS, json_encode($data)); + $this->curl->setopt($handle, CURLOPT_POSTFIELDS, $post_field); $resp = $this->_sendRequest($handle, $headers); return $resp; } @@ -525,18 +516,18 @@ protected function patch($url, $oauth, $data, $headers) { * * Prepare an OAuth post method. * - * @param mixed $url URL where we are making the request to - * @param mixed $data Data that is used to make the request - * @param mixed $headers Headers for the request + * @param mixed $url URL where we are making the request to + * @param mixed $url_params URL parameter string + * @param mixed $post_field Data that is used to make the request + * @param mixed $headers Headers for the request * @access protected * @return void */ - protected function post($url, $oauth, $data, $headers = array()) { - $url = $this->_addParametersToUrl($url, $oauth); + protected function post($url, $url_params, $post_field, $headers = array()) { + $url = $this->_addParametersToUrl($url, $url_params); $handle = $this->curl->init($url); $this->curl->setopt($handle, CURLOPT_POST, true); - $postData = in_array("Content-Type: application/json", $headers) ? json_encode($data) : $this->buildData($data); - $this->curl->setopt($handle, CURLOPT_POSTFIELDS, $postData); + $this->curl->setopt($handle, CURLOPT_POSTFIELDS, $post_field); $resp = $this->_sendRequest($handle, $headers); return $resp; } @@ -546,13 +537,13 @@ protected function post($url, $oauth, $data, $headers = array()) { * * Makes a DELETE request * @param mixed $url URL where we are making the request to - * @param mixed $data Data that is used in the request + * @param mixed $url_params URL parameter string * @param mixed $headers Headers for the request * @access protected * @return void */ - protected function delete($url, $data, $headers = array()) { - $url = $this->_addParametersToUrl($url, $data); + protected function delete($url, $url_params, $headers = array()) { + $url = $this->_addParametersToUrl($url, $url_params); $handle = $this->curl->init($url); $this->curl->setopt($handle, CURLOPT_CUSTOMREQUEST, 'DELETE'); $resp = $this->_sendRequest($handle, $headers); @@ -655,6 +646,42 @@ protected function userAgent() { return $this->userAgentTitle . $this->clientVersion . ' PHP/' . PHP_VERSION . ' ' . php_uname('m') . '-' . strtolower(php_uname('s')) . '-'. php_uname('r'); } + /** + * @param $method + * @param $headers + * @return bool + * + * Return True if headers array does not contain 'Content-Type: application/json' and is a POST, GET, or DELETE request + */ + protected function needsUrlFormatting($method, $headers) { + return !in_array("Content-Type: application/json", $headers) and ($method == 'POST' or $method == 'GET' or 'DELETE'); + } + + /** + * @param $method + * @param $url + * @param $data + * @param $headers + * @return array + */ + protected function formatRequestData($method, $url, $data, $headers) + { + # WARNING: If not being sent as json, non-primitive items in data must be json serialized in GET and POST. + if ($this->needsUrlFormatting($method, $headers)) { + foreach ($data as $key => $value) { + if (is_array($value)) { + $data[$key] = json_encode($value); + } + } + $url_params = $this->buildData($this->prepareRequest($method, $url, $data)); + $request_body = $this->buildData($data); + } else { + $url_params = $this->buildData($this->prepareRequest($method, $url, array())); + $request_body = json_encode($data); + } + return array($url_params, $request_body); + } + } /** diff --git a/tests/AWeberCollectionTest.php b/tests/AWeberCollectionTest.php index 40bb01b..7263e7d 100644 --- a/tests/AWeberCollectionTest.php +++ b/tests/AWeberCollectionTest.php @@ -23,7 +23,7 @@ public function setUp() { */ public function testFormatOfGetData() { $findParams = array('custom_fields' => array('test' => 'test')); - $expectedFindData = array('ws.op' => 'find', 'custom_fields' => '{"test":"test"}'); + $expectedUri = '/accounts/1/lists/303449/subscribers?custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=find'; $this->adapter->clearRequests(); @@ -31,7 +31,7 @@ public function testFormatOfGetData() { $req = $this->adapter->requestsMade[0]; $this->assertEquals($req['method'], 'GET'); - $this->assertEquals($req['data'], $expectedFindData); + $this->assertEquals($expectedUri, $req['uri']); $this->assertEmpty($req['headers'], "Find request shouldn't have a Content-Type header"); } @@ -84,7 +84,7 @@ public function testShouldInitiallyMake2APIRequests() { public function testShouldRequestCollectionPageFirst() { #$this->subscribers->find($this->params); $uri = $this->adapter->requestsMade[0]['uri']; - $this->assertEquals($uri, '/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=0&ws.op=find'); + $this->assertEquals($uri, '/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.op=find&ws.size=1&ws.start=0'); } /** @@ -92,7 +92,7 @@ public function testShouldRequestCollectionPageFirst() { */ public function testShouldRequestTotalSizePageSecond() { $uri = $this->adapter->requestsMade[1]['uri']; - $this->assertEquals($uri, '/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=0&ws.op=find&ws.show=total_size'); + $this->assertEquals($uri, '/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.op=find&ws.show=total_size&ws.size=1&ws.start=0'); } /** @@ -111,7 +111,7 @@ public function testShouldRequestCorrectCollectionPage() { $this->adapter->clearRequests(); $subscriber = $this->found[1]; $uri = $this->adapter->requestsMade[0]['uri']; - $this->assertEquals($uri, '/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=1&ws.op=find'); + $this->assertEquals($uri, '/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.op=find&ws.size=1&ws.start=1'); } /** diff --git a/tests/AWeberCreateEntryTest.php b/tests/AWeberCreateEntryTest.php index 77165ff..ede35ea 100644 --- a/tests/AWeberCreateEntryTest.php +++ b/tests/AWeberCreateEntryTest.php @@ -43,7 +43,7 @@ public function testCreateCustomFieldSuccess() { $req = $this->adapter->requestsMade[0]; $this->assertEquals($req['method'], 'POST'); - $this->assertEquals($req['uri'], $this->custom_fields->url); + $this->assertEquals($req['uri'], '/accounts/1/lists/303449/custom_fields?name=AwesomeField&ws.op=create'); $this->assertEquals($req['data'], array( 'ws.op' => 'create', 'name' => 'AwesomeField')); diff --git a/tests/AWeberEntryTest.php b/tests/AWeberEntryTest.php index 20dcbe2..82842ce 100644 --- a/tests/AWeberEntryTest.php +++ b/tests/AWeberEntryTest.php @@ -277,13 +277,13 @@ public function testShouldSupportFindSubscribersMethod() { public function testShouldFormatFindSubscribersParameters() { $findSubscribersParameters = array('email' => 'joe@example.com', 'custom_fields' => array('test' => 'test')); - $expectedFindSubscribersParameters = array('email' => 'joe@example.com', 'custom_fields' => '{"test":"test"}', 'ws.op' => 'findSubscribers'); + $expectedFindSubscribersUri = '/accounts/1?custom_fields=%7B%22test%22%3A%22test%22%7D&email=joe%40example.com&ws.op=findSubscribers'; $subscribers = $this->entry->findSubscribers($findSubscribersParameters); $req = $this->adapter->requestsMade[1]; $this->assertEquals($req['method'], 'GET'); - $this->assertEquals($req['data'], $expectedFindSubscribersParameters, "Request data should be formatted properly."); + $this->assertEquals($expectedFindSubscribersUri, $req['uri'],"Request data should be formatted properly."); } @@ -377,7 +377,7 @@ public function testMove_Success() { $req = $this->adapter->requestsMade[0]; $this->assertEquals($req['method'], 'POST'); - $this->assertEquals($req['uri'], $this->subscriber->url); + $this->assertEquals($req['uri'], '/accounts/1/lists/303449/subscribers/1?list_link=https%3A%2F%2Fapi.aweber.com%2F1.0%2Faccounts%2F1%2Flists%2F505454&ws.op=move'); $this->assertEquals($req['data'], array( 'ws.op' => 'move', 'list_link' => $this->different_list->self_link)); @@ -420,7 +420,7 @@ public function testMoveWLastMessageNumberSent_Success() { $req = $this->adapter->requestsMade[0]; $this->assertEquals($req['method'], 'POST'); - $this->assertEquals($req['uri'], $this->subscriber->url); + $this->assertEquals($req['uri'], '/accounts/1/lists/303449/subscribers/1?last_followup_message_number_sent=1&list_link=https%3A%2F%2Fapi.aweber.com%2F1.0%2Faccounts%2F1%2Flists%2F505454&ws.op=move'); $this->assertEquals($req['data'], array( 'ws.op' => 'move', 'list_link' => $this->different_list->self_link, diff --git a/tests/mock_adapter.php b/tests/mock_adapter.php index 4ea94e5..f23da9d 100644 --- a/tests/mock_adapter.php +++ b/tests/mock_adapter.php @@ -31,7 +31,7 @@ function get_mock_adapter() { $map['GET' ]['/accounts/1/lists/505454' ] = array(200, 'lists/505454'); $map['GET' ]['/accounts/1/lists/505454/subscribers/3' ] = array(200, 'subscribers/3'); $map['GET' ]['/accounts/1/lists/303449/subscribers/3' ] = array(200, 'subscribers/3'); -$map['GET' ]['/accounts/1/lists?ws.start=20&ws.size=20' ] = array(200, 'lists/page2'); +$map['GET' ]['/accounts/1/lists?ws.size=20&ws.start=20' ] = array(200, 'lists/page2'); $map['GET' ]['/accounts/1?email=joe%40example.com&ws.op=findSubscribers&ws.show=total_size' ] = array(200, 'accounts/findSubscribers_ts'); $map['GET' ]['/accounts/1?email=joe%40example.com&ws.op=findSubscribers' ] = array(200, 'accounts/findSubscribers'); $map['GET' ]['/accounts/1?ws.op=getWebFormSplitTests' ] = array(200, 'accounts/webFormSplitTests'); @@ -40,23 +40,24 @@ function get_mock_adapter() { $map['GET' ]['/accounts/1/lists/303449/broadcasts/1337' ] = array(200, 'broadcasts/1337'); # collection pagination tests -$map['GET' ]['/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=0&ws.op=find' ] = array(200, 'subscribers/find_1of2'); -$map['GET' ]['/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=1&ws.op=find' ] = array(200, 'subscribers/find_2of2'); -$map['GET' ]['/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.size=1&ws.start=0&ws.op=find&ws.show=total_size'] = array(200, 'subscribers/find_1of2_tsl'); +$map['GET' ]['/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.op=find&ws.size=1&ws.start=0' ] = array(200, 'subscribers/find_1of2'); +$map['GET' ]['/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.op=find&ws.size=1&ws.start=1' ] = array(200, 'subscribers/find_2of2'); +$map['GET' ]['/accounts/1/lists/303449/subscribers?status=unsubscribed&ws.op=find&ws.show=total_size&ws.size=1&ws.start=0'] = array(200, 'subscribers/find_1of2_tsl'); $map['PATCH' ]['/accounts/1/lists/303449' ] = array(209, 'lists/303449'); $map['PATCH' ]['/accounts/1/lists/303449/subscribers/1' ] = array(209, 'subscribers/1'); $map['PATCH' ]['/accounts/1/lists/505454' ] = array(404, 'error'); -$map['POST' ]['/accounts/1/lists/303449/custom_fields' ] = array(201, '/accounts/1/lists/303449/custom_fields/2'); -$map['POST' ]['/accounts/1/lists/303449/subscribers/1' ] = array(201, '/accounts/1/lists/505454/subscribers/3'); -$map['POST' ]['/accounts/1/lists/303449/subscribers/2' ] = array(400, 'error'); +$map['POST' ]['/accounts/1/lists/303449/custom_fields?name=AwesomeField&ws.op=create' ] = array(201, '/accounts/1/lists/303449/custom_fields/2'); +$map['POST' ]['/accounts/1/lists/303449/subscribers/1?list_link=https%3A%2F%2Fapi.aweber.com%2F1.0%2Faccounts%2F1%2Flists%2F505454&ws.op=move' ] = array(201, '/accounts/1/lists/505454/subscribers/3'); +$map['POST' ]['/accounts/1/lists/303449/subscribers/1?last_followup_message_number_sent=1&list_link=https%3A%2F%2Fapi.aweber.com%2F1.0%2Faccounts%2F1%2Flists%2F505454&ws.op=move' ] = array(201, '/accounts/1/lists/505454/subscribers/3'); +$map['POST' ]['/accounts/1/lists/303449/subscribers/2?list_link=https%3A%2F%2Fapi.aweber.com%2F1.0%2Faccounts%2F1%2Flists%2F505454&ws.op=move' ] = array(400, 'error'); # Entity Body formatting -$map['POST' ]['/accounts/1/lists/303449/subscribers' ] = array(201, '/accounts/1/lists/303449/subscribers/3'); -$map['GET' ]['/accounts/1?email=joe%40example.com&custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=findSubscribers&ws.show=total_size' ] = array(200, 'accounts/findSubscribers_ts'); -$map['GET' ]['/accounts/1?email=joe%40example.com&custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=findSubscribers' ] = array(200, 'accounts/findSubscribers'); -$map['GET' ]['/accounts/1/lists/303449/subscribers?custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=find' ] = array(200, 'subscribers/find_1of2'); +$map['POST' ]['/accounts/1/lists/303449/subscribers' ] = array(201, '/accounts/1/lists/303449/subscribers/3'); +$map['GET' ]['/accounts/1?custom_fields=%7B%22test%22%3A%22test%22%7D&email=joe%40example.com&ws.op=findSubscribers&ws.show=total_size' ] = array(200, 'accounts/findSubscribers_ts'); +$map['GET' ]['/accounts/1?custom_fields=%7B%22test%22%3A%22test%22%7D&email=joe%40example.com&ws.op=findSubscribers' ] = array(200, 'accounts/findSubscribers'); +$map['GET' ]['/accounts/1/lists/303449/subscribers?custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=find' ] = array(200, 'subscribers/find_1of2'); $map['GET' ]['/accounts/1/lists/303449/subscribers?custom_fields=%7B%22test%22%3A%22test%22%7D&ws.op=find&ws.show=total_size' ] = array(200, 'subscribers/find_1of2_tsl'); class MockOAuthAdapter extends OAuthApplication { @@ -75,14 +76,23 @@ public function clearRequests() { $this->requestsMade = array(); } + /* + * Overriding parent to prevent the addition of the OAuth parameters + */ + public function prepareRequest($method, $url, $data) + { + return $data; + } + public function makeRequest($method, $url, $data=array(), $headers=array()) { global $map; # append params to url (for fixtures) $uri = str_replace($this->app->baseUri, '', $url); - if ($method == 'GET' && !empty($data)) { - $uri = $uri.'?'. http_build_query($data); - } + + list($url_params, $request_body) = $this->formatRequestData($method, $uri, $data, $headers); + + $uri = $this->_addParametersToUrl($uri, $url_params); # extract response map parameters # From 614ddb7cb5eb5753a4dc5de69eabcd73c864e0ef Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Tue, 12 Sep 2017 09:44:43 -0400 Subject: [PATCH 106/112] Renaming the _type method to _getResourceType to be more descriptive. Renaming snake case variable to camel case to match PHP standards Improving the readability of the needsUrlFormatting method and fixing missing conditional --- aweber_api/aweber_collection.php | 6 +++--- aweber_api/aweber_response.php | 2 +- aweber_api/oauth_application.php | 22 +++++++++++----------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index 0ce6fed..b9821fd 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -84,7 +84,7 @@ public function getParentEntry(){ } /** - * _type + * _getResourceType * * Interpret what type of resources are held in this collection by * analyzing the URL @@ -92,7 +92,7 @@ public function getParentEntry(){ * @access protected * @return void */ - protected function _type() { + protected function _getResourceType() { $urlParts = explode('/', $this->url); $type = array_pop($urlParts); return $type; @@ -116,7 +116,7 @@ protected function _type() { public function create($kv_pairs) { # Create Resource $params = array_merge(array('ws.op' => 'create'), $kv_pairs); - $headers = $this->_type() == 'custom_fields' ? array() : array('Content-Type: application/json'); + $headers = $this->_getResourceType() == 'custom_fields' ? array() : array('Content-Type: application/json'); $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers'), $headers); # Return new Resource diff --git a/aweber_api/aweber_response.php b/aweber_api/aweber_response.php index 5d021a2..11971fd 100644 --- a/aweber_api/aweber_response.php +++ b/aweber_api/aweber_response.php @@ -65,7 +65,7 @@ public function __get($value) { if (array_key_exists($value, $this->data)) { return $this->data[$value]; } - if ($value == 'type') return $this->_type(); + if ($value == 'type') return $this->_getResourceType(); } } diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 49544f0..0dc2b9d 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -446,23 +446,23 @@ public function makeRequest($method, $url, $data=array(), $headers=array()) { if ($this->debug) echo "\n** {$method}: $url\n"; - list($url_params, $request_body) = $this->formatRequestData($method, $url, $data, $headers); + list($urlParams, $requestBody) = $this->formatRequestData($method, $url, $data, $headers); switch (strtoupper($method)) { case 'POST': - $resp = $this->post($url, $url_params, $request_body, $headers); + $resp = $this->post($url, $urlParams, $requestBody, $headers); break; case 'GET': - $resp = $this->get($url, $url_params, $headers); + $resp = $this->get($url, $urlParams, $headers); break; case 'DELETE': - $resp = $this->delete($url, $url_params, $headers); + $resp = $this->delete($url, $urlParams, $headers); break; case 'PATCH': - $resp = $this->patch($url, $url_params, $request_body, $headers); + $resp = $this->patch($url, $urlParams, $requestBody, $headers); break; } @@ -654,7 +654,7 @@ protected function userAgent() { * Return True if headers array does not contain 'Content-Type: application/json' and is a POST, GET, or DELETE request */ protected function needsUrlFormatting($method, $headers) { - return !in_array("Content-Type: application/json", $headers) and ($method == 'POST' or $method == 'GET' or 'DELETE'); + return !in_array("Content-Type: application/json", $headers) && in_array($method, array('POST', 'GET', 'DELETE')); } /** @@ -673,13 +673,13 @@ protected function formatRequestData($method, $url, $data, $headers) $data[$key] = json_encode($value); } } - $url_params = $this->buildData($this->prepareRequest($method, $url, $data)); - $request_body = $this->buildData($data); + $urlParams = $this->buildData($this->prepareRequest($method, $url, $data)); + $requestBody = $this->buildData($data); } else { - $url_params = $this->buildData($this->prepareRequest($method, $url, array())); - $request_body = json_encode($data); + $urlParams = $this->buildData($this->prepareRequest($method, $url, array())); + $requestBody = json_encode($data); } - return array($url_params, $request_body); + return array($urlParams, $requestBody); } } From 7793efc1e96445ae90e7ffd443389242d1a2afb6 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Wed, 13 Sep 2017 08:51:46 -0400 Subject: [PATCH 107/112] Putting the _getResourceType method back to the original name of _type Making sure the application/json conttent-type is set on PATCH --- aweber_api/aweber_collection.php | 6 +++--- aweber_api/aweber_response.php | 2 +- aweber_api/oauth_application.php | 34 ++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/aweber_api/aweber_collection.php b/aweber_api/aweber_collection.php index b9821fd..0ce6fed 100644 --- a/aweber_api/aweber_collection.php +++ b/aweber_api/aweber_collection.php @@ -84,7 +84,7 @@ public function getParentEntry(){ } /** - * _getResourceType + * _type * * Interpret what type of resources are held in this collection by * analyzing the URL @@ -92,7 +92,7 @@ public function getParentEntry(){ * @access protected * @return void */ - protected function _getResourceType() { + protected function _type() { $urlParts = explode('/', $this->url); $type = array_pop($urlParts); return $type; @@ -116,7 +116,7 @@ protected function _getResourceType() { public function create($kv_pairs) { # Create Resource $params = array_merge(array('ws.op' => 'create'), $kv_pairs); - $headers = $this->_getResourceType() == 'custom_fields' ? array() : array('Content-Type: application/json'); + $headers = $this->_type() == 'custom_fields' ? array() : array('Content-Type: application/json'); $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers'), $headers); # Return new Resource diff --git a/aweber_api/aweber_response.php b/aweber_api/aweber_response.php index 11971fd..5d021a2 100644 --- a/aweber_api/aweber_response.php +++ b/aweber_api/aweber_response.php @@ -65,7 +65,7 @@ public function __get($value) { if (array_key_exists($value, $this->data)) { return $this->data[$value]; } - if ($value == 'type') return $this->_getResourceType(); + if ($value == 'type') return $this->_type(); } } diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index 0dc2b9d..d02f8b2 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -462,6 +462,7 @@ public function makeRequest($method, $url, $data=array(), $headers=array()) { break; case 'PATCH': + $headers = $this->ensureContentType($headers, 'application/json'); $resp = $this->patch($url, $urlParams, $requestBody, $headers); break; } @@ -682,6 +683,39 @@ protected function formatRequestData($method, $url, $data, $headers) return array($urlParams, $requestBody); } + /** + * Checks the $headers array for content-type and adds the header if it doesn't exist and replaces it if isn't + * what is passed. + * + * @param $headers + * @param $expectedContentType + * @return array + */ + private function ensureContentType($headers, $expectedContentType) { + $found = false; + $stringStart = 0; + $stringLength = 13; + $explodeLimit = 1; + + foreach ($headers as $key => $value) { + if (substr(strtolower($value), $stringStart, $stringLength) == "content-type:") { + list($contentType) = explode(";", trim(substr($value, 14)), $explodeLimit); + if ($expectedContentType == $contentType){ + $found = true; + } else { + $found = true; + unset($headers[$key]); + array_push($headers, 'Content-Type: ' .$expectedContentType); + } + } + } + + if (!$found) { + array_push($headers, 'Content-Type: ' .$expectedContentType); + } + return $headers; + } + } /** From 1c3f07624afb85250a6515bbb98dc70f5f1b5731 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Wed, 13 Sep 2017 12:04:19 -0400 Subject: [PATCH 108/112] Simplifying the login in ensureContentType and adding the underscore to adhere with conventions --- aweber_api/oauth_application.php | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/aweber_api/oauth_application.php b/aweber_api/oauth_application.php index d02f8b2..35891b6 100644 --- a/aweber_api/oauth_application.php +++ b/aweber_api/oauth_application.php @@ -462,7 +462,7 @@ public function makeRequest($method, $url, $data=array(), $headers=array()) { break; case 'PATCH': - $headers = $this->ensureContentType($headers, 'application/json'); + $headers = $this->_ensureContentType($headers, 'application/json'); $resp = $this->patch($url, $urlParams, $requestBody, $headers); break; } @@ -691,28 +691,16 @@ protected function formatRequestData($method, $url, $data, $headers) * @param $expectedContentType * @return array */ - private function ensureContentType($headers, $expectedContentType) { - $found = false; - $stringStart = 0; - $stringLength = 13; - $explodeLimit = 1; + private function _ensureContentType($headers, $expectedContentType) { foreach ($headers as $key => $value) { - if (substr(strtolower($value), $stringStart, $stringLength) == "content-type:") { - list($contentType) = explode(";", trim(substr($value, 14)), $explodeLimit); - if ($expectedContentType == $contentType){ - $found = true; - } else { - $found = true; + if ( stripos($value, 'content-type:') !== false ) { unset($headers[$key]); - array_push($headers, 'Content-Type: ' .$expectedContentType); - } } - } - if (!$found) { - array_push($headers, 'Content-Type: ' .$expectedContentType); } + + $headers[] = 'Content-Type: ' . $expectedContentType; return $headers; } From 069687952511264e9dbfadced5a65db66aeab013 Mon Sep 17 00:00:00 2001 From: Geoff Paffett Date: Wed, 13 Sep 2017 13:03:44 -0400 Subject: [PATCH 109/112] Removing comment in change log --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 014f58b..3901a43 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,7 @@ Changelog: 2017-09-02: v1.1.18 * Fixing issues on the formatting of nested objects on 'application/json' requests * Fixing issue with extra data being sent in header. - * Fixing issue to allow the creation of custom fields to be sent as form encoded. - * Updating the deprecated getMock method to createMock. + * Fixing issue to allow the creation of custom fields to be sent as form encoded. 2017-08-21: v1.1.17 * Fixing UTF-8 issues on creates From fdf0a9d3e58878a824c7acaeb89ef3d010069d6c Mon Sep 17 00:00:00 2001 From: vincentf Date: Wed, 28 Aug 2019 15:29:04 -0400 Subject: [PATCH 110/112] add deprecation notice to readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 3901a43..52f34e0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +# This client library has been deprecated. +## This library will no longer be supported and does not support OAuth2. +## Please visit our [PHP Examples](https://github.com/aweber/public-api-examples/tree/master/php) as a reference. +---------------- + AWeber API PHP Library [![Build Status](https://secure.travis-ci.org/aweber/AWeber-API-PHP-Library.png?branch=master)](http://travis-ci.org/aweber/AWeber-API-PHP-Library) ====================== From 7be21ae0349f27abeb316b2d2754c39c63b66f88 Mon Sep 17 00:00:00 2001 From: vincentf Date: Wed, 28 Aug 2019 15:35:15 -0400 Subject: [PATCH 111/112] remove span --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 52f34e0..f2abc47 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# This client library has been deprecated. +# This client library has been deprecated. ## This library will no longer be supported and does not support OAuth2. ## Please visit our [PHP Examples](https://github.com/aweber/public-api-examples/tree/master/php) as a reference. ---------------- From 18b4ca944cec2598af57039344c65444acd7ac4b Mon Sep 17 00:00:00 2001 From: vincentf Date: Wed, 28 Aug 2019 16:22:30 -0400 Subject: [PATCH 112/112] change h2 to h3 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f2abc47..c09fcd6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # This client library has been deprecated. -## This library will no longer be supported and does not support OAuth2. -## Please visit our [PHP Examples](https://github.com/aweber/public-api-examples/tree/master/php) as a reference. +### This library will no longer be supported and does not support OAuth2. +### Please visit our [PHP Examples](https://github.com/aweber/public-api-examples/tree/master/php) as a reference. ---------------- AWeber API PHP Library [![Build Status](https://secure.travis-ci.org/aweber/AWeber-API-PHP-Library.png?branch=master)](http://travis-ci.org/aweber/AWeber-API-PHP-Library)