Commit Graph

329 Commits

Author SHA1 Message Date
Christian Krakau-Louis 0134ed37d5 Merge pull request #446 from christianlouis/copilot/optimize-test-timeouts
fix(ci): split test pipeline into quick/integration stages, fix hanging test
2026-03-01 18:23:06 +01:00
Christian Krakau-Louis 8ac4179b8b Merge pull request #445 from christianlouis/copilot/enforce-database-upgrades-migration
refactor(database): enforce Alembic-only schema migrations, deprecate manual migration code
2026-03-01 18:22:48 +01:00
copilot-swe-agent[bot] 8d81ed6c74 fix: address code review feedback - use specific exceptions, dynamic revision IDs in tests
- Replace bare Exception catches with sa.exc.OperationalError in migration 007
- Use ScriptDirectory.get_heads() for dynamic revision ID assertions in tests
- Make migration count assertion flexible (>= 8 instead of == 8)
- Rewrite pending migrations test to actually test upgrade from revision 006

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 16:57:19 +00:00
copilot-swe-agent[bot] 87d1b9d935 refactor(database): enforce Alembic-only database migrations, deprecate manual schema migrations
- Create alembic.ini and migrations/env.py for full Alembic CLI + programmatic support
- Add Alembic migration 006: detail column on processing_logs
- Add Alembic migration 007: ocr_quality_score column + drop unique filehash index
- Add Alembic migration 008: performance indexes
- Replace _run_schema_migrations() call in init_db() with _run_alembic_upgrade()
- Deprecate _run_schema_migrations() with DeprecationWarning
- Update tests for new Alembic-based approach and deprecation
- Update DatabaseConfiguration.md documentation

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 16:47:41 +00:00
copilot-swe-agent[bot] 6a21adcdd4 fix(ci): increase quick test job timeout to 15 minutes for CI runner headroom
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 16:46:57 +00:00
copilot-swe-agent[bot] c100250b23 docs: update CI workflow and integration test documentation for two-stage pipeline
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 16:45:44 +00:00
copilot-swe-agent[bot] 6c643e9962 fix(ci): add pytest-timeout, fix hanging test, split CI into quick + integration stages
- Add pytest-timeout>=2.3.0 to requirements-dev.txt with 120s global default
- Fix test_fallback_file_id_lookup: add missing _should_upload_* mocks that
  caused .delay() calls to hang on Redis broker connection
- Split CI test job into two stages:
  - Quick Tests (timeout: 10min, ~2min run): unit + basic integration
  - Integration Tests (timeout: 20min): Docker containers, external services
- Quick tests gate integration tests for fast-fail feedback
- Build job now depends on both test stages

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 16:43:56 +00:00
Christian Krakau-Louis 91bd4ad837 Merge pull request #444 from christianlouis/copilot/optimize-database-queries
fix(db): check column existence before creating indexes; fix mypy error in cache.py
2026-03-01 17:27:03 +01:00
copilot-swe-agent[bot] ce87b53331 style: fix spelling (British to American English)
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 14:41:29 +00:00
copilot-swe-agent[bot] d5a95e9270 docs: add Performance & Caching section to ConfigurationGuide
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 14:40:19 +00:00
copilot-swe-agent[bot] b79ba81e05 perf(db): add indexes on query-hot columns and Redis caching layer
- Add database indexes on FileRecord.created_at, FileRecord.mime_type,
  ProcessingLog.file_id, ProcessingLog.timestamp, and
  FileProcessingStep.status for faster filtering, sorting, and joins.
