<?php
namespace App\Controller\Request;
use App\Converter\RequestConverter;
use App\Exception\CreateRequestException;
use App\Exception\RequestRelationException;
use App\Manager\OrganizationManagerInterface;
use App\Message\ExportMessage;
use App\Service\RequestBridgeService;
use App\Models\Signal\Status as SignalStatus;
use App\Models\Request\Request as PceRequest;
use Psr\Log\LoggerInterface;
use Nelmio\ApiDocBundle\Annotation\Model as Model;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Annotation\Route;
use Swagger\Annotations as SWG;
use App\Manager\SignalManager;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use App\Constants\AppConstants;
use Symfony\Contracts\Cache\TagAwareCacheInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
class RequestController extends AbstractController
{
protected RequestBridgeService $requestBridgeService;
protected LoggerInterface $logger;
protected MessageBusInterface $bus;
protected SignalManager $signalManager;
protected NormalizerInterface $normalizer;
protected OrganizationManagerInterface $organizationManager;
protected TagAwareCacheInterface $portailCachePool;
public function __construct(
RequestBridgeService $requestBridgeService,
LoggerInterface $logger,
MessageBusInterface $bus,
SignalManager $signalManager,
NormalizerInterface $normalizer,
OrganizationManagerInterface $organizationManager,
TagAwareCacheInterface $portailCachePool
) {
$this->requestBridgeService = $requestBridgeService;
$this->logger = $logger;
$this->bus = $bus;
$this->signalManager = $signalManager;
$this->normalizer = $normalizer;
$this->organizationManager = $organizationManager;
$this->portailCachePool = $portailCachePool;
}
/**
* @Route("/api/request", name="get_filtered_requests_visible_user", methods={"GET"})
*
* @SWG\Get(summary="Gets all filtered requests visible to user")
*
* @SWG\Parameter(
* in="query",
* name="currentPage",
* description="Index of requested Fpage",
* type="string"
* )
* @SWG\Parameter(
* in="query",
* name="itemsPerPage",
* description="Items per page",
* type="string"
* )
* @SWG\Parameter(
* in="query",
* name="query",
* description="Search by keyword",
* type="string"
* )
* @SWG\Parameter(
* in="query",
* name="incrementalId",
* description="Incremental ID",
* type="integer"
* )
* @SWG\Parameter(
* in="query",
* name="dateCreationMin",
* description="Creation date min (YYYY-MM-DD)",
* type="string",
* format="date"
* )
* @SWG\Parameter(
* in="query",
* name="dateCreationMax",
* description="Creation date max (YYYY-MM-DD)",
* type="string",
* format="date"
* )
* @SWG\Parameter(
* name="sortField",
* description="Field to use for sorting",
* in="query",
* type="string"
* )
* @SWG\Parameter(
* name="sortDirection",
* description="Sort direction (asc, desc)",
* in="query",
* type="array",
* @SWG\Items(
* type="string",
* enum={"asc", "desc"},
* default="desc"
* )
* )
* @SWG\Parameter(
* name="format",
* description="Response format (json: fetch; csv: download)",
* in="query",
* type="array",
* @SWG\Items(
* type="string",
* enum={"json", "csv"},
* default="json"
* )
* )
* @SWG\Response(
* response=200,
* description="Everything is OK."
* )
* @SWG\Response(
* response=500,
* description="Everything is on fire."
* )
*
* @SWG\Tag(name="Request")
*
* @param Request $request
*
* @return JsonResponse
* @throws TransportExceptionInterface
*/
public function getAll(Request $request): Response
{
if ($request->query->get('format') === 'csv') {
// Traitement asynchrone avec envoie du rapport par email
$exportMessage = new ExportMessage(
$this->getUser(),
$request->query->all(),
$request->headers->all(),
$request->request->all(),
$request->attributes->all(),
$request->cookies->all(),
$request->files->all(),
$request->server->all(),
$request->getContent()
);
$this->bus->dispatch($exportMessage);
return new JsonResponse(['status' => 'OK'], Response::HTTP_OK);
}
$stream = $this->requestBridgeService->getRequests($request, $this->getUser());
$streamedResponse = new StreamedResponse();
$streamedResponse->headers->set('X-Accel-Buffering', 'no');
// The key method of a StreamResponse allow to get the Response object
// We need the Response to get the headers and status code to add them on StreamResponse
$response = $stream->key();
$streamedResponse->setStatusCode($response->getStatusCode());
foreach ($response->getHeaders(false) as $name => $values) {
$streamedResponse->headers->set($name, $values);
}
$streamedResponse->setCallback(function() use ($stream) {
foreach ($stream as $chunk) {
echo $chunk->getContent();
flush();
}
});
return $streamedResponse;
}
/**
* @Route("/api/request/{requestId}", methods={"GET"}, name="get_request")
* @SWG\Get(summary="Gets details for one request")
* @SWG\Parameter(
* name="id",
* description="Request id",
* in="query",
* type="string",
* required=true
* )
* @SWG\Response(
* response=200,
* description="Everything is OK."
* )
* @SWG\Response(
* response=403,
* description="Access denied. You do not have permission to view this request."
* )
* @SWG\Response(
* response=404,
* description="Request not found."
* )
* @SWG\Tag(name="Request")
*
* @param Request $request
* @param string $requestId
* @return JsonResponse
*/
public function getOne(Request $request, string $requestId): JsonResponse
{
$request = $this->requestBridgeService->getRequest($requestId, $this->getUser());
return new JsonResponse(json_decode($request, true), Response::HTTP_OK);
}
/**
* @Route("/api/request/{id}/status", methods={"POST"}, name="post_request_status")
* @SWG\Post(
* path="/api/request/{id}/status",
* summary="Update request status"
* )
* @SWG\Parameter(
* name="id",
* in="path",
* type="string",
* description="Request id to update",
* @SWG\Schema(
* type="string",
* required={"id"}
* )
* )
* @SWG\Parameter(
* name="body",
* in="body",
* description="update status",
* @SWG\Schema(
* @SWG\Property(property="status", type="string"),
* @SWG\Property(property="comment", type="string"),
* )
* )
* @SWG\Response(
* response=201,
* description="status updated."
* ),
* @SWG\Response(
* response=400,
* description="Form is invalid."
* )
*
* @SWG\Tag(name="Request")
*/
public function updateRequestStatus(Request $request): JsonResponse
{
$requests = $this->requestBridgeService->updateRequestStatusAndCloseSignal(
$request->attributes->get('id'),
json_decode($request->getContent(), true)
);
$jsonResponse = new JsonResponse($requests['content']);
$jsonResponse->headers->add($requests['headers']);
return $jsonResponse;
}
/**
* Get stats for request.
*
* @Route("/api/widget/request/stats", name="get_request_stats", methods={"GET"})
*
* @SWG\Get (
* path="/api/widget/request/stats",
* tags={"Request"},
* summary="Get statistics for request",
* @SWG\Response(
* response="200",
* description="stats"
* )
* )
*/
public function getStats(Request $request): JsonResponse
{
$requests = $this->requestBridgeService->getStats($request, $this->getUser());
$jsonResponse = new JsonResponse($requests['content'], Response::HTTP_OK);
$jsonResponse->headers->add($requests['headers']);
return $jsonResponse;
}
/**
* Get all status available for user.
*
* @Route("/api/contract/{contractId}/request/getAllStatus", name="get_all_status", methods={"GET"})
*
* @SWG\Get (
* path="/api/contract/{contractId}/request/getAllStatus",
* tags={"Request"},
* summary="Get status for connected user",
* @SWG\Response(
* response="200",
* description="status"
* )
* )
*/
public function getAllStatusByContract($contractId): JsonResponse
{
$cacheKey = hash( 'sha256', 'request_contract_status'.$contractId);
$cachedItem = $this->portailCachePool->getItem($cacheKey);
if (!$cachedItem->isHit()) {
//get list of organizations for a given contract
list($organizations, $pagination) = $this->organizationManager->getByContract(
$contractId,
[
AppConstants::DEFAULT_ALL_ITEMS_PER_PAGE,
AppConstants::DEFAULT_CURRENT_PAGE,
]
);
//get all request types for each organization
$requestTypes = [];
foreach ($organizations as $organization) {
$organizationRt = $this->organizationManager->getOrganizationsRequestType($organization->getId());
$jsonContent = $organizationRt->getContent();
$decodedContent = json_decode($jsonContent, true);
foreach ($decodedContent as $requestType) {
$requestTypes[$requestType['id']] = $requestType;
}
$cachedItem->tag([$organization->getId()]);
}
//get all status for each request type
$allStatus = [];
foreach ($requestTypes as $requestType) {
$statuses = $this->requestBridgeService->getRequestTypeStatus($requestType['id']);
$decodedStatuses = json_decode($statuses['content'], true);
foreach ($decodedStatuses as $status) {
$allStatus[$status['id']] = $status;
}
}
$cachedItem->set($allStatus);
$cachedItem->tag([$contractId]);
$this->portailCachePool->save($cachedItem);
}
$allStatus = $cachedItem->get();
return new JsonResponse($this->normalizer->normalize($allStatus, 'json'), Response::HTTP_OK);
}
/**
* Return request values for specific field.
*
* @Route("/api/request/fields/{field}", name="get_possible_values_for_field", methods={"GET"})
*
* @SWG\Get(summary="Return request values for specific field.")
*
* @SWG\Parameter(
* name="field",
* in="path",
* description="field name",
* required=true,
* type="string"
* )
*
* @SWG\Response(
* response=200,
* description="successful operation"
* )
*
* @SWG\Tag(name="Request")
*
*
* @param string $field
* @return Response
*/
public function getPossibleValuesAction(string $field): Response
{
$values = $this->requestBridgeService->findPossibleValuesByField($field, $this->getUser());
$response = new Response($values['content'], Response::HTTP_OK);
$response->headers->add($values['headers']);
return $response;
}
/**
* @Route("/api/mapping/{signalId}/request", methods={"POST"})
*
* @SWG\Parameter(
* name="body",
* in="body",
* @Model(type=PceRequest::class)
* )
* @SWG\Response(
* response=403,
* description="Access Denied.."
* )
* @SWG\Response(
* response=200,
* description="Everything is OK."
* )
* @SWG\Response(
* response=500,
* description="Everything is on fire."
* )
*
* @SWG\Tag(name="Request")
*/
public function mapRequest(Request $request, string $signalId, RequestConverter $requestConverter): Response
{
$data = $request->getContent();
$pceRequest = json_decode($data, true);
if (! $pceRequest) {
$errorMessages = sprintf("Impossible to decode the request body sent with value '%s'", $data);
$this->logger->error(
$errorMessages
);
return $this->json(
$errorMessages,
Response::HTTP_BAD_REQUEST
);
}
$signal = $this->signalManager->getSignalById($signalId);
// ADD new request with signal Parameters
$pceRequest = $requestConverter->convertSignalToPceRequest($pceRequest, $signal);
try {
$newRequestDatas = $this->requestBridgeService->postRequest($pceRequest);
} catch (CreateRequestException $e) {
return new Response(
$e->getMessage(),
Response::HTTP_BAD_REQUEST
);
}
$newRequestId = $newRequestDatas["content"]["id"];
try {
$this->requestBridgeService->postRequestRelation($signalId, $newRequestId, $pceRequest);
} catch (RequestRelationException $e) {
return new Response(
$e->getMessage(),
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
$this->requestBridgeService->duplicateAttachmentsFromSignalToRequest($signal, $newRequestId);
// Remove attachments from signal
$signal['attachments'] = [];
$signal['hasAttachments'] = false;
$signal['currentStatus']['comment'] = null;
$this->signalManager->updateSignal($signal);
$this->signalManager->updateSignalStatus($signalId, SignalStatus::APPROVED);
// return new request Id
return $this->json(
['id' => $newRequestId],
Response::HTTP_CREATED,
[
"location" => "/api/request/" . $newRequestId,
]
);
}
}