fix: say the true thing when Gmail, AI or mail is not set up

Two bugs with one shape: the interface confidently told you something
that was not so.

Connecting Gmail without a registered OAuth client said "Det er der
allerede." Thirteen different situations answered a plain `conflict`, and
the frontend renders that as "that already exists" — which for four of
them is not vague but wrong. An unconfigured Gmail is not a Gmail that is
already connected; a second factor that is off is not one that is on; the
Inbox is not a project that already exists somewhere else. Those four
have their own codes now, and their own sentences.

The mail-to-task address came out as todo+…@localhost. VERDANDE_SMTP_FROM
defaults to verdande@localhost and the domain was taken from it
unconditionally, so an instance with no mail server handed out an address
that looks real, can never receive anything, and gives no hint which of
the two it is. The default no longer wins over the public hostname, and
the response now carries whether a mail server exists at all — because
even with the right domain, nothing routes to it until one does.

errors.go has always claimed the code list is kept in one place "so the
frontend's mapping can be checked against it". Nothing checked it, and
the mapping was missing bad_request. Now a test reads both files and
fails on a code with no message.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kristian Wind
2026-08-17 14:35:36 +02:00
committed by Kristian Wind
co-authored by Claude Opus 5
parent 7e28d8bb92
commit 78ec9b08a1
11 changed files with 298 additions and 14 deletions
+21 -1
View File
@@ -34,9 +34,29 @@ const MESSAGES = {
validation_failed: 'Tjek felterne herunder.',
payload_too_large: 'Det er for stort.',
internal_error: 'Noget gik galt. Prøv igen.',
offline: 'Ingen forbindelse til serveren.'
bad_request: 'Anmodningen kunne ikke læses.',
// Client-only: a network failure is not an HTTP status, so the server has no
// code for it.
offline: 'Ingen forbindelse til serveren.',
// Situations that used to arrive as a plain `conflict` and were therefore
// shown as "Det er der allerede." — which was not merely vague but wrong. An
// unconfigured Gmail is not a Gmail that is already connected.
gmail_not_configured:
'Gmail er ikke sat op på denne server. Administratoren skal registrere en OAuth-klient hos Google og sætte VERDANDE_GMAIL_CLIENT_ID og _SECRET.',
ai_not_configured: 'Der er ikke valgt en AI-udbyder. Sæt den op under Indstillinger → AI.',
totp_not_enabled: 'To-faktor er ikke slået til.',
inbox_protected: 'Indbakken kan ikke slettes.'
};
/**
* What to show a person for a failed request.
*
* A code with no message here falls back to the server's prose, which is English
* and written for a log — not good, but better than swallowing the only
* explanation there is. A code that turns up in that fallback is a code this
* table is missing.
*/
export function humanMessage(err) {
if (!(err instanceof ApiError)) return MESSAGES.offline;
return MESSAGES[err.code] ?? err.message ?? MESSAGES.internal_error;