feat: strava sync
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\StravaConnection;
|
||||
use Illuminate\Http\Client\PendingRequest;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use RuntimeException;
|
||||
|
||||
class StravaClient
|
||||
{
|
||||
private const AUTHORIZE_URL = 'https://www.strava.com/oauth/mobile/authorize';
|
||||
|
||||
public function authorizationUrl(string $state): string
|
||||
{
|
||||
$clientId = config('services.strava.client_id');
|
||||
$redirectUri = config('services.strava.redirect_uri');
|
||||
|
||||
if (! $clientId || ! $redirectUri) {
|
||||
throw new RuntimeException('Strava is not configured.');
|
||||
}
|
||||
|
||||
return self::AUTHORIZE_URL.'?'.http_build_query([
|
||||
'client_id' => $clientId,
|
||||
'redirect_uri' => $redirectUri,
|
||||
'response_type' => 'code',
|
||||
'approval_prompt' => 'auto',
|
||||
'scope' => config('services.strava.scope', 'read,activity:read'),
|
||||
'state' => $state,
|
||||
], '', '&', PHP_QUERY_RFC3986);
|
||||
}
|
||||
|
||||
public function exchangeCode(string $code): array
|
||||
{
|
||||
return $this->tokenRequest()
|
||||
->post('/oauth/token', [
|
||||
'client_id' => config('services.strava.client_id'),
|
||||
'client_secret' => config('services.strava.client_secret'),
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
->throw()
|
||||
->json();
|
||||
}
|
||||
|
||||
public function refresh(StravaConnection $connection): StravaConnection
|
||||
{
|
||||
$payload = $this->tokenRequest()
|
||||
->post('/oauth/token', [
|
||||
'client_id' => config('services.strava.client_id'),
|
||||
'client_secret' => config('services.strava.client_secret'),
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $connection->refresh_token,
|
||||
])
|
||||
->throw()
|
||||
->json();
|
||||
|
||||
$connection->update([
|
||||
'access_token' => $payload['access_token'],
|
||||
'refresh_token' => $payload['refresh_token'],
|
||||
'expires_at' => Carbon::createFromTimestamp((int) $payload['expires_at']),
|
||||
]);
|
||||
|
||||
return $connection->refresh();
|
||||
}
|
||||
|
||||
public function activities(StravaConnection $connection, int $page, int $perPage): array
|
||||
{
|
||||
return Http::baseUrl('https://www.strava.com/api/v3')
|
||||
->withToken($this->accessToken($connection))
|
||||
->timeout(10)
|
||||
->connectTimeout(3)
|
||||
->retry([100, 500, 1000])
|
||||
->get('/athlete/activities', [
|
||||
'page' => $page,
|
||||
'per_page' => $perPage,
|
||||
])
|
||||
->throw()
|
||||
->json();
|
||||
}
|
||||
|
||||
private function accessToken(StravaConnection $connection): string
|
||||
{
|
||||
if (! $connection->expires_at || $connection->expires_at->lte(now()->addMinutes(5))) {
|
||||
$connection = $this->refresh($connection);
|
||||
}
|
||||
|
||||
return $connection->access_token;
|
||||
}
|
||||
|
||||
private function tokenRequest(): PendingRequest
|
||||
{
|
||||
return Http::baseUrl('https://www.strava.com')
|
||||
->asForm()
|
||||
->timeout(10)
|
||||
->connectTimeout(3)
|
||||
->retry([100, 500, 1000]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user