diff --git a/include/settings.hpp b/include/settings.hpp index dc3e8f6b..05b79925 100644 --- a/include/settings.hpp +++ b/include/settings.hpp @@ -90,12 +90,17 @@ struct ModuleInfo { int added = 0; double lastAdded = NAN; }; -// pluginSlug -> (moduleSlug -> ModuleInfo) +/** pluginSlug -> (moduleSlug -> ModuleInfo) */ extern std::map> moduleInfos; /** Returns a ModuleInfo if exists for the given slugs. */ ModuleInfo* getModuleInfo(const std::string& pluginSlug, const std::string& moduleSlug); +/** pluginSlug -> {moduleSlug} */ +extern std::map> moduleWhitelist; + +bool isModuleWhitelisted(const std::string& pluginSlug, const std::string& moduleSlug); + void init(); json_t* toJson(); void fromJson(json_t* rootJ); diff --git a/src/app/Browser.cpp b/src/app/Browser.cpp index 23c24264..cb486882 100644 --- a/src/app/Browser.cpp +++ b/src/app/Browser.cpp @@ -609,10 +609,15 @@ struct Browser : widget::OpaqueWidget { if (model->hidden) return false; + // Filter moduleInfo setting if enabled is false settings::ModuleInfo* mi = settings::getModuleInfo(model->plugin->slug, model->slug); if (mi && !mi->enabled) return false; + // Filter if not whitelisted by library + if (!settings::isModuleWhitelisted(model->plugin->slug, model->slug)) + return false; + // Filter favorites if (favorite) { if (!mi || !mi->favorite) diff --git a/src/library.cpp b/src/library.cpp index 4ad07da2..bd3b1220 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -163,12 +163,25 @@ void checkUpdates() { } DEFER({json_decref(userResJ);}); + // Get library manifests + std::string manifestsUrl = API_URL + "/library/manifests"; + json_t* manifestsReq = json_object(); + json_object_set(manifestsReq, "version", json_string(APP_VERSION_MAJOR.c_str())); + json_t* manifestsResJ = network::requestJson(network::METHOD_GET, manifestsUrl, manifestsReq); + json_decref(manifestsReq); + if (!manifestsResJ) { + WARN("Request for library manifests failed"); + updateStatus = "Could not query plugin manifests"; + return; + } + DEFER({json_decref(manifestsResJ);}); + // Get user's plugins list std::string pluginsUrl = API_URL + "/plugins"; json_t* pluginsResJ = network::requestJson(network::METHOD_GET, pluginsUrl, NULL, getTokenCookies()); if (!pluginsResJ) { WARN("Request for user's plugins failed"); - updateStatus = "Could not query plugins"; + updateStatus = "Could not query user's plugins"; return; } DEFER({json_decref(pluginsResJ);}); @@ -180,19 +193,6 @@ void checkUpdates() { return; } - // Get library manifests - std::string manifestsUrl = API_URL + "/library/manifests"; - json_t* manifestsReq = json_object(); - json_object_set(manifestsReq, "version", json_string(APP_VERSION_MAJOR.c_str())); - json_t* manifestsResJ = network::requestJson(network::METHOD_GET, manifestsUrl, manifestsReq); - json_decref(manifestsReq); - if (!manifestsResJ) { - WARN("Request for library manifests failed"); - updateStatus = "Could not query updates"; - return; - } - DEFER({json_decref(manifestsResJ);}); - json_t* manifestsJ = json_object_get(manifestsResJ, "manifests"); json_t* pluginsJ = json_object_get(pluginsResJ, "plugins"); @@ -252,36 +252,42 @@ void checkUpdates() { } // Get module whitelist - // TODO - // { - // std::string whitelistUrl = API_URL + "/modules"; - // json_t* whitelistResJ = network::requestJson(network::METHOD_GET, whitelistUrl, NULL, getTokenCookies()); - // if (!whitelistResJ) { - // WARN("Request for module whitelist failed"); - // updateStatus = "Could not query updates"; - // return; - // } - // DEFER({json_decref(whitelistResJ);}); - - // std::map> moduleWhitelist; - // json_t* pluginsJ = json_object_get(whitelistResJ, "plugins"); - - // // Iterate plugins - // const char* pluginSlug; - // json_t* modulesJ; - // json_object_foreach(pluginsJ, pluginSlug, modulesJ) { - // // Iterate modules in plugin - // size_t moduleIndex; - // json_t* moduleSlugJ; - // json_array_foreach(modulesJ, moduleIndex, moduleSlugJ) { - // std::string moduleSlug = json_string_value(moduleSlugJ); - // // Insert module in whitelist - // moduleWhitelist[pluginSlug].insert(moduleSlug); - // } - // } - - // settings::moduleWhitelist = moduleWhitelist; - // } + { + std::string whitelistUrl = API_URL + "/modules"; + json_t* whitelistResJ = network::requestJson(network::METHOD_GET, whitelistUrl, NULL, getTokenCookies()); + if (!whitelistResJ) { + WARN("Request for module whitelist failed"); + updateStatus = "Could not query user's modules"; + return; + } + DEFER({json_decref(whitelistResJ);}); + + // Clone plugin slugs from settings to temporary whitelist. + // This makes plugins entirely hidden if removed. + std::map> moduleWhitelist; + for (const auto& pluginPair : settings::moduleWhitelist) { + // Create an empty set + moduleWhitelist[pluginPair.first]; + } + + // Iterate plugins + json_t* pluginsJ = json_object_get(whitelistResJ, "plugins"); + const char* pluginSlug; + json_t* modulesJ; + json_object_foreach(pluginsJ, pluginSlug, modulesJ) { + // Iterate modules in plugin + size_t moduleIndex; + json_t* moduleSlugJ; + json_array_foreach(modulesJ, moduleIndex, moduleSlugJ) { + std::string moduleSlug = json_string_value(moduleSlugJ); + // Insert module in whitelist + DEBUG("plugin %s module %s", pluginSlug, moduleSlug.c_str()); + moduleWhitelist[pluginSlug].insert(moduleSlug); + } + } + + settings::moduleWhitelist = moduleWhitelist; + } updateStatus = ""; refreshRequested = true; diff --git a/src/network.cpp b/src/network.cpp index 4ff4fc04..a50d7b81 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -138,8 +138,6 @@ json_t* requestJson(Method method, const std::string& url, json_t* dataJ, const curl_easy_cleanup(curl); curl_slist_free_all(headers); - DEBUG("response: %s", resText.c_str()); - if (res != CURLE_OK) { WARN("Could not request %s: %s", urlS.c_str(), curl_easy_strerror(res)); return NULL; diff --git a/src/settings.cpp b/src/settings.cpp index 04f1296d..3ab3a88a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -63,6 +63,7 @@ bool discordUpdateActivity = true; BrowserSort browserSort = BROWSER_SORT_UPDATED; float browserZoom = -1.f; std::map> moduleInfos; +std::map> moduleWhitelist; ModuleInfo* getModuleInfo(const std::string& pluginSlug, const std::string& moduleSlug) { @@ -76,6 +77,18 @@ ModuleInfo* getModuleInfo(const std::string& pluginSlug, const std::string& modu } +bool isModuleWhitelisted(const std::string& pluginSlug, const std::string& moduleSlug) { + auto pluginIt = moduleWhitelist.find(pluginSlug); + // All modules in a plugin are visible if plugin set is empty. + if (pluginIt == moduleWhitelist.end()) + return true; + auto moduleIt = pluginIt->second.find(moduleSlug); + if (moduleIt == pluginIt->second.end()) + return false; + return true; +} + + void init() { settingsPath = asset::user("settings.json"); } @@ -159,6 +172,7 @@ json_t* toJson() { json_object_set_new(rootJ, "browserZoom", json_real(browserZoom)); + // moduleInfos json_t* moduleInfosJ = json_object(); for (const auto& pluginPair : moduleInfos) { json_t* pluginJ = json_object(); @@ -188,6 +202,17 @@ json_t* toJson() { } json_object_set_new(rootJ, "moduleInfos", moduleInfosJ); + // moduleWhitelist + json_t* moduleWhitelistJ = json_object(); + for (const auto& pluginPair : moduleWhitelist) { + json_t* pluginJ = json_array(); + for (const std::string& moduleSlug : pluginPair.second) { + json_array_append_new(pluginJ, json_stringn(moduleSlug.c_str(), moduleSlug.size())); + } + json_object_set_new(moduleWhitelistJ, pluginPair.first.c_str(), pluginJ); + } + json_object_set_new(rootJ, "moduleWhitelist", moduleWhitelistJ); + return rootJ; } @@ -367,6 +392,21 @@ void fromJson(json_t* rootJ) { } } } + + moduleWhitelist.clear(); + json_t* moduleWhitelistJ = json_object_get(rootJ, "moduleWhitelist"); + if (moduleWhitelistJ) { + const char* pluginSlug; + json_t* pluginJ; + json_object_foreach(moduleWhitelistJ, pluginSlug, pluginJ) { + size_t moduleIndex; + json_t* moduleJ; + json_array_foreach(pluginJ, moduleIndex, moduleJ) { + std::string moduleSlug = json_string_value(moduleJ); + moduleWhitelist[pluginSlug].insert(moduleSlug); + } + } + } } void save(std::string path) {