- Add _ensure_indexes() migration for existing databases.
- Create app/utils/cache.py with fail-open Redis GET/SET/DELETE helpers.
- Cache MIME types dropdown query in files view (120s TTL).
- Optimize batch status query to load only needed columns.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 14:38:28 +00:00
copilot-swe-agent[bot] f8c5dd539d feat(imap): add IMAP_READONLY_MODE feature flag to safeguard shared mailboxes
When enabled, IMAP processing will fetch and process attachments but
will NOT modify the mailbox state (no starring, labeling, deleting,
or flag changes). This allows preprod instances to safely share a
Gmail inbox with production without interfering with production
email processing.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 14:28:51 +00:00
Christian Krakau-Louis 96b14ec74f Merge pull request #440 from christianlouis/copilot/update-search-functionality
feat(search): add content-finding filters, saved searches, and text quality to Search view
2026-03-01 15:19:57 +01:00
copilot-swe-agent[bot] 83c3405c98 feat: persist ocr_quality_score and use it for numeric filtering
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 13:46:43 +00:00
copilot-swe-agent[bot] 5bf0a4c0b9 feat(search): add content-finding filters, saved searches, and text quality to Search view
- Add tags, sender, text_quality filters to search API and Meilisearch client
- Add sender and ocr_text_length to Meilisearch filterable attributes
- Expand saved search allowed filter keys to include q, document_type, language, sender, text_quality
- Add filters panel and saved searches UI to the Search view template
- Add tests for new search filters, saved search keys, and search view elements

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 13:46:15 +00:00
copilot-swe-agent[bot] 705b970522 feat: add bulk download, cloud OCR, and basic OCR quality filter
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 13:38:42 +00:00
Christian Krakau-Louis 05c35a6775 Merge pull request #437 from christianlouis/copilot/add-file-download-endpoint
fix(api): change download endpoint default version from `original` to `processed`
2026-03-01 13:30:30 +01:00
copilot-swe-agent[bot] e5a4c6c64a feat(api): add advanced filtering and saved searches
- Add date range (date_from/date_to), storage provider, and tags filters to GET /api/files
- Add SavedSearch model and migration (005_add_saved_searches)
- Add CRUD API endpoints for saved searches at /api/saved-searches
- Update files.html template with new filter controls and saved searches UI
- Update files view to pass new filter parameters to template
- Add comprehensive tests for all new functionality (26 tests)

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 11:22:07 +00:00
copilot-swe-agent[bot] 7b5494bafb feat(api): default download endpoint to processed file version
- Change default `version` param from 'original' to 'processed' so
  GET /api/files/{id}/download (no param) returns the processed file
- Update docstring to reflect new default
- Add tests: ?version=processed, default→processed, invalid→400
- Fix test_file_download_missing_mime_type to use explicit ?version=original
- Add File Download section to docs/API.md

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 11:15:14 +00:00
copilot-swe-agent[bot] d095e30467 fix: address code review feedback on tests and placeholder messages
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 07:51:07 +00:00
copilot-swe-agent[bot] 7a8ccba9be test(preview): add 23 tests for document preview features
Also updates UserGuide.md with documentation for pdf.js viewer,
image zoom/pan, text preview, and the file-list preview modal.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-01 07:42:48 +00:00
copilot-swe-agent[bot] 2f442b0906 test: improve upload retry tests with legacy path assertions and priority verification
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-28 12:57:50 +00:00
copilot-swe-agent[bot] bb98afac82 fix(api): use processed_file_path from DB in upload retry path resolution
The upload retry logic now checks file_record.processed_file_path first
(the GPT-suggested filename stored during finalization), before falling
back to legacy hash-based and original-filename-based path patterns.

This fixes the case where the processed file has a different name than
the original (e.g., '2023-10-01_Unknown.pdf' vs 'cable_graphic.pdf')
and the retry couldn't find the file on disk.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-28 12:56:01 +00:00
copilot-swe-agent[bot] 4fdb1b8d85 fix: address code review feedback - restrict terminal step check to success only, add test assertions
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-27 16:39:32 +00:00
copilot-swe-agent[bot] 2c55f076be fix(tasks): resolve files stuck in Pending status despite completed processing
The status calculation required ALL steps to be explicitly marked as
success/skipped before a file could be "completed". This failed for
dynamic pipelines where:

1. check_for_duplicates was logged before the file record existed (no
   file_id), so its FileProcessingStep was never updated from "pending"
2. extract_text was not marked as "skipped" for non-PDF files that go
   through PDF conversion first

Fix:
- Move check_for_duplicates success log to after initialize_file_steps()
  with the correct file_id so the step actually gets updated
- Mark extract_text as "skipped" for non-PDF files
- Add terminal-step fallback: if send_to_all_destinations is "success",
  the file is "completed" even if intermediate steps remain "pending"
  (handles any other dynamic pipeline edge cases)

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-27 16:38:10 +00:00
Christian Krakau-Louis c0d19a5398 Merge pull request #429 from christianlouis/copilot/fix-complete-status-error
fix(tests): align "completed" test fixtures with terminal-step guard semantics
2026-02-27 10:22:39 +01:00
copilot-swe-agent[bot] aba47af30a test: add send_to_all_destinations step to test_status_filter_completed
The terminal-step guard requires send_to_all_destinations: success before
a file is considered "completed". Update test_status_filter_completed to
include this step so it matches the new semantics.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-27 01:08:26 +00:00
copilot-swe-agent[bot] 9795ca0d52 test: update 3 tests broken by terminal-step completed guard
The previous fix (requiring send_to_all_destinations to be present
before marking a file as completed) broke 3 tests that used only
partial step sets and expected "completed":

- test_coverage_polish.py::TestFileQueriesDeduplicationEnabled::
  test_deduplication_enabled_adds_check_for_duplicates
- test_file_listing.py::TestFileListingPagination::
  test_processing_status_included
- test_file_listing.py::TestFileDetailEndpoint::
  test_file_detail_status_determination

