diff --git a/src/documents/migrations/0012_add_document_version.py b/src/documents/migrations/0012_add_document_version.py new file mode 100644 index 000000000..5b262154f --- /dev/null +++ b/src/documents/migrations/0012_add_document_version.py @@ -0,0 +1,153 @@ +from __future__ import annotations + +import django.core.validators +import django.db.models +import django.db.models.deletion +import django.utils.timezone +from django.db import migrations +from django.db import models + + +class Migration(migrations.Migration): + dependencies = [ + ("documents", "0011_alter_workflowaction_type"), + ] + + operations = [ + migrations.CreateModel( + name="DocumentVersion", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "version_number", + models.PositiveSmallIntegerField( + help_text="Sequential version number within this document, starting at 1.", + verbose_name="version number", + ), + ), + ( + "version_label", + models.CharField( + blank=True, + help_text="Optional short label for this version.", + max_length=64, + null=True, + verbose_name="version label", + ), + ), + ( + "added", + models.DateTimeField( + db_index=True, + default=django.utils.timezone.now, + editable=False, + verbose_name="added", + ), + ), + ( + "checksum", + models.CharField( + editable=False, + help_text="SHA-256 checksum of the original file for this version.", + max_length=64, + verbose_name="checksum", + ), + ), + ( + "archive_checksum", + models.CharField( + blank=True, + editable=False, + max_length=64, + null=True, + verbose_name="archive checksum", + ), + ), + ( + "content", + models.TextField( + blank=True, + help_text="OCR text content of this version.", + verbose_name="content", + ), + ), + ( + "page_count", + models.PositiveIntegerField( + blank=True, + null=True, + validators=[django.core.validators.MinValueValidator(1)], + verbose_name="page count", + ), + ), + ( + "mime_type", + models.CharField( + editable=False, + max_length=256, + verbose_name="mime type", + ), + ), + ( + "original_filename", + models.CharField( + blank=True, + editable=False, + max_length=1024, + null=True, + verbose_name="original filename", + ), + ), + ( + "filename", + models.FilePathField( + default=None, + editable=False, + help_text="Stored filename for this version's original file.", + max_length=1024, + null=True, + verbose_name="filename", + ), + ), + ( + "archive_filename", + models.FilePathField( + default=None, + editable=False, + max_length=1024, + null=True, + verbose_name="archive filename", + ), + ), + ( + "document", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="versions", + to="documents.document", + verbose_name="document", + ), + ), + ], + options={ + "verbose_name": "document version", + "verbose_name_plural": "document versions", + "ordering": ["-version_number"], + }, + ), + migrations.AddConstraint( + model_name="documentversion", + constraint=models.UniqueConstraint( + fields=("document", "version_number"), + name="documents_documentversion_doc_number_uniq", + ), + ), + ] diff --git a/src/documents/migrations/0012_document_root_document.py b/src/documents/migrations/0012_document_root_document.py deleted file mode 100644 index c287be0dc..000000000 --- a/src/documents/migrations/0012_document_root_document.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 5.1.6 on 2025-02-26 17:08 - -import django.db.models.deletion -from django.db import migrations -from django.db import models - - -class Migration(migrations.Migration): - dependencies = [ - ("documents", "0011_alter_workflowaction_type"), - ] - - operations = [ - migrations.AddField( - model_name="document", - name="root_document", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="versions", - to="documents.document", - verbose_name="root document for this version", - ), - ), - migrations.AddField( - model_name="document", - name="version_label", - field=models.CharField( - blank=True, - help_text="Optional short label for a document version.", - max_length=64, - null=True, - verbose_name="version label", - ), - ), - ] diff --git a/src/documents/migrations/0013_alter_paperlesstask_task_name.py b/src/documents/migrations/0013_alter_paperlesstask_task_name.py index 46882d537..0243b5fa5 100644 --- a/src/documents/migrations/0013_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", "0012_document_root_document"), + ("documents", "0012_add_document_version"), ] operations = [ diff --git a/src/documents/migrations/0015_document_version_index_and_more.py b/src/documents/migrations/0015_document_version_index_and_more.py deleted file mode 100644 index 5a817074c..000000000 --- a/src/documents/migrations/0015_document_version_index_and_more.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 5.2.11 on 2026-03-02 17:48 - -from django.conf import settings -from django.db import migrations -from django.db import models - - -class Migration(migrations.Migration): - dependencies = [ - ("documents", "0014_savedview_visibility_to_ui_settings"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AddField( - model_name="document", - name="version_index", - field=models.PositiveIntegerField( - blank=True, - db_index=True, - help_text="Index of this version within the root document.", - null=True, - verbose_name="version index", - ), - ), - migrations.AddConstraint( - model_name="document", - constraint=models.UniqueConstraint( - condition=models.Q( - ("root_document__isnull", False), - ("version_index__isnull", False), - ), - fields=("root_document", "version_index"), - name="documents_document_root_version_index_uniq", - ), - ), - ] diff --git a/src/documents/migrations/0016_sha256_checksums.py b/src/documents/migrations/0015_sha256_checksums.py similarity index 98% rename from src/documents/migrations/0016_sha256_checksums.py rename to src/documents/migrations/0015_sha256_checksums.py index de1c6c596..51d0cf5d8 100644 --- a/src/documents/migrations/0016_sha256_checksums.py +++ b/src/documents/migrations/0015_sha256_checksums.py @@ -100,7 +100,7 @@ def recompute_checksums(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ("documents", "0015_document_version_index_and_more"), + ("documents", "0014_savedview_visibility_to_ui_settings"), ] operations = [ diff --git a/src/documents/migrations/0017_migrate_fulltext_query_field_prefixes.py b/src/documents/migrations/0016_migrate_fulltext_query_field_prefixes.py similarity index 96% rename from src/documents/migrations/0017_migrate_fulltext_query_field_prefixes.py rename to src/documents/migrations/0016_migrate_fulltext_query_field_prefixes.py index 040780a60..cc3b8e1f2 100644 --- a/src/documents/migrations/0017_migrate_fulltext_query_field_prefixes.py +++ b/src/documents/migrations/0016_migrate_fulltext_query_field_prefixes.py @@ -28,7 +28,7 @@ def migrate_fulltext_query_field_prefixes(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ("documents", "0016_sha256_checksums"), + ("documents", "0015_sha256_checksums"), ] operations = [ diff --git a/src/documents/migrations/0018_saved_view_simple_search_rules.py b/src/documents/migrations/0017_saved_view_simple_search_rules.py similarity index 98% rename from src/documents/migrations/0018_saved_view_simple_search_rules.py rename to src/documents/migrations/0017_saved_view_simple_search_rules.py index 6d128c593..0a6624478 100644 --- a/src/documents/migrations/0018_saved_view_simple_search_rules.py +++ b/src/documents/migrations/0017_saved_view_simple_search_rules.py @@ -22,7 +22,7 @@ def migrate_saved_view_rules_forward(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ("documents", "0017_migrate_fulltext_query_field_prefixes"), + ("documents", "0016_migrate_fulltext_query_field_prefixes"), ] operations = [ diff --git a/src/documents/tests/search/test_migration_fulltext_query_field_prefixes.py b/src/documents/tests/search/test_migration_fulltext_query_field_prefixes.py index 739ea996c..7cdb52cdc 100644 --- a/src/documents/tests/search/test_migration_fulltext_query_field_prefixes.py +++ b/src/documents/tests/search/test_migration_fulltext_query_field_prefixes.py @@ -6,8 +6,8 @@ pytestmark = pytest.mark.search class TestMigrateFulltextQueryFieldPrefixes(TestMigrations): - migrate_from = "0016_sha256_checksums" - migrate_to = "0017_migrate_fulltext_query_field_prefixes" + migrate_from = "0015_sha256_checksums" + migrate_to = "0016_migrate_fulltext_query_field_prefixes" def setUpBeforeMigration(self, apps) -> None: User = apps.get_model("auth", "User") diff --git a/src/documents/tests/test_migration_sha256_checksums.py b/src/documents/tests/test_migration_sha256_checksums.py index 4a53b724c..07beddc47 100644 --- a/src/documents/tests/test_migration_sha256_checksums.py +++ b/src/documents/tests/test_migration_sha256_checksums.py @@ -17,8 +17,8 @@ def _sha256(data: bytes) -> str: class TestSha256ChecksumDataMigration(TestMigrations): """recompute_checksums correctly updates document checksums from MD5 to SHA256.""" - migrate_from = "0015_document_version_index_and_more" - migrate_to = "0016_sha256_checksums" + migrate_from = "0014_savedview_visibility_to_ui_settings" + migrate_to = "0015_sha256_checksums" reset_sequences = True ORIGINAL_CONTENT = b"original file content for sha256 migration test"