Skip to content
Open
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
54 changes: 41 additions & 13 deletions src/commands/close_cmd.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "commands.h"
#include "commands.h"
#include "../globals/globals.h"
#include "../ticket_registry.h"

#include <dpp/channel.h>
#include <dpp/permissions.h>
Expand Down Expand Up @@ -39,26 +40,53 @@ void cmd::closeCommand(dpp::cluster& bot, const dpp::slashcommand_t& event)
}
else if (event.command.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())
if (callback.is_error())
{
dpp::channel ticketChannel = std::get<dpp::channel>(callback.value);
std::vector<dpp::permission_overwrite> overwrites = ticketChannel.permission_overwrites;
event.reply(dpp::message("Unable to find this ticket.").set_flags(dpp::m_ephemeral));
return;
}

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);
}
}
const auto ticketChannel = std::get<dpp::channel>(callback.value);
for (const auto& overwrite : ticketChannel.permission_overwrites)
{
if (overwrite.type == dpp::overwrite_type::ot_member)
bot.channel_edit_permissions(ticketChannel, overwrite.id, 0, dpp::p_view_channel, true);
}

tickets::registry.removeByChannel(event.command.guild_id, ticketChannel.id);
event.reply(dpp::message("Closed ticket!"));
});
}
else
{
event.reply(dpp::message("This command only operates within tickets and threads.").set_flags(dpp::m_ephemeral));
}
}

void cmd::closeTicketButton(dpp::cluster& bot, const dpp::button_click_t& event)
{
if (event.command.channel.parent_id != globals::category::ticketId)
{
event.reply(dpp::message("This button only works inside a ticket.").set_flags(dpp::m_ephemeral));
return;
}

bot.channel_get(event.command.channel.id, [&bot, event](const dpp::confirmation_callback_t& callback) {
if (callback.is_error())
{
event.reply(dpp::message("Unable to find this ticket.").set_flags(dpp::m_ephemeral));
return;
}

const auto ticketChannel = std::get<dpp::channel>(callback.value);
for (const auto& overwrite : ticketChannel.permission_overwrites)
{
if (overwrite.type == dpp::overwrite_type::ot_member)
bot.channel_edit_permissions(ticketChannel, overwrite.id, 0, dpp::p_view_channel, true);
}

tickets::registry.removeByChannel(event.command.guild_id, ticketChannel.id);
event.reply(dpp::message("Closed ticket!"));
});
}
7 changes: 7 additions & 0 deletions src/commands/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ namespace cmd
*/
void closeCommand(dpp::cluster& bot, const dpp::slashcommand_t& event);

/**
* @brief Closes a ticket from its message button
* @param bot cluster
* @param event button click event
*/
void closeTicketButton(dpp::cluster& bot, const dpp::button_click_t& event);

