mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 10:04:18 +00:00
fix(compose): an autosave the server refused no longer says "Draft saved"
`response.ok` was the wrong question. A form the server REFUSES — a stale CSRF token, a validation failure — does not come back as an error status: it comes back as the window re-rendered with the errors on it, HTTP 200. The autosave read that as success, printed "Draft saved", and cleared the unsaved flag that the unload guard depends on. So the one path where writing is actually lost was also the one path that claimed everything was fine. ComposeController::draft() has passed `saved => true` on the accepted branch since it was written, and the template has never rendered it. It does now, and the client requires it. A refusal takes the same road as a network failure: "Could not save the draft", and `_unsaved` stays standing so leaving the page still warns. This is the half of the CSRF bug that made it invisible — the composer was telling the user their reply was safe while the server discarded it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a5f53a5b47
commit
097f6ca943
2 files changed
+24
No files matched your search
@@ -37,6 +37,19 @@ Variables: form, message, ctx (an App\Domain\DTO\Mail\ComposeContext)
|
||||
|
||||
<turbo-frame id="{{ frame }}">
|
||||
<div data-controller="compose--compose compose--compose-toolbar"
|
||||
{# The server's statement that this render followed a save that was
|
||||
actually ACCEPTED. ComposeController::draft() has always passed
|
||||
`saved` and this template has never rendered it, which left the
|
||||
client with no way to tell an accepted autosave from a refused one:
|
||||
a refusal re-renders the window with the errors on it and HTTP 200,
|
||||
the fetch saw `response.ok`, and the composer printed "Draft saved"
|
||||
about a draft the server had thrown away.
|
||||
|
||||
That is how a session-lost CSRF token (see config/packages/csrf.yaml)
|
||||
stayed invisible until a browser test caught it. Any future refusal
|
||||
would have been just as silent, which for an autosave means losing
|
||||
what somebody wrote. #}
|
||||
{% if saved|default(false) %}data-compose-saved="1"{% endif %}
|
||||
{# Every word the controller puts on screen, translated here rather
|
||||
than spelled in JavaScript — same arrangement as ui--select's
|
||||
i18n value. A string baked into the controller is a string that
|
||||
|
||||
Reference in new issue
Block a user