Keep form-based invitation screens open on account creation failures so users can see errors without replaying the welcome animation.
Centralize join form template context, preserve theming across invite routes, and add regression coverage for validation and E2E flows.
Commit 73c29458f renamed library_id/limit to _library_id/_limit to
suppress ARG002 warnings, but the widget caller passes them as keyword
arguments (limit=6), causing a silent TypeError that returns empty data.
Closes#1207
- 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
- Fix SUBTREE→BASE scope in _fetch_user_attributes (security)
- Remove is_ldap_user threading from all 8 media client interfaces;
set flag after join via workflow-level User.query.update instead
- Use find_user_dn (search-based) instead of build_user_dn (concatenation)
in delete_user and reset_user_password for robustness
- Wrap all user-facing strings in _() for i18n in ldap_auth.py
- Fix username fallback from hardcoded "wizarr" to unique per-user
- Return failure from _update_existing_user when password update fails
- Replace dynamic Tailwind classes with explicit conditionals in alert
- Add stale group cleanup and upsert in sync_ldap_groups
- Remove fake @ldap.local email fallback in user_sync
- Change EmbyClient.libraries() to return {Id: Name} instead of {Guid: Name}
so Library.external_id stores the value Emby's EnabledFolders policy field
expects, matching what JellyfinClient._set_specific_folders() resolves.
- Change EmbyClient.scan_libraries() to return {Name: Id} instead of
{Name: Guid} for the same reason.
- Override _set_specific_folders() in EmbyClient with a mapping that includes
{Name: Id}, {Id: Id}, and {Guid: Id} entries, providing backwards
compatibility for existing Library records that still hold a Guid.
- In both EmbyClient._set_specific_folders() and the inherited
JellyfinClient._set_specific_folders(), when the input names list is
non-empty but all lookups fail (folder_ids ends up empty), log a structured
WARNING via structlog and set EnableAllFolders: False with an empty
EnabledFolders list — restricting access to nothing — rather than silently
falling back to EnableAllFolders: True which would grant full access.
- Replace inline debug logging.info() calls with structlog structured events.
When a user who already has a Plex share uses a new invite link, the
"already sharing" error from the Plex API is now handled gracefully by
calling update_user_libraries() and update_user_permissions() instead of
propagating the error to the end-user. The route layer also switches to
a generic, translatable user-facing error message backed by structlog for
admin-visible diagnostics.
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
- Added a preview link for bundles in the wizard settings page. closes#1048
- Enhanced the wizard steps template to handle bundle preview mode.
- Updated JavaScript to generate URLs for bundle preview and runtime modes.
- Improved test coverage for password reset token generation by asserting token creation.
- A new API endpoint for requesting a password reset token, which can be accessed either through an API key or an authenticated session.
- A public route for handling the password reset process using the generated token.
- Updates media client to allow password resets.
fix: correct key for transcoding info in admin routes
feat: enhance Jellyfin client to extract additional session and media details
fix: update template to reflect changes in transcoding info structure
chore: update submodule reference for plus
- Added `identity_resolution.py` for resolving Wizarr users and identities.
- Created `ingestion.py` to handle recording and updating activity events.
- Introduced `maintenance.py` for cleanup and session management tasks.
- Developed `queries.py` for read-oriented operations on activity sessions.
- Implemented background tasks in `activity.py` for scheduled maintenance.
- Added tests for activity services and blueprint to ensure functionality.
- 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.
+ Much clearer separation of enable and disable (fixing the earlier terrible idea)
+ Audiobookshelf, jellyfin and romm now have enable user logic in the enable_user func
+ POST /users/<user_id>/enable added
+ Most service's enable_user implementation informs the user that enabling is not supported
+ Audiobookshelf, Jellyfin and RomM can now both disable and enable users
+ Since the few platforms that natively support disabling/enabling users use the same endpoints, disable_user has been given an optional boolean param called enable which defaults to false. This reduces the need of any working enable_user funcs to have a nearly identical implementation.
+ Jellyfin's disable_user now fetches raw user from Jellyfin for the user's original policies, then updates IsDisabled to true
+ Optional parameter "enable" added, default false (for future use with enable endpoint)
- Implemented LicenseValidationMiddleware for periodic license validation and feature protection.
- Created HistoricalDataService for importing historical viewing data from Plex into the ActivitySession model.
- Added KeygenLicenseService for runtime license verification and machine fingerprinting.
- Introduced new Jinja filters for built-in functions max and min.
- Updated settings UI to include a tab for Plus features.
- Added Docker support for Wizarr Plus with a dedicated docker-compose file.
- Created entrypoint script for license verification and initialization of the Wizarr Plus container.
- Added wrapper scripts for building, verifying licenses, and setting up Wizarr Plus.
- Updated dependencies in pyproject.toml to include websocket-client for Plus features.