suggestion form

This commit is contained in:
Benji Dial 2026-01-13 14:35:38 -05:00
parent 9814ad997d
commit f57ffaf076
4 changed files with 165 additions and 14 deletions

View file

@ -8,9 +8,9 @@ will be used to ping users about brackets.
=== Commands
All of these commands must be run with an environment variable BOT_TOKEN set
to the token of the Discord bot. All except for gateway interact with a SQLite3
database named database.db, which will be created if it does not exist. To run
any of these from the source repository, use the command:
to the token of the Discord bot. Some of these interact with a SQLite3 database
named database.db, which will be created if it does not exist. To run any of
these from the source repository, use the command:
BOT_TOKEN='<token>' cargo run --release --bin <command> [arguments]
== create-bracket <path to YAML file>
@ -39,13 +39,13 @@ Each entry has these keys:
entirely of decimal digits, then it is interpreted as an ID of a Discord
emoji. Otherwise, this is interpreted as a literal Unicode emoji.
== gateway
== gateway <shredder channel id>
This runs the "gateway" portion of the bot, which receives notifications
from Discord about the toggle role buttons being pressed, and toggles those
roles. This will continue running until there is some error communicating
with Discord. If this is not running, attempting to toggle roles will
display "interaction failed" under the button.
This runs the "gateway" portion of the bot, which receives notifications from
Discord about the toggle role and suggested bracket buttons being pressed, and
handles those interactions. This will continue running until there is some
error communicating with Discord. The "shredder channel id" argument is
the ID of a Discord channel to post bracket suggestions into.
== post-polls <bracket id> <number of polls>
@ -59,6 +59,11 @@ bracket after its winner has been announced. This should not be run on the same
bracket more than once without running process-polls in between. All polls are
posted with a length of 23 hours.
== post-suggestion-form <channel id>
This posts a button in the specified channel that users can click to suggest
new brackets. The suggestions are posted in another channel (see gateway).
== process-polls
This reads all of the polls that have been posted since the last time this was

View file

@ -1,4 +1,20 @@
#[tokio::main]
async fn main() {
bracket_bot_v4::run_gateway().await;
let args: Vec<String> = std::env::args().collect();
if args.len() != 2 {
eprintln!("This must be run with one argument: the channel to post suggested brackets into.");
std::process::exit(1);
}
let shredder_id =
match args[1].parse::<u64>() {
Ok(c) => c, Err(e) => {
eprintln!("Failed to parse argument: {e}");
std::process::exit(1);
}
};
bracket_bot_v4::run_gateway(shredder_id).await;
}

View file

@ -0,0 +1,22 @@
#[tokio::main]
async fn main() {
let dcf = bracket_bot_v4::create_discord_conn();
let args: Vec<String> = std::env::args().collect();
if args.len() != 2 {
eprintln!("This must be run with one argument: the channel to post the suggestion form in.");
std::process::exit(1);
}
let channel_id =
match args[1].parse::<u64>() {
Ok(c) => c, Err(e) => {
eprintln!("Failed to parse argument: {e}");
std::process::exit(1);
}
};
bracket_bot_v4::post_suggestion_form(&dcf.await, channel_id).await;
}

View file

