Source: Router/botLanguage/controller.js

/**
 * Bot Language Controller Layer
 *
 * HTTP-Schicht für die Labels der Bot-UIs. Die Ablage ist pro **Bot-Repo**
 * (z. B. `basic-bots`): mehrere Bots rendern dieselben geteilten Komponenten,
 * ein Text ist also einmal zu pflegen.
 *
 * Die Organisation kommt beim Lesen aus der Session (`req.session.root`, gesetzt
 * von `checkRoot`) — nicht aus der URL, damit ein Aufrufer nicht in einer
 * fremden Organisation lesen kann.
 */

// @ts-check
/**
 * @import {ExpressRequestAuthorized, ExpressResponse} from './../../types.js'
 */

import { errorLoggerUpdate } from '../../utils/requestLogger.js';
import * as botLanguageService from './service.js';

const DEFAULT_LANG = 'de';

/**
 * Sprachcode aus Query oder Pfad, mit Default.
 *
 * @param {ExpressRequestAuthorized} req
 * @returns {string}
 */
const readLang = (req) => {
    const lang = req.query?.lang ?? req.params?.lang ?? DEFAULT_LANG;
    return typeof lang === 'string' && lang.length > 0 ? lang : DEFAULT_LANG;
};

/**
 * @param {ExpressRequestAuthorized} req
 * @param {ExpressResponse} res
 * @param {number} status
 * @param {string} message
 * @returns {void}
 */
const fail = (req, res, status, message) => {
    res.status(status).json({ success: false, message });
};

/**
 * Dünne Überschicht aller Bot-Repos für die Session-Organisation.
 * Handles GET /?lang=de
 *
 * @param {ExpressRequestAuthorized} req
 * @param {ExpressResponse} res
 * @returns {Promise<void>}
 */
export const listRepoLanguageSlicesController = async (req, res) => {
    try {
        const UIDroot = req.session?.root;
        if (!UIDroot) return fail(req, res, 400, 'Keine Organisation in der Session');

        const lang = readLang(req);
        const result = await botLanguageService.listRepoLanguageSlices(UIDroot, lang);

        res.json({ success: true, lang, result });
    } catch (e) {
        errorLoggerUpdate(e);
        const err = /** @type {any} */ (e);
        if (err?.code === 'InvalidSegment') return fail(req, res, 400, err.message);
        res.status(500).json({ success: false, message: err.message });
    }
};

/**
 * Ein Bot-Repo mit getrennten Ebenen (Editor).
 * Handles GET /:repo?lang=de
 *
 * @param {ExpressRequestAuthorized} req
 * @param {ExpressResponse} res
 * @returns {Promise<void>}
 */
export const getRepoLanguageController = async (req, res) => {
    try {
        const UIDroot = req.session?.root ?? null;
        const result = await botLanguageService.getRepoLanguage(req.params.repo, readLang(req), UIDroot);

        res.json({ success: true, result });
    } catch (e) {
        errorLoggerUpdate(e);
        const err = /** @type {any} */ (e);
        if (err?.code === 'InvalidSegment') return fail(req, res, 400, err.message);
        res.status(500).json({ success: false, message: err.message });
    }
};

/**
 * Schreibt eine Ebene. Ohne `:UIDroot` die geteilte Ebene, sonst die der
 * angegebenen Organisation.
 * Handles PUT /:repo/:lang und PUT /:repo/:UIDroot/:lang
 *
 * @param {ExpressRequestAuthorized} req
 * @param {ExpressResponse} res
 * @returns {Promise<void>}
 */
export const putRepoLanguageController = async (req, res) => {
    try {
        const { labels, remove } = req.body ?? {};

        if (labels !== undefined && (typeof labels !== 'object' || labels === null || Array.isArray(labels))) {
            return fail(req, res, 400, '"labels" muss ein Objekt sein');
        }
        if (remove !== undefined && !Array.isArray(remove)) {
            return fail(req, res, 400, '"remove" muss ein Array sein');
        }

        const result = await botLanguageService.putRepoLanguage({
            repo: req.params.repo,
            lang: readLang(req),
            UIDroot: req.params.UIDroot ?? null,
            labels: labels ?? {},
            remove: remove ?? [],
        });

        res.json({ success: true, result });
    } catch (e) {
        errorLoggerUpdate(e);
        const err = /** @type {any} */ (e);
        if (err?.code === 'InvalidSegment') return fail(req, res, 400, err.message);
        res.status(500).json({ success: false, message: err.message });
    }
};