feat(fusion_clock): NFC tap endpoint debounce + 6 error-case tests
Adds module-level 5s debounce (_is_debounced) with thread-safe dict + GC. Inserts debounce guard in nfc_tap immediately after uid validation. Adds TestTapEndpointErrors (6 tests): unknown_card, clock_disabled, no_location_configured, kiosk_disabled, invalid_uid, debounce. Adds setUp() to both tap test classes to clear _recent_taps between tests, preventing cross-test debounce bleed. 29/29 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,12 +4,33 @@
|
||||
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
import threading
|
||||
from odoo import fields, http
|
||||
from odoo.http import request
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_UID_HEX_PATTERN = re.compile(r'^[0-9A-F]+$')
|
||||
|
||||
_DEBOUNCE_WINDOW_SECONDS = 5.0
|
||||
_recent_taps = {} # {card_uid: monotonic_ts}
|
||||
_recent_taps_lock = threading.Lock()
|
||||
|
||||
|
||||
def _is_debounced(uid):
|
||||
"""Return True if this UID was tapped within the debounce window."""
|
||||
now = time.monotonic()
|
||||
with _recent_taps_lock:
|
||||
last = _recent_taps.get(uid, 0)
|
||||
if now - last < _DEBOUNCE_WINDOW_SECONDS:
|
||||
return True
|
||||
_recent_taps[uid] = now
|
||||
# Opportunistic GC: drop entries older than 60s
|
||||
stale_keys = [k for k, t in _recent_taps.items() if now - t > 60]
|
||||
for k in stale_keys:
|
||||
_recent_taps.pop(k, None)
|
||||
return False
|
||||
|
||||
|
||||
class FusionClockNfcKiosk(http.Controller):
|
||||
"""NFC tap-to-clock kiosk controller. Reuses FusionClockAPI helpers."""
|
||||
@@ -120,6 +141,9 @@ class FusionClockNfcKiosk(http.Controller):
|
||||
if not normalized:
|
||||
return {'error': 'invalid_uid'}
|
||||
|
||||
if _is_debounced(normalized):
|
||||
return {'error': 'debounce'}
|
||||
|
||||
company = request.env.company
|
||||
location = company.x_fclk_nfc_kiosk_location_id
|
||||
if not location:
|
||||
|
||||
Reference in New Issue
Block a user