BotTerre/libs/bot/src/trivia/config.rs

178 lines
6.4 KiB
Rust

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<Channel>,
#[description = "Name of the trivia game"] name: Option<String>,
#[description = "Description of the trivia game"] description: Option<String>,
#[description = "Whether to use random questions"] random_question: Option<bool>,
#[description = "Role to ping when a question is asked"] role_ping: Option<Role>,
#[description = "Whether to enable role ping"] role_ping_enabled: Option<bool>,
#[description = "Reward kind for the trivia game"] reward_kind: Option<TrivialRewardKind>,
#[description = "Reward amount for the trivia game"] reward_amount: Option<u64>,
#[description = "Whether to send an ephemeral message when the answer is taken into account"]
taken_into_account: Option<bool>,
#[description = "When to ask the question, in cron format (e.g. '0 0 * * *' for daily)"]
cron: Option<String>,
#[description = "When to answer the question, in cron format (e.g. '0 0 * * *' for daily)"]
cron_answer: Option<String>,
) -> 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::<Trivial>(&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>(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(())
}