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}/mail`)
 *
 * 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}/mail → { host, port, user, password, userName, from, secure }
 */

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 ─────────────────────────────────────────────────────────────

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');
    if (!settings) return null;
    return {
        ...settings,
        password: settings.password ? 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) {
    let dataToSave = { ...settings };

    if (dataToSave.password === MASKED) {
        // Password not changed – keep existing value from Vault
        const existing = await getOrgSection(orgId, 'mail') ?? {};
        dataToSave.password = existing.password ?? '';
    }

    await saveOrgSection(orgId, 'mail', dataToSave);
}