diff --git a/Cargo.lock b/Cargo.lock index 80d74c5..eb9fa0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -714,6 +714,8 @@ dependencies = [ "clickhouse", "clickhouse_pool", "serde", + "serde_json", + "serde_repr", "tokio", "tracing", "uuid", @@ -1910,25 +1912,25 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "poise" version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1819d5a45e3590ef33754abce46432570c54a120798bdbf893112b4211fa09a6" +source = "git+https://github.com/serenity-rs/poise?branch=current#518ff0564865bca2abf01ae8995b77340f439ef9" dependencies = [ "async-trait", "derivative", "futures-util", + "indexmap 2.9.0", "parking_lot", "poise_macros", "regex", "serenity", "tokio", "tracing", + "trim-in-place", ] [[package]] name = "poise_macros" version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fa2c123c961e78315cd3deac7663177f12be4460f5440dbf62a7ed37b1effea" +source = "git+https://github.com/serenity-rs/poise?branch=current#518ff0564865bca2abf01ae8995b77340f439ef9" dependencies = [ "darling", "proc-macro2", @@ -2537,8 +2539,7 @@ dependencies = [ [[package]] name = "serenity" version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d72ec4323681bf9a3cabe40fd080abc2435859b502a1b5aa9bf693f125bfa76" +source = "git+https://github.com/serenity-rs/serenity?branch=current#9108d28fc7ac14fa67aefe3c5c2deba281bf69a6" dependencies = [ "arrayvec", "async-trait", @@ -3286,6 +3287,12 @@ dependencies = [ "tracing-log 0.2.0", ] +[[package]] +name = "trim-in-place" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" + [[package]] name = "triomphe" version = "0.1.14" diff --git a/Cargo.toml b/Cargo.toml index 1211eab..6fcd77a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ ] [workspace.dependencies] -poise = '0.6.1' +poise = { git = "https://github.com/serenity-rs/poise", branch = "current" } tokio = { version = '1.45.0', features = [ 'macros', 'rt-multi-thread', @@ -24,3 +24,6 @@ chrono = { version = "0.4.41", features = ["serde"] } [profile.release] lto = true + +[patch.crates-io] +serenity = { git = "https://github.com/serenity-rs/serenity", branch = "current" } diff --git a/Readme.md b/Readme.md index a9cf5cc..6b734ae 100644 --- a/Readme.md +++ b/Readme.md @@ -18,22 +18,22 @@ #### Command -- [ADMIN] trivial init : Creer une activité Trivial Daily -- [ADMIN] trivial list : List les activité -- [ADMIN] trivial config : Modification des paramétre de base d'un event -- [ADMIN] trivial add-question : Ajout de question + réponse ou X réponse -- [ADMIN] trivial del-question : Suppression de question -- [ADMIN] trivial load-question : Charge un fichier/lien de question -- [ADMIN] trivial choose-chan : Choix du channel -- trivial scoreboard : Scoreboard -- trivial score : Score d'une personne par défaut le sien -- trivial top : Top X par défaut 3 -- [ADMIN] trivial balance : Modifie le score d'une personne +/-/= +- [x] [ADMIN] trivial create : Creer une activité Trivial Daily +- [x] [ADMIN] trivial list : List les activité +- [ ] [ADMIN] trivial config : Modification des paramétre de base d'un event +- [ ] [ADMIN] trivial add-question : Ajout de question + réponse ou X réponse +- [ ] [ADMIN] trivial del-question : Suppression de question +- [ ] [ADMIN] trivial load-question : Charge un fichier/lien de question +- [ ] [ADMIN] trivial choose-chan : Choix du channel +- [ ] trivial scoreboard : Scoreboard +- [ ] trivial score : Score d'une personne par défaut le sien +- [ ] trivial top : Top X par défaut 3 +- [ ] [ADMIN] trivial balance : Modifie le score d'une personne +/-/= #### TODO - [x] Créer DB -- [ ] Créer Commande Admin +- [ ] Créer Commande Admin (limiter au admin) - [ ] Créer Processus Schedule - [ ] Créer API - [ ] Créer prise en compte trivial (réponse a une question) diff --git a/apps/bot/src/bot/mod.rs b/apps/bot/src/bot/mod.rs index df4456b..95ea02e 100644 --- a/apps/bot/src/bot/mod.rs +++ b/apps/bot/src/bot/mod.rs @@ -1,27 +1,15 @@ use std::sync::Arc; use clickhouse_pool::pool_manager::PoolManager; -use help::help; -use poise::serenity_prelude as serenity; use poise::serenity_prelude::GatewayIntents; -use tracing::{info, instrument}; +use tracing::info; +use trivia::trivia; +use utility::{age::age, help::help, server::servers}; use crate::config::Config; -pub mod help; - -/// Displays your or another user's account creation date -#[instrument(skip(ctx), level = "info", fields(channel_id = ctx.channel_id().get() , guild_id = ?ctx.guild_id(), user_id = ?ctx.author().id.get(), user_name = ctx.author().name))] -#[poise::command(slash_command, prefix_command)] -async fn age( - ctx: Context<'_>, - #[description = "Selected user"] user: Option, -) -> Result<(), Error> { - let u = user.as_ref().unwrap_or_else(|| ctx.author()); - let response = format!("{}'s account was created at {}", u.name, u.created_at()); - ctx.say(response).await?; - Ok(()) -} +pub mod trivia; +pub mod utility; pub struct Data { pub config: Config, @@ -47,7 +35,7 @@ pub async fn start_bot(config: Config, datalake_config: Arc) { let framework = poise::Framework::builder() .options(poise::FrameworkOptions { - commands: vec![age(), help()], + commands: vec![age(), help(), servers(), trivia()], prefix_options: poise::PrefixFrameworkOptions { prefix: Some(prefix), ..Default::default() diff --git a/apps/bot/src/bot/trivia/create.rs b/apps/bot/src/bot/trivia/create.rs new file mode 100644 index 0000000..ca543f7 --- /dev/null +++ b/apps/bot/src/bot/trivia/create.rs @@ -0,0 +1,104 @@ +use crate::bot::{Context, Error}; +use clickhouse_pool::traits::Model; +use database::trivial::Trivial; +use poise::serenity_prelude; +use tracing::{debug, info, instrument}; + +/// Create a trivia game +/// Use the current channel by default, or specify a different channel. +#[instrument(name="trivia_create",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")] +pub async fn create( + ctx: Context<'_>, + #[description = "Name of the trivia game"] name: String, + #[description = "Description of the trivia game, by default empty"] description: Option, + #[description = "Channel to create the trivia game in, by default current channel"] + channel: 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 { + Some(c) => c.id.get(), + None => { + ctx.say("No channel specified, using current channel.") + .await?; + ctx.channel_id().get() + } + }; + let creator_id = ctx.author().id.get(); + let manager_pool = ctx.data().datalake_config.clone(); + + // Check if a trivia game already exists in the channel + let get_trivia = Trivial::build_select_query( + Some(&format!( + "channel_id = {} and guild_id = {}", + channel_id, guild_id + )), + None, + None, + ); + + let trivia_exists: Vec = manager_pool.execute_select_with_retry(&get_trivia).await?; + if !trivia_exists.is_empty() { + ctx.say(format!( + "A trivia game already exists in this channel with the name: {}", + trivia_exists[0].name + )) + .await?; + return Ok(()); + } + info!( + "No existing trivia game found in channel <#{}>. Proceeding to create a new one.", + channel_id + ); + // Create a new trivia game + let new_trivia = Trivial::new( + name, + description.unwrap_or_else(|| "".to_string()), + guild_id, + channel_id, + creator_id, + creator_id, + ); + + let insert_query = new_trivia.insert_query(); + debug!("Insert query: {}", insert_query); + let mut inserter = match manager_pool + .get_insert::(Trivial::table_name()) + .await + { + Ok(inserter) => inserter, + Err(e) => { + tracing::error!("Failed to create inserter for Trivial: {}", e); + ctx.say("Failed to create trivia game. Please try again later.") + .await?; + return Ok(()); + } + }; + inserter.write(&new_trivia).await?; + match inserter.end().await { + Ok(_) => { + info!( + "Trivia game '{}' created successfully in channel <#{}>.", + new_trivia.name, channel_id + ); + ctx.say(format!( + "Trivia game '{}' created successfully in channel <#{}>.", + new_trivia.name, channel_id + )) + .await?; + } + Err(e) => { + tracing::error!("Failed to create trivia game: {}", e); + ctx.say("Failed to create trivia game. Please try again later.") + .await?; + } + } + Ok(()) +} diff --git a/apps/bot/src/bot/trivia/list.rs b/apps/bot/src/bot/trivia/list.rs new file mode 100644 index 0000000..9c207d8 --- /dev/null +++ b/apps/bot/src/bot/trivia/list.rs @@ -0,0 +1,153 @@ +use crate::bot::{Context, Error}; +use clickhouse_pool::traits::Model; +use database::trivial::Trivial; +use poise::{ + serenity_prelude::{self, ComponentInteractionCollector}, + CreateReply, +}; +use tracing::{info, instrument, warn}; + +/// Turn a trivia into an embed for listing +#[instrument(name = "trivia_list_embed", level = "info")] +pub fn trivia_list_embed(trivia: &Trivial, current_channel: bool) -> serenity_prelude::CreateEmbed { + let mut embed = serenity_prelude::CreateEmbed::default() + .title(&trivia.name) + .description(&trivia.description) + .field("Channel", format!("<#{}>", trivia.channel_id), true) + .field("Status", format!("{:?}", trivia.status), true) + .field("Reward Kind", format!("{:?}", trivia.reward_kind), true) + .field("Reward Amount", trivia.reward_amount.to_string(), true); + + if current_channel { + embed = embed.color(serenity_prelude::Color::GOLD); + } else { + embed = embed.color(serenity_prelude::Color::DARK_GREY); + } + + embed +} + +/// List trivia games in the current server and show if there are any in the current channel. +#[instrument(name="trivia_list",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")] +pub async fn list(ctx: Context<'_>) -> 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?; + warn!("User tried to list trivia games in a DM channel."); + return Ok(()); + } + }; + let channel_id = ctx.channel_id().get(); + let manager_pool = ctx.data().datalake_config.clone(); + + // Fetch all trivia games in the guild + let get_trivia = + Trivial::build_select_query(Some(&format!("guild_id = {}", guild_id)), None, None); + + let trivia_games: Vec = manager_pool.execute_select_with_retry(&get_trivia).await?; + + if trivia_games.is_empty() { + ctx.say("No trivia games found in this server.").await?; + info!( + "User requested trivia list, but no games found in guild {}", + guild_id + ); + return Ok(()); + } + + // Put the current channel's trivia game in a vec + let mut current_channel_trivia = Vec::new(); + for trivia in &trivia_games { + if trivia.channel_id == channel_id { + // push the trivia game to be the first one in the list + current_channel_trivia.insert(0, trivia.clone()); + } else { + current_channel_trivia.push(trivia.clone()); + } + } + + if current_channel_trivia.len() == 1 { + // If there is only one trivia game, just send it + let reply = CreateReply::default().embed(trivia_list_embed( + ¤t_channel_trivia[0], + current_channel_trivia[0].channel_id == channel_id, + )); + ctx.send(reply).await?; + return Ok(()); + } + + let ctx_id = ctx.id(); + let prev_button_id = format!("{}prev", ctx_id); + let next_button_id = format!("{}next", ctx_id); + let close_button_id = format!("{}close", ctx_id); + + let reply = { + let components = serenity_prelude::CreateActionRow::Buttons(vec![ + serenity_prelude::CreateButton::new(&prev_button_id).emoji('◀'), + serenity_prelude::CreateButton::new(&close_button_id) + .emoji('❌') + .style(serenity_prelude::ButtonStyle::Danger), + serenity_prelude::CreateButton::new(&next_button_id).emoji('▶'), + ]); + CreateReply::default() + .embed(trivia_list_embed( + ¤t_channel_trivia[0], + current_channel_trivia[0].channel_id == channel_id, + )) + .components(vec![components]) + }; + ctx.send(reply).await?; + // Loop through incoming interactions with the navigation buttons + let mut current_page = 0; + while let Some(press) = ComponentInteractionCollector::new(ctx) + .filter(move |press| press.data.custom_id.starts_with(&ctx_id.to_string())) + .timeout(std::time::Duration::from_secs(3600 * 2)) + .await + { + if press.data.custom_id == next_button_id { + current_page += 1; + if current_page >= current_channel_trivia.len() { + current_page = 0; + } + } else if press.data.custom_id == prev_button_id { + current_page = current_page + .checked_sub(1) + .unwrap_or(current_channel_trivia.len() - 1); + } else if press.data.custom_id == close_button_id { + // Close the interaction + press + .create_response( + ctx.serenity_context(), + serenity_prelude::CreateInteractionResponse::UpdateMessage( + serenity_prelude::CreateInteractionResponseMessage::new() + .content("Trivia list closed.") + .components(vec![]), + ), + ) + .await?; + return Ok(()); + } else { + // This is an unrelated button interaction + continue; + } + + // Update the message with the new page contents + press + .create_response( + ctx.serenity_context(), + serenity_prelude::CreateInteractionResponse::UpdateMessage( + serenity_prelude::CreateInteractionResponseMessage::new().embed( + trivia_list_embed( + ¤t_channel_trivia[current_page], + current_channel_trivia[current_page].channel_id == channel_id, + ), + ), + ), + ) + .await?; + } + Ok(()) +} diff --git a/apps/bot/src/bot/trivia/mod.rs b/apps/bot/src/bot/trivia/mod.rs new file mode 100644 index 0000000..af1340c --- /dev/null +++ b/apps/bot/src/bot/trivia/mod.rs @@ -0,0 +1,20 @@ +pub mod create; +pub mod list; + +use crate::bot::{Context, Error}; +use create::create; +use list::list; +use tracing::instrument; + +/// Handle trivia command +#[instrument(skip(ctx), level = "info", fields(channel = ctx.channel_id().get(), guild = ?ctx.guild_id().unwrap().get()))] +#[poise::command( + slash_command, + prefix_command, + category = "Trivia", + subcommands("create", "list"), + guild_only = true +)] +pub async fn trivia(ctx: Context<'_>) -> Result<(), Error> { + Ok(()) +} diff --git a/apps/bot/src/bot/utility/age.rs b/apps/bot/src/bot/utility/age.rs new file mode 100644 index 0000000..e268418 --- /dev/null +++ b/apps/bot/src/bot/utility/age.rs @@ -0,0 +1,16 @@ +use crate::bot::{Context, Error}; +use poise::serenity_prelude as serenity; +use tracing::instrument; + +/// Displays your or another user's account creation date +#[instrument(skip(ctx), level = "info", fields(channel_id = ctx.channel_id().get() , guild_id = ?ctx.guild_id(), user_id = ?ctx.author().id.get(), user_name = ctx.author().name))] +#[poise::command(slash_command, prefix_command, category = "Utility")] +pub async fn age( + ctx: Context<'_>, + #[description = "Selected user"] user: Option, +) -> Result<(), Error> { + let u = user.as_ref().unwrap_or_else(|| ctx.author()); + let response = format!("{}'s account was created at {}", u.name, u.created_at()); + ctx.say(response).await?; + Ok(()) +} diff --git a/apps/bot/src/bot/help.rs b/apps/bot/src/bot/utility/help.rs similarity index 87% rename from apps/bot/src/bot/help.rs rename to apps/bot/src/bot/utility/help.rs index 539847e..5739bf9 100644 --- a/apps/bot/src/bot/help.rs +++ b/apps/bot/src/bot/utility/help.rs @@ -1,5 +1,5 @@ use crate::bot::{Context, Error}; -use poise::samples::HelpConfiguration; +use poise::builtins::PrettyHelpConfiguration; use tracing::instrument; /// Show help message @@ -23,7 +23,7 @@ pub async fn help( let extra_text_at_bottom = "\ Provided by Mak with ❤️ and too much ☕"; - let config = HelpConfiguration { + let config = PrettyHelpConfiguration { show_subcommands: true, show_context_menu_commands: false, ephemeral: true, @@ -31,6 +31,6 @@ Provided by Mak with ❤️ and too much ☕"; ..Default::default() }; - poise::builtins::help(ctx, command.as_deref(), config).await?; + poise::builtins::pretty_help(ctx, command.as_deref(), config).await?; Ok(()) } diff --git a/apps/bot/src/bot/utility/mod.rs b/apps/bot/src/bot/utility/mod.rs new file mode 100644 index 0000000..7bb9a08 --- /dev/null +++ b/apps/bot/src/bot/utility/mod.rs @@ -0,0 +1,3 @@ +pub mod age; +pub mod help; +pub mod server; diff --git a/apps/bot/src/bot/utility/server.rs b/apps/bot/src/bot/utility/server.rs new file mode 100644 index 0000000..45cfbaa --- /dev/null +++ b/apps/bot/src/bot/utility/server.rs @@ -0,0 +1,10 @@ +use crate::bot::{Context, Error}; +use tracing::instrument; + +/// Lists all servers the bot is in +#[instrument(skip(ctx), level = "info",fields(channel = ctx.channel_id().get(), guild = ?ctx.guild_id().unwrap().get()))] +#[poise::command(slash_command, prefix_command, category = "Utility")] +pub async fn servers(ctx: Context<'_>) -> Result<(), Error> { + poise::builtins::servers(ctx).await?; + Ok(()) +} diff --git a/compose.yaml b/compose.yaml index 0315aad..b523f27 100644 --- a/compose.yaml +++ b/compose.yaml @@ -14,6 +14,8 @@ services: CLICKHOUSE_PASSWORD: password CLICKHOUSE_DB: default CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1 + volumes: + - ./resources/config_clickhouse.xml:/etc/clickhouse-server/config.d/config.xml jaeger: image: jaegertracing/jaeger:${JAEGER_VERSION:-2.6.0} ports: @@ -32,10 +34,9 @@ services: environment: CONNECTIONS: click LABEL_click: ClickHouse - SERVER_click: database USER_click: default PASSWORD_click: password - PORT_click: 8123 + URL_click: http://database:8123 ENGINE_click: clickhouse@dbgate-plugin-clickhouse DATABASE_click: default depends_on: diff --git a/libs/clickhouse_pool/src/pool_manager.rs b/libs/clickhouse_pool/src/pool_manager.rs index 77100d3..d852177 100644 --- a/libs/clickhouse_pool/src/pool_manager.rs +++ b/libs/clickhouse_pool/src/pool_manager.rs @@ -7,6 +7,8 @@ use crate::metrics::SharedRegistrar; use crate::pool::{get_query_type, ClickhouseConnectionPool, ClickhouseError}; use crate::traits::Model; use anyhow::Result; +use clickhouse::insert::Insert; +use clickhouse::Row; use serde::de::DeserializeOwned; use tokio::sync::mpsc; use tokio::time::interval; @@ -47,6 +49,21 @@ impl PoolManager { self.pool.clone() } + pub async fn get_insert( + &self, + table_name: &str, + ) -> Result, clickhouse::error::Error> + where + T: Model + Send + Sync + 'static, + { + self.pool + .clone() + .get_connection() + .await + .unwrap() + .insert(table_name) + } + pub fn seconds_since_last_recycle(&self) -> u64 { let last = self.last_recycle_time; diff --git a/libs/database/Cargo.toml b/libs/database/Cargo.toml index c93fad9..2b35717 100644 --- a/libs/database/Cargo.toml +++ b/libs/database/Cargo.toml @@ -11,5 +11,7 @@ clickhouse_pool = { path = "../clickhouse_pool" } clickhouse = { workspace = true } uuid = { workspace = true } chrono = { workspace = true } +serde_repr = "0.1.20" +serde_json = { workspace = true } # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/libs/database/src/trivial.rs b/libs/database/src/trivial.rs index 5fb6af9..a526db9 100644 --- a/libs/database/src/trivial.rs +++ b/libs/database/src/trivial.rs @@ -2,15 +2,26 @@ use chrono::{DateTime, Utc}; use clickhouse::Row; use clickhouse_pool::traits::Model; use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; use uuid::Uuid; -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize_repr, Deserialize_repr)] +#[repr(u8)] pub enum TrivialRewardKind { OnlyTheFirstOne = 0, TopThree = 1, TopFive = 2, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum TrivialStatus { + Init = 0, + Started = 1, + Finished = 2, + Paused = 3, +} + #[derive(Debug, Clone, PartialEq, PartialOrd, Row, Serialize, Deserialize)] pub struct Trivial { #[serde(with = "clickhouse::serde::uuid")] @@ -34,7 +45,53 @@ pub struct Trivial { pub role_ping_enabled: bool, pub reward_kind: TrivialRewardKind, pub reward_amount: u64, + /// Whether or not the bot should send an ephemeral message to the user when their answer is taken into account. pub taken_into_account: bool, + pub status: TrivialStatus, +} + +impl Default for Trivial { + fn default() -> Self { + Self { + id: Uuid::new_v4(), + name: String::new(), + description: String::new(), + guild_id: 0, + channel_id: 0, + created_at: Utc::now(), + updated_at: Utc::now(), + creator_id: 0, + updater_id: 0, + random_question: true, + role_ping: 0, + role_ping_enabled: false, + reward_kind: TrivialRewardKind::TopThree, + reward_amount: 3, + taken_into_account: true, + status: TrivialStatus::Init, + } + } +} + +impl Trivial { + pub fn new( + name: String, + description: String, + guild_id: u64, + channel_id: u64, + creator_id: u64, + updater_id: u64, + ) -> Self { + Self { + name, + description, + guild_id, + channel_id, + creator_id, + updater_id, + ..Default::default() + } + } } impl Model for Trivial { @@ -52,8 +109,8 @@ impl Model for Trivial { description String, guild_id UInt64, channel_id UInt64, - created_at DateTime64(3), - updated_at DateTime64(3), + created_at DateTime64(3, 'UTC'), + updated_at DateTime64(3, 'UTC'), creator_id UInt64, updater_id UInt64, random_question Bool, @@ -61,7 +118,8 @@ impl Model for Trivial { role_ping_enabled Bool, reward_kind Enum8('OnlyTheFirstOne' = 0, 'TopThree' = 1, 'TopFive' = 2), reward_amount UInt64, - taken_into_account Bool + taken_into_account Bool, + status Enum8('Init' = 0, 'Started' = 1, 'Finished' = 2, 'Paused' = 3) ) ENGINE = MergeTree() ORDER BY id "# @@ -84,6 +142,7 @@ impl Model for Trivial { "reward_kind", "reward_amount", "taken_into_account", + "status", ] } @@ -91,21 +150,22 @@ impl Model for Trivial { ( Self::column_names(), vec![ - self.id.to_string(), - self.name.clone(), - self.description.clone(), + format!("'{}'", self.id), + format!("'{}'", self.name), + format!("'{}'", self.description), self.guild_id.to_string(), self.channel_id.to_string(), - self.created_at.to_string(), - self.updated_at.to_string(), + format!("'{}'", self.created_at.to_rfc3339()), + format!("'{}'", self.updated_at.to_rfc3339()), self.creator_id.to_string(), self.updater_id.to_string(), self.random_question.to_string(), self.role_ping.to_string(), self.role_ping_enabled.to_string(), - format!("{:?}", self.reward_kind), + format!("'{:?}'", serde_json::to_string(&self.reward_kind)), self.reward_amount.to_string(), self.taken_into_account.to_string(), + format!("'{:?}'", serde_json::to_string(&self.status)), ], ) } diff --git a/resources/config.toml b/resources/config.toml index c4089ae..eaa35ce 100644 --- a/resources/config.toml +++ b/resources/config.toml @@ -22,7 +22,7 @@ level = 2 [[tracing]] kind = "Otel" name = "otel" -level = 2 +level = 1 [tracing.additional] endpoint = "http://localhost:4317" diff --git a/resources/config_clickhouse.xml b/resources/config_clickhouse.xml new file mode 100644 index 0000000..54a4440 --- /dev/null +++ b/resources/config_clickhouse.xml @@ -0,0 +1,7 @@ + + + true + + + + \ No newline at end of file