1<?php
2/**
3 * Strava service.
4 *
5 * @author  Pedro Amorim <contact@pamorim.fr>
6 * @license http://www.opensource.org/licenses/mit-license.html MIT License
7 * @link    http://strava.github.io/
8 * @link    http://strava.github.io/api/v3/oauth/
9 */
10
11namespace OAuth\OAuth2\Service;
12
13use OAuth\OAuth2\Token\StdOAuth2Token;
14use OAuth\Common\Http\Exception\TokenResponseException;
15use OAuth\Common\Http\Uri\Uri;
16use OAuth\Common\Consumer\CredentialsInterface;
17use OAuth\Common\Http\Client\ClientInterface;
18use OAuth\Common\Storage\TokenStorageInterface;
19use OAuth\Common\Http\Uri\UriInterface;
20use OAuth\OAuth2\Service\Exception\InvalidAccessTypeException;
21
22/**
23 * Strava service.
24 *
25 * @author  Pedro Amorim <contact@pamorim.fr>
26 * @license http://www.opensource.org/licenses/mit-license.html MIT License
27 * @link    http://strava.github.io/
28 * @link    http://strava.github.io/api/v3/oauth/
29 */
30class Strava extends AbstractService
31{
32    /**
33     * Scopes
34     */
35    // default
36    const SCOPE_PUBLIC       = 'public';
37    // Modify activities, upload on the user’s behalf
38    const SCOPE_WRITE        = 'write';
39    // View private activities and data within privacy zones
40    const SCOPE_VIEW_PRIVATE = 'view_private';
41
42    protected $approvalPrompt = 'auto';
43
44    public function __construct(
45        CredentialsInterface $credentials,
46        ClientInterface $httpClient,
47        TokenStorageInterface $storage,
48        $scopes = array(),
49        UriInterface $baseApiUri = null
50    ) {
51        if (empty($scopes)) {
52            $scopes = array(self::SCOPE_PUBLIC);
53        }
54
55        parent::__construct(
56            $credentials,
57            $httpClient,
58            $storage,
59            $scopes,
60            $baseApiUri,
61            true
62        );
63
64        if (null === $baseApiUri) {
65            $this->baseApiUri = new Uri('https://www.strava.com/api/v3/');
66        }
67    }
68
69    /**
70     * {@inheritdoc}
71     */
72    public function getAuthorizationEndpoint()
73    {
74        return new Uri('https://www.strava.com/oauth/authorize?approval_prompt=' . $this->approvalPrompt);
75    }
76
77    /**
78     * {@inheritdoc}
79     */
80    public function getAccessTokenEndpoint()
81    {
82        return new Uri('https://www.strava.com/oauth/token');
83    }
84
85    /**
86     * {@inheritdoc}
87     */
88    protected function getAuthorizationMethod()
89    {
90        return static::AUTHORIZATION_METHOD_HEADER_BEARER;
91    }
92
93    /**
94     * {@inheritdoc}
95     */
96    protected function parseAccessTokenResponse($responseBody)
97    {
98        $data = json_decode($responseBody, true);
99
100        if (null === $data || !is_array($data)) {
101            throw new TokenResponseException('Unable to parse response.');
102        } elseif (isset($data['error_description'])) {
103            throw new TokenResponseException(
104                'Error in retrieving token: "' . $data['error_description'] . '"'
105            );
106        } elseif (isset($data['error'])) {
107            throw new TokenResponseException(
108                'Error in retrieving token: "' . $data['error'] . '"'
109            );
110        }
111
112        $token = new StdOAuth2Token();
113        $token->setAccessToken($data['access_token']);
114
115        if (isset($data['expires_in'])) {
116            $token->setLifeTime($data['expires_in']);
117            unset($data['expires_in']);
118        }
119        if (isset($data['refresh_token'])) {
120            $token->setRefreshToken($data['refresh_token']);
121            unset($data['refresh_token']);
122        }
123
124        unset($data['access_token']);
125
126        $token->setExtraParams($data);
127
128        return $token;
129    }
130
131    public function setApprouvalPrompt($prompt)
132    {
133        if (!in_array($prompt, array('auto', 'force'), true)) {
134            // @todo Maybe could we rename this exception
135            throw new InvalidAccessTypeException('Invalid approuvalPrompt, expected either auto or force.');
136        }
137        $this->approvalPrompt = $prompt;
138    }
139
140    /**
141     * {@inheritdoc}
142     */
143    protected function getScopesDelimiter()
144    {
145        return ',';
146    }
147}
148