- Implemented a modal for renaming units with validation and confirmation prompts. - Added JavaScript functions to handle opening, closing, and submitting the rename unit form. - Enhanced the back navigation in the SLM detail page to check referrer history. - Updated breadcrumb navigation in the legacy dashboard to accommodate NRL locations. - Improved the sound level meters page with a more informative header and device list. - Introduced a live measurement chart with WebSocket support for real-time data streaming. - Added functionality to manage active devices and projects with auto-refresh capabilities.
140 lines
4.8 KiB
Python
140 lines
4.8 KiB
Python
"""
|
|
Roster Unit Rename Router
|
|
|
|
Provides endpoint for safely renaming unit IDs across all database tables.
|
|
"""
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Form
|
|
from sqlalchemy.orm import Session
|
|
from datetime import datetime
|
|
import logging
|
|
|
|
from backend.database import get_db
|
|
from backend.models import RosterUnit, Emitter, UnitHistory
|
|
from backend.routers.roster_edit import record_history, sync_slm_to_slmm_cache
|
|
|
|
router = APIRouter(prefix="/api/roster", tags=["roster-rename"])
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@router.post("/rename")
|
|
async def rename_unit(
|
|
old_id: str = Form(...),
|
|
new_id: str = Form(...),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Rename a unit ID across all tables.
|
|
Updates the unit ID in roster, emitters, unit_history, and all foreign key references.
|
|
|
|
IMPORTANT: This operation updates the primary key, which affects all relationships.
|
|
"""
|
|
# Validate input
|
|
if not old_id or not new_id:
|
|
raise HTTPException(status_code=400, detail="Both old_id and new_id are required")
|
|
|
|
if old_id == new_id:
|
|
raise HTTPException(status_code=400, detail="New ID must be different from old ID")
|
|
|
|
# Check if old unit exists
|
|
old_unit = db.query(RosterUnit).filter(RosterUnit.id == old_id).first()
|
|
if not old_unit:
|
|
raise HTTPException(status_code=404, detail=f"Unit '{old_id}' not found")
|
|
|
|
# Check if new ID already exists
|
|
existing_unit = db.query(RosterUnit).filter(RosterUnit.id == new_id).first()
|
|
if existing_unit:
|
|
raise HTTPException(status_code=409, detail=f"Unit ID '{new_id}' already exists")
|
|
|
|
device_type = old_unit.device_type
|
|
|
|
try:
|
|
# Record history for the rename operation (using old_id since that's still valid)
|
|
record_history(
|
|
db=db,
|
|
unit_id=old_id,
|
|
change_type="id_change",
|
|
field_name="id",
|
|
old_value=old_id,
|
|
new_value=new_id,
|
|
source="manual",
|
|
notes=f"Unit renamed from '{old_id}' to '{new_id}'"
|
|
)
|
|
|
|
# Update roster table (primary)
|
|
old_unit.id = new_id
|
|
old_unit.last_updated = datetime.utcnow()
|
|
|
|
# Update emitters table
|
|
emitter = db.query(Emitter).filter(Emitter.id == old_id).first()
|
|
if emitter:
|
|
emitter.id = new_id
|
|
|
|
# Update unit_history table (all entries for this unit)
|
|
db.query(UnitHistory).filter(UnitHistory.unit_id == old_id).update(
|
|
{"unit_id": new_id},
|
|
synchronize_session=False
|
|
)
|
|
|
|
# Update deployed_with_modem_id references (units that reference this as modem)
|
|
db.query(RosterUnit).filter(RosterUnit.deployed_with_modem_id == old_id).update(
|
|
{"deployed_with_modem_id": new_id},
|
|
synchronize_session=False
|
|
)
|
|
|
|
# Update unit_assignments table (if exists)
|
|
try:
|
|
from backend.models import UnitAssignment
|
|
db.query(UnitAssignment).filter(UnitAssignment.unit_id == old_id).update(
|
|
{"unit_id": new_id},
|
|
synchronize_session=False
|
|
)
|
|
except Exception as e:
|
|
logger.warning(f"Could not update unit_assignments: {e}")
|
|
|
|
# Update recording_sessions table (if exists)
|
|
try:
|
|
from backend.models import RecordingSession
|
|
db.query(RecordingSession).filter(RecordingSession.unit_id == old_id).update(
|
|
{"unit_id": new_id},
|
|
synchronize_session=False
|
|
)
|
|
except Exception as e:
|
|
logger.warning(f"Could not update recording_sessions: {e}")
|
|
|
|
# Commit all changes
|
|
db.commit()
|
|
|
|
# If sound level meter, sync updated config to SLMM cache
|
|
if device_type == "sound_level_meter":
|
|
logger.info(f"Syncing renamed SLM {new_id} (was {old_id}) config to SLMM cache...")
|
|
result = await sync_slm_to_slmm_cache(
|
|
unit_id=new_id,
|
|
host=old_unit.slm_host,
|
|
tcp_port=old_unit.slm_tcp_port,
|
|
ftp_port=old_unit.slm_ftp_port,
|
|
deployed_with_modem_id=old_unit.deployed_with_modem_id,
|
|
db=db
|
|
)
|
|
|
|
if not result["success"]:
|
|
logger.warning(f"SLMM cache sync warning for renamed unit {new_id}: {result['message']}")
|
|
|
|
logger.info(f"Successfully renamed unit '{old_id}' to '{new_id}'")
|
|
|
|
return {
|
|
"success": True,
|
|
"message": f"Successfully renamed unit from '{old_id}' to '{new_id}'",
|
|
"old_id": old_id,
|
|
"new_id": new_id,
|
|
"device_type": device_type
|
|
}
|
|
|
|
except Exception as e:
|
|
db.rollback()
|
|
logger.error(f"Error renaming unit '{old_id}' to '{new_id}': {e}")
|
|
raise HTTPException(
|
|
status_code=500,
|
|
detail=f"Failed to rename unit: {str(e)}"
|
|
)
|