The LDAP migration (20251226) ran batch_alter_table on the invitation and
user tables with PRAGMA foreign_keys=ON. In SQLite, DROP TABLE with FKs
enabled triggers an implicit DELETE FROM that fires ON DELETE CASCADE,
silently wiping every row in invitation_user. This caused the "Latest
Accepted Invites" card to show blank after updating to v2026.3.0.
- Extend PRAGMA foreign_keys=OFF to cover all batch_alter_table operations
in both upgrade() and downgrade()
- Add repair migration that repopulates invitation_user from
invitation.used_by_id and user.code matching (same logic as the
original 20250814 migration)
Closes#1207
Previous failed batch_alter_table attempts leave behind
_alembic_tmp_admin_account in SQLite (no transactional DDL).
Subsequent retries fail trying to CREATE the same temp table.
Now drops any _alembic_tmp_* tables before batch operations, and
splits the admin_account alter into two paths depending on whether
prior columns already exist.
The previous fix addressed the root cause (FK enforcement blocking
batch_alter_table), but users who already hit the bug have databases
with orphaned LDAP tables from the failed partial run. Since SQLite
has no transactional DDL, those tables persist despite the rollback.
Now the migration checks for existing tables/columns before creating
them, so it recovers cleanly regardless of database state.
SQLite batch_alter_table recreates tables via DROP + CREATE. With
PRAGMA foreign_keys=ON (set by our connection handler), the DROP TABLE
admin_account fails because webauthn_credential and api_key reference
it. This caused a crash loop: tables created before the crash persisted
(no transactional DDL in SQLite), then re-running created duplicates.
- Fix 55 test failures caused by missing request contexts and incorrect
session_transaction() usage across 8 test files
- Fix ruff import sorting errors and unused imports
- Fix 122 type errors: rename method override parameters to match base
classes, add None guards for fetchone()/datetime, widen dict type
annotations, add type: ignore for SQLAlchemy stub limitations
- Add [tool.ty.rules] config to suppress unsupported-base warnings
- Fix _ variable shadowing gettext in wizard routes
- Add noqa: ARG002 for unused method arguments required by base class
Add created_at column to the User model, an Alembic migration to
backfill existing rows via server_default, and update the API
serialization and OpenAPI spec from the stale `created` field to
`created_at` so the joined/created date is no longer returned as null.
Security:
- Fix XSS in HTMX responses by replacing f-string HTML with Jinja partials
- Fix TLS verify_cert not being applied (add Tls config to ldap3 Server)
- Fix password_hash NOT NULL conflict for LDAP-only admin accounts
- Fix should_create_ldap_user defaulting to True for existing invitations
Correctness:
- Fix DN reconstruction fragility using escape_rdn for special characters
- Fix connection leaks with try/finally in all LDAPClient methods
- Fix sync interval logic (check FLASK_ENV not WIZARR_ENABLE_SCHEDULER)
- Only register LDAP sync job when LDAP is actually configured
- Make find_user_dn and service_connection public API methods
Cleanup:
- Squash 5 incremental LDAP migrations into single 20251226_add_ldap_support
- Remove duplicate imports/queries in auth routes
- Replace f-string logging with %s formatting
- Extract inline HTML to Jinja template partials
Introduces Telegram as a notification agent, including backend logic, form fields, and database columns for bot token and chat ID. Updates creation and editing flows, notification service, and UI to support Telegram integration. Includes a migration to add the new fields to the Notification model.
- Introduced the HistoricalImportJob model to track historical data import jobs.
- Implemented asynchronous job processing for importing historical activity data from media servers.
- Enhanced the activity settings page to allow users to specify the number of days back for historical imports.
- Added a new route to display recent historical import jobs.
- Updated the import_historical_activity function to create and manage import jobs.
- Improved UI components for displaying success and error messages related to historical imports.
- Added migration script to create the historical_import_job table in the database.
Migration Changes:
- Renamed migration file from 20251004 to 20251005
- Updated down_revision from fd5a34530162 to 08a6c8fb44db
- Ensures migration runs after upstream notification events migration
- Fixes migration chain branching issue
- Removed incorrect merge migration (1e83c67d9785)
Migration chain is now:
fd5a34530162 (disabled attribute) → 08a6c8fb44db (notification events)
→ 20251005_add_category_to_wizard_step (wizard category)
Wizard Refactoring:
- Enhanced uniqueness constraint for WizardStep from (server_type, position)
to (server_type, category, position)
- Ensures steps in different categories (pre_invite vs post_invite) can have
the same position indexing without conflict
- Updated wizard state management documentation to explicitly list and
describe data-* attributes used in steps.html template
Code Quality:
- Applied djlint formatting to 8 template files to minimize rebase conflicts
- Applied ruff format and ruff check --fix (no changes needed)
- Removed redundant requirement comments from spec-driven development
- Fixed case sensitivity in test assertion (POST vs post)
- Updated test references from 20251004 to 20251005 to match corrected
migration revision ID
- Added columns `wizarr_user_id` and `wizarr_identity_id` to the `activity_session` table.
- Created foreign key constraints for the new columns linking to `user` and `identity` tables.
- Created indexes for the new columns to improve query performance.
- Dropped the `ended_at` column from the `activity_session` table.
- Added a new `active` column to the `activity_session` table with a default value of true.
- Created an index for the `active` column to enhance query efficiency.
- Introduced `is_disabled` attribute to the User model.
- Added `expiry_action` selection in the GeneralSettingsForm for user management.
- Implemented `disable_user` methods for various media clients (Audiobookshelf, Jellyfin, Kavita, etc.) to handle user disabling.
- Updated `check_expiring` task to process expired users based on the new settings.
- Enhanced user interface to reflect disabled status in user cards.
- Added migration for the new `is_disabled` column in the user table.
- Fix test database isolation by cleaning WizardStep data before tests run
- Remove unused imports and fix import ordering
- Replace setattr with direct attribute assignment
- Use contextlib.suppress for cleaner exception handling
- Fix nested if statement in wizard_export_import.py
Fixes the failing CI checks for PR #817.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive "require interaction" functionality for wizard steps that prevents users from proceeding until they engage with step content.
## Key Features:
- **Database Integration**: New `require_interaction` boolean field in WizardStep model with migration
- **Frontend Gating**: Robust JavaScript system that disables "Next" button until user clicks links/buttons in step content
- **UI Enhancement**: Improved checkbox forms with clear descriptions and visual indicators
- **Event Handling**: Advanced interaction detection with proper HTMX disabling and event capture
- **Admin Interface**: Full integration with wizard configuration forms (main and simple)
- **Export/Import**: Support for require_interaction field in wizard step data operations
## Technical Implementation:
- Disabled button state management with pointer-events and tabindex control
- HTMX attribute manipulation to prevent premature navigation
- Event listener capture phase handling for reliable interaction blocking
- Comprehensive test coverage for interaction scenarios
- Form validation and user experience improvements
## Files Modified:
- Backend: models, routes, forms, services, migration
- Frontend: JavaScript interaction logic, templates, UI components
- Testing: Complete test suite for interaction requirements
This feature ensures users engage with critical wizard content before proceeding, improving onboarding experience and preventing accidental step skipping.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove all migration helper scripts (over-engineering)
- Revert Docker entrypoint changes (not needed)
- Clean up CLAUDE.md migration strategy section
- Keep only the essential: beautifully renamed migration files
The simple solution won: just rename the files, Alembic doesn't care about filenames!
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
BREAKING CHANGE: Migration files renamed to clean YYYYMMDD format
- Renamed 17 migrations from chaotic hash-based to clean date-based names
- Maintained all revision IDs and dependency chains
- Updated Docker entrypoint to check/log migration mappings
- All tests pass, migration chain validated and healthy
- 28/30 migrations now follow YYYYMMDD_description.py format
- Added comprehensive migration management tooling
Changes:
- migrations/versions/*: 17 files renamed to YYYYMMDD format using real creation dates
- docker-entrypoint.sh: Added migration name checker before DB migrations
- Complete 4-phase renaming strategy implemented and executed
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Updated `InvitationCreateRequest` model to change `server_ids` from required to optional with improved description.
- Enhanced `library_model` to include `external_id`, `server_name`, and `enabled` fields.
- Modified `InvitationFlowManager` to prioritize new many-to-many relationship checks for invitations.
- Created a new migration file to merge branches related to API key and foreign key improvements.
- Added comprehensive tests for API endpoints, including status, users, invitations, libraries, servers, and API key management.
- Implemented error handling tests for malformed JSON and inactive API keys.