- Add Privacy Policy, Terms of Service, and Imprint links to WelcomeScreen
and LoginScreen for GDPR/Apple compliance (pre-login access)
- Enable multiple image selection in photo library picker
- Add HEIC/HEIF image support to backend (allowed_types, convert_to_pdf, upload handler)
- Create FileDetailScreen with processing status and logs
- Add search bar to FilesScreen with debounced search
- Set up i18n with expo-localization (EN, DE, ES, FR, IT)
- Add language selector to ProfileScreen settings
- Add Imprint link to ProfileScreen legal section
- Update docs and tests
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Move duplicate check before task enqueue in ui_upload endpoint
- Clean up temp file and return status "duplicate" for exact duplicates
- Add URI-level dedup guard in mobile UploadScreen to prevent repeated uploads
- Improve ShareContext URI normalization (collapse slashes, decode percent-encoding)
- Guard +not-found.tsx effect against re-firing for the same pathname
- Update mobile UploadResponse type and handlers for duplicate status
- Update web frontend upload.js to show duplicate status
- Update API and Configuration docs
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
Merge origin/main into branch, resolving conflict in app/database.py.
Combined improvements from both branches:
- Keep pool_pre_ping=True and structured variable approach from feature branch
- Add explicit QueuePool import and poolclass assignment from main
The QR code on /qr-login was not rendering because it depended on loading
qrcode@1.5.4 from the jsdelivr CDN, which may be blocked in some network
environments.
- Add segno>=1.6.0 (pure-Python QR library, no Pillow needed) to requirements.txt
- Generate QR code as a base64 SVG data URI server-side in the challenge endpoint
- Add qr_code_svg field to CreateChallengeResponse Pydantic model
- Replace canvas+CDN script in qr_login.html with an <img :src="qrCodeSvg">
- Remove the $nextTick/QRCode.toCanvas() client-side rendering block
- Extract QR rendering parameters (_QR_ERROR_LEVEL, _QR_SCALE) as module constants
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Add db_pool_size, db_max_overflow, db_pool_timeout, db_pool_recycle fields to app/config.py
- Add upload_rate_limit_per_user, upload_rate_limit_window fields to app/config.py
- Update app/database.py to use NullPool for SQLite and QueuePool with config-driven
pool settings for PostgreSQL/MySQL
- Add all 6 settings to SETTING_METADATA in app/utils/settings_service.py
Fixes test_all_config_settings_have_metadata failure
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
Add missing SETTING_METADATA entries for db_pool_size, db_max_overflow,
db_pool_timeout, db_pool_recycle, upload_rate_limit_per_user, and
upload_rate_limit_window so the test_all_config_settings_have_metadata
test passes.
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
Introduces a Redis-backed sliding-window rate limiter for upload
endpoints (/api/ui-upload, /api/process-url) that:
- Enforces per-user limits (default: 20 uploads / 60 s)
- Dynamically reduces limits under system stress (queue depth, CPU load)
- Returns 429 with Retry-After header when exceeded
- Fails open when Redis is unavailable
- Works with the existing client-side adaptive back-off
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
SQLite engines now use NullPool instead of QueuePool, eliminating the
"QueuePool limit of size 5 overflow 10 reached" TimeoutError under
concurrent load. PostgreSQL/MySQL engines use a configurable QueuePool
with sensible defaults (pool_size=10, max_overflow=20) exposed via
DB_POOL_SIZE, DB_MAX_OVERFLOW, DB_POOL_TIMEOUT, DB_POOL_RECYCLE env
vars. pool_pre_ping is enabled on all backends.
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
The QR login page countdown timer compared the server's UTC expiration
timestamp against the client's local clock, causing the QR code to appear
immediately expired when the client clock was ahead of the server.
Changes:
- Add ttl_seconds field to CreateChallengeResponse (seconds until expiry)
- Frontend countdown now uses relative elapsed time since response was
received, eliminating clock-skew issues
- Mobile app: replace alert-only QR button with actual camera-based
QR code scanner using expo-camera
- Add QRScannerScreen with barcode scanning, permission handling, and
scan area overlay
- Update camera permission description to mention QR code scanning
- Add tests for ttl_seconds computation
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Add path traversal guard in reimport file copy loop
- Improve error log message context for table wipe failures
- Use conditional role=alert/status on result banner for accessibility
- Make test assertions more specific (exact status codes)
- Rename ambiguous view test
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Add UserSession and QRLoginChallenge models for session tracking
and mobile QR authentication
- Add session_manager utility with create/validate/revoke/cleanup
functions and QR challenge helpers
- Add /api/sessions endpoints for listing, revoking, and
'log off everywhere' functionality
- Add /api/qr-auth endpoints for challenge creation, polling, and
claiming with API token issuance
- Add session config fields (lifetime, custom override, QR TTL)
- Update get_current_user to validate server-side sessions
- Create server-side sessions on all login paths (local, OAuth,
social, admin)
- Revoke server-side session on logout
- Configure SessionMiddleware max_age from session lifetime settings
- Graceful degradation: old sessions without _session_token continue
to work
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Merge origin/main into copilot/add-sharepoint-integration.
All four conflicts were resolved by keeping both the SharePoint
additions (from this branch) and the iCloud additions (from main):
- app/models.py: added both SHAREPOINT and ICLOUD to IntegrationType
- app/tasks/send_to_all.py: added both to service_map and services list
- app/tasks/upload_to_user_integration.py: kept both upload handlers
- frontend/templates/files.html: added both filter options
No database migration conflicts — SharePoint does not require schema changes.
The per-user notification functions (notify_user_document_processed /
notify_user_document_failed) were defined but never called from the
document processing pipeline.
- Call notify_user_document_processed in finalize_document_storage
when owner_id is available (creates in-app + email/webhook notifications)
- Add _dispatch_user_failure_notification helper to celery_app.py that
extracts file_id from failed task args and dispatches
notify_user_document_failed for document pipeline tasks
- Add comprehensive tests for both success and failure notification paths
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
Windows does not render regional indicator emoji as graphical flags,
showing raw text (DE, GB) instead. Replace all emoji flag values in
SUPPORTED_LANGUAGES with lowercase ISO 3166-1 alpha-2 country codes,
add the flag-icons@7.3.2 CSS library via CDN, and update templates to
render <span class="fi fi-{code}"> instead of emoji text.
Special cases:
- Welsh (cy): uses flag-icons region code "gb-wls"
- Catalan (ca): falls back to "es" (no dedicated ISO flag)
- Esperanto (eo): uses "un" (UN flag for international language)
<option> elements in profile.html no longer display flags since CSS
icon classes cannot be applied inside native <option> tags.
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Import translate_to_default_language in celery_worker.py
- Add default_document_language to SETTING_METADATA in settings_service.py
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- audit_logs.py: Remove _db_dep pattern that fails with latest FastAPI on
Python 3.11. Use clean DbSession = Annotated[Session, Depends(get_db)]
without default values.
- billing.py: Remove owner_id from log messages to fix CodeQL clear-text
logging of sensitive information alerts.
- files.py: Remove owner_id from log messages to fix CodeQL clear-text
logging of sensitive information alerts.
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
get_current_owner_id() only checked the session for authenticated users.
When the mobile app sends Authorization: Bearer <token>, there is no
session cookie, so the Depends(_get_owner_id) dependency raised HTTP 401
before the @require_login wrapper could resolve the Bearer token.
The function now checks three sources in order:
1. Session user dict (existing behavior)
2. request.state.api_token_user (cached by require_login or prior call)
3. Direct Bearer token resolution via _resolve_bearer_user (new)
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>