Source: Router/orgaSettings/service.js

/**
 * OrgaSettings Service — der verbliebene Vault-Anteil
 *
 * Apps und Domains liegen im Registry (`ObjectBase`/`Links`, siehe
 * `registryService.js`). Hier steht nur noch, was dort **nicht** liegt:
 *  - Mail/SMTP-Config (`orgas/data/{orgId}/mailserver`)
 *
 * Die **Stammdaten** (`orgas/data/{orgId}/metadata`, der Anzeigename) sind
 * entfallen: der Name kommt aus der Datenbank (`Member.Display`, gejoint in
 * `getAllDomainMappings`), nicht mehr aus Vault.
 *
 * Bis vor kurzem verwaltete dieses Modul auch den App- und Domain-Bestand in
 * Vault — zuletzt nur noch als Rückfall für den Registry-Lesemodus. Mit dem
 * entfallenen Umschalter (`REGISTRY_READ_MODE`) hatten diese Leser keinen
 * Aufrufer mehr; sie sind entfernt, nicht auskommentiert.
 *
 * Vault path convention (KV v2):
 *   orgas/data/{orgId}/mailserver → { mailHost, mailPort, mailUser, mailPassword,
 *                                     mailUserName, supportName, supportEmail,
 *                                     mailBcc, mailDebounceMs }
 *
 * Das ist **derselbe** Schlüssel, den `@commtool/bot-framework` in
 * `utils/mailHandler.js` liest. Der frühere Schlüssel `mail` hatte eine andere
 * Form (`host`, `port`, `user`, …) und wurde nur von diesem Endpunkt benutzt —
 * Einstellungen dort hatten auf den Versand keine Wirkung.
 */

import { getSecretsFromVault, saveSecretsToVault } from '@commtool/vault-secrets';
import { errorLoggerRead }      from '../../utils/requestLogger.js';

// ── Generic Vault section helpers ─────────────────────────────────────────────

/**
 * Load a named section for one organisation from Vault.
 * Returns `null` on missing key or error.
 * @param {string} orgId
 * @param {string} section  e.g. 'mail'
 * @returns {Promise<object|null>}
 */
async function getOrgSection(orgId, section) {
    try {
        return await getSecretsFromVault(`orgas/data/${orgId}/${section}`) ?? null;
    } catch (e) {
        errorLoggerRead(e);
        return null;
    }
}

/**
 * Persist a named section for one organisation in Vault.
 * @param {string} orgId
 * @param {string} section
 * @param {object} data
 */
async function saveOrgSection(orgId, section, data) {
    await saveSecretsToVault( data, `orgas/data/${orgId}/${section}`);
}

// ── Mail settings ─────────────────────────────────────────────────────────────

/**
 * Der Schlüssel, den der Mailversand tatsächlich liest
 * (`@commtool/bot-framework` → `utils/mailHandler.js`).
 */
const MAIL_SECTION = 'mailserver';

/**
 * Felder, die die Admin-Oberfläche verwaltet. Alles andere in der Sektion
 * (künftige Schlüssel, manuell gepflegte Werte) bleibt beim Speichern erhalten —
 * Vault KV v2 ersetzt bei einem Write den gesamten Datenblock.
 */
const MAIL_FIELDS = [
    'mailHost', 'mailPort', 'mailUser', 'mailPassword', 'mailUserName',
    'supportName', 'supportEmail', 'mailBcc', 'mailDebounceMs',
];

const MASKED = '••••••••';

/**
 * Load mail/SMTP settings for one organisation.
 * The password is masked before being returned.
 * @param {string} orgId
 * @returns {Promise<object|null>}
 */
export async function getMailSettings(orgId) {
    const settings = await getOrgSection(orgId, MAIL_SECTION);
    if (!settings) return null;
    return {
        ...settings,
        mailPassword: settings.mailPassword ? MASKED : '',
    };
}

/**
 * Persist mail/SMTP settings for one organisation.
 * If the password is the mask sentinel, the existing password is preserved.
 * @param {string} orgId
 * @param {object} settings
 */
export async function saveMailSettings(orgId, settings) {
    const existing = await getOrgSection(orgId, MAIL_SECTION) ?? {};
    const dataToSave = { ...existing };

    for (const field of MAIL_FIELDS) {
        if (settings[field] !== undefined)
            dataToSave[field] = settings[field];
    }

    if (dataToSave.mailPassword === MASKED)
        // Passwort unverändert – vorhandenen Wert aus Vault behalten
        dataToSave.mailPassword = existing.mailPassword ?? '';

    if (!dataToSave.mailPassword)
        throw Object.assign(new Error('Field "mailPassword" is required.'), { statusCode: 400 });

    await saveOrgSection(orgId, MAIL_SECTION, dataToSave);
}