diff --git a/pyproject.toml b/pyproject.toml index 12cd9555b..0ab1a6072 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "paperless-ngx" -version = "3.0.1" +version = "3.0.2" description = "A community-supported supercharged document management system: scan, index and archive all your physical documents" readme = "README.md" requires-python = ">=3.11" diff --git a/src-ui/package.json b/src-ui/package.json index f71c3c68a..5c029d261 100644 --- a/src-ui/package.json +++ b/src-ui/package.json @@ -1,6 +1,6 @@ { "name": "paperless-ngx-ui", - "version": "3.0.1", + "version": "3.0.2", "scripts": { "preinstall": "npx only-allow pnpm", "ng": "ng", diff --git a/src-ui/src/environments/environment.prod.ts b/src-ui/src/environments/environment.prod.ts index 076717c59..93c63e8b4 100644 --- a/src-ui/src/environments/environment.prod.ts +++ b/src-ui/src/environments/environment.prod.ts @@ -8,7 +8,7 @@ export const environment = { apiVersion: '10', // match src/paperless/settings.py appTitle: DEFAULT_APP_TITLE, tag: 'prod', - version: '3.0.1', + version: '3.0.2', webSocketHost: window.location.host, webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:', webSocketBaseUrl: base_url.pathname + 'ws/', diff --git a/src/paperless/version.py b/src/paperless/version.py index c06b79158..7af50ba81 100644 --- a/src/paperless/version.py +++ b/src/paperless/version.py @@ -1,6 +1,6 @@ from typing import Final -__version__: Final[tuple[int, int, int]] = (3, 0, 1) +__version__: Final[tuple[int, int, int]] = (3, 0, 2) # Version string like X.Y.Z __full_version_str__: Final[str] = ".".join(map(str, __version__)) # Version string like X.Y diff --git a/src/paperless_mail/migrations/0001_1_clamp_mailrule_maximum_age.py b/src/paperless_mail/migrations/0001_1_clamp_mailrule_maximum_age.py deleted file mode 100644 index 4b195b746..000000000 --- a/src/paperless_mail/migrations/0001_1_clamp_mailrule_maximum_age.py +++ /dev/null @@ -1,27 +0,0 @@ -# Split out of 0002_optimize_integer_field_sizes.py into its own migration -# (own transaction). Running this UPDATE in the same transaction as the -# later ALTER TABLE on paperless_mail_mailrule can fail on PostgreSQL with -# "cannot ALTER TABLE because it has pending trigger events", since the -# update queues FK trigger events against that table that are still pending -# when the subsequent AlterField tries to rewrite it. Committing the clamp -# here first avoids that. -from django.db import migrations - - -def clamp_mailrule_maximum_age(apps, schema_editor): - # Clamp the maximum_age field of MailRule because of PositiveIntegerField --> PositiveSmallIntegerField - MailRule = apps.get_model("paperless_mail", "MailRule") - MailRule.objects.filter(maximum_age__gt=32767).update(maximum_age=32767) - - -class Migration(migrations.Migration): - dependencies = [ - ("paperless_mail", "0001_squashed"), - ] - - operations = [ - migrations.RunPython( - clamp_mailrule_maximum_age, - migrations.RunPython.noop, - ), - ] diff --git a/src/paperless_mail/migrations/0002_optimize_integer_field_sizes.py b/src/paperless_mail/migrations/0002_optimize_integer_field_sizes.py index f42dafe36..0542d1429 100644 --- a/src/paperless_mail/migrations/0002_optimize_integer_field_sizes.py +++ b/src/paperless_mail/migrations/0002_optimize_integer_field_sizes.py @@ -4,9 +4,19 @@ from django.db import migrations from django.db import models +def clamp_mailrule_maximum_age(apps, schema_editor): + # Clamp the maximum_age field of MailRule because of PositiveIntegerField --> PositiveSmallIntegerField + MailRule = apps.get_model("paperless_mail", "MailRule") + MailRule.objects.filter(maximum_age__gt=32767).update(maximum_age=32767) + + class Migration(migrations.Migration): + # The data update must commit before PostgreSQL rewrites the table, otherwise + # pending foreign-key trigger events can block the subsequent ALTER TABLE. + atomic = False + dependencies = [ - ("paperless_mail", "0001_1_clamp_mailrule_maximum_age"), + ("paperless_mail", "0001_squashed"), ] operations = [ @@ -112,6 +122,10 @@ class Migration(migrations.Migration): verbose_name="consumption scope", ), ), + migrations.RunPython( + clamp_mailrule_maximum_age, + migrations.RunPython.noop, + ), migrations.AlterField( model_name="mailrule", name="maximum_age", diff --git a/src/paperless_mail/tests/test_migrations.py b/src/paperless_mail/tests/test_migrations.py new file mode 100644 index 000000000..a683c89fa --- /dev/null +++ b/src/paperless_mail/tests/test_migrations.py @@ -0,0 +1,37 @@ +import importlib + +from django.db import migrations + + +def test_optimize_integer_fields_preserves_released_migration_history(): + migration_module = importlib.import_module( + "paperless_mail.migrations.0002_optimize_integer_field_sizes", + ) + + assert migration_module.Migration.dependencies == [ + ("paperless_mail", "0001_squashed"), + ] + + +def test_mailrule_maximum_age_is_clamped_before_non_atomic_alter(): + migration_module = importlib.import_module( + "paperless_mail.migrations.0002_optimize_integer_field_sizes", + ) + migration = migration_module.Migration + + clamp_index = next( + index + for index, operation in enumerate(migration.operations) + if isinstance(operation, migrations.RunPython) + and operation.code is migration_module.clamp_mailrule_maximum_age + ) + alter_index = next( + index + for index, operation in enumerate(migration.operations) + if isinstance(operation, migrations.AlterField) + and operation.model_name == "mailrule" + and operation.name == "maximum_age" + ) + + assert migration.atomic is False + assert clamp_index < alter_index diff --git a/uv.lock b/uv.lock index b0a989691..15f0e4acb 100644 --- a/uv.lock +++ b/uv.lock @@ -2880,7 +2880,7 @@ wheels = [ [[package]] name = "paperless-ngx" -version = "3.0.1" +version = "3.0.2" source = { virtual = "." } dependencies = [ { name = "azure-ai-documentintelligence", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },