Skip to content

Commit e8644bf

Browse files
committed
fix: read the active days while the export streams, so an export that is the first visit of the day includes it
1 parent 03d484a commit e8644bf

2 files changed

Lines changed: 30 additions & 3 deletions

File tree

‎app/Actions/CreateExport.php‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* schema_version: int,
3838
* exported_at: string,
3939
* profile: array<string, bool|int|string|null>,
40-
* active_days: array<mixed>,
40+
* active_days: Generator<int, string>,
4141
* commits: Generator<int, array<string, mixed>>,
4242
* polls: Generator<int, ExportPoll>,
4343
* poll_votes: Generator<int, ExportPollVote>,
@@ -106,7 +106,7 @@ public function handle(User $user): array
106106
'created_at' => $user->created_at->toIso8601String(),
107107
'updated_at' => $user->updated_at->toIso8601String(),
108108
],
109-
'active_days' => DB::table('user_active_days')->where('user_id', $user->id)->oldest('seen_at')->pluck('seen_at')->all(),
109+
'active_days' => $this->activeDays($user),
110110
'commits' => $this->commits($user),
111111
'polls' => $this->polls($user),
112112
'poll_votes' => $this->pollVotes($user),
@@ -244,6 +244,22 @@ private function pollVotes(User $user): Generator
244244
}
245245
}
246246

247+
/**
248+
* The days the user was seen, oldest first. They are read while the export streams, after the request asking for it
249+
* was recorded, so an export that is the first visit of the day includes that day.
250+
*
251+
* @return Generator<int, string>
252+
*/
253+
private function activeDays(User $user): Generator
254+
{
255+
/** @var LazyCollection<int, object{seen_at: string}> $days */
256+
$days = DB::table('user_active_days')->where('user_id', $user->id)->oldest('seen_at')->cursor();
257+
258+
foreach ($days as $day) {
259+
yield $day->seen_at;
260+
}
261+
}
262+
247263
/**
248264
* @return Generator<int, string>
249265
*/

‎tests/Feature/Controllers/ExportControllerTest.php‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@
466466
});
467467

468468
it('exports the days the user was seen, oldest first, without the days of others', function (): void {
469-
$user = User::factory()->create();
469+
$user = User::factory()->create(['last_seen_at' => now()]);
470470
DB::table('user_active_days')->insert([
471471
['user_id' => $user->id, 'seen_at' => '2026-10-21'],
472472
['user_id' => $user->id, 'seen_at' => '2026-10-19'],
@@ -479,6 +479,17 @@
479479
expect($data['active_days'])->toBe(['2026-10-19', '2026-10-21']);
480480
});
481481

482+
it('exports today when the export is the first visit of the day', function (): void {
483+
$this->travelTo(now()->setDate(2026, 10, 30)->setTime(12, 0));
484+
$user = User::factory()->create(['last_seen_at' => '2026-10-29']);
485+
DB::table('user_active_days')->insert(['user_id' => $user->id, 'seen_at' => '2026-10-29']);
486+
487+
$response = $this->actingAs($user)->get(route('export'));
488+
$data = json_decode($response->streamedContent(), true, flags: JSON_THROW_ON_ERROR);
489+
490+
expect($data['active_days'])->toBe(['2026-10-29', '2026-10-30']);
491+
});
492+
482493
it('exports the devices approved for the app, oldest first', function (): void {
483494
$user = User::factory()->create();
484495
$older = Device::factory()->for($user)->create(['name' => 'devnull on iPad', 'approved_at' => now()->subWeek(), 'last_used_at' => now()->subDay()]);

0 commit comments

Comments
 (0)