b41be21190
- SmtpConfig.bugReportRecipient (string | null) und SaveSmtpPayload.bugReportRecipient (null loescht, fehlend bewahrt) - Eingabefeld type=email hinter der Absenderadresse mit Hinweistext; Payload traegt immer trim() || null - Zwei Komponententests: Vorbelegung aus GET, PUT-Payload mit Wert bzw. null - i18n settings.smtp.bugReportRecipient / bugReportRecipientHelp in de und en Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
100 lines
3.0 KiB
TypeScript
100 lines
3.0 KiB
TypeScript
/**
|
|
* Settings API client — SMTP configuration.
|
|
* Consumes the SettingsController built in 07-03.
|
|
* All calls use credentials: 'include' for cookie-based auth.
|
|
*
|
|
* T-07-17: SmtpConfig exposes only hasPassword, never the secret.
|
|
* The password field is never pre-filled from server data.
|
|
*/
|
|
|
|
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
|
|
|
|
// --- Types mirroring the 07-03 backend contract ---
|
|
|
|
/**
|
|
* SMTP configuration as returned by GET /settings/smtp.
|
|
* encryptedPassword is NEVER returned (T-07-17).
|
|
*/
|
|
export interface SmtpConfig {
|
|
host: string;
|
|
port: number;
|
|
encryption: 'none' | 'starttls' | 'ssl-tls';
|
|
username?: string;
|
|
fromAddress: string;
|
|
/** True when an encrypted password is stored; the password value is never exposed. */
|
|
hasPassword: boolean;
|
|
/** Postfach fuer den Fehler-melden-Knopf (quick-260914-m97); null = nicht gesetzt. */
|
|
bugReportRecipient: string | null;
|
|
}
|
|
|
|
/**
|
|
* Payload for PUT /settings/smtp and POST /settings/smtp/test.
|
|
* password is optional — omit to preserve the existing stored password.
|
|
*/
|
|
export interface SaveSmtpPayload {
|
|
host: string;
|
|
port: number;
|
|
encryption: 'none' | 'starttls' | 'ssl-tls';
|
|
username?: string;
|
|
/** Only include when the user has typed a new password. */
|
|
password?: string;
|
|
fromAddress: string;
|
|
/** If set, backend sends a real test email to this address instead of just verify(). */
|
|
testTo?: string;
|
|
/**
|
|
* Postfach fuer den Fehler-melden-Knopf (quick-260914-m97). Vertrag mit
|
|
* `saveSmtpConfig`: `null` loescht den gespeicherten Wert, ein fehlendes
|
|
* Feld bewahrt ihn.
|
|
*/
|
|
bugReportRecipient?: string | null;
|
|
}
|
|
|
|
// --- API functions ---
|
|
|
|
/**
|
|
* Fetch the SMTP configuration for the current tenant.
|
|
* GET /settings/smtp
|
|
* Returns null when no configuration has been saved yet (404).
|
|
*/
|
|
export async function fetchSmtp(): Promise<SmtpConfig | null> {
|
|
const res = await fetch(`${API_URL}/settings/smtp`, {
|
|
credentials: 'include',
|
|
});
|
|
if (res.status === 404) return null;
|
|
if (!res.ok) throw new Error('Failed to fetch SMTP config');
|
|
return res.json();
|
|
}
|
|
|
|
/**
|
|
* Save the SMTP configuration.
|
|
* PUT /settings/smtp
|
|
*/
|
|
export async function saveSmtp(payload: SaveSmtpPayload): Promise<SmtpConfig> {
|
|
const res = await fetch(`${API_URL}/settings/smtp`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'include',
|
|
body: JSON.stringify(payload),
|
|
});
|
|
if (!res.ok) throw new Error('Failed to save SMTP config');
|
|
return res.json();
|
|
}
|
|
|
|
/**
|
|
* Test the SMTP connection with the given settings.
|
|
* POST /settings/smtp/test
|
|
* Returns { success: boolean } — backend runs nodemailer.verify().
|
|
*/
|
|
export async function testSmtp(
|
|
payload: SaveSmtpPayload,
|
|
): Promise<{ success: boolean; warning?: string }> {
|
|
const res = await fetch(`${API_URL}/settings/smtp/test`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'include',
|
|
body: JSON.stringify(payload),
|
|
});
|
|
if (!res.ok) throw new Error('Failed to test SMTP config');
|
|
return res.json();
|
|
}
|