<?php
namespace App\Controller;
use App\Constants\AppConstants;
use App\DataTransformer\Heimdall\AreaOutputDataTransformer;
use App\Exception\Heimdall\ContractNotFoundException;
use App\Exception\Import\GeoJsonImportException;
use App\Manager\Admin\AdminImportManagerInterface;
use App\Manager\Admin\AdminManagerInterface;
use App\Manager\AreaManagerInterface;
use App\Manager\OrganizationManagerInterface;
use App\Manager\UserManagerInterface;
use App\Manager\HeimdallManagerInterface;
use App\Models\Heimdall\Portal;
use App\Models\Heimdall\Profile;
use Psr\EventDispatcher\EventDispatcherInterface;
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\Exception\ExceptionInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use App\Repository\HeimdallRepository;
use App\Models\Heimdall\Contract as HeimdallContract;
/**
* @SWG\Tag(name="Area")
*/
class AreaController extends AbstractController
{
protected AreaManagerInterface $areaManager;
protected EventDispatcherInterface $eventDispatcher;
protected OrganizationManagerInterface $organizationManager;
protected HeimdallRepository $repository;
protected HeimdallManagerInterface $heimdallManager;
public const HEIMDALL_CONTRACT_URL = '/api/contract/%s';
/**
* @param AreaManagerInterface $areaManager
* @param EventDispatcherInterface $eventDispatcher
* @param OrganizationManagerInterface $organizationManager
* @param HeimdallRepository $repository
*/
public function __construct(
AreaManagerInterface $areaManager,
EventDispatcherInterface $eventDispatcher,
OrganizationManagerInterface $organizationManager,
HeimdallRepository $repository,
HeimdallManagerInterface $heimdallManager
)
{
$this->areaManager = $areaManager;
$this->eventDispatcher = $eventDispatcher;
$this->organizationManager = $organizationManager;
$this->repository = $repository;
$this->heimdallManager = $heimdallManager;
}
/**
* @Route(
* "/api/contract/{contractId}/areas",
* name="get_contract_areas",
* methods={"GET"}
* )
*
* @SWG\Get(
* path="/api/contract/{contractId}/areas",
* summary="Get contract areas",
* tags={"Area"},
*
* @SWG\Parameter(
* name="contractId",
* in="path",
* required=true,
* type="string",
* description="Contract ID"
* ),
* @SWG\Parameter(
* name="withGeoJson",
* in="query",
* description="If true, returns a GeoJSON FeatureCollection",
* required=false,
* default=false,
* type="boolean"
* ),
* @SWG\Parameter(
* name="currentPage",
* in="query",
* description="current page for pagination offset",
* required=false,
* default=1,
* type="number"
* ),
* @SWG\Parameter(
* name="itemsPerPage",
* in="query",
* description="Nb items per page for pagination",
* required=false,
* default=20,
* type="number"
* ),
* @SWG\Parameter(
* name="labelFilter",
* in="query",
* description="Filter on area label name",
* required=false,
* type="string"
* ),
* @SWG\Response(
* response=200,
* description="Everything is OK."
* ),
* @SWG\Response(
* response=500,
* description="Error."
* )
* )
*
* @throws ExceptionInterface
*/
public function getClientAreas(Request $request, AdminManagerInterface $adminManager, string $contractId, NormalizerInterface $normalizer): JsonResponse
{
$this->denyAccessUnlessGranted(Profile::PROFILE_SUPER_ADMIN, $contractId);
$currentPage = $request->get('currentPage', 1);
$itemsPerPage = $request->get('itemsPerPage', 20);
$labelFilter = $request->get('labelFilter');
$withGeoJson = $request->query->getBoolean('withGeoJson', false);
$transformer = new AreaOutputDataTransformer();
if ($withGeoJson) {
$urlHeimdall = sprintf(static::HEIMDALL_CONTRACT_URL, $contractId);
$heimdallContract = $this->repository->getEntity($urlHeimdall, HeimdallContract::class);
$organizations = $this->heimdallManager->getOrganizationsByContract($heimdallContract);
$featureCollection = $this->areaManager->getOrganizationsAreasGeoJson($organizations, true);
return new JsonResponse($normalizer->normalize($featureCollection), Response::HTTP_OK);
}
list($areas, $pagination) = $adminManager->getClientAreas($contractId, $currentPage, $itemsPerPage, $labelFilter);
$areas = array_map(
function ($area) use ($transformer) {
return $transformer->transform($area);
},
$areas
);
return new JsonResponse($normalizer->normalize($areas), Response::HTTP_OK, $pagination);
}
/**
* @Route("/api/contract/{contractId}/area/{areaId}", name="get_contract_area", methods={"Get"})
*
* @SWG\Get (
* path="/api/contract/{contractId}/area/{areaId}",
* summary="Get contract area by id",
* tags={"Area"},
* @SWG\Response(
* response=200,
* description="Everything is OK."
* ),
* @SWG\Response(
* response=500,
* description="Error."
* )
* )
*
* @throws ExceptionInterface
*/
public function getContractArea(AreaManagerInterface $areaManager, NormalizerInterface $normalizer, string $contractId, string $areaId): JsonResponse
{
$this->denyAccessUnlessGranted(Profile::PROFILE_SUPER_ADMIN, $contractId);
$contract = $areaManager->getArea($areaId);
return new JsonResponse($normalizer->normalize($contract, 'json', ['groups' => 'front']));
}
/**
* @Route("/api/contract/{contractId}/areas/skillset", name="get_areas_skillsets", methods={"Get"})
*
* @SWG\Get (
* path="/api/contract/{contractId}/areas/skillset",
* summary="Get area skillset for multiple areas",
* tags={"Area"},
* @SWG\Parameter(
* name="countOnly",
* in="query",
* description="if true, will return only the number of skillsets for each Area instead of the full list.",
* type="boolean"
* ),
* @SWG\Parameter(
* name="areas[]",
* in="query",
* description="list of all the areas id we want SkillSets for",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi"
* ),
* @SWG\Response(
* response=200,
* description="Everything is OK."
* ),
* @SWG\Response(
* response=500,
* description="Error."
* )
* )
*/
public function getAreasSkillSets(Request $request, AreaManagerInterface $areaManager, string $contractId): JsonResponse
{
$this->denyAccessUnlessGranted(Profile::PROFILE_SUPER_ADMIN, $contractId);
$areas = $request->get('areas', []);
$countOnly = filter_var($request->get('countOnly', false), FILTER_VALIDATE_BOOLEAN);
$categories = $areaManager->getAreasCategories($areas, $countOnly);
return new JsonResponse($categories);
}
/**
* @Route("/api/contract/{contractId}/areas/organization", name="get_areas_organizations", methods={"Get"})
*
* @SWG\Get (
* path="/api/contract/{contractId}/areas/organization",
* summary="Get area organizations for multiple areas",
* tags={"Area"},
* @SWG\Parameter(
* name="countOnly",
* in="query",
* description="if true, will return only the number of organizations for each Area instead of the full list.",
* type="boolean"
* ),
* @SWG\Parameter(
* name="areas[]",
* in="query",
* description="list of all the areas id we want Organizations for",
* type="array",
* @SWG\Items(type="string"),
* collectionFormat="multi"
* ),
* @SWG\Parameter(
* name="organizationType",
* in="query",
* description="Filter by organization type",
* required=false,
* type="string",
* enum={"Community", "ExternalEntity", "Operator"}
* ),
* @SWG\Response(
* response=200,
* description="Everything is OK."
* ),
* @SWG\Response(
* response=500,
* description="Error."
* )
* )
*/
public function getAreasOrganizations(Request $request, AreaManagerInterface $areaManager, string $contractId): JsonResponse
{
$this->denyAccessUnlessGranted(Profile::PROFILE_SUPER_ADMIN, $contractId);
$areas = $request->get('areas', []);
$organizationType = $request->get('organizationType');
$countOnly = filter_var($request->get('countOnly', false), FILTER_VALIDATE_BOOLEAN);
$organizations = $areaManager->getAreasOrganizations($areas, $organizationType, $countOnly);
return new JsonResponse($organizations);
}
/**
* @Route("/api/contract/{contractId}/contractArea", name="create_contract_area_from_administrative_divisions", methods={"POST"})
*
* @SWG\Post (
* path="/api/contract/{contractId}/contractArea",
* tags={"Area"},
* summary="Create multiple areas on mdm and heimdall + contractAreas on Heimdall based on a list of administratives divisions",
* @SWG\Parameter(
* name="administrativeDivisions",
* in="body",
* @SWG\Schema(
* type="array",
* @SWG\Items(type="string")
* )
* ),
* @SWG\Response(
* response=200,
* description="location in the header"
* )
* )
*/
public function createAreasFromAdministrativeDivision(
Request $request,
AdminManagerInterface $adminManager,
string $contractId
): JsonResponse {
$this->denyAccessUnlessGranted(Profile::PROFILE_SUPER_ADMIN, Portal::PORTAL_VILLAGILE);
$administrativeDivisions = json_decode($request->getContent());
$adminManager->createAreaFromAdministrativeDivisions($contractId, $administrativeDivisions);
return new JsonResponse(null, Response::HTTP_OK);
}
/**
* @Route("/api/contract/{contractId}/contractArea/import", name="create_contract_area_from_geojson", methods={"POST"})
*
* @SWG\Post (
* path="/api/contract/{contractId}/contractArea/import",
* tags={"Area"},
* summary="Create multiple areas on mdm and heimdall + contractAreas on Heimdall based on a GeoJSON file upload",
* @SWG\Parameter(
* name="file",
* in="formData",
* type="file",
* description="GeoJSON file",
* required=true
* ),
* @SWG\Parameter(
* name="areasPropertiesName",
* in="formData",
* type="string",
* description="Name of attribute in GeoJSON properties to use as Area name",
* required=true
* ),
* @SWG\Parameter(
* name="postalCodePropertiesName",
* in="formData",
* type="string",
* description="Name of attribute in GeoJSON properties to use as Postal Code value",
* required=false
* ),
* @SWG\Response(
* response=200,
* description="location in the header"
* )
* )
*/
public function createAreasFromGeoJsonFile(
Request $request,
AdminImportManagerInterface $adminImportManager,
string $contractId
): JsonResponse {
$this->denyAccessUnlessGranted(Profile::PROFILE_SUPER_ADMIN, Portal::PORTAL_VILLAGILE);
$file = $request->files->get('file');
if (!$file) {
return new JsonResponse(['error' => 'No file provided'], Response::HTTP_BAD_REQUEST);
}
$areasPropertiesName = $request->request->get('areasPropertiesName');
if (!$areasPropertiesName) {
return new JsonResponse(['error' => 'No areasPropertiesName provided'], Response::HTTP_BAD_REQUEST);
}
$postalCodePropertiesName = $request->request->get('postalCodePropertiesName');
try {
$adminImportManager->importGeoJsonFile($contractId, $file->getPathname(), $areasPropertiesName, $postalCodePropertiesName);
} catch (ContractNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (GeoJsonImportException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_BAD_REQUEST);
} catch (\Exception $e) {
return new JsonResponse(['error' => 'An unexpected error occurred'], Response::HTTP_INTERNAL_SERVER_ERROR);
}
return new JsonResponse("Success created", Response::HTTP_CREATED);
}
/**
* @Route("/api/organization/{organizationId}/area", name="get_organization_areas", methods={"Get"})
*
* @SWG\Get (
* path="/api/organization/{organizationId}/area",
* summary="Get organization areas",
* tags={"Area"},
* @SWG\Parameter(
* name="currentPage",
* in="query",
* description="current page for pagination offset",
* required=false,
* default=1,
* type="number"
* ),
* @SWG\Parameter(
* name="itemsPerPage",
* in="query",
* description="Nb items per page for pagination",
* required=false,
* default=20,
* type="number"
* ),
* @SWG\Response(
* response=200,
* description="Everything is OK."
* ),
* @SWG\Response(
* response=500,
* description="Error."
* )
* )
*
* @throws ExceptionInterface
*/
public function getAreasByOrganization(Request $request, AreaManagerInterface $areaManager, string $organizationId, NormalizerInterface $normalizer): JsonResponse
{
$this->denyAccessUnlessGranted(Profile::PROFILE_SUPER_ADMIN, $organizationId);
$currentPage = $request->get('currentPage', 1);
$itemsPerPage = $request->get('itemsPerPage', 20);
list($areas, $pagination) = $areaManager->getOrganizationAreas($organizationId, $currentPage, $itemsPerPage);
return new JsonResponse(
$normalizer->normalize($areas, 'json', ['groups' => 'front']),
Response::HTTP_OK,
$pagination
);
}
/**
* @Route("/api/user/{userId}/area", name="get_user_areas", methods={"Get"})
*
* @SWG\Get (
* path="/api/user/{userId}/area",
* summary="Get areas of all user Organizations",
* tags={"Area"},
* @SWG\Response(
* response=200,
* description="Everything is OK."
* ),
* @SWG\Response(
* response=500,
* description="Error."
* )
* )
*
* @throws ExceptionInterface
*/
public function getUserAreas(AreaManagerInterface $areaManager, string $userId, NormalizerInterface $normalizer): JsonResponse
{
$areas = $areaManager->getUserAreas($userId);
return new JsonResponse($normalizer->normalize($areas, 'json', ['groups' => 'front']), Response::HTTP_OK);
}
/**
* @Route("/api/user/{userId}/contract/{contractId}/area", name="get_user_areas_by_contract", methods={"Get"})
*
* @SWG\Get (
* path="/api/user/{userId}/contract/{contractId}/area",
* summary="Get areas of all user Organizations by contract",
* tags={"Area"},
* @SWG\Response(
* response=200,
* description="Everything is OK."
* ),
* @SWG\Response(
* response=500,
* description="Error."
* )
* )
*
* @throws ExceptionInterface
*/
public function getUserAreasByContract(string $userId, string $contractId, NormalizerInterface $normalizer): JsonResponse
{
$userOrganizations = $this->organizationManager->getUsersOrganizationsByContract($contractId, $userId);
$areas = [];
foreach ($userOrganizations as $organizationId) {
list($organizationAreas, $pagination) = $this->areaManager->getOrganizationAreas($organizationId, AppConstants::DEFAULT_CURRENT_PAGE, AppConstants::DEFAULT_ALL_ITEMS_PER_PAGE);
$areas = array_merge($areas, $organizationAreas);
}
return new JsonResponse($normalizer->normalize($areas, 'json', ['groups' => 'front']), Response::HTTP_OK);
}
/**
* @Route("/api/user/{userId}/geoshape", name="get_user_geoshapes", methods={"Get"})
*
* @SWG\Get (
* path="/api/user/{userId}/geoshape",
* summary="Get user organizations geoshape",
* tags={"Area"},
* @SWG\Parameter(
* name="serviceCode",
* in="query",
* description="Filter by service activated on Organization",
* type="string"
* ),
* @SWG\Parameter(
* name="contractId",
* in="query",
* description="User contract id",
* type="string"
* ),
* @SWG\Parameter(
* name="merged",
* in="query",
* description="Merge in multipolygon",
* type="boolean"
* ),
* @SWG\Response(
* response=200,
* description="Everything is OK."
* ),
* @SWG\Response(
* response=500,
* description="Error."
* )
* )
*
* @throws ExceptionInterface
*/
public function getUserGeoShapes(
string $userId,
AreaManagerInterface $areaManager,
NormalizerInterface $normalizer,
Request $request,
UserManagerInterface $userManager
): JsonResponse {
$serviceCode = $request->query->get('serviceCode', '');
$merged = $request->query->getBoolean('merged');
$contractId = $request->query->get('contractId');
$user = $userManager->getUser($userId);
$geoShapes = $areaManager->getUserGeoJsonByService($user, [$serviceCode], $contractId);
if ($merged) {
$data = $geoShapes ? json_decode($geoShapes, true): [];
} else {
$data = $normalizer->normalize($geoShapes, 'json', ['groups' => 'front']);
}
return new JsonResponse($data, Response::HTTP_OK);
}
/**
* @Route("/api/contract/{contractId}/area/{areaId}", name="delete_contract_area_id", methods={"DELETE"})
*
* @SWG\Delete (
* path="/api/contract/{contractId}/area/{areaId}",
* summary="delete contract area id",
* tags={"Area"},
* @SWG\Response(
* response=204,
* description="Area is deleted."
* ),
* @SWG\Response(
* response=500,
* description="Error server."
* )
* )
*
* @throws ExceptionInterface
* @return Response
*/
public function deleteArea(Request $request, string $contractId, string $areaId): Response
{
$this->areaManager->deleteArea($areaId);
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
}
}