diff --git a/backend/main.py b/backend/main.py index ff23898..672cfaa 100644 --- a/backend/main.py +++ b/backend/main.py @@ -229,11 +229,18 @@ async def signal( if geo else "Гео нету" ) - text = ( - f"🚨 Сигнал от {user_name}\n" - f"⏰ {ts.strftime('%H:%M:%S')} UTC\n" - f"{geo_info}" - ) + if body.is_test: + text = ( + f"🧪 Тест от {user_name}\n" + f"⏰ {ts.strftime('%H:%M:%S')} UTC\n" + f"{geo_info}" + ) + else: + text = ( + f"🚨 Сигнал от {user_name}\n" + f"⏰ {ts.strftime('%H:%M:%S')} UTC\n" + f"{geo_info}" + ) asyncio.create_task(telegram.send_message(text)) return SignalResponse(status="ok", signal_id=signal_id) diff --git a/backend/models.py b/backend/models.py index 5137e1a..91c0941 100644 --- a/backend/models.py +++ b/backend/models.py @@ -25,6 +25,7 @@ class SignalRequest(BaseModel): user_id: Optional[str] = None # UUID for legacy api_key auth; omit for JWT auth timestamp: int = Field(..., gt=0) geo: Optional[GeoData] = None + is_test: bool = False class SignalResponse(BaseModel): diff --git a/frontend/app.js b/frontend/app.js index 0563b77..88aa0c0 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -203,6 +203,33 @@ function _setSosState(state) { btn.disabled = state === 'sending'; } +async function _handleTestSignal() { + if (!navigator.onLine) { + _setStatus('Нет соединения.', 'error'); + return; + } + const token = _getAuthToken(); + if (!token) return; + + _setStatus('', ''); + try { + const geo = await _getGeo(); + const body = { timestamp: Date.now(), is_test: true }; + if (geo) body.geo = geo; + await _apiPost('/api/signal', body, { Authorization: 'Bearer ' + token }); + _setStatus('Тест отправлен', 'success'); + setTimeout(() => _setStatus('', ''), 1500); + } catch (err) { + if (err && err.status === 401) { + _clearAuth(); + _setStatus('Сессия истекла. Войдите заново.', 'error'); + setTimeout(() => _showOnboarding(), 1500); + } else { + _setStatus('Ошибка отправки.', 'error'); + } + } +} + async function _handleSignal() { if (!navigator.onLine) { _setStatus('Нет соединения. Проверьте сеть и попробуйте снова.', 'error'); @@ -297,6 +324,20 @@ function _showMain() { btn.addEventListener('click', _handleSignal); btn.dataset.listenerAttached = '1'; } + + // Avatar and network indicator → test signal (only on main screen) + const avatar = document.getElementById('user-avatar'); + if (avatar && !avatar.dataset.testAttached) { + avatar.addEventListener('click', _handleTestSignal); + avatar.dataset.testAttached = '1'; + avatar.style.cursor = 'pointer'; + } + const indicator = document.getElementById('indicator-network'); + if (indicator && !indicator.dataset.testAttached) { + indicator.addEventListener('click', _handleTestSignal); + indicator.dataset.testAttached = '1'; + indicator.style.cursor = 'pointer'; + } } // ========== Service Worker ==========