Phase 1 : endpoints API complets
- CoastalPoint → shortName Spot → /api/spots (API Platform)
- SargassumForecast → shortName Forecast → /api/forecasts
- ObservationController : GET /api/observations avec filtres
bbox (PostGIS ST_Intersects), date, source + geometry ST_AsGeoJSON
- SpotScoreController : GET /api/spots/{id}/score avec ?at= optionnel
- FeedbackController : POST /api/feedback, anonyme, fingerprint SHA256
- CORS : autorisation radarsargasses971.com + localhost dev
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
67
backend/src/Controller/SpotScoreController.php
Normal file
67
backend/src/Controller/SpotScoreController.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\CoastalPoint;
|
||||
use App\Entity\ImpactScore;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
#[Route('/api/spots', name: 'api_spots_')]
|
||||
class SpotScoreController extends AbstractController
|
||||
{
|
||||
public function __construct(private EntityManagerInterface $em) {}
|
||||
|
||||
/**
|
||||
* GET /api/spots/{id}/score
|
||||
*
|
||||
* Retourne le score courant pour un CoastalPoint.
|
||||
* Paramètre optionnel : ?at=YYYY-MM-DDTHH:MM:SSZ (score à un instant donné)
|
||||
*/
|
||||
#[Route('/{id}/score', name: 'score', methods: ['GET'])]
|
||||
public function score(string $id, Request $request): JsonResponse
|
||||
{
|
||||
$spot = $this->em->getRepository(CoastalPoint::class)->find($id);
|
||||
|
||||
if ($spot === null) {
|
||||
return $this->json(['error' => 'Spot not found'], 404);
|
||||
}
|
||||
|
||||
$qb = $this->em->getRepository(ImpactScore::class)
|
||||
->createQueryBuilder('s')
|
||||
->where('s.coastalPoint = :spot')
|
||||
->setParameter('spot', $spot)
|
||||
->orderBy('s.timestamp', 'DESC')
|
||||
->setMaxResults(1);
|
||||
|
||||
$atParam = $request->query->get('at');
|
||||
if ($atParam !== null) {
|
||||
try {
|
||||
$at = new \DateTimeImmutable($atParam);
|
||||
$qb->andWhere('s.timestamp <= :at')->setParameter('at', $at);
|
||||
} catch (\Exception) {
|
||||
return $this->json(['error' => 'Invalid "at" parameter format'], 400);
|
||||
}
|
||||
}
|
||||
|
||||
$latest = $qb->getQuery()->getOneOrNullResult();
|
||||
|
||||
return $this->json([
|
||||
'spotId' => (string) $spot->getId(),
|
||||
'name' => $spot->getName(),
|
||||
'type' => $spot->getType(),
|
||||
'region' => $spot->getRegion(),
|
||||
'score' => $latest ? [
|
||||
'value' => $latest->getScore(),
|
||||
'level' => $latest->getLevel(),
|
||||
'distance' => $latest->getDistanceToNearestSargassum(),
|
||||
'density' => $latest->getDensityEstimate(),
|
||||
'trend' => $latest->getTrend(),
|
||||
'computedAt' => $latest->getTimestamp()?->format(\DateTimeInterface::ATOM),
|
||||
] : null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user