feat: add listing logger channels in a guild #11
| @ -7,7 +7,8 @@ | |||||||
| -- them from the database. This operation is noop in Rust and should | -- them from the database. This operation is noop in Rust and should | ||||||
| -- therefore not cost a single CPU cycle. | -- therefore not cost a single CPU cycle. | ||||||
| CREATE TABLE IF NOT EXISTS guild_log_channels ( | CREATE TABLE IF NOT EXISTS guild_log_channels ( | ||||||
|        guild_id INTEGER PRIMARY KEY, |        guild_id INTEGER NOT NULL, | ||||||
|        channel_id INTEGER NOT NULL, |        channel_id INTEGER NOT NULL, | ||||||
|        UNIQUE(guild_id, channel_id) |        UNIQUE(guild_id, channel_id) | ||||||
| ); | ); | ||||||
|  | CREATE INDEX IF NOT EXISTS guild_log_channels_guild_id ON guild_log_channels(guild_id); | ||||||
|  | |||||||
| @ -1,7 +1,10 @@ | |||||||
|  | #![allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)] | ||||||
|  | 
 | ||||||
| use std::env; | use std::env; | ||||||
| 
 | 
 | ||||||
| use poise::serenity_prelude::{ChannelId, GuildId}; | use poise::serenity_prelude::{ChannelId, GuildId}; | ||||||
| use sqlx::SqlitePool; | use sqlx::SqlitePool; | ||||||
|  | use tracing::error; | ||||||
| 
 | 
 | ||||||
| pub type Result<T> = ::std::result::Result<T, sqlx::Error>; | pub type Result<T> = ::std::result::Result<T, sqlx::Error>; | ||||||
| 
 | 
 | ||||||
