Skip to content

Commit

Permalink
Revert "Update checkout session handling"
Browse files Browse the repository at this point in the history
  • Loading branch information
daveearley authored Sep 6, 2024
1 parent 0594b96 commit 8647110
Show file tree
Hide file tree
Showing 24 changed files with 543 additions and 616 deletions.
9 changes: 2 additions & 7 deletions backend/app/Http/Actions/Orders/CreateOrderActionPublic.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,22 @@ public function __construct(
public function __invoke(CreateOrderRequest $request, int $eventId): JsonResponse
{
$this->orderCreateRequestValidationService->validateRequestData($eventId, $request->all());
$sessionId = $this->sessionIdentifierService->getSessionId();

$order = $this->orderHandler->handle(
$eventId,
CreateOrderPublicDTO::fromArray([
'is_user_authenticated' => $this->isUserAuthenticated(),
'promo_code' => $request->input('promo_code'),
'tickets' => TicketOrderDetailsDTO::collectionFromArray($request->input('tickets')),
'session_identifier' => $sessionId,
'session_identifier' => $this->sessionIdentifierService->getSessionId(),
'order_locale' => $this->localeService->getLocaleOrDefault($request->getPreferredLanguage()),
])
);

$response = $this->resourceResponse(
return $this->resourceResponse(
resource: OrderResourcePublic::class,
data: $order,
statusCode: ResponseCodes::HTTP_CREATED
);

return $response->withCookie(
cookie: $this->sessionIdentifierService->getSessionCookie(),
);
}
}
3 changes: 1 addition & 2 deletions backend/app/Http/Actions/Orders/GetOrderActionPublic.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use HiEvents\Services\Infrastructure\Session\CheckoutSessionManagementService;
use Illuminate\Http\JsonResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;

class GetOrderActionPublic extends BaseAction
{
Expand Down Expand Up @@ -52,7 +51,7 @@ public function __invoke(int $eventId, string $orderShortId): JsonResponse
->findByShortId($orderShortId);

if (!$order) {
throw new ResourceNotFoundException(__('Order not found'));
throw new NotFoundHttpException();
}

if ($order->getStatus() === OrderStatus::RESERVED->name) {
Expand Down
2 changes: 1 addition & 1 deletion backend/app/Repository/Eloquent/BaseRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public function findFirstByField(
array $columns = ['*']
): ?DomainObjectInterface
{
$model = $this->model->where($field, '=', $value)->first($columns);
$model = $this->model->where($field, '=', $value)->firstOrFail($columns);
$this->resetModel();

return $this->handleSingleResult($model);
Expand Down
22 changes: 13 additions & 9 deletions backend/app/Services/Handlers/Order/CreateOrderHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,20 @@
use HiEvents\Services\Domain\Order\OrderItemProcessingService;
use HiEvents\Services\Domain\Order\OrderManagementService;
use HiEvents\Services\Handlers\Order\DTO\CreateOrderPublicDTO;
use HiEvents\Services\Infrastructure\Session\CheckoutSessionManagementService;
use Illuminate\Database\DatabaseManager;
use Illuminate\Validation\UnauthorizedException;
use Throwable;

class CreateOrderHandler
readonly class CreateOrderHandler
{
public function __construct(
private readonly EventRepositoryInterface $eventRepository,
private readonly PromoCodeRepositoryInterface $promoCodeRepository,
private readonly OrderManagementService $orderManagementService,
private readonly OrderItemProcessingService $orderItemProcessingService,
private readonly DatabaseManager $databaseManager,
private EventRepositoryInterface $eventRepository,
private PromoCodeRepositoryInterface $promoCodeRepository,
private OrderManagementService $orderManagementService,
private OrderItemProcessingService $orderItemProcessingService,
private DatabaseManager $databaseManager,
private CheckoutSessionManagementService $sessionIdentifierService,
)
{
}
Expand All @@ -40,7 +42,9 @@ public function handle(
bool $deleteExistingOrdersForSession = true
): OrderDomainObject
{
return $this->databaseManager->transaction(function () use ($eventId, $createOrderPublicDTO, $deleteExistingOrdersForSession) {
$sessionId = $this->sessionIdentifierService->getSessionId();

return $this->databaseManager->transaction(function () use ($sessionId, $eventId, $createOrderPublicDTO, $deleteExistingOrdersForSession) {
$event = $this->eventRepository
->loadRelation(EventSettingDomainObject::class)
->findById($eventId);
Expand All @@ -50,7 +54,7 @@ public function handle(
$promoCode = $this->getPromoCode($createOrderPublicDTO, $eventId);

if ($deleteExistingOrdersForSession) {
$this->orderManagementService->deleteExistingOrders($eventId, $createOrderPublicDTO->session_identifier);
$this->orderManagementService->deleteExistingOrders($eventId, $sessionId);
}

$order = $this->orderManagementService->createNewOrder(
Expand All @@ -59,7 +63,7 @@ public function handle(
timeOutMinutes: $event->getEventSettings()?->getOrderTimeoutInMinutes(),
locale: $createOrderPublicDTO->order_locale,
promoCode: $promoCode,
sessionId: $createOrderPublicDTO->session_identifier,
sessionId: $sessionId,
);

$orderItems = $this->orderItemProcessingService->process(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ public function __construct(
*/
public readonly Collection $tickets,
public readonly bool $is_user_authenticated,
public readonly string $session_identifier,
public readonly ?string $order_locale = null,
public readonly ?string $promo_code = null,
public readonly ?string $session_identifier = null,
)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
namespace HiEvents\Services\Infrastructure\Session;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Cookie as SymfonyCookie;

class CheckoutSessionManagementService
{
Expand All @@ -17,37 +14,26 @@ public function __construct(
{
}

/**
* Get the session ID from the cookie, or generate a new one if it doesn't exist.
*/
public function getSessionId(): string
{
$sessionId = $this->request->cookie(self::SESSION_IDENTIFIER);
$userAgent = $this->request->userAgent();
$ipAddress = $this->getIpAddress();

if (!$sessionId) {
$sessionId = $this->createSessionId();
}

return $sessionId;
return sha1($userAgent . $ipAddress . $this->request->input(self::SESSION_IDENTIFIER));
}

public function verifySession(string $identifier): bool
{
return $this->getSessionId() === $identifier;
}

public function getSessionCookie(): SymfonyCookie
private function getIpAddress(): string
{
return Cookie::make(
name: self::SESSION_IDENTIFIER,
value: $this->getSessionId(),
secure: true,
sameSite: 'None',
);
}
if ($digitalOceanIp = $this->request->server('HTTP_DO_CONNECTING_IP')) {
return $digitalOceanIp;
}

private function createSessionId(): string
{
return sha1(Str::uuid() . Str::random(40));
return $this->request->ip();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -8,50 +8,46 @@

class CheckoutSessionManagementServiceTest extends TestCase
{
public function testGetSessionIdWithExistingCookie(): void
public function testGetSessionId(): void
{
$request = $this->createMock(Request::class);

$request->expects($this->once())
->method('cookie')
->method('userAgent')
->willReturn('userAgent');

$request->expects($this->once())
->method('input')
->with('session_identifier')
->willReturn('existingSessionId');
->willReturn('sessionIdentifier');

$request->expects($this->once())
->method('ip')
->willReturn('ip');

$service = new CheckoutSessionManagementService($request);

$this->assertEquals('existingSessionId', $service->getSessionId());
$this->assertEquals(sha1('userAgent' . 'ip' . 'sessionIdentifier'), $service->getSessionId());
}

public function testVerifySession(): void
{
$request = $this->createMock(Request::class);
$request->expects($this->once())
->method('userAgent')
->willReturn('userAgent');

$request->expects($this->once())
->method('cookie')
->method('input')
->with('session_identifier')
->willReturn('existingSessionId');

$service = new CheckoutSessionManagementService($request);

$this->assertTrue($service->verifySession('existingSessionId'));
}

public function testGetSessionCookie(): void
{
$request = $this->createMock(Request::class);
->willReturn('sessionIdentifier');

$request->expects($this->once())
->method('cookie')
->with('session_identifier')
->willReturn('existingSessionId');
->method('ip')
->willReturn('ip');

$service = new CheckoutSessionManagementService($request);

$cookie = $service->getSessionCookie();

$this->assertEquals('session_identifier', $cookie->getName());
$this->assertEquals('existingSessionId', $cookie->getValue());
$this->assertTrue($cookie->isSecure());
$this->assertEquals('none', $cookie->getSameSite());
$this->assertTrue($service->verifySession(sha1('userAgent' . 'ip' . 'sessionIdentifier')));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export const CollectInformation = () => {
data: order,
data: {order_items: orderItems} = {},
isError: isOrderError,
error: orderError,
} = useGetOrderPublic(eventId, orderShortId);
const {
data: event,
Expand Down Expand Up @@ -218,18 +217,6 @@ export const CollectInformation = () => {
navigate(`/event/${eventId}/${eventSlug}`);
}

if (isOrderError && orderError?.response?.status === 404) {
return (
<>
<HomepageInfoMessage
message={t`Sorry, this order no longer exists.`}
link={eventHomepagePath(event as Event)}
linkText={t`Back to event page`}
/>
</>
);
}

if (isOrderError || isEventError || isQuestionsError) {
return (
<>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/locales/de.js

Large diffs are not rendered by default.

Loading

0 comments on commit 8647110

Please sign in to comment.