From 0ee555c77d06b6af8bd27051f91acf8feb0cb6c9 Mon Sep 17 00:00:00 2001 From: Xander Zheleva Date: Sun, 17 Aug 2025 16:37:18 +0300 Subject: [PATCH 1/8] Update main.cpp --- src/main.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 541ce3a..0e70bc1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,10 +68,58 @@ int main() }); bot.on_button_click([&bot](const dpp::button_click_t& event) { + // Handle suggestion buttons if (event.custom_id == "delSuggestion") utils::suggestion::deleteSuggestion(bot, event); else if (event.custom_id == "editSuggestion") utils::suggestion::editSuggestion(bot, event); + // Handle project hint buttons + else if (event.custom_id.rfind("hint_button_", 0) == 0) + { + // Remove button + dpp::message updatedMsg = event.command.get_context_message(); + updatedMsg.components.clear(); + bot.message_edit(updatedMsg); + + // Parse the index from the button ID + const int hintButtonIndex = std::stoi(event.custom_id.substr(event.custom_id.rfind('_') + 1)); + + // Load project data + std::ifstream projectFile("res/project.json"); + if (!projectFile.is_open()) + { + event.reply(dpp::message("Failed to open project file.").set_flags(dpp::m_ephemeral)); + return; + } + + json data; + try + { + projectFile >> data; + } + catch (const json::parse_error& e) + { + event.reply(dpp::message("Failed to parse project file.").set_flags(dpp::m_ephemeral)); + return; + } + + if (!data.contains("projects") || !data["projects"].is_array() || + hintButtonIndex >= (int)data["projects"].size() || hintButtonIndex < 0) + { + event.reply(dpp::message("Invalid project data or index.").set_flags(dpp::m_ephemeral)); + return; + } + + 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(0x004482) // Using the default color directly since we can't access globals here + .add_field("Hint", hint); + + dpp::message hintMessage(event.command.channel_id, hintEmbed); + event.reply(hintMessage); + } }); bot.on_form_submit([&bot](const dpp::form_submit_t& event) { From e1b7f80bd5c9817a2403e9c0235483e134e11e32 Mon Sep 17 00:00:00 2001 From: Xander Zheleva Date: Sun, 17 Aug 2025 16:38:05 +0300 Subject: [PATCH 2/8] Update suggestion.cpp --- src/utils/suggestion/suggestion.cpp | 52 ++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/src/utils/suggestion/suggestion.cpp b/src/utils/suggestion/suggestion.cpp index 65ed685..d02558c 100644 --- a/src/utils/suggestion/suggestion.cpp +++ b/src/utils/suggestion/suggestion.cpp @@ -4,7 +4,7 @@ void utils::suggestion::createSuggestion(dpp::cluster& bot, const dpp::message_create_t& event) { dpp::user user = event.msg.author; - if (!user.is_bot()) + if (!user.is_bot() && !event.msg.content.empty()) { dpp::embed result = dpp::embed() .set_color(globals::color::defaultColor) @@ -34,7 +34,7 @@ void utils::suggestion::createSuggestion(dpp::cluster& bot, const dpp::message_c ) ); - bot.message_create(msg, [&bot](const dpp::confirmation_callback_t& callback) { + bot.message_create(msg, [&bot, event](const dpp::confirmation_callback_t& callback) { if (!callback.is_error()) { const dpp::message msg = std::get(callback.value); @@ -44,7 +44,7 @@ void utils::suggestion::createSuggestion(dpp::cluster& bot, const dpp::message_c if (yesEmoji && noEmoji) { - bot.message_add_reaction(msg.id, msg.channel_id, yesEmoji->format(), [&bot, &msg, &noEmoji](const dpp::confirmation_callback_t& reactionCallback) { + bot.message_add_reaction(msg.id, msg.channel_id, yesEmoji->format(), [&, msg, noEmoji](const dpp::confirmation_callback_t& reactionCallback) { if (!reactionCallback.is_error()) bot.message_add_reaction(msg.id, msg.channel_id, noEmoji->format()); }); @@ -52,19 +52,28 @@ void utils::suggestion::createSuggestion(dpp::cluster& bot, const dpp::message_c else { // fallback - bot.message_add_reaction(msg.id, msg.channel_id, "👍", [&bot, &msg](const dpp::confirmation_callback_t& reactionCallback) { + bot.message_add_reaction(msg.id, msg.channel_id, "👍", [&, msg](const dpp::confirmation_callback_t& reactionCallback) { if (!reactionCallback.is_error()) bot.message_add_reaction(msg.id, msg.channel_id, "👎"); }); } } + + // Delete the original message after attempting to create the suggestion + bot.message_delete(event.msg.id, event.msg.channel_id); }); - bot.message_delete(event.msg.id, event.msg.channel_id); } } void utils::suggestion::deleteSuggestion(dpp::cluster& bot, const dpp::button_click_t& event) { + // Check if the message has embeds and author information + if (event.command.msg.embeds.empty() || !event.command.msg.embeds[0].author) + { + event.reply(dpp::message("Invalid suggestion message.").set_flags(dpp::m_ephemeral)); + return; + } + std::string clicker = event.command.get_issuing_user().format_username(); std::string originalAuthor = event.command.msg.embeds[0].author->name; @@ -76,6 +85,13 @@ void utils::suggestion::deleteSuggestion(dpp::cluster& bot, const dpp::button_cl void utils::suggestion::editSuggestion(dpp::cluster& bot, const dpp::button_click_t& event) { + // Check if the message has embeds and author information + if (event.command.msg.embeds.empty() || !event.command.msg.embeds[0].author) + { + event.reply(dpp::message("Invalid suggestion message.").set_flags(dpp::m_ephemeral)); + return; + } + std::string clicker = event.command.get_issuing_user().format_username(); std::string originalAuthor = event.command.msg.embeds[0].author->name; @@ -102,21 +118,41 @@ void utils::suggestion::editSuggestion(dpp::cluster& bot, const dpp::button_clic void utils::suggestion::showSuggestionEditModal(dpp::cluster& bot, const dpp::form_submit_t& event) { + // Validate form data + if (event.components.empty() || event.components[0].components.empty()) + { + event.reply(dpp::message("Invalid form data.").set_flags(dpp::m_ephemeral)); + return; + } + std::string v = std::get(event.components[0].components[0].value); bot.message_get(event.command.msg.id, event.command.msg.channel_id, [&bot, event, v](const dpp::confirmation_callback_t& callback) { if (!callback.is_error()) { dpp::message msg = std::get(callback.value); - dpp::embed embed = event.command.msg.embeds[0]; - + + // Validate that the message has embeds + if (msg.embeds.empty()) + { + event.reply(dpp::message("Invalid suggestion message.").set_flags(dpp::m_ephemeral)); + return; + } + + dpp::embed embed = msg.embeds[0]; embed.set_description(v); msg.embeds[0] = embed; - bot.message_edit(msg, [&bot, event, embed](const dpp::confirmation_callback_t& callback) { + bot.message_edit(msg, [&bot, event](const dpp::confirmation_callback_t& callback) { if (!callback.is_error()) event.reply(dpp::message("Edited!").set_flags(dpp::m_ephemeral)); + else + event.reply(dpp::message("Failed to edit suggestion.").set_flags(dpp::m_ephemeral)); }); } + else + { + event.reply(dpp::message("Failed to retrieve suggestion message.").set_flags(dpp::m_ephemeral)); + } }); } From 77c912d6d3848d8173ba47f6f78902cc1259e841 Mon Sep 17 00:00:00 2001 From: Xander Zheleva Date: Sun, 17 Aug 2025 16:43:30 +0300 Subject: [PATCH 3/8] Update utils.cpp --- src/commands/utils.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/commands/utils.cpp b/src/commands/utils.cpp index 2745f58..e60b38d 100644 --- a/src/commands/utils.cpp +++ b/src/commands/utils.cpp @@ -2,25 +2,38 @@ #include #include +#include std::string cmd::utils::readFileLine(const std::string& path, int &index) { std::ifstream file(path); - std::string line; + if (file.is_open()) { - for (int i = 0; std::getline(file, line) && i < index; i++); + std::vector lines; + std::string currentLine; + while (std::getline(file, currentLine)) + { + if (!currentLine.empty()) + { + lines.push_back(currentLine); + } + } + file.close(); - // validate next line - if (std::string next; !getline(file, next) || line.length() == 0) - index = 0; - else - index++; + if (lines.empty()) + { + return "[!] No valid lines found in " + path; + } - file.close(); + index = index % lines.size(); + line = lines[index]; + index = (index + 1) % lines.size(); // Prepare for next call } else + { line = "[!] Could not open " + path; + } return line; } From 7635266ee0a8c96923b4c0fac9454198ee87805d Mon Sep 17 00:00:00 2001 From: Xander Zheleva Date: Sun, 17 Aug 2025 16:43:44 +0300 Subject: [PATCH 4/8] Update rule_cmd.cpp --- src/commands/rule_cmd.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/commands/rule_cmd.cpp b/src/commands/rule_cmd.cpp index 0af9778..a5c5b28 100644 --- a/src/commands/rule_cmd.cpp +++ b/src/commands/rule_cmd.cpp @@ -23,17 +23,17 @@ void cmd::ruleCommand(dpp::cluster& bot, const dpp::slashcommand_t& event) }; const dpp::command_interaction cmdData = event.command.get_command_interaction(); + if (cmdData.options.empty()) return event.reply(dpp::message("Please follow our <#" + globals::channel::rulesId.str() + ">.")); - const auto option = cmdData.options[0]; - - if (option.type != dpp::co_integer) - return; // should never happen + if (cmdData.options.empty() || cmdData.options[0].type != dpp::co_integer) + return event.reply(dpp::message("Invalid rule number provided.").set_flags(dpp::m_ephemeral)); + const auto option = cmdData.options[0]; const long index = std::get(option.value); - if ((index < 1 || index > rules.size())) + if (index < 1 || index > (long)rules.size()) return event.reply(dpp::message("Rule number " + std::to_string(index) + " does not exist. Visit <#" + globals::channel::rulesId.str() + "> to see all available rules.").set_flags(dpp::m_ephemeral)); const std::string& rule = rules.at(index-1); From 1c98556de41660f98f1ce149d2b51e6f77ae460f Mon Sep 17 00:00:00 2001 From: Xander Zheleva Date: Sun, 17 Aug 2025 16:43:58 +0300 Subject: [PATCH 5/8] Update project_cmd.cpp --- src/commands/project_cmd.cpp | 47 ++++++------------------------------ 1 file changed, 7 insertions(+), 40 deletions(-) diff --git a/src/commands/project_cmd.cpp b/src/commands/project_cmd.cpp index a2214c4..ecbf066 100644 --- a/src/commands/project_cmd.cpp +++ b/src/commands/project_cmd.cpp @@ -31,12 +31,14 @@ void cmd::projectCommand(dpp::cluster& bot, const dpp::slashcommand_t& event) return; } - // If index exceeds the number of projects, reset it to 0 - if (index >= data["projects"].size()) + if (data["projects"].empty()) { - index = 0; + event.reply("No projects available."); + return; } + index = index % data["projects"].size(); + const auto& project = data["projects"][index]; if (!project.contains("title") || !project.contains("description")) { @@ -55,7 +57,6 @@ void cmd::projectCommand(dpp::cluster& bot, const dpp::slashcommand_t& event) dpp::message message(event.command.channel_id, embed); - // Add hint button with index as custom_id message.add_component( dpp::component().add_component( dpp::component() @@ -67,40 +68,6 @@ 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++; + + index = (index + 1) % data["projects"].size(); } From 2ef7645a9a0707d0186c75c8693abd90cbe6a34d Mon Sep 17 00:00:00 2001 From: Xander Zheleva Date: Sun, 17 Aug 2025 16:44:41 +0300 Subject: [PATCH 6/8] Update ticket_cmd.cpp --- src/commands/ticket_cmd.cpp | 65 +++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/src/commands/ticket_cmd.cpp b/src/commands/ticket_cmd.cpp index aadf273..8df15e4 100644 --- a/src/commands/ticket_cmd.cpp +++ b/src/commands/ticket_cmd.cpp @@ -3,29 +3,52 @@ void cmd::ticketCommand(dpp::cluster& bot, const dpp::slashcommand_t& event) { - dpp::message message(event.command.channel_id, "Creating ticket..."); - event.reply(message.set_flags(dpp::m_ephemeral)); - - const dpp::channel ticketChannel = dpp::channel() - .set_name(event.command.get_issuing_user().username) - .set_type(dpp::CHANNEL_TEXT) - .set_guild_id(event.command.guild_id) - .set_parent_id(globals::category::ticketId) - .set_permission_overwrite(event.command.guild_id, dpp::overwrite_type::ot_role, 0, dpp::p_view_channel) - .set_permission_overwrite(event.command.get_issuing_user().id, dpp::overwrite_type::ot_member, dpp::p_view_channel, 0); - - bot.channel_create(ticketChannel, [&bot, event](const dpp::confirmation_callback_t& callback) { - if (!callback.is_error()) - { - const auto ticketChannel = std::get(callback.value); - const auto pingMessage = dpp::message(ticketChannel.id, event.command.get_issuing_user().get_mention() + " opened this ticket."); - bot.message_create(pingMessage); + bot.channels_get(event.command.guild_id, [&bot, event](const dpp::confirmation_callback_t& callback) { + if (callback.is_error()) { + dpp::message message(event.command.channel_id, "Failed to check existing tickets."); + return event.reply(message.set_flags(dpp::m_ephemeral)); + } - event.edit_response("Ticket " + ticketChannel.get_mention() + " created!"); + const auto channels = callback.get(); + bool hasExistingTicket = false; + + for (const auto& [channel_id, channel] : channels) { + if (channel.parent_id == globals::category::ticketId && + channel.name == event.command.get_issuing_user().username) { + hasExistingTicket = true; + break; + } } - else - { - event.edit_response("Failed to create ticket channel!"); + + if (hasExistingTicket) { + dpp::message message(event.command.channel_id, "You already have an open ticket."); + return event.reply(message.set_flags(dpp::m_ephemeral)); } + + dpp::message message(event.command.channel_id, "Creating ticket..."); + event.reply(message.set_flags(dpp::m_ephemeral)); + + const dpp::channel ticketChannel = dpp::channel() + .set_name(event.command.get_issuing_user().username) + .set_type(dpp::CHANNEL_TEXT) + .set_guild_id(event.command.guild_id) + .set_parent_id(globals::category::ticketId) + .set_permission_overwrite(event.command.guild_id, dpp::overwrite_type::ot_role, 0, dpp::p_view_channel) + .set_permission_overwrite(event.command.get_issuing_user().id, dpp::overwrite_type::ot_member, dpp::p_view_channel, 0); + + bot.channel_create(ticketChannel, [&bot, event](const dpp::confirmation_callback_t& callback) { + if (!callback.is_error()) + { + const auto ticketChannel = std::get(callback.value); + const auto pingMessage = dpp::message(ticketChannel.id, event.command.get_issuing_user().get_mention() + " opened this ticket."); + bot.message_create(pingMessage); + + event.edit_response("Ticket " + ticketChannel.get_mention() + " created!"); + } + else + { + event.edit_response("Failed to create ticket channel: " + callback.get_error().message); + } + }); }); } From 6ba69f6a79f5fe7459d63bff0e12a669a3f3bd9d Mon Sep 17 00:00:00 2001 From: Xander Zheleva Date: Sun, 17 Aug 2025 16:45:09 +0300 Subject: [PATCH 7/8] Update close_cmd.cpp --- src/commands/close_cmd.cpp | 58 ++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/src/commands/close_cmd.cpp b/src/commands/close_cmd.cpp index 4dcf845..8176ed8 100644 --- a/src/commands/close_cmd.cpp +++ b/src/commands/close_cmd.cpp @@ -1,4 +1,4 @@ -#include "commands.h" +#include "commands.h" #include "../globals/globals.h" #include @@ -8,18 +8,29 @@ void cmd::closeCommand(dpp::cluster& bot, const dpp::slashcommand_t& event) { - if (event.command.channel.get_type() == dpp::channel_type::CHANNEL_PUBLIC_THREAD) + const dpp::channel* channel = dpp::find_channel(event.command.channel_id); + if (!channel) + { + event.reply(dpp::message("[!] Channel not found").set_flags(dpp::m_ephemeral)); + return; + } + + if (channel->get_type() == dpp::channel_type::CHANNEL_PUBLIC_THREAD) { bot.thread_get(event.command.channel_id, [&bot, event](const dpp::confirmation_callback_t& callback) { if (callback.is_error()) return event.reply(dpp::message("[!] Callback error").set_flags(dpp::m_ephemeral)); - auto thread = callback.get(); + dpp::thread thread = callback.get(); - if (event.command.channel.owner_id != event.command.member.user_id) - return event.reply(dpp::message("You can only close your own posts.").set_flags(dpp::m_ephemeral)); + bool isOwner = (thread.owner_id == event.command.member.user_id); + bool hasManagePermission = event.command.member.has_permission(thread.guild_id, dpp::p_manage_threads); + + if (!isOwner && !hasManagePermission) + return event.reply(dpp::message("You can only close your own posts or you need manage threads permission.").set_flags(dpp::m_ephemeral)); thread.metadata.locked = true; + thread.metadata.archived = true; const std::string newThreadName = dpp::unicode_emoji::lock + std::string(" ") + thread.name; thread.set_name(newThreadName); @@ -37,25 +48,30 @@ void cmd::closeCommand(dpp::cluster& bot, const dpp::slashcommand_t& event) }); }); } - else if (event.command.channel.parent_id == globals::category::ticketId) + else if (channel->parent_id == globals::category::ticketId) { - event.reply(dpp::message("Closed ticket!")); - - bot.channel_get(event.command.channel.id, [&bot, event](const dpp::confirmation_callback_t& callback) { - if (!callback.is_error()) + bool isOwner = false; + bool hasManagePermission = event.command.member.has_permission(channel->guild_id, dpp::p_manage_channels); + + for (const auto& overwrite : channel->permission_overwrites) + { + if (overwrite.id == event.command.member.user_id && overwrite.type == dpp::overwrite_type::ot_member) { - dpp::channel ticketChannel = std::get(callback.value); - std::vector overwrites = ticketChannel.permission_overwrites; - - for (const auto& overwrite : overwrites) - { - if (overwrite.type == dpp::overwrite_type::ot_member) - { - bot.channel_edit_permissions(ticketChannel, overwrite.id, 0, dpp::p_view_channel, true); - } - } + isOwner = true; + break; } - }); + } + + if (!isOwner && !hasManagePermission) + { + event.reply(dpp::message("You can only close your own tickets or you need manage channels permission.").set_flags(dpp::m_ephemeral)); + return; + } + + event.reply(dpp::message("Closed ticket!")); + + // Remove user's access to the ticket + bot.channel_edit_permissions(*channel, event.command.member.user_id, 0, dpp::p_view_channel, true); } else { From d55211cc94f472ed6f1fad0bb186673d683cefcf Mon Sep 17 00:00:00 2001 From: Xander Zheleva Date: Sun, 17 Aug 2025 16:45:24 +0300 Subject: [PATCH 8/8] Update commands.h --- src/commands/commands.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/commands.h b/src/commands/commands.h index d8a729e..63a17c7 100644 --- a/src/commands/commands.h +++ b/src/commands/commands.h @@ -2,6 +2,7 @@ #define COMMANDS_H #include +#include #include #include #include @@ -74,7 +75,7 @@ struct cmdStruct std::string name; std::string desc; - typedef std::function cmdFunc; + typedef std::function cmdFunc; cmdFunc function; std::list args;