Skip to content

Commit a48f63c

Browse files
committed
Merge pull request #429 from PedroAmorim/pinterest
Add service Pinterest.
2 parents 848e4e0 + 5494db9 commit a48f63c

5 files changed

Lines changed: 368 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ Included service implementations
8383
- Netatmo
8484
- Parrot Flower Power
8585
- PayPal
86+
- Pinterest
8687
- Pocket
8788
- Reddit
8889
- RunKeeper

examples/init.example.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@
123123
'key' => '',
124124
'secret' => '',
125125
),
126+
'pinterest' => array(
127+
'key' => '',
128+
'secret' => '',
129+
),
126130
'pocket' => array(
127131
'key' => '',
128132
),

examples/pinterest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
/**
4+
* Example of retrieving an authentication token of the Pinterest service
5+
*
6+
* @author Pedro Amorim <contact@pamorim.fr>
7+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
8+
* @link https://developers.pinterest.com/docs/api/overview/
9+
*/
10+
11+
use OAuth\OAuth2\Service\Pinterest;
12+
use OAuth\Common\Storage\Session;
13+
use OAuth\Common\Consumer\Credentials;
14+
use OAuth\Common\Http\Client\CurlClient;
15+
16+
/**
17+
* Bootstrap the example
18+
*/
19+
require_once __DIR__ . '/bootstrap.php';
20+
21+
// Session storage
22+
$storage = new Session();
23+
24+
// Setup the credentials for the requests
25+
$credentials = new Credentials(
26+
$servicesCredentials['pinterest']['key'],
27+
$servicesCredentials['pinterest']['secret'],
28+
preg_replace('$http://$', 'https://', $currentUri->getAbsoluteUri()) // Pinterest require Https callback's url
29+
);
30+
$serviceFactory->setHttpClient(new CurlClient);
31+
// Instantiate the Pinterest service using the credentials, http client and storage mechanism for the token
32+
/** @var $pinterestService Pinterest */
33+
$pinterestService = $serviceFactory->createService('pinterest', $credentials, $storage, [Pinterest::SCOPE_READ_PUBLIC]);
34+
35+
if (!empty($_GET['code'])) {
36+
// retrieve the CSRF state parameter
37+
$state = isset($_GET['state']) ? $_GET['state'] : null;
38+
// This was a callback request from pinterest, get the token
39+
$token = $pinterestService->requestAccessToken($_GET['code'], $state);
40+
// Show some of the resultant data
41+
$result = json_decode($pinterestService->request('v1/me/'), true);
42+
echo 'Hello ' . ucfirst($result['data']['first_name'])
43+
. ' ' . strtoupper($result['data']['last_name'])
44+
. ' your Pinterst Id is ' . $result['data']['id'];
45+
} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
46+
$url = $pinterestService->getAuthorizationUri();
47+
header('Location: ' . $url);
48+
} else {
49+
$url = $currentUri->getRelativeUri() . '?go=go';
50+
echo "<a href='$url'>Login with Pinterest!</a>";
51+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
/**
3+
* Pinterest service.
4+
*
5+
* @author Pedro Amorim <contact@pamorim.fr>
6+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
7+
* @link https://developers.pinterest.com/docs/api/overview/
8+
*/
9+
10+
namespace OAuth\OAuth2\Service;
11+
12+
use OAuth\OAuth2\Token\StdOAuth2Token;
13+
use OAuth\Common\Http\Exception\TokenResponseException;
14+
use OAuth\Common\Http\Uri\Uri;
15+
use OAuth\Common\Consumer\CredentialsInterface;
16+
use OAuth\Common\Http\Client\ClientInterface;
17+
use OAuth\Common\Storage\TokenStorageInterface;
18+
use OAuth\Common\Http\Uri\UriInterface;
19+
20+
/**
21+
* Pinterest service.
22+
*
23+
* @author Pedro Amorim <contact@pamorim.fr>
24+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
25+
* @link https://developers.pinterest.com/docs/api/overview/
26+
*/
27+
class Pinterest extends AbstractService
28+
{
29+
/**
30+
* Defined scopes - More scopes are listed here:
31+
* https://developers.pinterest.com/docs/api/overview/
32+
*/
33+
const SCOPE_READ_PUBLIC = 'read_public'; // read a user’s Pins, boards and likes
34+
const SCOPE_WRITE_PUBLIC = 'write_public'; // write Pins, boards, likes
35+
const SCOPE_READ_RELATIONSHIPS = 'read_relationships'; // read a user’s follows (boards, users, interests)
36+
const SCOPE_WRITE_RELATIONSHIPS = 'write_relationships'; // follow boards, users and interests
37+
38+
public function __construct(
39+
CredentialsInterface $credentials,
40+
ClientInterface $httpClient,
41+
TokenStorageInterface $storage,
42+
$scopes = array(),
43+
UriInterface $baseApiUri = null
44+
) {
45+
parent::__construct(
46+
$credentials,
47+
$httpClient,
48+
$storage,
49+
$scopes,
50+
$baseApiUri,
51+
true
52+
);
53+
54+
if (null === $baseApiUri) {
55+
$this->baseApiUri = new Uri('https://api.pinterest.com/');
56+
}
57+
}
58+
59+
/**
60+
* {@inheritdoc}
61+
*/
62+
public function getAuthorizationEndpoint()
63+
{
64+
return new Uri('https://api.pinterest.com/oauth/');
65+
}
66+
67+
/**
68+
* {@inheritdoc}
69+
*/
70+
public function getAccessTokenEndpoint()
71+
{
72+
return new Uri('https://api.pinterest.com/v1/oauth/token');
73+
}
74+
75+
/**
76+
* {@inheritdoc}
77+
*/
78+
protected function getAuthorizationMethod()
79+
{
80+
return static::AUTHORIZATION_METHOD_HEADER_BEARER;
81+
}
82+
83+
/**
84+
* {@inheritdoc}
85+
*/
86+
protected function parseAccessTokenResponse($responseBody)
87+
{
88+
$data = json_decode($responseBody, true);
89+
90+
if (null === $data || !is_array($data)) {
91+
throw new TokenResponseException('Unable to parse response.');
92+
} elseif (isset($data['error'])) {
93+
throw new TokenResponseException(
94+
'Error in retrieving token: "' . $data['error'] . '"'
95+
);
96+
}
97+
98+
$token = new StdOAuth2Token();
99+
$token->setAccessToken($data['access_token']);
100+
101+
if (isset($data['expires_in'])) {
102+
$token->setLifeTime($data['expires_in']);
103+
unset($data['expires_in']);
104+
}
105+
// I hope one day Pinterest add a refresh token :)
106+
if (isset($data['refresh_token'])) {
107+
$token->setRefreshToken($data['refresh_token']);
108+
unset($data['refresh_token']);
109+
}
110+
111+
unset($data['access_token']);
112+
113+
$token->setExtraParams($data);
114+
115+
return $token;
116+
}
117+
}
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
<?php
2+
3+
namespace OAuthTest\Unit\OAuth2\Service;
4+
5+
use OAuth\OAuth2\Service\Pinterest;
6+
use OAuth\Common\Token\TokenInterface;
7+
8+
class PinterestTest extends \PHPUnit_Framework_TestCase
9+
{
10+
/**
11+
* @covers OAuth\OAuth2\Service\Pinterest::__construct
12+
*/
13+
public function testConstructCorrectInterfaceWithoutCustomUri()
14+
{
15+
$service = new Pinterest(
16+
$this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
17+
$this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
18+
$this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
19+
);
20+
21+
$this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
22+
}
23+
24+
/**
25+
* @covers OAuth\OAuth2\Service\Pinterest::__construct
26+
*/
27+
public function testConstructCorrectInstanceWithoutCustomUri()
28+
{
29+
$service = new Pinterest(
30+
$this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
31+
$this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
32+
$this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
33+
);
34+
35+
$this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
36+
}
37+
38+
/**
39+
* @covers OAuth\OAuth2\Service\Pinterest::__construct
40+
*/
41+
public function testConstructCorrectInstanceWithCustomUri()
42+
{
43+
$service = new Pinterest(
44+
$this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
45+
$this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
46+
$this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
47+
array(),
48+
$this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
49+
);
50+
51+
$this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
52+
}
53+
54+
/**
55+
* @covers OAuth\OAuth2\Service\Pinterest::__construct
56+
* @covers OAuth\OAuth2\Service\Pinterest::getAuthorizationEndpoint
57+
*/
58+
public function testGetAuthorizationEndpoint()
59+
{
60+
$service = new Pinterest(
61+
$this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
62+
$this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
63+
$this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
64+
);
65+
66+
$this->assertSame(
67+
'https://api.pinterest.com/oauth/',
68+
$service->getAuthorizationEndpoint()->getAbsoluteUri()
69+
);
70+
}
71+
72+
/**
73+
* @covers OAuth\OAuth2\Service\Pinterest::__construct
74+
* @covers OAuth\OAuth2\Service\Pinterest::getAccessTokenEndpoint
75+
*/
76+
public function testGetAccessTokenEndpoint()
77+
{
78+
$service = new Pinterest(
79+
$this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
80+
$this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
81+
$this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
82+
);
83+
84+
$this->assertSame(
85+
'https://api.pinterest.com/v1/oauth/token',
86+
$service->getAccessTokenEndpoint()->getAbsoluteUri()
87+
);
88+
}
89+
90+
/**
91+
* @covers OAuth\OAuth2\Service\Box::__construct
92+
* @covers OAuth\OAuth2\Service\Box::getAuthorizationMethod
93+
*/
94+
public function testGetAuthorizationMethod()
95+
{
96+
$client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
97+
$client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
98+
99+
$token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
100+
$token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
101+
$token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
102+
103+
$storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
104+
$storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
105+
106+
$service = new Pinterest(
107+
$this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
108+
$client,
109+
$storage
110+
);
111+
112+
$headers = $service->request('https://pieterhordijk.com/my/awesome/path');
113+
114+
$this->assertTrue(array_key_exists('Authorization', $headers));
115+
$this->assertTrue(in_array('Bearer foo', $headers, true));
116+
}
117+
118+
/**
119+
* @covers OAuth\OAuth2\Service\Pinterest::__construct
120+
* @covers OAuth\OAuth2\Service\Pinterest::parseAccessTokenResponse
121+
*/
122+
public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
123+
{
124+
$client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
125+
$client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
126+
127+
$service = new Pinterest(
128+
$this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
129+
$client,
130+
$this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
131+
);
132+
133+
$this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
134+
135+
$service->requestAccessToken('foo');
136+
}
137+
138+
/**
139+
* @covers OAuth\OAuth2\Service\Pinterest::__construct
140+
* @covers OAuth\OAuth2\Service\Pinterest::parseAccessTokenResponse
141+
*/
142+
public function testParseAccessTokenResponseThrowsExceptionOnErrorDescription()
143+
{
144+
$client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
145+
$client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error_description=some_error'));
146+
147+
$service = new Pinterest(
148+
$this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
149+
$client,
150+
$this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
151+
);
152+
153+
$this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
154+
155+
$service->requestAccessToken('foo');
156+
}
157+
158+
/**
159+
* @covers OAuth\OAuth2\Service\Pinterest::__construct
160+
* @covers OAuth\OAuth2\Service\Pinterest::parseAccessTokenResponse
161+
*/
162+
public function testParseAccessTokenResponseThrowsExceptionOnError()
163+
{
164+
$client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
165+
$client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
166+
167+
$service = new Pinterest(
168+
$this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
169+
$client,
170+
$this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
171+
);
172+
173+
$this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
174+
175+
$service->requestAccessToken('foo');
176+
}
177+
178+
/**
179+
* @covers OAuth\OAuth2\Service\Pinterest::__construct
180+
* @covers OAuth\OAuth2\Service\Pinterest::parseAccessTokenResponse
181+
*/
182+
public function testParseAccessTokenResponseValid()
183+
{
184+
$client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
185+
$client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
186+
187+
$service = new Pinterest(
188+
$this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
189+
$client,
190+
$this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
191+
);
192+
193+
$this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
194+
}
195+
}

0 commit comments

Comments
 (0)