132 lines
3.8 KiB
Rust
132 lines
3.8 KiB
Rust
#![allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
|
|
|
|
use poise::serenity_prelude::{ChannelId, GuildId};
|
|
use sqlx::{migrate::MigrateDatabase, Sqlite, SqlitePool};
|
|
use tracing::{error, info, debug};
|
|
|
|
pub type Result<T> = ::std::result::Result<T, sqlx::Error>;
|
|
|
|
pub struct Database(SqlitePool);
|
|
|
|
impl Database {
|
|
/// Initialize Sqlite database.
|
|
///
|
|
/// The Sqlite database should already exist and have its
|
|
/// migrations already executed.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// This function will return an error if the Sqlite pool fails to
|
|
/// create.
|
|
pub async fn new() -> Result<Self> {
|
|
let url = "sqlite:p4bl0t.db";
|
|
if !Sqlite::database_exists(url).await? {
|
|
info!("Creating database");
|
|
Sqlite::create_database(url).await?;
|
|
info!("Database created");
|
|
}
|
|
debug!("Getting pool connection");
|
|
let pool = SqlitePool::connect(url).await?;
|
|
info!("Running migrations");
|
|
sqlx::migrate!().run(&pool).await?;
|
|
debug!("Database initialized");
|
|
Ok(Self(pool))
|
|
}
|
|
|
|
/// Return from database all channels registered as loggers for a
|
|
/// guild.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// This function will return an error if `sqlx` does so.
|
|
pub async fn get_logging_channels(
|
|
&self,
|
|
guild_id: GuildId,
|
|
) -> Result<Vec<ChannelId>> {
|
|
let guild_id = guild_id.get() as i64;
|
|
sqlx::query!(
|
|
r#"
|
|
SELECT channel_id
|
|
FROM guild_log_channels
|
|
WHERE guild_id = ?1"#,
|
|
guild_id
|
|
)
|
|
.fetch_all(&self.0)
|
|
.await
|
|
.map_err(|e| {
|
|
error!(
|
|
"Error getting logging channels for guild {guild_id}: {e:?}"
|
|
);
|
|
e
|
|
})
|
|
.map(|channels| {
|
|
channels
|
|
.iter()
|
|
.map(|id| ChannelId::new(id.channel_id as u64))
|
|
.collect()
|
|
})
|
|
}
|
|
|
|
/// Adds a channel as a logger for a guild.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// This function will return an error if `sqlx` does so. This may
|
|
/// be either a database issue, or a channel is already registered
|
|
/// as a guild's logger, therefore violating the unicity
|
|
/// constraint for guild ID and channel ID pairs.
|
|
pub async fn set_logging_channel(
|
|
&self,
|
|
guild_id: GuildId,
|
|
channel_id: ChannelId,
|
|
) -> Result<()> {
|
|
let guild_id = guild_id.get() as i64;
|
|
let channel_id = channel_id.get() as i64;
|
|
let mut conn = self.0.acquire().await?;
|
|
|
|
sqlx::query!(r#"
|
|
INSERT INTO guild_log_channels (guild_id, channel_id)
|
|
VALUES ( ?1, ?2 )"#,
|
|
guild_id,
|
|
channel_id
|
|
)
|
|
.execute(&mut *conn)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Error setting channel {channel_id} as logger for guild {guild_id}: {e:?}");
|
|
e
|
|
})
|
|
.map(|_| ())
|
|
}
|
|
|
|
/// Unregister a channel as a logger for a guild.
|
|
///
|
|
/// This function will return a success value even if `channel`
|
|
/// was not a logger of `guild` already.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// This function will return an error if `sqlx` does so.
|
|
pub async fn remove_logging_channel(
|
|
&self,
|
|
guild: GuildId,
|
|
channel: ChannelId,
|
|
) -> Result<()> {
|
|
let guild_id = guild.get() as i64;
|
|
let channel_id = channel.get() as i64;
|
|
let mut conn = self.0.acquire().await?;
|
|
sqlx::query!(r#"
|
|
DELETE FROM guild_log_channels
|
|
WHERE guild_id = ?1 AND channel_id = ?2"#,
|
|
guild_id,
|
|
channel_id)
|
|
.execute(&mut *conn)
|
|
.await
|
|
.map_err(|e| {
|
|
error!("Error removing channel {channel_id} as a logger for guild {guild_id}: {e:?}");
|
|
e
|
|
})
|
|
.map(|_| ())
|
|
}
|
|
}
|