mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-07 17:23:05 +02:00
Add outgoing message region tagging. Closes #35.
This commit is contained in:
@@ -244,6 +244,7 @@ Main tables:
|
||||
- `mqtt_broker_host`, `mqtt_broker_port`, `mqtt_username`, `mqtt_password`
|
||||
- `mqtt_use_tls`, `mqtt_tls_insecure`, `mqtt_topic_prefix`, `mqtt_publish_messages`, `mqtt_publish_raw_packets`
|
||||
- `community_mqtt_enabled`, `community_mqtt_iata`, `community_mqtt_broker_host`, `community_mqtt_broker_port`, `community_mqtt_email`
|
||||
- `flood_scope`
|
||||
|
||||
## Security Posture (intentional)
|
||||
|
||||
|
||||
@@ -268,6 +268,13 @@ async def run_migrations(conn: aiosqlite.Connection) -> int:
|
||||
await set_version(conn, 33)
|
||||
applied += 1
|
||||
|
||||
# Migration 34: Add flood_scope column to app_settings
|
||||
if version < 34:
|
||||
logger.info("Applying migration 34: add flood_scope column to app_settings")
|
||||
await _migrate_034_add_flood_scope(conn)
|
||||
await set_version(conn, 34)
|
||||
applied += 1
|
||||
|
||||
if applied > 0:
|
||||
logger.info(
|
||||
"Applied %d migration(s), schema now at version %d", applied, await get_version(conn)
|
||||
@@ -1951,3 +1958,21 @@ async def _migrate_033_seed_remoteterm_channel(conn: aiosqlite.Connection) -> No
|
||||
await conn.commit()
|
||||
except Exception:
|
||||
logger.debug("Skipping #remoteterm seed (channels table not ready)")
|
||||
|
||||
|
||||
async def _migrate_034_add_flood_scope(conn: aiosqlite.Connection) -> None:
|
||||
"""Add flood_scope column to app_settings for outbound region tagging.
|
||||
|
||||
Empty string means disabled (no scope set, messages sent unscoped).
|
||||
"""
|
||||
try:
|
||||
await conn.execute("ALTER TABLE app_settings ADD COLUMN flood_scope TEXT DEFAULT ''")
|
||||
await conn.commit()
|
||||
except Exception as e:
|
||||
error_msg = str(e).lower()
|
||||
if "duplicate column" in error_msg:
|
||||
logger.debug("flood_scope column already exists, skipping")
|
||||
elif "no such table" in error_msg:
|
||||
logger.debug("app_settings table not ready, skipping flood_scope migration")
|
||||
else:
|
||||
raise
|
||||
|
||||
@@ -518,6 +518,10 @@ class AppSettings(BaseModel):
|
||||
default="",
|
||||
description="Email address for node claiming on the community aggregator (optional)",
|
||||
)
|
||||
flood_scope: str = Field(
|
||||
default="",
|
||||
description="Outbound flood scope / region name (empty = disabled, no tagging)",
|
||||
)
|
||||
|
||||
|
||||
class BusyChannel(BaseModel):
|
||||
|
||||
@@ -258,6 +258,14 @@ class RadioManager:
|
||||
# Sync radio clock with system time
|
||||
await sync_radio_time(mc)
|
||||
|
||||
# Apply flood scope from settings
|
||||
from app.repository import AppSettingsRepository
|
||||
|
||||
app_settings = await AppSettingsRepository.get()
|
||||
scope = app_settings.flood_scope
|
||||
await mc.commands.set_flood_scope(scope if scope else "")
|
||||
logger.info("Applied flood_scope=%r", scope or "(disabled)")
|
||||
|
||||
# Sync contacts/channels from radio to DB and clear radio
|
||||
logger.info("Syncing and offloading radio data...")
|
||||
result = await sync_and_offload_all(mc)
|
||||
|
||||
@@ -32,7 +32,7 @@ class AppSettingsRepository:
|
||||
mqtt_publish_messages, mqtt_publish_raw_packets,
|
||||
community_mqtt_enabled, community_mqtt_iata,
|
||||
community_mqtt_broker_host, community_mqtt_broker_port,
|
||||
community_mqtt_email
|
||||
community_mqtt_email, flood_scope
|
||||
FROM app_settings WHERE id = 1
|
||||
"""
|
||||
)
|
||||
@@ -112,6 +112,7 @@ class AppSettingsRepository:
|
||||
or "mqtt-us-v1.letsmesh.net",
|
||||
community_mqtt_broker_port=row["community_mqtt_broker_port"] or 443,
|
||||
community_mqtt_email=row["community_mqtt_email"] or "",
|
||||
flood_scope=row["flood_scope"] or "",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -139,6 +140,7 @@ class AppSettingsRepository:
|
||||
community_mqtt_broker_host: str | None = None,
|
||||
community_mqtt_broker_port: int | None = None,
|
||||
community_mqtt_email: str | None = None,
|
||||
flood_scope: str | None = None,
|
||||
) -> AppSettings:
|
||||
"""Update app settings. Only provided fields are updated."""
|
||||
updates = []
|
||||
@@ -238,6 +240,10 @@ class AppSettingsRepository:
|
||||
updates.append("community_mqtt_email = ?")
|
||||
params.append(community_mqtt_email)
|
||||
|
||||
if flood_scope is not None:
|
||||
updates.append("flood_scope = ?")
|
||||
params.append(flood_scope)
|
||||
|
||||
if updates:
|
||||
query = f"UPDATE app_settings SET {', '.join(updates)} WHERE id = 1"
|
||||
await db.conn.execute(query, params)
|
||||
|
||||
@@ -121,6 +121,10 @@ class AppSettingsUpdate(BaseModel):
|
||||
default=None,
|
||||
description="Email address for node claiming on the community aggregator",
|
||||
)
|
||||
flood_scope: str | None = Field(
|
||||
default=None,
|
||||
description="Outbound flood scope / region name (empty = disabled)",
|
||||
)
|
||||
|
||||
|
||||
class FavoriteRequest(BaseModel):
|
||||
@@ -237,6 +241,13 @@ async def update_settings(update: AppSettingsUpdate) -> AppSettings:
|
||||
kwargs["community_mqtt_email"] = update.community_mqtt_email
|
||||
community_mqtt_changed = True
|
||||
|
||||
# Flood scope
|
||||
flood_scope_changed = False
|
||||
if update.flood_scope is not None:
|
||||
stripped = update.flood_scope.strip()
|
||||
kwargs["flood_scope"] = stripped
|
||||
flood_scope_changed = True
|
||||
|
||||
# Require IATA when enabling community MQTT
|
||||
if kwargs.get("community_mqtt_enabled", False):
|
||||
# Check the IATA value being set, or fall back to current settings
|
||||
@@ -265,6 +276,19 @@ async def update_settings(update: AppSettingsUpdate) -> AppSettings:
|
||||
|
||||
await community_publisher.restart(result)
|
||||
|
||||
# Apply flood scope to radio immediately if changed
|
||||
if flood_scope_changed:
|
||||
from app.radio import radio_manager
|
||||
|
||||
if radio_manager.is_connected:
|
||||
try:
|
||||
scope = result.flood_scope
|
||||
async with radio_manager.radio_operation("set_flood_scope") as mc:
|
||||
await mc.commands.set_flood_scope(scope if scope else "")
|
||||
logger.info("Applied flood_scope=%r to radio", scope or "(disabled)")
|
||||
except Exception as e:
|
||||
logger.warning("Failed to apply flood_scope to radio: %s", e)
|
||||
|
||||
return result
|
||||
|
||||
return await AppSettingsRepository.get()
|
||||
|
||||
Reference in New Issue
Block a user