From abb68ff67ff30af0c537a792ab3c82085e5930a9 Mon Sep 17 00:00:00 2001 From: ebcq Date: Wed, 1 Jul 2026 18:13:35 +0200 Subject: [PATCH 1/6] refactor: hint button handling --- src/commands/commands.h | 7 ++++ src/commands/project_cmd.cpp | 65 +++++++++++++++++------------------- src/main.cpp | 2 ++ 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/commands/commands.h b/src/commands/commands.h index ed5bb73..0d13298 100644 --- a/src/commands/commands.h +++ b/src/commands/commands.h @@ -50,6 +50,13 @@ namespace cmd */ void projectCommand(dpp::cluster& bot, const dpp::slashcommand_t& event); + /** + * @brief Handles hint button clicks for project ideas + * @param bot cluster + * @param event button click event + */ + void handleProjectHintButton(dpp::cluster& bot, const dpp::button_click_t& event); + /** * @brief Replies with the rules * @param bot cluster diff --git a/src/commands/project_cmd.cpp b/src/commands/project_cmd.cpp index a2214c4..e0019bf 100644 --- a/src/commands/project_cmd.cpp +++ b/src/commands/project_cmd.cpp @@ -3,6 +3,37 @@ using json = nlohmann::json; +void cmd::handleProjectHintButton(dpp::cluster& bot, const dpp::button_click_t& event) +{ + // Remove button + dpp::message updatedMsg = event.command.get_context_message(); + updatedMsg.components.clear(); + bot.message_edit(updatedMsg); + + json data; + try + { + std::ifstream projectFile("res/project.json"); + projectFile >> data; + } + catch (const json::parse_error& e) + { + event.reply("Failed to parse project file."); + return; + } + + const int hintButtonIndex = std::stoi(event.custom_id.substr(event.custom_id.rfind('_') + 1)); + const auto& project = data["projects"][hintButtonIndex]; + const std::string hint = project.contains("hint") ? project["hint"] : "No hint available."; + + dpp::embed hintEmbed = dpp::embed() + .set_color(globals::color::defaultColor) + .add_field("Hint", hint); + + dpp::message hintMessage(event.command.channel_id, hintEmbed); + event.reply(hintMessage); +} + void cmd::projectCommand(dpp::cluster& bot, const dpp::slashcommand_t& event) { static int index = 0; @@ -68,39 +99,5 @@ void cmd::projectCommand(dpp::cluster& bot, const dpp::slashcommand_t& event) event.reply(message); - bot.on_button_click([&bot](const dpp::button_click_t& event) { - // Ignore if button id does not start with hint_button_ - if (event.custom_id.rfind("hint_button_", 0) != 0) - return; - - // Remove button - dpp::message updatedMsg = event.command.get_context_message(); - updatedMsg.components.clear(); - bot.message_edit(updatedMsg); - - json data; - try - { - std::ifstream projectFile("res/project.json"); - projectFile >> data; - } - catch (const json::parse_error& e) - { - event.reply("Failed to parse project file."); - return; - } - - const int hintButtonIndex = std::stoi(event.custom_id.substr(event.custom_id.rfind('_') + 1)); - const auto& project = data["projects"][hintButtonIndex]; - const std::string hint = project.contains("hint") ? project["hint"] : "No hint available."; - - dpp::embed hintEmbed = dpp::embed() - .set_color(globals::color::defaultColor) - .add_field("Hint", hint); - - dpp::message hintMessage(event.command.channel_id, hintEmbed); - event.reply(hintMessage); - }); - index++; } diff --git a/src/main.cpp b/src/main.cpp index 459c1b5..912af3a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -79,6 +79,8 @@ int main() utils::suggestion::deleteSuggestion(bot, event); else if (event.custom_id == "editSuggestion") utils::suggestion::editSuggestion(bot, event); + else if (event.custom_id.starts_with("hint_button_")) + cmd::handleProjectHintButton(bot, event); }); bot.on_form_submit([&bot](const dpp::form_submit_t& event) { From 859901fe979639298f4e07d1a9ae7b9bad4aa8ee Mon Sep 17 00:00:00 2001 From: ebcq Date: Wed, 1 Jul 2026 18:21:45 +0200 Subject: [PATCH 2/6] refactor: optimize message reaction handling in createSuggestion --- src/utils/suggestion/suggestion.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/utils/suggestion/suggestion.cpp b/src/utils/suggestion/suggestion.cpp index 65ed685..e1d3ce3 100644 --- a/src/utils/suggestion/suggestion.cpp +++ b/src/utils/suggestion/suggestion.cpp @@ -38,23 +38,28 @@ void utils::suggestion::createSuggestion(dpp::cluster& bot, const dpp::message_c if (!callback.is_error()) { const dpp::message msg = std::get(callback.value); + const dpp::snowflake messageId = msg.id; + const dpp::snowflake channelId = msg.channel_id; const auto yesEmoji = dpp::find_emoji(globals::emoji::yes); const auto noEmoji = dpp::find_emoji(globals::emoji::no); if (yesEmoji && noEmoji) { - bot.message_add_reaction(msg.id, msg.channel_id, yesEmoji->format(), [&bot, &msg, &noEmoji](const dpp::confirmation_callback_t& reactionCallback) { + const std::string yesEmojiText = yesEmoji->format(); + const std::string noEmojiText = noEmoji->format(); + + bot.message_add_reaction(messageId, channelId, yesEmojiText, [&bot, messageId, channelId, noEmojiText](const dpp::confirmation_callback_t& reactionCallback) { if (!reactionCallback.is_error()) - bot.message_add_reaction(msg.id, msg.channel_id, noEmoji->format()); + bot.message_add_reaction(messageId, channelId, noEmojiText); }); } else { // fallback - bot.message_add_reaction(msg.id, msg.channel_id, "👍", [&bot, &msg](const dpp::confirmation_callback_t& reactionCallback) { + bot.message_add_reaction(messageId, channelId, "👍", [&bot, messageId, channelId](const dpp::confirmation_callback_t& reactionCallback) { if (!reactionCallback.is_error()) - bot.message_add_reaction(msg.id, msg.channel_id, "👎"); + bot.message_add_reaction(messageId, channelId, "👎"); }); } } From 5f9f0cf7953c858cde312006c21b99621ae60c70 Mon Sep 17 00:00:00 2001 From: ebcq Date: Wed, 1 Jul 2026 20:55:33 +0200 Subject: [PATCH 3/6] refactor: snowflake from config --- CMakeLists.txt | 1 + README.md | 15 ++++++- src/config.json | 1 - src/config.json.example | 10 +++++ src/globals/globals.cpp | 99 +++++++++++++++++++++++++++++++++++++++++ src/globals/globals.h | 24 +++++++--- src/main.cpp | 8 ++++ 7 files changed, 149 insertions(+), 9 deletions(-) delete mode 100644 src/config.json create mode 100644 src/config.json.example create mode 100644 src/globals/globals.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index be98ca1..d35c902 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ add_executable(bot src/main.cpp #globals + src/globals/globals.cpp src/globals/globals.h # commands diff --git a/README.md b/README.md index 00120d6..ef758f9 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,20 @@ ```git clone https://github.com/cppdiscord/bot.git``` #### 2. Create the config file -Create a file called config.json in the src directory: ``{ "token": "bot token" }`` +Create a file called config.json in the src directory with the following values: + +```json +{ + "token": "your bot token", + "emoji_yes_id": "your yes emoji id", + "emoji_no_id": "your no emoji id", + "channel_rules_id": "your rules channel id", + "channel_jail_id": "your jail channel id", + "category_ticket_id": "your ticket category id", + "role_staff_id": "your staff role id", + "role_jail_id": "your jail role id" +} +``` ## Contributing We appreciate contributions to this community. Connect with other contributors through our [discord server](https://discord.gg/cpp), where we have dedicated channels for chatting and collaborating. diff --git a/src/config.json b/src/config.json deleted file mode 100644 index 917d0a1..0000000 --- a/src/config.json +++ /dev/null @@ -1 +0,0 @@ -{ "token": "bot token" } diff --git a/src/config.json.example b/src/config.json.example new file mode 100644 index 0000000..3a4955c --- /dev/null +++ b/src/config.json.example @@ -0,0 +1,10 @@ +{ + "token": "bot token", + "emoji_yes_id": "1226134958872199229", + "emoji_no_id": "1226134940006219817", + "channel_rules_id": "1130464978860785705", + "channel_jail_id": "1513269975844917409", + "category_ticket_id": "1234179713182732374", + "role_staff_id": "1130473404345110621", + "role_jail_id": "1506351798900887582" +} diff --git a/src/globals/globals.cpp b/src/globals/globals.cpp new file mode 100644 index 0000000..7deb27b --- /dev/null +++ b/src/globals/globals.cpp @@ -0,0 +1,99 @@ +#include "globals.h" + +namespace +{ + bool parseSnowflake(const nlohmann::json& config, const char* key, dpp::snowflake& out) + { + if (!config.contains(key)) + return false; + + const auto& value = config.at(key); + + if (value.is_string()) + { + out = dpp::snowflake(value.get()); + return true; + } + + if (value.is_number_unsigned() || value.is_number_integer()) + { + out = dpp::snowflake(value.get()); + return true; + } + + return false; + } +} + +namespace globals +{ + namespace emoji + { + dpp::snowflake yes{}; + dpp::snowflake no{}; + } + + namespace channel + { + dpp::snowflake rulesId{}; + dpp::snowflake jailId{}; + } + + namespace category + { + dpp::snowflake ticketId{}; + } + + namespace role + { + dpp::snowflake staffId{}; + dpp::snowflake jailId{}; + } + + bool loadFromConfig(const nlohmann::json& config, std::string& error) + { + if (!parseSnowflake(config, "emoji_yes_id", emoji::yes)) + { + error = "Missing or invalid config key: emoji_yes_id"; + return false; + } + + if (!parseSnowflake(config, "emoji_no_id", emoji::no)) + { + error = "Missing or invalid config key: emoji_no_id"; + return false; + } + + if (!parseSnowflake(config, "channel_rules_id", channel::rulesId)) + { + error = "Missing or invalid config key: channel_rules_id"; + return false; + } + + if (!parseSnowflake(config, "channel_jail_id", channel::jailId)) + { + error = "Missing or invalid config key: channel_jail_id"; + return false; + } + + if (!parseSnowflake(config, "category_ticket_id", category::ticketId)) + { + error = "Missing or invalid config key: category_ticket_id"; + return false; + } + + if (!parseSnowflake(config, "role_staff_id", role::staffId)) + { + error = "Missing or invalid config key: role_staff_id"; + return false; + } + + if (!parseSnowflake(config, "role_jail_id", role::jailId)) + { + error = "Missing or invalid config key: role_jail_id"; + return false; + } + + return true; + } +} diff --git a/src/globals/globals.h b/src/globals/globals.h index c095d3b..8420dc3 100644 --- a/src/globals/globals.h +++ b/src/globals/globals.h @@ -2,6 +2,8 @@ #define GLOBALS_H #include +#include +#include namespace globals { @@ -10,27 +12,35 @@ namespace globals static constexpr int defaultColor = 0x004482; } + /** + * @brief Load configured IDs used by the bot. + * @param config Parsed config JSON object. + * @param error Output error message when loading fails. + * @return true when all required IDs were loaded successfully. + */ + bool loadFromConfig(const nlohmann::json& config, std::string& error); + namespace emoji { - static constexpr dpp::snowflake yes = 1226134958872199229; - static constexpr dpp::snowflake no = 1226134940006219817; + extern dpp::snowflake yes; + extern dpp::snowflake no; } namespace channel { - static constexpr dpp::snowflake rulesId = 1130464978860785705; - static constexpr dpp::snowflake jailId = 1513269975844917409; + extern dpp::snowflake rulesId; + extern dpp::snowflake jailId; } namespace category { - static constexpr dpp::snowflake ticketId = 1234179713182732374; + extern dpp::snowflake ticketId; } namespace role { - static constexpr dpp::snowflake staffId = 1130473404345110621; - static constexpr dpp::snowflake jailId = 1506351798900887582; + extern dpp::snowflake staffId; + extern dpp::snowflake jailId; } } diff --git a/src/main.cpp b/src/main.cpp index 912af3a..c06f872 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include #include "commands/commands.h" +#include "globals/globals.h" #include "utils/suggestion/suggestion.h" #include "utils/moderation/moderation.h" @@ -24,6 +25,13 @@ int main() std::ifstream configFile("config.json"); json config = json::parse(configFile); + std::string globalsConfigError; + if (!globals::loadFromConfig(config, globalsConfigError)) + { + std::cerr << "[!] Invalid configuration: " << globalsConfigError << std::endl; + return 1; + } + dpp::cluster bot(config["token"], dpp::i_default_intents | dpp::i_message_content); ModerationService moderationService(bot); From 2570563f91ad703f2b496eb85670fc19ca141c02 Mon Sep 17 00:00:00 2001 From: ebcq Date: Wed, 1 Jul 2026 21:10:28 +0200 Subject: [PATCH 4/6] refactor: dont require config.json --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d35c902..ed8472d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,11 @@ else() message(STATUS "Using system-installed DPP") endif() -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/config.json DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/config.json) + file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/config.json DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +else() + message(STATUS "src/config.json not found; skipping config copy") +endif() file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/res DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) add_executable(bot From 67e7c0bb1661ddd075e4ea22625dcd19c8a4e5d9 Mon Sep 17 00:00:00 2001 From: ebcq Date: Wed, 1 Jul 2026 21:14:58 +0200 Subject: [PATCH 5/6] fix: remove include --- src/globals/globals.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/globals/globals.h b/src/globals/globals.h index 8420dc3..da4c962 100644 --- a/src/globals/globals.h +++ b/src/globals/globals.h @@ -2,7 +2,6 @@ #define GLOBALS_H #include -#include #include namespace globals From 89ba576813bfb35dda686155b36f6b3a436508c7 Mon Sep 17 00:00:00 2001 From: ebcq Date: Wed, 1 Jul 2026 21:21:09 +0200 Subject: [PATCH 6/6] fix: includes --- src/globals/globals.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/globals/globals.cpp b/src/globals/globals.cpp index 7deb27b..7c14267 100644 --- a/src/globals/globals.cpp +++ b/src/globals/globals.cpp @@ -1,5 +1,8 @@ #include "globals.h" +#include +#include + namespace { bool parseSnowflake(const nlohmann::json& config, const char* key, dpp::snowflake& out)