diff --git a/docker/compose/docker-compose.portainer.yml b/docker/compose/docker-compose.portainer.yml index 000b7e66a..a44b4b692 100644 --- a/docker/compose/docker-compose.portainer.yml +++ b/docker/compose/docker-compose.portainer.yml @@ -56,6 +56,7 @@ services: environment: PAPERLESS_REDIS: redis://broker:6379 PAPERLESS_DBHOST: db + PAPERLESS_DBENGINE: postgres env_file: - stack.env volumes: diff --git a/docker/compose/docker-compose.postgres-tika.yml b/docker/compose/docker-compose.postgres-tika.yml index bf8840e4b..216c7e80b 100644 --- a/docker/compose/docker-compose.postgres-tika.yml +++ b/docker/compose/docker-compose.postgres-tika.yml @@ -62,6 +62,7 @@ services: environment: PAPERLESS_REDIS: redis://broker:6379 PAPERLESS_DBHOST: db + PAPERLESS_DBENGINE: postgresql PAPERLESS_TIKA_ENABLED: 1 PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000 PAPERLESS_TIKA_ENDPOINT: http://tika:9998 diff --git a/docker/compose/docker-compose.postgres.yml b/docker/compose/docker-compose.postgres.yml index a4b334b71..5ce15f463 100644 --- a/docker/compose/docker-compose.postgres.yml +++ b/docker/compose/docker-compose.postgres.yml @@ -56,6 +56,7 @@ services: environment: PAPERLESS_REDIS: redis://broker:6379 PAPERLESS_DBHOST: db + PAPERLESS_DBENGINE: postgresql volumes: data: media: diff --git a/docker/compose/docker-compose.sqlite-tika.yml b/docker/compose/docker-compose.sqlite-tika.yml index 3481e16a7..ee7b59e79 100644 --- a/docker/compose/docker-compose.sqlite-tika.yml +++ b/docker/compose/docker-compose.sqlite-tika.yml @@ -51,6 +51,7 @@ services: env_file: docker-compose.env environment: PAPERLESS_REDIS: redis://broker:6379 + PAPERLESS_DBENGINE: sqlite PAPERLESS_TIKA_ENABLED: 1 PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000 PAPERLESS_TIKA_ENDPOINT: http://tika:9998 diff --git a/docker/compose/docker-compose.sqlite.yml b/docker/compose/docker-compose.sqlite.yml index 362fbc9d9..37c7f0c46 100644 --- a/docker/compose/docker-compose.sqlite.yml +++ b/docker/compose/docker-compose.sqlite.yml @@ -42,6 +42,7 @@ services: env_file: docker-compose.env environment: PAPERLESS_REDIS: redis://broker:6379 + PAPERLESS_DBENGINE: sqlite volumes: data: media: diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/init-migrations/run b/docker/rootfs/etc/s6-overlay/s6-rc.d/init-migrations/run index 5d9b45740..2635fa172 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/init-migrations/run +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/init-migrations/run @@ -10,8 +10,12 @@ cd "${PAPERLESS_SRC_DIR}" # The whole migrate, with flock, needs to run as the right user if [[ -n "${USER_IS_NON_ROOT}" ]]; then + exec s6-setlock -n "${data_dir}/migration_lock" python3 manage.py check --tag compatibility paperless exec s6-setlock -n "${data_dir}/migration_lock" python3 manage.py migrate --skip-checks --no-input else + exec s6-setuidgid paperless \ + s6-setlock -n "${data_dir}/migration_lock" \ + python3 manage.py check --tag compatibility paperless exec s6-setuidgid paperless \ s6-setlock -n "${data_dir}/migration_lock" \ python3 manage.py migrate --skip-checks --no-input diff --git a/src/documents/migrations/0004_remove_document_storage_type.py b/src/documents/migrations/0003_remove_document_storage_type.py similarity index 84% rename from src/documents/migrations/0004_remove_document_storage_type.py rename to src/documents/migrations/0003_remove_document_storage_type.py index e138d5d78..2c5c70d7f 100644 --- a/src/documents/migrations/0004_remove_document_storage_type.py +++ b/src/documents/migrations/0003_remove_document_storage_type.py @@ -5,7 +5,7 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ("documents", "0003_workflowaction_order"), + ("documents", "0002_squashed"), ] operations = [ diff --git a/src/documents/migrations/0003_workflowaction_order.py b/src/documents/migrations/0003_workflowaction_order.py deleted file mode 100644 index f4c8b88e1..000000000 --- a/src/documents/migrations/0003_workflowaction_order.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.9 on 2026-01-20 20:06 - -from django.db import migrations -from django.db import models - - -class Migration(migrations.Migration): - dependencies = [ - ("documents", "0002_squashed"), - ] - - operations = [ - migrations.AddField( - model_name="workflowaction", - name="order", - field=models.PositiveIntegerField(default=0, verbose_name="order"), - ), - ] diff --git a/src/documents/migrations/0005_workflowtrigger_filter_has_any_correspondents_and_more.py b/src/documents/migrations/0004_workflowtrigger_filter_has_any_correspondents_and_more.py similarity index 95% rename from src/documents/migrations/0005_workflowtrigger_filter_has_any_correspondents_and_more.py rename to src/documents/migrations/0004_workflowtrigger_filter_has_any_correspondents_and_more.py index db5ef5754..217328eb1 100644 --- a/src/documents/migrations/0005_workflowtrigger_filter_has_any_correspondents_and_more.py +++ b/src/documents/migrations/0004_workflowtrigger_filter_has_any_correspondents_and_more.py @@ -6,7 +6,7 @@ from django.db import models class Migration(migrations.Migration): dependencies = [ - ("documents", "0004_remove_document_storage_type"), + ("documents", "0003_remove_document_storage_type"), ] operations = [ diff --git a/src/documents/migrations/0006_alter_document_checksum_unique.py b/src/documents/migrations/0005_alter_document_checksum_unique.py similarity index 89% rename from src/documents/migrations/0006_alter_document_checksum_unique.py rename to src/documents/migrations/0005_alter_document_checksum_unique.py index f86799494..7a35cbb6d 100644 --- a/src/documents/migrations/0006_alter_document_checksum_unique.py +++ b/src/documents/migrations/0005_alter_document_checksum_unique.py @@ -6,7 +6,7 @@ from django.db import models class Migration(migrations.Migration): dependencies = [ - ("documents", "0005_workflowtrigger_filter_has_any_correspondents_and_more"), + ("documents", "0004_workflowtrigger_filter_has_any_correspondents_and_more"), ] operations = [ diff --git a/src/documents/migrations/0007_document_content_length.py b/src/documents/migrations/0006_document_content_length.py similarity index 92% rename from src/documents/migrations/0007_document_content_length.py rename to src/documents/migrations/0006_document_content_length.py index c294afca5..ccc8b86d3 100644 --- a/src/documents/migrations/0007_document_content_length.py +++ b/src/documents/migrations/0006_document_content_length.py @@ -7,7 +7,7 @@ from django.db import models class Migration(migrations.Migration): dependencies = [ - ("documents", "0006_alter_document_checksum_unique"), + ("documents", "0005_alter_document_checksum_unique"), ] operations = [ diff --git a/src/documents/migrations/0008_sharelinkbundle.py b/src/documents/migrations/0007_sharelinkbundle.py similarity index 99% rename from src/documents/migrations/0008_sharelinkbundle.py rename to src/documents/migrations/0007_sharelinkbundle.py index 35ef64c75..b7c3b7223 100644 --- a/src/documents/migrations/0008_sharelinkbundle.py +++ b/src/documents/migrations/0007_sharelinkbundle.py @@ -46,7 +46,7 @@ def revoke_share_link_bundle_permissions(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("documents", "0007_document_content_length"), + ("documents", "0006_document_content_length"), ] operations = [ diff --git a/src/documents/migrations/0009_workflowaction_passwords_alter_workflowaction_type.py b/src/documents/migrations/0008_workflowaction_passwords_alter_workflowaction_type.py similarity index 95% rename from src/documents/migrations/0009_workflowaction_passwords_alter_workflowaction_type.py rename to src/documents/migrations/0008_workflowaction_passwords_alter_workflowaction_type.py index ae3fef79f..c2f241086 100644 --- a/src/documents/migrations/0009_workflowaction_passwords_alter_workflowaction_type.py +++ b/src/documents/migrations/0008_workflowaction_passwords_alter_workflowaction_type.py @@ -6,7 +6,7 @@ from django.db import models class Migration(migrations.Migration): dependencies = [ - ("documents", "0008_sharelinkbundle"), + ("documents", "0007_sharelinkbundle"), ] operations = [ diff --git a/src/documents/migrations/0010_alter_document_content_length.py b/src/documents/migrations/0009_alter_document_content_length.py similarity index 92% rename from src/documents/migrations/0010_alter_document_content_length.py rename to src/documents/migrations/0009_alter_document_content_length.py index 1e584cda9..4210426e4 100644 --- a/src/documents/migrations/0010_alter_document_content_length.py +++ b/src/documents/migrations/0009_alter_document_content_length.py @@ -7,7 +7,7 @@ from django.db import models class Migration(migrations.Migration): dependencies = [ - ("documents", "0009_workflowaction_passwords_alter_workflowaction_type"), + ("documents", "0008_workflowaction_passwords_alter_workflowaction_type"), ] operations = [ diff --git a/src/documents/migrations/0011_optimize_integer_field_sizes.py b/src/documents/migrations/0010_optimize_integer_field_sizes.py similarity index 99% rename from src/documents/migrations/0011_optimize_integer_field_sizes.py rename to src/documents/migrations/0010_optimize_integer_field_sizes.py index d656fe35e..15aadadc3 100644 --- a/src/documents/migrations/0011_optimize_integer_field_sizes.py +++ b/src/documents/migrations/0010_optimize_integer_field_sizes.py @@ -7,7 +7,7 @@ from django.db import models class Migration(migrations.Migration): dependencies = [ - ("documents", "0010_alter_document_content_length"), + ("documents", "0009_alter_document_content_length"), ] operations = [ diff --git a/src/documents/migrations/0012_alter_workflowaction_type.py b/src/documents/migrations/0011_alter_workflowaction_type.py similarity index 92% rename from src/documents/migrations/0012_alter_workflowaction_type.py rename to src/documents/migrations/0011_alter_workflowaction_type.py index 4d707937c..c31f4241c 100644 --- a/src/documents/migrations/0012_alter_workflowaction_type.py +++ b/src/documents/migrations/0011_alter_workflowaction_type.py @@ -6,7 +6,7 @@ from django.db import models class Migration(migrations.Migration): dependencies = [ - ("documents", "0011_optimize_integer_field_sizes"), + ("documents", "0010_optimize_integer_field_sizes"), ] operations = [ diff --git a/src/documents/migrations/0013_document_root_document.py b/src/documents/migrations/0012_document_root_document.py similarity index 94% rename from src/documents/migrations/0013_document_root_document.py rename to src/documents/migrations/0012_document_root_document.py index 589e125cb..c287be0dc 100644 --- a/src/documents/migrations/0013_document_root_document.py +++ b/src/documents/migrations/0012_document_root_document.py @@ -7,7 +7,7 @@ from django.db import models class Migration(migrations.Migration): dependencies = [ - ("documents", "0012_alter_workflowaction_type"), + ("documents", "0011_alter_workflowaction_type"), ] operations = [ diff --git a/src/documents/migrations/0014_alter_paperlesstask_task_name.py b/src/documents/migrations/0013_alter_paperlesstask_task_name.py similarity index 94% rename from src/documents/migrations/0014_alter_paperlesstask_task_name.py rename to src/documents/migrations/0013_alter_paperlesstask_task_name.py index 02709a4d7..46882d537 100644 --- a/src/documents/migrations/0014_alter_paperlesstask_task_name.py +++ b/src/documents/migrations/0013_alter_paperlesstask_task_name.py @@ -6,7 +6,7 @@ from django.db import models class Migration(migrations.Migration): dependencies = [ - ("documents", "0013_document_root_document"), + ("documents", "0012_document_root_document"), ] operations = [ diff --git a/src/documents/migrations/0015_savedview_visibility_to_ui_settings.py b/src/documents/migrations/0014_savedview_visibility_to_ui_settings.py similarity index 98% rename from src/documents/migrations/0015_savedview_visibility_to_ui_settings.py rename to src/documents/migrations/0014_savedview_visibility_to_ui_settings.py index bcce863b0..2a91923f3 100644 --- a/src/documents/migrations/0015_savedview_visibility_to_ui_settings.py +++ b/src/documents/migrations/0014_savedview_visibility_to_ui_settings.py @@ -124,7 +124,7 @@ def _restore_visibility_fields(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ("documents", "0014_alter_paperlesstask_task_name"), + ("documents", "0013_alter_paperlesstask_task_name"), ] operations = [ diff --git a/src/documents/migrations/0016_document_version_index_and_more.py b/src/documents/migrations/0015_document_version_index_and_more.py similarity index 94% rename from src/documents/migrations/0016_document_version_index_and_more.py rename to src/documents/migrations/0015_document_version_index_and_more.py index 9c85b05d3..5a817074c 100644 --- a/src/documents/migrations/0016_document_version_index_and_more.py +++ b/src/documents/migrations/0015_document_version_index_and_more.py @@ -7,7 +7,7 @@ from django.db import models class Migration(migrations.Migration): dependencies = [ - ("documents", "0015_savedview_visibility_to_ui_settings"), + ("documents", "0014_savedview_visibility_to_ui_settings"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] diff --git a/src/documents/tests/test_migration_saved_view_visibility.py b/src/documents/tests/test_migration_saved_view_visibility.py index c6b2fbefd..c4996761a 100644 --- a/src/documents/tests/test_migration_saved_view_visibility.py +++ b/src/documents/tests/test_migration_saved_view_visibility.py @@ -6,8 +6,8 @@ SIDEBAR_VIEWS_VISIBLE_IDS_KEY = "sidebar_views_visible_ids" class TestMigrateSavedViewVisibilityToUiSettings(TestMigrations): - migrate_from = "0013_document_root_document" - migrate_to = "0015_savedview_visibility_to_ui_settings" + migrate_from = "0013_alter_paperlesstask_task_name" + migrate_to = "0014_savedview_visibility_to_ui_settings" def setUpBeforeMigration(self, apps) -> None: User = apps.get_model("auth", "User") @@ -132,8 +132,8 @@ class TestMigrateSavedViewVisibilityToUiSettings(TestMigrations): class TestReverseMigrateSavedViewVisibilityFromUiSettings(TestMigrations): - migrate_from = "0015_savedview_visibility_to_ui_settings" - migrate_to = "0014_alter_paperlesstask_task_name" + migrate_from = "0014_savedview_visibility_to_ui_settings" + migrate_to = "0013_alter_paperlesstask_task_name" def setUpBeforeMigration(self, apps) -> None: User = apps.get_model("auth", "User") diff --git a/src/documents/tests/test_migration_share_link_bundle.py b/src/documents/tests/test_migration_share_link_bundle.py index cf52de924..1d56469ca 100644 --- a/src/documents/tests/test_migration_share_link_bundle.py +++ b/src/documents/tests/test_migration_share_link_bundle.py @@ -2,8 +2,8 @@ from documents.tests.utils import TestMigrations class TestMigrateShareLinkBundlePermissions(TestMigrations): - migrate_from = "0007_document_content_length" - migrate_to = "0008_sharelinkbundle" + migrate_from = "0006_document_content_length" + migrate_to = "0007_sharelinkbundle" def setUpBeforeMigration(self, apps) -> None: User = apps.get_model("auth", "User") @@ -24,8 +24,8 @@ class TestMigrateShareLinkBundlePermissions(TestMigrations): class TestReverseMigrateShareLinkBundlePermissions(TestMigrations): - migrate_from = "0008_sharelinkbundle" - migrate_to = "0007_document_content_length" + migrate_from = "0007_sharelinkbundle" + migrate_to = "0006_document_content_length" def setUpBeforeMigration(self, apps) -> None: User = apps.get_model("auth", "User") diff --git a/src/paperless/checks.py b/src/paperless/checks.py index 79b9d96a5..bcea6ef24 100644 --- a/src/paperless/checks.py +++ b/src/paperless/checks.py @@ -7,6 +7,7 @@ from pathlib import Path from django.conf import settings from django.core.checks import Error +from django.core.checks import Tags from django.core.checks import Warning from django.core.checks import register from django.db import connections @@ -204,15 +205,16 @@ def audit_log_check(app_configs, **kwargs): return result -@register() +@register(Tags.compatibility) def check_v3_minimum_upgrade_version( app_configs: object, **kwargs: object, ) -> list[Error]: - """Enforce that upgrades to v3 must start from v2.20.9. + """ + Enforce that upgrades to v3 must start from v2.20.10. v3 squashes all prior migrations into 0001_squashed and 0002_squashed. - If a user skips v2.20.9, the data migration in 1075_workflowaction_order + If a user skips v2.20.10, the data migration in 1075_workflowaction_order never runs and the squash may apply schema changes against an incomplete database state. """ @@ -239,7 +241,7 @@ def check_v3_minimum_upgrade_version( if {"0001_squashed", "0002_squashed"} & applied: return [] - # On v2.20.9 exactly — squash will pick up cleanly from here + # On v2.20.10 exactly — squash will pick up cleanly from here if "1075_workflowaction_order" in applied: return [] @@ -250,8 +252,8 @@ def check_v3_minimum_upgrade_version( Error( "Cannot upgrade to Paperless-ngx v3 from this version.", hint=( - "Upgrading to v3 can only be performed from v2.20.9." - "Please upgrade to v2.20.9, run migrations, then upgrade to v3." + "Upgrading to v3 can only be performed from v2.20.10." + "Please upgrade to v2.20.10, run migrations, then upgrade to v3." "See https://docs.paperless-ngx.com/setup/#upgrading for details." ), id="paperless.E002", diff --git a/src/paperless/settings/custom.py b/src/paperless/settings/custom.py index 32b3aa364..5459576c3 100644 --- a/src/paperless/settings/custom.py +++ b/src/paperless/settings/custom.py @@ -209,7 +209,6 @@ def parse_db_settings(data_dir: Path) -> dict[str, dict[str, Any]]: engine = get_choice_from_env( "PAPERLESS_DBENGINE", {"sqlite", "postgresql", "mariadb"}, - default="sqlite", ) except ValueError: # MariaDB users already had to set PAPERLESS_DBENGINE, so it was picked up above diff --git a/src/paperless/tests/test_checks.py b/src/paperless/tests/test_checks.py index 14950e2ca..3572f02a4 100644 --- a/src/paperless/tests/test_checks.py +++ b/src/paperless/tests/test_checks.py @@ -581,11 +581,11 @@ class TestV3MinimumUpgradeVersionCheck: ) -> None: """ GIVEN: - - DB is on an old v2 version (pre-v2.20.9) + - DB is on an old v2 version (pre-v2.20.10) WHEN: - The v3 upgrade check runs THEN: - - The error hint explicitly references v2.20.9 so users know what to do + - The error hint explicitly references v2.20.10 so users know what to do """ mocker.patch.dict( "paperless.checks.connections", @@ -593,7 +593,7 @@ class TestV3MinimumUpgradeVersionCheck: ) result = check_v3_minimum_upgrade_version(None) assert len(result) == 1 - assert "v2.20.9" in result[0].hint + assert "v2.20.10" in result[0].hint def test_db_error_is_swallowed(self, mocker: MockerFixture) -> None: """