Address QA review: model registry, NOT NULL constraint, variable naming, toggle defaults, lockout UX
- C3: Register User, UserSession, NtfySent, TOTPUsage, BackupCode in models/__init__.py - C4: Enforce settings.user_id NOT NULL after backfill in migration 023, update model - W4: Rename misleading current_user → current_settings in dashboard.py - W5: Match NtfySettingsSection initial state defaults to backend (true/1/2) - W8: Clear lockout banner on username/password input change in LockScreen Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f136a0820d
commit
15c99152d3
@ -119,7 +119,12 @@ def upgrade() -> None:
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 6. Drop pin_hash from settings — data now lives in users.password_hash
|
||||
# 6. Enforce NOT NULL on user_id now that backfill is complete
|
||||
# ------------------------------------------------------------------
|
||||
op.alter_column('settings', 'user_id', nullable=False)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 7. Drop pin_hash from settings — data now lives in users.password_hash
|
||||
# ------------------------------------------------------------------
|
||||
op.drop_column('settings', 'pin_hash')
|
||||
|
||||
|
||||
@ -8,6 +8,11 @@ from app.models.project_task import ProjectTask
|
||||
from app.models.person import Person
|
||||
from app.models.location import Location
|
||||
from app.models.task_comment import TaskComment
|
||||
from app.models.user import User
|
||||
from app.models.session import UserSession
|
||||
from app.models.ntfy_sent import NtfySent
|
||||
from app.models.totp_usage import TOTPUsage
|
||||
from app.models.backup_code import BackupCode
|
||||
|
||||
__all__ = [
|
||||
"Settings",
|
||||
@ -20,4 +25,9 @@ __all__ = [
|
||||
"Person",
|
||||
"Location",
|
||||
"TaskComment",
|
||||
"User",
|
||||
"UserSession",
|
||||
"NtfySent",
|
||||
"TOTPUsage",
|
||||
"BackupCode",
|
||||
]
|
||||
|
||||
@ -10,10 +10,10 @@ class Settings(Base):
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, index=True)
|
||||
|
||||
# FK to users table — nullable during migration, will be NOT NULL after data migration
|
||||
user_id: Mapped[Optional[int]] = mapped_column(
|
||||
# FK to users table — NOT NULL enforced by migration 023 after data backfill
|
||||
user_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("users.id", ondelete="CASCADE"),
|
||||
nullable=True,
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
|
||||
|
||||
@ -26,11 +26,11 @@ _not_parent_template = or_(
|
||||
async def get_dashboard(
|
||||
client_date: Optional[date] = Query(None),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: Settings = Depends(get_current_settings)
|
||||
current_settings: Settings = Depends(get_current_settings)
|
||||
):
|
||||
"""Get aggregated dashboard data."""
|
||||
today = client_date or date.today()
|
||||
upcoming_cutoff = today + timedelta(days=current_user.upcoming_days)
|
||||
upcoming_cutoff = today + timedelta(days=current_settings.upcoming_days)
|
||||
|
||||
# Today's events (exclude parent templates — they are hidden, children are shown)
|
||||
today_start = datetime.combine(today, datetime.min.time())
|
||||
@ -143,7 +143,7 @@ async def get_upcoming(
|
||||
days: int = Query(default=7, ge=1, le=90),
|
||||
client_date: Optional[date] = Query(None),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: Settings = Depends(get_current_settings)
|
||||
current_settings: Settings = Depends(get_current_settings)
|
||||
):
|
||||
"""Get unified list of upcoming items (todos, events, reminders) sorted by date."""
|
||||
today = client_date or date.today()
|
||||
|
||||
@ -218,7 +218,7 @@ export default function LockScreen() {
|
||||
id="username"
|
||||
type="text"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
onChange={(e) => { setUsername(e.target.value); setLockoutMessage(null); }}
|
||||
placeholder="Enter username"
|
||||
required
|
||||
autoFocus
|
||||
@ -232,7 +232,7 @@ export default function LockScreen() {
|
||||
id="password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
onChange={(e) => { setPassword(e.target.value); setLockoutMessage(null); }}
|
||||
placeholder={isSetup ? 'Create a password' : 'Enter password'}
|
||||
required
|
||||
autoComplete={isSetup ? 'new-password' : 'current-password'}
|
||||
|
||||
@ -36,13 +36,13 @@ export default function NtfySettingsSection({ settings, updateSettings }: NtfySe
|
||||
const [showToken, setShowToken] = useState(false);
|
||||
|
||||
// Per-type toggles
|
||||
const [eventsEnabled, setEventsEnabled] = useState(false);
|
||||
const [eventsEnabled, setEventsEnabled] = useState(true);
|
||||
const [eventLeadMinutes, setEventLeadMinutes] = useState(15);
|
||||
const [remindersEnabled, setRemindersEnabled] = useState(false);
|
||||
const [todosEnabled, setTodosEnabled] = useState(false);
|
||||
const [todoLeadDays, setTodoLeadDays] = useState(0);
|
||||
const [projectsEnabled, setProjectsEnabled] = useState(false);
|
||||
const [projectLeadDays, setProjectLeadDays] = useState(0);
|
||||
const [remindersEnabled, setRemindersEnabled] = useState(true);
|
||||
const [todosEnabled, setTodosEnabled] = useState(true);
|
||||
const [todoLeadDays, setTodoLeadDays] = useState(1);
|
||||
const [projectsEnabled, setProjectsEnabled] = useState(true);
|
||||
const [projectLeadDays, setProjectLeadDays] = useState(2);
|
||||
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [isTestingNtfy, setIsTestingNtfy] = useState(false);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user