Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,18 @@ 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
src/main.cpp

#globals
src/globals/globals.cpp
src/globals/globals.h

# commands
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 7 additions & 0 deletions src/commands/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
65 changes: 31 additions & 34 deletions src/commands/project_cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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++;
}
1 change: 0 additions & 1 deletion src/config.json

This file was deleted.

10 changes: 10 additions & 0 deletions src/config.json.example
Original file line number Diff line number Diff line change
@@ -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"
}
102 changes: 102 additions & 0 deletions src/globals/globals.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include "globals.h"

#include <cstdint>
#include <dpp/nlohmann/json.hpp>

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<std::string>());
return true;
}

if (value.is_number_unsigned() || value.is_number_integer())
{
out = dpp::snowflake(value.get<uint64_t>());
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;
}
}
23 changes: 16 additions & 7 deletions src/globals/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define GLOBALS_H

#include <dpp/snowflake.h>
#include <string>

namespace globals
{
Expand All @@ -10,27 +11,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;
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <dpp/dpp.h>

#include "commands/commands.h"
#include "globals/globals.h"
#include "utils/suggestion/suggestion.h"
#include "utils/moderation/moderation.h"

Expand All @@ -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);

Expand Down Expand Up @@ -79,6 +87,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) {
Expand Down
13 changes: 9 additions & 4 deletions src/utils/suggestion/suggestion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<dpp::message>(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, "👎");
});
}
}
Expand Down
Loading