api/app/Services/StravaClient.php

101 lines
3.1 KiB
PHP

<?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]);
}
}