@ -140,6 +140,11 @@ fn get_token() -> String {
struct GatewayHandler;
struct ShredderChannelID;
impl serenity::prelude::TypeMapKey for ShredderChannelID {
type Value = u64;
}
#[serenity::async_trait]
impl serenity::client::EventHandler for GatewayHandler {
@ -174,11 +179,84 @@ impl serenity::client::EventHandler for GatewayHandler {
serenity::builder::CreateInteractionResponseMessage::default();
msg = msg.content(if removing { "Removed role." } else { "Added role." });
msg = msg.ephemeral(true);
let resp= serenity::builder::CreateInteractionResponse::Message(msg);
let resp = serenity::builder::CreateInteractionResponse::Message(msg);
cpt.create_response(&ctx, resp).await.unwrap();
}
else if id == "suggest" {
let mut form = serenity::builder::CreateModal::new("suggest-form", "Suggest a bracket");
let name =
serenity::builder::CreateInputText::new(
serenity::model::application::InputTextStyle::Short,
"Bracket name", "name");
let name_row = serenity::builder::CreateActionRow::InputText(name);
let mut details=
serenity::builder::CreateInputText::new(
serenity::model::application::InputTextStyle::Paragraph,
"Details (suggested entries, etc)", "details");
details = details.required(false);
let details_row = serenity::builder::CreateActionRow::InputText(details);
form = form.components(vec![name_row, details_row]);
let response = serenity::builder::CreateInteractionResponse::Modal(form);
cpt.create_response(&ctx, response).await.unwrap();
}
}
else if let serenity::model::application::Interaction::Modal(md) = interaction {
let id = &md.data.custom_id;
if id == "suggest-form" {
let name =
if let
serenity::model::application::ActionRowComponent::InputText(name_text) =
&md.data.components[0].components[0] { name_text.value.clone() } else { None };
let details =
if let
serenity::model::application::ActionRowComponent::InputText(details_text) =
&md.data.components[1].components[0] { details_text.value.clone() } else { None };
let data = ctx.data.read().await;
let shredder_channel_id = data.get::<ShredderChannelID>().unwrap();
let shredder = serenity::model::id::ChannelId::new(*shredder_channel_id);
drop(data);
let mut msg = format!("## Bracket suggestion: {}", name.unwrap());
if let Some(d) = details {
let mut sand = d;
while sand.ends_with('`') {
sand.remove(sand.len() - 1);
}
while let Some(i) = sand.find("```") {
sand.remove(i);
}
while sand.starts_with('`') {
sand.remove(0);
}
if sand != "" {
msg = msg + format!("\n```{}```", sand).as_str();
}
}
shredder.say(&ctx, msg).await.unwrap();
let mut msg2 =
serenity::builder::CreateInteractionResponseMessage::default();
msg2 = msg2.content("Suggestion submitted.");
msg2 = msg2.ephemeral(true);
let r = serenity::builder::CreateInteractionResponse::Message(msg2);
md.create_response(&ctx, r).await.unwrap();
}
}
}
@ -198,6 +276,29 @@ pub async fn create_discord_conn() -> DiscordConn {
}
}
async fn post_suggestion_form_core(dc: &DiscordConn, channel_id: u64) -> Result<(), serenity::Error> {
let channel = serenity::model::id::ChannelId::new(channel_id);
let mut message = serenity::builder::CreateMessage::new();
message = message.content("Click the button to suggest a new bracket.");
let mut button = serenity::builder::CreateButton::new("suggest");
button = button.label("Suggest a bracket");
message = message.button(button);
channel.send_message(&dc.client.http, message).await?;
Ok(())
}
pub async fn post_suggestion_form(dc: &DiscordConn, channel_id: u64) {
match post_suggestion_form_core(&dc, channel_id).await {
Ok(()) => {}, Err(e) => discord_error(&e)
}
}
async fn create_bracket_core_discord(dc: &DiscordConn, info: &CreateBracketInfo) -> Result<(), serenity::Error> {
let channel = serenity::model::id::ChannelId::new(info.channel_id);
@ -730,13 +831,20 @@ pub async fn ping_bracket_role(dbc: &DbConn, dc: &DiscordConn, bracket_id: i32,
}
async fn run_gateway_core() -> Result<(), serenity::Error> {
async fn run_gateway_core(shredder_id: u64) -> Result<(), serenity::Error> {
let mut client = create_gateway_client().await?;
let mut data = client.data.write().await;
data.insert::<ShredderChannelID>(shredder_id);
drop(data);
client.start().await
}
pub async fn run_gateway() {
match run_gateway_core().await {
pub async fn run_gateway(shredder_id: u64) {
match run_gateway_core(shredder_id).await {
Ok(()) => {}, Err(e) => discord_error(&e)
}
}