Commit 669a7934 authored by jan.koester's avatar jan.koester
Browse files

test

parent 6b26abf5
Loading
Loading
Loading
Loading
+64 −63
Original line number Diff line number Diff line
@@ -56,28 +56,35 @@ blogi::Config::Config(const std::string &path) : confplus::Config(path), _Config
    try { _ClientName=getValue(getKey("/BLOGI/AUTHDB/CLIENTNAME"),0); } catch(...) {}
    try { _ClientSecret=getValue(getKey("/BLOGI/AUTHDB/CLIENTSECRET"),0); } catch(...) {}

    // Parse multi-domain AUTHDB sources (parallel arrays)
    // Parse multi-domain AUTHDB sources.
    // Preferred form is an indexed sequence: /BLOGI/AUTHDB/<i>/URL ... .
    // A legacy single-mapping form (/BLOGI/AUTHDB/URL) is still supported.
    try {
        auto *urlKey = getKey("/BLOGI/AUTHDB/URL");
        auto *nameKey = getKey("/BLOGI/AUTHDB/CLIENTNAME");
        auto *secretKey = getKey("/BLOGI/AUTHDB/CLIENTSECRET");
        size_t count = getElements(urlKey);
        for (size_t i = 0; i < count; ++i) {
        bool indexed = false;
        for (size_t i = 0; ; ++i) {
            std::string base = "/BLOGI/AUTHDB/" + std::to_string(i);
            auto *node = getKey(base.c_str());
            if (!node) break;
            indexed = true;
            AuthSource src;
            src.url = getValue(urlKey, i);
            src.clientName = getValue(nameKey, i);
            src.clientSecret = getValue(secretKey, i);
            try {
                auto *domKey = getKey("/BLOGI/AUTHDB/DOMAIN");
                src.domain = getValue(domKey, i);
            } catch (...) {
                src.domain = "";
            try { src.url = getValue(getKey((base + "/URL").c_str()), 0); } catch(...) { continue; }
            try { src.clientName = getValue(getKey((base + "/CLIENTNAME").c_str()), 0); } catch(...) {}
            try { src.clientSecret = getValue(getKey((base + "/CLIENTSECRET").c_str()), 0); } catch(...) {}
            try { src.domain = getValue(getKey((base + "/DOMAIN").c_str()), 0); } catch(...) { src.domain = ""; }
            _AuthSources.push_back(std::move(src));
        }
        if (!indexed && !_AuthUrl.empty()) {
            // Legacy single mapping
            AuthSource src;
            src.url = _AuthUrl;
            src.clientName = _ClientName;
            src.clientSecret = _ClientSecret;
            try { src.domain = getValue(getKey("/BLOGI/AUTHDB/DOMAIN"), 0); } catch(...) { src.domain = ""; }
            _AuthSources.push_back(std::move(src));
        }
    } catch (...) {
        // If multi-domain parsing fails, create a single source from legacy fields
        if (!_AuthUrl.empty()) {
        if (_AuthSources.empty() && !_AuthUrl.empty()) {
            AuthSource src;
            src.url = _AuthUrl;
            src.clientName = _ClientName;
@@ -134,78 +141,72 @@ blogi::Config::Config(const std::string &path) : confplus::Config(path), _Config
        _MediaDBUrl="https://127.0.0.1:8442";
    }

    // Parse multi-domain configurations
    // libconfplus YAML stores sequence-of-mappings as flat keys with positional values.
    // Parse multi-domain configurations.
    // The libconfplus YAML loader produces a fully indexed tree: each entry of
    // the DOMAINS sequence lives under /BLOGI/DOMAINS/<i>/... .
    // Each domain entry MUST define its own DB_DRIVER, DB_CONNECTION, etc.
    // NAME is an array: one config entry can serve multiple domain names.
    // No global fallbacks — unconfigured domains get 404.
    // NAMES is a proper nested sequence: one config entry can serve multiple
    // domain names. No global fallbacks — unconfigured domains get 404.
    try {
        auto *dbDriverKey = getKey("/BLOGI/DOMAINS/DB_DRIVER");
        if (!dbDriverKey) throw std::runtime_error("no domains");
        size_t domCount = getElements(dbDriverKey);
        for (size_t i = 0; i < domCount; ++i) {
        for (size_t i = 0; ; ++i) {
            std::string base = "/BLOGI/DOMAINS/" + std::to_string(i);
            auto *domNode = getKey(base.c_str());
            if (!domNode) break; // no more domain entries

            DomainConfig dc;

            // NAME is stored as a sub-array per domain entry via DOMAINS/NAME
            // NAME: single primary name for this entry.
            try {
                auto *nameKey = getKey("/BLOGI/DOMAINS/NAME");
                auto *nameKey = getKey((base + "/NAME").c_str());
                if (nameKey) {
                    // In flat config, multiple names for the same domain entry
                    // are stored as comma-separated or as multiple positional values.
                    // With the current YAML parser, each domain entry gets one NAME value,
                    // but we also support NAMES as a separate multi-value key.
                    std::string n = getValue(nameKey, i);
                    std::string n = getValue(nameKey, 0);
                    if (!n.empty()) dc.names.push_back(n);
                }
            } catch(...) {}

            // Additional names via DOMAINS/NAMES (array per domain)
            // NAMES: nested sequence of additional names for this entry.
            try {
                auto *namesKey = getKey("/BLOGI/DOMAINS/NAMES");
                auto *namesKey = getKey((base + "/NAMES").c_str());
                if (namesKey) {
                    size_t namesCount = getElements(namesKey);
                    for (size_t j = 0; j < namesCount; ++j) {
                    size_t nameCount = getElements(namesKey);
                    for (size_t j = 0; j < nameCount; ++j) {
                        std::string n = getValue(namesKey, j);
                        // Only add names that belong to this domain index
                        // In flat config with seqMapping, all names at index i belong to domain i
                        if (!n.empty()) {
                        if (n.empty()) continue;
                        bool dup = false;
                        for (const auto &existing : dc.names)
                            if (existing == n) { dup = true; break; }
                        if (!dup) dc.names.push_back(n);
                    }
                }
                }
            } catch(...) {}

            if (dc.names.empty()) continue;

            try { dc.dbDriver = getValue(dbDriverKey, i); } catch(...) { continue; }
            try { dc.dbConnection = getValue(getKey("/BLOGI/DOMAINS/DB_CONNECTION"), i); } catch(...) { continue; }

            try {
                auto *repKey = getKey("/BLOGI/DOMAINS/DB_REPLICAS");
                if (repKey) {
                    // TODO: per-domain replicas if needed
                }
            } catch(...) {}
            try { dc.dbDriver = getValue(getKey((base + "/DB_DRIVER").c_str()), 0); } catch(...) { continue; }
            try { dc.dbConnection = getValue(getKey((base + "/DB_CONNECTION").c_str()), 0); } catch(...) { continue; }

            try { dc.authUrl = getValue(getKey("/BLOGI/DOMAINS/AUTH_URL"), i); } catch(...) {}
            try { dc.clientName = getValue(getKey("/BLOGI/DOMAINS/AUTH_CLIENTNAME"), i); } catch(...) {}
            try { dc.clientSecret = getValue(getKey("/BLOGI/DOMAINS/AUTH_CLIENTSECRET"), i); } catch(...) {}
            try { dc.siteUrl = getValue(getKey("/BLOGI/DOMAINS/URL"), i); } catch(...) {}
            try { dc.authUrl = getValue(getKey((base + "/AUTH_URL").c_str()), 0); } catch(...) {}
            try { dc.clientName = getValue(getKey((base + "/AUTH_CLIENTNAME").c_str()), 0); } catch(...) {}
            try { dc.clientSecret = getValue(getKey((base + "/AUTH_CLIENTSECRET").c_str()), 0); } catch(...) {}
            try { dc.siteUrl = getValue(getKey((base + "/URL").c_str()), 0); } catch(...) {}
            dc.siteUrls.clear();
            if (!dc.siteUrl.empty()) dc.siteUrls.push_back(dc.siteUrl);
            try { dc.prefix = getValue(getKey("/BLOGI/DOMAINS/PREFIX"), i); } catch(...) {}
            try { dc.prefix = getValue(getKey((base + "/PREFIX").c_str()), 0); } catch(...) {}
            if (dc.prefix == "/") dc.prefix = "";
            try { dc.templatePath = getValue(getKey("/BLOGI/DOMAINS/TEMPLATE"), i); } catch(...) {}
            try { dc.startPage = getValue(getKey("/BLOGI/DOMAINS/STARTPAGE"), i); } catch(...) {}
            try { dc.mediaDBUrl = getValue(getKey("/BLOGI/DOMAINS/MEDIA_URL"), i); } catch(...) {}
            try { dc.tmpDir = getValue(getKey("/BLOGI/DOMAINS/TMPDIR"), i); } catch(...) { dc.tmpDir = "/tmp/blogi"; }
            try { dc.templatePath = getValue(getKey((base + "/TEMPLATE").c_str()), 0); } catch(...) {}
            try { dc.startPage = getValue(getKey((base + "/STARTPAGE").c_str()), 0); } catch(...) {}
            try { dc.mediaDBUrl = getValue(getKey((base + "/MEDIA_URL").c_str()), 0); } catch(...) {}
            try { dc.tmpDir = getValue(getKey((base + "/TMPDIR").c_str()), 0); } catch(...) { dc.tmpDir = "/tmp/blogi"; }

            try {
                std::string plgdir = getValue(getKey("/BLOGI/DOMAINS/PLUGINDIR"), i);
                auto *plgKey = getKey((base + "/PLUGINDIR").c_str());
                if (plgKey) {
                    size_t plgCount = getElements(plgKey);
                    for (size_t j = 0; j < plgCount; ++j) {
                        std::string plgdir = getValue(plgKey, j);
                        if (!plgdir.empty()) dc.plgDirs.push_back(plgdir);
                    }
                }
            } catch(...) {}

            // Auth source from domain values