| @ -22,9 +25,9 @@ impl Database { | |||||||
| 
 | 
 | ||||||
|     pub async fn get_logging_channel( |     pub async fn get_logging_channel( | ||||||
|         &self, |         &self, | ||||||
|         guild_id: u64, |         guild_id: GuildId, | ||||||
|     ) -> Result<Vec<u64>> { |     ) -> Result<Vec<u64>> { | ||||||
|         let guild_id = guild_id as i64; |         let guild_id = guild_id.0 as i64; | ||||||
|         let channels = sqlx::query!( |         let channels = sqlx::query!( | ||||||
|             r#" |             r#" | ||||||
| SELECT channel_id | SELECT channel_id | ||||||
| @ -34,7 +37,11 @@ WHERE guild_id = ?1 | |||||||
|             guild_id |             guild_id | ||||||
|         ) |         ) | ||||||
|         .fetch_all(&self.pool) |         .fetch_all(&self.pool) | ||||||
|         .await?; |         .await | ||||||
|  |         .map_err(|e| { | ||||||
|  |             error!("Error getting logging channels for guild {guild_id}: {e:?}"); | ||||||
|  |             e | ||||||
|  |         })?; | ||||||
|         Ok(channels.iter().map(|id| id.channel_id as u64).collect()) |         Ok(channels.iter().map(|id| id.channel_id as u64).collect()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -57,6 +64,10 @@ VALUES ( ?1, ?2 ) | |||||||
|         ) |         ) | ||||||
|         .execute(&mut *conn) |         .execute(&mut *conn) | ||||||
|         .await |         .await | ||||||
|  |         .map_err(|e| { | ||||||
|  |             error!("Error setting channel {channel_id} as logger for guild {guild_id}: {e:?}"); | ||||||
|  |             e | ||||||
|  |         }) | ||||||
|         .map(|_| ()) |         .map(|_| ()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,12 +2,13 @@ use super::{Context, Error}; | |||||||
| 
 | 
 | ||||||
| use super::utils::serenity; | use super::utils::serenity; | ||||||
| 
 | 
 | ||||||
|  | #[allow(clippy::unused_async)] | ||||||
| #[poise::command(
 | #[poise::command(
 | ||||||
|     slash_command, |     slash_command, | ||||||
|     subcommands("add_channel"), |     subcommands("add_channel", "list_channels"), | ||||||
|     required_permissions = "ADMINISTRATOR" |     required_permissions = "ADMINISTRATOR" | ||||||
| )] | )] | ||||||
| pub async fn logging(_ctx: Context<'_>, _arg: String) -> Result<(), Error> { | pub async fn logging(_ctx: Context<'_>) -> Result<(), Error> { | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -18,7 +19,7 @@ pub async fn add_channel( | |||||||
| ) -> Result<(), Error> { | ) -> Result<(), Error> { | ||||||
|     let channel_id = channel.id(); |     let channel_id = channel.id(); | ||||||
|     let response = match ctx.guild_id() { |     let response = match ctx.guild_id() { | ||||||
|         None => "Error: Could not determine the guild's ID.".to_owned(), |         None => "Error: Could not determine the guild's ID".to_owned(), | ||||||
|         Some(guild_id) => { |         Some(guild_id) => { | ||||||
|             match ctx |             match ctx | ||||||
|                 .data() |                 .data() | ||||||
| @ -26,7 +27,7 @@ pub async fn add_channel( | |||||||
|                 .set_logging_channel(guild_id, channel_id) |                 .set_logging_channel(guild_id, channel_id) | ||||||
|                 .await |                 .await | ||||||
|             { |             { | ||||||
|                 Ok(_) => format!( |                 Ok(()) => format!( | ||||||
|                     "Added channel <#{channel_id}> as a logging channel" |                     "Added channel <#{channel_id}> as a logging channel" | ||||||
|                 ), |                 ), | ||||||
|                 Err(e) => { |                 Err(e) => { | ||||||
| @ -34,7 +35,7 @@ pub async fn add_channel( | |||||||
|                         if db_error.is_unique_violation() { |                         if db_error.is_unique_violation() { | ||||||
|                             format!("Channel <#{channel_id}> is already a logging channel") |                             format!("Channel <#{channel_id}> is already a logging channel") | ||||||
|                         } else { |                         } else { | ||||||
|                             format!("Error: {:?}", e) |                             format!("Error: {e:?}") | ||||||
|                         } |                         } | ||||||
|                     } else { |                     } else { | ||||||
|                         format!( |                         format!( | ||||||
| @ -48,3 +49,31 @@ pub async fn add_channel( | |||||||
|     ctx.say(response).await?; |     ctx.say(response).await?; | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #[poise::command(slash_command, aliases("list-channels"))] | ||||||
|  | pub async fn list_channels(ctx: Context<'_>) -> Result<(), Error> { | ||||||
|  |     let response = match ctx.guild_id() { | ||||||
|  |         None => "Error: Could not determine the guild's ID".to_owned(), | ||||||
|  |         Some(guild_id) => { | ||||||
|  |             match ctx.data().database.get_logging_channel(guild_id).await { | ||||||
|  |                 Ok(channels) => { | ||||||
|  |                     if channels.is_empty() { | ||||||
|  |                         "No channels registered as loggers".to_owned() | ||||||
|  |                     } else { | ||||||
|  |                         format!( | ||||||
|  |                             "Here are the channels currently set as loggers:\n{}", | ||||||
|  |                             channels | ||||||
|  |                                 .iter() | ||||||
|  |                                 .map(|channel| format!("- <#{channel}>")) | ||||||
|  |                                 .collect::<Vec<String>>() | ||||||
|  |                                 .join("\n") | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 Err(e) => format!("Could not retrieve loggers: {e:?}"), | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |     ctx.say(response).await?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | |||||||
| @ -8,9 +8,8 @@ use utils::serenity; | |||||||
| use commands::logging; | use commands::logging; | ||||||
| use utils::{BotData, Context, Error}; | use utils::{BotData, Context, Error}; | ||||||
| 
 | 
 | ||||||
| pub async fn make_bot() -> color_eyre::Result<FrameworkBuilder<BotData, Error>> | pub fn make_bot() -> FrameworkBuilder<BotData, Error> { | ||||||
| { |     poise::Framework::builder() | ||||||
|     let framework = poise::Framework::builder() |  | ||||||
|         .options(poise::FrameworkOptions { |         .options(poise::FrameworkOptions { | ||||||
|             commands: vec![logging()], |             commands: vec![logging()], | ||||||
|             ..Default::default() |             ..Default::default() | ||||||
| @ -26,6 +25,5 @@ pub async fn make_bot() -> color_eyre::Result<FrameworkBuilder<BotData, Error>> | |||||||
|                 .await?; |                 .await?; | ||||||
|                 Ok(BotData::new().await?) |                 Ok(BotData::new().await?) | ||||||
|             }) |             }) | ||||||
|         }); |         }) | ||||||
|     Ok(framework) |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | #![warn(clippy::style, clippy::pedantic)] | ||||||
|  | 
 | ||||||
| mod utils; | mod utils; | ||||||
| mod db; | mod db; | ||||||
| mod discord; | mod discord; | ||||||
| @ -10,7 +12,7 @@ async fn main() -> Result<(), Box<dyn Error>> { | |||||||
|     color_eyre::install()?; |     color_eyre::install()?; | ||||||
|     utils::setup_logging(); |     utils::setup_logging(); | ||||||
| 
 | 
 | ||||||
|     let bot = discord::make_bot().await?; |     let bot = discord::make_bot(); | ||||||
|     bot.run().await?; |     bot.run().await?; | ||||||
| 
 | 
 | ||||||
|     Ok(()) |     Ok(()) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user