use crate::helper::is_user_admin_right; use crate::{Context, Error}; use clickhouse_pool::traits::Model; use croner::Cron; use database::trivial::{Trivial, TrivialRewardKind}; use poise::serenity_prelude::{Channel, Role}; use tracing::{debug, info, instrument}; /// Config an existing trivia game #[instrument(name="trivia_config", skip(ctx), level = "info", fields(channel = ctx.channel_id().get(), guild = ?ctx.guild_id().unwrap().get()))] #[poise::command( prefix_command, slash_command, guild_only, category = "Trivia", check = "is_user_admin_right" )] pub async fn config( ctx: Context<'_>, #[description = "Channel of the trivia game, or current"] channel_id: Option, #[description = "Name of the trivia game"] name: Option, #[description = "Description of the trivia game"] description: Option, #[description = "Whether to use random questions"] random_question: Option, #[description = "Role to ping when a question is asked"] role_ping: Option, #[description = "Whether to enable role ping"] role_ping_enabled: Option, #[description = "Reward kind for the trivia game"] reward_kind: Option, #[description = "Reward amount for the trivia game"] reward_amount: Option, #[description = "Whether to send an ephemeral message when the answer is taken into account"] taken_into_account: Option, #[description = "When to ask the question, in cron format (e.g. '0 0 * * *' for daily)"] cron: Option, #[description = "When to answer the question, in cron format (e.g. '0 0 * * *' for daily)"] cron_answer: Option, ) -> Result<(), Error> { let guild_id = match ctx.guild_id() { Some(id) => id.get(), None => { ctx.say("This command can only be used in a server.") .await?; return Ok(()); } }; let channel_id = match channel_id { Some(c) => c.id().get(), None => { info!("No channel specified, using current channel."); ctx.channel_id().get() } }; let manager = ctx.data().datalake_config.clone(); let search_query = Trivial::build_select_query( Some(&format!( "channel_id = {} and guild_id = {}", channel_id, guild_id )), None, None, ); let mut trivia_exists: Trivial = match manager .execute_select_with_retry::(&search_query) .await { Ok(trivia) => { if trivia.is_empty() { ctx.say("No trivia game found in this channel. Please create one first.") .await?; return Ok(()); } if trivia.len() > 1 { ctx.say("Multiple trivia games found in this channel. Please contact an admin to resolve this.") .await?; return Ok(()); } trivia[0].clone() } Err(e) => { ctx.say(format!("Error fetching trivia game: {}", e)) .await?; return Err(Error::from(e)); } }; debug!("Found trivia game: {:?}", trivia_exists); let mut inserter = match manager.get_insert::(Trivial::table_name()).await { Ok(inserter) => inserter, Err(e) => { tracing::error!("Failed to create inserter for Trivial: {}", e); ctx.say("Failed to update trivia game. Please try again later.") .await?; return Ok(()); } }; trivia_exists.sign = -1; // Set sign to -1 to indicate an update inserter.write(&trivia_exists.clone()).await?; // Update the trivia game with provided options if let Some(name) = name { trivia_exists.name = name; } if let Some(description) = description { trivia_exists.description = description; } if let Some(random_question) = random_question { trivia_exists.random_question = random_question; } if let Some(role_ping) = role_ping { trivia_exists.role_ping = role_ping.id.get(); } if let Some(role_ping_enabled) = role_ping_enabled { trivia_exists.role_ping_enabled = role_ping_enabled; } if let Some(reward_kind) = reward_kind { trivia_exists.reward_kind = reward_kind; } if let Some(reward_amount) = reward_amount { trivia_exists.reward_amount = reward_amount; } if let Some(taken_into_account) = taken_into_account { trivia_exists.taken_into_account = taken_into_account; } if let Some(cron) = cron { match Cron::new(&cron).parse() { Ok(_) => {} Err(e) => { ctx.say(format!("Invalid cron format: {}", e)).await?; return Ok(()); } }; trivia_exists.question_asked = cron; } if let Some(cron_answer) = cron_answer { match Cron::new(&cron_answer).parse() { Ok(_) => {} Err(e) => { ctx.say(format!("Invalid cron answer format: {}", e)) .await?; return Ok(()); } }; trivia_exists.answer_given = cron_answer; } trivia_exists.updated_at = chrono::Utc::now(); trivia_exists.updater_id = ctx.author().id.get(); debug!("Updated trivia game: {:?}", trivia_exists); // Set sign to 1 to indicate a successful update trivia_exists.sign = 1; // Write the updated trivia game back to the database inserter.write(&trivia_exists).await?; match inserter.end().await { Ok(_) => { info!( "Trivia game '{}' updated successfully in channel <#{}>.", trivia_exists.name, channel_id ); ctx.say(format!( "Trivia game '{}' has been successfully updated.", trivia_exists.name )) .await?; } Err(e) => { tracing::error!("Failed to update trivia game: {}", e); ctx.say("Failed to update trivia game. Please try again later.") .await?; return Ok(()); } } if let Err(e) = manager .execute_with_retry(&Trivial::optimize_table_sql()) .await { tracing::error!("Failed to optimize trivia table: {}", e); } else { info!("Trivia table optimized successfully."); } Ok(()) }