feat: api endpoints for pickups planning
This commit is contained in:
@@ -59,6 +59,7 @@ APP_TRAVEL_ENABLE_FALLBACK=true
|
|||||||
API_KEYS=
|
API_KEYS=
|
||||||
|
|
||||||
XML_EXPORT_PATH="%kernel.project_dir%/var/xmlexport"
|
XML_EXPORT_PATH="%kernel.project_dir%/var/xmlexport"
|
||||||
|
JSON_EXPORT_PATH="%kernel.project_dir%/var/jsonexport"
|
||||||
|
|
||||||
SFTP_XML_EXPORT_HOST=
|
SFTP_XML_EXPORT_HOST=
|
||||||
SFTP_XML_EXPORT_PORT=
|
SFTP_XML_EXPORT_PORT=
|
||||||
|
|||||||
@@ -84,3 +84,17 @@ Authorization: Bearer {{$auth.token("oauth2_api")}}
|
|||||||
"email": "[email protected]",
|
"email": "[email protected]",
|
||||||
"phone": "12345"
|
"phone": "12345"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
### API pickups planning webhook
|
||||||
|
POST {{base_url}}/api/pickups-planning
|
||||||
|
Accept: application/json
|
||||||
|
Content-Type: application/json
|
||||||
|
Authorization: Bearer {{$auth.token("oauth2_api")}}
|
||||||
|
|
||||||
|
< ./assets/json/zustiegplanung.json
|
||||||
|
|
||||||
|
### API pickups planning
|
||||||
|
GET {{base_url}}/api/pickups-planning/DPWWTS191125
|
||||||
|
Accept: application/json
|
||||||
|
Content-Type: application/json
|
||||||
|
Authorization: Bearer {{$auth.token("oauth2_api")}}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -8,6 +8,10 @@ flysystem:
|
|||||||
adapter: 'local'
|
adapter: 'local'
|
||||||
options:
|
options:
|
||||||
directory: '%kernel.project_dir%/var/bpn'
|
directory: '%kernel.project_dir%/var/bpn'
|
||||||
|
json_export.storage:
|
||||||
|
adapter: 'local'
|
||||||
|
options:
|
||||||
|
directory: '%env(resolve:JSON_EXPORT_PATH)%'
|
||||||
# adapter: 'sftp'
|
# adapter: 'sftp'
|
||||||
# options:
|
# options:
|
||||||
# host: '%env(SFTP_XML_EXPORT_HOST)%'
|
# host: '%env(SFTP_XML_EXPORT_HOST)%'
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ services:
|
|||||||
bind:
|
bind:
|
||||||
$xmlExport: '@xml_export.storage'
|
$xmlExport: '@xml_export.storage'
|
||||||
$xmlDump: '@xml_dump.storage'
|
$xmlDump: '@xml_dump.storage'
|
||||||
|
$jsonExport: '@json_export.storage'
|
||||||
$travelInfoBaseUrl: '%env(APP_TRAVEL_INFO_BASE_URL)%'
|
$travelInfoBaseUrl: '%env(APP_TRAVEL_INFO_BASE_URL)%'
|
||||||
$logger: '@monolog.logger.core'
|
$logger: '@monolog.logger.core'
|
||||||
$environment: '%kernel.environment%'
|
$environment: '%kernel.environment%'
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ add('shared_dirs', [
|
|||||||
'var/bpn',
|
'var/bpn',
|
||||||
'var/log',
|
'var/log',
|
||||||
'var/sessions',
|
'var/sessions',
|
||||||
|
'var/jsonexport',
|
||||||
'var/xmlexport',
|
'var/xmlexport',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\BusProNet\DataProcessor;
|
||||||
|
|
||||||
|
class PickupPlanningTransformer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param array<int, array<string, mixed>> $payload
|
||||||
|
*
|
||||||
|
* @return array<string, array<int, array<string, string>>>
|
||||||
|
*/
|
||||||
|
public function transform(array $payload): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($payload as $item) {
|
||||||
|
if ('HIN' !== ($item['PlanungsArt'] ?? null)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$travelCode = $item['Reisecode'] ?? null;
|
||||||
|
if (null === $travelCode) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dateTime = \DateTimeImmutable::createFromFormat('d.m.Y H:i', $item['Zeit'] ?? '');
|
||||||
|
|
||||||
|
$result[$travelCode][] = [
|
||||||
|
'city' => $item['Zustieg/Ausstieg Ort'] ?? '',
|
||||||
|
'location' => $item['Zustieg/Ausstieg Strasse'] ?? '',
|
||||||
|
'datetime' => false !== $dateTime ? $dateTime->format('Y-m-d H:i') : '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($result as $travelCode => $pickups) {
|
||||||
|
usort($pickups, static fn (array $a, array $b): int => $a['datetime'] <=> $b['datetime']);
|
||||||
|
$result[$travelCode] = $pickups;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,9 +2,13 @@
|
|||||||
|
|
||||||
namespace App\Controller\Api;
|
namespace App\Controller\Api;
|
||||||
|
|
||||||
|
use App\BusProNet\DataProcessor\PickupPlanningTransformer;
|
||||||
use App\BusProNet\XmlLoader\PickupLoader;
|
use App\BusProNet\XmlLoader\PickupLoader;
|
||||||
|
use League\Flysystem\FilesystemException;
|
||||||
|
use League\Flysystem\FilesystemOperator;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
@@ -13,8 +17,13 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
|||||||
#[IsGranted('ROLE_OAUTH2_API')]
|
#[IsGranted('ROLE_OAUTH2_API')]
|
||||||
class PickupController extends AbstractController
|
class PickupController extends AbstractController
|
||||||
{
|
{
|
||||||
public function __construct(private readonly PickupLoader $xmlLoader)
|
private const PLANNING_FILE = 'pickup_planning.json';
|
||||||
{
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly PickupLoader $xmlLoader,
|
||||||
|
private readonly PickupPlanningTransformer $planningTransformer,
|
||||||
|
private readonly FilesystemOperator $jsonExport,
|
||||||
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/pickups', name: 'api_pickups_all')]
|
#[Route('/pickups', name: 'api_pickups_all')]
|
||||||
@@ -32,4 +41,44 @@ class PickupController extends AbstractController
|
|||||||
|
|
||||||
return $this->json($pickup, Response::HTTP_OK, [], ['groups' => 'api:list']);
|
return $this->json($pickup, Response::HTTP_OK, [], ['groups' => 'api:list']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('/pickups-planning/{travelCode}', name: 'api_pickups_planning_single', methods: ['GET'])]
|
||||||
|
public function planningByTravelCode(string $travelCode): JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (false === $this->jsonExport->fileExists(self::PLANNING_FILE)) {
|
||||||
|
return $this->json(['error' => 'Planning data not available'], Response::HTTP_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
$planning = json_decode($this->jsonExport->read(self::PLANNING_FILE), true, 512, \JSON_THROW_ON_ERROR);
|
||||||
|
} catch (FilesystemException|\JsonException) {
|
||||||
|
return $this->json(['error' => 'Failed to read planning data'], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === \array_key_exists($travelCode, $planning)) {
|
||||||
|
return $this->json(['error' => 'Travel code not found'], Response::HTTP_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json($planning[$travelCode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/pickups-planning', name: 'api_pickups_planning', methods: ['POST'])]
|
||||||
|
public function planning(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$payload = $request->toArray();
|
||||||
|
} catch (\JsonException) {
|
||||||
|
return $this->json(['error' => 'Invalid JSON payload'], Response::HTTP_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
$transformed = $this->planningTransformer->transform($payload);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->jsonExport->write(self::PLANNING_FILE, json_encode($transformed, \JSON_THROW_ON_ERROR));
|
||||||
|
} catch (FilesystemException|\JsonException) {
|
||||||
|
return $this->json(['error' => 'Failed to write planning data'], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json(['status' => 'ok']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user