feat: return xp

This commit is contained in:
Leon Morival 2026-04-29 15:55:29 +02:00
parent 270f10a916
commit 6f4aa9f4e4
4 changed files with 72 additions and 22 deletions

View File

@ -9,6 +9,7 @@ use App\Notifications\HuntParticipantJoinedNotification;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
class HuntsController extends Controller class HuntsController extends Controller
@ -20,10 +21,14 @@ class HuntsController extends Controller
$filters = $this->buildMeilisearchFilters($request); $filters = $this->buildMeilisearchFilters($request);
$search = Hunts::search($searchTerm ?? '') $search = Hunts::search($searchTerm ?? '')
->query(fn ($query) => $query->with('participants:id,avatar_uri')) ->query(fn ($query) => $query
->with('participants:id,avatar_uri')
->withSum('steps', 'xp')
)
->options(['filter' => $filters]); ->options(['filter' => $filters]);
$result = $search->paginate(10); $result = $search->paginate(10);
$this->appendTotalXpToHunts($result->getCollection());
Log::info('HUNTS_SEARCH_SUCCESS', [ Log::info('HUNTS_SEARCH_SUCCESS', [
'total' => $result->total(), 'total' => $result->total(),
@ -448,6 +453,17 @@ class HuntsController extends Controller
return $searchTerm !== '' ? $searchTerm : null; return $searchTerm !== '' ? $searchTerm : null;
} }
/**
* @param Collection<int, Hunts> $hunts
*/
private function appendTotalXpToHunts(Collection $hunts): void
{
$hunts->each(function (Hunts $hunt): void {
$hunt->setAttribute('xp', $hunt->totalXp());
$hunt->makeHidden('steps_sum_xp');
});
}
private function parseDateFilterUtc(mixed $value): ?Carbon private function parseDateFilterUtc(mixed $value): ?Carbon
{ {
if (! is_string($value) || trim($value) === '') { if (! is_string($value) || trim($value) === '') {

View File

@ -17,27 +17,7 @@ class HuntResource extends JsonResource
public function toArray(Request $request): array public function toArray(Request $request): array
{ {
return array_merge(parent::toArray($request), [ return array_merge(parent::toArray($request), [
'xp' => $this->totalXp(), 'xp' => $this->resource->totalXp(),
]); ]);
} }
private function totalXp(): int
{
if ($this->resource->relationLoaded('steps')) {
return (int) $this->resource->steps->sum('xp');
}
$stepsSumXp = $this->resource->getAttribute('steps_sum_xp');
if ($stepsSumXp !== null) {
return (int) $stepsSumXp;
}
return (int) (
$this->resource->steps_sum_xp
?? $this->resource->steps?->sum('xp')
?? $this->resource->steps()->sum('xp')
?? 0
);
}
} }

View File

@ -64,6 +64,21 @@ class Hunts extends Model
->withTimestamps(); ->withTimestamps();
} }
public function totalXp(): int
{
if ($this->relationLoaded('steps')) {
return (int) $this->steps->sum('xp');
}
$stepsSumXp = $this->getAttribute('steps_sum_xp');
if ($stepsSumXp !== null) {
return (int) $stepsSumXp;
}
return (int) $this->steps()->sum('xp');
}
/** /**
* Configure Meilisearch index settings * Configure Meilisearch index settings
*/ */

View File

@ -0,0 +1,39 @@
<?php
use App\Models\Hunts;
use App\Models\HuntSteps;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Scout\EngineManager;
uses(RefreshDatabase::class);
it('lists hunts with total step xp', function () {
config(['scout.driver' => 'collection']);
app(EngineManager::class)->forgetEngines();
$user = User::factory()->create();
$hunt = Hunts::withoutSyncingToSearch(fn () => Hunts::factory()->create([
'title' => 'Treasure hunt',
]));
HuntSteps::factory()->create([
'hunt_id' => $hunt->id,
'xp' => 125,
]);
HuntSteps::factory()->create([
'hunt_id' => $hunt->id,
'xp' => 75,
]);
$response = $this
->actingAs($user, 'sanctum')
->getJson('/api/hunts');
$response
->assertOk()
->assertJsonPath('data.0.id', $hunt->id)
->assertJsonPath('data.0.xp', 200)
->assertJsonMissingPath('data.0.steps_sum_xp');
});