feat: try sync calories
Laravel CI-CD / Tests Unitaires (push) Successful in 22s Details
Laravel CI-CD / Deploy with Kamal (push) Successful in 1m46s Details

This commit is contained in:
Leon Morival 2026-05-20 17:06:32 +02:00
parent 3d240eca81
commit 75b2743e75
3 changed files with 79 additions and 2 deletions

View File

@ -5,6 +5,7 @@ namespace App\Http\Controllers;
use App\Enums\WorkoutSource; use App\Enums\WorkoutSource;
use App\Http\Requests\StravaCallbackRequest; use App\Http\Requests\StravaCallbackRequest;
use App\Http\Requests\StravaSyncRequest; use App\Http\Requests\StravaSyncRequest;
use App\Models\StravaConnection;
use App\Models\WorkoutSessions; use App\Models\WorkoutSessions;
use App\Services\StravaClient; use App\Services\StravaClient;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@ -111,11 +112,13 @@ class StravaController extends Controller
], 422); ], 422);
} }
$activities = $strava->activities( $activities = collect($strava->activities(
$connection, $connection,
$request->integer('page', 1), $request->integer('page', 1),
$request->integer('per_page', 30), $request->integer('per_page', 30),
); ))
->map(fn (array $activity): array => $this->activityForStorage($strava, $connection, $activity))
->all();
$importedCount = collect($activities) $importedCount = collect($activities)
->map(fn (array $activity): WorkoutSessions => $this->storeActivity($request, $activity)) ->map(fn (array $activity): WorkoutSessions => $this->storeActivity($request, $activity))
@ -144,6 +147,15 @@ class StravaController extends Controller
]); ]);
} }
private function activityForStorage(StravaClient $strava, StravaConnection $connection, array $activity): array
{
if (array_key_exists('calories', $activity) || empty($activity['id'])) {
return $activity;
}
return array_replace($activity, $strava->activity($connection, $activity['id']));
}
private function canReadActivities(array $scopes): bool private function canReadActivities(array $scopes): bool
{ {
return in_array('activity:read', $scopes, true) return in_array('activity:read', $scopes, true)

View File

@ -79,6 +79,20 @@ class StravaClient
->json(); ->json();
} }
public function activity(StravaConnection $connection, int|string $activityId): array
{
return Http::baseUrl('https://www.strava.com/api/v3')
->withToken($this->accessToken($connection))
->timeout(10)
->connectTimeout(3)
->retry([100, 500, 1000])
->get("/activities/{$activityId}", [
'include_all_efforts' => false,
])
->throw()
->json();
}
private function accessToken(StravaConnection $connection): string private function accessToken(StravaConnection $connection): string
{ {
if (! $connection->expires_at || $connection->expires_at->lte(now()->addMinutes(5))) { if (! $connection->expires_at || $connection->expires_at->lte(now()->addMinutes(5))) {

View File

@ -144,6 +144,57 @@ it('syncs strava activities into workouts', function () {
]); ]);
}); });
it('syncs strava calories from detailed activities when summaries omit them', function () {
Http::preventStrayRequests();
Http::fake([
'https://www.strava.com/api/v3/athlete/activities*' => Http::response([
[
'id' => 1122334455,
'name' => 'Evening ride',
'sport_type' => 'Ride',
'moving_time' => 2410,
'distance' => 20500.2,
'start_date' => '2026-05-19T17:45:00Z',
],
]),
'https://www.strava.com/api/v3/activities/1122334455*' => Http::response([
'id' => 1122334455,
'name' => 'Evening ride',
'sport_type' => 'Ride',
'moving_time' => 2410,
'calories' => 618.4,
'distance' => 20500.2,
'start_date' => '2026-05-19T17:45:00Z',
]),
]);
$user = User::factory()->create();
StravaConnection::create([
'user_id' => $user->id,
'athlete_id' => 123456,
'access_token' => 'access-token',
'refresh_token' => 'refresh-token',
'expires_at' => now()->addHour(),
'scopes' => ['read', 'activity:read'],
'athlete' => ['id' => 123456],
]);
Sanctum::actingAs($user);
$this
->postJson('/api/strava/sync')
->assertOk()
->assertJsonPath('data.importedCount', 1)
->assertJsonPath('data.fetchedCount', 1);
$this->assertDatabaseHas('workout_sessions', [
'user_id' => $user->id,
'source' => WorkoutSource::STRAVA->value,
'external_id' => '1122334455',
'calories_burned' => 618,
]);
});
it('requires an activity read scope before syncing strava activities', function () { it('requires an activity read scope before syncing strava activities', function () {
$user = User::factory()->create(); $user = User::factory()->create();
StravaConnection::create([ StravaConnection::create([