diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f112c0e..f86adbd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,16 @@ The published image tags: `latest` follows the most recent release below, ## Unreleased +**Saving an attachment to Paperless-ngx works.** The "Save to…" chooser listed your Paperless tags +as folders to open, but a tag has nothing inside it, so clicking one only reloaded the same list and +the dialog seemed to do nothing. A tag is now the choice itself: click it and the attachment is filed +under it, or pick **No tag** to file it under none. The same goes for the folder a filter saves to. +The upload itself was also refused ("No file was submitted") because it was sent in a form +Paperless could not read; it now goes through. Paperless still turns down file types it cannot +consume, a ZIP for one, and says so. Nextcloud, Google Drive, OneDrive, Dropbox, Immich and Google Photos choose exactly as before. No +migration. +[#78](https://github.com/karatektus/pl_mail/pull/78), by @Flouss. + **A message's header no longer breaks into pieces in a narrow pane.** On a phone, or with the reading pane on the right and dragged narrow, the sender's address was cut mid-word across three lines while the date and the buttons took half the width. Below 36rem of pane width the date, the diff --git a/src/Domain/Enum/Integration/DestinationKind.php b/src/Domain/Enum/Integration/DestinationKind.php new file mode 100644 index 00000000..3bf06866 --- /dev/null +++ b/src/Domain/Enum/Integration/DestinationKind.php @@ -0,0 +1,36 @@ + DestinationKind::Album, + self::Paperless => DestinationKind::Tag, + default => DestinationKind::Folder, + }; + } + /** * Whether a "Save to…" of this content type could possibly land. * diff --git a/src/Service/Integration/Driver/PaperlessDriver.php b/src/Service/Integration/Driver/PaperlessDriver.php index 1387dea5..bb80c533 100644 --- a/src/Service/Integration/Driver/PaperlessDriver.php +++ b/src/Service/Integration/Driver/PaperlessDriver.php @@ -266,7 +266,11 @@ final readonly class PaperlessDriver implements IntegrationDriverInterface, Sear $response = $this->request($integration, 'POST', $this->url($integration, '/documents/post_document/'), [ 'headers' => $form->getPreparedHeaders()->toArray(), - 'body' => $form->bodyToIterable(), + // A string, not bodyToIterable(): a streamed body leaves chunked with + // no Content-Length, and Paperless's server then reads the form as + // empty and answers 400 "No file was submitted." to a valid PDF. The + // whole file is held in memory for it; attachments are mail-sized. + 'body' => $form->toString(), ]); return self::TASK_PREFIX.$this->taskId($response); diff --git a/templates/integration/_destination.html.twig b/templates/integration/_destination.html.twig index 9cf9e861..154c4b1c 100644 --- a/templates/integration/_destination.html.twig +++ b/templates/integration/_destination.html.twig @@ -16,6 +16,13 @@ Two shapes, decided by the taxonomy rather than by provider name: tree to descend, so each album is itself the button, and a "Library" row saves with no album at all. + A document archive (Paperless) gets its tags the same way, flat: a tag is a + label a document is filed under, not a place that holds anything. Each tag is + itself the button, and a "No tag" row files under none. What decides between + this and a tree is Provider::destinationKind(), not whether the service holds + photos — a flat list drawn as a tree is a list of links that all lead back to + the same list. + And two MODES, decided by whether there is a part: With a part, a choice is a save: the row or the footer posts the upload and @@ -36,7 +43,11 @@ a successful save is exactly when the modal should close. #} {% extends '_layout/app.html.twig' %} -{% set isMediaLibrary = integration.provider.isMediaLibrary %} +{# Folder, album or tag: the shape of the containers, and so what they are + called. `isFlat` is what changes the markup; `kind.value` completes the + translation keys, so a fourth kind is one enum case and its strings. #} +{% set kind = integration.provider.destinationKind %} +{% set isFlat = kind.isFlat %} {# Pick mode is the absence of something to upload, not a separate flag — see FilePickerController::renderDestination(). #} @@ -107,9 +118,7 @@ drift into looking like different features. the folder a rule will use for whatever arrives. #} {{ 'integration.destination.choose_for_filter'|trans }} {% else %} - {{ (isMediaLibrary - ? 'integration.destination.choose_album' - : 'integration.destination.choose_folder')|trans({ '%file%': part.filename ?: 'attachment' }) }} + {{ ('integration.destination.choose_' ~ kind.value)|trans({ '%file%': part.filename ?: 'attachment' }) }} {% endif %}
@@ -138,7 +147,7 @@ drift into looking like different features. {% else %} {# ── Breadcrumb — a folder tree only ── #} - {% if not isMediaLibrary %} + {% if not isFlat %}