settings overhaul, many QOL improvements

This commit is contained in:
serversdwn
2025-12-09 02:08:00 +00:00
parent 690669c697
commit 6fc8721830
11 changed files with 1188 additions and 348 deletions

View File

@@ -18,7 +18,7 @@ Base.metadata.create_all(bind=engine)
ENVIRONMENT = os.getenv("ENVIRONMENT", "production")
# Initialize FastAPI app
VERSION = "0.2.2"
VERSION = "0.2.3"
app = FastAPI(
title="Seismo Fleet Manager",
description="Backend API for managing seismograph fleet status",

View File

@@ -0,0 +1,80 @@
"""
Migration script to add user_preferences table.
This creates a new table for storing persistent user preferences:
- Display settings (timezone, theme, date format)
- Auto-refresh configuration
- Calibration defaults
- Status threshold customization
Run this script once to migrate an existing database.
"""
import sqlite3
import os
# Database path
DB_PATH = "./data/seismo_fleet.db"
def migrate_database():
"""Create user_preferences table"""
if not os.path.exists(DB_PATH):
print(f"Database not found at {DB_PATH}")
print("The database will be created automatically when you run the application.")
return
print(f"Migrating database: {DB_PATH}")
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
# Check if user_preferences table already exists
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='user_preferences'")
table_exists = cursor.fetchone()
if table_exists:
print("Migration already applied - user_preferences table exists")
conn.close()
return
print("Creating user_preferences table...")
try:
cursor.execute("""
CREATE TABLE user_preferences (
id INTEGER PRIMARY KEY DEFAULT 1,
timezone TEXT DEFAULT 'America/New_York',
theme TEXT DEFAULT 'auto',
auto_refresh_interval INTEGER DEFAULT 10,
date_format TEXT DEFAULT 'MM/DD/YYYY',
table_rows_per_page INTEGER DEFAULT 25,
calibration_interval_days INTEGER DEFAULT 365,
calibration_warning_days INTEGER DEFAULT 30,
status_ok_threshold_hours INTEGER DEFAULT 12,
status_pending_threshold_hours INTEGER DEFAULT 24,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
print(" ✓ Created user_preferences table")
# Insert default preferences
cursor.execute("""
INSERT INTO user_preferences (id) VALUES (1)
""")
print(" ✓ Inserted default preferences")
conn.commit()
print("\nMigration completed successfully!")
except sqlite3.Error as e:
print(f"\nError during migration: {e}")
conn.rollback()
raise
finally:
conn.close()
if __name__ == "__main__":
migrate_database()

View File

@@ -1,4 +1,4 @@
from sqlalchemy import Column, String, DateTime, Boolean, Text, Date
from sqlalchemy import Column, String, DateTime, Boolean, Text, Date, Integer
from datetime import datetime
from backend.database import Base
@@ -56,4 +56,24 @@ class IgnoredUnit(Base):
id = Column(String, primary_key=True, index=True)
reason = Column(String, nullable=True)
ignored_at = Column(DateTime, default=datetime.utcnow)
ignored_at = Column(DateTime, default=datetime.utcnow)
class UserPreferences(Base):
"""
User preferences: persistent storage for application settings.
Single-row table (id=1) to store global user preferences.
"""
__tablename__ = "user_preferences"
id = Column(Integer, primary_key=True, default=1)
timezone = Column(String, default="America/New_York")
theme = Column(String, default="auto") # auto, light, dark
auto_refresh_interval = Column(Integer, default=10) # seconds
date_format = Column(String, default="MM/DD/YYYY")
table_rows_per_page = Column(Integer, default=25)
calibration_interval_days = Column(Integer, default=365)
calibration_warning_days = Column(Integer, default=30)
status_ok_threshold_hours = Column(Integer, default=12)
status_pending_threshold_hours = Column(Integer, default=24)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

View File

@@ -2,11 +2,13 @@ from fastapi import APIRouter, Depends, HTTPException, UploadFile, File
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
from datetime import datetime, date
from pydantic import BaseModel
from typing import Optional
import csv
import io
from backend.database import get_db
from backend.models import RosterUnit, Emitter, IgnoredUnit
from backend.models import RosterUnit, Emitter, IgnoredUnit, UserPreferences
router = APIRouter(prefix="/api/settings", tags=["settings"])
@@ -239,3 +241,87 @@ def clear_ignored(db: Session = Depends(get_db)):
except Exception as e:
db.rollback()
raise HTTPException(status_code=500, detail=f"Clear failed: {str(e)}")
# User Preferences Endpoints
class PreferencesUpdate(BaseModel):
"""Schema for updating user preferences (all fields optional)"""
timezone: Optional[str] = None
theme: Optional[str] = None
auto_refresh_interval: Optional[int] = None
date_format: Optional[str] = None
table_rows_per_page: Optional[int] = None
calibration_interval_days: Optional[int] = None
calibration_warning_days: Optional[int] = None
status_ok_threshold_hours: Optional[int] = None
status_pending_threshold_hours: Optional[int] = None
@router.get("/preferences")
def get_preferences(db: Session = Depends(get_db)):
"""
Get user preferences. Creates default preferences if none exist.
"""
prefs = db.query(UserPreferences).filter(UserPreferences.id == 1).first()
if not prefs:
# Create default preferences
prefs = UserPreferences(id=1)
db.add(prefs)
db.commit()
db.refresh(prefs)
return {
"timezone": prefs.timezone,
"theme": prefs.theme,
"auto_refresh_interval": prefs.auto_refresh_interval,
"date_format": prefs.date_format,
"table_rows_per_page": prefs.table_rows_per_page,
"calibration_interval_days": prefs.calibration_interval_days,
"calibration_warning_days": prefs.calibration_warning_days,
"status_ok_threshold_hours": prefs.status_ok_threshold_hours,
"status_pending_threshold_hours": prefs.status_pending_threshold_hours,
"updated_at": prefs.updated_at.isoformat() if prefs.updated_at else None
}
@router.put("/preferences")
def update_preferences(
updates: PreferencesUpdate,
db: Session = Depends(get_db)
):
"""
Update user preferences. Accepts partial updates.
Creates default preferences if none exist.
"""
prefs = db.query(UserPreferences).filter(UserPreferences.id == 1).first()
if not prefs:
# Create default preferences
prefs = UserPreferences(id=1)
db.add(prefs)
# Update only provided fields
update_data = updates.dict(exclude_unset=True)
for field, value in update_data.items():
setattr(prefs, field, value)
prefs.updated_at = datetime.utcnow()
db.commit()
db.refresh(prefs)
return {
"message": "Preferences updated successfully",
"timezone": prefs.timezone,
"theme": prefs.theme,
"auto_refresh_interval": prefs.auto_refresh_interval,
"date_format": prefs.date_format,
"table_rows_per_page": prefs.table_rows_per_page,
"calibration_interval_days": prefs.calibration_interval_days,
"calibration_warning_days": prefs.calibration_warning_days,
"status_ok_threshold_hours": prefs.status_ok_threshold_hours,
"status_pending_threshold_hours": prefs.status_pending_threshold_hours,
"updated_at": prefs.updated_at.isoformat() if prefs.updated_at else None
}