Commit 23f604aa authored by jan.koester's avatar jan.koester
Browse files

test

parent 94499621
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -29,8 +29,6 @@ target_link_libraries(blogidev PUBLIC
    dbpp::dbpp
    uuidp::uuidp
    tinyxml2::tinyxml2
    mediadb_client
    cjson
)

if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows")
+24 −167
Original line number Diff line number Diff line
@@ -44,7 +44,6 @@
#include "conf.h"
#include "compress.h"
#include "i18n.h"
#include "session.h"

blogi::Theme::Theme(blogi::ThemeConfig& config,bool formated) : _Config(config){
    auto trimlines = [&] (const std::string in){
@@ -164,29 +163,13 @@ blogi::Theme::~Theme(){
    // Destructor implementation
}

void blogi::Theme::ensureMediaClient(const int tid, const std::string &token) {
    if (_MdbClients.empty())
        _MdbClients.resize(_Config.TDatabase.size());
    std::string mdbUrl;
    try { getConfig(*_Config.TDatabase[tid], "MEDIADB_URL", mdbUrl); } catch (...) {}
    if (mdbUrl.empty())
        return;
    if (!_MdbClients[tid])
        _MdbClients[tid] = std::make_unique<mediadb::Client>(mdbUrl, false, true);
    if (!token.empty())
        _MdbClients[tid]->set_token(token);
}

std::string blogi::Theme::getLogoUrl(const int tid) const {
    std::string mediaId, mediaExt;
    try { getConfig(*_Config.TDatabase[tid], "THEME_LOGO_MEDIA_ID", mediaId); } catch (...) {}
    try { getConfig(*_Config.TDatabase[tid], "THEME_LOGO_MEDIA_EXT", mediaExt); } catch (...) {}
    if (!mediaId.empty()) {
        if (mediaExt.empty()) mediaExt = "webp";
        return _Config.config.buildurl("media/getimage/" + mediaId + "." + mediaExt);
    }
    std::string logoUrl;
    try { getConfig(*_Config.TDatabase[tid], "THEME_LOGO_URL", logoUrl); } catch (...) {}
    if (!logoUrl.empty())
        return logoUrl;
    // Fallback to theme default
    return _Config.config.getprefix() + "/theme/public/header.webp";
    return _Config.config.getprefix() + "/theme/public/logo.webp";
}

void blogi::Theme::renderPage(const int tid,const char *name,libhtmlpp::HtmlPage& page, libhtmlpp::HtmlElement &index){
@@ -590,16 +573,6 @@ void blogi::Theme::injectThemeColors(const int tid, libhtmlpp::HtmlElement *inde
json_object* blogi::Theme::SettingsTheme(const int tid, libhttppp::HttpRequest &req, const std::string &sessionid){
    bool saved = false;
    bool reset = false;
    std::string logoMsg;

    // Get auth token for mediadb
    std::string authToken;
    if (!sessionid.empty()) {
        try {
            Session sess(*_Config.TDatabase[tid]);
            sess.getSessionData(sessionid, "authid", authToken);
        } catch (...) {}
    }

    // Handle form POST — save dark and light color fields
    libhttppp::HttpForm form;
@@ -608,11 +581,15 @@ json_object* blogi::Theme::SettingsTheme(const int tid, libhttppp::HttpRequest &
    const char *suffixes[] = {"BG","SURFACE","SURFACE_A","TEXT","TEXT_MUTED","ACCENT","ACCENT_DARK","BORDER","BG_ALT","ERROR","ERROR_BG","ERROR_TEXT","SUCCESS_BG","SUCCESS_TEXT","NAV_ACTIVE","NAV_HOVER","NAV_BORDER"};
    const char *profiles[] = {"dark", "light"};

    // Check for reset / logo delete / logo width
    // Check for reset / logo URL / logo width
    for(const auto &cur : form.urlData()){
        if(cur.key == "theme_reset" && cur.value == "1"){
            reset = true;
        }
        if(cur.key == "logo_url"){
            setConfig(*_Config.TDatabase[tid], "THEME_LOGO_URL", cur.value);
            saved = true;
        }
        if(cur.key == "logo_width" && !cur.value.empty()){
            int w = std::atoi(cur.value.c_str());
            if (w > 0 && w <= 4096) {
@@ -627,7 +604,6 @@ json_object* blogi::Theme::SettingsTheme(const int tid, libhttppp::HttpRequest &
                    if (arr) json_object_put(arr);
                    arr = json_object_new_array();
                }
                // Check if this width already exists (h=0 means auto)
                bool found = false;
                size_t alen = json_object_array_length(arr);
                for (size_t i = 0; i < alen; ++i) {
@@ -653,107 +629,6 @@ json_object* blogi::Theme::SettingsTheme(const int tid, libhttppp::HttpRequest &
                saved = true;
            }
        }
        if(cur.key == "delete_logo" && !cur.value.empty()){
            // Delete logo from mediadb and clear config
            std::string oldMediaId;
            try { getConfig(*_Config.TDatabase[tid], "THEME_LOGO_MEDIA_ID", oldMediaId); } catch (...) {}
            if (!oldMediaId.empty()) {
                try {
                    ensureMediaClient(tid, authToken);
                    if (_MdbClients[tid])
                        _MdbClients[tid]->delete_media(oldMediaId);
                } catch (...) {}
                setConfig(*_Config.TDatabase[tid], "THEME_LOGO_MEDIA_ID", "");
                setConfig(*_Config.TDatabase[tid], "THEME_LOGO_MEDIA_EXT", "");
            }
            logoMsg = "Logo deleted!";
            saved = true;
        }
    }

    // Handle logo file upload (multipart)
    for (const auto &part : form.multipartData()) {
        std::string fieldName, filename;
        for (const auto &disp : part.dispositions) {
            if (disp.key == "name") fieldName = disp.value;
            if (disp.key == "filename") filename = disp.value;
        }
        if (fieldName == "theme_logo" && !filename.empty() && !part.value.empty()) {
            try {
                ensureMediaClient(tid, authToken);
                if (!_MdbClients[tid]) {
                    logoMsg = "MediaDB not configured (set MEDIADB_URL)";
                    break;
                }

                // Find or create a "theme" album in the first available store
                std::string albumId;
                std::string mdbStores;
                try { getConfig(*_Config.TDatabase[tid], "MEDIADB_STORES", mdbStores); } catch (...) {}

                // Parse first store ID from JSON array
                std::string storeId;
                if (!mdbStores.empty()) {
                    json_object *jstores = json_tokener_parse(mdbStores.c_str());
                    if (jstores && json_object_is_type(jstores, json_type_array) && json_object_array_length(jstores) > 0) {
                        storeId = json_object_get_string(json_object_array_get_idx(jstores, 0));
                    }
                    if (jstores) json_object_put(jstores);
                }

                if (storeId.empty()) {
                    // Try single store config
                    try { getConfig(*_Config.TDatabase[tid], "MEDIADB_STORE", storeId); } catch (...) {}
                }

                if (storeId.empty()) {
                    // List stores and use first one
                    auto stores = _MdbClients[tid]->list_stores();
                    if (!stores.empty()) storeId = stores[0].id;
                }

                if (storeId.empty()) {
                    logoMsg = "No MediaDB store available";
                    break;
                }

                // Find or create "blogi-theme" album
                auto albums = _MdbClients[tid]->list_albums(storeId);
                for (const auto &a : albums) {
                    if (a.name == "blogi-theme") { albumId = a.id; break; }
                }
                if (albumId.empty()) {
                    auto newAlbum = _MdbClients[tid]->create_album(storeId, "blogi-theme");
                    albumId = newAlbum.id;
                }

                // Delete old logo if exists
                std::string oldMediaId;
                try { getConfig(*_Config.TDatabase[tid], "THEME_LOGO_MEDIA_ID", oldMediaId); } catch (...) {}
                if (!oldMediaId.empty()) {
                    try { _MdbClients[tid]->delete_media(oldMediaId); } catch (...) {}
                }

                // Upload
                std::vector<std::uint8_t> payload(
                    reinterpret_cast<const std::uint8_t*>(part.value.data()),
                    reinterpret_cast<const std::uint8_t*>(part.value.data()) + part.value.size());
                auto mi = _MdbClients[tid]->upload(albumId, filename, payload);

                // Determine extension
                std::string ext = "webp";
                size_t dp = mi.filename.rfind('.');
                if (dp != std::string::npos) ext = mi.filename.substr(dp + 1);

                setConfig(*_Config.TDatabase[tid], "THEME_LOGO_MEDIA_ID", mi.id);
                setConfig(*_Config.TDatabase[tid], "THEME_LOGO_MEDIA_EXT", ext);
                logoMsg = "Logo uploaded!";
                saved = true;
            } catch (std::exception &e) {
                logoMsg = std::string("Upload failed: ") + e.what();
            }
            break;
        }
    }

    struct ColorDef { const char *suffix; const char *label; const char *darkDef; const char *lightDef; };
@@ -805,15 +680,9 @@ json_object* blogi::Theme::SettingsTheme(const int tid, libhttppp::HttpRequest &
    json_object *jroot = json_object_new_object();
    json_object_object_add(jroot, "title", json_object_new_string("Theme Settings"));

    if(saved && !logoMsg.empty()){
        json_object_object_add(jroot, "message", json_object_new_string(logoMsg.c_str()));
        json_object_object_add(jroot, "message_type", json_object_new_string("success"));
    } else if(saved){
    if(saved){
        json_object_object_add(jroot, "message", json_object_new_string("Saved!"));
        json_object_object_add(jroot, "message_type", json_object_new_string("success"));
    } else if(!logoMsg.empty()){
        json_object_object_add(jroot, "message", json_object_new_string(logoMsg.c_str()));
        json_object_object_add(jroot, "message_type", json_object_new_string("error"));
    }
    if(reset){
        json_object_object_add(jroot, "message", json_object_new_string("Reset to defaults!"));
@@ -823,33 +692,35 @@ json_object* blogi::Theme::SettingsTheme(const int tid, libhttppp::HttpRequest &
    json_object *jform = json_object_new_object();
    json_object_object_add(jform, "method", json_object_new_string("POST"));
    json_object_object_add(jform, "action", json_object_new_string(req.getRequestURL().c_str()));
    json_object_object_add(jform, "enctype", json_object_new_string("multipart/form-data"));

    json_object *jfields = json_object_new_array();

    // Section header: Logo
    {
        std::string logoUrl = getLogoUrl(tid);
        std::string curMediaId;
        try { getConfig(*_Config.TDatabase[tid], "THEME_LOGO_MEDIA_ID", curMediaId); } catch (...) {}
        std::string curUrl;
        try { getConfig(*_Config.TDatabase[tid], "THEME_LOGO_URL", curUrl); } catch (...) {}

        std::string logoLabel = "Logo";
        if (!curMediaId.empty())
        logoLabel += " &mdash; <img src=\"" + logoUrl + "\" style=\"max-height:60px;max-width:200px;vertical-align:middle;margin-left:8px;\" />";
        else
            logoLabel += " (using theme default)";
        if (curUrl.empty())
            logoLabel += " <small>(theme default)</small>";

        json_object *jf = json_object_new_object();
        json_object_object_add(jf, "type", json_object_new_string("heading"));
        json_object_object_add(jf, "label", json_object_new_string(logoLabel.c_str()));
        json_object_array_add(jfields, jf);
    }
    // Logo file upload
    // Logo URL (from media plugin — upload via Media settings, paste URL here)
    {
        std::string curUrl;
        try { getConfig(*_Config.TDatabase[tid], "THEME_LOGO_URL", curUrl); } catch (...) {}

        json_object *jf = json_object_new_object();
        json_object_object_add(jf, "name", json_object_new_string("theme_logo"));
        json_object_object_add(jf, "type", json_object_new_string("file"));
        json_object_object_add(jf, "label", json_object_new_string("Upload Logo"));
        json_object_object_add(jf, "name", json_object_new_string("logo_url"));
        json_object_object_add(jf, "type", json_object_new_string("text"));
        json_object_object_add(jf, "label", json_object_new_string("Logo URL (e.g. /media/getimage/UUID.webp) &mdash; leave empty for theme default"));
        json_object_object_add(jf, "value", json_object_new_string(curUrl.c_str()));
        json_object_array_add(jfields, jf);
    }
    // Logo width
@@ -865,20 +736,6 @@ json_object* blogi::Theme::SettingsTheme(const int tid, libhttppp::HttpRequest &
        json_object_object_add(jf, "value", json_object_new_string(curWidth.c_str()));
        json_object_array_add(jfields, jf);
    }
    // Delete logo checkbox (only if a logo is set)
    {
        std::string curMediaId;
        try { getConfig(*_Config.TDatabase[tid], "THEME_LOGO_MEDIA_ID", curMediaId); } catch (...) {}
        if (!curMediaId.empty()) {
            json_object *jf = json_object_new_object();
            json_object_object_add(jf, "name", json_object_new_string("delete_logo"));
            json_object_object_add(jf, "type", json_object_new_string("checkbox"));
            json_object_object_add(jf, "label", json_object_new_string("Delete Logo (revert to theme default)"));
            json_object_object_add(jf, "value", json_object_new_string("1"));
            json_object_array_add(jfields, jf);
        }
    }

    // Section header: Dark
    {
        json_object *jf = json_object_new_object();
+2 −7
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <string>
#include <vector>
#include <memory>

#include <netplus/socket.h>
#include <netplus/connection.h>
@@ -37,7 +36,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <dbpp/database.h>
#include <json-c/json.h>
#include <mediadb/client.h>

#include "conf.h"
#include "auth.h"
@@ -87,18 +85,15 @@ namespace blogi {
        /// Build a <style> block with CSS custom properties from the active theme profile
        void injectThemeColors(const int tid, libhtmlpp::HtmlElement *index);

        /// Settings UI for theme colors + logo upload (returns JSON form descriptor)
        /// Settings UI for theme colors + logo (returns JSON form descriptor)
        json_object* SettingsTheme(const int tid, libhttppp::HttpRequest &req, const std::string &sessionid);

        /// Get the logo URL (uploaded or theme default)
        /// Get the logo URL (configured or theme default)
        std::string getLogoUrl(const int tid) const;

    private:
        void ensureMediaClient(const int tid, const std::string &token = "");

        ThemeConfig                                        _Config;
        std::vector<ThemeFiles>                             _PublicFiles;
        bool                                               _Formated;
        mutable std::vector<std::unique_ptr<mediadb::Client>> _MdbClients;
    };
};