"""Serialize opt-in remote/desktop timer writes using the same transaction helpers.""" from contextlib import nullcontext from functools import wraps from app.core.config import settings from app.core.database import atomic_transaction, _transaction_connection, execute_query def serialized_timer(function): @wraps(function) async def wrapped(*args, **kwargs): # Leave legacy behavior unchanged while remote control is disabled. if not settings.REMOTE_ENABLED: return await function(*args, **kwargs) import inspect arguments = inspect.signature(function).bind_partial(*args, **kwargs).arguments user = arguments.get('current_user') if not isinstance(user, dict) or not user.get('id'): return await function(*args, **kwargs) context = nullcontext() if _transaction_connection.get() else atomic_transaction() with context: ids = {int(user['id'])} payload = arguments.get('payload') or {} if function.__name__ in {'start_live_timer_v1', 'create_manual_time_v1'}: raw_ids = payload.get('medarbejder_ids') or [payload.get('medarbejder_id')] if isinstance(raw_ids, list): for uid in raw_ids: try: if uid is not None: ids.add(int(uid)) except (ValueError, TypeError): pass # The existing handler supplies the validation error. execute_query('SELECT user_id FROM users WHERE user_id=ANY(%s) ORDER BY user_id FOR UPDATE', (sorted(ids),)) return await function(*args, **kwargs) return wrapped