Add working bot
This commit is contained in:
+148
@@ -0,0 +1,148 @@
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
|
||||
use serenity::async_trait;
|
||||
use serenity::builder::CreateApplicationCommands;
|
||||
use serenity::model::application::command::Command;
|
||||
use serenity::model::application::interaction::{Interaction, InteractionResponseType};
|
||||
use serenity::model::gateway::Ready;
|
||||
use serenity::model::id::GuildId;
|
||||
use serenity::model::prelude::command::CommandOptionType;
|
||||
use serenity::model::prelude::interaction::application_command::{
|
||||
ApplicationCommandInteraction, CommandDataOptionValue,
|
||||
};
|
||||
use serenity::model::prelude::Role;
|
||||
use serenity::prelude::*;
|
||||
use tracing::{event, Level};
|
||||
|
||||
type StdErr<T> = Result<T, Box<dyn Error + Send + Sync>>;
|
||||
|
||||
struct Handler;
|
||||
|
||||
async fn user_to_role(ctx: &Context, cmd: &ApplicationCommandInteraction) -> StdErr<String> {
|
||||
if let Some(role_option) = cmd.data.options.iter().find(|opt| opt.name == "role") {
|
||||
if let Some(CommandDataOptionValue::Role(role)) = &role_option.resolved {
|
||||
let guild_id = cmd.guild_id.ok_or("No guild id in command")?.into();
|
||||
let user_id = cmd.user.id.into();
|
||||
if cmd.data.name == "giverole" {
|
||||
ctx.http
|
||||
.add_member_role(
|
||||
guild_id,
|
||||
user_id,
|
||||
role.id.into(),
|
||||
Some("User added themselves to role via bot."),
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
ctx.http
|
||||
.remove_member_role(
|
||||
guild_id,
|
||||
user_id,
|
||||
role.id.into(),
|
||||
Some("User removed themselves from role via bot."),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Ok("Role updated".into())
|
||||
} else {
|
||||
Err("Invalid role value".into())
|
||||
}
|
||||
} else {
|
||||
Err("No role option given".into())
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle(r: StdErr<String>) -> String {
|
||||
r.unwrap_or_else(|error| {
|
||||
event!(Level::ERROR, ?error, "Error handling command");
|
||||
"Sorry, there was an error while handling that command.".into()
|
||||
})
|
||||
}
|
||||
|
||||
fn register_commands(cmds: &mut CreateApplicationCommands) -> &mut CreateApplicationCommands {
|
||||
cmds.create_application_command(|cmd| cmd.name("ping").description("Go pong!"))
|
||||
.create_application_command(|cmd| cmd.name("roles").description("List available roles"))
|
||||
.create_application_command(|cmd| {
|
||||
cmd.name("giverole")
|
||||
.description("Add yourself to a role")
|
||||
.create_option(|c| {
|
||||
c.name("role")
|
||||
.kind(CommandOptionType::Role)
|
||||
.description("The role you want to be added to")
|
||||
.required(true)
|
||||
})
|
||||
})
|
||||
.create_application_command(|cmd| {
|
||||
cmd.name("takerole")
|
||||
.description("Remove yourself from a role")
|
||||
.create_option(|c| {
|
||||
c.name("role")
|
||||
.kind(CommandOptionType::Role)
|
||||
.description("The role you want to be removed from")
|
||||
.required(true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl EventHandler for Handler {
|
||||
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
||||
if let Interaction::ApplicationCommand(command) = interaction {
|
||||
println!("Received command interaction: {:#?}", command);
|
||||
|
||||
let content = match command.data.name.as_str() {
|
||||
"ping" => "pong!".to_string(),
|
||||
"giverole" => handle(user_to_role(&ctx, &command).await).await,
|
||||
"takerole" => handle(user_to_role(&ctx, &command).await).await,
|
||||
_ => "not implemented :(".to_string(),
|
||||
};
|
||||
|
||||
if let Err(why) = command
|
||||
.create_interaction_response(&ctx.http, |response| {
|
||||
response
|
||||
.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||
.interaction_response_data(|message| {
|
||||
message.content(content).ephemeral(true)
|
||||
})
|
||||
})
|
||||
.await
|
||||
{
|
||||
println!("Cannot respond to slash command: {}", why);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn ready(&self, ctx: Context, ready: Ready) {
|
||||
println!("{} is connected!", ready.user.name);
|
||||
|
||||
// If a guild id is given, run in dev mode and register commands to that guild.
|
||||
if let Ok(gid) = env::var("GUILD_ID") {
|
||||
event!(Level::INFO, ?gid, "Running in debug mode for guild");
|
||||
let guild_id = GuildId(gid.parse().expect("GUILD_ID must be int"));
|
||||
let commands = GuildId::set_application_commands(&guild_id, &ctx.http, |commands| {
|
||||
register_commands(commands)
|
||||
})
|
||||
.await;
|
||||
} else {
|
||||
let guild_command = Command::set_global_application_commands(&ctx.http, |commands| {
|
||||
register_commands(commands)
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> StdErr<()> {
|
||||
tracing_subscriber::fmt::init();
|
||||
// Configure the client with your Discord bot token in the environment.
|
||||
let token = env::var("DISCORD_TOKEN").expect("Expected a token in the environment");
|
||||
|
||||
// Build our client.
|
||||
let mut client = Client::builder(token, GatewayIntents::empty())
|
||||
.event_handler(Handler)
|
||||
.await
|
||||
.expect("Error creating client");
|
||||
|
||||
Ok(client.start().await?)
|
||||
}
|
||||
Reference in New Issue
Block a user