feat: authenticated booking
This commit is contained in:
@@ -32,11 +32,12 @@ class IndexController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a fresh booking session and redirects to step 1.
|
||||
* Initializes a fresh booking session and redirects to the login page.
|
||||
*
|
||||
* This endpoint provides a clean way to start the booking flow with just
|
||||
* dateId and hotelId parameters. It clears any existing booking session
|
||||
* and creates a fresh BookingCreateDto before redirecting to step 1.
|
||||
* dateId and hotelId parameters. It clears any existing booking session,
|
||||
* creates a fresh BookingDto, and redirects to the login page where users
|
||||
* can authenticate (for prepopulation) or continue as guest.
|
||||
*
|
||||
* Optionally accepts an agency code parameter. If provided and valid, the
|
||||
* corresponding agency ID is stored in the booking. If not provided or invalid,
|
||||
@@ -59,17 +60,17 @@ class IndexController extends AbstractController
|
||||
// Create fresh booking session with the provided parameters
|
||||
$this->bookingService->startFreshBooking($request, $dateId, $hotelId, $agencyId);
|
||||
|
||||
// Redirect to step 1 of the booking flow
|
||||
return $this->redirectToRoute('app_booking_create_step_1');
|
||||
} catch (TravelNotFoundException $e) {
|
||||
// Redirect to login page (optional authentication before Step 1)
|
||||
return $this->redirectToRoute('app_login');
|
||||
} catch (TravelNotFoundException) {
|
||||
throw $this->createNotFoundException(sprintf('Travel not found for date ID %d', $dateId));
|
||||
} catch (HotelNotFoundException $e) {
|
||||
} catch (HotelNotFoundException) {
|
||||
throw $this->createNotFoundException(sprintf('Hotel not found for hotel ID %d', $hotelId));
|
||||
} catch (HotelNotInTravelException $e) {
|
||||
} catch (HotelNotInTravelException) {
|
||||
throw $this->createNotFoundException(sprintf('Hotel ID %d is not available for travel ID %d', $hotelId, $dateId));
|
||||
} catch (NoRoomsAvailableException $e) {
|
||||
} catch (NoRoomsAvailableException) {
|
||||
throw $this->createNotFoundException('No rooms available for this travel.');
|
||||
} catch (BookingNotPossibleException $e) {
|
||||
} catch (BookingNotPossibleException) {
|
||||
throw $this->createNotFoundException('Booking is not possible for this travel (Buchungsstop).');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ use App\Htmx\HxTrait;
|
||||
use App\Service\BookingPriceCalculatorService;
|
||||
use App\Service\BookingService;
|
||||
use App\Service\ParticipantCardDataService;
|
||||
use App\Service\ParticipantPrepopulationService;
|
||||
use App\Service\RoomAssignmentService;
|
||||
use App\Service\TravelDataService;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
@@ -42,6 +43,7 @@ class Step2Controller extends AbstractController
|
||||
private readonly RoomAssignmentService $roomAssignmentService,
|
||||
private readonly ParticipantCardDataService $participantCardService,
|
||||
private readonly ParticipantFieldOptionsProvider $fieldOptionsProvider,
|
||||
private readonly ParticipantPrepopulationService $prepopulationService,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -227,10 +229,29 @@ class Step2Controller extends AbstractController
|
||||
for ($i = 0; $i < $participantsCount; ++$i) {
|
||||
$participant = $participants[$i] ?? new ParticipantDto();
|
||||
$participant->index = $i;
|
||||
|
||||
// Prepopulate applicant from authenticated user (index 0 only)
|
||||
if (0 === $i && $this->getUser() && $this->shouldPrepopulate($participant)) {
|
||||
$participant = $this->prepopulationService->prepopulateApplicantFromUser(
|
||||
$this->getUser(),
|
||||
$participant
|
||||
);
|
||||
}
|
||||
|
||||
$bookingCreateDto->participants[$i] = $participant;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a participant should be prepopulated.
|
||||
*
|
||||
* Only prepopulates if the participant is "fresh" (no name set yet).
|
||||
*/
|
||||
private function shouldPrepopulate(ParticipantDto $participant): bool
|
||||
{
|
||||
return null === $participant->firstName || '' === $participant->firstName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enriches travel data with cached availability information from BusProNet API.
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Service\BookingService;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -13,8 +14,17 @@ class SecurityController extends AbstractController
|
||||
{
|
||||
#[Route('/', name: 'app_login')]
|
||||
#[IsGranted('PUBLIC_ACCESS')]
|
||||
public function login(AuthenticationUtils $authenticationUtils, Request $request): Response
|
||||
public function login(AuthenticationUtils $authenticationUtils, Request $request, BookingService $bookingService): Response
|
||||
{
|
||||
// Check if this is a booking flow (BookingDto exists in session)
|
||||
$isBookingFlow = null !== $bookingService->getBookingDto($request, BookingService::BOOKING_CREATE_KEY);
|
||||
|
||||
// If authenticated and in booking flow, proceed to Step 1
|
||||
if (null !== $this->getUser() && true === $isBookingFlow) {
|
||||
return $this->redirectToRoute('app_booking_create_step_1');
|
||||
}
|
||||
|
||||
// If authenticated but not in booking flow, go to personal data
|
||||
if (null !== $this->getUser()) {
|
||||
return $this->redirectToRoute('app_personal_data');
|
||||
}
|
||||
@@ -31,7 +41,15 @@ class SecurityController extends AbstractController
|
||||
$session->set('_oauth2', true);
|
||||
}
|
||||
|
||||
return $this->render('security/login.html.twig', [
|
||||
// For booking flow, set target path to Step 1 (after successful auth, redirect there)
|
||||
if (true === $isBookingFlow) {
|
||||
$session->set('_security.main.target_path', $this->generateUrl('app_booking_create_step_1'));
|
||||
}
|
||||
|
||||
// Render booking login template if in booking flow, otherwise standard login
|
||||
$template = true === $isBookingFlow ? 'booking/create/authenticate.html.twig' : 'security/login.html.twig';
|
||||
|
||||
return $this->render($template, [
|
||||
'last_username' => $lastUsername,
|
||||
'error' => $error,
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user