mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-02 13:45:10 -05:00
Merge branch 'dev' into feature-improve-paperless-task
This commit is contained in:
commit
53e9e910d8
2
Pipfile
2
Pipfile
@ -14,7 +14,7 @@ django-celery-results = "*"
|
|||||||
django-compression-middleware = "*"
|
django-compression-middleware = "*"
|
||||||
django-cors-headers = "*"
|
django-cors-headers = "*"
|
||||||
django-extensions = "*"
|
django-extensions = "*"
|
||||||
django-filter = "~=24.3"
|
django-filter = "~=25.1"
|
||||||
django-guardian = "*"
|
django-guardian = "*"
|
||||||
django-multiselectfield = "*"
|
django-multiselectfield = "*"
|
||||||
django-soft-delete = "*"
|
django-soft-delete = "*"
|
||||||
|
16
Pipfile.lock
generated
16
Pipfile.lock
generated
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "8c1714db280429940577d7b88e5a59a63f92147a15bc6ae14fc4ff2820f2790e"
|
"sha256": "4d54b43e6f093a817b2dc9b923f93b889bf7a42cd937ea971cd8773484fc4636"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {},
|
"requires": {},
|
||||||
@ -577,12 +577,12 @@
|
|||||||
},
|
},
|
||||||
"django-filter": {
|
"django-filter": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:c4852822928ce17fb699bcfccd644b3574f1a2d80aeb2b4ff4f16b02dd49dc64",
|
"sha256:1ec9eef48fa8da1c0ac9b411744b16c3f4c31176c867886e4c48da369c407153",
|
||||||
"sha256:d8ccaf6732afd21ca0542f6733b11591030fa98669f8d15599b358e24a2cd9c3"
|
"sha256:4fa48677cf5857b9b1347fed23e355ea792464e0fe07244d1fdfb8a806215b80"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"markers": "python_version >= '3.8'",
|
"markers": "python_version >= '3.9'",
|
||||||
"version": "==24.3"
|
"version": "==25.1"
|
||||||
},
|
},
|
||||||
"django-guardian": {
|
"django-guardian": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -3582,12 +3582,12 @@
|
|||||||
},
|
},
|
||||||
"mkdocs-material": {
|
"mkdocs-material": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1125622067e26940806701219303b27c0933e04533560725d97ec26fd16a39cf",
|
"sha256:414e8376551def6d644b8e6f77226022868532a792eb2c9accf52199009f568f",
|
||||||
"sha256:c87f7d1c39ce6326da5e10e232aed51bae46252e646755900f4b0fc9192fa832"
|
"sha256:4d1d35e1c1d3e15294cb7fa5d02e0abaee70d408f75027dc7be6e30fb32e6867"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"markers": "python_version >= '3.8'",
|
"markers": "python_version >= '3.8'",
|
||||||
"version": "==9.6.3"
|
"version": "==9.6.4"
|
||||||
},
|
},
|
||||||
"mkdocs-material-extensions": {
|
"mkdocs-material-extensions": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -2230,7 +2230,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
||||||
<context context-type="linenumber">103</context>
|
<context context-type="linenumber">106</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
|
<context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
|
||||||
@ -2565,7 +2565,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
||||||
<context context-type="linenumber">105</context>
|
<context context-type="linenumber">108</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
|
<context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
|
||||||
@ -3322,7 +3322,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
||||||
<context context-type="linenumber">85</context>
|
<context context-type="linenumber">87</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1841172489943868696" datatype="html">
|
<trans-unit id="1841172489943868696" datatype="html">
|
||||||
@ -3333,7 +3333,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
||||||
<context context-type="linenumber">93</context>
|
<context context-type="linenumber">96</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6048892649018070225" datatype="html">
|
<trans-unit id="6048892649018070225" datatype="html">
|
||||||
@ -8193,28 +8193,28 @@
|
|||||||
<source>Confirm delete field</source>
|
<source>Confirm delete field</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
||||||
<context context-type="linenumber">101</context>
|
<context context-type="linenumber">104</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2939457975223185057" datatype="html">
|
<trans-unit id="2939457975223185057" datatype="html">
|
||||||
<source>This operation will permanently delete this field.</source>
|
<source>This operation will permanently delete this field.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
||||||
<context context-type="linenumber">102</context>
|
<context context-type="linenumber">105</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4679555638382452936" datatype="html">
|
<trans-unit id="4679555638382452936" datatype="html">
|
||||||
<source>Deleted field "<x id="PH" equiv-text="field.name"/>"</source>
|
<source>Deleted field "<x id="PH" equiv-text="field.name"/>"</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
||||||
<context context-type="linenumber">111</context>
|
<context context-type="linenumber">114</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4704551499967874824" datatype="html">
|
<trans-unit id="4704551499967874824" datatype="html">
|
||||||
<source>Error deleting field "<x id="PH" equiv-text="field.name"/>".</source>
|
<source>Error deleting field "<x id="PH" equiv-text="field.name"/>".</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
<context context-type="sourcefile">src/app/components/manage/custom-fields/custom-fields.component.ts</context>
|
||||||
<context context-type="linenumber">118</context>
|
<context context-type="linenumber">122</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8084492669582894778" datatype="html">
|
<trans-unit id="8084492669582894778" datatype="html">
|
||||||
|
@ -71,6 +71,10 @@ export const DOCUMENT_SOURCE_OPTIONS = [
|
|||||||
id: DocumentSource.MailFetch,
|
id: DocumentSource.MailFetch,
|
||||||
name: $localize`Mail Fetch`,
|
name: $localize`Mail Fetch`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: DocumentSource.WebUI,
|
||||||
|
name: $localize`Web UI`,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const SCHEDULE_DATE_FIELD_OPTIONS = [
|
export const SCHEDULE_DATE_FIELD_OPTIONS = [
|
||||||
|
@ -145,7 +145,10 @@ export class SavedViewWidgetComponent
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.savedView.display_fields) {
|
if (
|
||||||
|
this.savedView.display_fields &&
|
||||||
|
this.savedView.display_fields.length > 0
|
||||||
|
) {
|
||||||
this.displayFields = this.savedView.display_fields
|
this.displayFields = this.savedView.display_fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ export enum DocumentSource {
|
|||||||
ConsumeFolder = 1,
|
ConsumeFolder = 1,
|
||||||
ApiUpload = 2,
|
ApiUpload = 2,
|
||||||
MailFetch = 3,
|
MailFetch = 3,
|
||||||
|
WebUI = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum WorkflowTriggerType {
|
export enum WorkflowTriggerType {
|
||||||
|
@ -114,6 +114,48 @@ describe(`Additional service tests for SavedViewService`, () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should treat empty display_fields as null', () => {
|
||||||
|
subscription = service
|
||||||
|
.patch({
|
||||||
|
id: 1,
|
||||||
|
name: 'Saved View',
|
||||||
|
show_on_dashboard: true,
|
||||||
|
show_in_sidebar: true,
|
||||||
|
sort_field: 'name',
|
||||||
|
sort_reverse: true,
|
||||||
|
filter_rules: [],
|
||||||
|
display_fields: [],
|
||||||
|
})
|
||||||
|
.subscribe()
|
||||||
|
const req = httpTestingController.expectOne(
|
||||||
|
`${environment.apiBaseUrl}${endpoint}/1/`
|
||||||
|
)
|
||||||
|
expect(req.request.body.display_fields).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should support patch without reload', () => {
|
||||||
|
subscription = service
|
||||||
|
.patch(
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Saved View',
|
||||||
|
show_on_dashboard: true,
|
||||||
|
show_in_sidebar: true,
|
||||||
|
sort_field: 'name',
|
||||||
|
sort_reverse: true,
|
||||||
|
filter_rules: [],
|
||||||
|
},
|
||||||
|
false
|
||||||
|
)
|
||||||
|
.subscribe()
|
||||||
|
const req = httpTestingController.expectOne(
|
||||||
|
`${environment.apiBaseUrl}${endpoint}/1/`
|
||||||
|
)
|
||||||
|
expect(req.request.method).toEqual('PATCH')
|
||||||
|
req.flush({})
|
||||||
|
httpTestingController.verify() // no reload
|
||||||
|
})
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Dont need to setup again
|
// Dont need to setup again
|
||||||
|
|
||||||
|
@ -87,12 +87,21 @@ export class SavedViewService extends AbstractPaperlessService<SavedView> {
|
|||||||
return super.create(o).pipe(tap(() => this.reload()))
|
return super.create(o).pipe(tap(() => this.reload()))
|
||||||
}
|
}
|
||||||
|
|
||||||
update(o: SavedView) {
|
patch(o: SavedView, reload: boolean = false): Observable<SavedView> {
|
||||||
return super.update(o).pipe(tap(() => this.reload()))
|
if (o.display_fields?.length === 0) {
|
||||||
|
o.display_fields = null
|
||||||
|
}
|
||||||
|
return super.patch(o).pipe(
|
||||||
|
tap(() => {
|
||||||
|
if (reload) {
|
||||||
|
this.reload()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
patchMany(objects: SavedView[]): Observable<SavedView[]> {
|
patchMany(objects: SavedView[]): Observable<SavedView[]> {
|
||||||
return combineLatest(objects.map((o) => super.patch(o))).pipe(
|
return combineLatest(objects.map((o) => this.patch(o, false))).pipe(
|
||||||
tap(() => this.reload())
|
tap(() => this.reload())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ export class UploadDocumentsService {
|
|||||||
private uploadFile(file: File) {
|
private uploadFile(file: File) {
|
||||||
let formData = new FormData()
|
let formData = new FormData()
|
||||||
formData.append('document', file, file.name)
|
formData.append('document', file, file.name)
|
||||||
|
formData.append('from_webui', 'true')
|
||||||
let status = this.websocketStatusService.newFileUpload(file.name)
|
let status = this.websocketStatusService.newFileUpload(file.name)
|
||||||
|
|
||||||
status.message = $localize`Connecting...`
|
status.message = $localize`Connecting...`
|
||||||
|
@ -144,6 +144,7 @@ class DocumentSource(IntEnum):
|
|||||||
ConsumeFolder = 1
|
ConsumeFolder = 1
|
||||||
ApiUpload = 2
|
ApiUpload = 2
|
||||||
MailFetch = 3
|
MailFetch = 3
|
||||||
|
WebUI = 4
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
# Generated by Django 5.1.6 on 2025-02-20 04:55
|
||||||
|
|
||||||
|
import multiselectfield.db.fields
|
||||||
|
from django.db import migrations
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
# WebUI source was added, so all existing APIUpload sources should be updated to include WebUI
|
||||||
|
def update_workflow_sources(apps, schema_editor):
|
||||||
|
WorkflowTrigger = apps.get_model("documents", "WorkflowTrigger")
|
||||||
|
for trigger in WorkflowTrigger.objects.all():
|
||||||
|
sources = list(trigger.sources)
|
||||||
|
if 2 in sources:
|
||||||
|
sources.append(4)
|
||||||
|
trigger.sources = sources
|
||||||
|
trigger.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("documents", "1062_alter_savedviewfilterrule_rule_type"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="workflowactionwebhook",
|
||||||
|
name="url",
|
||||||
|
field=models.CharField(
|
||||||
|
help_text="The destination URL for the notification.",
|
||||||
|
max_length=256,
|
||||||
|
verbose_name="webhook url",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="workflowtrigger",
|
||||||
|
name="sources",
|
||||||
|
field=multiselectfield.db.fields.MultiSelectField(
|
||||||
|
choices=[
|
||||||
|
(1, "Consume Folder"),
|
||||||
|
(2, "Api Upload"),
|
||||||
|
(3, "Mail Fetch"),
|
||||||
|
(4, "Web UI"),
|
||||||
|
],
|
||||||
|
default="1,2,3,4",
|
||||||
|
max_length=7,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
code=update_workflow_sources,
|
||||||
|
reverse_code=migrations.RunPython.noop,
|
||||||
|
),
|
||||||
|
]
|
@ -1054,6 +1054,7 @@ class WorkflowTrigger(models.Model):
|
|||||||
CONSUME_FOLDER = DocumentSource.ConsumeFolder.value, _("Consume Folder")
|
CONSUME_FOLDER = DocumentSource.ConsumeFolder.value, _("Consume Folder")
|
||||||
API_UPLOAD = DocumentSource.ApiUpload.value, _("Api Upload")
|
API_UPLOAD = DocumentSource.ApiUpload.value, _("Api Upload")
|
||||||
MAIL_FETCH = DocumentSource.MailFetch.value, _("Mail Fetch")
|
MAIL_FETCH = DocumentSource.MailFetch.value, _("Mail Fetch")
|
||||||
|
WEB_UI = DocumentSource.WebUI.value, _("Web UI")
|
||||||
|
|
||||||
class ScheduleDateField(models.TextChoices):
|
class ScheduleDateField(models.TextChoices):
|
||||||
ADDED = "added", _("Added")
|
ADDED = "added", _("Added")
|
||||||
@ -1068,9 +1069,9 @@ class WorkflowTrigger(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
sources = MultiSelectField(
|
sources = MultiSelectField(
|
||||||
max_length=5,
|
max_length=7,
|
||||||
choices=DocumentSourceChoices.choices,
|
choices=DocumentSourceChoices.choices,
|
||||||
default=f"{DocumentSource.ConsumeFolder},{DocumentSource.ApiUpload},{DocumentSource.MailFetch}",
|
default=f"{DocumentSource.ConsumeFolder},{DocumentSource.ApiUpload},{DocumentSource.MailFetch},{DocumentSource.WebUI}",
|
||||||
)
|
)
|
||||||
|
|
||||||
filter_path = models.CharField(
|
filter_path = models.CharField(
|
||||||
|
@ -1147,6 +1147,15 @@ class SavedViewSerializer(OwnedObjectSerializer):
|
|||||||
if "user" in validated_data:
|
if "user" in validated_data:
|
||||||
# backwards compatibility
|
# backwards compatibility
|
||||||
validated_data["owner"] = validated_data.pop("user")
|
validated_data["owner"] = validated_data.pop("user")
|
||||||
|
if (
|
||||||
|
"display_fields" in validated_data
|
||||||
|
and isinstance(
|
||||||
|
validated_data["display_fields"],
|
||||||
|
list,
|
||||||
|
)
|
||||||
|
and len(validated_data["display_fields"]) == 0
|
||||||
|
):
|
||||||
|
validated_data["display_fields"] = None
|
||||||
super().update(instance, validated_data)
|
super().update(instance, validated_data)
|
||||||
if rules_data is not None:
|
if rules_data is not None:
|
||||||
SavedViewFilterRule.objects.filter(saved_view=instance).delete()
|
SavedViewFilterRule.objects.filter(saved_view=instance).delete()
|
||||||
@ -1537,6 +1546,12 @@ class PostDocumentSerializer(serializers.Serializer):
|
|||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from_webui = serializers.BooleanField(
|
||||||
|
label="Documents are from Paperless-ngx WebUI",
|
||||||
|
write_only=True,
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
def validate_document(self, document):
|
def validate_document(self, document):
|
||||||
document_data = document.file.read()
|
document_data = document.file.read()
|
||||||
mime_type = magic.from_buffer(document_data, mime=True)
|
mime_type = magic.from_buffer(document_data, mime=True)
|
||||||
|
@ -360,7 +360,7 @@ def empty_trash(doc_ids=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
deleted_document_ids = documents.values_list("id", flat=True)
|
deleted_document_ids = list(documents.values_list("id", flat=True))
|
||||||
# Temporarily connect the cleanup handler
|
# Temporarily connect the cleanup handler
|
||||||
models.signals.post_delete.connect(cleanup_document_deletion, sender=Document)
|
models.signals.post_delete.connect(cleanup_document_deletion, sender=Document)
|
||||||
documents.delete() # this is effectively a hard delete
|
documents.delete() # this is effectively a hard delete
|
||||||
|
@ -38,6 +38,7 @@ from documents.models import SavedView
|
|||||||
from documents.models import ShareLink
|
from documents.models import ShareLink
|
||||||
from documents.models import StoragePath
|
from documents.models import StoragePath
|
||||||
from documents.models import Tag
|
from documents.models import Tag
|
||||||
|
from documents.models import WorkflowTrigger
|
||||||
from documents.tests.utils import DirectoriesMixin
|
from documents.tests.utils import DirectoriesMixin
|
||||||
from documents.tests.utils import DocumentConsumeDelayMixin
|
from documents.tests.utils import DocumentConsumeDelayMixin
|
||||||
|
|
||||||
@ -1362,6 +1363,30 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
|
|||||||
self.assertEqual(overrides.filename, "simple.pdf")
|
self.assertEqual(overrides.filename, "simple.pdf")
|
||||||
self.assertEqual(overrides.custom_field_ids, [custom_field.id])
|
self.assertEqual(overrides.custom_field_ids, [custom_field.id])
|
||||||
|
|
||||||
|
def test_upload_with_webui_source(self):
|
||||||
|
"""
|
||||||
|
GIVEN: A document with a source file
|
||||||
|
WHEN: Upload the document with 'from_webui' flag
|
||||||
|
THEN: Consume is called with the source set as WebUI
|
||||||
|
"""
|
||||||
|
self.consume_file_mock.return_value = celery.result.AsyncResult(
|
||||||
|
id=str(uuid.uuid4()),
|
||||||
|
)
|
||||||
|
|
||||||
|
with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
|
||||||
|
response = self.client.post(
|
||||||
|
"/api/documents/post_document/",
|
||||||
|
{"document": f, "from_webui": True},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
self.consume_file_mock.assert_called_once()
|
||||||
|
|
||||||
|
input_doc, overrides = self.get_last_consume_delay_call_args()
|
||||||
|
|
||||||
|
self.assertEqual(input_doc.source, WorkflowTrigger.DocumentSourceChoices.WEB_UI)
|
||||||
|
|
||||||
def test_upload_invalid_pdf(self):
|
def test_upload_invalid_pdf(self):
|
||||||
"""
|
"""
|
||||||
GIVEN: Invalid PDF named "*.pdf" that mime_type is in settings.CONSUMER_PDF_RECOVERABLE_MIME_TYPES
|
GIVEN: Invalid PDF named "*.pdf" that mime_type is in settings.CONSUMER_PDF_RECOVERABLE_MIME_TYPES
|
||||||
@ -1815,6 +1840,19 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
# empty display fields treated as none
|
||||||
|
response = self.client.patch(
|
||||||
|
f"/api/saved_views/{v1.id}/",
|
||||||
|
{
|
||||||
|
"display_fields": [],
|
||||||
|
},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
v1.refresh_from_db()
|
||||||
|
self.assertEqual(v1.display_fields, None)
|
||||||
|
|
||||||
def test_saved_view_display_customfields(self):
|
def test_saved_view_display_customfields(self):
|
||||||
"""
|
"""
|
||||||
GIVEN:
|
GIVEN:
|
||||||
|
@ -1387,6 +1387,7 @@ class PostDocumentView(GenericAPIView):
|
|||||||
created = serializer.validated_data.get("created")
|
created = serializer.validated_data.get("created")
|
||||||
archive_serial_number = serializer.validated_data.get("archive_serial_number")
|
archive_serial_number = serializer.validated_data.get("archive_serial_number")
|
||||||
custom_field_ids = serializer.validated_data.get("custom_fields")
|
custom_field_ids = serializer.validated_data.get("custom_fields")
|
||||||
|
from_webui = serializer.validated_data.get("from_webui")
|
||||||
|
|
||||||
t = int(mktime(datetime.now().timetuple()))
|
t = int(mktime(datetime.now().timetuple()))
|
||||||
|
|
||||||
@ -1401,7 +1402,7 @@ class PostDocumentView(GenericAPIView):
|
|||||||
os.utime(temp_file_path, times=(t, t))
|
os.utime(temp_file_path, times=(t, t))
|
||||||
|
|
||||||
input_doc = ConsumableDocument(
|
input_doc = ConsumableDocument(
|
||||||
source=DocumentSource.ApiUpload,
|
source=DocumentSource.WebUI if from_webui else DocumentSource.ApiUpload,
|
||||||
original_file=temp_file_path,
|
original_file=temp_file_path,
|
||||||
)
|
)
|
||||||
input_doc_overrides = DocumentMetadataOverrides(
|
input_doc_overrides = DocumentMetadataOverrides(
|
||||||
|
@ -305,6 +305,11 @@ urlpatterns = [
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
re_path(
|
||||||
|
r"^confirm-email/(?P<key>[-:\w]+)/$",
|
||||||
|
allauth_account_views.ConfirmEmailView.as_view(),
|
||||||
|
name="account_confirm_email",
|
||||||
|
),
|
||||||
re_path(
|
re_path(
|
||||||
r"^password/reset/key/(?P<uidb36>[0-9A-Za-z]+)-(?P<key>.+)/$",
|
r"^password/reset/key/(?P<uidb36>[0-9A-Za-z]+)-(?P<key>.+)/$",
|
||||||
allauth_account_views.password_reset_from_key,
|
allauth_account_views.password_reset_from_key,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user