Add send_to_all_destinations: success to each test's dataset so
"completed" status is reached correctly under the new semantics.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-27 01:04:42 +00:00
copilot-swe-agent[bot] e6dd39c27d fix(status): prevent false Completed status when mandatory pipeline steps have not run
Add a terminal-step guard (send_to_all_destinations) to all status
calculation paths so that files are only marked Completed once the
entire processing pipeline has been recorded.

- get_file_overall_status: require TERMINAL_STEP to be present
- get_files_processing_status: same guard for bulk status
- get_step_summary: count missing terminal step as queued so
  total_main_steps > main_completed when pipeline is incomplete
- apply_status_filter: SQL sub-query requires terminal step for
  completed filter
- process_document: call initialize_file_steps after creating a new
  file record so all mandatory steps are pre-created as pending

Define TERMINAL_STEP constant in step_manager.py and reference it in
file_status.py and file_queries.py to avoid magic strings.

Tests updated: add send_to_all_destinations to completed-file
fixtures; add test verifying initialize_file_steps is called for
new files.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-27 00:51:14 +00:00
copilot-swe-agent[bot] 4dd018f210 refactor(queue): address code review feedback — extract constants and sync refresh interval
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-27 00:47:58 +00:00
copilot-swe-agent[bot] c7c5718f78 feat(queue): add queue monitoring dashboard and pending banner on files page
- Add /api/queue/stats endpoint with Redis queue lengths, Celery worker
  inspection, and DB processing summaries
- Add /api/queue/pending-count lightweight endpoint for the files page banner
- Add /admin/queue admin-only view with auto-refreshing queue dashboard
- Add queue pending banner on /files page showing queued/processing count
- Add Queue Monitor link to admin dropdown in navigation (desktop + mobile)
- Add comprehensive tests for all new endpoints and views

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-27 00:42:55 +00:00
copilot-swe-agent[bot] 4a251fd3ca fix(test): update drop overlay text assertion to match new directory-upload message
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-26 23:50:46 +00:00
copilot-swe-agent[bot] a05690bd5f feat(upload): adaptive 429 backoff, full Gotenberg file types, directory traversal
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-26 23:24:26 +00:00
copilot-swe-agent[bot] 36b668020b fix(tests): fix OAuth integration tests failing due to Docker registry timeout
The mock_oauth_server session fixture tried to pull ghcr.io/navikt/mock-oauth2-server:2.1.1
from Docker, which times out in sandboxed CI, causing all 14 OAuth integration tests to ERROR.

Changes to tests/conftest_oauth.py:
- mock_oauth_server: catch container startup exceptions, attempt cleanup, yield None
  instead of propagating (static fallback config is used instead)
- oauth_config: add elif mock_oauth_server is None branch returning a static hardcoded
  config (mode="static") using module-level URL constants
- oauth_enabled_app: use authorize_url/access_token_url directly (no HTTP metadata
  discovery), clear/restore authlib _clients/_registry cache per test, add cleanup in teardown
- Extract _STATIC_OAUTH_* constants to avoid URL duplication

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-26 14:21:58 +00:00
copilot-swe-agent[bot] 44dcabd1f3 fix(tests): fix TestGetFullConfigException using PropertyMock on module-level settings
The test was using patch.object(type(settings), "onedrive_client_id", property(...))
to make settings.onedrive_client_id raise. Pydantic v2 Settings fields are not plain
Python descriptors so this approach raises AttributeError.

Fix: patch app.api.onedrive.settings with a MagicMock whose onedrive_client_id
is a PropertyMock(side_effect=Exception), which correctly triggers the except
branch in get_onedrive_full_config and returns {"status": "error"}.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-26 12:04:38 +00:00
copilot-swe-agent[bot] b4e93c00b4 fix(tests): fix test_save_settings_outer_exception in OneDrive coverage tests
The test was patching os.path.join, which is called inside an inner
try/except block in save_onedrive_settings. This meant the exception
was silently caught and logged, never reaching the outer exception
handler that returns HTTP 500.

Fix by patching notify_settings_updated instead, which is called in
the outer try block, so exceptions correctly propagate to the outer
handler.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-26 11:02:16 +00:00
Christian Krakau-Louis a64de0a6cb Merge pull request #420 from christianlouis/copilot/improve-code-coverage-tests
fix(tests): correct mock patch targets in google_drive coverage tests
2026-02-26 11:46:03 +01:00
copilot-swe-agent[bot] 09a6337c6f fix(ui): prevent search input from clearing on each keystroke and add dedicated /search page
The debounceSearch() function in files.html called clearFullTextSearch()
when the query was shorter than 2 characters. Since clearFullTextSearch()
sets input.value = '', every single keystroke was immediately erased —
users could paste text but not type.

Fix: debounceSearch now only hides the results panel for short queries
without touching the input value.

