Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@

Two exceptions: orders and drivers are written constantly, so a transaction's order or driver snapshot can lag by up to the five-minute list cache.

- **Public API requests weren't logged.** Writes to the public wallet API (`ledger/v1/...`) and the customer invoice routes (`ledger/public/...`, such as paying an invoice) are now written to the API request logs, like core's public API. Webhooks and the console's internal routes aren't logged.

---
## Upgrading
Takes effect with fleetbase/core-api's cache dependency support ([fleetbase/core-api#301](https://github.com/fleetbase/core-api/pull/301)). With an older core-api the change is inert.
The transaction list fix takes effect with fleetbase/core-api's cache dependency support ([fleetbase/core-api#301](https://github.com/fleetbase/core-api/pull/301)). With an older core-api the change is inert.

API request logging takes effect with [fleetbase/core-api#302](https://github.com/fleetbase/core-api/pull/302), which logs every route that runs `LogApiRequests` rather than only `v1/...`. With an older core-api, ledger requests are still not logged.

---
## Need help?
Expand Down
2 changes: 1 addition & 1 deletion scripts/pest-bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ function config(?string $key = null, mixed $default = null): mixed

if (!$app->bound('router')) {
if (!class_exists('Fleetbase\TestSupport\RouteRegistrar')) {
eval('namespace Fleetbase\TestSupport; class RouteRegistrar { public static array $routes = []; public static function reset(): void { self::$routes = []; } public function prefix(string $prefix): self { return $this; } public function namespace(string $namespace): self { return $this; } public function group(array|\Closure $attributes, ?\Closure $callback = null): self { ($callback ?? $attributes)($this); return $this; } public function get(string $uri, mixed $action): self { self::$routes[] = ["GET", $uri, $action]; return $this; } public function post(string $uri, mixed $action): self { self::$routes[] = ["POST", $uri, $action]; return $this; } public function fleetbaseRoutes(string $resource, ?\Closure $callback = null): self { self::$routes[] = ["RESOURCE", $resource, null]; if ($callback) { $callback($this, fn (string $method): string => $resource . "Controller@" . $method); } return $this; } }');
eval('namespace Fleetbase\TestSupport; class RouteRegistrar { public static array $routes = []; public static array $middleware = []; public static function reset(): void { self::$routes = []; self::$middleware = []; } public function prefix(string $prefix): self { return $this; } public function namespace(string $namespace): self { return $this; } public function group(array|\Closure $attributes, ?\Closure $callback = null): self { $previous = self::$middleware; if (is_array($attributes)) { self::$middleware = array_merge(self::$middleware, (array) ($attributes["middleware"] ?? [])); } ($callback ?? $attributes)($this); self::$middleware = $previous; return $this; } public function get(string $uri, mixed $action): self { self::$routes[] = ["GET", $uri, $action, self::$middleware]; return $this; } public function post(string $uri, mixed $action): self { self::$routes[] = ["POST", $uri, $action, self::$middleware]; return $this; } public function fleetbaseRoutes(string $resource, ?\Closure $callback = null): self { self::$routes[] = ["RESOURCE", $resource, null]; if ($callback) { $callback($this, fn (string $method): string => $resource . "Controller@" . $method); } return $this; } }');
}

$app->singleton('router', fn () => new Fleetbase\TestSupport\RouteRegistrar());
Expand Down
18 changes: 11 additions & 7 deletions server/src/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,22 @@ function ($router) {
|--------------------------------------------------------------------------
|
| These routes allow customers to view and pay invoices without logging in.
| They are scoped by the globally-unique invoice public_id / uuid.
| They are scoped by the globally-unique invoice public_id / uuid. Writes
| are logged to the API request logs like the public API's.
|
| GET /ledger/public/invoices/{public_id}
| GET /ledger/public/invoices/{public_id}/gateways
| POST /ledger/public/invoices/{public_id}/pay
*/
$router->prefix('public')->namespace('Public')->group(function ($router) {
$router->get('invoices/{public_id}', 'PublicInvoiceController@show');
$router->get('invoices/{public_id}/gateways', 'PublicInvoiceController@gateways');
$router->post('invoices/{public_id}/pay', 'PublicInvoiceController@pay');
$router->get('refunds/{refund_id}', 'PublicInvoiceController@refund');
});
$router->prefix('public')->namespace('Public')->group(
['middleware' => [Fleetbase\Http\Middleware\LogApiRequests::class]],
function ($router) {
$router->get('invoices/{public_id}', 'PublicInvoiceController@show');
$router->get('invoices/{public_id}/gateways', 'PublicInvoiceController@gateways');
$router->post('invoices/{public_id}/pay', 'PublicInvoiceController@pay');
$router->get('refunds/{refund_id}', 'PublicInvoiceController@refund');
}
);

/*
|--------------------------------------------------------------------------
Expand Down
22 changes: 22 additions & 0 deletions server/tests/Routes/RouteRegistrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,25 @@
'GET|reports/wallet-summary|ReportController@walletSummary',
);
});

test('Ledger logs requests to its public API and customer invoice routes but not webhooks or internal routes', function () {
RouteRegistrar::reset();
Facade::clearResolvedInstance('router');
Container::getInstance()->instance('router', new RouteRegistrar());

require __DIR__ . '/../../src/routes.php';

$middleware = [];
foreach (RouteRegistrar::$routes as $route) {
if (is_string($route[2])) {
$middleware[$route[0] . '|' . $route[1] . '|' . $route[2]] = $route[3] ?? [];
}
}

// The public API's fleetbase.api group runs LogApiRequests
expect($middleware['POST|wallet/topup|Api\v1\WalletApiController@topUp'])->toBe(['fleetbase.api'])
->and($middleware['POST|invoices/{public_id}/pay|PublicInvoiceController@pay'])->toBe([Fleetbase\Http\Middleware\LogApiRequests::class])
->and($middleware['GET|invoices/{public_id}|PublicInvoiceController@show'])->toBe([Fleetbase\Http\Middleware\LogApiRequests::class])
->and($middleware['POST|webhooks/{driver}|WebhookController@handle'])->toBe([])
->and($middleware['GET|gateways/drivers|GatewayController@drivers'])->toBe(['fleetbase.protected']);
});