/**
* 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);
}