-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathStravaConnector.php
225 lines (224 loc) · 8.35 KB
/
StravaConnector.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
<?php
/*
* GNU General Public License v3.0
* Contributors: ADD YOUR NAME HERE, Mike P. Sinn
*/
namespace App\DataSources\Connectors;
use App\DataSources\OAuth2Connector;
use App\Exceptions\InvalidVariableValueAttributeException;
use App\Slim\Controller\Connector\ConnectorException;
use App\Slim\Controller\Connector\ConnectorRedirectResponse;
use App\Slim\Controller\Connector\ConnectorResponse;
use App\Slim\Model\Measurement\QMMeasurement;
use App\Units\MetersPerSecondUnit;
use App\Units\MetersUnit;
use App\VariableCategories\PhysicalActivityVariableCategory;
use App\Variables\QMUserVariable;
use OAuth\Common\Http\Exception\TokenResponseException;
use OAuth\Common\Http\Uri\Uri;
use OAuth\Common\Storage\Exception\TokenNotFoundException;
use OAuth\OAuth2\Service\Exception\InvalidAccessTypeException;
use OAuth\OAuth2\Service\Strava;
use OAuth\OAuth2\Token\StdOAuth2Token;
use Pest;
use Strava\API\Client;
use Strava\API\Exception;
use Strava\API\Service\REST;
/** Class StravaConnector
* @package App\DataSources\Connectors
*/
class StravaConnector extends OAuth2Connector {
/**
* Scopes
*/
// default
const SCOPE_READ = 'read';
// Modify activities, upload on the user’s behalf
const SCOPE_WRITE = 'write';
// View private activities and data within privacy zones
const SCOPE_VIEW_PRIVATE = 'view_private';
protected $approvalPrompt = 'auto';
protected $providesEmail = false;
protected const AFFILIATE = false;
protected const BACKGROUND_COLOR = '#fc4c02';
protected const CLIENT_REQUIRES_SECRET = true;
protected const DEFAULT_VARIABLE_CATEGORY_NAME = 'Physical Activity';
public const DISPLAY_NAME = 'Strava';
public const DISABLED_UNTIL = "2023-04-01";
protected const ENABLED = 0; // TODO: Update authentication
protected const GET_IT_URL = null;
public const IMAGE = 'https://assets.ifttt.com/images/channels/1055884022/icons/large.png';
protected const LOGO_COLOR = '#2d2d2d';
protected const LONG_DESCRIPTION = 'If you like to run, ride or just adventure outside, you\'ll love Strava. Give it a try, it\'s free! Millions of runners, cyclists and active people use Strava to record their activities, compare performance over time, connect with their community, and share the photos, stories and highlights of their adventures with friends.';
protected const PREMIUM = true;
protected const SHORT_DESCRIPTION = 'Runners and cyclists use Strava to record their activities and compare performance over time';
protected const DEVELOPER_CONSOLE = 'https://www.strava.com/settings/api';
protected const API_DOCS = 'http://developers.strava.com/docs/reference';
public $affiliate = self::AFFILIATE;
public $backgroundColor = self::BACKGROUND_COLOR;
public $clientRequiresSecret = self::CLIENT_REQUIRES_SECRET;
public $defaultVariableCategoryName = self::DEFAULT_VARIABLE_CATEGORY_NAME;
public $displayName = self::DISPLAY_NAME;
public $enabled = self::ENABLED;
public $getItUrl = self::GET_IT_URL;
public $id = self::ID;
public $image = self::IMAGE;
public $logoColor = self::LOGO_COLOR;
public $longDescription = self::LONG_DESCRIPTION;
public $name = self::NAME;
public $premium = self::PREMIUM;
public $providesUserProfileForLogin = true;
public $shortDescription = self::SHORT_DESCRIPTION;
public const ID = 76;
public const NAME = 'strava';
public static array$SCOPES = [Strava::SCOPE_READ];
public static $OAUTH_SERVICE_NAME = 'Strava';
// Dev Console: https://Strava.com/settings/applications/new
/**
* @param $parameters
* @return ConnectorException|ConnectorResponse|ConnectorRedirectResponse
* @throws TokenResponseException
*/
public function connect($parameters){
return parent::connect($parameters);
}
/**
* @return void
* @throws InvalidVariableValueAttributeException
* @throws TokenNotFoundException
* @throws TokenResponseException
*/
public function importData(): void{
$loginName = $this->getConnectorUserName();
$this->logDebug("Strava Connector: Login name: $loginName");
$this->getActivities();
}
/**
* @return Client
* @throws TokenResponseException
* @throws TokenNotFoundException
* @noinspection PhpMissingReturnTypeInspection
*/
private function getStravaClient(){
$adapter = new \GuzzleHttp\Client(['base_uri' => 'https://www.strava.com/api/v3/']);
$service = new REST($this->getAccessTokenString(), $adapter); // Define your user token here.
$client = new Client($service);
return $client;
}
/**
* @return int
* @throws InvalidVariableValueAttributeException
* @throws TokenResponseException
* @throws TokenNotFoundException
*/
private function getActivities(): int{
try {
$activities = $this->getStravaClient()->getAthleteActivities();
} catch (Exception $e) {
le($e);
}
foreach($activities as $activity){
$this->addAverageSpeedMeasurement($activity);
$this->addDistanceMeasurement($activity);
}
$this->saveMeasurements();
}
/**
* @param float $value
* @param array $activity
* @param QMUserVariable $v
* @param string $unitName
* @return QMMeasurement
*/
private function getMeasurementItem(float $value, array $activity, QMUserVariable $v,
string $unitName): QMMeasurement{
$m = $this->generateMeasurement($v, $activity['start_date'], $value, $unitName, $activity['moving_time'],
$activity['name']);
$m->getAdditionalMetaData()->addMetaData('start_latlng', $activity['start_latlng']);
$m->getAdditionalMetaData()->addMetaData('end_latlng', $activity['end_latlng']);
$m->getAdditionalMetaData()->addMetaData('map', $activity['map']);
$m->setLatitude($activity['start_latitude']);
$m->setLongitude($activity['start_longitude']);
return $m;
}
/**
* @param array $activity
* @throws InvalidVariableValueAttributeException
*/
private function addDistanceMeasurement(array $activity){
$variableName = $activity['type'] . " Distance";
$v = $this->getQMUserVariable($variableName, MetersUnit::NAME, PhysicalActivityVariableCategory::NAME);
$measurementItem = $this->getMeasurementItem($activity['distance'], $activity, $v, MetersUnit::NAME);
$measurementItem->setOriginalUnitByNameOrId(MetersUnit::NAME);
$v->addToMeasurementQueueIfNoneExist($measurementItem);
}
/**
* @param array $activity
* @throws InvalidVariableValueAttributeException
*/
private function addAverageSpeedMeasurement(array $activity){
$variableName = "Average " . $activity['type'] . " Speed";
$v = $this->getQMUserVariable($variableName, MetersPerSecondUnit::NAME, PhysicalActivityVariableCategory::NAME);
$m = $this->getMeasurementItem($activity['average_speed'], $activity, $v, MetersPerSecondUnit::NAME);
$v->addToMeasurementQueueIfNoneExist($m);
}
/**
* @throws Exception
* @throws TokenResponseException
* @throws TokenNotFoundException
*/
public function getConnectorUserProfile(): ?array{
if($this->connectorUserProfile){
return $this->connectorUserProfile;
}
$profile = $this->getStravaClient()->getAthlete();
$this->updateUserMeta($profile);
return $this->connectorUserProfile = $profile;
}
protected function updateUserMeta(array $profile){
$this->updateUserAvatarIfNecessary($profile['profile']);
parent::updateUserMeta($profile);
}
/**
* {@inheritdoc}
*/
public function getAuthorizationEndpoint(){
return new Uri('https://www.strava.com/oauth/authorize?approval_prompt=' . $this->approvalPrompt);
}
/**
* {@inheritdoc}
*/
public function getAccessTokenEndpoint(){
return new Uri('https://www.strava.com/oauth/token');
}
/**
* {@inheritdoc}
*/
protected function getAuthorizationMethod(): int{
return static::AUTHORIZATION_METHOD_HEADER_BEARER;
}
/**
* {@inheritdoc}
*/
protected function parseAccessTokenResponse($responseBody): StdOAuth2Token{
$data = $this->jsonDecodeAccessTokenResponse($responseBody);
return $this->newStdOAuth2Token($data);
}
/**
* @param $prompt
* @throws InvalidAccessTypeException
*/
public function setApprovalPrompt($prompt){
if(!in_array($prompt, ['auto', 'force'], true)){
// @todo Maybe could we rename this exception
throw new InvalidAccessTypeException('Invalid approvalPrompt, expected either auto or force.');
}
$this->approvalPrompt = $prompt;
}
/**
* {@inheritdoc}
*/
protected function getScopesDelimiter(): string{
return ',';
}
}