fix(loyalty): make device tokens authenticate via require_module_access too
Some checks failed
Some checks failed
Two follow-ups from the live smoke test:
1. The store router has two auth gates: its own get_current_store_api
(already taught about device tokens) and router-level
require_module_access("loyalty", FrontendType.STORE), which goes
through get_current_store_from_cookie_or_header. That cookie-or-header
variant didn't know about device tokens, so live curl with a paired
device JWT was rejected with 401 "Authentication required". Tests
passed only because dependency overrides bypass the module-access dep.
Add the same _try_authenticate_terminal_device branch there.
2. Normalize the /merchants/loyalty/locations response in the devices
Alpine factory: the endpoint returns {id, name, code} but the
templates bind to loc.store_id/loc.store_name. Map both shapes so
the pair-tablet store dropdown populates.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -728,6 +728,12 @@ def get_current_store_from_cookie_or_header(
|
||||
logger.warning(f"Store auth failed: No token for {request.url.path}")
|
||||
raise InvalidTokenException("Store authentication required")
|
||||
|
||||
# Paired terminal-device tokens authenticate to the store API too.
|
||||
# Cookie path won't carry a device JWT; this only matters for header.
|
||||
device_ctx = _try_authenticate_terminal_device(token, db, request)
|
||||
if device_ctx is not None:
|
||||
return device_ctx
|
||||
|
||||
# Validate token and get user
|
||||
user = _validate_user_token(token, db)
|
||||
|
||||
|
||||
@@ -95,9 +95,15 @@ function loyaltyDevicesList(config) {
|
||||
async loadLocations() {
|
||||
try {
|
||||
const response = await apiClient.get(locationsPrefix + '/locations');
|
||||
if (response) {
|
||||
this.locations = Array.isArray(response) ? response : (response.locations || []);
|
||||
}
|
||||
if (!response) return;
|
||||
const raw = Array.isArray(response) ? response : (response.locations || []);
|
||||
// Endpoint returns {id, name, code}; templates bind to store_id/store_name.
|
||||
// Normalize so callers don't have to care about either shape.
|
||||
this.locations = raw.map(loc => ({
|
||||
store_id: loc.store_id ?? loc.id,
|
||||
store_name: loc.store_name ?? loc.name,
|
||||
store_code: loc.store_code ?? loc.code,
|
||||
}));
|
||||
} catch (error) {
|
||||
loyaltyDevicesListLog.warn('Failed to load locations:', error.message);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user