1
0
Fork 0
mirror of https://github.com/Syping/dtranslatebot.git synced 2025-08-22 17:58:14 +02:00
dtranslatebot/src/slashcommands.cpp

318 lines
18 KiB
C++

/*****************************************************************************
* dtranslatebot Discord Translate Bot
* Copyright (C) 2024 Syping
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* This software is provided as-is, no warranties are given to you, we are not
* responsible for anything with use of the software, you are self responsible.
*****************************************************************************/
#include <sstream>
#include "slashcommands.h"
using namespace std::string_literals;
void bot::slashcommands::process_command_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event)
{
if (event.command.get_command_name() == "list")
bot::slashcommands::process_list_command(bot, settings, event);
else if (event.command.get_command_name() == "translate" || event.command.get_command_name() == "translate_pref")
bot::slashcommands::process_translate_command(bot, settings, event);
}
void bot::slashcommands::process_list_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event)
{
try {
dpp::command_interaction interaction = event.command.get_command_interaction();
if (interaction.options[0].name == "channel") {
const std::lock_guard<bot::settings::settings> guard(*settings);
if (const bot::settings::channel *channel = settings->get_channel(event.command.guild_id, event.command.channel_id)) {
std::ostringstream reply_translated;
reply_translated << "**Channel <#" << channel->id << ">**\n";
reply_translated << "Source: " << channel->source << '\n';
reply_translated << "Targets: " << channel->targets.size();
// We want give more information to users who can Manage Webhooks
dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id);
if (user_permissions.has(dpp::p_manage_webhooks)) {
std::shared_ptr<bot::database::database> database = settings->get_database();
const bot::settings::channel db_channel = database->get_channel(event.command.guild_id, event.command.channel_id);
for (auto target = channel->targets.begin(); target != channel->targets.end(); target++) {
reply_translated << "\n\n";
reply_translated << "**Target " << target->target << "**\n";
bool db_found = false;
for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) {
if (db_target->target == target->target) {
db_found = true;
break;
}
}
reply_translated << "Deleteable: " << (db_found ? "Yes" : "No") << '\n';
reply_translated << "Webhook: " << target->webhook.id;
}
}
event.reply(dpp::message(reply_translated.str()).set_flags(dpp::m_ephemeral));
}
else {
event.reply(dpp::message("The current channel is not being translated!").set_flags(dpp::m_ephemeral));
}
}
else if (interaction.options[0].name == "guild") {
const std::lock_guard<bot::settings::settings> guard(*settings);
if (const bot::settings::guild *guild = settings->get_guild(event.command.guild_id)) {
if (!guild->channel.empty()) {
std::ostringstream reply_translated;
for (auto channel = guild->channel.begin(); channel != guild->channel.end();) {
reply_translated << "**Channel <#" << channel->id << ">**\n";
reply_translated << "Source: " << channel->source << '\n';
reply_translated << "Targets: " << channel->targets.size();
if (++channel != guild->channel.end())
reply_translated << "\n\n";
}
event.reply(dpp::message(reply_translated.str()).set_flags(dpp::m_ephemeral));
}
else {
event.reply(dpp::message("The current guild have no translated channel!").set_flags(dpp::m_ephemeral));
}
}
else {
event.reply(dpp::message("The current guild have no translated channel!").set_flags(dpp::m_ephemeral));
}
}
else {
throw std::invalid_argument("Option " + interaction.options[0].name + " is not known");
}
}
catch (const std::exception& exception) {
std::cerr << "[Exception] " << exception.what() << std::endl;
event.reply(dpp::message("Exception while processing command:\n"s + exception.what()).set_flags(dpp::m_ephemeral));
}
}
void bot::slashcommands::process_translate_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event)
{
try {
std::variant<dpp::channel,dpp::webhook> v_target;
const std::string source = std::get<std::string>(event.get_parameter("source"));
const std::string target = std::get<std::string>(event.get_parameter("target"));
dpp::command_interaction interaction = event.command.get_command_interaction();
if (interaction.options[0].name == "channel") {
v_target = event.command.get_resolved_channel(
std::get<dpp::snowflake>(event.get_parameter("channel")));
}
else if (interaction.options[0].name == "webhook") {
v_target = dpp::webhook(std::get<std::string>(event.get_parameter("webhook")));
}
const std::vector<bot::translator::language> languages = settings->get_translator()->get_languages();
std::ostringstream language_codes;
bool source_valid = false, target_valid = false;
for (const bot::translator::language &language : languages) {
if (language.code == source)
source_valid = true;
if (language.code == target)
target_valid = true;
if (source_valid && target_valid)
break;
language_codes << " " << language.code;
}
if (source_valid && target_valid) {
const std::lock_guard<bot::settings::settings> guard(*settings);
const bot::settings::channel *channel = settings->get_channel(event.command.guild_id, event.command.channel_id);
if (!channel) {
if (dpp::channel *channel = std::get_if<dpp::channel>(&v_target)) {
dpp::webhook webhook;
webhook.channel_id = channel->id;
webhook.guild_id = channel->guild_id;
webhook.name = "Translate Bot Webhook <" + std::to_string(event.command.channel_id) + ":" + source + ":" + target + ">";
bot->create_webhook(webhook, std::bind(&bot::slashcommands::process_translate_webhook_new_channel, bot, settings, event, source, target, std::placeholders::_1));
}
else if (dpp::webhook *webhook = std::get_if<dpp::webhook>(&v_target)) {
const bot::settings::target s_target = { target, *webhook };
const bot::settings::channel s_channel = { event.command.channel_id, source, { s_target } };
settings->add_channel(s_channel, event.command.guild_id);
settings->add_translatebot_webhook(webhook->id);
std::shared_ptr<bot::database::database> database = settings->get_database();
database->set_channel_source(event.command.guild_id, event.command.channel_id, source);
database->add_channel_target(event.command.guild_id, event.command.channel_id, s_target);
database->sync();
event.reply(dpp::message("Channel will be now translated!").set_flags(dpp::m_ephemeral));
}
}
else if (!settings->get_target(channel, target)) {
if (channel->source != source) {
event.reply(dpp::message("The current channel is already being translated from a different source language!").set_flags(dpp::m_ephemeral));
}
else if (dpp::channel *channel = std::get_if<dpp::channel>(&v_target)) {
dpp::webhook webhook;
webhook.channel_id = channel->id;
webhook.guild_id = channel->guild_id;
webhook.name = "Translate Bot Webhook <" + std::to_string(event.command.channel_id) + ":" + source + ":" + target + ">";
bot->create_webhook(webhook, std::bind(&bot::slashcommands::process_translate_webhook_add_target, bot, settings, event, target, std::placeholders::_1));
}
else if (dpp::webhook *webhook = std::get_if<dpp::webhook>(&v_target)) {
const bot::settings::target s_target = { target, *webhook };
settings->add_target(s_target, event.command.guild_id, event.command.channel_id);
settings->add_translatebot_webhook(webhook->id);
std::shared_ptr<bot::database::database> database = settings->get_database();
database->add_channel_target(event.command.guild_id, event.command.channel_id, s_target);
database->sync();
event.reply(dpp::message("Channel will be now translated!").set_flags(dpp::m_ephemeral));
}
}
else {
event.reply(dpp::message("The current channel is already being translated to the target language!").set_flags(dpp::m_ephemeral));
}
}
else if (!source_valid && !target_valid) {
event.reply(dpp::message("Source and target languages are not valid!\nAvailable languages are:" + language_codes.str()).set_flags(dpp::m_ephemeral));
}
else if (!source_valid) {
event.reply(dpp::message("Source language is not valid!\nAvailable languages are:" + language_codes.str()).set_flags(dpp::m_ephemeral));
}
else if (!target_valid) {
event.reply(dpp::message("Target language is not valid!\nAvailable languages are:" + language_codes.str()).set_flags(dpp::m_ephemeral));
}
}
catch (const std::exception &exception) {
std::cerr << "[Exception] " << exception.what() << std::endl;
event.reply(dpp::message("Exception while processing command:\n"s + exception.what()).set_flags(dpp::m_ephemeral));
}
}
void bot::slashcommands::process_translate_webhook_add_target(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &target, const dpp::confirmation_callback_t &callback)
{
if (callback.is_error()) {
event.reply(dpp::message("Failed to generate webhook!").set_flags(dpp::m_ephemeral));
return;
}
const dpp::webhook webhook = callback.get<dpp::webhook>();
const bot::settings::target s_target = { target, webhook };
const std::lock_guard<bot::settings::settings> guard(*settings);
settings->add_target(s_target, event.command.guild_id, event.command.channel_id);
settings->add_translatebot_webhook(webhook.id);
std::shared_ptr<bot::database::database> database = settings->get_database();
database->add_channel_target(event.command.guild_id, event.command.channel_id, s_target);
database->sync();
event.reply(dpp::message("Channel will be now translated!").set_flags(dpp::m_ephemeral));
}
void bot::slashcommands::process_translate_webhook_new_channel(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &source, const std::string &target, const dpp::confirmation_callback_t &callback)
{
if (callback.is_error()) {
event.reply(dpp::message("Failed to generate webhook!").set_flags(dpp::m_ephemeral));
return;
}
const dpp::webhook webhook = callback.get<dpp::webhook>();
const bot::settings::target s_target = { target, webhook };
const bot::settings::channel s_channel = { event.command.channel_id, source, { s_target } };
const std::lock_guard<bot::settings::settings> guard(*settings);
settings->add_channel(s_channel, event.command.guild_id);
settings->add_translatebot_webhook(webhook.id);
std::shared_ptr<bot::database::database> database = settings->get_database();
database->set_channel_source(event.command.guild_id, event.command.channel_id, source);
database->add_channel_target(event.command.guild_id, event.command.channel_id, s_target);
database->sync();
event.reply(dpp::message("Channel will be now translated!").set_flags(dpp::m_ephemeral));
}
void bot::slashcommands::register_commands(dpp::cluster *bot, bot::settings::settings *settings)
{
settings->lock();
const std::vector<bot::translator::language> languages = settings->get_translator()->get_languages();
const std::vector<std::string> preferred_languages = settings->preferred_languages();
settings->unlock();
std::vector<dpp::slashcommand> commands;
/*
dpp::slashcommand command_edit("edit", "Edit current channel settings", bot->me.id);
command_edit.set_default_permissions(dpp::p_manage_webhooks);
dpp::command_option source_edit_subcommand(dpp::co_sub_command, "source", "Edit current channel source language");
command_edit.add_option(source_edit_subcommand);
commands.push_back(command_edit);
*/
dpp::slashcommand command_list("list", "List translation settings", bot->me.id);
dpp::command_option channel_list_subcommand(dpp::co_sub_command, "channel", "List current channel translation settings");
dpp::command_option guild_list_subcommand(dpp::co_sub_command, "guild", "List current guild translation settings");
command_list.add_option(channel_list_subcommand);
command_list.add_option(guild_list_subcommand);
commands.push_back(command_list);
dpp::slashcommand command_translate("translate", "Translate current channel", bot->me.id);
command_translate.set_default_permissions(dpp::p_manage_webhooks);
dpp::command_option channel_translate_subcommand(dpp::co_sub_command, "channel", "Translate current channel to a channel");
dpp::command_option webhook_translate_subcommand(dpp::co_sub_command, "webhook", "Translate current channel to a webhook");
dpp::command_option source_option(dpp::co_string, "source", "Source language (ISO 639-1)", true);
source_option.set_max_length(static_cast<int64_t>(2)).set_min_length(static_cast<int64_t>(2));
dpp::command_option target_option(dpp::co_string, "target", "Target language (ISO 639-1)", true);
target_option.set_max_length(static_cast<int64_t>(2)).set_min_length(static_cast<int64_t>(2));
dpp::command_option channel_option(dpp::co_channel, "channel", "Target channel", true);
channel_option.add_channel_type(dpp::CHANNEL_TEXT);
dpp::command_option webhook_option(dpp::co_string, "webhook", "Target webhook", true);
channel_translate_subcommand.add_option(source_option);
channel_translate_subcommand.add_option(target_option);
channel_translate_subcommand.add_option(channel_option);
webhook_translate_subcommand.add_option(source_option);
webhook_translate_subcommand.add_option(target_option);
webhook_translate_subcommand.add_option(webhook_option);
command_translate.add_option(channel_translate_subcommand);
command_translate.add_option(webhook_translate_subcommand);
commands.push_back(command_translate);
if (preferred_languages.size() > 1) {
dpp::slashcommand command_translate_pref("translate_pref", "Translate current channel (Preferred languages)", bot->me.id);
command_translate_pref.set_default_permissions(dpp::p_manage_webhooks);
dpp::command_option channel_pref_subcommand(dpp::co_sub_command, "channel", "Translate current channel to a channel (Preferred languages)");
dpp::command_option webhook_pref_subcommand(dpp::co_sub_command, "webhook", "Translate current channel to a webhook (Preferred languages)");
dpp::command_option source_pref_option(dpp::co_string, "source", "Source language", true);
dpp::command_option target_pref_option(dpp::co_string, "target", "Target language", true);
for (const bot::translator::language &language : languages) {
if (std::find(preferred_languages.begin(), preferred_languages.end(), language.code) != preferred_languages.end()) {
source_pref_option.add_choice(dpp::command_option_choice(language.name, language.code));
target_pref_option.add_choice(dpp::command_option_choice(language.name, language.code));
}
}
channel_pref_subcommand.add_option(source_pref_option);
channel_pref_subcommand.add_option(target_pref_option);
channel_pref_subcommand.add_option(channel_option);
webhook_pref_subcommand.add_option(source_pref_option);
webhook_pref_subcommand.add_option(target_pref_option);
webhook_pref_subcommand.add_option(webhook_option);
command_translate_pref.add_option(channel_pref_subcommand);
command_translate_pref.add_option(webhook_pref_subcommand);
commands.push_back(command_translate_pref);
}
bot->global_bulk_command_create(commands);
}