mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-12-20 01:45:58 -06:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7604a0b583 | ||
|
|
4e789acf2d | ||
|
|
d9459d04ea | ||
|
|
305d764805 |
@@ -1,5 +1,7 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## paperless-ngx 2.20.3
|
||||||
|
|
||||||
## paperless-ngx 2.20.2
|
## paperless-ngx 2.20.2
|
||||||
|
|
||||||
### Features / Enhancements
|
### Features / Enhancements
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
@if (previewText) {
|
@if (previewText) {
|
||||||
<div class="bg-light p-3 overflow-auto whitespace-preserve" width="100%">{{previewText}}</div>
|
<div class="bg-light p-3 overflow-auto whitespace-preserve" width="100%">{{previewText}}</div>
|
||||||
} @else {
|
} @else {
|
||||||
<object [data]="previewURL | safeUrl" width="100%" class="bg-light" [class.p-2]="!isPdf"></object>
|
<object [data]="previewUrl | safeUrl" width="100%" class="bg-light" [class.p-2]="!isPdf"></object>
|
||||||
}
|
}
|
||||||
} @else {
|
} @else {
|
||||||
@if (requiresPassword) {
|
@if (requiresPassword) {
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
@if (!requiresPassword) {
|
@if (!requiresPassword) {
|
||||||
<pdf-viewer
|
<pdf-viewer
|
||||||
[src]="previewURL"
|
[src]="previewUrl"
|
||||||
[original-size]="false"
|
[original-size]="false"
|
||||||
[show-borders]="false"
|
[show-borders]="false"
|
||||||
[show-all]="true"
|
[show-all]="true"
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export class PreviewPopupComponent implements OnDestroy {
|
|||||||
return (this.isPdf && this.useNativePdfViewer) || !this.isPdf
|
return (this.isPdf && this.useNativePdfViewer) || !this.isPdf
|
||||||
}
|
}
|
||||||
|
|
||||||
get previewURL() {
|
get previewUrl() {
|
||||||
return this.documentService.getPreviewUrl(this.document.id)
|
return this.documentService.getPreviewUrl(this.document.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ export class PreviewPopupComponent implements OnDestroy {
|
|||||||
init() {
|
init() {
|
||||||
if (this.document.mime_type?.includes('text')) {
|
if (this.document.mime_type?.includes('text')) {
|
||||||
this.http
|
this.http
|
||||||
.get(this.previewURL, { responseType: 'text' })
|
.get(this.previewUrl, { responseType: 'text' })
|
||||||
.pipe(first(), takeUntil(this.unsubscribeNotifier))
|
.pipe(first(), takeUntil(this.unsubscribeNotifier))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (res) => {
|
next: (res) => {
|
||||||
@@ -126,10 +126,6 @@ export class PreviewPopupComponent implements OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get previewUrl() {
|
|
||||||
return this.documentService.getPreviewUrl(this.document.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
mouseEnterPreview() {
|
mouseEnterPreview() {
|
||||||
this.mouseOnPreview = true
|
this.mouseOnPreview = true
|
||||||
if (!this.popover.isOpen()) {
|
if (!this.popover.isOpen()) {
|
||||||
|
|||||||
@@ -379,7 +379,7 @@
|
|||||||
<ng-template #previewContent>
|
<ng-template #previewContent>
|
||||||
<div class="thumb-preview position-absolute pe-none text-center" [class.fade]="previewLoaded">
|
<div class="thumb-preview position-absolute pe-none text-center" [class.fade]="previewLoaded">
|
||||||
@if (showThumbnailOverlay) {
|
@if (showThumbnailOverlay) {
|
||||||
<img [src]="thumbUrl | safeUrl" class="mx-auto" [attr.width]="previewZoomScale === 'page-fit' ? 'auto' : '100%'" [attr.height]="previewZoomScale === 'page-fit' ? '100%' : 'auto'" alt="Document loading..." i18n-alt />
|
<img [src]="thumbUrl" class="mx-auto" [attr.width]="previewZoomScale === 'page-fit' ? 'auto' : '100%'" [attr.height]="previewZoomScale === 'page-fit' ? '100%' : 'auto'" alt="Document loading..." i18n-alt />
|
||||||
}
|
}
|
||||||
<div class="position-absolute top-0 start-0 m-2 p-2 d-flex align-items-center justify-content-center">
|
<div class="position-absolute top-0 start-0 m-2 p-2 d-flex align-items-center justify-content-center">
|
||||||
<div>
|
<div>
|
||||||
@@ -414,7 +414,7 @@
|
|||||||
}
|
}
|
||||||
@case (ContentRenderType.Image) {
|
@case (ContentRenderType.Image) {
|
||||||
<div class="preview-sticky">
|
<div class="preview-sticky">
|
||||||
<img [src]="previewUrl | safeUrl" width="100%" height="100%" alt="{{title}}" />
|
<img [src]="previewUrl" width="100%" height="100%" alt="{{title}}" />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@case (ContentRenderType.TIFF) {
|
@case (ContentRenderType.TIFF) {
|
||||||
|
|||||||
@@ -186,7 +186,11 @@ class BarcodePlugin(ConsumeTaskPlugin):
|
|||||||
|
|
||||||
# Update/overwrite an ASN if possible
|
# Update/overwrite an ASN if possible
|
||||||
# After splitting, as otherwise each split document gets the same ASN
|
# After splitting, as otherwise each split document gets the same ASN
|
||||||
if self.settings.barcode_enable_asn and (located_asn := self.asn) is not None:
|
if (
|
||||||
|
self.settings.barcode_enable_asn
|
||||||
|
and not self.metadata.skip_asn
|
||||||
|
and (located_asn := self.asn) is not None
|
||||||
|
):
|
||||||
logger.info(f"Found ASN in barcode: {located_asn}")
|
logger.info(f"Found ASN in barcode: {located_asn}")
|
||||||
self.metadata.asn = located_asn
|
self.metadata.asn = located_asn
|
||||||
|
|
||||||
|
|||||||
@@ -433,6 +433,8 @@ def merge(
|
|||||||
|
|
||||||
if user is not None:
|
if user is not None:
|
||||||
overrides.owner_id = user.id
|
overrides.owner_id = user.id
|
||||||
|
# Avoid copying or detecting ASN from merged PDFs to prevent collision
|
||||||
|
overrides.skip_asn = True
|
||||||
|
|
||||||
logger.info("Adding merged document to the task queue.")
|
logger.info("Adding merged document to the task queue.")
|
||||||
|
|
||||||
|
|||||||
@@ -696,7 +696,7 @@ class ConsumerPlugin(
|
|||||||
pk=self.metadata.storage_path_id,
|
pk=self.metadata.storage_path_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.metadata.asn is not None:
|
if self.metadata.asn is not None and not self.metadata.skip_asn:
|
||||||
document.archive_serial_number = self.metadata.asn
|
document.archive_serial_number = self.metadata.asn
|
||||||
|
|
||||||
if self.metadata.owner_id:
|
if self.metadata.owner_id:
|
||||||
@@ -812,8 +812,8 @@ class ConsumerPreflightPlugin(
|
|||||||
"""
|
"""
|
||||||
Check that if override_asn is given, it is unique and within a valid range
|
Check that if override_asn is given, it is unique and within a valid range
|
||||||
"""
|
"""
|
||||||
if self.metadata.asn is None:
|
if self.metadata.skip_asn or self.metadata.asn is None:
|
||||||
# check not necessary in case no ASN gets set
|
# if skip is set or ASN is None
|
||||||
return
|
return
|
||||||
# Validate the range is above zero and less than uint32_t max
|
# Validate the range is above zero and less than uint32_t max
|
||||||
# otherwise, Whoosh can't handle it in the index
|
# otherwise, Whoosh can't handle it in the index
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class DocumentMetadataOverrides:
|
|||||||
change_users: list[int] | None = None
|
change_users: list[int] | None = None
|
||||||
change_groups: list[int] | None = None
|
change_groups: list[int] | None = None
|
||||||
custom_fields: dict | None = None
|
custom_fields: dict | None = None
|
||||||
|
skip_asn: bool = False
|
||||||
|
|
||||||
def update(self, other: "DocumentMetadataOverrides") -> "DocumentMetadataOverrides":
|
def update(self, other: "DocumentMetadataOverrides") -> "DocumentMetadataOverrides":
|
||||||
"""
|
"""
|
||||||
@@ -49,6 +50,8 @@ class DocumentMetadataOverrides:
|
|||||||
self.storage_path_id = other.storage_path_id
|
self.storage_path_id = other.storage_path_id
|
||||||
if other.owner_id is not None:
|
if other.owner_id is not None:
|
||||||
self.owner_id = other.owner_id
|
self.owner_id = other.owner_id
|
||||||
|
if other.skip_asn:
|
||||||
|
self.skip_asn = True
|
||||||
|
|
||||||
# merge
|
# merge
|
||||||
if self.tag_ids is None:
|
if self.tag_ids is None:
|
||||||
|
|||||||
@@ -602,11 +602,13 @@ class TestPDFActions(DirectoriesMixin, TestCase):
|
|||||||
expected_filename,
|
expected_filename,
|
||||||
)
|
)
|
||||||
self.assertEqual(consume_file_args[1].title, None)
|
self.assertEqual(consume_file_args[1].title, None)
|
||||||
|
self.assertTrue(consume_file_args[1].skip_asn)
|
||||||
|
|
||||||
# With metadata_document_id overrides
|
# With metadata_document_id overrides
|
||||||
result = bulk_edit.merge(doc_ids, metadata_document_id=metadata_document_id)
|
result = bulk_edit.merge(doc_ids, metadata_document_id=metadata_document_id)
|
||||||
consume_file_args, _ = mock_consume_file.call_args
|
consume_file_args, _ = mock_consume_file.call_args
|
||||||
self.assertEqual(consume_file_args[1].title, "A (merged)")
|
self.assertEqual(consume_file_args[1].title, "A (merged)")
|
||||||
|
self.assertTrue(consume_file_args[1].skip_asn)
|
||||||
|
|
||||||
self.assertEqual(result, "OK")
|
self.assertEqual(result, "OK")
|
||||||
|
|
||||||
@@ -647,6 +649,7 @@ class TestPDFActions(DirectoriesMixin, TestCase):
|
|||||||
expected_filename,
|
expected_filename,
|
||||||
)
|
)
|
||||||
self.assertEqual(consume_file_args[1].title, None)
|
self.assertEqual(consume_file_args[1].title, None)
|
||||||
|
self.assertTrue(consume_file_args[1].skip_asn)
|
||||||
|
|
||||||
delete_documents_args, _ = mock_delete_documents.call_args
|
delete_documents_args, _ = mock_delete_documents.call_args
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
|||||||
@@ -412,6 +412,14 @@ class TestConsumer(
|
|||||||
self.assertEqual(document.archive_serial_number, 123)
|
self.assertEqual(document.archive_serial_number, 123)
|
||||||
self._assert_first_last_send_progress()
|
self._assert_first_last_send_progress()
|
||||||
|
|
||||||
|
def testMetadataOverridesSkipAsnPropagation(self):
|
||||||
|
overrides = DocumentMetadataOverrides()
|
||||||
|
incoming = DocumentMetadataOverrides(skip_asn=True)
|
||||||
|
|
||||||
|
overrides.update(incoming)
|
||||||
|
|
||||||
|
self.assertTrue(overrides.skip_asn)
|
||||||
|
|
||||||
def testOverrideTitlePlaceholders(self):
|
def testOverrideTitlePlaceholders(self):
|
||||||
c = Correspondent.objects.create(name="Correspondent Name")
|
c = Correspondent.objects.create(name="Correspondent Name")
|
||||||
dt = DocumentType.objects.create(name="DocType Name")
|
dt = DocumentType.objects.create(name="DocType Name")
|
||||||
|
|||||||
@@ -1108,6 +1108,7 @@ class TestMail(
|
|||||||
self.assertEqual(len(self.mailMocker.bogus_mailbox.messages), 2)
|
self.assertEqual(len(self.mailMocker.bogus_mailbox.messages), 2)
|
||||||
self.assertEqual(len(self.mailMocker.bogus_mailbox.messages_spam), 1)
|
self.assertEqual(len(self.mailMocker.bogus_mailbox.messages_spam), 1)
|
||||||
|
|
||||||
|
@pytest.mark.flaky(reruns=4)
|
||||||
def test_error_skip_rule(self):
|
def test_error_skip_rule(self):
|
||||||
account = MailAccount.objects.create(
|
account = MailAccount.objects.create(
|
||||||
name="test2",
|
name="test2",
|
||||||
|
|||||||
Reference in New Issue
Block a user