<?php
namespace App\Controller;
use App\Entity\User;
use App\Manager\AreaManagerInterface;
use App\Manager\ContractManagerInterface;
use App\Manager\OrganizationManagerInterface;
use App\Manager\SignalManagerInterface;
use App\Manager\UserManagerInterface;
use App\Models\Heimdall\Service;
use Psr\Log\LoggerInterface;
use Swagger\Annotations as SWG;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
class SignalController extends AbstractController
{
protected AreaManagerInterface $areaManager;
protected ContractManagerInterface $contractManager;
protected LoggerInterface $logger;
protected NormalizerInterface $normalizer;
protected SignalManagerInterface $signalManager;
protected UserManagerInterface $userManager;
protected OrganizationManagerInterface $organizationManager;
public function __construct(
AreaManagerInterface $areaManager,
ContractManagerInterface $contractManager,
LoggerInterface $logger,
NormalizerInterface $normalizer,
SignalManagerInterface $signalManager,
UserManagerInterface $userManager,
OrganizationManagerInterface $organizationManager
) {
$this->areaManager = $areaManager;
$this->contractManager = $contractManager;
$this->logger = $logger;
$this->normalizer = $normalizer;
$this->signalManager = $signalManager;
$this->userManager = $userManager;
$this->organizationManager = $organizationManager;
}
/**
* Get all Signal.
*
* @Route("/api/signal.{format}", name="get_signals" , defaults={"format": "json"}, methods={"GET"})
*
* @SWG\Get (
* path="/api/signal.{format}",
* tags={"Signal"},
* summary="Get filtered signals",
* @SWG\Parameter(
* name="format",
* in="path",
* type="string",
* enum={"json","xml","csv","geojson"},
* default="json",
* description="Technical attribute to manage output format without header 'Accept' data",
* required=true
* ),
* @SWG\Parameter(
* name="q",
* in="query",
* type="string",
* description="Search",
* required=false
* ),
* @SWG\Parameter(
* name="filter[ownerApplication][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="The owner Application code (created by)",
* required=false
* ),
* @SWG\Parameter(
* name="filter[creatorApplication][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="The creator application id (created for)",
* required=false
* ),
* @SWG\Parameter(
* name="filter[requestType][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="The specific type of request",
* required=false
* ),
* @SWG\Parameter(
* name="filter[comment][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="The specific comment of request (part of text)",
* required=false
* ),
* @SWG\Parameter(
* name="filter[languageCode][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="The language code of the request",
* required=false
* ),
* @SWG\Parameter(
* name="filter[applicationUser][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="The user of the request",
* required=false
* ),
* @SWG\Parameter(
* name="filter[thirdParty][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="The thirdParty of the request",
* required=false
* ),
* @SWG\Parameter(
* name="filter[siret][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="The user of the request",
* required=false
* ),
* @SWG\Parameter(
* name="filter[status][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="The id of the current status of the request",
* required=false
* ),
* @SWG\Parameter(
* name="timeline",
* in="query",
* type="boolean",
* description="Display timeLine",
* required=false
* ),
* @SWG\Parameter(
* name="filter[createdAt][start]",
* in="query",
* type="string",
* format="date-time",
* description="Start date to filter the creation date (ISO 8601, ex : 2016-01-01T00:00:00Z)",
* required=false
* ),
* @SWG\Parameter(
* name="filter[createdAt][end]",
* in="query",
* type="string",
* format="date-time",
* description="End date to filter the creation date (ISO 8601, ex : 2016-01-01T00:00:00Z)",
* required=false
* ),
* @SWG\Parameter(
* name="filter[updatedAt][start]",
* in="query",
* type="string",
* format="date-time",
* description="Start date to filter the modification date (ISO 8601, ex : 2016-01-01T00:00:00Z)",
* required=false
* ),
* @SWG\Parameter(
* name="filter[updatedAt][end]",
* in="query",
* type="string",
* format="date-time",
* description="End date to filter the modification date (ISO 8601, ex : 2016-01-01T00:00:00Z)",
* required=false
* ),
* @SWG\Parameter(
* name="filter[receiptDate][start]",
* in="query",
* type="string",
* format="date-time",
* description="Start date to filter the receipt date (ISO 8601, ex : 2016-01-01T00:00:00Z)",
* required=false
* ),
* @SWG\Parameter(
* name="filter[receiptDate][end]",
* in="query",
* type="string",
* format="date-time",
* description="End date to filter the receipt date (ISO 8601, ex : 2016-01-01T00:00:00Z)",
* required=false
* ),
* @SWG\Parameter(
* name="filter[deadlineResponseDate][start]",
* in="query",
* type="string",
* format="date-time",
* description="Start date to filter the deadline response date (ISO 8601, ex : 2016-01-01T00:00:00Z)",
* required=false
* ),
* @SWG\Parameter(
* name="filter[deadlineResponseDate][end]",
* in="query",
* type="string",
* format="date-time",
* description="End date to filter the deadline response date (ISO 8601, ex : 2016-01-01T00:00:00Z)",
* required=false
* ),
* @SWG\Parameter(
* name="filterFields[]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="Filter fields, to filter one by one some fields. Each line have format : ```<fieldName><operator>[<valuesCommaSeparator>]```. Operator can be ```__EQ__, __EQS__, __RANGE__, __LT__, __GT__, __EQLT__, __EQGT__, __NULLGT__, __NULLLT__, __IS__, __ISNOT__```",
* required=false
* ),
* @SWG\Parameter(
* name="context[type][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* required=false
* ),
* @SWG\Parameter(
* name="context[id][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* ),
* @SWG\Parameter(
* name="context[condition][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* ),
* @SWG\Parameter(
* name="sort[fields][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="Name of the field to sort",
* required=false
* ),
* @SWG\Parameter(
* name="sort[order][]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="The way to order (asc or desc)",
* required=false
* ),
* @SWG\Parameter(
* name="pagination[page]",
* in="query",
* type="integer",
* description="Current page",
* required=false
* ),
* @SWG\Parameter(
* name="pagination[size]",
* in="query",
* description="Items per page",
* required=false,
* type="integer"
* ),
* @SWG\Parameter(
* name="exportFields[]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="Fields to export",
* required=false
* ),
* @SWG\Parameter(
* name="exportLabels[]",
* in="query",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi",
* description="Labels for export",
* required=false
* ),
* @SWG\Parameter(
* name="distance[length]",
* in="query",
* type="number",
* description="The distance is in meter.",
* required=false
* ),
* @SWG\Parameter(
* name="distance[latitude]",
* in="query",
* type="number",
* description="latitude",
* required=false
* ),
* @SWG\Parameter(
* name="distance[longitude]",
* in="query",
* type="number",
* description="longitude",
* required=false
* ),
* @SWG\Parameter(
* name="withStatuses",
* in="query",
* type="boolean",
* description="Display all statuses",
* required=false
* ),
* @SWG\Response(
* response="200",
* description="Returned when successful"
* )
*)
*
* @return JsonResponse
*
* @throws \App\Exception\UserNotFoundException
*/
public function getSignalements(Request $request, string $format)
{
$parameters = $request->query->all();
/** @var User $user */
$user = $this->getUser();
$userHeimdall = $this->userManager->findUser($user->getUsername());
$contractId = $user->getCurrentContractId();
$geojson = $this->areaManager->getUserGeoJsonByService(
$userHeimdall,
[Service::SIGNAL_NOTIFY_SERVICE_CODE], $contractId
);
if (empty($geojson)) {
$this->logger->error(
sprintf (
'Error getting user\'s geojson %s by services %s',
$user->getUsername(),
Service::SIGNAL_NOTIFY_SERVICE_CODE
)
);
return new JsonResponse([]);
}
$parameters = $this->addRequestTypeFiltersByUser($parameters);
/** @var array $signals */
$signals= $this->signalManager->getFilteredSignals(['query' => $parameters, 'body' => $geojson], $format);
return new JsonResponse($signals["data"], Response::HTTP_OK, $signals["headers"]);
}
/**
* Get one Signal.
*
* @Route("/api/signal/{signalId}", name="get_one_signal", methods={"GET"})
*
* @SWG\Get (
* path="/api/signal/{signalId}",
* tags={"Signal"},
* summary="Get one signal",
* @SWG\Parameter(
* name="signalId",
* in="path",
* type="string",
* description="The signal unique id",
* required=true
* ),
* @SWG\Parameter(
* name="withTranslationKey",
* in="query",
* type="boolean",
* description="If true, add translationKey to response",
* required=false
* ),
* @SWG\Response(
* response="200",
* description="Returned when successful"
* ),
* @SWG\Response(
* response=403,
* description="Access denied. You do not have permission to view this request."
* ),
* @SWG\Response(
* response="404",
* description="Returned when the signal is not found"
* )
* )
*
* @param string $signalId
*
* @return JsonResponse
*
* @throws ClientExceptionInterface
*/
public function getOne(string $signalId, Request $request): JsonResponse
{
$withTranslationKey = json_decode($request->query->get('withTranslationKey'));
$withStatuses = json_decode($request->query->get('withStatuses'));
$signal = $this->signalManager->getSignalById($signalId, $this->getUser(), $withTranslationKey, $withStatuses);
return new JsonResponse($signal, Response::HTTP_OK);
}
private function addRequestTypeFiltersByUser(array $parameters): array
{
/** @var User $user */
$user = $this->getUser();
$contractId = $user->getCurrentContractId();
$userRequestTypes = $this->signalManager->getUserOrganizationsRequestTypes($user->getHeimdallId(), $contractId);
$userRequestTypesToFilter = array_filter(
$parameters['filter']['requestType'] ?? [],
fn($requestType) => in_array($requestType, $userRequestTypes)
);
$parameters['filter']['requestType'] = $userRequestTypesToFilter;
return $parameters;
}
/**
* Get all Signal.
*
* @Route("/api/requestTypes", name="get_signal_request_types", methods={"GET"})
*
* @SWG\Get (
* path="/api/requestTypes",
* tags={"Signal"},
* summary="Get all request types from signal organizations",
* @SWG\Response(
* response="200",
* description="Returned when successful"
* )
* )
*
* @param Request $request
* @return JsonResponse
*/
public function getSignalRequestTypes(Request $request): JsonResponse
{
$parameters = $request->query->all();
$signals= $this->signalManager->getSignalRequestTypes(['query' => $parameters]);
return new JsonResponse($signals["data"], Response::HTTP_OK, $signals["headers"]);
}
/**
* Get top category signal in user perimeter.
*
* @Route("/api/widget/signal/top-category/{length}", name="get_signal_top_category", methods={"GET"})
*
* @SWG\Get(
* path="/api/widget/signal/top-category/{length}",
* tags={"Signal"},
* summary="Get top category signal in user perimeter",
* @SWG\Parameter(
* name="length",
* in="path",
* type="integer",
* default=5,
* description="Number of elements returned",
* required=true
* ),
* @SWG\Response(
* response="200",
* description="Returned when successful"
* )
* )
*/
public function getSignalTopCategory(int $length = 5): JsonResponse
{
$user = $this->userManager->findUser($this->getUser()->getUsername());
$geoJson = $this->areaManager->getUserGeoJsonByService($user, [Service::SIGNAL_NOTIFY_SERVICE_CODE]);
if ('' === $geoJson) {
$this->logger->error(
sprintf (
'Error getting user\'s geojson %s by services %s',
$this->getUser()->getUsername(),
Service::SIGNAL_NOTIFY_SERVICE_CODE
)
);
return new JsonResponse([], Response::HTTP_OK);
}
$topCategory = $this->signalManager->getSignalTopCategory($length, $geoJson);
if ('' === $topCategory) {
return new JsonResponse(null, Response::HTTP_BAD_REQUEST);
}
return new JsonResponse($topCategory, Response::HTTP_OK, [], true);
}
/**
* Get stats for Signal.
*
* @Route("/api/statistics/status", name="get_signals_status_direct", methods={"GET"})
*
* @SWG\Get (
* path="/api/statistics/status",
* tags={"Signal"},
* summary="Get statistics for signals",
* @SWG\Response(
* response="200",
* description="stats"
* )
* )
*/
public function getStatsDirect(Request $request): JsonResponse
{
$parameters = $request->query->all();
$user = $this->userManager->findUser($this->getUser()->getUsername());
$geoJson = $this->areaManager->getUserGeoJsonByService($user, [Service::SIGNAL_NOTIFY_SERVICE_CODE]);
if (empty($geoJson)) {
$this->logger->error(
sprintf (
'Error getting user\'s geojson %s by services %s',
$this->getUser()->getUsername(),
Service::SIGNAL_NOTIFY_SERVICE_CODE
)
);
return new JsonResponse([], Response::HTTP_OK);
}
$parameters = $this->addRequestTypeFiltersByUser($parameters);
list($stats) = $this->signalManager->getStatsSignals($geoJson, $parameters);
return new JsonResponse($stats);
}
/**
* Get stats for Signal.
*
* @Route("/api/widget/signal/stats", name="get_signals_stats", methods={"GET"})
*
* @SWG\Get (
* path="/api/widget/signal/stats",
* tags={"Signal"},
* summary="Get statistics for signals",
* @SWG\Response(
* response="200",
* description="stats"
* )
* )
*/
public function getStats(): JsonResponse
{
/** @var User $user */
$user = $this->getUser();
$userHeimdall = $this->userManager->findUser($user->getUsername());
$contractId = $user->getCurrentContractId();
$geoJson = $this->areaManager->getUserGeoJsonByService($userHeimdall, [Service::SIGNAL_NOTIFY_SERVICE_CODE], $contractId);
$userRequestTypes = $this->signalManager->getUserOrganizationsRequestTypes($user->getId(), $contractId);
if ('' === $geoJson) {
$this->logger->error(
sprintf (
'Error getting user\'s geojson %s by services %s',
$this->getUser()->getUsername(),
Service::SIGNAL_NOTIFY_SERVICE_CODE
)
);
return new JsonResponse([], Response::HTTP_OK);
}
$queryParams = [
'filter' => [
'requestType' => $userRequestTypes
]
];
list($stats) = $this->signalManager->getStatsSignals($geoJson, $queryParams);
return new JsonResponse($stats);
}
/**
* @Route("/api/organization/{organizationId}/signal", methods={"POST"})
*
* @SWG\Post (
* path="/api/organization/{organizationId}/signal",
* tags={"Signal"},
* summary="Create signals",
* @SWG\Response(
* response="201",
* description="created"
* )
* )
*
* @param Request $request
* @param string $organizationId
*
* @return Response
*/
public function create(Request $request, string $organizationId): Response
{
/** @var User $user */
$user = $this->getUser();
$data = json_decode($request->getContent(), true);
$options['contract'] = $user->getCurrentContract();
$options['authorization'] = $request->headers->get('authorization');
try {
$response = $this->signalManager->createSignal($organizationId, $data, $options);
$explodedLocation = explode('/', $response->getHeaders()['location'][0]);
$signalId = end($explodedLocation);
return new JsonResponse([], Response::HTTP_CREATED, [
"location" => "/api/signal/" . $signalId
]);
} catch (ClientExceptionInterface $exception) {
return new JsonResponse(null, Response::HTTP_NOT_FOUND);
}
}
}