/**
* @brief Opens a ticket
* @param bot cluster
Expand Down
54 changes: 42 additions & 12 deletions src/commands/ticket_cmd.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
#include "commands.h"
#include "../globals/globals.h"
#include "../ticket_registry.h"

void cmd::ticketCommand(dpp::cluster& bot, const dpp::slashcommand_t& event)
{
const auto guildId = event.command.guild_id;
const auto userId = event.command.get_issuing_user().id;

if (const auto existingTicket = tickets::registry.find(guildId, userId))
{
event.reply(dpp::message(
"You already have an open ticket: <#" + existingTicket->str() + ">")
.set_flags(dpp::m_ephemeral));
return;
}

dpp::message message(event.command.channel_id, "Creating ticket...");
event.reply(message.set_flags(dpp::m_ephemeral));

Expand All @@ -14,10 +26,10 @@ void cmd::ticketCommand(dpp::cluster& bot, const dpp::slashcommand_t& event)
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_guild_id(guildId)
.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, ticketPerms, 0)
.set_permission_overwrite(guildId, dpp::overwrite_type::ot_role, 0, dpp::p_view_channel)
.set_permission_overwrite(userId, dpp::overwrite_type::ot_member, ticketPerms, 0)
.set_permission_overwrite(globals::role::staffId, dpp::overwrite_type::ot_role, ticketPerms, 0);

const dpp::command_interaction cmdData = event.command.get_command_interaction();
Expand All @@ -30,18 +42,36 @@ void cmd::ticketCommand(dpp::cluster& bot, const dpp::slashcommand_t& event)
}
}

bot.channel_create(ticketChannel, [&bot, event](const dpp::confirmation_callback_t& callback) {
if (!callback.is_error())
bot.channel_create(ticketChannel, [&bot, event, guildId, userId](const dpp::confirmation_callback_t& callback) {
if (callback.is_error())
{
const auto ticketChannel = std::get<dpp::channel>(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!");
event.edit_response("Failed to create ticket channel.");
return;
}
else

const auto createdChannel = std::get<dpp::channel>(callback.value);
if (!tickets::registry.add(guildId, userId, createdChannel.id))
{
event.edit_response("Failed to create ticket channel!");
bot.channel_delete(createdChannel.id);
event.edit_response("You already have an open ticket.");
return;
}

const auto pingMessage = dpp::message(
createdChannel.id,
event.command.get_issuing_user().get_mention() + " opened this ticket.");

dpp::message ticketMessage = pingMessage;
ticketMessage.add_component(
dpp::component().add_component(
dpp::component()
.set_label("Close ticket")
.set_type(dpp::cot_button)
.set_style(dpp::cos_danger)
.set_id("closeTicket")));

bot.message_create(ticketMessage);

event.edit_response("Ticket " + createdChannel.get_mention() + " created!");
});
}
4 changes: 3 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ int main()
});

bot.on_button_click([&bot](const dpp::button_click_t& event) {
if (event.custom_id == "delSuggestion")
if (event.custom_id == "closeTicket")
cmd::closeTicketButton(bot, event);
else if (event.custom_id == "delSuggestion")
utils::suggestion::deleteSuggestion(bot, event);
else if (event.custom_id == "editSuggestion")
utils::suggestion::editSuggestion(bot, event);
Expand Down
47 changes: 47 additions & 0 deletions src/ticket_registry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "ticket_registry.h"

#include <algorithm>

namespace tickets
{
std::optional<dpp::snowflake> Registry::find(
const dpp::snowflake guildId,
const dpp::snowflake userId) const
{
std::scoped_lock lock(mutex);

const auto ticket = tickets.find({guildId, userId});

if (ticket == tickets.end())
return std::nullopt;

return ticket->second;
}

bool Registry::add(
const dpp::snowflake guildId,
const dpp::snowflake userId,
const dpp::snowflake channelId)
{
std::scoped_lock lock(mutex);

return tickets.emplace(
Key{guildId, userId},
channelId).second;
}

void Registry::removeByChannel(
const dpp::snowflake guildId,
const dpp::snowflake channelId)
{
std::scoped_lock lock(mutex);

std::erase_if(tickets, [guildId, channelId](const auto& ticket) {
return ticket.first.guildId == guildId
&& ticket.second == channelId;
});
}

Registry registry;
}

69 changes: 69 additions & 0 deletions src/ticket_registry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#ifndef TICKET_REGISTRY_H
#define TICKET_REGISTRY_H

#include <dpp/snowflake.h>

#include <cstdint>
#include <functional>
#include <mutex>
#include <optional>
#include <unordered_map>

namespace tickets
{
class Registry
{
public:
std::optional<dpp::snowflake> find(
dpp::snowflake guildId,
dpp::snowflake userId) const;

bool add(
dpp::snowflake guildId,
dpp::snowflake userId,
dpp::snowflake channelId);

void removeByChannel(
dpp::snowflake guildId,
dpp::snowflake channelId);

private:
struct Key
{
dpp::snowflake guildId{};
dpp::snowflake userId{};

bool operator==(const Key& other) const
{
return guildId == other.guildId
&& userId == other.userId;
}
};

struct KeyHash
{
std::size_t operator()(const Key& key) const
{
const auto guildHash =
std::hash<std::uint64_t>{}(
static_cast<std::uint64_t>(key.guildId));

const auto userHash =
std::hash<std::uint64_t>{}(
static_cast<std::uint64_t>(key.userId));

return guildHash
^ (userHash + 0x9e3779b9
+ (guildHash << 6)
+ (guildHash >> 2));
}
};

mutable std::mutex mutex;
std::unordered_map<Key, dpp::snowflake, KeyHash> tickets;
};

extern Registry registry;
}

#endif // TICKET_REGISTRY_H
39 changes: 33 additions & 6 deletions src/utils/suggestion/suggestion.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
#include "suggestion.h"
#include "../../globals/globals.h"

#include <exception>
#include <optional>
#include <string_view>

namespace
{
constexpr std::string_view authorFooterPrefix = "author_id:";

std::optional<dpp::snowflake> getSuggestionAuthorId(const dpp::message& message)
{
if (message.embeds.empty() || !message.embeds.front().footer)
return std::nullopt;

const auto& footer = message.embeds.front().footer;
if (!footer->text.starts_with(authorFooterPrefix))
return std::nullopt;

try
{
return dpp::snowflake(footer->text.substr(authorFooterPrefix.size()));
}
catch (const std::exception&)
{
return std::nullopt;
}
}
}

void utils::suggestion::createSuggestion(dpp::cluster& bot, const dpp::message_create_t& event)
{
dpp::user user = event.msg.author;
Expand All @@ -27,6 +55,7 @@ void utils::suggestion::createSuggestion(dpp::cluster& bot, const dpp::message_c
.set_color(globals::color::defaultColor)
.set_title("Suggestion")
.set_author(user.format_username(), "", user.get_avatar_url())
.set_footer("author_id:" + user.id.str())
.set_description(event.msg.content);

dpp::message msg(event.msg.channel_id, result);
Expand Down Expand Up @@ -86,21 +115,19 @@ void utils::suggestion::createSuggestion(dpp::cluster& bot, const dpp::message_c

void utils::suggestion::deleteSuggestion(dpp::cluster& bot, const dpp::button_click_t& event)
{
std::string clicker = event.command.get_issuing_user().format_username();
std::string originalAuthor = event.command.msg.embeds[0].author->name;
const auto originalAuthorId = getSuggestionAuthorId(event.command.msg);

if (clicker == originalAuthor)
if (originalAuthorId && event.command.get_issuing_user().id == *originalAuthorId)
bot.message_delete(event.command.msg.id, event.command.msg.channel_id);
else
event.reply(dpp::message("You can only delete your own suggestions.").set_flags(dpp::m_ephemeral));
}

void utils::suggestion::editSuggestion(dpp::cluster& bot, const dpp::button_click_t& event)
{
std::string clicker = event.command.get_issuing_user().format_username();
std::string originalAuthor = event.command.msg.embeds[0].author->name;
const auto originalAuthorId = getSuggestionAuthorId(event.command.msg);

if (clicker == originalAuthor)
if (originalAuthorId && event.command.get_issuing_user().id == *originalAuthorId)
{
dpp::interaction_modal_response modal("editModal", "Edit suggestion");

Expand Down