Also adds a dedicated /search page with Google-style results showing
content previews (document title, filename, type badges, tag badges,
sender, and OCR text snippets with highlighted matches).

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-26 09:18:28 +00:00
copilot-swe-agent[bot] c6ac6b50e9 fix(tests): use targeted settings mock instead of broad getattr patch
Replace module-level getattr patch with a MagicMock that has a property
raising on google_drive_use_oauth access, as suggested by code review.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-26 09:16:49 +00:00
copilot-swe-agent[bot] 096aedb8a0 fix(tests): correct mock patch targets in google_drive coverage tests
- Change @patch("app.api.google_drive.get_google_drive_service") to
  @patch("app.tasks.upload_to_google_drive.get_google_drive_service")
  because the function is imported locally inside the endpoint function
  body, not at module level
- Replace patch.object(type(settings), "google_drive_use_oauth", ...)
  with patch("app.api.google_drive.getattr", ...) because Pydantic v2
  models don't expose fields as regular class attributes

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-26 09:14:08 +00:00
copilot-swe-agent[bot] ffa0e1eb7b test(coverage): add celery_worker coverage and remove dead config_validator.py
- Rewrite tests/test_celery_worker.py to mock check_credentials.apply_async
  at import time, enabling all 35 statements to be covered without Redis
- Add tests for conditional beat schedule entries (IMAP, Uptime Kuma)
- Delete app/utils/config_validator.py — dead code shadowed by the
  config_validator/ package directory (Python gives packages precedence)
- Remove both files from coverage omit in pyproject.toml
- celery_worker.py now at 100% coverage (was 0%)

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-25 21:08:24 +00:00
Christian Krakau-Louis e58b58537d Merge pull request #415 from christianlouis/copilot/increase-test-coverage-modules
test(coverage): add coverage tests for onedrive and google_drive API modules
2026-02-25 17:43:04 +01:00
Christian Krakau-Louis 3635e97dbd Merge pull request #416 from christianlouis/copilot/improve-test-coverage-mid-range-files
test: improve coverage for process_with_ocr, api/settings, and settings_service to 90%+
2026-02-25 17:42:03 +01:00
Christian Krakau-Louis 1bb463f719 Merge pull request #417 from christianlouis/copilot/polish-coverage-to-90-percent
test(coverage): push coverage to 95%+ for 11 target files
2026-02-25 17:41:43 +01:00
github-actions[bot] 69cb16c522 style: apply ruff auto-fix
- Auto-formatted code with ruff format
- Applied ruff linting fixes with --fix

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-25 15:43:40 +00:00
copilot-swe-agent[bot] e3cd687757 test(coverage): add coverage tests for app/api/onedrive.py and app/api/google_drive.py
Add targeted tests covering uncovered lines:
- OneDrive: token refresh failure, token rotation with .env update,
  DB persist failure, user info failure, exception handlers
- Google Drive: service account test-token paths, update settings
  exception handler, get-token-info outer exception

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-25 15:41:01 +00:00
copilot-swe-agent[bot] 759647f957 test(coverage): add tests to push coverage above 95% for 11 target files
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-25 15:36:46 +00:00
copilot-swe-agent[bot] d9abbc1c99 test: improve coverage for process_with_ocr, api/settings, and settings_service to 90%+
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-25 15:24:42 +00:00
copilot-swe-agent[bot] 0821e2f989 feat(privacy): implement GDPR and global privacy compliance
- Add dismissable cookie notice banner to base template (essential
  cookies only, ePrivacy Directive compliant, localStorage persistence)
- Expand Privacy Notice to cover all target markets: EU/GDPR,
  UK GDPR, Switzerland nFADP, Ukraine, US CCPA/CPRA, Canada PIPEDA/
  Law 25, Brazil LGPD/Latin America, and Asia-Pacific & Japan (APPI,
  Australia Privacy Act, South Korea PIPA, Singapore PDPA, India DPDP)
- Add International Data Transfers section (SCCs, IDTAs, adequacy
  decisions) and Data Minimization & Purpose Limitation section
- Update Cookie Policy with precise cookie table, ePrivacy exemption
  rationale, and localStorage notice dismissal documentation
- Create docs/PrivacyCompliance.md: full multi-market compliance guide
  covering cookie strategy, data transfer mechanisms, data subject
  rights handling matrix with response timelines, and market-specific
  notes for all supported regions
- Add docs/PrivacyCompliance.md to mkdocs.yml Compliance nav section
- Add 10 new targeted tests to test_views_general.py validating all
  key compliance content areas

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-25 15:15:24 +00:00
copilot-swe-agent[bot] db581ba355 fix(database): add runtime migrations for ocr_text, ai_metadata, document_title columns
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-02-25 14:37:56 +00:00